From 2b334d02a2eaa44af844b22f38e04a1ed11366d8 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 10 Jun 2015 12:22:53 +0200 Subject: [PATCH 0001/1520] Fix some links --- README.rst | 2 +- docs/logging-best-practices.rst | 11 +++++------ docs/processors.rst | 2 +- structlog/threadlocal.py | 3 ++- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.rst b/README.rst index 22544438..c4649145 100644 --- a/README.rst +++ b/README.rst @@ -30,4 +30,4 @@ It's dual-licensed under `Apache License, version 2 `_! +If you need any help, visit us on ``#structlog`` on `Freenode `_! diff --git a/docs/logging-best-practices.rst b/docs/logging-best-practices.rst index 14c6003b..7d1286dc 100644 --- a/docs/logging-best-practices.rst +++ b/docs/logging-best-practices.rst @@ -84,18 +84,17 @@ Graylog2 ^^^^^^^^ Graylog_ goes one step further. -It not only supports everything those above do (and then some); you can also log directly JSON entries towards it -- optionally even through an AMQP_ server (like RabbitMQ_) for better reliability. +It not only supports everything those above do (and then some); you can also log directly JSON entries towards it -- optionally even through an AMQP server (like RabbitMQ_) for better reliability. Additionally, `Graylog's Extended Log Format`_ (GELF) allows for structured data which makes it an obvious choice to use together with structlog. .. [*] This is obviously a privileged UNIX-centric view but even Windows has tools and means for log management although we won't be able to discuss them here. -.. _AMQP: https://www.graylog2.org/resources/documentation .. _Graylog: http://graylog2.org -.. _Logstash: http://logstash.net -.. _logstash-forwarder: https://github.com/elasticsearch/logstash-forwarder +.. _Logstash: https://www.elastic.co/products/logstash +.. _logstash-forwarder: https://github.com/elastic/logstash-forwarder .. _RabbitMQ: http://www.rabbitmq.com -.. _`Graylog's Extended Log Format`: http://graylog2.org/gelf +.. _`Graylog's Extended Log Format`: https://www.graylog.org/resources/gelf-2/ .. _`daemon showdown`: https://web.archive.org/web/20130907200323/http://tech.cueup.com/blog/2013/03/08/running-daemons/ .. _`standard out`: http://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29 .. _`they can be switched off`: http://blog.abhijeetr.com/2013/01/disable-rate-limiting-in-rsyslog-v5.html @@ -107,4 +106,4 @@ Additionally, `Graylog's Extended Log Format`_ (GELF) allows for structured data .. _svlogd: http://smarden.org/runit/svlogd.8.html .. _syslogd: http://en.wikipedia.org/wiki/Syslogd .. _tai64n: http://cr.yp.to/daemontools/tai64n.html -.. _elasticsearch: http://www.elasticsearch.org +.. _elasticsearch: https://www.elastic.co/products/elasticsearch diff --git a/docs/processors.rst b/docs/processors.rst index d5259f3e..fe933105 100644 --- a/docs/processors.rst +++ b/docs/processors.rst @@ -113,7 +113,7 @@ Examples ^^^^^^^^ The probably most useful formatter for string based loggers is :class:`~structlog.processors.JSONRenderer`. -Advanced log aggregation and analysis tools like `logstash `_ offer features like telling them “this is JSON, deal with it” instead of fiddling with regular expressions. +Advanced log aggregation and analysis tools like `logstash `_ offer features like telling them “this is JSON, deal with it” instead of fiddling with regular expressions. More examples can be found in the :ref:`examples ` chapter. For a list of shipped processors, check out the :ref:`API documentation `. diff --git a/structlog/threadlocal.py b/structlog/threadlocal.py index f777ca58..b0cd0399 100644 --- a/structlog/threadlocal.py +++ b/structlog/threadlocal.py @@ -67,7 +67,8 @@ def as_immutable(logger): """ Extract the context from a thread local logger into an immutable logger. - :param BoundLogger logger: A logger with *possibly* thread local state. + :param structlog.BoundLogger logger: A logger with *possibly* thread local + state. :rtype: :class:`~structlog.BoundLogger` with an immutable context. """ if isinstance(logger, BoundLoggerLazyProxy): From 11ecaf5ac6d6487ba028d9970394f27087b7adf0 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 10 Jun 2015 14:14:43 +0200 Subject: [PATCH 0002/1520] Release 15.2.0 --- docs/changelog.rst | 2 +- structlog/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 0b71ca76..62720a46 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -2,7 +2,7 @@ Changelog ========= -- :release:`15.2.0 ` +- :release:`15.2.0 <2015-06-10>` - :bug:`- major` Allow empty lists of processors. This is a valid use case since `#26 `_ has been merged. Before, supplying an empty list resulted in the defaults being used. diff --git a/structlog/__init__.py b/structlog/__init__.py index e5df98f9..1f350d93 100644 --- a/structlog/__init__.py +++ b/structlog/__init__.py @@ -44,7 +44,7 @@ twisted = None -__version__ = "15.2.0.dev0" +__version__ = "15.2.0" __title__ = "structlog" __description__ = "Structured Logging in Python" From be288a9e284105360b6608e06ee305e96f0bfdb8 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 10 Jun 2015 14:21:37 +0200 Subject: [PATCH 0003/1520] Start new cycle --- structlog/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/structlog/__init__.py b/structlog/__init__.py index 1f350d93..f840a7ae 100644 --- a/structlog/__init__.py +++ b/structlog/__init__.py @@ -44,7 +44,7 @@ twisted = None -__version__ = "15.2.0" +__version__ = "15.3.0.dev0" __title__ = "structlog" __description__ = "Structured Logging in Python" From 8dcb9562f4ac0fe51c57c6f3e887c9867a49010a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 3 Jul 2015 15:13:28 +0200 Subject: [PATCH 0004/1520] Fix markup in BoundLogger docstring --- structlog/_generic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/structlog/_generic.py b/structlog/_generic.py index 502b611f..89c3f55c 100644 --- a/structlog/_generic.py +++ b/structlog/_generic.py @@ -19,7 +19,7 @@ class BoundLogger(BoundLoggerBase): Every unknown method will be passed to the wrapped logger. If that's too much magic for you, try :class:`structlog.twisted.BoundLogger` or - `:class:`structlog.twisted.BoundLogger` which also take advantage of + :class:`structlog.twisted.BoundLogger` which also take advantage of knowing the wrapped class which generally results in better performance. Not intended to be instantiated by yourself. See From 88e6d56f7088c2b5038647adb1acf677daf01495 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 3 Jul 2015 15:40:09 +0200 Subject: [PATCH 0005/1520] Add failure to ReturnLogger & PrintLogger --- docs/api.rst | 4 ++-- docs/changelog.rst | 1 + structlog/_loggers.py | 12 ++++++------ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index c7ebf6bc..710c1959 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -24,12 +24,12 @@ structlog Package :members: new, bind, unbind .. autoclass:: PrintLogger - :members: msg, err, debug, info, warning, error, critical, log + :members: msg, err, debug, info, warning, error, critical, log, failure .. autoclass:: PrintLoggerFactory .. autoclass:: ReturnLogger - :members: msg, err, debug, info, warning, error, critical, log + :members: msg, err, debug, info, warning, error, critical, log, failure .. autoclass:: ReturnLoggerFactory diff --git a/docs/changelog.rst b/docs/changelog.rst index 62720a46..6c952ce8 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -2,6 +2,7 @@ Changelog ========= +- :feature:`-` Add :func:`structlog.ReturnLogger.failure` and :func:`structlog.PrintLogger.failure` as preparation for the new Twisted logging system. - :release:`15.2.0 <2015-06-10>` - :bug:`- major` Allow empty lists of processors. This is a valid use case since `#26 `_ has been merged. diff --git a/structlog/_loggers.py b/structlog/_loggers.py index 1ed703f5..1419fbec 100644 --- a/structlog/_loggers.py +++ b/structlog/_loggers.py @@ -16,7 +16,7 @@ class PrintLoggerFactory(object): """ - Produces :class:`PrintLogger`\ s. + Produce :class:`PrintLogger`\ s. To be used with :func:`structlog.configure`\ 's `logger_factory`. @@ -38,7 +38,7 @@ def __call__(self, *args): class PrintLogger(object): """ - Prints events into a file. + Print events into a file. :param file file: File to print to. (default: stdout) @@ -76,12 +76,12 @@ def msg(self, message): until_not_interrupted(self._flush) log = debug = info = warn = warning = msg - err = error = critical = exception = msg + failure = err = error = critical = exception = msg class ReturnLoggerFactory(object): """ - Produces and caches :class:`ReturnLogger`\ s. + Produce and cache :class:`ReturnLogger`\ s. To be used with :func:`structlog.configure`\ 's `logger_factory`. @@ -98,7 +98,7 @@ def __call__(self, *args): class ReturnLogger(object): """ - Returns the string that it's called with. + Return the arguments that it's called with. >>> from structlog import ReturnLogger >>> ReturnLogger().msg('hello') @@ -122,4 +122,4 @@ def msg(self, *args, **kw): return args, kw log = debug = info = warn = warning = msg - err = error = critical = exception = msg + failure = err = error = critical = exception = msg From daebc812e61a2446111789c54d60ee068e013a67 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 3 Jul 2015 16:22:55 +0200 Subject: [PATCH 0006/1520] Move to codecov and shields --- .travis.yml | 37 ++++++++++++++++++++----------------- README.rst | 6 +++--- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/.travis.yml b/.travis.yml index 08052602..c215abf0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,26 +2,29 @@ language: python sudo: false python: 2.7 env: - - TOX_ENV=py26-threads - - TOX_ENV=py27-threads - - TOX_ENV=py33-threads - - TOX_ENV=py34-threads - - TOX_ENV=pypy-threads - - TOX_ENV=py26-greenlets - - TOX_ENV=py27-greenlets - - TOX_ENV=py33-greenlets - - TOX_ENV=py34-greenlets - - TOX_ENV=pypy-greenlets - - TOX_ENV=docs - - TOX_ENV=flake8-py2 - - TOX_ENV=flake8-py3 - - TOX_ENV=manifest + - TOX_ENV=py26-threads + - TOX_ENV=py27-threads + - TOX_ENV=py33-threads + - TOX_ENV=py34-threads + - TOX_ENV=pypy-threads + - TOX_ENV=py26-greenlets + - TOX_ENV=py27-greenlets + - TOX_ENV=py33-greenlets + - TOX_ENV=py34-greenlets + - TOX_ENV=pypy-greenlets + - TOX_ENV=docs + - TOX_ENV=flake8-py2 + - TOX_ENV=flake8-py3 + - TOX_ENV=manifest install: - - pip install tox coveralls + - pip install tox script: - - tox -e $TOX_ENV + - tox -e $TOX_ENV + +before_install: + - pip install codecov after_success: - - coveralls + - codecov diff --git a/README.rst b/README.rst index c4649145..82ac2d7c 100644 --- a/README.rst +++ b/README.rst @@ -2,15 +2,15 @@ structlog: Structured Logging for Python ======================================== -.. image:: https://pypip.in/version/structlog/badge.svg +.. image:: https://img.shields.io/pypi/v/structlog.svg :target: https://pypi.python.org/pypi/structlog/ :alt: Latest Version .. image:: https://travis-ci.org/hynek/structlog.svg?branch=master :target: https://travis-ci.org/hynek/structlog -.. image:: https://coveralls.io/repos/hynek/structlog/badge.svg?branch=master - :target: https://coveralls.io/r/hynek/structlog?branch=master +.. image:: https://codecov.io/github/hynek/structlog/coverage.svg?branch=master + :target: https://codecov.io/github/hynek/structlog?branch=master ``structlog`` makes structured logging in Python easy by *augmenting* your *existing* logger. It allows you to split your log entries up into key/value pairs and build them incrementally without annoying boilerplate code. From a3c12f174637ce90016b7bed9e9c18c182c3df51 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 26 Jul 2015 13:56:10 +0200 Subject: [PATCH 0007/1520] Speed up builds --- .travis.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c215abf0..98fc8ced 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,9 @@ -language: python sudo: false +cache: + directories: + - $HOME/.cache/pip + +language: python python: 2.7 env: - TOX_ENV=py26-threads From d8b00c0b5b56547b2763555b7ecce2ac7f312dd9 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 11 Aug 2015 08:37:21 +0200 Subject: [PATCH 0008/1520] Stress that binding is optional --- README.rst | 2 ++ docs/index.rst | 2 +- docs/why.rst | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 82ac2d7c..e49e528b 100644 --- a/README.rst +++ b/README.rst @@ -19,6 +19,8 @@ It allows you to split your log entries up into key/value pairs and build them i >>> from structlog import get_logger >>> log = get_logger() + >>> log.info("key_value_logging", out_of_the_box=True, effort=0) + out_of_the_box=True effort=0 event='key_value_logging' >>> log = log.bind(user='anonymous', some_key=23) >>> log = log.bind(user='hynek', another_key=42) >>> log.info('user.logged_in', happy=True) diff --git a/docs/index.rst b/docs/index.rst index 807df7df..f17ebb7a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -10,7 +10,7 @@ Release v\ |version| (:doc:`What's new? `). The Pitch ========= -``structlog`` makes structured logging with *incremental context building* and *arbitrary formatting* as easy as: +``structlog`` makes structured logging with *key-value logging*, *incremental context building* and *arbitrary formatting* as easy as: .. doctest:: diff --git a/docs/why.rst b/docs/why.rst index 67615dcd..77f3256c 100644 --- a/docs/why.rst +++ b/docs/why.rst @@ -21,7 +21,7 @@ Structured logging means that you don't write hard-to-parse and hard-to-keep-con Because it's easy and you don't have to replace your underlying logger -- you just add structure to your log entries and format them to strings before they hit your real loggers. -structlog supports you with building your context as you go (e.g. if a user logs in, you bind their user name to your current logger) and log events when they happen (i.e. the user does something log-worthy): +``structlog`` supports you with building your context as you go (e.g. if a user logs in, you bind their user name to your current logger) and log events when they happen (i.e. the user does something log-worthy): .. doctest:: From f3aab39d5b040c705bf76b790b599e3aa30e3622 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 11 Aug 2015 10:27:18 +0200 Subject: [PATCH 0009/1520] Don't use setup.py test It doesn't use pip to install it's dependencies which is why we don't get to use it's advantages. --- .gitignore | 1 - setup.py | 29 ----------------------------- tox.ini | 9 +++++++-- 3 files changed, 7 insertions(+), 32 deletions(-) diff --git a/.gitignore b/.gitignore index 11887247..bcf2790e 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,3 @@ htmlcov dist docs/_build *.pyc -.eggs diff --git a/setup.py b/setup.py index fa716fa1..af8f83aa 100644 --- a/setup.py +++ b/setup.py @@ -28,26 +28,6 @@ def find_version(*file_paths): raise RuntimeError("Unable to find version string.") -class PyTest(TestCommand): - user_options = [('pytest-args=', 'a', "Arguments to pass to py.test")] - - def initialize_options(self): - TestCommand.initialize_options(self) - self.pytest_args = None - - def finalize_options(self): - TestCommand.finalize_options(self) - self.test_args = [] - self.test_suite = True - - def run_tests(self): - # import here, cause outside the eggs aren't loaded - import pytest - errno = pytest.main(self.pytest_args or [] + - ["tests"]) - sys.exit(errno) - - if __name__ == "__main__": setup( name='structlog', @@ -75,13 +55,4 @@ def run_tests(self): 'Programming Language :: Python', 'Topic :: Software Development :: Libraries :: Python Modules', ], - tests_require=[ - "freezegun>=0.2.8", - "pretend", - "pytest", - "twisted", - ], - cmdclass={ - "test": PyTest, - }, ) diff --git a/tox.ini b/tox.ini index 11a8eb3b..01c14cd9 100644 --- a/tox.ini +++ b/tox.ini @@ -7,11 +7,16 @@ deps = coverage py26: ordereddict greenlets: greenlet + freezegun>=0.2.8 + pretend + pytest + twisted + setenv = PYTHONHASHSEED = 0 threads: TRICKING_TOX_INTO_GENERATING_AN_ENVIRONMENT = 1 commands = - coverage run setup.py test + coverage run {envbindir}/py.test tests coverage report [testenv:flake8-py2] @@ -30,7 +35,7 @@ setenv = PYTHONHASHSEED = 0 deps = releases - sphinx==1.2.3 + sphinx twisted commands = sphinx-build -W -b html -d {envtmpdir}/doctrees docs docs/_build/html From eeb03e9daa5263dc97cc3c0d104663abc72e3ae0 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 11 Aug 2015 10:45:26 +0200 Subject: [PATCH 0010/1520] Dedup meta data --- setup.py | 82 ++++++++++++++++++++++++++----------------- structlog/__init__.py | 2 +- tox.ini | 5 ++- 3 files changed, 53 insertions(+), 36 deletions(-) diff --git a/setup.py b/setup.py index af8f83aa..d8c1e579 100644 --- a/setup.py +++ b/setup.py @@ -3,56 +3,74 @@ # repository for complete details. from setuptools import setup, find_packages -from setuptools.command.test import test as TestCommand import codecs import os import re -import sys -here = os.path.abspath(os.path.dirname(__file__)) +NAME = "structlog" +META_PATH = os.path.join("structlog", "__init__.py") + +############################################################################### + +HERE = os.path.abspath(os.path.dirname(__file__)) def read(*parts): - with codecs.open(os.path.join(here, *parts), 'r') as f: + """ + Build an absolute path from *parts* and and return the contents of the + resulting file. Assume UTF-8 encoding. + """ + with codecs.open(os.path.join(HERE, *parts), "rb", "utf-8") as f: return f.read() -def find_version(*file_paths): - version_file = read(*file_paths) - version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", - version_file, re.M) - if version_match: - return version_match.group(1) - raise RuntimeError("Unable to find version string.") +META_FILE = read(META_PATH) + + +def find_meta(meta): + """ + Extract __*meta*__ from META_FILE. + """ + meta_match = re.search( + r"^__{meta}__ = ['\"]([^'\"]*)['\"]".format(meta=meta), + META_FILE, re.M + ) + if meta_match: + return meta_match.group(1) + raise RuntimeError("Unable to find __{meta}__ string.".format(meta=meta)) if __name__ == "__main__": setup( - name='structlog', - version=find_version('structlog', '__init__.py'), - description='Structured logging for Python.', + name=NAME, + description=find_meta("description"), + license=find_meta("license"), + url=find_meta("uri"), + version=find_meta("version"), + author=find_meta("author"), + author_email=find_meta("email"), + maintainer=find_meta("author"), + maintainer_email=find_meta("email"), long_description=read('README.rst'), - url='http://www.structlog.org/', - license='MIT or Apache License, Version 2.0', - author='Hynek Schlawack', - author_email='hs@ox.cx', packages=find_packages(exclude=['tests*']), + zip_safe=False, + keywords=["logging", "structured", "structure", "log"], classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: Apache Software License', - 'License :: OSI Approved :: MIT License', - 'Natural Language :: English', - 'Operating System :: OS Independent', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.6', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python', - 'Topic :: Software Development :: Libraries :: Python Modules', + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "License :: OSI Approved :: MIT License", + "Natural Language :: English", + "Operating System :: OS Independent", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.6", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python", + "Topic :: Software Development :: Libraries :: Python Modules", ], ) diff --git a/structlog/__init__.py b/structlog/__init__.py index f840a7ae..13418ea5 100644 --- a/structlog/__init__.py +++ b/structlog/__init__.py @@ -47,7 +47,7 @@ __version__ = "15.3.0.dev0" __title__ = "structlog" -__description__ = "Structured Logging in Python" +__description__ = "Structured Logging for Python" __uri__ = "http://www.structlog.org/" __author__ = "Hynek Schlawack" diff --git a/tox.ini b/tox.ini index 01c14cd9..662d41de 100644 --- a/tox.ini +++ b/tox.ini @@ -3,7 +3,6 @@ envlist = {py26,py27,py33,py34,pypy}-{threads,greenlets}, flake8-{py2,py3}, docs [testenv] deps = - setuptools>=7.0 coverage py26: ordereddict greenlets: greenlet @@ -22,13 +21,13 @@ commands = [testenv:flake8-py2] deps = flake8 commands = - flake8 structlog tests + flake8 structlog tests setup.py [testenv:flake8-py3] basepython = py3: python3.4 deps = flake8 commands = - flake8 structlog tests + flake8 structlog tests setup.py [testenv:docs] setenv = From 67353b81680eb141b9c3fa0df92cf92644a210ba Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 11 Aug 2015 11:16:31 +0200 Subject: [PATCH 0011/1520] OCD --- structlog/__init__.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/structlog/__init__.py b/structlog/__init__.py index 13418ea5..d0964d71 100644 --- a/structlog/__init__.py +++ b/structlog/__init__.py @@ -58,21 +58,21 @@ __all__ = [ - 'BoundLogger', - 'BoundLoggerBase', - 'DropEvent', - 'PrintLogger', - 'PrintLoggerFactory', - 'ReturnLogger', - 'ReturnLoggerFactory', - 'configure', - 'configure_once', - 'getLogger', - 'get_logger', - 'processors', - 'reset_defaults', - 'stdlib', - 'threadlocal', - 'twisted', - 'wrap_logger', + "BoundLogger", + "BoundLoggerBase", + "DropEvent", + "PrintLogger", + "PrintLoggerFactory", + "ReturnLogger", + "ReturnLoggerFactory", + "configure", + "configure_once", + "getLogger", + "get_logger", + "processors", + "reset_defaults", + "stdlib", + "threadlocal", + "twisted", + "wrap_logger", ] From b39a63aec22d65722b1674286e2ffddae7cff658 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 13 Aug 2015 18:15:41 +0200 Subject: [PATCH 0012/1520] Fix link to logging.Logger --- structlog/stdlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/structlog/stdlib.py b/structlog/stdlib.py index 06d19d1c..c94717e2 100644 --- a/structlog/stdlib.py +++ b/structlog/stdlib.py @@ -224,7 +224,7 @@ def __call__(self, *args): ``structlog.get_logger('foo')`` would cause this method to be called with ``'foo'`` as its first positional argument. - :rtype: `logging.Logger` + :rtype: logging.Logger .. versionchanged:: 0.4.0 Added support for optional positional arguments. Using the first From f8bb8ccadd118d9cea37bda20934c0359f5de82a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 14 Aug 2015 16:47:21 +0200 Subject: [PATCH 0013/1520] Get rid of flaky shields.io --- README.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.rst b/README.rst index e49e528b..8ac15064 100644 --- a/README.rst +++ b/README.rst @@ -2,10 +2,6 @@ structlog: Structured Logging for Python ======================================== -.. image:: https://img.shields.io/pypi/v/structlog.svg - :target: https://pypi.python.org/pypi/structlog/ - :alt: Latest Version - .. image:: https://travis-ci.org/hynek/structlog.svg?branch=master :target: https://travis-ci.org/hynek/structlog From e8a2c949f7698cfaac5c2d7a0286270f3c9c7ca9 Mon Sep 17 00:00:00 2001 From: Fran Fitzpatrick Date: Thu, 27 Aug 2015 17:38:27 -0500 Subject: [PATCH 0014/1520] Fixed a minor spelling mistake --- docs/configuration.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.rst b/docs/configuration.rst index b73c34ca..189bd66a 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -118,7 +118,7 @@ The :ref:`Twisted example ` shows how easy it is for Twisted. `LoggerFactory()`-style factories always need to get passed as *instances* like in the examples above. While neither allows for customization using parameters yet, they may do so in the future. -Calling :func:`structlog.get_logger` without configuration gives you a perfectly useful :class:`structlog.PrintLogger` with the default values exaplained above. +Calling :func:`structlog.get_logger` without configuration gives you a perfectly useful :class:`structlog.PrintLogger` with the default values explained above. I don't believe silent loggers are a sensible default. From 03506bb7ff1cfd188406f15ee9515505f1cc46ec Mon Sep 17 00:00:00 2001 From: Fran Fitzpatrick Date: Thu, 27 Aug 2015 17:54:36 -0500 Subject: [PATCH 0015/1520] Added Fran Fitzpatrick to AUTHORS --- AUTHORS.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.rst b/AUTHORS.rst index 975bb518..bc80cbe6 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -13,6 +13,7 @@ The following folks helped forming ``structlog`` into what it is now: - `Daniel Lindsley `_ - `David Reid `_ - `Donald Stufft `_ +- `Fran Fitzpatrick `_ - `George-Cristian Bîrzan `_ - `Glyph `_ - `Holger Krekel `_ From fdcf878238be7259cd5e6c69069a14da3fe9c2b7 Mon Sep 17 00:00:00 2001 From: Justin Wood Date: Mon, 14 Sep 2015 20:58:13 -0400 Subject: [PATCH 0016/1520] Better support for missing __name__ in frame traversal --- docs/changelog.rst | 1 + structlog/_frames.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 6c952ce8..16d52f81 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -2,6 +2,7 @@ Changelog ========= +- :bug:`- major` Tolerate frames without a ``__name__``, better. - :feature:`-` Add :func:`structlog.ReturnLogger.failure` and :func:`structlog.PrintLogger.failure` as preparation for the new Twisted logging system. - :release:`15.2.0 <2015-06-10>` - :bug:`- major` Allow empty lists of processors. diff --git a/structlog/_frames.py b/structlog/_frames.py index 0ed95355..a1b64622 100644 --- a/structlog/_frames.py +++ b/structlog/_frames.py @@ -40,7 +40,7 @@ def _find_first_app_frame_and_name(additional_ignores=None): name = f.f_globals.get("__name__", "?") while any(name.startswith(i) for i in ignores): f = f.f_back - name = f.f_globals.get("__name__", "?") + name = f.f_globals.get("__name__") or "?" return f, name From 7f6fb3cf395f978a5f8fb7c3d5b3ffa23f30fda9 Mon Sep 17 00:00:00 2001 From: Justin Wood Date: Tue, 15 Sep 2015 12:12:41 -0400 Subject: [PATCH 0017/1520] Fix one more spot of frame traversal, and write tests. Also fixes _frame tests with "SyntaxWarning: assertion is always true, perhaps remove parentheses?" And lastly add me to Authors. --- AUTHORS.rst | 1 + structlog/_frames.py | 2 +- tests/test_frames.py | 27 +++++++++++++++++++++++---- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/AUTHORS.rst b/AUTHORS.rst index bc80cbe6..41e48584 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -20,6 +20,7 @@ The following folks helped forming ``structlog`` into what it is now: - `Itamar Turner-Trauring `_ - `Jack Pearkes `_ - `Jean-Paul Calderone `_ +- `Justin Wood (Callek) `_ - `Lakshmi Kannan `_ - `Lynn Root `_ - `Mathieu Leplatre `_ diff --git a/structlog/_frames.py b/structlog/_frames.py index a1b64622..c0da4cbc 100644 --- a/structlog/_frames.py +++ b/structlog/_frames.py @@ -37,7 +37,7 @@ def _find_first_app_frame_and_name(additional_ignores=None): """ ignores = ["structlog"] + (additional_ignores or []) f = sys._getframe() - name = f.f_globals.get("__name__", "?") + name = f.f_globals.get("__name__") or "?" while any(name.startswith(i) for i in ignores): f = f.f_back name = f.f_globals.get("__name__") or "?" diff --git a/tests/test_frames.py b/tests/test_frames.py index 5f2c8b94..da1911c5 100644 --- a/tests/test_frames.py +++ b/tests/test_frames.py @@ -28,7 +28,7 @@ def test_ignores_structlog_by_default(self, monkeypatch): f2 = stub(f_globals={'__name__': 'structlog.blubb'}, f_back=f1) monkeypatch.setattr(structlog._frames.sys, '_getframe', lambda: f2) f, n = _find_first_app_frame_and_name() - assert ((f1, 'test') == f, n) + assert ((f1, 'test') == (f, n)) def test_ignoring_of_additional_frame_names_works(self, monkeypatch): """ @@ -38,17 +38,36 @@ def test_ignoring_of_additional_frame_names_works(self, monkeypatch): f2 = stub(f_globals={'__name__': 'ignored.bar'}, f_back=f1) f3 = stub(f_globals={'__name__': 'structlog.blubb'}, f_back=f2) monkeypatch.setattr(structlog._frames.sys, '_getframe', lambda: f3) - f, n = _find_first_app_frame_and_name() - assert ((f1, 'test') == f, n) + f, n = _find_first_app_frame_and_name(additional_ignores=['ignored']) + assert ((f1, 'test') == (f, n)) def test_tolerates_missing_name(self, monkeypatch): """ Use ``?`` if `f_globals` lacks a `__name__` key """ f1 = stub(f_globals={}, f_back=None) + monkeypatch.setattr(structlog._frames.sys, "_getframe", lambda: f1) f, n = _find_first_app_frame_and_name() + assert ((f1, "?") == (f, n)) + + def test_tolerates_missing_names_explicitly_None_oneframe(self, monkeypatch): + """ + Use ``?`` if `f_globals` has a `None` valued `__name__` key + """ + f1 = stub(f_globals={'__name__': None}, f_back=None) monkeypatch.setattr(structlog._frames.sys, "_getframe", lambda: f1) - assert ((f1, "?") == f, n) + f, n = _find_first_app_frame_and_name() + assert ((f1, "?") == (f, n)) + + def test_tolerates_missing_names_explicitly_None_manyframe(self, monkeypatch): + """ + Use ``?`` if `f_globals` has a `None` valued `__name__` key, multiple frames up. + """ + f1 = stub(f_globals={'__name__': None}, f_back=None) + f2 = stub(f_globals={'__name__': 'structlog.blubb'}, f_back=f1) + monkeypatch.setattr(structlog._frames.sys, "_getframe", lambda: f2) + f, n = _find_first_app_frame_and_name() + assert ((f1, "?") == (f, n)) @pytest.fixture From c3b8d035c29954e26360e45c390c094ce8f0e752 Mon Sep 17 00:00:00 2001 From: Justin Wood Date: Tue, 15 Sep 2015 12:18:05 -0400 Subject: [PATCH 0018/1520] Locally I don't adhere to E501 in tests, but fix it here --- tests/test_frames.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_frames.py b/tests/test_frames.py index da1911c5..8feea117 100644 --- a/tests/test_frames.py +++ b/tests/test_frames.py @@ -50,7 +50,7 @@ def test_tolerates_missing_name(self, monkeypatch): f, n = _find_first_app_frame_and_name() assert ((f1, "?") == (f, n)) - def test_tolerates_missing_names_explicitly_None_oneframe(self, monkeypatch): + def test_tolerates_name_explicitly_None_oneframe(self, monkeypatch): """ Use ``?`` if `f_globals` has a `None` valued `__name__` key """ @@ -59,7 +59,7 @@ def test_tolerates_missing_names_explicitly_None_oneframe(self, monkeypatch): f, n = _find_first_app_frame_and_name() assert ((f1, "?") == (f, n)) - def test_tolerates_missing_names_explicitly_None_manyframe(self, monkeypatch): + def test_tolerates_name_explicitly_None_manyframe(self, monkeypatch): """ Use ``?`` if `f_globals` has a `None` valued `__name__` key, multiple frames up. """ From 49a26a220459d234d63ca4146ff7cb8899ab0c7d Mon Sep 17 00:00:00 2001 From: Justin Wood Date: Tue, 15 Sep 2015 12:30:33 -0400 Subject: [PATCH 0019/1520] Missed one line-length --- tests/test_frames.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_frames.py b/tests/test_frames.py index 8feea117..9852f9cd 100644 --- a/tests/test_frames.py +++ b/tests/test_frames.py @@ -61,7 +61,8 @@ def test_tolerates_name_explicitly_None_oneframe(self, monkeypatch): def test_tolerates_name_explicitly_None_manyframe(self, monkeypatch): """ - Use ``?`` if `f_globals` has a `None` valued `__name__` key, multiple frames up. + Use ``?`` if `f_globals` has a `None` valued `__name__` key, + multiple frames up. """ f1 = stub(f_globals={'__name__': None}, f_back=None) f2 = stub(f_globals={'__name__': 'structlog.blubb'}, f_back=f1) From 8d13674ea32e30b62e9e14b21d7ebd0a7fc721c2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 22 Sep 2015 09:28:02 +0200 Subject: [PATCH 0020/1520] Add Python 3.5 --- .gitignore | 1 + .travis.yml | 57 ++++++++++++++++++++++++++++++++-------------- README.rst | 2 +- docs/changelog.rst | 1 + setup.py | 1 + tox.ini | 4 ++-- 6 files changed, 46 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index bcf2790e..40462405 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ htmlcov dist docs/_build *.pyc +.cache diff --git a/.travis.yml b/.travis.yml index 98fc8ced..d16b8b74 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,28 +4,51 @@ cache: - $HOME/.cache/pip language: python -python: 2.7 -env: - - TOX_ENV=py26-threads - - TOX_ENV=py27-threads - - TOX_ENV=py33-threads - - TOX_ENV=py34-threads - - TOX_ENV=pypy-threads - - TOX_ENV=py26-greenlets - - TOX_ENV=py27-greenlets - - TOX_ENV=py33-greenlets - - TOX_ENV=py34-greenlets - - TOX_ENV=pypy-greenlets - - TOX_ENV=docs - - TOX_ENV=flake8-py2 - - TOX_ENV=flake8-py3 - - TOX_ENV=manifest + + +matrix: + include: + - python: "2.6" # these are just to make travis's UI a bit prettier + env: TOXENV=py26-threads + - python: "2.6" + env: TOXENV=py26-greenlets + - python: "2.7" + env: TOXENV=py27-threads + - python: "2.7" + env: TOXENV=py27-greenlets + - python: "3.3" + env: TOXENV=py33-threads + - python: "3.3" + env: TOXENV=py33-greenlets + - python: "3.4" + env: TOXENV=py34-threads + - python: "3.4" + env: TOXENV=py34-greenlets + - python: "3.5" + env: TOXENV=py35-threads + - python: "3.5" + env: TOXENV=py35-greenlets + - python: "pypy" + env: TOXENV=pypy-threads + - python: "pypy" + env: TOXENV=pypy-greenlets + + + # Meta + - python: "2.7" + env: TOXENV=flake8-py2 + - python: "3.5" + env: TOXENV=flake8-py3 + - python: "2.7" + env: TOXENV=manifest + - python: "2.7" + env: TOXENV=docs install: - pip install tox script: - - tox -e $TOX_ENV + - tox before_install: - pip install codecov diff --git a/README.rst b/README.rst index 8ac15064..a9e6c3ea 100644 --- a/README.rst +++ b/README.rst @@ -26,6 +26,6 @@ It allows you to split your log entries up into key/value pairs and build them i It's dual-licensed under `Apache License, version 2 `_ and `MIT `_, available from `PyPI `_, the source code can be found on `GitHub `_, the documentation at `http://www.structlog.org/ `_. -``structlog`` targets Python 2.6, 2.7, 3.3, 3.4, and PyPy with no additional dependencies for core functionality. +``structlog`` targets Python 2.6, 2.7, 3.3 and newer, and PyPy with no additional dependencies for core functionality. If you need any help, visit us on ``#structlog`` on `Freenode `_! diff --git a/docs/changelog.rst b/docs/changelog.rst index 6c952ce8..045d911e 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -2,6 +2,7 @@ Changelog ========= +- :feature:`-` Officially support Python 3.5. - :feature:`-` Add :func:`structlog.ReturnLogger.failure` and :func:`structlog.PrintLogger.failure` as preparation for the new Twisted logging system. - :release:`15.2.0 <2015-06-10>` - :bug:`- major` Allow empty lists of processors. diff --git a/setup.py b/setup.py index d8c1e579..19c0691b 100644 --- a/setup.py +++ b/setup.py @@ -70,6 +70,7 @@ def find_meta(meta): "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", "Programming Language :: Python", "Topic :: Software Development :: Libraries :: Python Modules", ], diff --git a/tox.ini b/tox.ini index 662d41de..8dcd8d54 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = {py26,py27,py33,py34,pypy}-{threads,greenlets}, flake8-{py2,py3}, docs, manifest +envlist = {py26,py27,py33,py34,py35,pypy}-{threads,greenlets}, flake8-{py2,py3}, docs, manifest [testenv] deps = @@ -24,7 +24,7 @@ commands = flake8 structlog tests setup.py [testenv:flake8-py3] -basepython = py3: python3.4 +basepython = py3: python3.5 deps = flake8 commands = flake8 structlog tests setup.py From 6e9252dc478e19a76b54a86f85e6b64c5e60fbf7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 25 Sep 2015 13:02:40 +0200 Subject: [PATCH 0021/1520] Better setup.py dedup --- setup.py | 47 +++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/setup.py b/setup.py index 19c0691b..1a889ec5 100644 --- a/setup.py +++ b/setup.py @@ -9,8 +9,30 @@ import re +############################################################################### + NAME = "structlog" +PACKAGES = find_packages(exclude=['tests*']) META_PATH = os.path.join("structlog", "__init__.py") +KEYWORDS = ["logging", "structured", "structure", "log"] +CLASSIFIERS = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "License :: OSI Approved :: MIT License", + "Natural Language :: English", + "Operating System :: OS Independent", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.6", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python", + "Topic :: Software Development :: Libraries :: Python Modules", +] +INSTALL_REQUIRES = [] ############################################################################### @@ -53,25 +75,10 @@ def find_meta(meta): author_email=find_meta("email"), maintainer=find_meta("author"), maintainer_email=find_meta("email"), - long_description=read('README.rst'), - packages=find_packages(exclude=['tests*']), + long_description=read("README.rst"), + keywords=KEYWORDS, + packages=PACKAGES, + classifiers=CLASSIFIERS, + install_requires=INSTALL_REQUIRES, zip_safe=False, - keywords=["logging", "structured", "structure", "log"], - classifiers=[ - "Development Status :: 5 - Production/Stable", - "Intended Audience :: Developers", - "License :: OSI Approved :: Apache Software License", - "License :: OSI Approved :: MIT License", - "Natural Language :: English", - "Operating System :: OS Independent", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.6", - "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.3", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python", - "Topic :: Software Development :: Libraries :: Python Modules", - ], ) From 2c88212c3704b8e6b2d89512633fb9c6299ccf64 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 25 Sep 2015 13:12:42 +0200 Subject: [PATCH 0022/1520] Fix a bunch of links in docs --- docs/custom-wrappers.rst | 2 +- docs/logging-best-practices.rst | 6 +++--- docs/processors.rst | 2 +- docs/thread-local.rst | 2 +- docs/twisted.rst | 2 +- structlog/processors.py | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/custom-wrappers.rst b/docs/custom-wrappers.rst index b8eb3412..489240f2 100644 --- a/docs/custom-wrappers.rst +++ b/docs/custom-wrappers.rst @@ -44,4 +44,4 @@ You can observe the following: These two methods and one attribute is all you need to write own wrapper classes. -.. _DRY: http://en.wikipedia.org/wiki/Don%27t_repeat_yourself +.. _DRY: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself diff --git a/docs/logging-best-practices.rst b/docs/logging-best-practices.rst index 7d1286dc..c2de415f 100644 --- a/docs/logging-best-practices.rst +++ b/docs/logging-best-practices.rst @@ -94,9 +94,9 @@ Additionally, `Graylog's Extended Log Format`_ (GELF) allows for structured data .. _Logstash: https://www.elastic.co/products/logstash .. _logstash-forwarder: https://github.com/elastic/logstash-forwarder .. _RabbitMQ: http://www.rabbitmq.com -.. _`Graylog's Extended Log Format`: https://www.graylog.org/resources/gelf-2/ +.. _`Graylog's Extended Log Format`: https://www.graylog.org/resources/gelf/ .. _`daemon showdown`: https://web.archive.org/web/20130907200323/http://tech.cueup.com/blog/2013/03/08/running-daemons/ -.. _`standard out`: http://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29 +.. _`standard out`: https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29 .. _`they can be switched off`: http://blog.abhijeetr.com/2013/01/disable-rate-limiting-in-rsyslog-v5.html .. _`this post`: http://www.revsys.com/blog/2010/aug/26/centralized-logging-fun-and-profit/ .. _`this tutorial`: https://rubyists.github.io/2011/05/02/runit-for-ruby-and-everything-else.html @@ -104,6 +104,6 @@ Additionally, `Graylog's Extended Log Format`_ (GELF) allows for structured data .. _rsyslog: http://www.rsyslog.com .. _runit: http://smarden.org/runit/ .. _svlogd: http://smarden.org/runit/svlogd.8.html -.. _syslogd: http://en.wikipedia.org/wiki/Syslogd +.. _syslogd: https://en.wikipedia.org/wiki/Syslogd .. _tai64n: http://cr.yp.to/daemontools/tai64n.html .. _elasticsearch: https://www.elastic.co/products/elasticsearch diff --git a/docs/processors.rst b/docs/processors.rst index fe933105..d873a3af 100644 --- a/docs/processors.rst +++ b/docs/processors.rst @@ -58,7 +58,7 @@ and call ``log.msg('some_event', y=23)``, it results in the following call chain In this case, ``f4`` has to make sure it returns something ``wrapped_logger.msg`` can handle (see :ref:`adapting`). The simplest modification a processor can make is adding new values to the ``event_dict``. -Parsing human-readable timestamps is tedious, not so `UNIX timestamps `_ -- let's add one to each log entry! +Parsing human-readable timestamps is tedious, not so `UNIX timestamps `_ -- let's add one to each log entry! .. literalinclude:: code_examples/processors/timestamper.py :language: python diff --git a/docs/thread-local.rst b/docs/thread-local.rst index 17761e35..722fd80d 100644 --- a/docs/thread-local.rst +++ b/docs/thread-local.rst @@ -19,7 +19,7 @@ Immutability The behavior of copying itself, adding new values, and returning the result is useful for applications that keep somehow their own context using classes or closures. Twisted is a :ref:`fine example ` for that. Another possible approach is passing wrapped loggers around or log only within your view where you gather errors and events using return codes and exceptions. -If you are willing to do that, you should stick to it because `immutable state `_ is a very good thing\ [*]_. +If you are willing to do that, you should stick to it because `immutable state `_ is a very good thing\ [*]_. Sooner or later, global state and mutable data lead to unpleasant surprises. However, in the case of conventional web development, we realize that passing loggers around seems rather cumbersome, intrusive, and generally against the mainstream culture. diff --git a/docs/twisted.rst b/docs/twisted.rst index f211fdbd..235022d9 100644 --- a/docs/twisted.rst +++ b/docs/twisted.rst @@ -101,4 +101,4 @@ Suggested Configuration See also :doc:`logging-best-practices`. -.. _`standard out`: http://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29 +.. _`standard out`: https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29 diff --git a/structlog/processors.py b/structlog/processors.py index bec29394..cedc38b6 100644 --- a/structlog/processors.py +++ b/structlog/processors.py @@ -204,8 +204,8 @@ class TimeStamper(object): :doc:`logging-best-practices`. :param str format: strftime format string, or ``"iso"`` for `ISO 8601 - `_, or `None` for a `UNIX - timestamp `_. + `_, or `None` for a `UNIX + timestamp `_. :param bool utc: Whether timestamp should be in UTC or local time. :param str key: Target key in `event_dict` for added timestamps. From ccfc47e40d7c43435f5f874eeacb84db1995837d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 25 Sep 2015 13:06:59 +0200 Subject: [PATCH 0023/1520] Prepare 15.3.0 --- docs/changelog.rst | 1 + structlog/__init__.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index bd424ea8..2a486587 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -2,6 +2,7 @@ Changelog ========= +- :release:`15.3.0 <2015-09-25>` - :bug:`- major` Tolerate frames without a ``__name__``, better. - :feature:`-` Officially support Python 3.5. - :feature:`-` Add :func:`structlog.ReturnLogger.failure` and :func:`structlog.PrintLogger.failure` as preparation for the new Twisted logging system. diff --git a/structlog/__init__.py b/structlog/__init__.py index d0964d71..0760e747 100644 --- a/structlog/__init__.py +++ b/structlog/__init__.py @@ -44,7 +44,7 @@ twisted = None -__version__ = "15.3.0.dev0" +__version__ = "15.3.0" __title__ = "structlog" __description__ = "Structured Logging for Python" From 4c1c86f7b0b39b911882ba6f72fa3a3ab0dc5337 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 25 Sep 2015 13:29:14 +0200 Subject: [PATCH 0024/1520] Start new release cycle --- structlog/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/structlog/__init__.py b/structlog/__init__.py index 0760e747..d563a62a 100644 --- a/structlog/__init__.py +++ b/structlog/__init__.py @@ -44,7 +44,7 @@ twisted = None -__version__ = "15.3.0" +__version__ = "15.4.0.dev0" __title__ = "structlog" __description__ = "Structured Logging for Python" From 34326ebb1c58f2ef7001e48322e9b29c95e41bff Mon Sep 17 00:00:00 2001 From: Justin Wood Date: Tue, 15 Sep 2015 12:19:37 -0400 Subject: [PATCH 0025/1520] Fix assert-is-always-True in twisted tests --- tests/test_twisted.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_twisted.py b/tests/test_twisted.py index e8117fb9..44736f4a 100644 --- a/tests/test_twisted.py +++ b/tests/test_twisted.py @@ -101,12 +101,12 @@ def test_handlesFailures(self): Extracts failures and events. """ assert ( - Failure(ValueError()), "foo", {} == + (Failure(ValueError()), "foo", {}) == _extractStuffAndWhy({"_why": "foo", "_stuff": Failure(ValueError())}) ) assert ( - Failure(ValueError()), "error", {} == + (Failure(ValueError()), "error", {}) == _extractStuffAndWhy({"_stuff": Failure(ValueError())}) ) From 6b376ba2df33e3c363bdeb9441dd7770241707a1 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 28 Sep 2015 13:55:12 +0200 Subject: [PATCH 0026/1520] Use single Failure instance so we can compare --- tests/test_twisted.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/test_twisted.py b/tests/test_twisted.py index 44736f4a..c7aeead1 100644 --- a/tests/test_twisted.py +++ b/tests/test_twisted.py @@ -4,11 +4,10 @@ from __future__ import absolute_import, division, print_function -import pytest -pytest.importorskip('twisted') # noqa - import json +import pytest + from pretend import call_recorder from twisted.python.failure import Failure, NoCurrentExceptionError from twisted.python.log import ILogObserver @@ -100,14 +99,15 @@ def test_handlesFailures(self): """ Extracts failures and events. """ + f = Failure(ValueError()) assert ( - (Failure(ValueError()), "foo", {}) == + (f, "foo", {}) == _extractStuffAndWhy({"_why": "foo", - "_stuff": Failure(ValueError())}) + "_stuff": f}) ) assert ( - (Failure(ValueError()), "error", {}) == - _extractStuffAndWhy({"_stuff": Failure(ValueError())}) + (f, None, {}) == + _extractStuffAndWhy({"_stuff": f}) ) def test_handlesMissingFailure(self): From cff77a52c52cdeb4fbe4fa34262de73142a95a0f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 16 Oct 2015 15:32:56 +0200 Subject: [PATCH 0027/1520] Move source into src --- .coveragerc | 8 ++++++-- .gitignore | 2 +- docs/conf.py | 4 ++-- setup.py | 5 +++-- {structlog => src/structlog}/__init__.py | 0 {structlog => src/structlog}/_base.py | 0 {structlog => src/structlog}/_compat.py | 8 +------- {structlog => src/structlog}/_config.py | 0 {structlog => src/structlog}/_exc.py | 0 {structlog => src/structlog}/_frames.py | 0 {structlog => src/structlog}/_generic.py | 0 {structlog => src/structlog}/_loggers.py | 0 {structlog => src/structlog}/_utils.py | 0 {structlog => src/structlog}/processors.py | 0 {structlog => src/structlog}/stdlib.py | 0 {structlog => src/structlog}/threadlocal.py | 0 {structlog => src/structlog}/twisted.py | 0 tox.ini | 21 ++++++++++++++++----- 18 files changed, 29 insertions(+), 19 deletions(-) rename {structlog => src/structlog}/__init__.py (100%) rename {structlog => src/structlog}/_base.py (100%) rename {structlog => src/structlog}/_compat.py (90%) rename {structlog => src/structlog}/_config.py (100%) rename {structlog => src/structlog}/_exc.py (100%) rename {structlog => src/structlog}/_frames.py (100%) rename {structlog => src/structlog}/_generic.py (100%) rename {structlog => src/structlog}/_loggers.py (100%) rename {structlog => src/structlog}/_utils.py (100%) rename {structlog => src/structlog}/processors.py (100%) rename {structlog => src/structlog}/stdlib.py (100%) rename {structlog => src/structlog}/threadlocal.py (100%) rename {structlog => src/structlog}/twisted.py (100%) diff --git a/.coveragerc b/.coveragerc index 6585d666..3c342ab0 100644 --- a/.coveragerc +++ b/.coveragerc @@ -2,7 +2,11 @@ branch = True source = structlog +[paths] +source = + src/structlog + .tox/*/lib/python*/site-packages/structlog + .tox/pypy*/site-packages/structlog + [report] show_missing = True -omit = - structlog/_compat.py diff --git a/.gitignore b/.gitignore index 40462405..76de8bc3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -.coverage +.coverage* .tox structlog.egg-info htmlcov diff --git a/docs/conf.py b/docs/conf.py index 0076cff1..ceaedadc 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -86,9 +86,9 @@ def find_version(*file_paths): # built documents. # # The short X.Y version. -version = find_version('..', 'structlog', '__init__.py') +version = find_version("..", "src", "structlog", "__init__.py") # The full version, including alpha/beta/rc tags. -release = '' +release = "" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/setup.py b/setup.py index 1a889ec5..6463a61c 100644 --- a/setup.py +++ b/setup.py @@ -12,8 +12,8 @@ ############################################################################### NAME = "structlog" -PACKAGES = find_packages(exclude=['tests*']) -META_PATH = os.path.join("structlog", "__init__.py") +PACKAGES = find_packages(where="src", exclude=['tests*']) +META_PATH = os.path.join("src", "structlog", "__init__.py") KEYWORDS = ["logging", "structured", "structure", "log"] CLASSIFIERS = [ "Development Status :: 5 - Production/Stable", @@ -78,6 +78,7 @@ def find_meta(meta): long_description=read("README.rst"), keywords=KEYWORDS, packages=PACKAGES, + package_dir={"": "src"}, classifiers=CLASSIFIERS, install_requires=INSTALL_REQUIRES, zip_safe=False, diff --git a/structlog/__init__.py b/src/structlog/__init__.py similarity index 100% rename from structlog/__init__.py rename to src/structlog/__init__.py diff --git a/structlog/_base.py b/src/structlog/_base.py similarity index 100% rename from structlog/_base.py rename to src/structlog/_base.py diff --git a/structlog/_compat.py b/src/structlog/_compat.py similarity index 90% rename from structlog/_compat.py rename to src/structlog/_compat.py index 3effb835..9d12a3ac 100644 --- a/structlog/_compat.py +++ b/src/structlog/_compat.py @@ -27,7 +27,7 @@ if sys.version_info[:2] == (2, 6): try: from ordereddict import OrderedDict - except ImportError: + except ImportError: # pragma: nocover class OrderedDict(object): def __init__(self, *args, **kw): raise NotImplementedError( @@ -52,9 +52,3 @@ def __init__(self, *args, **kw): text_type = unicode binary_type = str unicode_type = unicode - -def with_metaclass(meta, *bases): - """ - Create a base class with a metaclass. - """ - return meta("NewBase", bases, {}) diff --git a/structlog/_config.py b/src/structlog/_config.py similarity index 100% rename from structlog/_config.py rename to src/structlog/_config.py diff --git a/structlog/_exc.py b/src/structlog/_exc.py similarity index 100% rename from structlog/_exc.py rename to src/structlog/_exc.py diff --git a/structlog/_frames.py b/src/structlog/_frames.py similarity index 100% rename from structlog/_frames.py rename to src/structlog/_frames.py diff --git a/structlog/_generic.py b/src/structlog/_generic.py similarity index 100% rename from structlog/_generic.py rename to src/structlog/_generic.py diff --git a/structlog/_loggers.py b/src/structlog/_loggers.py similarity index 100% rename from structlog/_loggers.py rename to src/structlog/_loggers.py diff --git a/structlog/_utils.py b/src/structlog/_utils.py similarity index 100% rename from structlog/_utils.py rename to src/structlog/_utils.py diff --git a/structlog/processors.py b/src/structlog/processors.py similarity index 100% rename from structlog/processors.py rename to src/structlog/processors.py diff --git a/structlog/stdlib.py b/src/structlog/stdlib.py similarity index 100% rename from structlog/stdlib.py rename to src/structlog/stdlib.py diff --git a/structlog/threadlocal.py b/src/structlog/threadlocal.py similarity index 100% rename from structlog/threadlocal.py rename to src/structlog/threadlocal.py diff --git a/structlog/twisted.py b/src/structlog/twisted.py similarity index 100% rename from structlog/twisted.py rename to src/structlog/twisted.py diff --git a/tox.ini b/tox.ini index 8dcd8d54..a8bc4f84 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = {py26,py27,py33,py34,py35,pypy}-{threads,greenlets}, flake8-{py2,py3}, docs, manifest +envlist = coverage-clean, {py26,py27,py33,py34,py35,pypy}-{threads,greenlets}, flake8-{py2,py3}, docs, manifest, coverage-report [testenv] deps = @@ -15,19 +15,18 @@ setenv = PYTHONHASHSEED = 0 threads: TRICKING_TOX_INTO_GENERATING_AN_ENVIRONMENT = 1 commands = - coverage run {envbindir}/py.test tests - coverage report + coverage run --parallel -m pytest tests [testenv:flake8-py2] deps = flake8 commands = - flake8 structlog tests setup.py + flake8 src tests setup.py [testenv:flake8-py3] basepython = py3: python3.5 deps = flake8 commands = - flake8 structlog tests setup.py + flake8 src tests setup.py [testenv:docs] setenv = @@ -45,3 +44,15 @@ deps = check-manifest commands = check-manifest + +[testenv:coverage-clean] +deps = coverage +skip_install = true +commands = coverage erase + +[testenv:coverage-report] +deps = coverage +skip_install = true +commands = + coverage combine + coverage report From 3f6b1dcf15fbcf56d2d4db9d91834e2f060dbbe2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 16 Oct 2015 15:37:16 +0200 Subject: [PATCH 0028/1520] Add IRCCloud badge --- README.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.rst b/README.rst index a9e6c3ea..b5b9d14f 100644 --- a/README.rst +++ b/README.rst @@ -8,6 +8,9 @@ structlog: Structured Logging for Python .. image:: https://codecov.io/github/hynek/structlog/coverage.svg?branch=master :target: https://codecov.io/github/hynek/structlog?branch=master +.. image:: https://www.irccloud.com/invite-svg?channel=%23structlog&hostname=irc.freenode.net&port=6697&ssl=1 + :target: https://www.irccloud.com/invite?channel=%23structlog&hostname=irc.freenode.net&port=6697&ssl=1 + ``structlog`` makes structured logging in Python easy by *augmenting* your *existing* logger. It allows you to split your log entries up into key/value pairs and build them incrementally without annoying boilerplate code. From ba375080718d381c337738cb2df4ef1f6d094b03 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 18 Oct 2015 12:05:24 +0200 Subject: [PATCH 0029/1520] Clean up nocovers --- setup.py | 2 +- src/structlog/stdlib.py | 4 ++-- src/structlog/threadlocal.py | 4 ++-- src/structlog/twisted.py | 2 +- tests/test_threadlocal.py | 16 +++++++++++++--- tox.ini | 2 +- 6 files changed, 20 insertions(+), 10 deletions(-) diff --git a/setup.py b/setup.py index 6463a61c..0aadd584 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ ############################################################################### NAME = "structlog" -PACKAGES = find_packages(where="src", exclude=['tests*']) +PACKAGES = find_packages(where="src") META_PATH = os.path.join("src", "structlog", "__init__.py") KEYWORDS = ["logging", "structured", "structure", "log"] CLASSIFIERS = [ diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index c94717e2..e6a8d699 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -30,7 +30,7 @@ def findCaller(self, stack_info=False): This logger gets set as the default one when using LoggerFactory. """ f, name = _find_first_app_frame_and_name(['logging']) - if PY3: # pragma: nocover + if PY3: if stack_info: sinfo = _format_stack(f) else: @@ -165,7 +165,7 @@ def hasHandlers(self): Exists only in Python 3. """ - return self._logger.hasHandlers() # pragma: nocover + return self._logger.hasHandlers() def callHandlers(self, record): """ diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index b0cd0399..7d842a42 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -15,9 +15,9 @@ try: from greenlet import getcurrent -except ImportError: # pragma: nocover +except ImportError: from threading import local as ThreadLocal -else: # pragma: nocover +else: from weakref import WeakKeyDictionary class ThreadLocal(object): diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index 8102789c..9594696b 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -109,7 +109,7 @@ def _extractStuffAndWhy(eventDict): # formatting. Avoid log.err() to dump another traceback into the log. if isinstance(_stuff, BaseException): _stuff = Failure(_stuff) - if PY2: # pragma: nocover we don't care about the implicit else + if PY2: sys.exc_clear() return _stuff, _why, eventDict diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py index 0d9b3801..2897978e 100644 --- a/tests/test_threadlocal.py +++ b/tests/test_threadlocal.py @@ -189,14 +189,24 @@ def test_delattr(self, D): assert 42 == d._dict["delattr"] del d.__class__._tl.dict_ + def test_delattr_missing(self, D): + """ + __delattr__ on an inexisting attribute raises AttributeError. + """ + d = D() + with pytest.raises(AttributeError) as e: + d._tl.__delattr__("does_not_exist") + assert "does_not_exist" == e.value.args[0] + def test_del(self, D): """ ___del__ is proxied to the wrapped class. """ d = D() - d['del'] = 13 - del d['del'] - assert 'del' not in d._dict + d["del"] = 13 + assert 13 == d._dict["del"] + del d["del"] + assert "del" not in d._dict def test_new_class(self, D): """ diff --git a/tox.ini b/tox.ini index a8bc4f84..3f1c20ce 100644 --- a/tox.ini +++ b/tox.ini @@ -15,7 +15,7 @@ setenv = PYTHONHASHSEED = 0 threads: TRICKING_TOX_INTO_GENERATING_AN_ENVIRONMENT = 1 commands = - coverage run --parallel -m pytest tests + coverage run --parallel -m pytest tests {posargs} [testenv:flake8-py2] deps = flake8 From cea0a69a8760ff6b716dfa98aaf22126fcd6e33d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 20 Oct 2015 07:06:53 +0200 Subject: [PATCH 0030/1520] Make coverage work again --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index d16b8b74..d0285236 100644 --- a/.travis.yml +++ b/.travis.yml @@ -54,4 +54,5 @@ before_install: - pip install codecov after_success: + - tox -e coverage-report - codecov From f169d6b0c89cd326a9cff84f257fa06125716623 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 2 Dec 2015 07:39:52 +0100 Subject: [PATCH 0031/1520] Add some py.test options --- setup.cfg | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/setup.cfg b/setup.cfg index 71bcbac1..f8a6c9a6 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,7 +1,8 @@ [pytest] -minversion = 2.6 +minversion = 2.8 strict = true -norecursedirs = build dist .* *.egg docs +addopts = -ra +testpaths = tests [wheel] # we're pure-python From 00b81314ccad58eca79825c80d5896edc5dd1c7a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 2 Dec 2015 08:24:51 +0100 Subject: [PATCH 0032/1520] Fix Python 2.6 tests in CI Twisted 15.5.0 is 2.7-only. --- tox.ini | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tox.ini b/tox.ini index 3f1c20ce..11a3f0a1 100644 --- a/tox.ini +++ b/tox.ini @@ -4,12 +4,13 @@ envlist = coverage-clean, {py26,py27,py33,py34,py35,pypy}-{threads,greenlets}, f [testenv] deps = coverage - py26: ordereddict - greenlets: greenlet freezegun>=0.2.8 + greenlets: greenlet pretend pytest - twisted + py26: ordereddict + py26: twisted<15.5.0 + py27,py33,py34,py35,pypy: twisted setenv = PYTHONHASHSEED = 0 From d215ea60016699ea643c55d1d965cf2c46f68a3c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 2 Dec 2015 14:58:46 +0100 Subject: [PATCH 0033/1520] Refactor documentation --- AUTHORS.rst | 27 +---- CHANGELOG.rst | 198 ++++++++++++++++++++++++++++++++ CODE_OF_CONDUCT.rst | 25 ++++ CONTRIBUTING.rst | 49 ++++---- docs/backward-compatibility.rst | 16 +++ docs/changelog.rst | 76 +----------- docs/conf.py | 5 - docs/custom-wrappers.rst | 4 +- docs/index.rst | 1 + docs/license.rst | 4 +- 10 files changed, 271 insertions(+), 134 deletions(-) create mode 100644 CHANGELOG.rst create mode 100644 CODE_OF_CONDUCT.rst create mode 100644 docs/backward-compatibility.rst diff --git a/AUTHORS.rst b/AUTHORS.rst index 41e48584..1b3375b3 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -2,34 +2,11 @@ Authors ------- ``structlog`` is written and maintained by `Hynek Schlawack `_. -It’s inspired by previous work done by `Jean-Paul Calderone `_ and `David Reid `_. +It’s inspired by previous work done by `Jean-Paul Calderone `_ and `David Reid `_. The development is kindly supported by `Variomedia AG `_. -The following folks helped forming ``structlog`` into what it is now: - -- `Alex Gaynor `_ -- `Christopher Armstrong `_ -- `Daniel Lindsley `_ -- `David Reid `_ -- `Donald Stufft `_ -- `Fran Fitzpatrick `_ -- `George-Cristian Bîrzan `_ -- `Glyph `_ -- `Holger Krekel `_ -- `Itamar Turner-Trauring `_ -- `Jack Pearkes `_ -- `Jean-Paul Calderone `_ -- `Justin Wood (Callek) `_ -- `Lakshmi Kannan `_ -- `Lynn Root `_ -- `Mathieu Leplatre `_ -- `Noah Kantrowitz `_ -- `Tarek Ziadé `_ -- `Thomas Heinrichsdobler `_ -- `Tom Lazar `_ -- `Wouter Bolsterlee `_ - +A full list of contributors can be found on `GitHub `_. Some of them disapprove of the addition of thread local context data. :) diff --git a/CHANGELOG.rst b/CHANGELOG.rst new file mode 100644 index 00000000..e14ca8c7 --- /dev/null +++ b/CHANGELOG.rst @@ -0,0 +1,198 @@ +Changelog +========= + +Versions are year-based with a strict :doc:`backward-compatibility` policy. +The third digit is only for regressions. + + +15.4.0 (UNRELEASED) +------------------- + + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +*none* + + +Deprecations: +^^^^^^^^^^^^^ + +*none* + + +Changes: +^^^^^^^^ + +*none* + + +15.3.0 (2015-09-25) +------------------- + +Changes: +^^^^^^^^ + +- Tolerate frames without a ``__name__``, better. + [`58 `_] +- Officially support Python 3.5. +- Add :func:`structlog.ReturnLogger.failure` and :func:`structlog.PrintLogger.failure` as preparation for the new Twisted logging system. + + +15.2.0 (2015-06-10) +------------------- + +Changes: +^^^^^^^^ + +- Allow empty lists of processors. + This is a valid use case since `#26 `_ has been merged. + Before, supplying an empty list resulted in the defaults being used. +- Prevent Twisted's ``log.err`` from quoting strings rendered by :class:`structlog.twisted.JSONRenderer`. +- Better support of :meth:`logging.Logger.exception` within ``structlog``. + [`52 `_] +- Add option to specify target key in :class:`structlog.processors.TimeStamper` processor. + [`51 `_] + + +15.1.0 (2015-02-24) +------------------- + +Changes: +^^^^^^^^ + +- Tolerate frames without a ``__name__``. + + +15.0.0 (2015-01-23) +------------------- + +Changes: +^^^^^^^^ + +- Add :func:`structlog.stdlib.add_log_level` and :func:`structlog.stdlib.add_logger_name` processors. + [`44 `_] +- Add :func:`structlog.stdlib.BoundLogger.log`. + [`42 `_] +- Pass positional arguments to stdlib wrapped loggers that use string formatting. + [`19 `_] +- ``structlog`` is now dually licensed under the `Apache License, Version 2 `_ and the `MIT `_ license. + Therefore it is now legal to use structlog with `GPLv2 `_-licensed projects. + [`28 `_] +- Add :func:`structlog.stdlib.BoundLogger.exception`. + [`22 `_] + + +0.4.2 (2014-07-26) +------------------ + +Changes: +^^^^^^^^ + +- Fixed a memory leak in greenlet code that emulates thread locals. + It shouldn't matter in practice unless you use multiple wrapped dicts within one program that is rather unlikely. + [`8 `_] +- :class:`structlog.PrintLogger` now is thread-safe. +- Test Twisted-related code on Python 3 (with some caveats). +- Drop support for Python 3.2. + There is no justification to add complexity for a Python version that nobody uses. + If you are one of the `0.350% `_ that use Python 3.2, please stick to the 0.4 branch; critical bugs will still be fixed. +- Officially support Python 3.4. +- Allow final processor to return a dictionary. + See :ref:`adapting`. + [`26 `_] +- ``from structlog import *`` works now (but you still shouldn't use it). + + +0.4.1 (2013-12-19) +------------------ + +Changes: +^^^^^^^^ + +- Don't cache proxied methods in :class:`structlog.threadlocal._ThreadLocalDictWrapper`. + This doesn't affect regular users. +- Various doc fixes. + + +0.4.0 (2013-11-10) +------------------ + + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Changes: +^^^^^^^^ + +- Add :class:`structlog.processors.StackInfoRenderer` for adding stack information to log entries without involving exceptions. + Also added it to default processor chain. + [`6 `_] +- Allow optional positional arguments for :func:`structlog.get_logger` that are passed to logger factories. + The standard library factory uses this for explicit logger naming. + [`12 `_] +- Add :class:`structlog.processors.ExceptionPrettyPrinter` for development and testing when multiline log entries aren't just acceptable but even helpful. +- Allow the standard library name guesser to ignore certain frame names. + This is useful together with frameworks. +- Add meta data (e.g. function names, line numbers) extraction for wrapped stdlib loggers. + [`5 `_] + + +0.3.2 (2013-09-27) +------------------ + +Changes: +^^^^^^^^ + +- Fix stdlib's name guessing. + + +0.3.1 (2013-09-26) +------------------ + +Changes: +^^^^^^^^ + +- Add forgotten :class:`structlog.processors.TimeStamper` to API documentation. + + +0.3.0 (2013-09-23) +------------------ + +Changes: +^^^^^^^^ + +- Greatly enhanced and polished the documentation and added a new theme based on Write The Docs, requests, and Flask. +- Add Python Standard Library-specific BoundLogger that has an explicit API instead of intercepting unknown method calls. + See :class:`structlog.stdlib.BoundLogger`. +- :class:`structlog.ReturnLogger` now allows arbitrary positional and keyword arguments. +- Add Twisted-specific BoundLogger that has an explicit API instead of intercepting unknown method calls. + See :class:`structlog.twisted.BoundLogger`. +- Allow logger proxies that are returned by :func:`structlog.get_logger` and :func:`structlog.wrap_logger` to cache the BoundLogger they assemble according to configuration on first use. + See :doc:`performance` and the `cache_logger_on_first_use` of :func:`structlog.configure` and :func:`structlog.wrap_logger`. +- Extract a common base class for loggers that does nothing except keeping the context state. + This makes writing custom loggers much easier and more straight-forward. + See :class:`structlog.BoundLoggerBase`. + + +0.2.0 (2013-09-17) +------------------ + +Changes: +^^^^^^^^ + +- Promote to stable, thus henceforth a strict backward compatibility policy is put into effect. + See :ref:`contributing`. +- Add `key_order` option to :class:`structlog.processors.KeyValueRenderer` for more predictable log entries with any `dict` class. +- :class:`structlog.PrintLogger` now uses proper I/O routines and is thus viable not only for examples but also for production. +- :doc:`Enhance Twisted support ` by offering JSONification of non-structlog log entries. +- Allow for custom serialization in :class:`structlog.twisted.JSONRenderer` without abusing ``__repr__``. + + +0.1.0 (2013-09-16) +------------------ + +Changes: +^^^^^^^^ + +- Initial release. diff --git a/CODE_OF_CONDUCT.rst b/CODE_OF_CONDUCT.rst new file mode 100644 index 00000000..f902e7c6 --- /dev/null +++ b/CODE_OF_CONDUCT.rst @@ -0,0 +1,25 @@ +Contributor Code of Conduct +=========================== + +As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. + +We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery +* Personal attacks +* Trolling or insulting/derogatory comments +* Public or private harassment +* Publishing other's private information, such as physical or electronic addresses, without explicit permission +* Other unethical or unprofessional conduct. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. +By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. +Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. + +This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. + +This Code of Conduct is adapted from the `Contributor Covenant `_, version 1.2.0, available at http://contributor-covenant.org/version/1/2/0/. diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index b93daf40..4eda63b8 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -1,40 +1,39 @@ How To Contribute ================= -Every open source project lives from the generous help by contributors that sacrifice their time and structlog is no different. +Every open source project lives from the generous help by contributors that sacrifice their time and ``structlog`` is no different. -To make participation as pleasant as possible, this project adheres to the `Code of Conduct`_ by the Python Software Foundation. +Here are a few guidelines to get you started: -Here are a few hints and rules to get you started: - -- Add yourself to the AUTHORS.rst_ file in an alphabetical fashion. - Every contribution is valuable and shall be credited. +- To run the test suite, all you need is a recent tox_. + It will ensure the test suite runs with all dependencies against all Python versions just as it will on `Travis CI`_. + If you lack some Python version, you can can always limit the environments like ``tox -e py27,py35`` (in that case you may want to look into pyenv_ that makes it very easy to install many different Python versions in parallel). +- Make sure your changes pass our CI. + You won't get any feedback until it's green unless you ask for it. - If your change is noteworthy, add an entry to the changelog_. - No contribution is too small; please submit as many fixes for typos and grammar bloopers as you can! -- Don’t *ever* break backward compatibility. - ``structlog`` is an infrastructure library people rely on; therefore highest care must be put into avoiding breakage on updates. - If it ever *has* to happen for higher reasons, structlog will follow the proven procedures_ of the Twisted project. +- Don’t break `backward compatibility`_. - *Always* add tests and docs for your code. - This is a hard rule; patches with missing tests or documentation won’t be merged – if a feature is not tested or documented, it doesn’t exist. + This is a hard rule; patches with missing tests or documentation won’t be merged. +- Write `good test docstrings`_. - Obey `PEP 8`_ and `PEP 257`_. - Twisted-specific modules use CamelCase. -- Write `good commit messages`_. - -.. note:: - If you have something great but aren’t sure whether it adheres -- or even can adhere -- to the rules above: **please submit a pull request anyway**! +- If you address review feedback, make sure to bump the pull request. + Maintainers don’t receive notifications if you push new commits. - In the best case, we can mold it into something, in the worst case the pull request gets politely closed. - There’s absolutely nothing to fear. +Please note that this project is released with a Contributor `Code of Conduct`_. +By participating in this project you agree to abide by its terms. +Please report any harm to `Hynek Schlawack `_ in any way you find appropriate. -Thank you for considering to contribute to structlog! -If you have any question or concerns, feel free to reach out to me -- there is also a ``#structlog`` channel on freenode_. +Thank you for considering to contribute to ``structlog``! +.. _me: https://hynek.me/about/ .. _`PEP 8`: https://www.python.org/dev/peps/pep-0008/ .. _`PEP 257`: https://www.python.org/dev/peps/pep-0257/ -.. _`good commit messages`: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html -.. _`Code of Conduct`: https://www.python.org/psf/codeofconduct/ -.. _changelog: https://github.com/hynek/structlog/blob/master/docs/changelog.rst -.. _AUTHORS.rst: https://github.com/hynek/structlog/blob/master/AUTHORS.rst -.. _procedures: https://twistedmatrix.com/trac/wiki/CompatibilityPolicy -.. _`freenode`: https://freenode.net +.. _`good test docstrings`: https://jml.io/pages/test-docstrings.html +.. _`Code of Conduct`: https://github.com/hynek/structlog/blob/master/CODE_OF_CONDUCT.rst +.. _changelog: https://github.com/hynek/structlog/blob/master/CHANGELOG.rst +.. _`backward compatibility`: https://structlog.readthedocs.org/en/latest/backward-compatibility.html +.. _`tox`: https://testrun.org/tox/ +.. _`Travis CI`: https://travis-ci.org/ +.. _pyenv: https://github.com/yyuu/pyenv diff --git a/docs/backward-compatibility.rst b/docs/backward-compatibility.rst new file mode 100644 index 00000000..e5f09164 --- /dev/null +++ b/docs/backward-compatibility.rst @@ -0,0 +1,16 @@ +Backward Compatibility +====================== + +``structlog`` has a very strong backward compatibility policy that is inspired by the one of the `Twisted framework `_. + +Put simply, you shouldn't ever be afraid to upgrade ``structlog`` if you're using its public APIs. +If there will ever be need to break compatibility, it will be announced in the :doc:`changelog` and raise deprecation warning for a year before it's finally really broken. + + +.. _exemption: + +.. warning:: + + You cannot however rely on the default settings. + They may be adjusted in the future to provide a better experience when starting to use ``structlog``. + So please make sure to **always** properly configure your applications. diff --git a/docs/changelog.rst b/docs/changelog.rst index 2a486587..565b0521 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,75 +1 @@ -========= -Changelog -========= - -- :release:`15.3.0 <2015-09-25>` -- :bug:`- major` Tolerate frames without a ``__name__``, better. -- :feature:`-` Officially support Python 3.5. -- :feature:`-` Add :func:`structlog.ReturnLogger.failure` and :func:`structlog.PrintLogger.failure` as preparation for the new Twisted logging system. -- :release:`15.2.0 <2015-06-10>` -- :bug:`- major` Allow empty lists of processors. - This is a valid use case since `#26 `_ has been merged. - Before, supplying an empty list resulted in the defaults being used. -- :bug:`- major` Prevent Twisted's ``log.err`` from quoting strings rendered by :class:`structlog.twisted.JSONRenderer`. -- :feature:`52` Better support of :meth:`logging.Logger.exception` within ``structlog``. -- :feature:`51` Add option to specify target key in :class:`structlog.processors.TimeStamper` processor. -- :release:`15.1.0 <2015-02-24>` -- :bug:`- major` Tolerate frames without a ``__name__``. -- :release:`15.0.0 <2015-01-23>` -- :feature:`44` Add :func:`structlog.stdlib.add_log_level` and :func:`structlog.stdlib.add_logger_name` processors. -- :feature:`42` Add :func:`structlog.stdlib.BoundLogger.log`. -- :feature:`19` Pass positional arguments to stdlib wrapped loggers that use string formatting. -- :feature:`28` structlog is now dually licensed under the `Apache License, Version 2 `_ and the `MIT `_ license. - Therefore it is now legal to use structlog with `GPLv2 `_-licensed projects. -- :feature:`22` Add :func:`structlog.stdlib.BoundLogger.exception`. -- :release:`0.4.2 <2014-07-26>` -- :bug:`8` Fixed a memory leak in greenlet code that emulates thread locals. - It shouldn't matter in practice unless you use multiple wrapped dicts within one program that is rather unlikely. -- :feature:`-` :class:`structlog.PrintLogger` now is thread-safe. -- :feature:`-` Test Twisted-related code on Python 3 (with some caveats). -- :feature:`-` Drop support for Python 3.2. - There is no justification to add complexity for a Python version that nobody uses. - If you are one of the `0.350% `_ that use Python 3.2, please stick to the 0.4 branch; critical bugs will still be fixed. -- :feature:`-` Officially support Python 3.4. -- :feature:`26` Allow final processor to return a dictionary. - See :ref:`adapting`. -- :bug:`-` ``from structlog import *`` works now (but you still shouldn't use it). -- :release:`0.4.1 <2013-12-19>` -- :bug:`-` Don't cache proxied methods in :class:`structlog.threadlocal._ThreadLocalDictWrapper`. - This doesn't affect regular users. -- :bug:`-` Various doc fixes. -- :release:`0.4.0 <2013-11-10>` -- :feature:`6` Add :class:`structlog.processors.StackInfoRenderer` for adding stack information to log entries without involving exceptions. - Also added it to default processor chain. -- :feature:`12` Allow optional positional arguments for :func:`structlog.get_logger` that are passed to logger factories. - The standard library factory uses this for explicit logger naming. -- :feature:`-` Add :class:`structlog.processors.ExceptionPrettyPrinter` for development and testing when multiline log entries aren't just acceptable but even helpful. -- :feature:`-` Allow the standard library name guesser to ignore certain frame names. - This is useful together with frameworks. -- :feature:`5` Add meta data (e.g. function names, line numbers) extraction for wrapped stdlib loggers. -- :release:`0.3.2 <2013-09-27>` -- :bug:`-` Fix stdlib's name guessing. -- :release:`0.3.1 <2013-09-26>` -- :bug:`-` Add forgotten :class:`structlog.processors.TimeStamper` to API documentation. -- :release:`0.3.0 <2013-09-23>` -- :support:`-` Greatly enhanced and polished the documentation and added a new theme based on Write The Docs, requests, and Flask. - See :doc:`license`. -- :feature:`-` Add Python Standard Library-specific BoundLogger that has an explicit API instead of intercepting unknown method calls. - See :class:`structlog.stdlib.BoundLogger`. -- :feature:`-` :class:`structlog.ReturnLogger` now allows arbitrary positional and keyword arguments. -- :feature:`-` Add Twisted-specific BoundLogger that has an explicit API instead of intercepting unknown method calls. - See :class:`structlog.twisted.BoundLogger`. -- :feature:`-` Allow logger proxies that are returned by :func:`structlog.get_logger` and :func:`structlog.wrap_logger` to cache the BoundLogger they assemble according to configuration on first use. - See :doc:`performance` and the `cache_logger_on_first_use` of :func:`structlog.configure` and :func:`structlog.wrap_logger`. -- :feature:`-` Extract a common base class for loggers that does nothing except keeping the context state. - This makes writing custom loggers much easier and more straight-forward. - See :class:`structlog.BoundLoggerBase`. -- :release:`0.2.0 <2013-09-17>` -- :feature:`-` Promote to stable, thus henceforth a strict backward compatibility policy is put into effect. - See :ref:`contributing`. -- :feature:`-` Add `key_order` option to :class:`structlog.processors.KeyValueRenderer` for more predictable log entries with any `dict` class. -- :feature:`-` :class:`structlog.PrintLogger` now uses proper I/O routines and is thus viable not only for examples but also for production. -- :feature:`-` :doc:`Enhance Twisted support ` by offering JSONification of non-structlog log entries. -- :feature:`-` Allow for custom serialization in :class:`structlog.twisted.JSONRenderer` without abusing ``__repr__``. -- :release:`0.1.0 <2013-09-16>` -- :feature:`-` Initial work. +.. include:: ../CHANGELOG.rst diff --git a/docs/conf.py b/docs/conf.py index ceaedadc..c8fe82f0 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -53,17 +53,12 @@ def find_version(*file_paths): # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ - 'releases', 'sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', 'sphinx.ext.viewcode', ] -# 'releases' (changelog) settings -releases_issue_uri = "https://github.com/hynek/structlog/issues/%s" -releases_release_uri = "https://github.com/hynek/structlog/tree/%s" - # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/docs/custom-wrappers.rst b/docs/custom-wrappers.rst index 489240f2..92d0bbe4 100644 --- a/docs/custom-wrappers.rst +++ b/docs/custom-wrappers.rst @@ -1,13 +1,13 @@ Custom Wrappers =============== -structlog comes with a generic bound logger called :class:`structlog.BoundLogger` that can be used to wrap any logger class you fancy. +``structlog`` comes with a generic bound logger called :class:`structlog.BoundLogger` that can be used to wrap any logger class you fancy. It does so by intercepting unknown method names and proxying them to the wrapped logger. This works fine, except that it has a performance penalty and the API of :class:`~structlog.BoundLogger` isn't clear from reading the documentation because large parts depend on the wrapped logger. An additional reason is that you may want to have semantically meaningful log method names that add meta data to log entries as it is fit (see example below). -To solve that, structlog offers you to use an own wrapper class which you can configure using :func:`structlog.configure`. +To solve that, ``structlog`` offers you to use an own wrapper class which you can configure using :func:`structlog.configure`. And to make it easier for you, it comes with the class :class:`structlog.BoundLoggerBase` which takes care of all data binding duties so you just add your log methods if you choose to sub-class it. diff --git a/docs/index.rst b/docs/index.rst index f17ebb7a..eef4af36 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -82,6 +82,7 @@ Project Information .. toctree:: :maxdepth: 1 + backward-compatibility contributing license changelog diff --git a/docs/license.rst b/docs/license.rst index 95cf7b8f..fc176661 100644 --- a/docs/license.rst +++ b/docs/license.rst @@ -8,8 +8,8 @@ For more legal details, see `this issue `_. -- `MIT `_. +- `Apache License 2.0 `_ +- `MIT `_ .. _authors: From 9dd4d657bb1d6371d4e2936c8169f94b9bc9bad6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 2 Dec 2015 16:19:26 +0100 Subject: [PATCH 0034/1520] Add ``serializer`` parameter to structlog.processors.JSONRenderer --- .travis.yml | 4 +-- CHANGELOG.rst | 2 +- dev-requirements.txt | 10 +++---- docs-requirements.txt | 1 - docs/performance.rst | 9 ++++++ src/structlog/processors.py | 36 +++++++++++----------- tests/test_processors.py | 60 +++++++++++++++++++++++++++++++++++-- tox.ini | 31 +++++++------------ 8 files changed, 102 insertions(+), 51 deletions(-) diff --git a/.travis.yml b/.travis.yml index d0285236..e84f6c3e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,10 +35,8 @@ matrix: # Meta - - python: "2.7" - env: TOXENV=flake8-py2 - python: "3.5" - env: TOXENV=flake8-py3 + env: TOXENV=flake8 - python: "2.7" env: TOXENV=manifest - python: "2.7" diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e14ca8c7..13a642bd 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,7 +24,7 @@ Deprecations: Changes: ^^^^^^^^ -*none* +- Add ``serializer`` parameter to :func:`structlog.processors.JSONRenderer` which allows for using different (possibly faster) JSON encoders than the standard library. 15.3.0 (2015-09-25) diff --git a/dev-requirements.txt b/dev-requirements.txt index 36702310..e8165ec7 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,8 +1,6 @@ --r docs-requirements.txt -check-manifest -freezegun +-e . +coverage +freezegun>=0.2.8 pretend -pytest-cov pytest -twine -wheel +simplejson diff --git a/docs-requirements.txt b/docs-requirements.txt index 06624feb..ddd60f88 100644 --- a/docs-requirements.txt +++ b/docs-requirements.txt @@ -1,5 +1,4 @@ -e . -releases sphinx sphinx_rtd_theme twisted diff --git a/docs/performance.rst b/docs/performance.rst index 1618908a..2cce90e3 100644 --- a/docs/performance.rst +++ b/docs/performance.rst @@ -35,3 +35,12 @@ Here are a few hints how to get most out of ``structlog`` in production: configure(cache_logger_on_first_use=True) This has the only drawback is that later calls on :func:`~structlog.configure` don't have any effect on already cached loggers -- that shouldn't matter outside of testing though. +#. Use a faster JSON serializer than the standard library. + Possible alternatives are among others simplejson_, UltraJSON_, or RapidJSON_ (Python 3 only):: + + structlog.processors.JSONRenderer(serializer=rapidjson.dumps) + + +.. _simplejson: https://simplejson.readthedocs.org/ +.. _UltraJSON: https://github.com/esnme/ultrajson/ +.. _RapidJSON: https://pypi.python.org/pypi/python-rapidjson/ diff --git a/src/structlog/processors.py b/src/structlog/processors.py index cedc38b6..50090887 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -112,6 +112,11 @@ class JSONRenderer(object): Render the `event_dict` using `json.dumps(event_dict, **json_kw)`. :param json_kw: Are passed unmodified to `json.dumps()`. + :param callable serializer: A :meth:`json.dumps`-compatible callable that + will be used to format the string. This can be used to use alternative + JSON encoders like `simplejson + `_ or `RapidJSON + `_. >>> from structlog.processors import JSONRenderer >>> JSONRenderer(sort_keys=True)(None, None, {'a': 42, 'b': [1, 2, 3]}) @@ -139,31 +144,28 @@ class JSONRenderer(object): .. versionchanged:: 0.2.0 Added support for ``__structlog__`` serialization method. """ - def __init__(self, **dumps_kw): + def __init__(self, serializer=json.dumps, **dumps_kw): self._dumps_kw = dumps_kw + self._dumps = serializer def __call__(self, logger, name, event_dict): - return json.dumps(event_dict, cls=_JSONFallbackEncoder, - **self._dumps_kw) + return self._dumps(event_dict, default=_json_fallback_handler, + **self._dumps_kw) -class _JSONFallbackEncoder(json.JSONEncoder): +def _json_fallback_handler(obj): """ Serialize custom datatypes and pass the rest to __structlog__ & repr(). """ - def default(self, obj): - """ - Serialize obj with repr(obj) as fallback. - """ - # circular imports :( - from structlog.threadlocal import _ThreadLocalDictWrapper - if isinstance(obj, _ThreadLocalDictWrapper): - return obj._dict - else: - try: - return obj.__structlog__() - except AttributeError: - return repr(obj) + # circular imports :( + from structlog.threadlocal import _ThreadLocalDictWrapper + if isinstance(obj, _ThreadLocalDictWrapper): + return obj._dict + else: + try: + return obj.__structlog__() + except AttributeError: + return repr(obj) def format_exc_info(logger, name, event_dict): diff --git a/tests/test_processors.py b/tests/test_processors.py index 99bffdd0..c6d80ac2 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -9,6 +9,12 @@ import sys import pytest +import simplejson + +try: + import rapidjson +except ImportError: + rapidjson = None from freezegun import freeze_time @@ -22,7 +28,7 @@ StackInfoRenderer, TimeStamper, UnicodeEncoder, - _JSONFallbackEncoder, + _json_fallback_handler, format_exc_info, ) from structlog.threadlocal import wrap_dict @@ -44,12 +50,18 @@ def __repr__(self): class TestKeyValueRenderer(object): def test_sort_keys(self, event_dict): + """ + Keys are sorted if sort_keys is set. + """ assert ( r"a= b=[3, 4] x=7 y='test' z=(1, 2)" == KeyValueRenderer(sort_keys=True)(None, None, event_dict) ) def test_order_complete(self, event_dict): + """ + Orders keys according to key_order. + """ assert ( r"y='test' b=[3, 4] a= z=(1, 2) x=7" == KeyValueRenderer(key_order=['y', 'b', 'a', 'z', 'x']) @@ -80,12 +92,18 @@ def test_order_extra(self, event_dict): ) def test_random_order(self, event_dict): + """ + No special ordering doesn't blow up. + """ rv = KeyValueRenderer()(None, None, event_dict) assert isinstance(rv, str) class TestJSONRenderer(object): def test_renders_json(self, event_dict): + """ + Renders a predictable JSON string. + """ assert ( r'{"a": "", "b": [3, 4], "x": 7, "y": "test", "z": ' r'[1, 2]}' == @@ -93,16 +111,52 @@ def test_renders_json(self, event_dict): ) def test_FallbackEncoder_handles_ThreadLocalDictWrapped_dicts(self): + """ + Our fallback handling handles properly ThreadLocalDictWrapper values. + """ s = json.dumps(wrap_dict(dict)({'a': 42}), - cls=_JSONFallbackEncoder) + default=_json_fallback_handler) assert '{"a": 42}' == s def test_FallbackEncoder_falls_back(self): + """ + The fallback handler uses repr if it doesn't know the type. + """ s = json.dumps({'date': datetime.date(1980, 3, 25)}, - cls=_JSONFallbackEncoder,) + default=_json_fallback_handler) assert '{"date": "datetime.date(1980, 3, 25)"}' == s + def test_serializer(self): + """ + A custom serializer is used if specified. + """ + jr = JSONRenderer(serializer=lambda obj, **kw: {"a": 42}) + obj = object() + + assert {"a": 42} == jr(None, None, obj) + + def test_simplejson(self, event_dict): + """ + Integration test with simplejson. + """ + jr = JSONRenderer(serializer=simplejson.dumps) + + assert { + 'a': '', 'b': [3, 4], 'x': 7, 'y': 'test', 'z': [1, 2] + } == json.loads(jr(None, None, event_dict)) + + @pytest.mark.skipif(rapidjson is None, reason="rapidjson is missing.") + def test_rapidjson(self, event_dict): + """ + Integration test with python-rapidjson. + """ + jr = JSONRenderer(serializer=rapidjson.dumps) + + assert { + 'a': '', 'b': [3, 4], 'x': 7, 'y': 'test', 'z': [1, 2] + } == json.loads(jr(None, None, event_dict)) + class TestTimeStamper(object): def test_disallowsNonUTCUNIXTimestamps(self): diff --git a/tox.ini b/tox.ini index 11a3f0a1..2e804795 100644 --- a/tox.ini +++ b/tox.ini @@ -1,33 +1,25 @@ [tox] -envlist = coverage-clean, {py26,py27,py33,py34,py35,pypy}-{threads,greenlets}, flake8-{py2,py3}, docs, manifest, coverage-report +envlist = coverage-clean,{py26,py27,py33,py34,py35,pypy}-{threads,greenlets},flake8,docs,manifest,coverage-report [testenv] deps = - coverage - freezegun>=0.2.8 + -rdev-requirements.txt greenlets: greenlet - pretend - pytest py26: ordereddict py26: twisted<15.5.0 py27,py33,py34,py35,pypy: twisted + py35: python-rapidjson setenv = PYTHONHASHSEED = 0 threads: TRICKING_TOX_INTO_GENERATING_AN_ENVIRONMENT = 1 -commands = - coverage run --parallel -m pytest tests {posargs} +commands = coverage run --parallel -m pytest {posargs} -[testenv:flake8-py2] +[testenv:flake8] +skip_install = true +basepython = python3.5 deps = flake8 -commands = - flake8 src tests setup.py - -[testenv:flake8-py3] -basepython = py3: python3.5 -deps = flake8 -commands = - flake8 src tests setup.py +commands = flake8 src tests setup.py [testenv:docs] setenv = @@ -41,10 +33,9 @@ commands = sphinx-build -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html [testenv:manifest] -deps = - check-manifest -commands = - check-manifest +skip_install = true +deps = check-manifest +commands = check-manifest [testenv:coverage-clean] deps = coverage From 0569222f59a7422dc17fc71aaa8ecd36f9555960 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 2 Dec 2015 16:40:09 +0100 Subject: [PATCH 0035/1520] Remove releases from docs target --- tox.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/tox.ini b/tox.ini index 2e804795..7eb73171 100644 --- a/tox.ini +++ b/tox.ini @@ -25,7 +25,6 @@ commands = flake8 src tests setup.py setenv = PYTHONHASHSEED = 0 deps = - releases sphinx twisted commands = From 571a82492f25e6ac810917c8c4751f820ccef945 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 2 Dec 2015 17:23:37 +0100 Subject: [PATCH 0036/1520] Add UnicodeDecoder to decode byte string fields --- CHANGELOG.rst | 1 + docs/api.rst | 2 ++ src/structlog/processors.py | 48 ++++++++++++++++++++++++++----------- tests/test_processors.py | 24 +++++++++++++++++++ 4 files changed, 61 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 13a642bd..b61b1ea4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,6 +24,7 @@ Deprecations: Changes: ^^^^^^^^ +- Add :class:`structlog.processors.UnicodeDecoder` that will decode all byte string values in an event dictionary to Unicode. - Add ``serializer`` parameter to :func:`structlog.processors.JSONRenderer` which allows for using different (possibly faster) JSON encoders than the standard library. diff --git a/docs/api.rst b/docs/api.rst index 710c1959..e5bb57f8 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -60,6 +60,8 @@ structlog Package .. autoclass:: KeyValueRenderer +.. autoclass:: UnicodeDecoder + .. autoclass:: UnicodeEncoder .. autofunction:: format_exc_info diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 50090887..63390c25 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -78,21 +78,12 @@ class UnicodeEncoder(object): """ Encode unicode values in `event_dict`. - :param str encoding: Encoding to encode to (default: ``'utf-8'``. + :param str encoding: Encoding to encode to (default: ``'utf-8'``). :param str errors: How to cope with encoding errors (default ``'backslashreplace'``). - Useful for :class:`KeyValueRenderer` if you don't want to see u-prefixes: - - >>> from structlog.processors import KeyValueRenderer, UnicodeEncoder - >>> KeyValueRenderer()(None, None, {'foo': u'bar'}) - "foo=u'bar'" - >>> KeyValueRenderer()(None, None, - ... UnicodeEncoder()(None, None, {'foo': u'bar'})) - "foo='bar'" - - or :class:`JSONRenderer` and :class:`structlog.twisted.JSONRenderer` to - make sure user-supplied strings don't break the renderer. + Useful if you're running Python 2 as otherwise ``u"abc"`` will be rendered + as ``'u"abc"'``. Just put it in the processor chain before the renderer. """ @@ -107,6 +98,32 @@ def __call__(self, logger, name, event_dict): return event_dict +class UnicodeDecoder(object): + """ + Decode byte string values in `event_dict`. + + :param str encoding: Encoding to decode from (default: ``'utf-8'``). + :param str errors: How to cope with encoding errors (default: + ``'replace'``). + + Useful if you're running Python 3 as otherwise ``b"abc"`` will be rendered + as ``'b"abc"'``. + + Just put it in the processor chain before the renderer. + + .. versionadded:: 15.4.0 + """ + def __init__(self, encoding='utf-8', errors='replace'): + self._encoding = encoding + self._errors = errors + + def __call__(self, logger, name, event_dict): + for key, value in event_dict.items(): + if isinstance(value, bytes): + event_dict[key] = value.decode(self._encoding, self._errors) + return event_dict + + class JSONRenderer(object): """ Render the `event_dict` using `json.dumps(event_dict, **json_kw)`. @@ -141,8 +158,11 @@ class JSONRenderer(object): the standard library JSON module knows about -- like in this example a list. - .. versionchanged:: 0.2.0 - Added support for ``__structlog__`` serialization method. + .. versionadded:: 0.2.0 + Support for ``__structlog__`` serialization method. + + .. versionadded:: 15.4.0 + ``serializer`` parameter. """ def __init__(self, serializer=json.dumps, **dumps_kw): self._dumps_kw = dumps_kw diff --git a/tests/test_processors.py b/tests/test_processors.py index c6d80ac2..8c7f0265 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -27,6 +27,7 @@ KeyValueRenderer, StackInfoRenderer, TimeStamper, + UnicodeDecoder, UnicodeEncoder, _json_fallback_handler, format_exc_info, @@ -240,6 +241,29 @@ def test_bytes_nop(self): assert {"foo": b"b\xc3\xa4r"} == ue(None, None, {"foo": b"b\xc3\xa4r"}) +class TestUnicodeDecoder(object): + def test_decodes(self): + """ + Byte strings get decoded (as UTF-8 by default). + """ + ud = UnicodeDecoder() + assert {"foo": u"b\xe4r"} == ud(None, None, {"foo": b"b\xc3\xa4r"}) + + def test_passes_arguments(self): + """ + Encoding options are passed into the encoding call. + """ + ud = UnicodeDecoder("utf-8", "ignore") + assert {"foo": u""} == ud(None, None, {"foo": b"\xa1\xa4"}) + + def test_bytes_nop(self): + """ + If the value is already unicode, don't do anything. + """ + ud = UnicodeDecoder() + assert {"foo": u"b\u2013r"} == ud(None, None, {"foo": u"b\u2013r"}) + + class TestExceptionPrettyPrinter(object): def test_stdout_by_default(self): """ From 2122c1ab890b2cfe9e0cb225a7a263ebcaac93aa Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 4 Dec 2015 15:21:59 +0100 Subject: [PATCH 0037/1520] Use six for compatibility after all --- AUTHORS.rst | 9 --------- CHANGELOG.rst | 1 + setup.py | 2 +- src/structlog/_compat.py | 25 ++++--------------------- src/structlog/processors.py | 4 ++-- 5 files changed, 8 insertions(+), 33 deletions(-) diff --git a/AUTHORS.rst b/AUTHORS.rst index 1b3375b3..ca6a7e30 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -8,12 +8,3 @@ The development is kindly supported by `Variomedia AG `_. Some of them disapprove of the addition of thread local context data. :) - - -Third Party Code -^^^^^^^^^^^^^^^^ - -The compatibility code that makes this software run on both Python 2 and 3 is heavily inspired and partly copy and pasted from the MIT-licensed six_ by Benjamin Peterson. -The only reason why it’s not used as a dependency is to avoid any runtime dependency in the first place. - -.. _six: https://bitbucket.org/gutworth/six/ diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b61b1ea4..7d5cc057 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,6 +24,7 @@ Deprecations: Changes: ^^^^^^^^ +- Use `six `_ for compatibility. - Add :class:`structlog.processors.UnicodeDecoder` that will decode all byte string values in an event dictionary to Unicode. - Add ``serializer`` parameter to :func:`structlog.processors.JSONRenderer` which allows for using different (possibly faster) JSON encoders than the standard library. diff --git a/setup.py b/setup.py index 0aadd584..abb4f7ac 100644 --- a/setup.py +++ b/setup.py @@ -32,7 +32,7 @@ "Programming Language :: Python", "Topic :: Software Development :: Libraries :: Python Modules", ] -INSTALL_REQUIRES = [] +INSTALL_REQUIRES = ["six"] ############################################################################### diff --git a/src/structlog/_compat.py b/src/structlog/_compat.py index 9d12a3ac..0c03ae6a 100644 --- a/src/structlog/_compat.py +++ b/src/structlog/_compat.py @@ -3,10 +3,7 @@ # repository for complete details. """ -Python 2 + 3 compatibility utilities. - -Derived from MIT-licensed https://bitbucket.org/gutworth/six/ which is -Copyright 2010-2013 by Benjamin Peterson. +Compatibility utilities. """ from __future__ import absolute_import, division, print_function @@ -15,8 +12,9 @@ import sys import types -PY2 = sys.version_info[0] == 2 -PY3 = sys.version_info[0] == 3 +from six import ( + PY2, PY3, string_types, integer_types, class_types, text_type +) try: @@ -37,18 +35,3 @@ def __init__(self, *args, **kw): ) else: from collections import OrderedDict - -if PY3: - string_types = str, - integer_types = int, - class_types = type, - text_type = str - binary_type = bytes - unicode_type = str -else: - string_types = basestring, - integer_types = (int, long) - class_types = (type, types.ClassType) - text_type = unicode - binary_type = str - unicode_type = unicode diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 63390c25..350782f0 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -15,7 +15,7 @@ import sys import time -from structlog._compat import unicode_type +from structlog._compat import text_type from structlog._frames import ( _find_first_app_frame_and_name, _format_exception, @@ -93,7 +93,7 @@ def __init__(self, encoding='utf-8', errors='backslashreplace'): def __call__(self, logger, name, event_dict): for key, value in event_dict.items(): - if isinstance(value, unicode_type): + if isinstance(value, text_type): event_dict[key] = value.encode(self._encoding, self._errors) return event_dict From a046d44c7947bbb78111cdf607a7307880e3b7c4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 4 Dec 2015 15:24:33 +0100 Subject: [PATCH 0038/1520] Move DropEvent into a public module for nicer tracebacks --- src/structlog/__init__.py | 2 +- src/structlog/_base.py | 2 +- src/structlog/{_exc.py => exceptions.py} | 0 src/structlog/stdlib.py | 2 +- tests/test_base.py | 2 +- tests/test_stdlib.py | 2 +- 6 files changed, 5 insertions(+), 5 deletions(-) rename src/structlog/{_exc.py => exceptions.py} (100%) diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index d563a62a..72589a43 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -24,7 +24,7 @@ reset_defaults, wrap_logger, ) -from structlog._exc import ( +from structlog.exceptions import ( DropEvent, ) from structlog._generic import ( diff --git a/src/structlog/_base.py b/src/structlog/_base.py index e83d069a..40f0a82b 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -9,7 +9,7 @@ from __future__ import absolute_import, division, print_function from structlog._compat import string_types -from structlog._exc import DropEvent +from structlog.exceptions import DropEvent class BoundLoggerBase(object): diff --git a/src/structlog/_exc.py b/src/structlog/exceptions.py similarity index 100% rename from src/structlog/_exc.py rename to src/structlog/exceptions.py diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index e6a8d699..c7d3ac2f 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -15,8 +15,8 @@ from structlog._base import BoundLoggerBase from structlog._compat import PY3 -from structlog._exc import DropEvent from structlog._frames import _find_first_app_frame_and_name, _format_stack +from structlog.exceptions import DropEvent class _FixedFindCallerLogger(logging.Logger): diff --git a/tests/test_base.py b/tests/test_base.py index 8a242fba..d51ff557 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -10,8 +10,8 @@ from structlog._base import BoundLoggerBase from structlog._config import _CONFIG -from structlog._exc import DropEvent from structlog._loggers import ReturnLogger +from structlog.exceptions import DropEvent from structlog.processors import KeyValueRenderer diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 2ae8f095..869098c4 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -11,8 +11,8 @@ import pytest from pretend import call_recorder -from structlog._exc import DropEvent from structlog._loggers import ReturnLogger +from structlog.exceptions import DropEvent from structlog.stdlib import ( BoundLogger, CRITICAL, From 361077aea6c4b9cb1b24d52d7359b2f25ef1691e Mon Sep 17 00:00:00 2001 From: djeebus Date: Mon, 7 Dec 2015 00:20:13 -0800 Subject: [PATCH 0039/1520] Protect from scenarios where all frames should be ignored --- src/structlog/_frames.py | 3 +++ tests/test_frames.py | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/src/structlog/_frames.py b/src/structlog/_frames.py index c0da4cbc..a3b73b48 100644 --- a/src/structlog/_frames.py +++ b/src/structlog/_frames.py @@ -39,6 +39,9 @@ def _find_first_app_frame_and_name(additional_ignores=None): f = sys._getframe() name = f.f_globals.get("__name__") or "?" while any(name.startswith(i) for i in ignores): + if f.f_back is None: + name = "?" + break f = f.f_back name = f.f_globals.get("__name__") or "?" return f, name diff --git a/tests/test_frames.py b/tests/test_frames.py index 9852f9cd..db04a4aa 100644 --- a/tests/test_frames.py +++ b/tests/test_frames.py @@ -70,6 +70,15 @@ def test_tolerates_name_explicitly_None_manyframe(self, monkeypatch): f, n = _find_first_app_frame_and_name() assert ((f1, "?") == (f, n)) + def test_tolerates_f_back_is_None(self, monkeypatch): + """ + Use ``?`` if all frames are in ignored frames. + """ + f1 = stub(f_globals={'__name__': 'structlog'}, f_back=None) + monkeypatch.setattr(structlog._frames.sys, "_getframe", lambda: f1) + f, n = _find_first_app_frame_and_name() + assert ((f1, "?") == (f, n)) + @pytest.fixture def exc_info(): From 46f83983d45e40193c5019113ff8ba7b7dfa8f8b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 8 Dec 2015 16:01:10 +0100 Subject: [PATCH 0040/1520] Repo janitoring --- CODE_OF_CONDUCT.rst | 24 ++++++++++++++++++------ CONTRIBUTING.rst | 2 ++ setup.py | 2 ++ tox.ini | 7 ++++++- 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/CODE_OF_CONDUCT.rst b/CODE_OF_CONDUCT.rst index f902e7c6..16233970 100644 --- a/CODE_OF_CONDUCT.rst +++ b/CODE_OF_CONDUCT.rst @@ -11,15 +11,27 @@ Examples of unacceptable behavior by participants include: * Personal attacks * Trolling or insulting/derogatory comments * Public or private harassment -* Publishing other's private information, such as physical or electronic addresses, without explicit permission -* Other unethical or unprofessional conduct. +* Publishing other's private information, such as physical or electronic + addresses, without explicit permission +* Other unethical or unprofessional conduct + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. -This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting a project maintainer at hs@ox.cx. +All complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. +Maintainers are obligated to maintain confidentiality with regard to the reporter of an +incident. + -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. +This Code of Conduct is adapted from the `Contributor Covenant `_, +version 1.3.0, available at +`http://contributor-covenant.org/version/1/3/0/ `_. -This Code of Conduct is adapted from the `Contributor Covenant `_, version 1.2.0, available at http://contributor-covenant.org/version/1/2/0/. +.. _homepage: http://contributor-covenant.org +.. _version: http://contributor-covenant.org/version/1/3/0/ diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 4eda63b8..787902ff 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -5,12 +5,14 @@ Every open source project lives from the generous help by contributors that sacr Here are a few guidelines to get you started: +- Try to limit each pull request to one change only. - To run the test suite, all you need is a recent tox_. It will ensure the test suite runs with all dependencies against all Python versions just as it will on `Travis CI`_. If you lack some Python version, you can can always limit the environments like ``tox -e py27,py35`` (in that case you may want to look into pyenv_ that makes it very easy to install many different Python versions in parallel). - Make sure your changes pass our CI. You won't get any feedback until it's green unless you ask for it. - If your change is noteworthy, add an entry to the changelog_. + Use present tense, semantic newlines, and add link to your pull request. - No contribution is too small; please submit as many fixes for typos and grammar bloopers as you can! - Don’t break `backward compatibility`_. - *Always* add tests and docs for your code. diff --git a/setup.py b/setup.py index abb4f7ac..c466f355 100644 --- a/setup.py +++ b/setup.py @@ -29,6 +29,8 @@ "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", "Programming Language :: Python", "Topic :: Software Development :: Libraries :: Python Modules", ] diff --git a/tox.ini b/tox.ini index 7eb73171..1a170db0 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,7 @@ [tox] envlist = coverage-clean,{py26,py27,py33,py34,py35,pypy}-{threads,greenlets},flake8,docs,manifest,coverage-report + [testenv] deps = -rdev-requirements.txt @@ -9,18 +10,19 @@ deps = py26: twisted<15.5.0 py27,py33,py34,py35,pypy: twisted py35: python-rapidjson - setenv = PYTHONHASHSEED = 0 threads: TRICKING_TOX_INTO_GENERATING_AN_ENVIRONMENT = 1 commands = coverage run --parallel -m pytest {posargs} + [testenv:flake8] skip_install = true basepython = python3.5 deps = flake8 commands = flake8 src tests setup.py + [testenv:docs] setenv = PYTHONHASHSEED = 0 @@ -31,16 +33,19 @@ commands = sphinx-build -W -b html -d {envtmpdir}/doctrees docs docs/_build/html sphinx-build -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html + [testenv:manifest] skip_install = true deps = check-manifest commands = check-manifest + [testenv:coverage-clean] deps = coverage skip_install = true commands = coverage erase + [testenv:coverage-report] deps = coverage skip_install = true From 728004a243c6827e9271b6412fc50215fd289b95 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 8 Dec 2015 16:11:45 +0100 Subject: [PATCH 0041/1520] Make the CHANGELOG a proper RST file (remove Sphinxisms) --- CHANGELOG.rst | 60 ++++++++++++++++++++++++--------------------------- setup.py | 2 +- 2 files changed, 29 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7d5cc057..6227ea57 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,7 +1,7 @@ Changelog ========= -Versions are year-based with a strict :doc:`backward-compatibility` policy. +Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. @@ -25,8 +25,8 @@ Changes: ^^^^^^^^ - Use `six `_ for compatibility. -- Add :class:`structlog.processors.UnicodeDecoder` that will decode all byte string values in an event dictionary to Unicode. -- Add ``serializer`` parameter to :func:`structlog.processors.JSONRenderer` which allows for using different (possibly faster) JSON encoders than the standard library. +- Add ``structlog.processors.UnicodeDecoder`` that will decode all byte string values in an event dictionary to Unicode. +- Add ``serializer`` parameter to ``structlog.processors.JSONRenderer`` which allows for using different (possibly faster) JSON encoders than the standard library. 15.3.0 (2015-09-25) @@ -38,7 +38,7 @@ Changes: - Tolerate frames without a ``__name__``, better. [`58 `_] - Officially support Python 3.5. -- Add :func:`structlog.ReturnLogger.failure` and :func:`structlog.PrintLogger.failure` as preparation for the new Twisted logging system. +- Add ``structlog.ReturnLogger.failure`` and ``structlog.PrintLogger.failure`` as preparation for the new Twisted logging system. 15.2.0 (2015-06-10) @@ -50,10 +50,10 @@ Changes: - Allow empty lists of processors. This is a valid use case since `#26 `_ has been merged. Before, supplying an empty list resulted in the defaults being used. -- Prevent Twisted's ``log.err`` from quoting strings rendered by :class:`structlog.twisted.JSONRenderer`. -- Better support of :meth:`logging.Logger.exception` within ``structlog``. +- Prevent Twisted's ``log.err`` from quoting strings rendered by ``structlog.twisted.JSONRenderer``. +- Better support of ``logging.Logger.exception`` within ``structlog``. [`52 `_] -- Add option to specify target key in :class:`structlog.processors.TimeStamper` processor. +- Add option to specify target key in ``structlog.processors.TimeStamper`` processor. [`51 `_] @@ -72,16 +72,16 @@ Changes: Changes: ^^^^^^^^ -- Add :func:`structlog.stdlib.add_log_level` and :func:`structlog.stdlib.add_logger_name` processors. +- Add ``structlog.stdlib.add_log_level`` and ``structlog.stdlib.add_logger_name`` processors. [`44 `_] -- Add :func:`structlog.stdlib.BoundLogger.log`. +- Add ``structlog.stdlib.BoundLogger.log``. [`42 `_] - Pass positional arguments to stdlib wrapped loggers that use string formatting. [`19 `_] - ``structlog`` is now dually licensed under the `Apache License, Version 2 `_ and the `MIT `_ license. Therefore it is now legal to use structlog with `GPLv2 `_-licensed projects. [`28 `_] -- Add :func:`structlog.stdlib.BoundLogger.exception`. +- Add ``structlog.stdlib.BoundLogger.exception``. [`22 `_] @@ -94,14 +94,14 @@ Changes: - Fixed a memory leak in greenlet code that emulates thread locals. It shouldn't matter in practice unless you use multiple wrapped dicts within one program that is rather unlikely. [`8 `_] -- :class:`structlog.PrintLogger` now is thread-safe. +- ``structlog.PrintLogger`` now is thread-safe. - Test Twisted-related code on Python 3 (with some caveats). - Drop support for Python 3.2. There is no justification to add complexity for a Python version that nobody uses. If you are one of the `0.350% `_ that use Python 3.2, please stick to the 0.4 branch; critical bugs will still be fixed. - Officially support Python 3.4. - Allow final processor to return a dictionary. - See :ref:`adapting`. + See the adapting chapter. [`26 `_] - ``from structlog import *`` works now (but you still shouldn't use it). @@ -112,7 +112,7 @@ Changes: Changes: ^^^^^^^^ -- Don't cache proxied methods in :class:`structlog.threadlocal._ThreadLocalDictWrapper`. +- Don't cache proxied methods in ``structlog.threadlocal._ThreadLocalDictWrapper``. This doesn't affect regular users. - Various doc fixes. @@ -127,13 +127,13 @@ Backward-incompatible changes: Changes: ^^^^^^^^ -- Add :class:`structlog.processors.StackInfoRenderer` for adding stack information to log entries without involving exceptions. +- Add ``structlog.processors.StackInfoRenderer`` for adding stack information to log entries without involving exceptions. Also added it to default processor chain. [`6 `_] -- Allow optional positional arguments for :func:`structlog.get_logger` that are passed to logger factories. +- Allow optional positional arguments for ``structlog.get_logger`` that are passed to logger factories. The standard library factory uses this for explicit logger naming. [`12 `_] -- Add :class:`structlog.processors.ExceptionPrettyPrinter` for development and testing when multiline log entries aren't just acceptable but even helpful. +- Add ``structlog.processors.ExceptionPrettyPrinter`` for development and testing when multiline log entries aren't just acceptable but even helpful. - Allow the standard library name guesser to ignore certain frame names. This is useful together with frameworks. - Add meta data (e.g. function names, line numbers) extraction for wrapped stdlib loggers. @@ -155,7 +155,7 @@ Changes: Changes: ^^^^^^^^ -- Add forgotten :class:`structlog.processors.TimeStamper` to API documentation. +- Add forgotten ``structlog.processors.TimeStamper`` to API documentation. 0.3.0 (2013-09-23) @@ -166,15 +166,15 @@ Changes: - Greatly enhanced and polished the documentation and added a new theme based on Write The Docs, requests, and Flask. - Add Python Standard Library-specific BoundLogger that has an explicit API instead of intercepting unknown method calls. - See :class:`structlog.stdlib.BoundLogger`. -- :class:`structlog.ReturnLogger` now allows arbitrary positional and keyword arguments. + See ``structlog.stdlib.BoundLogger``. +- ``structlog.ReturnLogger`` now allows arbitrary positional and keyword arguments. - Add Twisted-specific BoundLogger that has an explicit API instead of intercepting unknown method calls. - See :class:`structlog.twisted.BoundLogger`. -- Allow logger proxies that are returned by :func:`structlog.get_logger` and :func:`structlog.wrap_logger` to cache the BoundLogger they assemble according to configuration on first use. - See :doc:`performance` and the `cache_logger_on_first_use` of :func:`structlog.configure` and :func:`structlog.wrap_logger`. + See ``structlog.twisted.BoundLogger``. +- Allow logger proxies that are returned by ``structlog.get_logger`` and ``structlog.wrap_logger`` to cache the BoundLogger they assemble according to configuration on first use. + See the chapter on performance and the ``cache_logger_on_first_use`` argument of ``structlog.configure`` and ``structlog.wrap_logger``. - Extract a common base class for loggers that does nothing except keeping the context state. This makes writing custom loggers much easier and more straight-forward. - See :class:`structlog.BoundLoggerBase`. + See ``structlog.BoundLoggerBase``. 0.2.0 (2013-09-17) @@ -184,17 +184,13 @@ Changes: ^^^^^^^^ - Promote to stable, thus henceforth a strict backward compatibility policy is put into effect. - See :ref:`contributing`. -- Add `key_order` option to :class:`structlog.processors.KeyValueRenderer` for more predictable log entries with any `dict` class. -- :class:`structlog.PrintLogger` now uses proper I/O routines and is thus viable not only for examples but also for production. -- :doc:`Enhance Twisted support ` by offering JSONification of non-structlog log entries. -- Allow for custom serialization in :class:`structlog.twisted.JSONRenderer` without abusing ``__repr__``. +- Add ``key_order`` option to ``structlog.processors.KeyValueRenderer`` for more predictable log entries with any ``dict`` class. +- ``structlog.PrintLogger`` now uses proper I/O routines and is thus viable not only for examples but also for production. +- Enhance Twisted support by offering JSONification of non-structlog log entries. +- Allow for custom serialization in ``structlog.twisted.JSONRenderer`` without abusing ``__repr__``. 0.1.0 (2013-09-16) ------------------ -Changes: -^^^^^^^^ - -- Initial release. +Initial release. diff --git a/setup.py b/setup.py index c466f355..3c43438b 100644 --- a/setup.py +++ b/setup.py @@ -77,7 +77,7 @@ def find_meta(meta): author_email=find_meta("email"), maintainer=find_meta("author"), maintainer_email=find_meta("email"), - long_description=read("README.rst"), + long_description=read("README.rst") + "\n\n" + read("CHANGELOG.rst"), keywords=KEYWORDS, packages=PACKAGES, package_dir={"": "src"}, From e6cbad261fe24a0825e7f0eecd1e30804719a9c2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 9 Dec 2015 09:05:37 +0100 Subject: [PATCH 0042/1520] Simplify setup.py some more --- setup.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index 3c43438b..5eda3901 100644 --- a/setup.py +++ b/setup.py @@ -12,8 +12,6 @@ ############################################################################### NAME = "structlog" -PACKAGES = find_packages(where="src") -META_PATH = os.path.join("src", "structlog", "__init__.py") KEYWORDS = ["logging", "structured", "structure", "log"] CLASSIFIERS = [ "Development Status :: 5 - Production/Stable", @@ -49,8 +47,17 @@ def read(*parts): with codecs.open(os.path.join(HERE, *parts), "rb", "utf-8") as f: return f.read() +try: + PACKAGES +except NameError: + PACKAGES = find_packages(where="src") -META_FILE = read(META_PATH) +try: + META_PATH +except NameError: + META_PATH = os.path.join(HERE, "src", NAME, "__init__.py") +finally: + META_FILE = read(META_PATH) def find_meta(meta): @@ -77,7 +84,11 @@ def find_meta(meta): author_email=find_meta("email"), maintainer=find_meta("author"), maintainer_email=find_meta("email"), - long_description=read("README.rst") + "\n\n" + read("CHANGELOG.rst"), + long_description=( + read("README.rst") + "\n\n" + + read("AUTHORS.rst") + "\n\n" + + read("CHANGELOG.rst") + ), keywords=KEYWORDS, packages=PACKAGES, package_dir={"": "src"}, From 6d56821b7c917214a06f86e4ad5fad3b031bc53b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 9 Dec 2015 09:59:21 +0100 Subject: [PATCH 0043/1520] Test RapidJSON on other 3.x too --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 1a170db0..05cba96f 100644 --- a/tox.ini +++ b/tox.ini @@ -9,7 +9,7 @@ deps = py26: ordereddict py26: twisted<15.5.0 py27,py33,py34,py35,pypy: twisted - py35: python-rapidjson + py33,py34,py35: python-rapidjson setenv = PYTHONHASHSEED = 0 threads: TRICKING_TOX_INTO_GENERATING_AN_ENVIRONMENT = 1 From 19bb0dbba49cd45332127e8e2befd723f480e114 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 19 Dec 2015 13:57:00 +0100 Subject: [PATCH 0044/1520] janitoring --- .travis.yml | 2 + AUTHORS.rst | 4 +- CHANGELOG.rst | 2 +- LICENSE.mit | 2 +- README.rst | 2 +- docs/api.rst | 4 +- docs/conf.py | 103 ++++++++++++++++++++++++------------------------- docs/index.rst | 2 +- tox.ini | 10 ++++- 9 files changed, 69 insertions(+), 62 deletions(-) diff --git a/.travis.yml b/.travis.yml index e84f6c3e..b9543e33 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,6 +41,8 @@ matrix: env: TOXENV=manifest - python: "2.7" env: TOXENV=docs + - python: "3.5" + env: TOXENV=readme install: - pip install tox diff --git a/AUTHORS.rst b/AUTHORS.rst index ca6a7e30..06cee70c 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -1,10 +1,10 @@ Authors -------- +======= ``structlog`` is written and maintained by `Hynek Schlawack `_. It’s inspired by previous work done by `Jean-Paul Calderone `_ and `David Reid `_. The development is kindly supported by `Variomedia AG `_. -A full list of contributors can be found on `GitHub `_. +A full list of contributors can be found on GitHub’s `overview `_. Some of them disapprove of the addition of thread local context data. :) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 6227ea57..2be1d3b9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -78,7 +78,7 @@ Changes: [`42 `_] - Pass positional arguments to stdlib wrapped loggers that use string formatting. [`19 `_] -- ``structlog`` is now dually licensed under the `Apache License, Version 2 `_ and the `MIT `_ license. +- ``structlog`` is now dually licensed under the `Apache License, Version 2 `_ and the `MIT `_ license. Therefore it is now legal to use structlog with `GPLv2 `_-licensed projects. [`28 `_] - Add ``structlog.stdlib.BoundLogger.exception``. diff --git a/LICENSE.mit b/LICENSE.mit index d210e740..cdaa1f7e 100644 --- a/LICENSE.mit +++ b/LICENSE.mit @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013-2015 Hynek Schlawack +Copyright (c) 2013 Hynek Schlawack Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.rst b/README.rst index b5b9d14f..3f5b070a 100644 --- a/README.rst +++ b/README.rst @@ -29,6 +29,6 @@ It allows you to split your log entries up into key/value pairs and build them i It's dual-licensed under `Apache License, version 2 `_ and `MIT `_, available from `PyPI `_, the source code can be found on `GitHub `_, the documentation at `http://www.structlog.org/ `_. -``structlog`` targets Python 2.6, 2.7, 3.3 and newer, and PyPy with no additional dependencies for core functionality. +``structlog`` targets Python 2.6, 2.7, 3.3 and newer, and PyPy. If you need any help, visit us on ``#structlog`` on `Freenode `_! diff --git a/docs/api.rst b/docs/api.rst index e5bb57f8..7307ec14 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -1,7 +1,7 @@ .. _api: -structlog Package -================= +API Reference +============= .. module:: structlog diff --git a/docs/conf.py b/docs/conf.py index c8fe82f0..8b8b3bd7 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,7 +14,6 @@ # serve to show the default. import codecs -import datetime import os import re @@ -66,7 +65,7 @@ def find_version(*file_paths): source_suffix = '.rst' # The encoding of source files. -#source_encoding = 'utf-8-sig' +# source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' @@ -74,7 +73,7 @@ def find_version(*file_paths): # General information about the project. project = u'structlog' author = u"Hynek Schlawack" -copyright = u'2013-{0}, {1}'.format(datetime.date.today().year, author) +copyright = u'2013, {author}'.format(author=author) # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -87,13 +86,13 @@ def find_version(*file_paths): # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. -#language = None +# language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: -#today = '' +# today = '' # Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' +# today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -103,24 +102,24 @@ def find_version(*file_paths): # The reST default role (used for this markup: `text`) to use for all # documents. -#default_role = None +# default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True +# add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +# add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. -#show_authors = False +# show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] +# modindex_common_prefix = [] # -- Options for HTML output -------------------------------------------------- @@ -136,26 +135,26 @@ def find_version(*file_paths): # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -#html_theme_options = {} +# html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. # html_theme_path = ['_themes'] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -#html_title = None +# html_title = None # A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None +# html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. -#html_logo = None +# html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = None +# html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -164,44 +163,44 @@ def find_version(*file_paths): # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' +# html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. -#html_use_smartypants = True +# html_use_smartypants = True # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +# html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. -#html_additional_pages = {} +# html_additional_pages = {} # If false, no module index is generated. -#html_domain_indices = True +# html_domain_indices = True # If false, no index is generated. -#html_use_index = True +# html_use_index = True # If true, the index is split into individual pages for each letter. -#html_split_index = False +# html_split_index = False # If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True +# html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True +# html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True +# html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. -#html_use_opensearch = '' +# html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None +# html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'structlogdoc' @@ -211,13 +210,13 @@ def find_version(*file_paths): latex_elements = { # The paper size ('letterpaper' or 'a4paper'). - #'papersize': 'letterpaper', + # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). - #'pointsize': '10pt', + # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. - #'preamble': '', + # 'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples @@ -230,23 +229,23 @@ def find_version(*file_paths): # The name of an image file (relative to this directory) to place at the top of # the title page. -#latex_logo = None +# latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. -#latex_use_parts = False +# latex_use_parts = False # If true, show page references after internal links. -#latex_show_pagerefs = False +# latex_show_pagerefs = False # If true, show URL addresses after external links. -#latex_show_urls = False +# latex_show_urls = False # Documents to append as an appendix to all manuals. -#latex_appendices = [] +# latex_appendices = [] # If false, no module index is generated. -#latex_domain_indices = True +# latex_domain_indices = True # -- Options for manual page output ------------------------------------------- @@ -259,7 +258,7 @@ def find_version(*file_paths): ] # If true, show URL addresses after external links. -#man_show_urls = False +# man_show_urls = False # -- Options for Texinfo output ----------------------------------------------- @@ -274,13 +273,13 @@ def find_version(*file_paths): ] # Documents to append as an appendix to all manuals. -#texinfo_appendices = [] +# texinfo_appendices = [] # If false, no module index is generated. -#texinfo_domain_indices = True +# texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' +# texinfo_show_urls = 'footnote' # -- Options for Epub output -------------------------------------------------- @@ -293,37 +292,37 @@ def find_version(*file_paths): # The language of the text. It defaults to the language option # or en if the language is not set. -#epub_language = '' +# epub_language = '' # The scheme of the identifier. Typical schemes are ISBN or URL. -#epub_scheme = '' +# epub_scheme = '' # The unique identifier of the text. This can be a ISBN number # or the project homepage. -#epub_identifier = '' +# epub_identifier = '' # A unique identification for the text. -#epub_uid = '' +# epub_uid = '' # A tuple containing the cover image and cover page html template filenames. -#epub_cover = () +# epub_cover = () # HTML files that should be inserted before the pages created by sphinx. # The format is a list of tuples containing the path and title. -#epub_pre_files = [] +# epub_pre_files = [] # HTML files shat should be inserted after the pages created by sphinx. # The format is a list of tuples containing the path and title. -#epub_post_files = [] +# epub_post_files = [] # A list of files that should not be packed into the epub file. -#epub_exclude_files = [] +# epub_exclude_files = [] # The depth of the table of contents in toc.ncx. -#epub_tocdepth = 3 +# epub_tocdepth = 3 # Allow duplicate toc entries. -#epub_tocdup = True +# epub_tocdup = True linkcheck_ignore = [ # 404s for unknown reasons @@ -338,5 +337,5 @@ def find_version(*file_paths): linkcheck_timeout = 300 intersphinx_mapping = { - 'https://docs.python.org/2': None, + 'https://docs.python.org/3': None, } diff --git a/docs/index.rst b/docs/index.rst index eef4af36..67b6e637 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -55,7 +55,7 @@ Basics Integration with Existing Systems --------------------------------- -``structlog`` can be used immediately with any existing logger. +``structlog`` can be used immediately with *any* existing logger. However it comes with special wrappers for the Python standard library and Twisted that are optimized for their respective underlying loggers and contain less magic. .. toctree:: diff --git a/tox.ini b/tox.ini index 05cba96f..0040bce9 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = coverage-clean,{py26,py27,py33,py34,py35,pypy}-{threads,greenlets},flake8,docs,manifest,coverage-report +envlist = coverage-clean,{py26,py27,py33,py34,py35,pypy}-{threads,greenlets},flake8,docs,readme,manifest,coverage-report [testenv] @@ -20,7 +20,7 @@ commands = coverage run --parallel -m pytest {posargs} skip_install = true basepython = python3.5 deps = flake8 -commands = flake8 src tests setup.py +commands = flake8 src tests setup.py docs/conf.py [testenv:docs] @@ -34,6 +34,12 @@ commands = sphinx-build -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html +[testenv:readme] +deps = readme +skip_install = true +commands = python setup.py check -r -s + + [testenv:manifest] skip_install = true deps = check-manifest From bc1370f492f2a566c02a2c2bf53fc8111dd6627a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 19 Dec 2015 14:16:50 +0100 Subject: [PATCH 0045/1520] reindent --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 3f5b070a..00506e82 100644 --- a/README.rst +++ b/README.rst @@ -6,10 +6,10 @@ structlog: Structured Logging for Python :target: https://travis-ci.org/hynek/structlog .. image:: https://codecov.io/github/hynek/structlog/coverage.svg?branch=master - :target: https://codecov.io/github/hynek/structlog?branch=master + :target: https://codecov.io/github/hynek/structlog?branch=master .. image:: https://www.irccloud.com/invite-svg?channel=%23structlog&hostname=irc.freenode.net&port=6697&ssl=1 - :target: https://www.irccloud.com/invite?channel=%23structlog&hostname=irc.freenode.net&port=6697&ssl=1 + :target: https://www.irccloud.com/invite?channel=%23structlog&hostname=irc.freenode.net&port=6697&ssl=1 ``structlog`` makes structured logging in Python easy by *augmenting* your *existing* logger. It allows you to split your log entries up into key/value pairs and build them incrementally without annoying boilerplate code. From 06730a33769ea85f3a3c198f423843bd26bc3cd2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 19 Dec 2015 19:23:35 +0100 Subject: [PATCH 0046/1520] Add ConsoleRenderer and structlog.dev in general --- CHANGELOG.rst | 1 + MANIFEST.in | 10 +- docs/_static/console_renderer.png | Bin 0 -> 68922 bytes docs/api.rst | 12 ++ docs/backward-compatibility.rst | 2 +- docs/development.rst | 34 ++++++ docs/index.rst | 1 + docs/standard-library.rst | 6 +- setup.py | 4 + src/structlog/__init__.py | 2 + src/structlog/_config.py | 2 +- src/structlog/dev.py | 139 +++++++++++++++++++++ tests/test_dev.py | 195 ++++++++++++++++++++++++++++++ tox.ini | 7 +- 14 files changed, 402 insertions(+), 13 deletions(-) create mode 100644 docs/_static/console_renderer.png create mode 100644 docs/development.rst create mode 100644 src/structlog/dev.py create mode 100644 tests/test_dev.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2be1d3b9..6ebb9c41 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,6 +24,7 @@ Deprecations: Changes: ^^^^^^^^ +- Add ``structlog.dev.ConsoleRenderer`` that renders the event dictionary aligned and with colors. - Use `six `_ for compatibility. - Add ``structlog.processors.UnicodeDecoder`` that will decode all byte string values in an event dictionary to Unicode. - Add ``serializer`` parameter to ``structlog.processors.JSONRenderer`` which allows for using different (possibly faster) JSON encoders than the standard library. diff --git a/MANIFEST.in b/MANIFEST.in index b6d90cb6..20cc4b2b 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -3,11 +3,7 @@ include *.rst include *.txt include .travis.yml include tox.ini -recursive-include docs *.bat -recursive-include docs *.keep -recursive-include docs *.py -recursive-include docs *.rst -recursive-include docs *.txt -recursive-include docs Makefile -recursive-include tests *.py +graft tests +recursive-exclude tests *.pyc +graft docs prune docs/_build diff --git a/docs/_static/console_renderer.png b/docs/_static/console_renderer.png new file mode 100644 index 0000000000000000000000000000000000000000..1479357d94ec7fdab5dcc0373ffd574167d248cb GIT binary patch literal 68922 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

PiJ6jCvLF~6L+B~iUB>W!C?hejGKOYY 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 0 else 0) + + +if colorama is not None: + RESET_ALL = colorama.Style.RESET_ALL + BRIGHT = colorama.Style.BRIGHT + DIM = colorama.Style.DIM + RED = colorama.Fore.RED + BLUE = colorama.Fore.BLUE + CYAN = colorama.Fore.CYAN + MAGENTA = colorama.Fore.MAGENTA + YELLOW = colorama.Fore.YELLOW + GREEN = colorama.Fore.GREEN + + +class ConsoleRenderer(object): + """ + Render `event_dict` nicely aligned, in colors, and ordered. + + :param int pad_event: Pad the event to this many characters. + + Requires the colorama_ package. + + .. _colorama: https://pypi.python.org/pypi/colorama/ + + .. versionadded:: 16.0.0 + """ + def __init__(self, pad_event=_EVENT_WIDTH): + if colorama is None: + raise SystemError( + _MISSING.format( + who=self.__class__.__name__, + package="colorama" + ) + ) + colorama.init() + + self._pad_event = pad_event + self._level_to_color = { + "critical": RED, + "exception": RED, + "error": RED, + "warn": YELLOW, + "warning": YELLOW, + "info": GREEN, + "debug": GREEN, + "notset": colorama.Back.RED, + } + self._longest_level = len(max( + self._level_to_color.keys(), + key=lambda e: len(e) + )) + + def __call__(self, _, __, event_dict): + sio = StringIO() + + ts = event_dict.pop("timestamp", None) + if ts is not None: + sio.write( + # can be a number if timestamp is UNIXy + DIM + str(ts) + RESET_ALL + " " + ) + level = event_dict.pop("level", None) + if level is not None: + sio.write( + "[" + self._level_to_color[level] + + _pad(level, self._longest_level) + + RESET_ALL + "] " + ) + + sio.write( + BRIGHT + + _pad(event_dict.pop("event"), self._pad_event) + + RESET_ALL + " " + ) + + logger_name = event_dict.pop("logger", None) + if logger_name is not None: + sio.write( + "[" + BLUE + BRIGHT + + logger_name + RESET_ALL + + "] " + ) + + stack = event_dict.pop("stack", None) + exc = event_dict.pop("exception", None) + sio.write( + " ".join( + CYAN + key + RESET_ALL + + "=" + + MAGENTA + repr(event_dict[key]) + + RESET_ALL + for key in sorted(event_dict.keys()) + ) + ) + + if stack is not None: + sio.write("\n" + stack) + if exc is not None: + sio.write("\n\n" + "=" * 79 + "\n") + if exc is not None: + sio.write("\n" + exc) + + return sio.getvalue() diff --git a/tests/test_dev.py b/tests/test_dev.py new file mode 100644 index 00000000..d0277eb8 --- /dev/null +++ b/tests/test_dev.py @@ -0,0 +1,195 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the MIT License. See the LICENSE file in the root of this +# repository for complete details. + +from __future__ import absolute_import, division, print_function + +import pytest + +from structlog import dev + + +class TestPad(object): + def test_normal(self): + """ + If chars are missing, adequate number of " " are added. + """ + assert 100 == len(dev._pad("test", 100)) + + def test_negative(self): + """ + If string is already too long, don't do anything. + """ + assert len("test") == len(dev._pad("test", 2)) + + +@pytest.mark.skipif(dev.colorama is not None, + reason="Colorama must be missing.") +def test_missing_colorama(): + """ + ConsoleRenderer() raises SystemError on initialization if colorama is + missing. + + This is a function such that TestConsoleRenderer can be protected on class + level. + """ + with pytest.raises(SystemError) as e: + dev.ConsoleRenderer() + + assert ( + "ConsoleRenderer requires the colorama package installed." + ) in e.value.args[0] + + +@pytest.fixture +def cr(): + return dev.ConsoleRenderer() + + +if dev.colorama is not None: + PADDED_TEST = ( + dev.BRIGHT + + dev._pad("test", dev._EVENT_WIDTH) + + dev.RESET_ALL + " " + ) + + +@pytest.mark.skipif(dev.colorama is None, reason="Requires colorama.") +class TestConsoleRenderer(object): + def test_plain(self, cr): + """ + Works with a plain event_dict with only the event. + """ + rv = cr(None, None, {"event": "test"}) + + assert PADDED_TEST == rv + + def test_timestamp(self, cr): + """ + Timestamps get prepended dimmed.. + """ + rv = cr(None, None, {"event": "test", "timestamp": 42}) + + assert ( + dev.DIM + "42" + dev.RESET_ALL + + " " + PADDED_TEST + ) == rv + + def test_level(self, cr): + """ + Levels are rendered aligned, in square brackets, and color coded. + """ + rv = cr(None, None, {"event": "test", "level": "critical"}) + + assert ( + "[" + dev.RED + + dev._pad("critical", cr._longest_level) + + dev.RESET_ALL + "] " + + PADDED_TEST + ) == rv + + def test_logger_name(self, cr): + """ + Logger names are appended after the event. + """ + rv = cr(None, None, {"event": "test", "logger": "some_module"}) + + assert ( + PADDED_TEST + + "[" + dev.BLUE + dev.BRIGHT + + "some_module" + + dev.RESET_ALL + "] " + ) == rv + + def test_key_values(self, cr): + """ + Key-value pairs go sorted alphabetically to the end. + """ + rv = cr(None, None, { + "event": "test", + "key": "value", + "foo": "bar", + }) + assert ( + PADDED_TEST + + dev.CYAN + "foo" + dev.RESET_ALL + "=" + dev.MAGENTA + "'bar'" + + dev.RESET_ALL + " " + + dev.CYAN + "key" + dev.RESET_ALL + "=" + dev.MAGENTA + "'value'" + + dev.RESET_ALL + ) == rv + + def test_exception(self, cr): + """ + Exceptions are rendered after a new line. + """ + exc = "Traceback:\nFake traceback...\nFakeError: yolo" + + rv = cr(None, None, { + "event": "test", + "exception": exc + }) + + assert ( + PADDED_TEST + "\n" + exc + ) == rv + + def test_stack_info(self, cr): + """ + Stack traces are rendered after a new line. + """ + stack = "fake stack" + rv = cr(None, None, { + "event": "test", + "stack": stack + }) + + assert ( + PADDED_TEST + "\n" + stack + ) == rv + + def test_pad_event_param(self): + """ + `pad_event` parameter works. + """ + rv = dev.ConsoleRenderer(42)(None, None, {"event": "test"}) + + assert ( + dev.BRIGHT + + dev._pad("test", 42) + + dev.RESET_ALL + " " + ) == rv + + def test_everything(self, cr): + """ + Put all cases together. + """ + exc = "Traceback:\nFake traceback...\nFakeError: yolo" + stack = "fake stack trace" + + rv = cr(None, None, { + "event": "test", + "exception": exc, + "key": "value", + "foo": "bar", + "timestamp": "13:13", + "logger": "some_module", + "level": "error", + "stack": stack, + }) + + assert ( + dev.DIM + "13:13" + dev.RESET_ALL + + " [" + dev.RED + + dev._pad("error", cr._longest_level) + + dev.RESET_ALL + "] " + + PADDED_TEST + + "[" + dev.BLUE + dev.BRIGHT + + "some_module" + + dev.RESET_ALL + "] " + + dev.CYAN + "foo" + dev.RESET_ALL + "=" + dev.MAGENTA + "'bar'" + + dev.RESET_ALL + " " + + dev.CYAN + "key" + dev.RESET_ALL + "=" + dev.MAGENTA + "'value'" + + dev.RESET_ALL + + "\n" + stack + "\n\n" + "=" * 79 + "\n" + + "\n" + exc + ) == rv diff --git a/tox.ini b/tox.ini index 0040bce9..05826ead 100644 --- a/tox.ini +++ b/tox.ini @@ -1,18 +1,21 @@ [tox] -envlist = coverage-clean,{py26,py27,py33,py34,py35,pypy}-{threads,greenlets},flake8,docs,readme,manifest,coverage-report +envlist = coverage-clean,{py26,py27,py33,py34,py35,pypy}-{threads,greenlets},py35-nocolorama,flake8,docs,readme,manifest,coverage-report [testenv] deps = -rdev-requirements.txt greenlets: greenlet + # indirectly ensure that only -nocolorama has no colorama + # sadly 0.3.5 is broken, so we use github until a fix is released + threads: --editable=git+https://github.com/tartley/colorama@44dc8af9bc8111b70dd046a822bb26c851ba3687#egg=colorama + greenlets: --editable=git+https://github.com/tartley/colorama@44dc8af9bc8111b70dd046a822bb26c851ba3687#egg=colorama py26: ordereddict py26: twisted<15.5.0 py27,py33,py34,py35,pypy: twisted py33,py34,py35: python-rapidjson setenv = PYTHONHASHSEED = 0 - threads: TRICKING_TOX_INTO_GENERATING_AN_ENVIRONMENT = 1 commands = coverage run --parallel -m pytest {posargs} From d2430beaba94f4eea7351f4bcc27e78591f51109 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 19 Dec 2015 20:28:11 +0100 Subject: [PATCH 0047/1520] Brighten up level colors --- docs/_static/console_renderer.png | Bin 68922 -> 79966 bytes src/structlog/dev.py | 2 ++ tests/test_dev.py | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/_static/console_renderer.png b/docs/_static/console_renderer.png index 1479357d94ec7fdab5dcc0373ffd574167d248cb..cfff817c9a4b1adcb4c82fe18931d086edad8160 100644 GIT binary patch literal 79966 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

PiJ6jCvLF~6L+B~iUB>W!C?hejGKOYY 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 Date: Sun, 20 Dec 2015 07:55:02 +0100 Subject: [PATCH 0048/1520] 25 is a bit little --- src/structlog/dev.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index df5b1cb8..04bd8988 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -25,7 +25,7 @@ "If you want to use the helpers from structlog.dev, it is strongly " "recommended to install structlog using `pip install structlog[dev]`." ) -_EVENT_WIDTH = 25 # pad the event name to so many characters +_EVENT_WIDTH = 30 # pad the event name to so many characters def _pad(s, l): From 56a997247350c3e7262f4a875bc326cc44dfd859 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 4 Jan 2016 13:49:48 +0100 Subject: [PATCH 0049/1520] 2016 --- CHANGELOG.rst | 2 +- src/structlog/__init__.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 6ebb9c41..e1d46a5b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,7 +5,7 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. -15.4.0 (UNRELEASED) +16.0.0 (UNRELEASED) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 17f80da1..7ebf613c 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -45,7 +45,7 @@ twisted = None -__version__ = "15.4.0.dev0" +__version__ = "16.0.0.dev0" __title__ = "structlog" __description__ = "Structured Logging for Python" @@ -55,7 +55,7 @@ __email__ = "hs@ox.cx" __license__ = "MIT or Apache License, Version 2.0" -__copyright__ = "Copyright (c) 2013-2015 {0}".format(__author__) +__copyright__ = "Copyright (c) 2013 {0}".format(__author__) __all__ = [ From b686579b844ae59f2f38b9d077f15f297aacd851 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 6 Jan 2016 14:04:18 +0100 Subject: [PATCH 0050/1520] readme has been renamed --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 05826ead..3e8fa06e 100644 --- a/tox.ini +++ b/tox.ini @@ -38,7 +38,7 @@ commands = [testenv:readme] -deps = readme +deps = readme_renderer skip_install = true commands = python setup.py check -r -s From 324294d7543ce381179d1afefba94ace98dd02d0 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 11 Jan 2016 09:18:46 +0100 Subject: [PATCH 0051/1520] colorama has a release with the fix --- tox.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index 3e8fa06e..d1c813bf 100644 --- a/tox.ini +++ b/tox.ini @@ -8,8 +8,8 @@ deps = greenlets: greenlet # indirectly ensure that only -nocolorama has no colorama # sadly 0.3.5 is broken, so we use github until a fix is released - threads: --editable=git+https://github.com/tartley/colorama@44dc8af9bc8111b70dd046a822bb26c851ba3687#egg=colorama - greenlets: --editable=git+https://github.com/tartley/colorama@44dc8af9bc8111b70dd046a822bb26c851ba3687#egg=colorama + threads: colorama>=0.3.6 + greenlets: colorama>=0.3.6 py26: ordereddict py26: twisted<15.5.0 py27,py33,py34,py35,pypy: twisted From db958913bc69017d14e89235d473b949340580bb Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 22 Jan 2016 13:33:44 +0100 Subject: [PATCH 0052/1520] Appease new flake8 --- src/structlog/dev.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 04bd8988..1f94e88a 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -123,8 +123,8 @@ def __call__(self, _, __, event_dict): exc = event_dict.pop("exception", None) sio.write( " ".join( - CYAN + key + RESET_ALL - + "=" + + CYAN + key + RESET_ALL + + "=" + MAGENTA + repr(event_dict[key]) + RESET_ALL for key in sorted(event_dict.keys()) From 8bf7608a09dcf0a3b2b07b293711759b0d193a75 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 22 Jan 2016 14:55:18 +0100 Subject: [PATCH 0053/1520] Fix reST markup --- CODE_OF_CONDUCT.rst | 15 ++++----------- CONTRIBUTING.rst | 4 ++-- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/CODE_OF_CONDUCT.rst b/CODE_OF_CONDUCT.rst index 16233970..b7f31dd6 100644 --- a/CODE_OF_CONDUCT.rst +++ b/CODE_OF_CONDUCT.rst @@ -23,15 +23,8 @@ Project maintainers who do not follow or enforce the Code of Conduct may be perm This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting a project maintainer at hs@ox.cx. -All complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. -Maintainers are obligated to maintain confidentiality with regard to the reporter of an -incident. +All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. +Maintainers are obligated to maintain confidentiality with regard to the reporter of an incident. - -This Code of Conduct is adapted from the `Contributor Covenant `_, -version 1.3.0, available at -`http://contributor-covenant.org/version/1/3/0/ `_. - -.. _homepage: http://contributor-covenant.org -.. _version: http://contributor-covenant.org/version/1/3/0/ +This Code of Conduct is adapted from the `Contributor Covenant `_, +version 1.3.0, available at http://contributor-covenant.org/version/1/3/0/. diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 787902ff..a2cbcbe3 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -24,12 +24,12 @@ Here are a few guidelines to get you started: Please note that this project is released with a Contributor `Code of Conduct`_. By participating in this project you agree to abide by its terms. -Please report any harm to `Hynek Schlawack `_ in any way you find appropriate. +Please report any harm to `Hynek Schlawack`_ in any way you find appropriate. Thank you for considering to contribute to ``structlog``! -.. _me: https://hynek.me/about/ +.. _`Hynek Schlawack`: https://hynek.me/about/ .. _`PEP 8`: https://www.python.org/dev/peps/pep-0008/ .. _`PEP 257`: https://www.python.org/dev/peps/pep-0257/ .. _`good test docstrings`: https://jml.io/pages/test-docstrings.html From 604b8a47d4b2c5d5acddce5220d319b9347b0543 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 22 Jan 2016 15:07:47 +0100 Subject: [PATCH 0054/1520] Add changelog entry for #62 --- CHANGELOG.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e1d46a5b..a35b6812 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,6 +24,8 @@ Deprecations: Changes: ^^^^^^^^ +- Be more more lenient about missing ``__name__``\ s. + [`62 `_] - Add ``structlog.dev.ConsoleRenderer`` that renders the event dictionary aligned and with colors. - Use `six `_ for compatibility. - Add ``structlog.processors.UnicodeDecoder`` that will decode all byte string values in an event dictionary to Unicode. From eb8ffffdfc63be9064460000c649ee8c80f094d2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 22 Jan 2016 15:50:13 +0100 Subject: [PATCH 0055/1520] Add an FAQ --- docs/faq.rst | 18 ++++++++++++++++++ docs/index.rst | 1 + 2 files changed, 19 insertions(+) create mode 100644 docs/faq.rst diff --git a/docs/faq.rst b/docs/faq.rst new file mode 100644 index 00000000..6a2cdee3 --- /dev/null +++ b/docs/faq.rst @@ -0,0 +1,18 @@ +Frequently Asked Questions +========================== + +I try to bind key-value pairs but they don't appear in the log files? + + ``structlog``\ 's loggers are *immutable*. + Meaning that you have to use the logger that is returned from ``bind()``: + + .. doctest:: + + >>> import structlog + >>> log = structlog.get_logger() + >>> log.bind(x=42) # doctest: +SKIP + >>> log.msg("hello") + event='hello' + >>> new_log = log.bind(x=42) + >>> new_log.msg("hello") + x=42 event='hello' diff --git a/docs/index.rst b/docs/index.rst index 1642b395..a93bcf5d 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -51,6 +51,7 @@ Basics processors examples development + faq Integration with Existing Systems From f0ec7908dcb3d78b44eeb4377cbfa2062d7cf0c1 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 22 Jan 2016 16:02:45 +0100 Subject: [PATCH 0056/1520] Remove stale comment --- tox.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/tox.ini b/tox.ini index d1c813bf..b5b76cf9 100644 --- a/tox.ini +++ b/tox.ini @@ -7,7 +7,6 @@ deps = -rdev-requirements.txt greenlets: greenlet # indirectly ensure that only -nocolorama has no colorama - # sadly 0.3.5 is broken, so we use github until a fix is released threads: colorama>=0.3.6 greenlets: colorama>=0.3.6 py26: ordereddict From 85be2b94fad79ff014f7093252df8b7e415c15fd Mon Sep 17 00:00:00 2001 From: Tin Tvrtkovic Date: Fri, 22 Jan 2016 19:38:17 +0100 Subject: [PATCH 0057/1520] tmp_bind cleans up properly after exceptions. --- src/structlog/threadlocal.py | 8 +++++--- tests/test_threadlocal.py | 13 +++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index 7d842a42..b64509c7 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -103,9 +103,11 @@ def tmp_bind(logger, **tmp_values): event='event' """ saved = as_immutable(logger)._context - yield logger.bind(**tmp_values) - logger._context.clear() - logger._context.update(saved) + try: + yield logger.bind(**tmp_values) + finally: + logger._context.clear() + logger._context.update(saved) class _ThreadLocalDictWrapper(object): diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py index 2897978e..d44675c9 100644 --- a/tests/test_threadlocal.py +++ b/tests/test_threadlocal.py @@ -57,6 +57,19 @@ def test_bind(self, log): } == tmp_log._context._dict == log._context._dict assert {'y': 23} == log._context._dict + def test_bind_exc(self, log): + """ + tmp_bind cleans up properly on exceptions. + """ + log = log.bind(y=23) + with pytest.raises(ValueError): + with tmp_bind(log, x=42, y='foo') as tmp_log: + assert { + 'y': 'foo', 'x': 42 + } == tmp_log._context._dict == log._context._dict + raise ValueError + assert {'y': 23} == log._context._dict + class TestAsImmutable(object): def test_does_not_affect_global(self, log): From 2631a217ced9d1128426c9ef43233eb6ec6eb418 Mon Sep 17 00:00:00 2001 From: Tin Tvrtkovic Date: Fri, 22 Jan 2016 23:26:30 +0100 Subject: [PATCH 0058/1520] Add changelog entry for #64. --- CHANGELOG.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a35b6812..0606f642 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -30,6 +30,8 @@ Changes: - Use `six `_ for compatibility. - Add ``structlog.processors.UnicodeDecoder`` that will decode all byte string values in an event dictionary to Unicode. - Add ``serializer`` parameter to ``structlog.processors.JSONRenderer`` which allows for using different (possibly faster) JSON encoders than the standard library. +- Clean up the context when exiting ``structlog.threadlocal.tmp_bind`` in case of exceptions. + [`64 `_] 15.3.0 (2015-09-25) From b2e08f9a9731d459b1b0d52ce506ecef41644cf2 Mon Sep 17 00:00:00 2001 From: Tin Tvrtkovic Date: Fri, 22 Jan 2016 23:27:06 +0100 Subject: [PATCH 0059/1520] Enable py35-nocolorama for Travis. --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index b9543e33..51d659cb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,6 +28,8 @@ matrix: env: TOXENV=py35-threads - python: "3.5" env: TOXENV=py35-greenlets + - python: "3.5" + env: TOXENV=py35-nocolorama - python: "pypy" env: TOXENV=pypy-threads - python: "pypy" From 6f6bda9cab36b00ef921a0fba97fd3964fce02dc Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 27 Jan 2016 13:21:06 +0100 Subject: [PATCH 0060/1520] Add support to pass Exceptions into formatters Python 3 only of course. --- CHANGELOG.rst | 1 + docs/api.rst | 7 ++++ src/structlog/_base.py | 3 +- src/structlog/processors.py | 47 ++++++++++++++++--------- src/structlog/stdlib.py | 3 +- src/structlog/twisted.py | 2 +- tests/test_config.py | 2 +- tests/test_processors.py | 70 +++++++++++++++++++++++++++++++++---- tests/test_stdlib.py | 6 ++-- tests/test_twisted.py | 3 +- tests/utils.py | 16 +++++++++ 11 files changed, 129 insertions(+), 31 deletions(-) create mode 100644 tests/utils.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0606f642..209f9214 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,6 +24,7 @@ Deprecations: Changes: ^^^^^^^^ +- ``structlog.processors.ExceptionPrettyPrinter`` and ``structlog.processors.format_exc_info`` now support passing of Exceptions on Python 3. - Be more more lenient about missing ``__name__``\ s. [`62 `_] - Add ``structlog.dev.ConsoleRenderer`` that renders the event dictionary aligned and with colors. diff --git a/docs/api.rst b/docs/api.rst index 79aa6c85..652ffed2 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -76,6 +76,13 @@ API Reference .. autofunction:: format_exc_info + >>> from structlog.processors import format_exc_info + >>> try: + ... raise ValueError + ... except ValueError: + ... format_exc_info(None, None, {'exc_info': True})# doctest: +ELLIPSIS + {'exception': 'Traceback (most recent call last):... + .. autoclass:: StackInfoRenderer .. autoclass:: ExceptionPrettyPrinter diff --git a/src/structlog/_base.py b/src/structlog/_base.py index 40f0a82b..084f0487 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -8,9 +8,10 @@ from __future__ import absolute_import, division, print_function -from structlog._compat import string_types from structlog.exceptions import DropEvent +from six import string_types + class BoundLoggerBase(object): """ diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 350782f0..e01f4a7b 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -15,7 +15,8 @@ import sys import time -from structlog._compat import text_type +import six + from structlog._frames import ( _find_first_app_frame_and_name, _format_exception, @@ -93,7 +94,7 @@ def __init__(self, encoding='utf-8', errors='backslashreplace'): def __call__(self, logger, name, event_dict): for key, value in event_dict.items(): - if isinstance(value, text_type): + if isinstance(value, six.text_type): event_dict[key] = value.encode(self._encoding, self._errors) return event_dict @@ -196,24 +197,19 @@ def format_exc_info(logger, name, event_dict): behaviors: - If the value is a tuple, render it into the key ``exception``. + - If the value is an Exception *and* you're running Python 3, render it + into the key ``exception``. - If the value true but no tuple, obtain exc_info ourselves and render that. If there is no ``exc_info`` key, the *event_dict* is not touched. This behavior is analogue to the one of the stdlib's logging. - - >>> from structlog.processors import format_exc_info - >>> try: - ... raise ValueError - ... except ValueError: - ... format_exc_info(None, None, {'exc_info': True})# doctest: +ELLIPSIS - {'exception': 'Traceback (most recent call last):... """ exc_info = event_dict.pop('exc_info', None) if exc_info: - if not isinstance(exc_info, tuple): - exc_info = sys.exc_info() - event_dict['exception'] = _format_exception(exc_info) + event_dict['exception'] = _format_exception( + _figure_out_exc_info(exc_info) + ) return event_dict @@ -265,11 +261,28 @@ def stamper(self, _, __, event_dict): return type('TimeStamper', (object,), {'__call__': stamper})() +def _figure_out_exc_info(v): + """ + Depending on the Python version will try to do the smartest thing possible + to transform *v* into an ``exc_info`` tuple. + + :rtype: tuple + """ + if v is True: + return sys.exc_info() + elif six.PY3 and isinstance(v, BaseException): + tb = getattr(v, "__traceback__") + if tb is not None: + return (v.__class__, v, tb) + + return v + + class ExceptionPrettyPrinter(object): """ Pretty print exceptions and remove them from the `event_dict`. - :param file file: Target file for output (default: `sys.stdout`). + :param file file: Target file for output (default: ``sys.stdout``). This processor is mostly for development and testing so you can read exceptions properly formatted. @@ -282,6 +295,8 @@ class ExceptionPrettyPrinter(object): `exception` as well as `exc_info` keys. .. versionadded:: 0.4.0 + .. versionchanged:: 16.0.0 + Added support for passing exceptions as ``exc_info`` on Python 3. """ def __init__(self, file=None): if file is not None: @@ -290,12 +305,10 @@ def __init__(self, file=None): self._file = sys.stdout def __call__(self, logger, name, event_dict): - exc = event_dict.pop('exception', None) + exc = event_dict.pop("exception", None) if exc is None: - exc_info = event_dict.pop('exc_info', None) + exc_info = _figure_out_exc_info(event_dict.pop("exc_info", None)) if exc_info: - if not isinstance(exc_info, tuple): - exc_info = sys.exc_info() exc = _format_exception(exc_info) if exc: print(exc, file=self._file) diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index c7d3ac2f..59ba0fba 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -14,10 +14,11 @@ import logging from structlog._base import BoundLoggerBase -from structlog._compat import PY3 from structlog._frames import _find_first_app_frame_and_name, _format_stack from structlog.exceptions import DropEvent +from six import PY3 + class _FixedFindCallerLogger(logging.Logger): """ diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index 9594696b..1541a064 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -14,13 +14,13 @@ import json import sys +from six import PY2, string_types from twisted.python import log from twisted.python.failure import Failure from twisted.python.log import ILogObserver, textFromEventDict from zope.interface import implementer from structlog._base import BoundLoggerBase -from structlog._compat import PY2, string_types from structlog._utils import until_not_interrupted from structlog.processors import ( # can't import processors module without risking circular imports diff --git a/tests/test_config.py b/tests/test_config.py index e8c1f20f..a2b2f1d1 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -9,9 +9,9 @@ import pytest from pretend import call_recorder, call, stub +from six import PY3 from structlog._base import BoundLoggerBase -from structlog._compat import PY3 from structlog._config import ( BoundLoggerLazyProxy, _CONFIG, diff --git a/tests/test_processors.py b/tests/test_processors.py index 8c7f0265..53bac0ff 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -29,11 +29,14 @@ TimeStamper, UnicodeDecoder, UnicodeEncoder, + _figure_out_exc_info, _json_fallback_handler, format_exc_info, ) from structlog.threadlocal import wrap_dict +from .utils import py3_only + @pytest.fixture def sio(): @@ -201,21 +204,43 @@ def test_key_can_be_specified(self): class TestFormatExcInfo(object): def test_formats_tuple(self, monkeypatch): + """ + If exc_info is a tuple, it is used. + """ monkeypatch.setattr(structlog.processors, - '_format_exception', + "_format_exception", lambda exc_info: exc_info) - d = format_exc_info(None, None, {'exc_info': (None, None, 42)}) - assert {'exception': (None, None, 42)} == d + d = format_exc_info(None, None, {"exc_info": (None, None, 42)}) + assert {"exception": (None, None, 42)} == d def test_gets_exc_info_on_bool(self): + """ + If exc_info is True, it is obtained using sys.exc_info(). + """ # monkeypatching sys.exc_info makes currently py.test return 1 on # success. try: raise ValueError('test') except ValueError: - d = format_exc_info(None, None, {'exc_info': True}) - assert 'exc_info' not in d - assert 'raise ValueError(\'test\')\nValueError: test' in d['exception'] + d = format_exc_info(None, None, {"exc_info": True}) + assert "exc_info" not in d + assert "raise ValueError('test')\nValueError: test" in d["exception"] + + @py3_only + def test_exception_on_py3(self, monkeypatch): + """ + Passing excetions as exc_info is valid on Python 3. + """ + monkeypatch.setattr(structlog.processors, + "_format_exception", + lambda exc_info: exc_info) + try: + raise ValueError("test") + except ValueError as e: + d = format_exc_info(None, None, {"exc_info": e}) + assert {"exception": (ValueError, e, e.__traceback__)} == d + else: + pytest.fail("Exception not raised.") class TestUnicodeEncoder(object): @@ -347,6 +372,18 @@ def test_own_exc_info(self, sio): epp(None, None, {"exc_info": ei}) assert "XXX" in sio.getvalue() + @py3_only + def test_exception_on_py3(self, sio): + """ + On Python 3, it's also legal to pass an Exception. + """ + epp = ExceptionPrettyPrinter(sio) + try: + raise ValueError("XXX") + except ValueError as e: + epp(None, None, {"exc_info": e}) + assert "XXX" in sio.getvalue() + @pytest.fixture def sir(): @@ -371,3 +408,24 @@ def test_adds_stack_if_asked(self, sir): def test_renders_correct_stack(self, sir): ed = sir(None, None, {'stack_info': True}) assert "ed = sir(None, None, {'stack_info': True})" in ed['stack'] + + +class TestFigureOutExcInfo(object): + def test_obtains_exc_info_on_True(self): + """ + If True is passed, obtain exc_info ourselves. + """ + try: + 0/0 + except Exception: + assert sys.exc_info() == _figure_out_exc_info(True) + else: + pytest.fail("Exception not raised.") + + def test_py3_exception_no_traceback(self): + """ + Not sure how likely this is but the ``raise`` docs are a bit vague. + If an exception without a traceback is passed it's passed back. + """ + e = ValueError() + assert e is _figure_out_exc_info(e) diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 869098c4..73dda2b5 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -24,9 +24,9 @@ add_logger_name, _FixedFindCallerLogger, ) -from structlog._compat import PY2 from .additional_frame import additional_frame +from .utils import py3_only def build_bl(logger=None, processors=None, context=None): @@ -83,13 +83,13 @@ def test_deduces_correct_caller(self): assert file_name == os.path.realpath(__file__) assert func_name == 'test_deduces_correct_caller' - @pytest.mark.skipif(PY2, reason="Py3-only") + @py3_only def test_stack_info(self): logger = _FixedFindCallerLogger('test') testing, is_, fun, stack_info = logger.findCaller(stack_info=True) assert 'testing, is_, fun' in stack_info - @pytest.mark.skipif(PY2, reason="Py3-only") + @py3_only def test_no_stack_info_by_default(self): logger = _FixedFindCallerLogger('test') testing, is_, fun, stack_info = logger.findCaller() diff --git a/tests/test_twisted.py b/tests/test_twisted.py index c7aeead1..2f87b532 100644 --- a/tests/test_twisted.py +++ b/tests/test_twisted.py @@ -9,11 +9,12 @@ import pytest from pretend import call_recorder +from six import PY3 from twisted.python.failure import Failure, NoCurrentExceptionError from twisted.python.log import ILogObserver from structlog._config import _CONFIG -from structlog._compat import OrderedDict, StringIO, PY3 +from structlog._compat import OrderedDict, StringIO from structlog._loggers import ReturnLogger from structlog.twisted import ( BoundLogger, diff --git a/tests/utils.py b/tests/utils.py new file mode 100644 index 00000000..65bd3b3c --- /dev/null +++ b/tests/utils.py @@ -0,0 +1,16 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the MIT License. See the LICENSE file in the root of this +# repository for complete details. + +""" +Shared test utilities. +""" + +from __future__ import absolute_import, division, print_function + +import pytest +import six + + +py3_only = pytest.mark.skipif(not six.PY3, reason="Python 3-only") +py2_only = pytest.mark.skipif(not six.PY2, reason="Python 2-only") From d545fcff05a9795355b9260c630e1796f07a21c3 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 27 Jan 2016 13:47:44 +0100 Subject: [PATCH 0061/1520] Minor doc polishing --- docs/api.rst | 59 +++++++++++++++++++++++++++++++++---- src/structlog/__init__.py | 2 +- src/structlog/processors.py | 48 ++++-------------------------- 3 files changed, 60 insertions(+), 49 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 652ffed2..f9e73c5c 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -70,18 +70,30 @@ API Reference .. autoclass:: KeyValueRenderer + .. doctest:: + + >>> from structlog.processors import KeyValueRenderer + >>> KeyValueRenderer(sort_keys=True)(None, None, {'a': 42, 'b': [1, 2, 3]}) + 'a=42 b=[1, 2, 3]' + >>> KeyValueRenderer(key_order=['b', 'a'])(None, None, + ... {'a': 42, 'b': [1, 2, 3]}) + 'b=[1, 2, 3] a=42' + + .. autoclass:: UnicodeDecoder .. autoclass:: UnicodeEncoder .. autofunction:: format_exc_info - >>> from structlog.processors import format_exc_info - >>> try: - ... raise ValueError - ... except ValueError: - ... format_exc_info(None, None, {'exc_info': True})# doctest: +ELLIPSIS - {'exception': 'Traceback (most recent call last):... + .. doctest:: + + >>> from structlog.processors import format_exc_info + >>> try: + ... raise ValueError + ... except ValueError: + ... format_exc_info(None, None, {'exc_info': True})# doctest: +ELLIPSIS + {'exception': 'Traceback (most recent call last):... .. autoclass:: StackInfoRenderer @@ -89,6 +101,16 @@ API Reference .. autoclass:: TimeStamper(fmt=None, utc=True) + .. doctest:: + + >>> from structlog.processors import TimeStamper + >>> TimeStamper()(None, None, {}) # doctest: +SKIP + {'timestamp': 1378994017} + >>> TimeStamper(fmt='iso')(None, None, {}) # doctest: +SKIP + {'timestamp': '2013-09-12T13:54:26.996778Z'} + >>> TimeStamper(fmt='%Y', key='year')(None, None, {}) # doctest: +SKIP + {'year': '2013'} + :mod:`stdlib` Module -------------------- @@ -125,6 +147,31 @@ API Reference .. autoclass:: JSONRenderer + .. doctest:: + + >>> from structlog.processors import JSONRenderer + >>> JSONRenderer(sort_keys=True)(None, None, {'a': 42, 'b': [1, 2, 3]}) + '{"a": 42, "b": [1, 2, 3]}' + + Bound objects are attempted to be serialize using a ``__structlog__`` method. + If none is defined, ``repr()`` is used: + + .. doctest:: + + >>> class C1(object): + ... def __structlog__(self): + ... return ['C1!'] + ... def __repr__(self): + ... return '__structlog__ took precedence' + >>> class C2(object): + ... def __repr__(self): + ... return 'No __structlog__, so this is used.' + >>> from structlog.processors import JSONRenderer + >>> JSONRenderer(sort_keys=True)(None, None, {'c1': C1(), 'c2': C2()}) + '{"c1": ["C1!"], "c2": "No __structlog__, so this is used."}' + + Please note that additionally to strings, you can also return any type the standard library JSON module knows about -- like in this example a list. + .. autofunction:: plainJSONStdOutLogger .. autofunction:: JSONLogObserverWrapper diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 7ebf613c..5c3de7ec 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -45,7 +45,7 @@ twisted = None -__version__ = "16.0.0.dev0" +__version__ = "16.0.0.dev1" __title__ = "structlog" __description__ = "Structured Logging for Python" diff --git a/src/structlog/processors.py b/src/structlog/processors.py index e01f4a7b..db4d4812 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -33,14 +33,6 @@ class KeyValueRenderer(object): order. Missing keys will be rendered as `None`, extra keys depending on *sort_keys* and the dict class. - - >>> from structlog.processors import KeyValueRenderer - >>> KeyValueRenderer(sort_keys=True)(None, None, {'a': 42, 'b': [1, 2, 3]}) - 'a=42 b=[1, 2, 3]' - >>> KeyValueRenderer(key_order=['b', 'a'])(None, None, - ... {'a': 42, 'b': [1, 2, 3]}) - 'b=[1, 2, 3] a=42' - .. versionadded:: 0.2.0 `key_order` """ @@ -129,35 +121,13 @@ class JSONRenderer(object): """ Render the `event_dict` using `json.dumps(event_dict, **json_kw)`. - :param json_kw: Are passed unmodified to `json.dumps()`. + :param dict json_kw: Are passed unmodified to `json.dumps()`. :param callable serializer: A :meth:`json.dumps`-compatible callable that will be used to format the string. This can be used to use alternative JSON encoders like `simplejson `_ or `RapidJSON - `_. - - >>> from structlog.processors import JSONRenderer - >>> JSONRenderer(sort_keys=True)(None, None, {'a': 42, 'b': [1, 2, 3]}) - '{"a": 42, "b": [1, 2, 3]}' - - Bound objects are attempted to be serialize using a ``__structlog__`` - method. If none is defined, ``repr()`` is used: - - >>> class C1(object): - ... def __structlog__(self): - ... return ['C1!'] - ... def __repr__(self): - ... return '__structlog__ took precedence' - >>> class C2(object): - ... def __repr__(self): - ... return 'No __structlog__, so this is used.' - >>> from structlog.processors import JSONRenderer - >>> JSONRenderer(sort_keys=True)(None, None, {'c1': C1(), 'c2': C2()}) - '{"c1": ["C1!"], "c2": "No __structlog__, so this is used."}' - - Please note that additionally to strings, you can also return any type - the standard library JSON module knows about -- like in this example - a list. + `_ (faster but Python + 3-only). .. versionadded:: 0.2.0 Support for ``__structlog__`` serialization method. @@ -218,7 +188,8 @@ class TimeStamper(object): Add a timestamp to `event_dict`. .. note:: - You probably want to let OS tools take care of timestamping. See also + + You should let OS tools take care of timestamping. See also :doc:`logging-best-practices`. :param str format: strftime format string, or ``"iso"`` for `ISO 8601 @@ -226,14 +197,6 @@ class TimeStamper(object): timestamp `_. :param bool utc: Whether timestamp should be in UTC or local time. :param str key: Target key in `event_dict` for added timestamps. - - >>> from structlog.processors import TimeStamper - >>> TimeStamper()(None, None, {}) # doctest: +SKIP - {'timestamp': 1378994017} - >>> TimeStamper(fmt='iso')(None, None, {}) # doctest: +SKIP - {'timestamp': '2013-09-12T13:54:26.996778Z'} - >>> TimeStamper(fmt='%Y', key='year')(None, None, {}) # doctest: +SKIP - {'year': '2013'} """ def __new__(cls, fmt=None, utc=True, key='timestamp'): if fmt is None and not utc: @@ -295,6 +258,7 @@ class ExceptionPrettyPrinter(object): `exception` as well as `exc_info` keys. .. versionadded:: 0.4.0 + .. versionchanged:: 16.0.0 Added support for passing exceptions as ``exc_info`` on Python 3. """ From 3d4803733a202e7d5c88d642d889d7eaee302f26 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 27 Jan 2016 13:52:25 +0100 Subject: [PATCH 0062/1520] Newer changes go to the top --- CHANGELOG.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 209f9214..b2ddd173 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -25,14 +25,14 @@ Changes: ^^^^^^^^ - ``structlog.processors.ExceptionPrettyPrinter`` and ``structlog.processors.format_exc_info`` now support passing of Exceptions on Python 3. +- Clean up the context when exiting ``structlog.threadlocal.tmp_bind`` in case of exceptions. + [`64 `_] - Be more more lenient about missing ``__name__``\ s. [`62 `_] - Add ``structlog.dev.ConsoleRenderer`` that renders the event dictionary aligned and with colors. - Use `six `_ for compatibility. - Add ``structlog.processors.UnicodeDecoder`` that will decode all byte string values in an event dictionary to Unicode. - Add ``serializer`` parameter to ``structlog.processors.JSONRenderer`` which allows for using different (possibly faster) JSON encoders than the standard library. -- Clean up the context when exiting ``structlog.threadlocal.tmp_bind`` in case of exceptions. - [`64 `_] 15.3.0 (2015-09-25) From 8d5730e106113aaedbc731383abc780e213f10a9 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 28 Jan 2016 13:22:50 +0100 Subject: [PATCH 0063/1520] Add FAQ entry on stdlib integration --- CHANGELOG.rst | 13 ------------- README.rst | 2 +- docs/faq.rst | 33 ++++++++++++++++++++++++++++++++- setup.py | 17 ++++++++++++----- 4 files changed, 45 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b2ddd173..5c471a02 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,19 +8,6 @@ The third digit is only for regressions. 16.0.0 (UNRELEASED) ------------------- - -Backward-incompatible changes: -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -*none* - - -Deprecations: -^^^^^^^^^^^^^ - -*none* - - Changes: ^^^^^^^^ diff --git a/README.rst b/README.rst index 00506e82..33b98850 100644 --- a/README.rst +++ b/README.rst @@ -27,7 +27,7 @@ It allows you to split your log entries up into key/value pairs and build them i .. begin -It's dual-licensed under `Apache License, version 2 `_ and `MIT `_, available from `PyPI `_, the source code can be found on `GitHub `_, the documentation at `http://www.structlog.org/ `_. +It's dual-licensed under `Apache License, version 2 `_ and `MIT `_, available from `PyPI `_, the source code can be found on `GitHub `_, the documentation at http://www.structlog.org/. ``structlog`` targets Python 2.6, 2.7, 3.3 and newer, and PyPy. diff --git a/docs/faq.rst b/docs/faq.rst index 6a2cdee3..7f1952ab 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -2,7 +2,6 @@ Frequently Asked Questions ========================== I try to bind key-value pairs but they don't appear in the log files? - ``structlog``\ 's loggers are *immutable*. Meaning that you have to use the logger that is returned from ``bind()``: @@ -16,3 +15,35 @@ I try to bind key-value pairs but they don't appear in the log files? >>> new_log = log.bind(x=42) >>> new_log.msg("hello") x=42 event='hello' + + +How can I make third party components log in JSON too? + Since Twisted's logging is nicely composable, ``structlog`` comes with `integration support `_ out of the box. + + The standard library is a bit more complicated and tough to solve universally. + But generally speaking, all you need is a handler that will redirect standard library logging into ``structlog``. + For example like this:: + + import logging + + class StructlogHandler(logging.Handler): + """ + Feeds all events back into structlog. + """ + def __init__(self, *args, **kw): + super(StructlogHandler, self).__init__(*args, **kw) + self._log = structlog.get_logger() + + def emit(self, record): + self._log.log(record.levelno, record.msg, name=record.name) + + root_logger = logging.getLogger() + root_logger.addHandler(StructlogHandler()) + + There are two things to keep in mind: + + #. You can't log out using the standard library since that would create an infinite loop. + In other words you have to use for example ``PrintLogger`` for actual output (which is nothing wrong with). + #. You can't affect the logging of your parent process. + So for example if you're running a web application as `Gunicorn `_ workers, you have to configure Gunicorn's logging separately if you want it to write JSON logs. + In these cases a library like `python-json-logger `_ should come in handy. diff --git a/setup.py b/setup.py index 91cfa508..b6e95bd8 100644 --- a/setup.py +++ b/setup.py @@ -76,6 +76,17 @@ def find_meta(meta): raise RuntimeError("Unable to find __{meta}__ string.".format(meta=meta)) +LONG = ( + read("README.rst") + "\n\n" + + "Release Information\n" + + "===================\n\n" + + re.search("(\d{2}.\d.\d \(.*?\)\n.*?)\n\n\n", + read("CHANGELOG.rst"), re.S).group(1) + + "\n\n`Full changelog " + + "`_.\n\n" + + read("AUTHORS.rst") +) + if __name__ == "__main__": setup( name=NAME, @@ -87,11 +98,7 @@ def find_meta(meta): author_email=find_meta("email"), maintainer=find_meta("author"), maintainer_email=find_meta("email"), - long_description=( - read("README.rst") + "\n\n" + - read("AUTHORS.rst") + "\n\n" + - read("CHANGELOG.rst") - ), + long_description=LONG, keywords=KEYWORDS, packages=PACKAGES, package_dir={"": "src"}, From 8a429b1c6ce045d6f43ae8a093d18bcbc6623325 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 28 Jan 2016 13:37:18 +0100 Subject: [PATCH 0064/1520] Prepare 16.0.0 --- CHANGELOG.rst | 2 +- src/structlog/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5c471a02..ca9869c8 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,7 +5,7 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. -16.0.0 (UNRELEASED) +16.0.0 (2016-01-28) ------------------- Changes: diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 5c3de7ec..51a24c06 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -45,7 +45,7 @@ twisted = None -__version__ = "16.0.0.dev1" +__version__ = "16.0.0" __title__ = "structlog" __description__ = "Structured Logging for Python" From 1ce15febc80edaf5b730c47123137090650cab89 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 28 Jan 2016 13:52:35 +0100 Subject: [PATCH 0065/1520] Start new release cycle --- CHANGELOG.rst | 9 +++++++++ setup.py | 2 +- src/structlog/__init__.py | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ca9869c8..fd47b960 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,15 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. +16.1.0 (UNRELEASED) +------------------- + +Changes: +^^^^^^^^ + +*none* + + 16.0.0 (2016-01-28) ------------------- diff --git a/setup.py b/setup.py index b6e95bd8..86da25a3 100644 --- a/setup.py +++ b/setup.py @@ -83,7 +83,7 @@ def find_meta(meta): re.search("(\d{2}.\d.\d \(.*?\)\n.*?)\n\n\n", read("CHANGELOG.rst"), re.S).group(1) + "\n\n`Full changelog " + - "`_.\n\n" + + "`_.\n\n" + read("AUTHORS.rst") ) diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 51a24c06..6aeabc29 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -45,7 +45,7 @@ twisted = None -__version__ = "16.0.0" +__version__ = "16.1.0.dev0" __title__ = "structlog" __description__ = "Structured Logging for Python" From 9c6904a7f3b8df21aafdbc08d649d630e0da7239 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 1 Feb 2016 09:35:08 +0100 Subject: [PATCH 0066/1520] 1.4 --- CODE_OF_CONDUCT.rst | 59 ++++++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/CODE_OF_CONDUCT.rst b/CODE_OF_CONDUCT.rst index b7f31dd6..fa8b5bb2 100644 --- a/CODE_OF_CONDUCT.rst +++ b/CODE_OF_CONDUCT.rst @@ -1,30 +1,55 @@ -Contributor Code of Conduct -=========================== +Contributor Covenant Code of Conduct +==================================== -As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. +Our Pledge +---------- -We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +Our Standards +------------- + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members Examples of unacceptable behavior by participants include: -* The use of sexualized language or imagery -* Personal attacks -* Trolling or insulting/derogatory comments +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment -* Publishing other's private information, such as physical or electronic - addresses, without explicit permission -* Other unethical or unprofessional conduct +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +Our Responsibilities +-------------------- + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. -By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. -Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. +Scope +----- This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. +Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. +Representation of a project may be further defined and clarified by project maintainers. + +Enforcement +----------- + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hs@ox.cx. +all complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. +The project team is obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting a project maintainer at hs@ox.cx. -All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. -Maintainers are obligated to maintain confidentiality with regard to the reporter of an incident. +Attribution +----------- -This Code of Conduct is adapted from the `Contributor Covenant `_, -version 1.3.0, available at http://contributor-covenant.org/version/1/3/0/. +This Code of Conduct is adapted from the `Contributor Covenant `_, version 1.4, available at http://contributor-covenant.org/version/1/4. From 41595917902dd35c0ce109d0a9f0a0e3954cbf12 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 1 Feb 2016 20:37:17 +0100 Subject: [PATCH 0067/1520] Render also traceback-less exception (Py3) --- CHANGELOG.rst | 2 +- src/structlog/processors.py | 4 +--- tests/test_processors.py | 17 ++++++++++++++--- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index fd47b960..601fab9b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -11,7 +11,7 @@ The third digit is only for regressions. Changes: ^^^^^^^^ -*none* +- Exceptions without a ``__traceback__`` are now also rendered on Python 3. 16.0.0 (2016-01-28) diff --git a/src/structlog/processors.py b/src/structlog/processors.py index db4d4812..5dcc0ac6 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -234,9 +234,7 @@ def _figure_out_exc_info(v): if v is True: return sys.exc_info() elif six.PY3 and isinstance(v, BaseException): - tb = getattr(v, "__traceback__") - if tb is not None: - return (v.__class__, v, tb) + return (v.__class__, v, getattr(v, "__traceback__")) return v diff --git a/tests/test_processors.py b/tests/test_processors.py index 53bac0ff..a1517aba 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -242,6 +242,16 @@ def test_exception_on_py3(self, monkeypatch): else: pytest.fail("Exception not raised.") + @py3_only + def test_exception_without_traceback(self): + """ + If an Exception is missing a traceback, render it anyway. + """ + rv = format_exc_info(None, None, { + "exc_info": Exception("no traceback!") + }) + assert {"exception": "Exception: no traceback!"} == rv + class TestUnicodeEncoder(object): def test_encodes(self): @@ -422,10 +432,11 @@ def test_obtains_exc_info_on_True(self): else: pytest.fail("Exception not raised.") + @py3_only def test_py3_exception_no_traceback(self): """ - Not sure how likely this is but the ``raise`` docs are a bit vague. - If an exception without a traceback is passed it's passed back. + Exceptions without tracebacks are simply returned with None for + traceback. """ e = ValueError() - assert e is _figure_out_exc_info(e) + assert (e.__class__, e, None) == _figure_out_exc_info(e) From a82337ce6b66fd08feb455335a1cf300826e5b85 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 17 Feb 2016 12:34:20 +0100 Subject: [PATCH 0068/1520] Drop legacy Python version Keep 2.7 and PyPy tho. --- .travis.yml | 12 ++---------- CHANGELOG.rst | 12 ++++++++++++ README.rst | 2 +- docs/configuration.rst | 2 +- docs/getting-started.rst | 10 ---------- docs/loggers.rst | 4 ++-- docs/thread-local.rst | 2 +- setup.py | 2 -- src/structlog/__init__.py | 2 +- src/structlog/_compat.py | 37 ------------------------------------- src/structlog/_config.py | 3 ++- src/structlog/_frames.py | 2 +- tests/test_loggers.py | 2 +- tests/test_processors.py | 2 +- tests/test_threadlocal.py | 3 ++- tests/test_twisted.py | 4 +++- tox.ini | 13 ++++++++----- 17 files changed, 38 insertions(+), 76 deletions(-) delete mode 100644 src/structlog/_compat.py diff --git a/.travis.yml b/.travis.yml index 51d659cb..99906ff0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,18 +8,10 @@ language: python matrix: include: - - python: "2.6" # these are just to make travis's UI a bit prettier - env: TOXENV=py26-threads - - python: "2.6" - env: TOXENV=py26-greenlets - python: "2.7" env: TOXENV=py27-threads - python: "2.7" env: TOXENV=py27-greenlets - - python: "3.3" - env: TOXENV=py33-threads - - python: "3.3" - env: TOXENV=py33-greenlets - python: "3.4" env: TOXENV=py34-threads - python: "3.4" @@ -39,9 +31,9 @@ matrix: # Meta - python: "3.5" env: TOXENV=flake8 - - python: "2.7" + - python: "3.5" env: TOXENV=manifest - - python: "2.7" + - python: "3.5" env: TOXENV=docs - python: "3.5" env: TOXENV=readme diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 601fab9b..4bf8659b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,18 @@ The third digit is only for regressions. 16.1.0 (UNRELEASED) ------------------- +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Python 3.3 and 2.6 aren't supported anymore. + They may work by chance but any support to them has been ceased. + + The last Python 2.6 release was on October 29, 2013 and isn't supported by the CPython core team anymore. + Major Python packages like Django and Twisted dropped Python 2.6 a while ago already. + + Python 3.3 never had a significant user base and wasn't part of any distribution's LTS release. + + Changes: ^^^^^^^^ diff --git a/README.rst b/README.rst index 33b98850..23b0576c 100644 --- a/README.rst +++ b/README.rst @@ -29,6 +29,6 @@ It allows you to split your log entries up into key/value pairs and build them i It's dual-licensed under `Apache License, version 2 `_ and `MIT `_, available from `PyPI `_, the source code can be found on `GitHub `_, the documentation at http://www.structlog.org/. -``structlog`` targets Python 2.6, 2.7, 3.3 and newer, and PyPy. +``structlog`` targets Python 2.7, 3.4 and newer, and PyPy. If you need any help, visit us on ``#structlog`` on `Freenode `_! diff --git a/docs/configuration.rst b/docs/configuration.rst index 189bd66a..7392a750 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -30,7 +30,7 @@ The :ref:`example ` from the previous chapter could thus have been written from structlog import PrintLogger, configure, reset_defaults, wrap_logger, get_logger from structlog.threadlocal import wrap_dict def proc(logger, method_name, event_dict): - print 'I got called with', event_dict + print('I got called with', event_dict) return repr(event_dict) .. doctest:: config_wrap_logger diff --git a/docs/getting-started.rst b/docs/getting-started.rst index c8650f0c..488f2ca0 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -12,16 +12,6 @@ structlog can be easily installed using:: $ pip install structlog -Python 2.6 -^^^^^^^^^^ - -If you're running Python 2.6 and want to use ``OrderedDict``\ s for your context (which is the default), you also have to install the respective compatibility package:: - - $ pip install ordereddict - -If the order of the keys of your context doesn't matter (e.g. if you're logging JSON that gets parsed anyway), simply use a vanilla ``dict`` to avoid this dependency. -See :doc:`configuration` on how to achieve that. - Your First Log Entry -------------------- diff --git a/docs/loggers.rst b/docs/loggers.rst index 11e32ea8..627f62f1 100644 --- a/docs/loggers.rst +++ b/docs/loggers.rst @@ -24,9 +24,9 @@ For that there is the :func:`structlog.wrap_logger` function (or the convenience >>> from structlog import wrap_logger >>> class PrintLogger(object): ... def msg(self, message): - ... print message + ... print(message) >>> def proc(logger, method_name, event_dict): - ... print 'I got called with', event_dict + ... print('I got called with', event_dict) ... return repr(event_dict) >>> log = wrap_logger(PrintLogger(), processors=[proc], context_class=dict) >>> log2 = log.bind(x=42) diff --git a/docs/thread-local.rst b/docs/thread-local.rst index 722fd80d..a6001c06 100644 --- a/docs/thread-local.rst +++ b/docs/thread-local.rst @@ -51,7 +51,7 @@ Within one thread, every instance of the returned class will have a *common* ins >>> d1 == d2 == d3 == WrappedDictClass() True >>> d3 # doctest: +ELLIPSIS - + Then use an instance of the generated class as the context class:: diff --git a/setup.py b/setup.py index 86da25a3..39787263 100644 --- a/setup.py +++ b/setup.py @@ -21,10 +21,8 @@ "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: Implementation :: CPython", diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 6aeabc29..b5bca7e9 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -45,7 +45,7 @@ twisted = None -__version__ = "16.1.0.dev0" +__version__ = "16.1.0.dev1" __title__ = "structlog" __description__ = "Structured Logging for Python" diff --git a/src/structlog/_compat.py b/src/structlog/_compat.py deleted file mode 100644 index 0c03ae6a..00000000 --- a/src/structlog/_compat.py +++ /dev/null @@ -1,37 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the MIT License. See the LICENSE file in the root of this -# repository for complete details. - -""" -Compatibility utilities. -""" - -from __future__ import absolute_import, division, print_function - -import abc -import sys -import types - -from six import ( - PY2, PY3, string_types, integer_types, class_types, text_type -) - - -try: - from cStringIO import StringIO -except ImportError: - from io import StringIO # flake8: noqa - -if sys.version_info[:2] == (2, 6): - try: - from ordereddict import OrderedDict - except ImportError: # pragma: nocover - class OrderedDict(object): - def __init__(self, *args, **kw): - raise NotImplementedError( - 'The ordereddict package is needed on Python 2.6. ' - 'See .' - ) -else: - from collections import OrderedDict diff --git a/src/structlog/_config.py b/src/structlog/_config.py index cd350ed6..234dbcf1 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -10,7 +10,8 @@ import warnings -from structlog._compat import OrderedDict +from collections import OrderedDict + from structlog._generic import BoundLogger from structlog._loggers import ( PrintLoggerFactory, diff --git a/src/structlog/_frames.py b/src/structlog/_frames.py index a3b73b48..5c8e5ccb 100644 --- a/src/structlog/_frames.py +++ b/src/structlog/_frames.py @@ -7,7 +7,7 @@ import sys import traceback -from structlog._compat import StringIO +from six.moves import cStringIO as StringIO def _format_exception(exc_info): diff --git a/tests/test_loggers.py b/tests/test_loggers.py index 3d706516..28b5a8cf 100644 --- a/tests/test_loggers.py +++ b/tests/test_loggers.py @@ -8,7 +8,7 @@ import pytest -from structlog._compat import StringIO +from six.moves import cStringIO as StringIO from structlog._loggers import ( PrintLogger, PrintLoggerFactory, diff --git a/tests/test_processors.py b/tests/test_processors.py index a1517aba..5ad635d3 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -17,10 +17,10 @@ rapidjson = None from freezegun import freeze_time +from six.moves import cStringIO as StringIO import structlog -from structlog._compat import StringIO from structlog.processors import ( ExceptionPrettyPrinter, JSONRenderer, diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py index d44675c9..055d7b64 100644 --- a/tests/test_threadlocal.py +++ b/tests/test_threadlocal.py @@ -6,11 +6,12 @@ import threading +from collections import OrderedDict + import pytest from structlog._base import BoundLoggerBase from structlog._config import wrap_logger -from structlog._compat import OrderedDict from structlog._loggers import ReturnLogger from structlog.threadlocal import as_immutable, wrap_dict, tmp_bind diff --git a/tests/test_twisted.py b/tests/test_twisted.py index 2f87b532..67b4e1ce 100644 --- a/tests/test_twisted.py +++ b/tests/test_twisted.py @@ -6,15 +6,17 @@ import json +from collections import OrderedDict + import pytest from pretend import call_recorder from six import PY3 +from six.moves import cStringIO as StringIO from twisted.python.failure import Failure, NoCurrentExceptionError from twisted.python.log import ILogObserver from structlog._config import _CONFIG -from structlog._compat import OrderedDict, StringIO from structlog._loggers import ReturnLogger from structlog.twisted import ( BoundLogger, diff --git a/tox.ini b/tox.ini index b5b76cf9..c52258b2 100644 --- a/tox.ini +++ b/tox.ini @@ -1,17 +1,15 @@ [tox] -envlist = coverage-clean,{py26,py27,py33,py34,py35,pypy}-{threads,greenlets},py35-nocolorama,flake8,docs,readme,manifest,coverage-report +envlist = coverage-clean,{py27,py33,py34,py35,pypy}-{threads,greenlets},py35-nocolorama,flake8,docs,readme,manifest,coverage-report [testenv] deps = -rdev-requirements.txt greenlets: greenlet + twisted # indirectly ensure that only -nocolorama has no colorama threads: colorama>=0.3.6 greenlets: colorama>=0.3.6 - py26: ordereddict - py26: twisted<15.5.0 - py27,py33,py34,py35,pypy: twisted py33,py34,py35: python-rapidjson setenv = PYTHONHASHSEED = 0 @@ -19,13 +17,14 @@ commands = coverage run --parallel -m pytest {posargs} [testenv:flake8] -skip_install = true basepython = python3.5 +skip_install = true deps = flake8 commands = flake8 src tests setup.py docs/conf.py [testenv:docs] +basepython = python3.5 setenv = PYTHONHASHSEED = 0 deps = @@ -37,24 +36,28 @@ commands = [testenv:readme] +basepython = python3.5 deps = readme_renderer skip_install = true commands = python setup.py check -r -s [testenv:manifest] +basepython = python3.5 skip_install = true deps = check-manifest commands = check-manifest [testenv:coverage-clean] +basepython = python3.5 deps = coverage skip_install = true commands = coverage erase [testenv:coverage-report] +basepython = python3.5 deps = coverage skip_install = true commands = From ea0833e94a87381d994caf38d95ce030533408c7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 17 Feb 2016 14:27:14 +0100 Subject: [PATCH 0069/1520] Make Travis stop emailing me --- .travis.yml | 8 ++++++++ CHANGELOG.rst | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 99906ff0..52b93e0e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,15 +38,23 @@ matrix: - python: "3.5" env: TOXENV=readme + install: - pip install tox + script: - tox + before_install: - pip install codecov + after_success: - tox -e coverage-report - codecov + + +notifications: + email: false diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4bf8659b..f1fbcacb 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,7 +12,7 @@ Backward-incompatible changes: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Python 3.3 and 2.6 aren't supported anymore. - They may work by chance but any support to them has been ceased. + They may work by chance but any effort to keep them working has ceased. The last Python 2.6 release was on October 29, 2013 and isn't supported by the CPython core team anymore. Major Python packages like Django and Twisted dropped Python 2.6 a while ago already. From 42d28234531d4f04d40ad2e9a21dbbeb7d392464 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 29 Mar 2016 10:23:52 +0200 Subject: [PATCH 0070/1520] Add dividers to changelog --- CHANGELOG.rst | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f1fbcacb..c045ab9f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -26,6 +26,9 @@ Changes: - Exceptions without a ``__traceback__`` are now also rendered on Python 3. +---- + + 16.0.0 (2016-01-28) ------------------- @@ -43,6 +46,9 @@ Changes: - Add ``serializer`` parameter to ``structlog.processors.JSONRenderer`` which allows for using different (possibly faster) JSON encoders than the standard library. +---- + + 15.3.0 (2015-09-25) ------------------- @@ -55,6 +61,9 @@ Changes: - Add ``structlog.ReturnLogger.failure`` and ``structlog.PrintLogger.failure`` as preparation for the new Twisted logging system. +---- + + 15.2.0 (2015-06-10) ------------------- @@ -71,6 +80,9 @@ Changes: [`51 `_] +---- + + 15.1.0 (2015-02-24) ------------------- @@ -80,6 +92,9 @@ Changes: - Tolerate frames without a ``__name__``. +---- + + 15.0.0 (2015-01-23) ------------------- @@ -99,6 +114,9 @@ Changes: [`22 `_] +---- + + 0.4.2 (2014-07-26) ------------------ @@ -120,6 +138,9 @@ Changes: - ``from structlog import *`` works now (but you still shouldn't use it). +---- + + 0.4.1 (2013-12-19) ------------------ @@ -131,6 +152,9 @@ Changes: - Various doc fixes. +---- + + 0.4.0 (2013-11-10) ------------------ @@ -154,6 +178,9 @@ Changes: [`5 `_] +---- + + 0.3.2 (2013-09-27) ------------------ @@ -163,6 +190,9 @@ Changes: - Fix stdlib's name guessing. +---- + + 0.3.1 (2013-09-26) ------------------ @@ -172,6 +202,9 @@ Changes: - Add forgotten ``structlog.processors.TimeStamper`` to API documentation. +---- + + 0.3.0 (2013-09-23) ------------------ @@ -191,6 +224,9 @@ Changes: See ``structlog.BoundLoggerBase``. +---- + + 0.2.0 (2013-09-17) ------------------ @@ -204,6 +240,9 @@ Changes: - Allow for custom serialization in ``structlog.twisted.JSONRenderer`` without abusing ``__repr__``. +---- + + 0.1.0 (2013-09-16) ------------------ From 0e083381fb06221e94c7a80beb2266a7b742ce56 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 29 Mar 2016 10:24:11 +0200 Subject: [PATCH 0071/1520] Fix coverage reporting for Python 2 --- tox.ini | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index c52258b2..12adb358 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = coverage-clean,{py27,py33,py34,py35,pypy}-{threads,greenlets},py35-nocolorama,flake8,docs,readme,manifest,coverage-report +envlist = coverage-clean,{py27,py34,py35,pypy}-{threads,greenlets},py35-nocolorama,flake8,docs,readme,manifest,coverage-report [testenv] @@ -57,7 +57,6 @@ commands = coverage erase [testenv:coverage-report] -basepython = python3.5 deps = coverage skip_install = true commands = From 8df0ef912b496a7e40ed1bd7bf6e6e36283f42e1 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 19 Apr 2016 12:00:13 +0200 Subject: [PATCH 0072/1520] It's bdist_wheel now --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index f8a6c9a6..4a9b6ce5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,6 +4,6 @@ strict = true addopts = -ra testpaths = tests -[wheel] +[bdist_wheel] # we're pure-python universal = 1 From e22484ccfb95cb5326ce37252ecddf65999bd36c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 28 Apr 2016 08:14:53 +0200 Subject: [PATCH 0073/1520] Fix links --- CONTRIBUTING.rst | 2 +- docs/logging-best-practices.rst | 4 ++-- docs/performance.rst | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index a2cbcbe3..e858a964 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -35,7 +35,7 @@ Thank you for considering to contribute to ``structlog``! .. _`good test docstrings`: https://jml.io/pages/test-docstrings.html .. _`Code of Conduct`: https://github.com/hynek/structlog/blob/master/CODE_OF_CONDUCT.rst .. _changelog: https://github.com/hynek/structlog/blob/master/CHANGELOG.rst -.. _`backward compatibility`: https://structlog.readthedocs.org/en/latest/backward-compatibility.html +.. _`backward compatibility`: http://www.structlog.org/en/latest/backward-compatibility.html .. _`tox`: https://testrun.org/tox/ .. _`Travis CI`: https://travis-ci.org/ .. _pyenv: https://github.com/yyuu/pyenv diff --git a/docs/logging-best-practices.rst b/docs/logging-best-practices.rst index c2de415f..4a88e9d2 100644 --- a/docs/logging-best-practices.rst +++ b/docs/logging-best-practices.rst @@ -94,13 +94,13 @@ Additionally, `Graylog's Extended Log Format`_ (GELF) allows for structured data .. _Logstash: https://www.elastic.co/products/logstash .. _logstash-forwarder: https://github.com/elastic/logstash-forwarder .. _RabbitMQ: http://www.rabbitmq.com -.. _`Graylog's Extended Log Format`: https://www.graylog.org/resources/gelf/ +.. _`Graylog's Extended Log Format`: http://docs.graylog.org/en/latest/pages/gelf.html .. _`daemon showdown`: https://web.archive.org/web/20130907200323/http://tech.cueup.com/blog/2013/03/08/running-daemons/ .. _`standard out`: https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29 .. _`they can be switched off`: http://blog.abhijeetr.com/2013/01/disable-rate-limiting-in-rsyslog-v5.html .. _`this post`: http://www.revsys.com/blog/2010/aug/26/centralized-logging-fun-and-profit/ .. _`this tutorial`: https://rubyists.github.io/2011/05/02/runit-for-ruby-and-everything-else.html -.. _logrotate: http://manpages.ubuntu.com/manpages/raring/man8/logrotate.8.html +.. _logrotate: http://manpages.ubuntu.com/manpages/xenial/en/man8/logrotate.8.html .. _rsyslog: http://www.rsyslog.com .. _runit: http://smarden.org/runit/ .. _svlogd: http://smarden.org/runit/svlogd.8.html diff --git a/docs/performance.rst b/docs/performance.rst index 2cce90e3..e3f4ddca 100644 --- a/docs/performance.rst +++ b/docs/performance.rst @@ -41,6 +41,6 @@ Here are a few hints how to get most out of ``structlog`` in production: structlog.processors.JSONRenderer(serializer=rapidjson.dumps) -.. _simplejson: https://simplejson.readthedocs.org/ +.. _simplejson: https://simplejson.readthedocs.io/ .. _UltraJSON: https://github.com/esnme/ultrajson/ .. _RapidJSON: https://pypi.python.org/pypi/python-rapidjson/ From 0efdf93c65952e8dd3da4c2a488ef02070cd2a88 Mon Sep 17 00:00:00 2001 From: Marc Sibson Date: Mon, 25 Apr 2016 09:55:26 -0700 Subject: [PATCH 0074/1520] drop missing keys from KeyValueRender Rather than render as None, simply drop any missing keys --- src/structlog/processors.py | 12 ++++++++---- tests/test_processors.py | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 5dcc0ac6..af578f44 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -31,19 +31,22 @@ class KeyValueRenderer(object): :param bool sort_keys: Whether to sort keys when formatting. :param list key_order: List of keys that should be rendered in this exact order. Missing keys will be rendered as `None`, extra keys depending - on *sort_keys* and the dict class. + on *sort_keys* and the dict class unless drop_missing is True. + :param bool drop_missing: When True, extra keys in key_order will be dropped rather + than rendered as None .. versionadded:: 0.2.0 `key_order` """ - def __init__(self, sort_keys=False, key_order=None): + def __init__(self, sort_keys=False, key_order=None, drop_missing=False): # Use an optimized version for each case. if key_order and sort_keys: def ordered_items(event_dict): items = [] for key in key_order: value = event_dict.pop(key, None) - items.append((key, value)) + if value or not drop_missing: + items.append((key, value)) items += sorted(event_dict.items()) return items elif key_order: @@ -51,7 +54,8 @@ def ordered_items(event_dict): items = [] for key in key_order: value = event_dict.pop(key, None) - items.append((key, value)) + if value or not drop_missing: + items.append((key, value)) items += event_dict.items() return items elif sort_keys: diff --git a/tests/test_processors.py b/tests/test_processors.py index 5ad635d3..2cee8434 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -82,6 +82,16 @@ def test_order_missing(self, event_dict): (None, None, event_dict) ) + def test_order_missing_dropped(self, event_dict): + """ + Missing keys get dropped + """ + assert ( + r"y='test' b=[3, 4] a= z=(1, 2) x=7" == + KeyValueRenderer(key_order=['c', 'y', 'b', 'a', 'z', 'x'], drop_missing=True) + (None, None, event_dict) + ) + def test_order_extra(self, event_dict): """ Extra keys get sorted if sort_keys=True. @@ -95,6 +105,19 @@ def test_order_extra(self, event_dict): (None, None, event_dict) ) + def test_order_sorted_missing_dropped(self, event_dict): + """ + Keys get sorted if sort_keys=True and extras get dropped. + """ + event_dict['B'] = 'B' + event_dict['A'] = 'A' + assert ( + r"y='test' b=[3, 4] a= z=(1, 2) x=7 A='A' B='B'" == + KeyValueRenderer(key_order=['c', 'y', 'b', 'a', 'z', 'x'], + sort_keys=True, drop_missing=True) + (None, None, event_dict) + ) + def test_random_order(self, event_dict): """ No special ordering doesn't blow up. From 2cd7e96843eec01a0cf4e461121862410d9362b0 Mon Sep 17 00:00:00 2001 From: Marc Sibson Date: Mon, 25 Apr 2016 11:14:23 -0700 Subject: [PATCH 0075/1520] style fixin --- src/structlog/processors.py | 4 ++-- tests/test_processors.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/structlog/processors.py b/src/structlog/processors.py index af578f44..091d1f3b 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -32,8 +32,8 @@ class KeyValueRenderer(object): :param list key_order: List of keys that should be rendered in this exact order. Missing keys will be rendered as `None`, extra keys depending on *sort_keys* and the dict class unless drop_missing is True. - :param bool drop_missing: When True, extra keys in key_order will be dropped rather - than rendered as None + :param bool drop_missing: When True, extra keys in key_order will be + dropped rather than rendered as None .. versionadded:: 0.2.0 `key_order` diff --git a/tests/test_processors.py b/tests/test_processors.py index 2cee8434..5737259b 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -88,7 +88,8 @@ def test_order_missing_dropped(self, event_dict): """ assert ( r"y='test' b=[3, 4] a= z=(1, 2) x=7" == - KeyValueRenderer(key_order=['c', 'y', 'b', 'a', 'z', 'x'], drop_missing=True) + KeyValueRenderer(key_order=['c', 'y', 'b', 'a', 'z', 'x'], + drop_missing=True) (None, None, event_dict) ) From b730d9a94a61c13f902b85ac0a60ba8e1329c498 Mon Sep 17 00:00:00 2001 From: Marc Sibson Date: Wed, 4 May 2016 08:57:04 -0700 Subject: [PATCH 0076/1520] only drop None --- src/structlog/processors.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 091d1f3b..0991c732 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -45,7 +45,7 @@ def ordered_items(event_dict): items = [] for key in key_order: value = event_dict.pop(key, None) - if value or not drop_missing: + if value is not None or not drop_missing: items.append((key, value)) items += sorted(event_dict.items()) return items @@ -54,7 +54,7 @@ def ordered_items(event_dict): items = [] for key in key_order: value = event_dict.pop(key, None) - if value or not drop_missing: + if value is not None or not drop_missing: items.append((key, value)) items += event_dict.items() return items From fafe9fbe32ed2c5db0ec7fb05cb6cf9fa92cba38 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 8 May 2016 08:33:32 +0200 Subject: [PATCH 0077/1520] Add CHANGELOG entry + light docs polishing --- CHANGELOG.rst | 3 +++ src/structlog/processors.py | 12 +++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c045ab9f..22e80e69 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -23,6 +23,9 @@ Backward-incompatible changes: Changes: ^^^^^^^^ +- Add a ``drop_missing`` argument to ``KeyValueRenderer``. + If ``key_order`` is used and a key is missing a value, it's not rendered at all instead of being rendered as ``None``. + `#67 `_ - Exceptions without a ``__traceback__`` are now also rendered on Python 3. diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 0991c732..29ff387a 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -30,13 +30,15 @@ class KeyValueRenderer(object): :param bool sort_keys: Whether to sort keys when formatting. :param list key_order: List of keys that should be rendered in this exact - order. Missing keys will be rendered as `None`, extra keys depending - on *sort_keys* and the dict class unless drop_missing is True. - :param bool drop_missing: When True, extra keys in key_order will be - dropped rather than rendered as None + order. Missing keys will be rendered as ``None``, extra keys depending + on *sort_keys* and the dict class. + :param bool drop_missing: When True, extra keys in *key_order* will be + dropped rather than rendered as ``None``. .. versionadded:: 0.2.0 - `key_order` + *key_order* + .. versionadded:: 16.1.0 + *drop_missing* """ def __init__(self, sort_keys=False, key_order=None, drop_missing=False): # Use an optimized version for each case. From 9ae0c00ffa84ea7cb77d9a5d8985628b67dd56af Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 8 May 2016 09:34:21 +0200 Subject: [PATCH 0078/1520] Doc tweaks --- docs/code_examples/processors/timestamper.py | 2 +- docs/configuration.rst | 16 ++++++++-------- docs/examples.rst | 8 ++++---- docs/getting-started.rst | 20 +++++++++++--------- docs/loggers.rst | 10 +++++----- docs/logging-best-practices.rst | 2 +- docs/processors.rst | 5 ++--- docs/standard-library.rst | 8 ++++---- docs/thread-local.rst | 6 +++--- docs/twisted.rst | 12 ++++++------ docs/why.rst | 6 +++--- 11 files changed, 48 insertions(+), 47 deletions(-) diff --git a/docs/code_examples/processors/timestamper.py b/docs/code_examples/processors/timestamper.py index e6fa9180..9f81f094 100644 --- a/docs/code_examples/processors/timestamper.py +++ b/docs/code_examples/processors/timestamper.py @@ -3,5 +3,5 @@ def timestamper(logger, log_method, event_dict): - event_dict['timestamp'] = calendar.timegm(time.gmtime()) + event_dict["timestamp"] = calendar.timegm(time.gmtime()) return event_dict diff --git a/docs/configuration.rst b/docs/configuration.rst index 7392a750..1c50a57e 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -7,7 +7,7 @@ Configuration Global Defaults --------------- -To make logging as unintrusive and straight-forward to use as possible, structlog comes with a plethora of configuration options and convenience functions. +To make logging as unintrusive and straight-forward to use as possible, ``structlog`` comes with a plethora of configuration options and convenience functions. Let me start at the end and introduce you to the ultimate convenience function that relies purely on configuration: :func:`structlog.get_logger` (and its Twisted-friendly alias :func:`structlog.getLogger`). The goal is to reduce your per-file logging boilerplate to:: @@ -57,7 +57,7 @@ because :class:`~structlog.processors.PrintLogger` is the default ``LoggerFactor #. Arguments passed to :func:`structlog.wrap_logger` *always* take the highest precedence over configuration. That means that you can overwrite whatever you've configured for each logger respectively. -#. If you leave them on `None`, structlog will check whether you've configured default values using :func:`structlog.configure` and uses them if so. +#. If you leave them on `None`, ``structlog`` will check whether you've configured default values using :func:`structlog.configure` and uses them if so. #. If you haven't configured or passed anything at all, the default fallback values are used which means :class:`collections.OrderedDict` for context and ``[``:class:`~structlog.processors.StackInfoRenderer`, :func:`~structlog.processors.format_exc_info`, :class:`~structlog.processors.KeyValueRenderer`\ ``]`` for the processor chain, and `False` for `cache_logger_on_first_use`. If necessary, you can always reset your global configuration back to default values using :func:`structlog.reset_defaults`. @@ -65,7 +65,7 @@ That can be handy in tests. .. note:: - Since you will call :func:`structlog.wrap_logger` (or one of the ``get_logger()`` functions) most likely at import time and thus before you had a chance to configure structlog, they return a **proxy** that returns a correct wrapped logger on first ``bind()``/``new()``. + Since you will call :func:`structlog.wrap_logger` (or one of the ``get_logger()`` functions) most likely at import time and thus before you had a chance to configure ``structlog``, they return a **proxy** that returns a correct wrapped logger on first ``bind()``/``new()``. Therefore, you must not call ``new()`` or ``bind()`` in module scope! Use :func:`~structlog.get_logger`\ 's ``initial_values`` to achieve pre-populated contexts. @@ -90,17 +90,17 @@ But you can also pass in an instance of a class with a ``__call__`` method for m :func:`structlog.get_logger` can optionally take positional parameters. These will be passed to the logger factories. -For example, if you use run ``structlog.get_logger('a name')`` and configure structlog to use the standard library :class:`~structlog.stdlib.LoggerFactory` which has support for positional parameters, the returned logger will have the name ``'a name'``. +For example, if you use run ``structlog.get_logger('a name')`` and configure ``structlog`` to use the standard library :class:`~structlog.stdlib.LoggerFactory` which has support for positional parameters, the returned logger will have the name ``'a name'``. When writing custom logger factories, they should always accept positional parameters even if they don't use them. That makes sure that loggers are interchangeable. -For the common cases of standard library logging and Twisted logging, structlog comes with two factories built right in: +For the common cases of standard library logging and Twisted logging, ``structlog`` comes with two factories built right in: - :class:`structlog.stdlib.LoggerFactory` - :class:`structlog.twisted.LoggerFactory` -So all it takes to use structlog with standard library logging is this:: +So all it takes to use ``structlog`` with standard library logging is this:: >>> from structlog import get_logger, configure >>> from structlog.stdlib import LoggerFactory @@ -109,7 +109,7 @@ So all it takes to use structlog with standard library logging is this:: >>> log.critical('this is too easy!') event='this is too easy!' -By using structlog's :class:`structlog.stdlib.LoggerFactory`, it is also ensured that variables like function names and line numbers are expanded correctly in your log format. +By using ``structlog``'s :class:`structlog.stdlib.LoggerFactory`, it is also ensured that variables like function names and line numbers are expanded correctly in your log format. The :ref:`Twisted example ` shows how easy it is for Twisted. @@ -143,4 +143,4 @@ If you use standard library's logging, it makes sense to configure them next to The `plugin definition `_ is the best place. If your app is not a plugin, put it into your `tac file `_ (and then `learn `_ about plugins). -If you have no choice but *have* to configure on import time in module-global scope, or can't rule out for other reasons that that your :func:`structlog.configure` gets called more than once, structlog offers :func:`structlog.configure_once` that raises a warning if structlog has been configured before (no matter whether using :func:`structlog.configure` or :func:`~structlog.configure_once`) but doesn't change anything. +If you have no choice but *have* to configure on import time in module-global scope, or can't rule out for other reasons that that your :func:`structlog.configure` gets called more than once, ``structlog`` offers :func:`structlog.configure_once` that raises a warning if ``structlog`` has been configured before (no matter whether using :func:`structlog.configure` or :func:`~structlog.configure_once`) but doesn't change anything. diff --git a/docs/examples.rst b/docs/examples.rst index 973d9018..97a49039 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -3,7 +3,7 @@ Examples ======== -This chapter is intended to give you a taste of realistic usage of structlog. +This chapter is intended to give you a taste of realistic usage of ``structlog``. .. _flask-example: @@ -49,7 +49,7 @@ gives you something like: ... peer='10.10.0.1' connection_id='85234511-...' count=1 data='cba\n' event='echoed data!' ... peer='127.0.0.1' connection_id='1c6c0cb5-...' count=4 data='bar\n' event='echoed data!' -Since Twisted's logging system is a bit peculiar, structlog ships with an :class:`adapter ` so it keeps behaving like you'd expect it to behave. +Since Twisted's logging system is a bit peculiar, ``structlog`` ships with an :class:`adapter ` so it keeps behaving like you'd expect it to behave. I'd also like to point out the Counter class that doesn't do anything spectacular but gets bound *once* per connection to the logger and since its repr is the number itself, it's logged out correctly for each event. This shows off the strength of keeping a dict of objects for context instead of passing around serialized strings. @@ -60,7 +60,7 @@ This shows off the strength of keeping a dict of objects for context instead of Processors ---------- -:ref:`Processors` are a both simple and powerful feature of structlog. +:ref:`Processors` are a both simple and powerful feature of ``structlog``. So you want timestamps as part of the structure of the log entry, censor passwords, filter out log entries below your log level before they even get rendered, and get your output as JSON for convenient parsing? Here you go: @@ -97,4 +97,4 @@ Here you go: "timestamp": "datetime.datetime(..., ..., ..., ..., ...)" } -structlog comes with many handy processors build right in -- for a list of shipped processors, check out the :ref:`API documentation `. +``structlog`` comes with many handy processors build right in -- for a list of shipped processors, check out the :ref:`API documentation `. diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 488f2ca0..235b617d 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -8,7 +8,7 @@ Getting Started Installation ------------ -structlog can be easily installed using:: +``structlog`` can be easily installed using:: $ pip install structlog @@ -16,7 +16,7 @@ structlog can be easily installed using:: Your First Log Entry -------------------- -A lot of effort went into making structlog accessible without reading pages of documentation. +A lot of effort went into making ``structlog`` accessible without reading pages of documentation. And indeed, the simplest possible usage looks like this: .. doctest:: @@ -26,7 +26,7 @@ And indeed, the simplest possible usage looks like this: >>> log.msg('greeted', whom='world', more_than_a_string=[1, 2, 3]) whom='world' more_than_a_string=[1, 2, 3] event='greeted' -Here, structlog takes full advantage of its hopefully useful default settings: +Here, ``structlog`` takes full advantage of its hopefully useful default settings: - Output is sent to `standard out`_ instead of exploding into the user's face. Yes, that seems a rather controversial attitude towards logging. @@ -71,11 +71,13 @@ Let's have a look at a better approach: Suddenly your logger becomes your closure! -For structlog, a log entry is just a dictionary called *event dict[ionary]*: +For ``structlog``, a log entry is just a dictionary called *event dict[ionary]*: - You can pre-build a part of the dictionary step by step. These pre-saved values are called the *context*. - As soon as an *event* happens -- which is a dictionary too -- it is merged together with the *context* to an *event dict* and logged out. +- If you don't like the concept of pre-building a context: just don't! + Convenient key-value-based logging is great to have on it's own. - To keep as much order of the keys as possible, an :class:`collections.OrderedDict` is used for the context by default. - The recommended way of binding values is the one in these examples: creating new loggers with a new context. If you're okay with giving up immutable local state for convenience, you can also use :ref:`thread/greenlet local storage ` for the context. @@ -86,12 +88,12 @@ For structlog, a log entry is just a dictionary called *event dict[ionary]*: structlog and Standard Library's logging ---------------------------------------- -structlog's primary application isn't printing though. +``structlog``'s primary application isn't printing though. Instead, it's intended to wrap your *existing* loggers and **add** *structure* and *incremental context building* to them. -For that, structlog is *completely* agnostic of your underlying logger -- you can use it with any logger you like. +For that, ``structlog`` is *completely* agnostic of your underlying logger -- you can use it with any logger you like. The most prominent example of such an 'existing logger' is without doubt the logging module in the standard library. -To make this common case as simple as possible, structlog comes with some tools to help you: +To make this common case as simple as possible, ``structlog`` comes with some tools to help you: .. doctest:: @@ -104,9 +106,9 @@ To make this common case as simple as possible, structlog comes with some tools >>> log.warn('it works!', difficulty='easy') # doctest: +SKIP WARNING:structlog...:difficulty='easy' event='it works!' -In other words, you tell structlog that you would like to use the standard library logger factory and keep calling :func:`~structlog.get_logger` like before. +In other words, you tell ``structlog`` that you would like to use the standard library logger factory and keep calling :func:`~structlog.get_logger` like before. -Since structlog is mainly used together with standard library's logging, there's :doc:`more ` goodness to make it as fast and convenient as possible. +Since ``structlog`` is mainly used together with standard library's logging, there's :doc:`more ` goodness to make it as fast and convenient as possible. Liked what you saw? diff --git a/docs/loggers.rst b/docs/loggers.rst index 627f62f1..6b7357d5 100644 --- a/docs/loggers.rst +++ b/docs/loggers.rst @@ -5,7 +5,7 @@ Loggers Bound Loggers ------------- -The center of structlog is the immutable log wrapper :class:`~structlog.BoundLogger`. +The center of ``structlog`` is the immutable log wrapper :class:`~structlog.BoundLogger`. All it does is: @@ -77,7 +77,7 @@ Additionally, the following arguments are allowed too: .. note:: Free your mind from the preconception that log entries have to be serialized to strings eventually. - All structlog cares about is a *dictionary* of *keys* and *values*. + All ``structlog`` cares about is a *dictionary* of *keys* and *values*. What happens to it depends on the logger you wrap and your processors alone. This gives you the power to log directly to databases, log aggregation servers, web services, and whatnot. @@ -86,7 +86,7 @@ Additionally, the following arguments are allowed too: Printing and Testing -------------------- -To save you the hassle of using standard library logging for simple standard out logging, structlog ships a :class:`~structlog.PrintLogger` that can log into arbitrary files -- including standard out (which is the default if no file is passed into the constructor): +To save you the hassle of using standard library logging for simple standard out logging, ``structlog`` ships a :class:`~structlog.PrintLogger` that can log into arbitrary files -- including standard out (which is the default if no file is passed into the constructor): .. doctest:: @@ -96,7 +96,7 @@ To save you the hassle of using standard library logging for simple standard out It's handy for both examples and in combination with tools like `runit `_ or `stdout/stderr-forwarding `_. -Additionally -- mostly for unit testing -- structlog also ships with a logger that just returns whatever it gets passed into it: :class:`~structlog.ReturnLogger`. +Additionally -- mostly for unit testing -- ``structlog`` also ships with a logger that just returns whatever it gets passed into it: :class:`~structlog.ReturnLogger`. .. doctest:: @@ -110,4 +110,4 @@ Additionally -- mostly for unit testing -- structlog also ships with a logger th (('hello',), {'when': 'again'}) -.. [*] Since this is slightly magicy, structlog comes with concrete loggers for the :doc:`standard-library` and :doc:`twisted` that offer you explicit APIs for the supported logging methods but behave identically like the generic BoundLogger otherwise. +.. [*] Since this is slightly magicy, ``structlog`` comes with concrete loggers for the :doc:`standard-library` and :doc:`twisted` that offer you explicit APIs for the supported logging methods but behave identically like the generic BoundLogger otherwise. diff --git a/docs/logging-best-practices.rst b/docs/logging-best-practices.rst index 4a88e9d2..441bdfad 100644 --- a/docs/logging-best-practices.rst +++ b/docs/logging-best-practices.rst @@ -85,7 +85,7 @@ Graylog2 Graylog_ goes one step further. It not only supports everything those above do (and then some); you can also log directly JSON entries towards it -- optionally even through an AMQP server (like RabbitMQ_) for better reliability. -Additionally, `Graylog's Extended Log Format`_ (GELF) allows for structured data which makes it an obvious choice to use together with structlog. +Additionally, `Graylog's Extended Log Format`_ (GELF) allows for structured data which makes it an obvious choice to use together with ``structlog``. .. [*] This is obviously a privileged UNIX-centric view but even Windows has tools and means for log management although we won't be able to discuss them here. diff --git a/docs/processors.rst b/docs/processors.rst index d873a3af..5dea766f 100644 --- a/docs/processors.rst +++ b/docs/processors.rst @@ -63,8 +63,7 @@ Parsing human-readable timestamps is tedious, not so `UNIX timestamps `_! If you're a heavy :mod:`logging` user, your `help `_ to ensure a better compatibility would be highly appreciated! @@ -11,7 +11,7 @@ If you're a heavy :mod:`logging` user, your `help `_: +And since it's more important that people actually *use* ``structlog`` than to be pure and snobby, ``structlog`` contains a dirty but convenient trick: thread local context storage which you may already know from `Flask `_: Thread local storage makes your logger's context global but *only within the current thread*\ [*]_. In the case of web frameworks this usually means that your context becomes global to the current request. @@ -34,7 +34,7 @@ The following explanations may sound a bit confusing at first but the :ref:`Flas Wrapped Dicts ------------- -In order to make your context thread local, structlog ships with a function that can wrap any dict-like class to make it usable for thread local storage: :func:`structlog.threadlocal.wrap_dict`. +In order to make your context thread local, ``structlog`` ships with a function that can wrap any dict-like class to make it usable for thread local storage: :func:`structlog.threadlocal.wrap_dict`. Within one thread, every instance of the returned class will have a *common* instance of the wrapped dict-like class: @@ -134,7 +134,7 @@ You can easily write deterministic tests using a call-capturing processor if you This big red box is also what separates immutable local from mutable global data. -.. [*] In the spirit of Python's 'consenting adults', structlog doesn't enforce the immutability with technical means. +.. [*] In the spirit of Python's 'consenting adults', ``structlog`` doesn't enforce the immutability with technical means. However, if you don't meddle with undocumented data, the objects can be safely considered immutable. .. [*] Special care has been taken to detect and support greenlets properly. diff --git a/docs/twisted.rst b/docs/twisted.rst index 235022d9..2ad4b6f2 100644 --- a/docs/twisted.rst +++ b/docs/twisted.rst @@ -9,20 +9,20 @@ Twisted Concrete Bound Logger --------------------- -To make structlog's behavior less magicy, it ships with a Twisted-specific wrapper class that has an explicit API instead of improvising: :class:`structlog.twisted.BoundLogger`. +To make ``structlog``'s behavior less magicy, it ships with a Twisted-specific wrapper class that has an explicit API instead of improvising: :class:`structlog.twisted.BoundLogger`. It behaves exactly like the generic :class:`structlog.BoundLogger` except: - it's slightly faster due to less overhead, - has an explicit API (:func:`~structlog.twisted.BoundLogger.msg` and :func:`~structlog.twisted.BoundLogger.err`), - hence causing less cryptic error messages if you get method names wrong. -In order to avoid that structlog disturbs your CamelCase harmony, it comes with an alias for :func:`structlog.get_logger` called :func:`structlog.getLogger`. +In order to avoid that ``structlog`` disturbs your CamelCase harmony, it comes with an alias for :func:`structlog.get_logger` called :func:`structlog.getLogger`. Processors ---------- -structlog comes with two Twisted-specific processors: +``structlog`` comes with two Twisted-specific processors: :class:`~structlog.twisted.EventAdapter` This is useful if you have an existing Twisted application and just want to wrap your loggers for now. @@ -42,7 +42,7 @@ structlog comes with two Twisted-specific processors: configure(processors=[EventAdapter(KeyValueRenderer()]) The drawback of this approach is that Twisted will format your exceptions as multi-line log entries which is painful to parse. - Therefore structlog comes with: + Therefore ``structlog`` comes with: :class:`~structlog.twisted.JSONRenderer` @@ -53,7 +53,7 @@ structlog comes with two Twisted-specific processors: Bending Foreign Logging To Your Will ------------------------------------ -structlog comes with a wrapper for Twisted's log observers to ensure the rest of your logs are in JSON too: :func:`~structlog.twisted.JSONLogObserverWrapper`. +``structlog`` comes with a wrapper for Twisted's log observers to ensure the rest of your logs are in JSON too: :func:`~structlog.twisted.JSONLogObserverWrapper`. What it does is determining whether a log entry has been formatted by :class:`~structlog.twisted.JSONRenderer` and if not, converts the log entry to JSON with `event` being the log message and putting Twisted's `system` into a second key. @@ -68,7 +68,7 @@ becomes:: There is obviously some redundancy here. Also, I'm presuming that if you write out JSON logs, you're going to let something else parse them which makes the human-readable date entries more trouble than they're worth. -To get a clean log without timestamps and additional system fields (``[-]``), structlog comes with :class:`~structlog.twisted.PlainFileLogObserver` that writes only the plain message to a file and :func:`~structlog.twisted.plainJSONStdOutLogger` that composes it with the aforementioned :func:`~structlog.twisted.JSONLogObserverWrapper` and gives you a pure JSON log without any timestamps or other noise straight to `standard out`_:: +To get a clean log without timestamps and additional system fields (``[-]``), ``structlog`` comes with :class:`~structlog.twisted.PlainFileLogObserver` that writes only the plain message to a file and :func:`~structlog.twisted.plainJSONStdOutLogger` that composes it with the aforementioned :func:`~structlog.twisted.JSONLogObserverWrapper` and gives you a pure JSON log without any timestamps or other noise straight to `standard out`_:: $ twistd -n --logger structlog.twisted.plainJSONStdOutLogger web diff --git a/docs/why.rst b/docs/why.rst index 77f3256c..1c390523 100644 --- a/docs/why.rst +++ b/docs/why.rst @@ -21,7 +21,7 @@ Structured logging means that you don't write hard-to-parse and hard-to-keep-con Because it's easy and you don't have to replace your underlying logger -- you just add structure to your log entries and format them to strings before they hit your real loggers. -``structlog`` supports you with building your context as you go (e.g. if a user logs in, you bind their user name to your current logger) and log events when they happen (i.e. the user does something log-worthy): +``structlog`` supports you with accepting key-value pairs as arguments, building your context as you go (e.g. if a user logs in, you bind their user name to your current logger) and log events when they happen (i.e. the user does something log-worthy): .. doctest:: @@ -34,6 +34,6 @@ Because it's easy and you don't have to replace your underlying logger -- you ju This ability to bind key/values pairs to a logger frees you from using conditionals, closures, or boilerplate methods to log out all relevant data. -Additionally, structlog offers you a flexible way to *filter* and *modify* your log entries using so called :ref:`processors ` before the entry is passed to your real logger. +Additionally, ``structlog`` offers you a flexible way to *filter* and *modify* your log entries using so called :ref:`processors ` before the entry is passed to your real logger. The possibilities include :class:`logging in JSON `, adding arbitrary meta data like :class:`timestamps `, counting events as metrics, or :ref:`dropping log entries ` caused by your monitoring system. -structlog is also flexible enough to allow transparent :ref:`thread local ` storage for your context if you don't like the idea of local bindings as in the example above. +``structlog`` is also flexible enough to allow transparent :ref:`thread local ` storage for your context if you don't like the idea of local bindings as in the example above. From b6236d451072dc6a79d46271dfac5ab6b16eaf52 Mon Sep 17 00:00:00 2001 From: Ethan Glasser-Camp Date: Mon, 23 May 2016 15:00:57 -0400 Subject: [PATCH 0079/1520] Don't cache logger (#72) Don't cache logger in lazy proxy --- src/structlog/_config.py | 7 ++++--- tests/test_config.py | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 234dbcf1..cba63fbe 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -247,15 +247,16 @@ def bind(self, **new_values): else: ctx = _CONFIG.default_context_class(self._initial_values) cls = self._wrapper_class or _CONFIG.default_wrapper_class - if not self._logger: - self._logger = _CONFIG.logger_factory(*self._logger_factory_args) + _logger = self._logger + if not _logger: + _logger = _CONFIG.logger_factory(*self._logger_factory_args) if self._processors is None: procs = _CONFIG.default_processors else: procs = self._processors logger = cls( - self._logger, + _logger, processors=procs, context=ctx, ) diff --git a/tests/test_config.py b/tests/test_config.py index a2b2f1d1..869a6fb6 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -212,6 +212,22 @@ def test_argument_takes_precedence_over_configuration2(self): proxy.bind() assert bind != proxy.bind + def test_bind_doesnt_cache_logger(self): + """ + Calling configure() changes BoundLoggerLazyProxys immediately. + Previous uses of the BoundLoggerLazyProxy don't interfere. + """ + class F(object): + "New logger factory with a new attribute" + def a(self, *args): + return 5 + + proxy = BoundLoggerLazyProxy(None) + proxy.bind() + configure(logger_factory=F) + new_b = proxy.bind() + assert new_b.a() == 5 + def test_emphemeral(self): """ Calling an unknown method proxy creates a new wrapped bound logger From 66b3f8a1b81fdb117cd4c933f498242dee02e932 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 24 May 2016 06:52:18 +0200 Subject: [PATCH 0080/1520] Add changelog entry --- CHANGELOG.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 22e80e69..1d8dbeff 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -27,7 +27,9 @@ Changes: If ``key_order`` is used and a key is missing a value, it's not rendered at all instead of being rendered as ``None``. `#67 `_ - Exceptions without a ``__traceback__`` are now also rendered on Python 3. - +- Don't cache loggers in lazy proxies returned from ``get_logger()``. + This lead to in-place mutation of them if used before configuration which in turn lead to the problem that configuration was applied only partially to them later. + `#72 `_ ---- From 99f1c4b3d131f49755f55cc11166a0a09312af1d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 24 May 2016 16:03:55 +0200 Subject: [PATCH 0081/1520] Nicer PR syntax --- CHANGELOG.rst | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1d8dbeff..797916ca 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -42,9 +42,9 @@ Changes: - ``structlog.processors.ExceptionPrettyPrinter`` and ``structlog.processors.format_exc_info`` now support passing of Exceptions on Python 3. - Clean up the context when exiting ``structlog.threadlocal.tmp_bind`` in case of exceptions. - [`64 `_] + `#64 `_ - Be more more lenient about missing ``__name__``\ s. - [`62 `_] + `#62 `_ - Add ``structlog.dev.ConsoleRenderer`` that renders the event dictionary aligned and with colors. - Use `six `_ for compatibility. - Add ``structlog.processors.UnicodeDecoder`` that will decode all byte string values in an event dictionary to Unicode. @@ -61,7 +61,7 @@ Changes: ^^^^^^^^ - Tolerate frames without a ``__name__``, better. - [`58 `_] + `#58 `_ - Officially support Python 3.5. - Add ``structlog.ReturnLogger.failure`` and ``structlog.PrintLogger.failure`` as preparation for the new Twisted logging system. @@ -80,9 +80,9 @@ Changes: Before, supplying an empty list resulted in the defaults being used. - Prevent Twisted's ``log.err`` from quoting strings rendered by ``structlog.twisted.JSONRenderer``. - Better support of ``logging.Logger.exception`` within ``structlog``. - [`52 `_] + `#52 `_ - Add option to specify target key in ``structlog.processors.TimeStamper`` processor. - [`51 `_] + `#51 `_ ---- @@ -107,16 +107,16 @@ Changes: ^^^^^^^^ - Add ``structlog.stdlib.add_log_level`` and ``structlog.stdlib.add_logger_name`` processors. - [`44 `_] + `#44 `_ - Add ``structlog.stdlib.BoundLogger.log``. - [`42 `_] + `#42 `_ - Pass positional arguments to stdlib wrapped loggers that use string formatting. - [`19 `_] + `#19 `_ - ``structlog`` is now dually licensed under the `Apache License, Version 2 `_ and the `MIT `_ license. Therefore it is now legal to use structlog with `GPLv2 `_-licensed projects. - [`28 `_] + `#28 `_ - Add ``structlog.stdlib.BoundLogger.exception``. - [`22 `_] + `#22 `_ ---- @@ -130,7 +130,7 @@ Changes: - Fixed a memory leak in greenlet code that emulates thread locals. It shouldn't matter in practice unless you use multiple wrapped dicts within one program that is rather unlikely. - [`8 `_] + `#8 `_ - ``structlog.PrintLogger`` now is thread-safe. - Test Twisted-related code on Python 3 (with some caveats). - Drop support for Python 3.2. @@ -139,7 +139,7 @@ Changes: - Officially support Python 3.4. - Allow final processor to return a dictionary. See the adapting chapter. - [`26 `_] + `#26`_ - ``from structlog import *`` works now (but you still shouldn't use it). @@ -172,15 +172,15 @@ Changes: - Add ``structlog.processors.StackInfoRenderer`` for adding stack information to log entries without involving exceptions. Also added it to default processor chain. - [`6 `_] + `#6 `_ - Allow optional positional arguments for ``structlog.get_logger`` that are passed to logger factories. The standard library factory uses this for explicit logger naming. - [`12 `_] + `#12 `_ - Add ``structlog.processors.ExceptionPrettyPrinter`` for development and testing when multiline log entries aren't just acceptable but even helpful. - Allow the standard library name guesser to ignore certain frame names. This is useful together with frameworks. - Add meta data (e.g. function names, line numbers) extraction for wrapped stdlib loggers. - [`5 `_] + `#5 `_ ---- From cf6b51e9bffcfad5099eeeb8f1dd57bcda558030 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 24 May 2016 16:19:37 +0200 Subject: [PATCH 0082/1520] Make VERSION a global variable in setup.py I use it in my release scripts. --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 39787263..2983acb7 100644 --- a/setup.py +++ b/setup.py @@ -74,6 +74,7 @@ def find_meta(meta): raise RuntimeError("Unable to find __{meta}__ string.".format(meta=meta)) +VERSION = find_meta("version") LONG = ( read("README.rst") + "\n\n" + "Release Information\n" + @@ -91,7 +92,7 @@ def find_meta(meta): description=find_meta("description"), license=find_meta("license"), url=find_meta("uri"), - version=find_meta("version"), + version=VERSION, author=find_meta("author"), author_email=find_meta("email"), maintainer=find_meta("author"), From 0515833d409d0d16d903e4c8573f335b39d732d2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 24 May 2016 16:21:57 +0200 Subject: [PATCH 0083/1520] Better changelog re --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 2983acb7..0e599bf2 100644 --- a/setup.py +++ b/setup.py @@ -79,7 +79,7 @@ def find_meta(meta): read("README.rst") + "\n\n" + "Release Information\n" + "===================\n\n" + - re.search("(\d{2}.\d.\d \(.*?\)\n.*?)\n\n\n", + re.search("(\d+.\d.\d \(.*?\)\n.*?)\n\n\n----\n\n\n", read("CHANGELOG.rst"), re.S).group(1) + "\n\n`Full changelog " + "`_.\n\n" + From 2555ebf5aafdb2fc65855bdfd50d10319d8b003d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 24 May 2016 16:24:07 +0200 Subject: [PATCH 0084/1520] Add missing empty line --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 797916ca..b3acaa20 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -19,7 +19,6 @@ Backward-incompatible changes: Python 3.3 never had a significant user base and wasn't part of any distribution's LTS release. - Changes: ^^^^^^^^ @@ -31,6 +30,7 @@ Changes: This lead to in-place mutation of them if used before configuration which in turn lead to the problem that configuration was applied only partially to them later. `#72 `_ + ---- From a39f6906a268fb2f4c365042b31d0200468fb492 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 24 May 2016 16:34:57 +0200 Subject: [PATCH 0085/1520] Prepare 16.1.0 --- CHANGELOG.rst | 2 +- src/structlog/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b3acaa20..5f4471c5 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,7 +5,7 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. -16.1.0 (UNRELEASED) +16.1.0 (2016-05-24) ------------------- Backward-incompatible changes: diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index b5bca7e9..f37f55b7 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -45,7 +45,7 @@ twisted = None -__version__ = "16.1.0.dev1" +__version__ = "16.1.0" __title__ = "structlog" __description__ = "Structured Logging for Python" From 52bad1f7101d0cb9efac4c51082fb6eb2039c4a9 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 24 May 2016 16:56:32 +0200 Subject: [PATCH 0086/1520] Start new release cycle --- CHANGELOG.rst | 12 ++++++++++++ src/structlog/__init__.py | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5f4471c5..719476d0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,18 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. +16.2.0 (UNRELEASED) +------------------- + +Changes: +^^^^^^^^ + +*none* + + +---- + + 16.1.0 (2016-05-24) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index f37f55b7..4db89a30 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -45,7 +45,7 @@ twisted = None -__version__ = "16.1.0" +__version__ = "16.2.0.dev0" __title__ = "structlog" __description__ = "Structured Logging for Python" From d8b48bc28a469cbc4c41df79e629d0765bd293ae Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 9 Jul 2016 12:24:27 +0200 Subject: [PATCH 0087/1520] Make less assumptions about what potential users --- README.rst | 71 +++++++++++++++++++++++++++++++++++++++++++++----- docs/conf.py | 3 +++ docs/index.rst | 52 ++++++++++-------------------------- docs/why.rst | 5 ++-- 4 files changed, 84 insertions(+), 47 deletions(-) diff --git a/README.rst b/README.rst index 23b0576c..2252c329 100644 --- a/README.rst +++ b/README.rst @@ -11,8 +11,15 @@ structlog: Structured Logging for Python .. image:: https://www.irccloud.com/invite-svg?channel=%23structlog&hostname=irc.freenode.net&port=6697&ssl=1 :target: https://www.irccloud.com/invite?channel=%23structlog&hostname=irc.freenode.net&port=6697&ssl=1 -``structlog`` makes structured logging in Python easy by *augmenting* your *existing* logger. -It allows you to split your log entries up into key/value pairs and build them incrementally without annoying boilerplate code. +.. begin + +``structlog`` makes structured logging in Python easy by either *augmenting* your *existing* logger if you need interoperability or supplying you with a lightweight logging layer if you want *performance* and *simplicity*. + + +Easier Logging +============== + +You will immediately appreciate the convenience of key/value-based logging: .. code-block:: pycon @@ -20,14 +27,64 @@ It allows you to split your log entries up into key/value pairs and build them i >>> log = get_logger() >>> log.info("key_value_logging", out_of_the_box=True, effort=0) out_of_the_box=True effort=0 event='key_value_logging' - >>> log = log.bind(user='anonymous', some_key=23) - >>> log = log.bind(user='hynek', another_key=42) - >>> log.info('user.logged_in', happy=True) + +Never ponder on how to phrase a log message again! + + +Data Binding +============ + +If you wish to, you can also bind key/value-pairs to loggers that get added automatically to all following loging calls: + +.. code-block:: pycon + + >>> log = log.bind(user="anonymous", some_key=23) + >>> log = log.bind(user="hynek", another_key=42) + >>> log.info("user.logged_in", happy=True) some_key=23 user='hynek' another_key=42 happy=True event='user.logged_in' -.. begin +Stop repeating yourself and still never forget an important piece of unformation in a log entry again! + +Please note that those examples do *not* use standard library logging (but `could so `_). +The logger that's returned by ``structlog.get_logger()`` is *freely* `configurable `_ and uses a simple but effective `structlog.PrintLogger `_ by default. + + +Powerful Pipelines +================== + +Since the log entries are dictionaries now (instead of unstructured prose strings), they allow for simple yet powerful `processor pipelines `_ of callables that receive a dictionary and return a new one: + +.. code-block:: python + + def timestamper(logger, log_method, event_dict): + """Add a timestamp to each log entry.""" + event_dict["timestamp"] = calendar.timegm(time.gmtime()) + return event_dict + +There are `plenty of processors `_ for most common tasks coming with ``structlog``. + + +Formatting +========== + +Finally, structured data is much easier to format into *any* other logging format. +Be it `colorful console output in developement `_, imitating the nginx log format, or logging out JSON for parsing and centralized storage. + +.. image:: http://www.structlog.org/en/stable/_images/console_renderer.png + +Internally, formatters are just processors whose return value is passed into wrapped loggers and ``structlog`` comes with multiple useful formatters out of-the-box. + + + +Since ``structlog`` avoids monkey-patching and events are fully free-form, you can start using it **today**! + +.. -end- + + +Project Information +=================== -It's dual-licensed under `Apache License, version 2 `_ and `MIT `_, available from `PyPI `_, the source code can be found on `GitHub `_, the documentation at http://www.structlog.org/. +``structlog`` is dual-licensed under `Apache License, version 2 `_ and `MIT `_, available from `PyPI `_, the source code can be found on `GitHub `_, the documentation at http://www.structlog.org/. ``structlog`` targets Python 2.7, 3.4 and newer, and PyPy. diff --git a/docs/conf.py b/docs/conf.py index 8b8b3bd7..c82d14f9 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -25,6 +25,9 @@ here = os.path.abspath(os.path.dirname(__file__)) +# We want an image in the README and include the README in the docs. +suppress_warnings = ['image.nonlocal_uri'] + def read(*parts): return codecs.open(os.path.join(here, *parts), 'r').read() diff --git a/docs/index.rst b/docs/index.rst index a93bcf5d..a87a03ba 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -6,42 +6,18 @@ Release v\ |version| (:doc:`What's new? `). .. include:: ../README.rst :start-after: begin + :end-before: -end- -The Pitch -========= - -``structlog`` makes structured logging with *key-value logging*, *incremental context building* and *arbitrary formatting* as easy as: - -.. doctest:: - - >>> from structlog import get_logger - >>> log = get_logger() - >>> log = log.bind(user='anonymous', some_key=23) - >>> log = log.bind(user='hynek', another_key=42) - >>> log.info('user.logged_in', happy=True) - some_key=23 user='hynek' another_key=42 happy=True event='user.logged_in' - -Please note that this example does *not* use standard library logging (but could so :ref:`easily `). -The logger that's returned by :func:`~structlog.get_logger()` is *freely* :doc:`configurable ` and uses a simple :class:`~structlog.PrintLogger` by default. - - - -For… - -- …reasons why structured logging in general and ``structlog`` in particular are the way to go, consult :doc:`why`. -- …more realistic examples, peek into :doc:`examples`. -- …getting started right away, jump straight into :doc:`getting-started`. - -Since ``structlog`` avoids monkey-patching and events are fully free-form, you can start using it **today**! User's Guide ============ + Basics ------ .. toctree:: - :maxdepth: 1 + :maxdepth: 2 why getting-started @@ -78,25 +54,25 @@ Advanced Topics performance -Project Information -=================== +API Reference +============= .. toctree:: - :maxdepth: 1 + :maxdepth: 4 - backward-compatibility - contributing - license - changelog + api -API Reference -============= +.. include:: ../README.rst + :start-after: -end- .. toctree:: - :maxdepth: 4 + :maxdepth: 1 - api + backward-compatibility + contributing + license + changelog Indices and tables diff --git a/docs/why.rst b/docs/why.rst index 1c390523..d0ec5720 100644 --- a/docs/why.rst +++ b/docs/why.rst @@ -19,9 +19,9 @@ Structured logging means that you don't write hard-to-parse and hard-to-keep-con …structlog? ------------ -Because it's easy and you don't have to replace your underlying logger -- you just add structure to your log entries and format them to strings before they hit your real loggers. +Because it's easy and you don't have to replace your underlying logger (but you can!) -- you just add structure to your log entries and format them to strings before they hit your real loggers. -``structlog`` supports you with accepting key-value pairs as arguments, building your context as you go (e.g. if a user logs in, you bind their user name to your current logger) and log events when they happen (i.e. the user does something log-worthy): +``structlog`` supports you with accepting key/value pairs as arguments, building your context as you go (e.g. if a user logs in, you bind their user name to your current logger) and log events when they happen (i.e. the user does something log-worthy): .. doctest:: @@ -36,4 +36,5 @@ This ability to bind key/values pairs to a logger frees you from using condition Additionally, ``structlog`` offers you a flexible way to *filter* and *modify* your log entries using so called :ref:`processors ` before the entry is passed to your real logger. The possibilities include :class:`logging in JSON `, adding arbitrary meta data like :class:`timestamps `, counting events as metrics, or :ref:`dropping log entries ` caused by your monitoring system. + ``structlog`` is also flexible enough to allow transparent :ref:`thread local ` storage for your context if you don't like the idea of local bindings as in the example above. From 296b90c522252a1731639d781cb25a86f76c48c0 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 9 Jul 2016 14:04:51 +0200 Subject: [PATCH 0088/1520] Explain structured logging right away --- README.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.rst b/README.rst index 2252c329..2f1b91b7 100644 --- a/README.rst +++ b/README.rst @@ -15,6 +15,11 @@ structlog: Structured Logging for Python ``structlog`` makes structured logging in Python easy by either *augmenting* your *existing* logger if you need interoperability or supplying you with a lightweight logging layer if you want *performance* and *simplicity*. +Structured logging means that you don't log out hard-to-parse and hard-to-come-up-with prose. +Instead think of log entries as events that happen in a context that is made up from key/value pairs. + +This approach has numerous advantages: + Easier Logging ============== From d821e04ccf846de47455c475b106550ab1b14e24 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 9 Jul 2016 15:01:22 +0200 Subject: [PATCH 0089/1520] Remove codecov badge See codecov/support#219 --- README.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.rst b/README.rst index 2f1b91b7..0e007e16 100644 --- a/README.rst +++ b/README.rst @@ -5,9 +5,6 @@ structlog: Structured Logging for Python .. image:: https://travis-ci.org/hynek/structlog.svg?branch=master :target: https://travis-ci.org/hynek/structlog -.. image:: https://codecov.io/github/hynek/structlog/coverage.svg?branch=master - :target: https://codecov.io/github/hynek/structlog?branch=master - .. image:: https://www.irccloud.com/invite-svg?channel=%23structlog&hostname=irc.freenode.net&port=6697&ssl=1 :target: https://www.irccloud.com/invite?channel=%23structlog&hostname=irc.freenode.net&port=6697&ssl=1 From d61a0342c7c189c3fbff2d178e9e8494dae18301 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 23 Jul 2016 17:52:42 +0200 Subject: [PATCH 0090/1520] Refinement --- README.rst | 51 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/README.rst b/README.rst index 0e007e16..c145e059 100644 --- a/README.rst +++ b/README.rst @@ -10,18 +10,15 @@ structlog: Structured Logging for Python .. begin -``structlog`` makes structured logging in Python easy by either *augmenting* your *existing* logger if you need interoperability or supplying you with a lightweight logging layer if you want *performance* and *simplicity*. +``structlog`` makes logging in Python less painful and more powerful by adding structure to your log entries. -Structured logging means that you don't log out hard-to-parse and hard-to-come-up-with prose. -Instead think of log entries as events that happen in a context that is made up from key/value pairs. - -This approach has numerous advantages: +It's up to you whether you want ``structlog`` to take care about the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's ``logging`` module. Easier Logging ============== -You will immediately appreciate the convenience of key/value-based logging: +You can stop writing prose and start thinking in terms of an event that happens in the context of key/value pairs: .. code-block:: pycon @@ -30,13 +27,13 @@ You will immediately appreciate the convenience of key/value-based logging: >>> log.info("key_value_logging", out_of_the_box=True, effort=0) out_of_the_box=True effort=0 event='key_value_logging' -Never ponder on how to phrase a log message again! +Each log entry is a meaningful dictionary instead of an opaque string now! Data Binding ============ -If you wish to, you can also bind key/value-pairs to loggers that get added automatically to all following loging calls: +Since log entries are dictionaries, you can start binding and re-binding key/value pairs to your loggers to ensure they are present in every following logging call: .. code-block:: pycon @@ -45,16 +42,12 @@ If you wish to, you can also bind key/value-pairs to loggers that get added auto >>> log.info("user.logged_in", happy=True) some_key=23 user='hynek' another_key=42 happy=True event='user.logged_in' -Stop repeating yourself and still never forget an important piece of unformation in a log entry again! - -Please note that those examples do *not* use standard library logging (but `could so `_). -The logger that's returned by ``structlog.get_logger()`` is *freely* `configurable `_ and uses a simple but effective `structlog.PrintLogger `_ by default. - Powerful Pipelines ================== -Since the log entries are dictionaries now (instead of unstructured prose strings), they allow for simple yet powerful `processor pipelines `_ of callables that receive a dictionary and return a new one: +Each log entry goes through a `processor pipeline `_ that is just a chain of functions that receive a dictionary and return a new dictionary that gets fed into the next function. +That allows for simple but powerful data manipulation: .. code-block:: python @@ -63,20 +56,40 @@ Since the log entries are dictionaries now (instead of unstructured prose string event_dict["timestamp"] = calendar.timegm(time.gmtime()) return event_dict -There are `plenty of processors `_ for most common tasks coming with ``structlog``. +There are `plenty of processors `_ for most common tasks coming with ``structlog``: + +- Collectors of `call stack information `_ ("How did this log entry happen?"), +- …and `exceptions `_ ("What happened‽"). +- Unicode encoders/decoders. +- Flexible `timestamping `_. + Formatting ========== -Finally, structured data is much easier to format into *any* other logging format. -Be it `colorful console output in developement `_, imitating the nginx log format, or logging out JSON for parsing and centralized storage. +``structlog`` is completely flexible about *how* the resulting log entry is emitted. +Since each log entry is a dictionary, it can be formatted to **any** format: + +- A colorful key/value format for `local development `_, +- `JSON `_ for easy parsing, +- or some standard format you have parsers for like nginx or Apache httpd. + +Internally, formatters are processors whose return value is passed into wrapped loggers and ``structlog`` comes with multiple useful formatters out of-the-box. -.. image:: http://www.structlog.org/en/stable/_images/console_renderer.png -Internally, formatters are just processors whose return value is passed into wrapped loggers and ``structlog`` comes with multiple useful formatters out of-the-box. +Output +====== +``structlog`` is also very flexible with the final output of your log entries: +- A **built-in** lightweight printer like in the examples above. + Easy to configure and fast. +- Use the **standard library**'s or **Twisted**'s logging modules for compatibility. + In this case ``structlog`` works like a wrapper that formats a string and passes them off into existing systems that won't ever know that ``structlog`` even exists. +- Don't format it to a string at all! + ``structlog`` passes you a dictionary and you can do with it whatever you want. + Reported uses cases are sending them out via network or saving them in a database. Since ``structlog`` avoids monkey-patching and events are fully free-form, you can start using it **today**! From 6e87575f952dac25978321311a1b966e342325d4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 23 Jul 2016 18:01:11 +0200 Subject: [PATCH 0091/1520] Move monkey-patching up --- README.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.rst b/README.rst index c145e059..8187864a 100644 --- a/README.rst +++ b/README.rst @@ -13,6 +13,7 @@ structlog: Structured Logging for Python ``structlog`` makes logging in Python less painful and more powerful by adding structure to your log entries. It's up to you whether you want ``structlog`` to take care about the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's ``logging`` module. +*No* `monkey patching `_ involved. Easier Logging @@ -91,8 +92,6 @@ Output ``structlog`` passes you a dictionary and you can do with it whatever you want. Reported uses cases are sending them out via network or saving them in a database. -Since ``structlog`` avoids monkey-patching and events are fully free-form, you can start using it **today**! - .. -end- From 3d8e42d04268da91fa29558bf5d7a060070f1133 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 24 Jul 2016 11:42:20 +0200 Subject: [PATCH 0092/1520] Add docs badge --- README.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.rst b/README.rst index 8187864a..f84822ab 100644 --- a/README.rst +++ b/README.rst @@ -2,6 +2,10 @@ structlog: Structured Logging for Python ======================================== +.. image:: https://readthedocs.org/projects/structlog/badge/?version=stable + :target: http://structlog.readthedocs.io/en/stable/?badge=stable + :alt: Documentation Status + .. image:: https://travis-ci.org/hynek/structlog.svg?branch=master :target: https://travis-ci.org/hynek/structlog From e9bc8f6b5863d6d4d00448299260c130c7f9edae Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 24 Jul 2016 11:49:48 +0200 Subject: [PATCH 0093/1520] Be more explicit about lack of MP --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index f84822ab..dc1fbd18 100644 --- a/README.rst +++ b/README.rst @@ -17,7 +17,7 @@ structlog: Structured Logging for Python ``structlog`` makes logging in Python less painful and more powerful by adding structure to your log entries. It's up to you whether you want ``structlog`` to take care about the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's ``logging`` module. -*No* `monkey patching `_ involved. +*No* `monkey patching `_ involved in either case. Easier Logging From 25d6cb976f7503044e19ea965688d3ddc3efa151 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 7 Aug 2016 11:34:58 +0200 Subject: [PATCH 0094/1520] Make Flask example runnable Also set log level to info so people aren't surprised about lack of output. --- README.rst | 5 +++-- docs/code_examples/flask_/__init__.py | 0 docs/code_examples/flask_/webapp.py | 16 ++++++++++++---- docs/standard-library.rst | 11 ++++++----- tox.ini | 9 +-------- 5 files changed, 22 insertions(+), 19 deletions(-) delete mode 100644 docs/code_examples/flask_/__init__.py diff --git a/README.rst b/README.rst index dc1fbd18..fe12d9f5 100644 --- a/README.rst +++ b/README.rst @@ -80,7 +80,8 @@ Since each log entry is a dictionary, it can be formatted to **any** format: - `JSON `_ for easy parsing, - or some standard format you have parsers for like nginx or Apache httpd. -Internally, formatters are processors whose return value is passed into wrapped loggers and ``structlog`` comes with multiple useful formatters out of-the-box. +Internally, formatters are processors whose return value (usually a string) is passed into loggers that are responsible for the output of your message. +``structlog`` comes with multiple useful formatters out of-the-box. Output @@ -89,7 +90,7 @@ Output ``structlog`` is also very flexible with the final output of your log entries: - A **built-in** lightweight printer like in the examples above. - Easy to configure and fast. + Easy to use and fast. - Use the **standard library**'s or **Twisted**'s logging modules for compatibility. In this case ``structlog`` works like a wrapper that formats a string and passes them off into existing systems that won't ever know that ``structlog`` even exists. - Don't format it to a string at all! diff --git a/docs/code_examples/flask_/__init__.py b/docs/code_examples/flask_/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/docs/code_examples/flask_/webapp.py b/docs/code_examples/flask_/webapp.py index 4001282e..594c84bb 100644 --- a/docs/code_examples/flask_/webapp.py +++ b/docs/code_examples/flask_/webapp.py @@ -1,34 +1,42 @@ +import logging +import sys import uuid import flask import structlog -from .some_module import some_function +from some_module import some_function logger = structlog.get_logger() app = flask.Flask(__name__) -@app.route('/login', methods=['POST', 'GET']) +@app.route("/login", methods=["POST", "GET"]) def some_route(): log = logger.new( request_id=str(uuid.uuid4()), ) # do something # ... - log.info('user logged in', user='test-user') + log.info("user logged in", user="test-user") # gives you: # event='user logged in' request_id='ffcdc44f-b952-4b5f-95e6-0f1f3a9ee5fd' user='test-user' # ... some_function() # ... + return "logged in!" if __name__ == "__main__": + logging.basicConfig( + format="%(message)s", + stream=sys.stdout, + level=logging.INFO, + ) structlog.configure( processors=[ structlog.processors.KeyValueRenderer( - key_order=['event', 'request_id'], + key_order=["event", "request_id"], ), ], context_class=structlog.threadlocal.wrap_dict(dict), diff --git a/docs/standard-library.rst b/docs/standard-library.rst index 2576f759..81b4e6cf 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -70,12 +70,13 @@ A basic configuration to output structured logs in JSON format looks like this: To make your program behave like a proper `12 factor app`_ that outputs only JSON to ``stdout``, configure the ``logging`` module like this:: - import logging - import sys + import logging - handler = logging.StreamHandler(sys.stdout) - root_logger = logging.getLogger() - root_logger.addHandler(handler) + logging.basicConfig( + format="%(message)s", + stream=sys.stdout, + level=logging.INFO, + ) If you plan to hook up the logging output to `logstash`, as suggested in :doc:`logging-best-practices`, the simplest approach is to configure ``logstash-forwarder`` to pick up the output from your application. To achieve this, configure your process supervisor (such as ``runit`` or ``supervisord``) to store the output in a file, and have ``logstash-forwarder`` monitor that file to ship it to the central log collection server. diff --git a/tox.ini b/tox.ini index 12adb358..962a3ac4 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = coverage-clean,{py27,py34,py35,pypy}-{threads,greenlets},py35-nocolorama,flake8,docs,readme,manifest,coverage-report +envlist = {py27,py34,py35,pypy}-{threads,greenlets},py35-nocolorama,flake8,docs,readme,manifest,coverage-report [testenv] @@ -49,13 +49,6 @@ deps = check-manifest commands = check-manifest -[testenv:coverage-clean] -basepython = python3.5 -deps = coverage -skip_install = true -commands = coverage erase - - [testenv:coverage-report] deps = coverage skip_install = true From 4d03bbe0830d337c08cba70722bc01df651f4923 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 17 Aug 2016 12:19:00 +0200 Subject: [PATCH 0095/1520] Fix double twisted in examples for concrete loggers --- src/structlog/_generic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/_generic.py b/src/structlog/_generic.py index 89c3f55c..b2b43a42 100644 --- a/src/structlog/_generic.py +++ b/src/structlog/_generic.py @@ -18,7 +18,7 @@ class BoundLogger(BoundLoggerBase): A generic BoundLogger that can wrap anything. Every unknown method will be passed to the wrapped logger. If that's too - much magic for you, try :class:`structlog.twisted.BoundLogger` or + much magic for you, try :class:`structlog.stdlib.BoundLogger` or :class:`structlog.twisted.BoundLogger` which also take advantage of knowing the wrapped class which generally results in better performance. From 896516de79fe5326f44a5063c3f9e2169ca7faf5 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 17 Aug 2016 12:19:30 +0200 Subject: [PATCH 0096/1520] Re-add codecov badge They seem to have changed the urls. --- README.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.rst b/README.rst index fe12d9f5..45259b65 100644 --- a/README.rst +++ b/README.rst @@ -9,6 +9,10 @@ structlog: Structured Logging for Python .. image:: https://travis-ci.org/hynek/structlog.svg?branch=master :target: https://travis-ci.org/hynek/structlog +.. image:: https://codecov.io/github/hynek/structlog/branch/master/graph/badge.svg + :target: https://codecov.io/github/hynek/structlog + :alt: Test Coverage + .. image:: https://www.irccloud.com/invite-svg?channel=%23structlog&hostname=irc.freenode.net&port=6697&ssl=1 :target: https://www.irccloud.com/invite?channel=%23structlog&hostname=irc.freenode.net&port=6697&ssl=1 From 1bfa171c0f7304e7efca750cfb304f3a7a008093 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 21 Aug 2016 14:21:36 +0200 Subject: [PATCH 0097/1520] Link dumps --- src/structlog/processors.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 29ff387a..e8af0cd3 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -127,8 +127,8 @@ class JSONRenderer(object): """ Render the `event_dict` using `json.dumps(event_dict, **json_kw)`. - :param dict json_kw: Are passed unmodified to `json.dumps()`. - :param callable serializer: A :meth:`json.dumps`-compatible callable that + :param dict json_kw: Are passed unmodified to :func:`json.dumps`. + :param callable serializer: A :func:`json.dumps`-compatible callable that will be used to format the string. This can be used to use alternative JSON encoders like `simplejson `_ or `RapidJSON From cf5d57cc3a75d95df5b8daa6b66445121033e2c0 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 17 Sep 2016 12:01:19 +0200 Subject: [PATCH 0098/1520] Add color arg to ConsoleRenderer & make it default Fixes #78. --- .travis.yml | 6 +- CHANGELOG.rst | 11 ++- README.rst | 4 +- docs/api.rst | 29 +++++++ docs/custom-wrappers.rst | 13 +++ docs/examples.rst | 8 +- docs/faq.rst | 15 +++- docs/getting-started.rst | 14 +++- docs/thread-local.rst | 15 +++- docs/why.rst | 4 +- setup.cfg | 4 +- src/structlog/_config.py | 17 ++-- src/structlog/dev.py | 123 +++++++++++++++++++-------- src/structlog/threadlocal.py | 10 --- src/structlog/twisted.py | 14 ++-- tests/test_config.py | 3 +- tests/test_dev.py | 157 +++++++++++++++++++++-------------- tests/test_twisted.py | 31 ++++--- tox.ini | 8 +- 19 files changed, 328 insertions(+), 158 deletions(-) diff --git a/.travis.yml b/.travis.yml index 52b93e0e..1605ff86 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,12 +20,14 @@ matrix: env: TOXENV=py35-threads - python: "3.5" env: TOXENV=py35-greenlets - - python: "3.5" - env: TOXENV=py35-nocolorama - python: "pypy" env: TOXENV=pypy-threads - python: "pypy" env: TOXENV=pypy-greenlets + - python: "2.7" + env: TOXENV=py27-colorama + - python: "3.5" + env: TOXENV=py35-colorama # Meta diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 719476d0..3318f8aa 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,10 +8,19 @@ The third digit is only for regressions. 16.2.0 (UNRELEASED) ------------------- +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- The default renderer is ``structlog.dev.ConsoleRenderer`` now if you don't configure ``structlog``. + Colors are used if available and human-friendly timestamps are prepended. + This is in line with our backward `compatibility policy `_ that explicitly excludes default settings. + + Changes: ^^^^^^^^ -*none* +- Add *colors* argument to ``structlog.dev.ConsoleRenderer`` and make it the default renderer. + `#78 `_ ---- diff --git a/README.rst b/README.rst index 45259b65..d47eaef5 100644 --- a/README.rst +++ b/README.rst @@ -34,7 +34,7 @@ You can stop writing prose and start thinking in terms of an event that happens >>> from structlog import get_logger >>> log = get_logger() >>> log.info("key_value_logging", out_of_the_box=True, effort=0) - out_of_the_box=True effort=0 event='key_value_logging' + 2016-04-20 16:20.13 key_value_logging effort=0 out_of_the_box=True Each log entry is a meaningful dictionary instead of an opaque string now! @@ -49,7 +49,7 @@ Since log entries are dictionaries, you can start binding and re-binding key/val >>> log = log.bind(user="anonymous", some_key=23) >>> log = log.bind(user="hynek", another_key=42) >>> log.info("user.logged_in", happy=True) - some_key=23 user='hynek' another_key=42 happy=True event='user.logged_in' + 2016-04-20 16:20.13 user.logged_in another_key=42 happy=True some_key=23 user='hynek' Powerful Pipelines diff --git a/docs/api.rst b/docs/api.rst index f9e73c5c..36fb1fd2 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -3,6 +3,24 @@ API Reference ============= +.. note:: + The examples here use a very simplified configuration using the minimalistic :class:`structlog.processors.KeyValueRenderer` for brewity and to enable doctests. + The output is going to be different (nicer!) with default configuration. + + +.. testsetup:: * + + import structlog + structlog.configure( + processors=[structlog.processors.KeyValueRenderer()], + ) + +.. testcleanup:: * + + import structlog + structlog.reset_defaults() + + .. module:: structlog :mod:`structlog` Package @@ -56,6 +74,17 @@ API Reference .. autofunction:: tmp_bind(logger, **tmp_values) + >>> from structlog import wrap_logger, PrintLogger + >>> from structlog.threadlocal import tmp_bind, wrap_dict + >>> logger = wrap_logger(PrintLogger(), context_class=wrap_dict(dict)) + >>> with tmp_bind(logger, x=5) as tmp_logger: + ... logger = logger.bind(y=3) + ... tmp_logger.msg("event") + y=3 x=5 event='event' + >>> logger.msg("event") + event='event' + + .. autofunction:: as_immutable diff --git a/docs/custom-wrappers.rst b/docs/custom-wrappers.rst index 92d0bbe4..ca266034 100644 --- a/docs/custom-wrappers.rst +++ b/docs/custom-wrappers.rst @@ -1,6 +1,19 @@ Custom Wrappers =============== +.. testsetup:: * + + import structlog + structlog.configure( + processors=[structlog.processors.KeyValueRenderer()], + ) + +.. testcleanup:: * + + import structlog + structlog.reset_defaults() + + ``structlog`` comes with a generic bound logger called :class:`structlog.BoundLogger` that can be used to wrap any logger class you fancy. It does so by intercepting unknown method names and proxying them to the wrapped logger. diff --git a/docs/examples.rst b/docs/examples.rst index 97a49039..de236152 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -90,11 +90,11 @@ Here you go: ... ] ... ) >>> log.info('something.filtered') - >>> log.warning('something.not_filtered', password='secret') # doctest: +SKIP + >>> log.warning('something.not_filtered', password='secret') # doctest: +ELLIPSIS { - "event": "something.not_filtered", - "password": "*CENSORED*", - "timestamp": "datetime.datetime(..., ..., ..., ..., ...)" + "event": "something.not_filtered", + "password": "*CENSORED*", + "timestamp": "datetime.datetime(..., ..., ..., ..., ...)" } ``structlog`` comes with many handy processors build right in -- for a list of shipped processors, check out the :ref:`API documentation `. diff --git a/docs/faq.rst b/docs/faq.rst index 7f1952ab..ebd21f45 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -1,6 +1,18 @@ Frequently Asked Questions ========================== +.. testsetup:: * + + import structlog + structlog.configure( + processors=[structlog.processors.KeyValueRenderer()], + ) + +.. testcleanup:: * + + import structlog + structlog.reset_defaults() + I try to bind key-value pairs but they don't appear in the log files? ``structlog``\ 's loggers are *immutable*. Meaning that you have to use the logger that is returned from ``bind()``: @@ -9,7 +21,8 @@ I try to bind key-value pairs but they don't appear in the log files? >>> import structlog >>> log = structlog.get_logger() - >>> log.bind(x=42) # doctest: +SKIP + >>> log.bind(x=42) # doctest: +ELLIPSIS + ])> >>> log.msg("hello") event='hello' >>> new_log = log.bind(x=42) diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 235b617d..0bff1ba3 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -12,6 +12,10 @@ Installation $ pip install structlog +If you'd like colorful output in development (you know you do!), install using:: + + $ pip install structlog[dev] + Your First Log Entry -------------------- @@ -23,19 +27,23 @@ And indeed, the simplest possible usage looks like this: >>> import structlog >>> log = structlog.get_logger() - >>> log.msg('greeted', whom='world', more_than_a_string=[1, 2, 3]) - whom='world' more_than_a_string=[1, 2, 3] event='greeted' + >>> log.msg("greeted", whom="world", more_than_a_string=[1, 2, 3]) # doctest: +SKIP + 2016-09-17 10:13.45 greeted more_than_a_string=[1, 2, 3] whom='world' Here, ``structlog`` takes full advantage of its hopefully useful default settings: - Output is sent to `standard out`_ instead of exploding into the user's face. Yes, that seems a rather controversial attitude towards logging. -- All keywords are formatted using :class:`structlog.processors.KeyValueRenderer`. +- All keywords are formatted using :class:`structlog.dev.ConsoleRenderer`. That in turn uses `repr()`_ to serialize all values to strings. Thus, it's easy to add support for logging of your own objects\ [*]_. +- If you have `colorama `_ installed, it's even rendered in nice :doc:`colors `. It should be noted that even in most complex logging setups the example would still look just like that thanks to :ref:`configuration`. +.. note:: + For brewity and to enable doctests, all further examples in ``structlog``\ 's documentation use the more simplistic :class:`structlog.processors.KeyValueRenderer()` without timestamps. + There you go, structured logging! However, this alone wouldn't warrant its own package. After all, there's even a recipe_ on structured logging for the standard library. diff --git a/docs/thread-local.rst b/docs/thread-local.rst index 88e1ae8a..16aa045a 100644 --- a/docs/thread-local.rst +++ b/docs/thread-local.rst @@ -3,6 +3,13 @@ Thread Local Context ==================== +.. testsetup:: * + + import structlog + structlog.configure( + processors=[structlog.processors.KeyValueRenderer()], + ) + .. testcleanup:: * import structlog @@ -90,12 +97,12 @@ In order to be able to bind values temporarily to a logger, :mod:`structlog.thre >>> log.bind(x=42) # doctest: +ELLIPSIS , ...)> - >>> log.msg('event!') + >>> log.msg("event!") x=42 event='event!' - >>> with tmp_bind(log, x=23, y='foo') as tmp_log: - ... tmp_log.msg('another event!') + >>> with tmp_bind(log, x=23, y="foo") as tmp_log: + ... tmp_log.msg("another event!") y='foo' x=23 event='another event!' - >>> log.msg('one last event!') + >>> log.msg("one last event!") x=42 event='one last event!' The state before the ``with`` statement is saved and restored once it's left. diff --git a/docs/why.rst b/docs/why.rst index d0ec5720..9c8200c7 100644 --- a/docs/why.rst +++ b/docs/why.rst @@ -29,8 +29,8 @@ Because it's easy and you don't have to replace your underlying logger (but you >>> log = get_logger() >>> log = log.bind(user='anonymous', some_key=23) >>> log = log.bind(user='hynek', another_key=42) - >>> log.info('user.logged_in', happy=True) - some_key=23 user='hynek' another_key=42 happy=True event='user.logged_in' + >>> log.info('user.logged_in', happy=True) # doctest: +SKIP + 2016-04-20 16:20.13 user.logged_in another_key=42 happy=True some_key=23 user='hynek' This ability to bind key/values pairs to a logger frees you from using conditionals, closures, or boilerplate methods to log out all relevant data. diff --git a/setup.cfg b/setup.cfg index 4a9b6ce5..ce5783da 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ -[pytest] -minversion = 2.8 +[tool:pytest] +minversion = 3.0 strict = true addopts = -ra testpaths = tests diff --git a/src/structlog/_config.py b/src/structlog/_config.py index cba63fbe..cd64f493 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -12,20 +12,22 @@ from collections import OrderedDict -from structlog._generic import BoundLogger -from structlog._loggers import ( +from ._generic import BoundLogger +from ._loggers import ( PrintLoggerFactory, ) -from structlog.processors import ( - KeyValueRenderer, +from .dev import ConsoleRenderer, _has_colorama +from .processors import ( StackInfoRenderer, + TimeStamper, format_exc_info, ) _BUILTIN_DEFAULT_PROCESSORS = [ StackInfoRenderer(), format_exc_info, - KeyValueRenderer(), + TimeStamper(fmt="%Y-%m-%d %H:%M.%S", utc=False), + ConsoleRenderer(colors=_has_colorama), ] _BUILTIN_DEFAULT_CONTEXT_CLASS = OrderedDict _BUILTIN_DEFAULT_WRAPPER_CLASS = BoundLogger @@ -57,7 +59,7 @@ def get_logger(*args, **initial_values): >>> from structlog import get_logger >>> log = get_logger(y=23) - >>> log.msg('hello', x=42) + >>> log.msg("hello", x=42) y=23 x=42 event='hello' :param args: *Optional* positional arguments that are passed unmodified to @@ -188,7 +190,8 @@ def reset_defaults(): That means [:class:`~structlog.processors.StackInfoRenderer`, :func:`~structlog.processors.format_exc_info`, - :class:`~structlog.processors.KeyValueRenderer`] for *processors*, + :class:`~structlog.processors.TimeStamper`, + :class:`~structlog.dev.ConsoleRenderer`] for *processors*, :class:`~structlog.BoundLogger` for *wrapper_class*, ``OrderedDict`` for *context_class*, :class:`~structlog.PrintLoggerFactory` for *logger_factory*, and `False` for *cache_logger_on_first_use*. diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 1f94e88a..bd46763f 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -3,7 +3,7 @@ # repository for complete details. """ -Helpers that aim to make development with ``structlog`` more pleasant. +Helpers that make development with ``structlog`` more pleasant. """ from __future__ import absolute_import, division, print_function @@ -15,6 +15,7 @@ except ImportError: colorama = None + __all__ = [ "ConsoleRenderer", ] @@ -37,6 +38,8 @@ def _pad(s, l): if colorama is not None: + _has_colorama = True + RESET_ALL = colorama.Style.RESET_ALL BRIGHT = colorama.Style.BRIGHT DIM = colorama.Style.DIM @@ -46,43 +49,94 @@ def _pad(s, l): MAGENTA = colorama.Fore.MAGENTA YELLOW = colorama.Fore.YELLOW GREEN = colorama.Fore.GREEN + RED_BACK = colorama.Back.RED +else: + _has_colorama = False + + RESET_ALL = BRIGHT = DIM = RED = BLUE = CYAN = MAGENTA = YELLOW = GREEN = \ + RED_BACK = "" + + +class _ColorfulStyles(object): + reset = RESET_ALL + bright = BRIGHT + + level_critical = RED + level_exception = RED + level_error = RED + level_warn = YELLOW + level_info = GREEN + level_debug = GREEN + level_notset = RED_BACK + + timestamp = DIM + logger_name = BLUE + kv_key = CYAN + kv_value = MAGENTA + + +class _PlainStyles(object): + reset = "" + bright = "" + + level_critical = "" + level_exception = "" + level_error = "" + level_warn = "" + level_info = "" + level_debug = "" + level_notset = "" + + timestamp = "" + logger_name = "" + kv_key = "" + kv_value = "" class ConsoleRenderer(object): """ - Render `event_dict` nicely aligned, in colors, and ordered. + Render `event_dict` nicely aligned, possibly in colors, and ordered. :param int pad_event: Pad the event to this many characters. + :param bool colors: Use colors for a nicer output. - Requires the colorama_ package. + Requires the colorama_ package if *colors* is ``True``. - .. _colorama: https://pypi.python.org/pypi/colorama/ + .. _colorama: https://pypi.org/project/colorama/ - .. versionadded:: 16.0.0 + .. versionadded:: 16.0 + .. versionadded:: 16.1 *colors* argument """ - def __init__(self, pad_event=_EVENT_WIDTH): - if colorama is None: - raise SystemError( - _MISSING.format( - who=self.__class__.__name__, - package="colorama" + def __init__(self, pad_event=_EVENT_WIDTH, colors=True): + if colors is True: + if colorama is None: + raise SystemError( + _MISSING.format( + who=self.__class__.__name__ + " with `colors=True`", + package="colorama" + ) ) - ) - colorama.init() + colorama.init() + styles = _ColorfulStyles + else: + styles = _PlainStyles + + self._styles = styles self._pad_event = pad_event self._level_to_color = { - "critical": RED, - "exception": RED, - "error": RED, - "warn": YELLOW, - "warning": YELLOW, - "info": GREEN, - "debug": GREEN, - "notset": colorama.Back.RED, + "critical": styles.level_critical, + "exception": styles.level_exception, + "error": styles.level_error, + "warn": styles.level_warn, + "warning": styles.level_warn, + "info": styles.level_info, + "debug": styles.level_debug, + "notset": styles.level_notset, } + for key in self._level_to_color.keys(): - self._level_to_color[key] += BRIGHT + self._level_to_color[key] += styles.bright self._longest_level = len(max( self._level_to_color.keys(), key=lambda e: len(e) @@ -95,27 +149,28 @@ def __call__(self, _, __, event_dict): if ts is not None: sio.write( # can be a number if timestamp is UNIXy - DIM + str(ts) + RESET_ALL + " " + self._styles.timestamp + str(ts) + self._styles.reset + " " ) level = event_dict.pop("level", None) if level is not None: sio.write( "[" + self._level_to_color[level] + _pad(level, self._longest_level) + - RESET_ALL + "] " + self._styles.reset + "] " ) - sio.write( - BRIGHT + - _pad(event_dict.pop("event"), self._pad_event) + - RESET_ALL + " " - ) + event = event_dict.pop("event") + if event_dict: + event = _pad(event, self._pad_event) + self._styles.reset + " " + else: + event += self._styles.reset + sio.write(self._styles.bright + event) logger_name = event_dict.pop("logger", None) if logger_name is not None: sio.write( - "[" + BLUE + BRIGHT + - logger_name + RESET_ALL + + "[" + self._styles.logger_name + self._styles.bright + + logger_name + self._styles.reset + "] " ) @@ -123,10 +178,10 @@ def __call__(self, _, __, event_dict): exc = event_dict.pop("exception", None) sio.write( " ".join( - CYAN + key + RESET_ALL + + self._styles.kv_key + key + self._styles.reset + "=" + - MAGENTA + repr(event_dict[key]) + - RESET_ALL + self._styles.kv_value + repr(event_dict[key]) + + self._styles.reset for key in sorted(event_dict.keys()) ) ) diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index b64509c7..281a5612 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -91,16 +91,6 @@ def as_immutable(logger): def tmp_bind(logger, **tmp_values): """ Bind *tmp_values* to *logger* & memorize current state. Rewind afterwards. - - >>> from structlog import wrap_logger, PrintLogger - >>> from structlog.threadlocal import tmp_bind, wrap_dict - >>> logger = wrap_logger(PrintLogger(), context_class=wrap_dict(dict)) - >>> with tmp_bind(logger, x=5) as tmp_logger: - ... logger = logger.bind(y=3) - ... tmp_logger.msg('event') - y=3 x=5 event='event' - >>> logger.msg('event') - event='event' """ saved = as_immutable(logger)._context try: diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index 1541a064..dc2199b0 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -20,12 +20,12 @@ from twisted.python.log import ILogObserver, textFromEventDict from zope.interface import implementer -from structlog._base import BoundLoggerBase -from structlog._utils import until_not_interrupted -from structlog.processors import ( +from ._base import BoundLoggerBase +from ._config import _BUILTIN_DEFAULT_PROCESSORS +from ._utils import until_not_interrupted +from .processors import ( # can't import processors module without risking circular imports JSONRenderer as GenericJSONRenderer, - KeyValueRenderer, ) @@ -47,13 +47,13 @@ def msg(self, event=None, **kw): """ Process event and call ``log.msg()`` with the result. """ - return self._proxy_to_logger('msg', event, **kw) + return self._proxy_to_logger("msg", event, **kw) def err(self, event=None, **kw): """ Process event and call ``log.err()`` with the result. """ - return self._proxy_to_logger('err', event, **kw) + return self._proxy_to_logger("err", event, **kw) class LoggerFactory(object): @@ -268,7 +268,7 @@ def __init__(self, dictRenderer=None): """ :param dictRenderer: A processor used to format the log message. """ - self._dictRenderer = dictRenderer or KeyValueRenderer() + self._dictRenderer = dictRenderer or _BUILTIN_DEFAULT_PROCESSORS[-1] def __call__(self, logger, name, eventDict): if name == 'err': diff --git a/tests/test_config.py b/tests/test_config.py index 869a6fb6..b5b86449 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -226,7 +226,8 @@ def a(self, *args): proxy.bind() configure(logger_factory=F) new_b = proxy.bind() - assert new_b.a() == 5 + + assert new_b.a("test") == 5 def test_emphemeral(self): """ diff --git a/tests/test_dev.py b/tests/test_dev.py index 4307ad0d..9d8978f9 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -23,85 +23,94 @@ def test_negative(self): assert len("test") == len(dev._pad("test", 2)) -@pytest.mark.skipif(dev.colorama is not None, - reason="Colorama must be missing.") -def test_missing_colorama(): - """ - ConsoleRenderer() raises SystemError on initialization if colorama is - missing. - - This is a function such that TestConsoleRenderer can be protected on class - level. - """ - with pytest.raises(SystemError) as e: - dev.ConsoleRenderer() - - assert ( - "ConsoleRenderer requires the colorama package installed." - ) in e.value.args[0] +@pytest.fixture +def cr(): + return dev.ConsoleRenderer(colors=dev._has_colorama) @pytest.fixture -def cr(): - return dev.ConsoleRenderer() +def styles(cr): + return cr._styles -if dev.colorama is not None: - PADDED_TEST = ( - dev.BRIGHT + +@pytest.fixture +def padded(styles): + return ( + styles.bright + dev._pad("test", dev._EVENT_WIDTH) + - dev.RESET_ALL + " " + styles.reset + " " ) -@pytest.mark.skipif(dev.colorama is None, reason="Requires colorama.") +@pytest.fixture +def unpadded(styles): + return styles.bright + "test" + styles.reset + + class TestConsoleRenderer(object): - def test_plain(self, cr): + @pytest.mark.skipif(dev._has_colorama, reason="Colorama must be missing.") + def test_missing_colorama(self): + """ + ConsoleRenderer(colors=True) raises SystemError on initialization if + colorama is missing. + """ + with pytest.raises(SystemError) as e: + dev.ConsoleRenderer() + + assert ( + "ConsoleRenderer with `colors=True` requires the colorama package " + "installed." + ) in e.value.args[0] + + def test_plain(self, cr, styles, unpadded): """ Works with a plain event_dict with only the event. """ rv = cr(None, None, {"event": "test"}) - assert PADDED_TEST == rv + assert unpadded == rv - def test_timestamp(self, cr): + def test_timestamp(self, cr, styles, unpadded): """ - Timestamps get prepended dimmed.. + Timestamps get prepended. """ rv = cr(None, None, {"event": "test", "timestamp": 42}) assert ( - dev.DIM + "42" + dev.RESET_ALL + - " " + PADDED_TEST + styles.timestamp + "42" + styles.reset + " " + unpadded ) == rv - def test_level(self, cr): + def test_level(self, cr, styles, padded): """ Levels are rendered aligned, in square brackets, and color coded. """ - rv = cr(None, None, {"event": "test", "level": "critical"}) + rv = cr(None, None, { + "event": "test", "level": "critical", "foo": "bar" + }) assert ( - "[" + dev.RED + dev.BRIGHT + + "[" + dev.RED + styles.bright + dev._pad("critical", cr._longest_level) + - dev.RESET_ALL + "] " + - PADDED_TEST + styles.reset + "] " + + padded + + styles.kv_key + "foo" + styles.reset + "=" + + styles.kv_value + "'bar'" + styles.reset ) == rv - def test_logger_name(self, cr): + def test_logger_name(self, cr, styles, padded): """ Logger names are appended after the event. """ rv = cr(None, None, {"event": "test", "logger": "some_module"}) assert ( - PADDED_TEST + - "[" + dev.BLUE + dev.BRIGHT + + padded + + "[" + dev.BLUE + styles.bright + "some_module" + - dev.RESET_ALL + "] " + styles.reset + "] " ) == rv - def test_key_values(self, cr): + def test_key_values(self, cr, styles, padded): """ Key-value pairs go sorted alphabetically to the end. """ @@ -111,14 +120,16 @@ def test_key_values(self, cr): "foo": "bar", }) assert ( - PADDED_TEST + - dev.CYAN + "foo" + dev.RESET_ALL + "=" + dev.MAGENTA + "'bar'" + - dev.RESET_ALL + " " + - dev.CYAN + "key" + dev.RESET_ALL + "=" + dev.MAGENTA + "'value'" + - dev.RESET_ALL + padded + + styles.kv_key + "foo" + styles.reset + "=" + + styles.kv_value + "'bar'" + + styles.reset + " " + + styles.kv_key + "key" + styles.reset + "=" + + styles.kv_value + "'value'" + + styles.reset ) == rv - def test_exception(self, cr): + def test_exception(self, cr, padded): """ Exceptions are rendered after a new line. """ @@ -130,10 +141,10 @@ def test_exception(self, cr): }) assert ( - PADDED_TEST + "\n" + exc + padded + "\n" + exc ) == rv - def test_stack_info(self, cr): + def test_stack_info(self, cr, padded): """ Stack traces are rendered after a new line. """ @@ -144,22 +155,27 @@ def test_stack_info(self, cr): }) assert ( - PADDED_TEST + "\n" + stack + padded + "\n" + stack ) == rv - def test_pad_event_param(self): + def test_pad_event_param(self, styles): """ `pad_event` parameter works. """ - rv = dev.ConsoleRenderer(42)(None, None, {"event": "test"}) + rv = dev.ConsoleRenderer(42, dev._has_colorama)(None, None, { + "event": "test", + "foo": "bar" + }) assert ( - dev.BRIGHT + + styles.bright + dev._pad("test", 42) + - dev.RESET_ALL + " " + styles.reset + " " + + styles.kv_key + "foo" + styles.reset + "=" + + styles.kv_value + "'bar'" + styles.reset ) == rv - def test_everything(self, cr): + def test_everything(self, cr, styles, padded): """ Put all cases together. """ @@ -178,18 +194,33 @@ def test_everything(self, cr): }) assert ( - dev.DIM + "13:13" + dev.RESET_ALL + - " [" + dev.RED + dev.BRIGHT + + styles.timestamp + "13:13" + styles.reset + + " [" + styles.level_error + styles.bright + dev._pad("error", cr._longest_level) + - dev.RESET_ALL + "] " + - PADDED_TEST + - "[" + dev.BLUE + dev.BRIGHT + + styles.reset + "] " + + padded + + "[" + dev.BLUE + styles.bright + "some_module" + - dev.RESET_ALL + "] " + - dev.CYAN + "foo" + dev.RESET_ALL + "=" + dev.MAGENTA + "'bar'" + - dev.RESET_ALL + " " + - dev.CYAN + "key" + dev.RESET_ALL + "=" + dev.MAGENTA + "'value'" + - dev.RESET_ALL + + styles.reset + "] " + + styles.kv_key + "foo" + styles.reset + "=" + + styles.kv_value + "'bar'" + + styles.reset + " " + + styles.kv_key + "key" + styles.reset + "=" + + styles.kv_value + "'value'" + + styles.reset + "\n" + stack + "\n\n" + "=" * 79 + "\n" + "\n" + exc ) == rv + + def test_colorama_colors_false(self): + """ + If colors is False, don't use colors or styles ever. + """ + plain_cr = dev.ConsoleRenderer(colors=False) + + rv = plain_cr(None, None, { + "event": "event", "level": "info", "foo": "bar" + }) + + assert dev._PlainStyles is plain_cr._styles + assert "[info ] event foo='bar'" == rv diff --git a/tests/test_twisted.py b/tests/test_twisted.py index 67b4e1ce..0cda3b77 100644 --- a/tests/test_twisted.py +++ b/tests/test_twisted.py @@ -17,7 +17,8 @@ from twisted.python.log import ILogObserver from structlog._config import _CONFIG -from structlog._loggers import ReturnLogger +from structlog import ReturnLogger +from structlog.processors import KeyValueRenderer from structlog.twisted import ( BoundLogger, EventAdapter, @@ -46,32 +47,42 @@ def build_bl(logger=None, processors=None, context=None): """ return BoundLogger( logger or ReturnLogger(), - processors or _CONFIG.default_processors, + processors or [KeyValueRenderer()], context if context is not None else _CONFIG.default_context_class(), ) class TestBoundLogger(object): def test_msg(self): + """ + log.msg renders correctly. + """ bl = build_bl() - assert "foo=42 event='event'" == bl.msg('event', foo=42) + assert "foo=42 event='event'" == bl.msg("event", foo=42) def test_errVanilla(self): + """ + log.err renders correctly if no failure is attached. + """ bl = build_bl() - assert "foo=42 event='event'" == bl.err('event', foo=42) + assert "foo=42 event='event'" == bl.err("event", foo=42) def test_errWithFailure(self): - bl = build_bl(processors=[EventAdapter()]) + """ + Failures are correctly injected into the log entries. + """ + bl = build_bl(processors=[ + EventAdapter(dictRenderer=KeyValueRenderer()) + ]) try: raise ValueError except ValueError: # Use str() for comparison to avoid tricky # deep-compares of Failures. - assert ( - str(((), {'_stuff': Failure(ValueError()), - '_why': "foo=42 event='event'"})) == - str(bl.err('event', foo=42)) - ) + assert str(((), { + '_stuff': Failure(ValueError()), + '_why': "foo=42 event='event'", + })) == str(bl.err('event', foo=42)) class TestExtractStuffAndWhy(object): diff --git a/tox.ini b/tox.ini index 962a3ac4..d4dc1a8b 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = {py27,py34,py35,pypy}-{threads,greenlets},py35-nocolorama,flake8,docs,readme,manifest,coverage-report +envlist = {py27,py34,py35,pypy}-{threads,greenlets},{py27,py35}-colorama,flake8,docs,readme,manifest,coverage-report [testenv] @@ -7,10 +7,8 @@ deps = -rdev-requirements.txt greenlets: greenlet twisted - # indirectly ensure that only -nocolorama has no colorama - threads: colorama>=0.3.6 - greenlets: colorama>=0.3.6 - py33,py34,py35: python-rapidjson + colorama: colorama + py34,py35: python-rapidjson setenv = PYTHONHASHSEED = 0 commands = coverage run --parallel -m pytest {posargs} From 4b7593bdc963b378593f2675978c237865e7488a Mon Sep 17 00:00:00 2001 From: Ilian Iliev Date: Sat, 17 Sep 2016 12:03:47 +0200 Subject: [PATCH 0099/1520] Handling the case when exc_info is not True but evalues to True (#80) --- src/structlog/processors.py | 8 +++++--- tests/test_processors.py | 9 ++++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/structlog/processors.py b/src/structlog/processors.py index e8af0cd3..60ddfd28 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -237,10 +237,12 @@ def _figure_out_exc_info(v): :rtype: tuple """ - if v is True: - return sys.exc_info() - elif six.PY3 and isinstance(v, BaseException): + if six.PY3 and isinstance(v, BaseException): return (v.__class__, v, getattr(v, "__traceback__")) + elif isinstance(v, tuple): + return v + elif v: + return sys.exc_info() return v diff --git a/tests/test_processors.py b/tests/test_processors.py index 5737259b..c3d936e8 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -445,14 +445,17 @@ def test_renders_correct_stack(self, sir): class TestFigureOutExcInfo(object): - def test_obtains_exc_info_on_True(self): + @pytest.mark.parametrize('true_value', [ + True, 1, 1.1 + ]) + def test_obtains_exc_info_on_True(self, true_value): """ - If True is passed, obtain exc_info ourselves. + If the passed argument evaluates to True obtain exc_info ourselves. """ try: 0/0 except Exception: - assert sys.exc_info() == _figure_out_exc_info(True) + assert sys.exc_info() == _figure_out_exc_info(true_value) else: pytest.fail("Exception not raised.") From c256057977b42faffbf814f99dbd512d2b7b901b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 17 Sep 2016 13:12:40 +0200 Subject: [PATCH 0100/1520] Mention UnicodeDecoder in narrative docs --- docs/standard-library.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/standard-library.rst b/docs/standard-library.rst index 81b4e6cf..b236c1e4 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -59,6 +59,7 @@ A basic configuration to output structured logs in JSON format looks like this: structlog.processors.TimeStamper(fmt="iso"), structlog.processors.StackInfoRenderer(), structlog.processors.format_exc_info, + structlog.processors.UnicodeDecoder(), structlog.processors.JSONRenderer() ], context_class=dict, @@ -67,6 +68,7 @@ A basic configuration to output structured logs in JSON format looks like this: cache_logger_on_first_use=True, ) +(if you're still runnning Python 2, replace :class:`~structlog.processors.UnicodeDecoder` through :class:`~structlog.processors.UnicodeEncoder`) To make your program behave like a proper `12 factor app`_ that outputs only JSON to ``stdout``, configure the ``logging`` module like this:: From b4850e4d8356fc44701cf42dc46bfeccd64960ef Mon Sep 17 00:00:00 2001 From: Matias Surdi Date: Wed, 19 Oct 2016 18:23:05 +0200 Subject: [PATCH 0101/1520] Fix format argument docs for TimeStamper class (#85) --- src/structlog/processors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 60ddfd28..4ab5e23f 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -198,7 +198,7 @@ class TimeStamper(object): You should let OS tools take care of timestamping. See also :doc:`logging-best-practices`. - :param str format: strftime format string, or ``"iso"`` for `ISO 8601 + :param str fmt: strftime format string, or ``"iso"`` for `ISO 8601 `_, or `None` for a `UNIX timestamp `_. :param bool utc: Whether timestamp should be in UTC or local time. From b7da54cbe739f46ed19da8faf2d1c33ae6fc2d2b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 23 Oct 2016 07:33:33 +0200 Subject: [PATCH 0102/1520] Move extra JSONRenderer docs from twisted to default --- docs/api.rst | 51 ++++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 36fb1fd2..553a0f17 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -97,6 +97,32 @@ API Reference .. autoclass:: JSONRenderer + .. doctest:: + + >>> from structlog.processors import JSONRenderer + >>> JSONRenderer(sort_keys=True)(None, None, {'a': 42, 'b': [1, 2, 3]}) + '{"a": 42, "b": [1, 2, 3]}' + + Bound objects are attempted to be serialize using a ``__structlog__`` method. + If none is defined, ``repr()`` is used: + + .. doctest:: + + >>> class C1(object): + ... def __structlog__(self): + ... return ['C1!'] + ... def __repr__(self): + ... return '__structlog__ took precedence' + >>> class C2(object): + ... def __repr__(self): + ... return 'No __structlog__, so this is used.' + >>> from structlog.processors import JSONRenderer + >>> JSONRenderer(sort_keys=True)(None, None, {'c1': C1(), 'c2': C2()}) + '{"c1": ["C1!"], "c2": "No __structlog__, so this is used."}' + + Please note that additionally to strings, you can also return any type the standard library JSON module knows about -- like in this example a list. + + .. autoclass:: KeyValueRenderer .. doctest:: @@ -176,31 +202,6 @@ API Reference .. autoclass:: JSONRenderer - .. doctest:: - - >>> from structlog.processors import JSONRenderer - >>> JSONRenderer(sort_keys=True)(None, None, {'a': 42, 'b': [1, 2, 3]}) - '{"a": 42, "b": [1, 2, 3]}' - - Bound objects are attempted to be serialize using a ``__structlog__`` method. - If none is defined, ``repr()`` is used: - - .. doctest:: - - >>> class C1(object): - ... def __structlog__(self): - ... return ['C1!'] - ... def __repr__(self): - ... return '__structlog__ took precedence' - >>> class C2(object): - ... def __repr__(self): - ... return 'No __structlog__, so this is used.' - >>> from structlog.processors import JSONRenderer - >>> JSONRenderer(sort_keys=True)(None, None, {'c1': C1(), 'c2': C2()}) - '{"c1": ["C1!"], "c2": "No __structlog__, so this is used."}' - - Please note that additionally to strings, you can also return any type the standard library JSON module knows about -- like in this example a list. - .. autofunction:: plainJSONStdOutLogger .. autofunction:: JSONLogObserverWrapper From 9ac8c09c57bbf83399ca00a7f6a1b64ca834de0c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 23 Oct 2016 07:43:00 +0200 Subject: [PATCH 0103/1520] Make JSONRenderer docs more generic --- src/structlog/processors.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 4ab5e23f..689fbc59 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -125,15 +125,15 @@ def __call__(self, logger, name, event_dict): class JSONRenderer(object): """ - Render the `event_dict` using `json.dumps(event_dict, **json_kw)`. + Render the `event_dict` using ``serializer(event_dict, **json_kw)``. - :param dict json_kw: Are passed unmodified to :func:`json.dumps`. + :param dict json_kw: Are passed unmodified to *serializer*. :param callable serializer: A :func:`json.dumps`-compatible callable that will be used to format the string. This can be used to use alternative JSON encoders like `simplejson `_ or `RapidJSON `_ (faster but Python - 3-only). + 3-only) (default: :func:`json.dumps`). .. versionadded:: 0.2.0 Support for ``__structlog__`` serialization method. From 838abddd4f6efbe541a352e10f9d593759efefde Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 23 Oct 2016 07:43:30 +0200 Subject: [PATCH 0104/1520] Use https for RTD badge --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index d47eaef5..e05ddf3f 100644 --- a/README.rst +++ b/README.rst @@ -3,7 +3,7 @@ structlog: Structured Logging for Python ======================================== .. image:: https://readthedocs.org/projects/structlog/badge/?version=stable - :target: http://structlog.readthedocs.io/en/stable/?badge=stable + :target: https://structlog.readthedocs.io/en/stable/?badge=stable :alt: Documentation Status .. image:: https://travis-ci.org/hynek/structlog.svg?branch=master From 3d0e297d32894d20ab3eeac95d0b398fc1a014a2 Mon Sep 17 00:00:00 2001 From: Gilbert Gilb's Date: Fri, 25 Nov 2016 13:41:43 +0100 Subject: [PATCH 0105/1520] Handle log formatting for third party components (#90) We should be using `record.getMessage()` instead of `record.msg` to ensure that third party libraries logs are formatted. --- docs/faq.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/faq.rst b/docs/faq.rst index ebd21f45..246ccf1e 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -48,7 +48,7 @@ How can I make third party components log in JSON too? self._log = structlog.get_logger() def emit(self, record): - self._log.log(record.levelno, record.msg, name=record.name) + self._log.log(record.levelno, record.getMessage(), name=record.name) root_logger = logging.getLogger() root_logger.addHandler(StructlogHandler()) From e9fdd963ae85ea83063229018210a4c2947c2229 Mon Sep 17 00:00:00 2001 From: Bence Nagy Date: Fri, 25 Nov 2016 14:33:08 +0100 Subject: [PATCH 0106/1520] Fix flake8 errors (#91) --- setup.py | 1 + src/structlog/stdlib.py | 1 + 2 files changed, 2 insertions(+) diff --git a/setup.py b/setup.py index 0e599bf2..a7203c07 100644 --- a/setup.py +++ b/setup.py @@ -48,6 +48,7 @@ def read(*parts): with codecs.open(os.path.join(HERE, *parts), "rb", "utf-8") as f: return f.read() + try: PACKAGES except NameError: diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 59ba0fba..f0cf297e 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -277,6 +277,7 @@ def __call__(self, _, __, event_dict): del event_dict['positional_args'] return event_dict + # Adapted from the stdlib CRITICAL = 50 From bd83cc95776bddc6721046f1c2e55b06c1c23e6e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 9 Dec 2016 12:39:05 +0100 Subject: [PATCH 0107/1520] Add repr_native_str to KeyValueRenderer & ConsoleRenderer ref #94 --- CHANGELOG.rst | 4 ++++ src/structlog/dev.py | 23 ++++++++++++++++++++--- src/structlog/processors.py | 30 ++++++++++++++++++++++-------- src/structlog/stdlib.py | 1 - tests/test_dev.py | 35 ++++++++++++++++++++++++++++------- tests/test_processors.py | 18 ++++++++++++++++++ 6 files changed, 92 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 3318f8aa..f9c01c51 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -19,6 +19,10 @@ Backward-incompatible changes: Changes: ^^^^^^^^ +- Add *repr_native_str* to ``structlog.processors.KeyValueRenderer`` and ``structlog.dev.ConsoleRenderer``. + This allows for human-readable non-ASCII output on Python 2 (``repr()`` on Python 2 haves like ``ascii()`` on Python 3 in that regard). + As per compatibility policy, it's on (original behavior) in ``KeyValueRenderer`` and off (humand-friendly behavior) in ``ConsoleRenderer``. + `#94 `_ - Add *colors* argument to ``structlog.dev.ConsoleRenderer`` and make it the default renderer. `#78 `_ diff --git a/src/structlog/dev.py b/src/structlog/dev.py index bd46763f..0bd48519 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -99,15 +99,22 @@ class ConsoleRenderer(object): :param int pad_event: Pad the event to this many characters. :param bool colors: Use colors for a nicer output. + :param bool repr_native_str: When ``True``, :func:`repr()` is also applied + to native strings (i.e. unicode on Python 3 and bytes on Python 2). + Setting this to ``False`` is useful if you want to have human-readable + non-ASCII output on Python 2. The `event` key is *never* + :func:`repr()` -ed. Requires the colorama_ package if *colors* is ``True``. .. _colorama: https://pypi.org/project/colorama/ .. versionadded:: 16.0 - .. versionadded:: 16.1 *colors* argument + .. versionadded:: 16.1 *colors* + .. versionadded:: 16.2 *repr_native_str* """ - def __init__(self, pad_event=_EVENT_WIDTH, colors=True): + def __init__(self, pad_event=_EVENT_WIDTH, colors=True, + repr_native_str=False): if colors is True: if colorama is None: raise SystemError( @@ -142,6 +149,16 @@ def __init__(self, pad_event=_EVENT_WIDTH, colors=True): key=lambda e: len(e) )) + if repr_native_str is True: + self._repr = repr + else: + def _repr(inst): + if isinstance(inst, str): + return inst + else: + return repr(inst) + self._repr = _repr + def __call__(self, _, __, event_dict): sio = StringIO() @@ -180,7 +197,7 @@ def __call__(self, _, __, event_dict): " ".join( self._styles.kv_key + key + self._styles.reset + "=" + - self._styles.kv_value + repr(event_dict[key]) + + self._styles.kv_value + self._repr(event_dict[key]) + self._styles.reset for key in sorted(event_dict.keys()) ) diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 689fbc59..ed9c7ea8 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -32,15 +32,19 @@ class KeyValueRenderer(object): :param list key_order: List of keys that should be rendered in this exact order. Missing keys will be rendered as ``None``, extra keys depending on *sort_keys* and the dict class. - :param bool drop_missing: When True, extra keys in *key_order* will be + :param bool drop_missing: When ``True``, extra keys in *key_order* will be dropped rather than rendered as ``None``. - - .. versionadded:: 0.2.0 - *key_order* - .. versionadded:: 16.1.0 - *drop_missing* + :param bool repr_native_str: When ``True``, :func:`repr()` is also applied + to native strings (i.e. unicode on Python 3 and bytes on Python 2). + Setting this to ``False`` is useful if you want to have human-readable + non-ASCII output on Python 2. + + .. versionadded:: 0.2.0 *key_order* + .. versionadded:: 16.1.0 *drop_missing* + .. versionadded:: 16.2.0 *repr_native_str* """ - def __init__(self, sort_keys=False, key_order=None, drop_missing=False): + def __init__(self, sort_keys=False, key_order=None, drop_missing=False, + repr_native_str=True): # Use an optimized version for each case. if key_order and sort_keys: def ordered_items(event_dict): @@ -68,8 +72,18 @@ def ordered_items(event_dict): self._ordered_items = ordered_items + if repr_native_str is True: + self._repr = repr + else: + def _repr(inst): + if isinstance(inst, str): + return inst + else: + return repr(inst) + self._repr = _repr + def __call__(self, _, __, event_dict): - return ' '.join(k + '=' + repr(v) + return ' '.join(k + '=' + self._repr(v) for k, v in self._ordered_items(event_dict)) diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index f0cf297e..97d9b672 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -279,7 +279,6 @@ def __call__(self, _, __, event_dict): # Adapted from the stdlib - CRITICAL = 50 FATAL = CRITICAL ERROR = 40 diff --git a/tests/test_dev.py b/tests/test_dev.py index 9d8978f9..b9c4394f 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- + # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. @@ -5,6 +7,7 @@ from __future__ import absolute_import, division, print_function import pytest +import six from structlog import dev @@ -94,7 +97,7 @@ def test_level(self, cr, styles, padded): styles.reset + "] " + padded + styles.kv_key + "foo" + styles.reset + "=" + - styles.kv_value + "'bar'" + styles.reset + styles.kv_value + "bar" + styles.reset ) == rv def test_logger_name(self, cr, styles, padded): @@ -122,10 +125,10 @@ def test_key_values(self, cr, styles, padded): assert ( padded + styles.kv_key + "foo" + styles.reset + "=" + - styles.kv_value + "'bar'" + + styles.kv_value + "bar" + styles.reset + " " + styles.kv_key + "key" + styles.reset + "=" + - styles.kv_value + "'value'" + + styles.kv_value + "value" + styles.reset ) == rv @@ -172,7 +175,7 @@ def test_pad_event_param(self, styles): dev._pad("test", 42) + styles.reset + " " + styles.kv_key + "foo" + styles.reset + "=" + - styles.kv_value + "'bar'" + styles.reset + styles.kv_value + "bar" + styles.reset ) == rv def test_everything(self, cr, styles, padded): @@ -203,10 +206,10 @@ def test_everything(self, cr, styles, padded): "some_module" + styles.reset + "] " + styles.kv_key + "foo" + styles.reset + "=" + - styles.kv_value + "'bar'" + + styles.kv_value + "bar" + styles.reset + " " + styles.kv_key + "key" + styles.reset + "=" + - styles.kv_value + "'value'" + + styles.kv_value + "value" + styles.reset + "\n" + stack + "\n\n" + "=" * 79 + "\n" + "\n" + exc @@ -223,4 +226,22 @@ def test_colorama_colors_false(self): }) assert dev._PlainStyles is plain_cr._styles - assert "[info ] event foo='bar'" == rv + assert "[info ] event foo=bar" == rv + + @pytest.mark.parametrize("rns", [True, False]) + def test_repr_native_str(self, rns): + """ + repr_native_str=False doesn't repr on native strings. "event" is + never repr'ed. + """ + rv = dev.ConsoleRenderer( + colors=False, repr_native_str=rns)(None, None, { + "event": "哈", "key": 42, "key2": "哈", + } + ) + + cnt = rv.count("哈") + if rns and six.PY2: + assert 1 == cnt + else: + assert 2 == cnt diff --git a/tests/test_processors.py b/tests/test_processors.py index c3d936e8..80cd3496 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- + # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. @@ -10,6 +12,7 @@ import pytest import simplejson +import six try: import rapidjson @@ -126,6 +129,21 @@ def test_random_order(self, event_dict): rv = KeyValueRenderer()(None, None, event_dict) assert isinstance(rv, str) + @pytest.mark.parametrize("rns", [True, False]) + def test_repr_native_str(self, rns): + """ + repr_native_str=False doesn't repr on native strings. + """ + rv = KeyValueRenderer(repr_native_str=rns)(None, None, { + "event": "哈", "key": 42, "key2": "哈", + }) + + cnt = rv.count("哈") + if rns and six.PY2: + assert 0 == cnt + else: + assert 2 == cnt + class TestJSONRenderer(object): def test_renders_json(self, event_dict): From 50f1a88a2b7bd1a211e98501e5cf9785edca6869 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 10 Dec 2016 11:43:58 +0100 Subject: [PATCH 0108/1520] Improve contributing guide --- CONTRIBUTING.rst | 114 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 96 insertions(+), 18 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index e858a964..a04388aa 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -1,32 +1,108 @@ How To Contribute ================= -Every open source project lives from the generous help by contributors that sacrifice their time and ``structlog`` is no different. +First off, thank you for considering contributing to ``structlog``! +It's people like *you* who make it is such a great tool for everyone. -Here are a few guidelines to get you started: +Here are a few guidelines to get you started (but don't be afraid to open half-finished PRs and ask questions if something is unclear!): -- Try to limit each pull request to one change only. -- To run the test suite, all you need is a recent tox_. - It will ensure the test suite runs with all dependencies against all Python versions just as it will on `Travis CI`_. - If you lack some Python version, you can can always limit the environments like ``tox -e py27,py35`` (in that case you may want to look into pyenv_ that makes it very easy to install many different Python versions in parallel). -- Make sure your changes pass our CI. + +Workflow +-------- + +- No contribution is too small! + Please submit as many fixes for typos and grammar bloopers as you can! +- Try to limit each pull request to *one* change only. +- *Always* add tests and docs for your code. + This is a hard rule; patches with missing tests or documentation can't be accepted. +- Make sure your changes pass our CI_. You won't get any feedback until it's green unless you ask for it. -- If your change is noteworthy, add an entry to the changelog_. - Use present tense, semantic newlines, and add link to your pull request. -- No contribution is too small; please submit as many fixes for typos and grammar bloopers as you can! +- Once you've addressed review feedback, make sure to bump the pull request with a short note. + Maintainers don’t receive notifications when you push new commits. - Don’t break `backward compatibility`_. -- *Always* add tests and docs for your code. - This is a hard rule; patches with missing tests or documentation won’t be merged. -- Write `good test docstrings`_. + + +Code +---- + - Obey `PEP 8`_ and `PEP 257`_. -- If you address review feedback, make sure to bump the pull request. - Maintainers don’t receive notifications if you push new commits. + We use the ``"""``\ -on-separate-lines style for docstrings: + + .. code-block:: python + + def func(x): + """ + Does something. + + :param str x: A very important parameter. + + :rtype: str + """ +- If you add or change public APIs, tag the docstring using ``.. versionadded:: 16.0.0 WHAT`` or ``.. versionchanged:: 16.2.0 WHAT``. +- Prefer double quotes (``"``) over single quotes (``'``) unless the string contains double quotes itself. + + +Tests +----- + +- Write your asserts as ``expected == actual`` to line them up nicely: + + .. code-block:: python + + x = f() + + assert 42 == x.some_attribute + assert "foo" == x._a_private_attribute + +- To run the test suite, all you need is a recent tox_. + It will ensure the test suite runs with all dependencies against all Python versions just as it will on Travis CI. + If you lack some Python versions, you can can always limit the environments like ``tox -e py27,py35`` (in that case you may want to look into pyenv_, which makes it very easy to install many different Python versions in parallel). +- Write `good test docstrings`_. + + +Documentation +------------- + +- Use `semantic newlines`_ in reStructuredText_ files (files ending in ``.rst``): + + .. code-block:: rst + + This is a sentence. + This is another sentence. + +- If you start a new section, add two blank lines before and one blank line after the header: + + .. code-block:: rst + + Last line of previous section. + + + Header of New Section + ^^^^^^^^^^^^^^^^^^^^^ + + First line of new section. +- If your change is noteworthy, add an entry to the changelog_. + Use present tense, `semantic newlines`_, and add a link to your pull request: + + .. code-block:: rst + + - Add awesome new feature. + The feature really *is* awesome. + [`#1 `_] + - Fix nasty bug. + The bug really *was* nasty. + [`#2 `_] + +**** + +Again, this list is mainly to help you to get started by codifying tribal knowledge and expectations. +If something is unclear, feel free to ask for help! Please note that this project is released with a Contributor `Code of Conduct`_. By participating in this project you agree to abide by its terms. Please report any harm to `Hynek Schlawack`_ in any way you find appropriate. -Thank you for considering to contribute to ``structlog``! +Thank you for considering contributing to ``structlog``! .. _`Hynek Schlawack`: https://hynek.me/about/ @@ -35,7 +111,9 @@ Thank you for considering to contribute to ``structlog``! .. _`good test docstrings`: https://jml.io/pages/test-docstrings.html .. _`Code of Conduct`: https://github.com/hynek/structlog/blob/master/CODE_OF_CONDUCT.rst .. _changelog: https://github.com/hynek/structlog/blob/master/CHANGELOG.rst -.. _`backward compatibility`: http://www.structlog.org/en/latest/backward-compatibility.html +.. _`backward compatibility`: https://structlog.readthedocs.io/en/latest/backward-compatibility.html .. _`tox`: https://testrun.org/tox/ -.. _`Travis CI`: https://travis-ci.org/ .. _pyenv: https://github.com/yyuu/pyenv +.. _reStructuredText: http://sphinx-doc.org/rest.html +.. _semantic newlines: http://rhodesmill.org/brandon/2012/one-sentence-per-line/ +.. _CI: https://travis-ci.org/hynek/structlog/ From 4db913e684d120beeb3bc56f2507aa526fe4f8ac Mon Sep 17 00:00:00 2001 From: Bence Nagy Date: Sat, 10 Dec 2016 12:28:00 +0100 Subject: [PATCH 0109/1520] Add note about third party processors to docs (#89) --- docs/processors.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/processors.rst b/docs/processors.rst index 5dea766f..ffc46832 100644 --- a/docs/processors.rst +++ b/docs/processors.rst @@ -116,3 +116,15 @@ Advanced log aggregation and analysis tools like `logstash ` chapter. For a list of shipped processors, check out the :ref:`API documentation `. + + +Third Party Packages +-------------------- + +Since processors are self-contained callables, +it's easy to write your own and to share them in separate packages. +The following processor packages are known to be currently available on PyPI: + +- `structlog-pretty `_: Processors for prettier output -- a code syntax highlighter, JSON and XML prettifiers, a multiline string printer, and a numeric value rounder. + +Please feel free to submit a pull request to extend this list with *your* package! From 2b534604600a587abeb9690291fb1158dfb6d4bd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 30 Jan 2017 08:20:19 +0100 Subject: [PATCH 0110/1520] Python 3.6 --- .travis.yml | 12 ++++++++---- docs/api.rst | 2 +- docs/thread-local.rst | 2 +- tox.ini | 10 +++++----- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1605ff86..4a39aee3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,10 @@ matrix: env: TOXENV=py35-threads - python: "3.5" env: TOXENV=py35-greenlets + - python: "3.6" + env: TOXENV=py36-threads + - python: "3.6" + env: TOXENV=py36-greenlets - python: "pypy" env: TOXENV=pypy-threads - python: "pypy" @@ -31,13 +35,13 @@ matrix: # Meta - - python: "3.5" + - python: "3.6" env: TOXENV=flake8 - - python: "3.5" + - python: "3.6" env: TOXENV=manifest - - python: "3.5" + - python: "3.6" env: TOXENV=docs - - python: "3.5" + - python: "3.6" env: TOXENV=readme diff --git a/docs/api.rst b/docs/api.rst index 553a0f17..3e66ebcf 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -80,7 +80,7 @@ API Reference >>> with tmp_bind(logger, x=5) as tmp_logger: ... logger = logger.bind(y=3) ... tmp_logger.msg("event") - y=3 x=5 event='event' + x=5 y=3 event='event' >>> logger.msg("event") event='event' diff --git a/docs/thread-local.rst b/docs/thread-local.rst index 16aa045a..6f20e9b0 100644 --- a/docs/thread-local.rst +++ b/docs/thread-local.rst @@ -101,7 +101,7 @@ In order to be able to bind values temporarily to a logger, :mod:`structlog.thre x=42 event='event!' >>> with tmp_bind(log, x=23, y="foo") as tmp_log: ... tmp_log.msg("another event!") - y='foo' x=23 event='another event!' + x=23 y='foo' event='another event!' >>> log.msg("one last event!") x=42 event='one last event!' diff --git a/tox.ini b/tox.ini index d4dc1a8b..7394d90b 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = {py27,py34,py35,pypy}-{threads,greenlets},{py27,py35}-colorama,flake8,docs,readme,manifest,coverage-report +envlist = {py27,py34,py35,py36,pypy}-{threads,greenlets},{py27,py35}-colorama,flake8,docs,readme,manifest,coverage-report [testenv] @@ -15,14 +15,14 @@ commands = coverage run --parallel -m pytest {posargs} [testenv:flake8] -basepython = python3.5 +basepython = python3.6 skip_install = true deps = flake8 commands = flake8 src tests setup.py docs/conf.py [testenv:docs] -basepython = python3.5 +basepython = python3.6 setenv = PYTHONHASHSEED = 0 deps = @@ -34,14 +34,14 @@ commands = [testenv:readme] -basepython = python3.5 +basepython = python3.6 deps = readme_renderer skip_install = true commands = python setup.py check -r -s [testenv:manifest] -basepython = python3.5 +basepython = python3.6 skip_install = true deps = check-manifest commands = check-manifest From 52866c1ace4af1d2842706133d5111b66aebb893 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 30 Jan 2017 08:33:04 +0100 Subject: [PATCH 0111/1520] Add classifier --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index a7203c07..63b7605d 100644 --- a/setup.py +++ b/setup.py @@ -25,6 +25,7 @@ "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Programming Language :: Python", From b0b386e540aa1eb09576ff23bb9e5d122468c8b7 Mon Sep 17 00:00:00 2001 From: Ouroboros Chrysopoeia Date: Fri, 3 Feb 2017 11:44:44 -0500 Subject: [PATCH 0112/1520] s/it's/its (#103) Grammar fix. --- docs/getting-started.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 0bff1ba3..907dc1a3 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -85,7 +85,7 @@ For ``structlog``, a log entry is just a dictionary called *event dict[ionary]*: These pre-saved values are called the *context*. - As soon as an *event* happens -- which is a dictionary too -- it is merged together with the *context* to an *event dict* and logged out. - If you don't like the concept of pre-building a context: just don't! - Convenient key-value-based logging is great to have on it's own. + Convenient key-value-based logging is great to have on its own. - To keep as much order of the keys as possible, an :class:`collections.OrderedDict` is used for the context by default. - The recommended way of binding values is the one in these examples: creating new loggers with a new context. If you're okay with giving up immutable local state for convenience, you can also use :ref:`thread/greenlet local storage ` for the context. From 69eed86e9770904ff881f9659f64de5370d0ab1a Mon Sep 17 00:00:00 2001 From: Gilbert Gilb's Date: Wed, 8 Feb 2017 15:45:01 +0100 Subject: [PATCH 0113/1520] Fix stdlib errors being logged as exceptions sometimes. (#92) --- CHANGELOG.rst | 3 +++ src/structlog/stdlib.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f9c01c51..dc11a46b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -25,6 +25,9 @@ Changes: `#94 `_ - Add *colors* argument to ``structlog.dev.ConsoleRenderer`` and make it the default renderer. `#78 `_ +- Fix bug with Python 3 and ``structlog.stdlib.log`` function. Error log level was not reproductible and was logged as exception + one time out of two. + `#92 `_ ---- diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 97d9b672..30c9cac5 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -301,7 +301,7 @@ def __call__(self, _, __, event_dict): _LEVEL_TO_NAME = dict( (v, k) for k, v in _NAME_TO_LEVEL.items() - if k not in ("warn", "notset") + if k not in ("warn", "exception", "notset", ) ) From 705d3a3581ffca1180e72845dd3af829fe1d2ac2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 9 Feb 2017 22:33:12 +0100 Subject: [PATCH 0114/1520] Use time.time() for unix epoch time --- CHANGELOG.rst | 1 + src/structlog/processors.py | 3 +-- tests/test_processors.py | 7 +++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index dc11a46b..13dccc38 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -19,6 +19,7 @@ Backward-incompatible changes: Changes: ^^^^^^^^ +- UNIX epoch timestamps from ``structlog.processors.TimeStamper`` are more precise now. - Add *repr_native_str* to ``structlog.processors.KeyValueRenderer`` and ``structlog.dev.ConsoleRenderer``. This allows for human-readable non-ASCII output on Python 2 (``repr()`` on Python 2 haves like ``ascii()`` on Python 3 in that regard). As per compatibility policy, it's on (original behavior) in ``KeyValueRenderer`` and off (humand-friendly behavior) in ``ConsoleRenderer``. diff --git a/src/structlog/processors.py b/src/structlog/processors.py index ed9c7ea8..def39637 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -8,7 +8,6 @@ from __future__ import absolute_import, division, print_function -import calendar import datetime import json import operator @@ -225,7 +224,7 @@ def __new__(cls, fmt=None, utc=True, key='timestamp'): now_method = getattr(datetime.datetime, 'utcnow' if utc else 'now') if fmt is None: def stamper(self, _, __, event_dict): - event_dict[key] = calendar.timegm(time.gmtime()) + event_dict[key] = time.time() return event_dict elif fmt.upper() == 'ISO': if utc: diff --git a/tests/test_processors.py b/tests/test_processors.py index 80cd3496..b88668b8 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -211,10 +211,13 @@ def test_disallowsNonUTCUNIXTimestamps(self): assert 'UNIX timestamps are always UTC.' == e.value.args[0] def test_insertsUTCUNIXTimestampByDefault(self): + """ + Per default a float UNIX timestamp is used. + """ ts = TimeStamper() d = ts(None, None, {}) - # freezegun doesn't work with time.gmtime :( - assert isinstance(d['timestamp'], int) + # freezegun doesn't work with time.time. :( + assert isinstance(d['timestamp'], float) @freeze_time('1980-03-25 16:00:00') def test_local(self): From a820f77c6e1efce0d36ff80699799e0c8e510f08 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 20 Feb 2017 12:46:11 +0100 Subject: [PATCH 0115/1520] Fix example --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index e05ddf3f..abf7dfae 100644 --- a/README.rst +++ b/README.rst @@ -62,7 +62,7 @@ That allows for simple but powerful data manipulation: def timestamper(logger, log_method, event_dict): """Add a timestamp to each log entry.""" - event_dict["timestamp"] = calendar.timegm(time.gmtime()) + event_dict["timestamp"] = time.time() return event_dict There are `plenty of processors `_ for most common tasks coming with ``structlog``: From efae84ea56bd5160de1e494165c245e3b474d7ff Mon Sep 17 00:00:00 2001 From: sky Date: Tue, 10 Jan 2017 18:00:19 +0200 Subject: [PATCH 0116/1520] Add LogRecordCompatibleDictRenderer processor Fixes #98 --- CHANGELOG.rst | 9 ++++- MANIFEST.in | 2 +- conftest.py | 31 +++++++++++++++ docs/api.rst | 2 + docs/standard-library.rst | 81 +++++++++++++++++++++++++++++++++++---- src/structlog/stdlib.py | 17 ++++++++ tests/test_processors.py | 15 -------- tests/test_stdlib.py | 28 ++++++++++++-- 8 files changed, 156 insertions(+), 29 deletions(-) create mode 100644 conftest.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 13dccc38..96ad21d6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,7 +5,7 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. -16.2.0 (UNRELEASED) +17.1.0 (UNRELEASED) ------------------- Backward-incompatible changes: @@ -19,6 +19,11 @@ Backward-incompatible changes: Changes: ^^^^^^^^ +- Added ``structlog.stdlib.render_to_log_kwargs()``. + This allows to let standard library's ``logging`` do all formatting. + It gives you much more consistently formatted logs if you have mixed ``structlog`` and ``logging`` output. + Have a look at the updated `standard library chapter `_ on how to use it! + `#98 `_ - UNIX epoch timestamps from ``structlog.processors.TimeStamper`` are more precise now. - Add *repr_native_str* to ``structlog.processors.KeyValueRenderer`` and ``structlog.dev.ConsoleRenderer``. This allows for human-readable non-ASCII output on Python 2 (``repr()`` on Python 2 haves like ``ascii()`` on Python 3 in that regard). @@ -26,7 +31,7 @@ Changes: `#94 `_ - Add *colors* argument to ``structlog.dev.ConsoleRenderer`` and make it the default renderer. `#78 `_ -- Fix bug with Python 3 and ``structlog.stdlib.log`` function. Error log level was not reproductible and was logged as exception +- Fix bug with Python 3 and ``structlog.stdlib.BoundLogger.log()``. Error log level was not reproductible and was logged as exception one time out of two. `#92 `_ diff --git a/MANIFEST.in b/MANIFEST.in index 20cc4b2b..81c5a1f8 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,4 @@ -include LICENSE LICENSE.apache2 LICENSE.mit .coveragerc +include LICENSE LICENSE.apache2 LICENSE.mit .coveragerc conftest.py include *.rst include *.txt include .travis.yml diff --git a/conftest.py b/conftest.py new file mode 100644 index 00000000..26b319ce --- /dev/null +++ b/conftest.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- + +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the MIT License. See the LICENSE file in the root of this +# repository for complete details. + +from __future__ import absolute_import, division, print_function + +import pytest + +from six.moves import cStringIO as StringIO + + +@pytest.fixture +def sio(): + """ + A StringIO instance. + """ + return StringIO() + + +@pytest.fixture +def event_dict(): + """ + An example event dictionary with multiple value types w/o the event itself. + """ + class A(object): + def __repr__(self): + return "" + + return {"a": A(), "b": [3, 4], "x": 7, "y": "test", "z": (1, 2)} diff --git a/docs/api.rst b/docs/api.rst index 3e66ebcf..c64dc11c 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -178,6 +178,8 @@ API Reference .. autoclass:: LoggerFactory :members: __call__ +.. autofunction:: render_to_log_kwargs + .. autofunction:: filter_by_level .. autofunction:: add_log_level diff --git a/docs/standard-library.rst b/docs/standard-library.rst index b236c1e4..3a08eb81 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -1,5 +1,5 @@ -Python Standard Library -======================= +Standard Library Logging +======================== Ideally, ``structlog`` should be able to be used as a drop-in replacement for standard library's :mod:`logging` by wrapping it. In other words, you should be able to replace your call to :func:`logging.getLogger` by a call to :func:`structlog.get_logger` and things should keep working as before (if ``structlog`` is configured right, see :ref:`stdlib-config` below). @@ -24,6 +24,10 @@ Processors ``structlog`` comes with a few standard library-specific processors: +:func:`~structlog.stdlib.render_to_log_kwargs`: + Renders the event dictionary into keyword arguments for :func:`logging.log` that attaches everything except the `event` field to the *extra* argument. + This is useful if you want to render your log entries entirely within :mod:`logging`. + :func:`~structlog.stdlib.filter_by_level`: Checks the log entry's log level against the configuration of standard library's logging. Log entries below the threshold get silently dropped. @@ -41,8 +45,64 @@ Processors .. _stdlib-config: -Suggested Configuration ------------------------ +Suggested Configurations +------------------------ + +Depending where you'd like to do your formatting, you can take one of two approaches: + + +Rendering Within :mod:`logging` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: python + + import structlog + + structlog.configure( + processors=[ + structlog.stdlib.filter_by_level, + structlog.stdlib.add_logger_name, + structlog.stdlib.add_log_level, + structlog.stdlib.PositionalArgumentsFormatter(), + structlog.processors.StackInfoRenderer(), + structlog.processors.format_exc_info, + structlog.processors.UnicodeDecoder(), + structlog.stdlib.render_to_log_kwargs, + ], + context_class=dict, + logger_factory=structlog.stdlib.LoggerFactory(), + wrapper_class=structlog.stdlib.BoundLogger, + cache_logger_on_first_use=True, + ) + +Now you have the event dict available within each log record. +If you want all your log entries (i.e. also those not from your app/``structlog``) to be formatted as JSON, you can use the `python-json-logger library `_: + +.. code-block:: python + + import logging + import sys + + from pythonjsonlogger import jsonlogger + + handler = logging.StreamHandler(sys.stdout) + handler.setFormatter(jsonlogger.JsonFormatter()) + root_logger = logging.getLogger() + root_logger.addHandler(handler) + +Now both ``structlog`` and ``logging`` will emit JSON logs: + +.. code-block:: pycon + + >>> structlog.get_logger("test").warning("hello") + {"message": "hello", "logger": "test", "level": "warning"} + + >>> logging.getLogger("test").warning("hello") + {"message": "hello"} + + +Rendering Within ``structlog`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ A basic configuration to output structured logs in JSON format looks like this: @@ -73,6 +133,7 @@ A basic configuration to output structured logs in JSON format looks like this: To make your program behave like a proper `12 factor app`_ that outputs only JSON to ``stdout``, configure the ``logging`` module like this:: import logging + import sys logging.basicConfig( format="%(message)s", @@ -80,8 +141,14 @@ To make your program behave like a proper `12 factor app`_ that outputs only JSO level=logging.INFO, ) -If you plan to hook up the logging output to `logstash`, as suggested in :doc:`logging-best-practices`, the simplest approach is to configure ``logstash-forwarder`` to pick up the output from your application. -To achieve this, configure your process supervisor (such as ``runit`` or ``supervisord``) to store the output in a file, and have ``logstash-forwarder`` monitor that file to ship it to the central log collection server. -This approach also applies to other centralized logging solutions. +In this case *only* your own logs are formatted as JSON: + +.. code-block:: pycon + + >>> structlog.get_logger("test").warning("hello") + {"event": "hello", "logger": "test", "level": "warning", "timestamp": "2017-03-06T07:39:09.518720Z"} + + >>> logging.getLogger("test").warning("hello") + hello .. _`12 factor app`: http://12factor.net/logs diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 30c9cac5..281137e3 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -348,3 +348,20 @@ def add_logger_name(logger, method_name, event_dict): """ event_dict['logger'] = logger.name return event_dict + + +def render_to_log_kwargs(wrapped_logger, method_name, event_dict): + """ + Render `event_dict` into keyword arguments for :func:`logging.log`. + + The `event` field is translated into `msg` and the rest of the `event_dict` + is added as `extra`. + + This allows you to defer formatting to :mod:`logging`. + + .. versionadded:: 17.1.0 + """ + return { + "msg": event_dict.pop("event"), + "extra": event_dict, + } diff --git a/tests/test_processors.py b/tests/test_processors.py index b88668b8..04e9fdf5 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -20,7 +20,6 @@ rapidjson = None from freezegun import freeze_time -from six.moves import cStringIO as StringIO import structlog @@ -41,20 +40,6 @@ from .utils import py3_only -@pytest.fixture -def sio(): - return StringIO() - - -@pytest.fixture -def event_dict(): - class A(object): - def __repr__(self): - return '' - - return {'a': A(), 'b': [3, 4], 'x': 7, 'y': 'test', 'z': (1, 2)} - - class TestKeyValueRenderer(object): def test_sort_keys(self, event_dict): """ diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 73dda2b5..7ed84015 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -19,10 +19,11 @@ LoggerFactory, PositionalArgumentsFormatter, WARN, - filter_by_level, + _FixedFindCallerLogger, add_log_level, add_logger_name, - _FixedFindCallerLogger, + render_to_log_kwargs, + filter_by_level, ) from .additional_frame import additional_frame @@ -283,7 +284,26 @@ def test_logger_name_added(self): """ The logger name is added to the event dict. """ - name = 'sample-name' + name = "sample-name" logger = logging.getLogger(name) event_dict = add_logger_name(logger, None, {}) - assert name == event_dict['logger'] + assert name == event_dict["logger"] + + +class TestRenderToLogKW(object): + def test_default(self): + """ + Translates `event` to `msg` and handles otherwise empty `event_dict`s. + """ + d = render_to_log_kwargs(None, None, {"event": "message"}) + + assert {"msg": "message", "extra": {}} == d + + def test_add_extra_event_dict(self, event_dict): + """ + Adds all remaining data from `event_dict` into `extra`. + """ + event_dict["event"] = "message" + d = render_to_log_kwargs(None, None, event_dict) + + assert {"msg": "message", "extra": event_dict} == d From 065b69aaba436ec704c4b19eef733af78043e3f1 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 24 Apr 2017 12:13:54 +0200 Subject: [PATCH 0117/1520] Add ProcessorFormatter (#105) Based on the work of @fabianbuechler, @insolite, and @if-fi. Fixes #79, #9 --- CHANGELOG.rst | 11 +++- docs/api.rst | 3 + docs/standard-library.rst | 100 ++++++++++++++++++++++++++++++- src/structlog/stdlib.py | 73 +++++++++++++++++++++++ tests/test_base.py | 10 +++- tests/test_stdlib.py | 122 +++++++++++++++++++++++++++++++++++++- 6 files changed, 308 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 96ad21d6..de3caade 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,10 @@ The third digit is only for regressions. 17.1.0 (UNRELEASED) ------------------- +The main features of this release are multiple improvements in standard library's ``logging`` integration. +Have a look at the updated `standard library chapter `_ on how to use them! + + Backward-incompatible changes: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,10 +24,11 @@ Changes: ^^^^^^^^ - Added ``structlog.stdlib.render_to_log_kwargs()``. - This allows to let standard library's ``logging`` do all formatting. - It gives you much more consistently formatted logs if you have mixed ``structlog`` and ``logging`` output. - Have a look at the updated `standard library chapter `_ on how to use it! + This allows you to use ``logging``-based formatters to take care of rendering your entries. `#98 `_ +- Added ``structlog.stdlib.ProcessorFormatter`` which does the opposite: + This allows you to run ``structlog`` processors on arbitrary ``logging.LogRecords``. + `#79 `_ - UNIX epoch timestamps from ``structlog.processors.TimeStamper`` are more precise now. - Add *repr_native_str* to ``structlog.processors.KeyValueRenderer`` and ``structlog.dev.ConsoleRenderer``. This allows for human-readable non-ASCII output on Python 2 (``repr()`` on Python 2 haves like ``ascii()`` on Python 3 in that regard). diff --git a/docs/api.rst b/docs/api.rst index c64dc11c..b8f3cba7 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -188,6 +188,9 @@ API Reference .. autoclass:: PositionalArgumentsFormatter +.. autoclass:: ProcessorFormatter + :members: wrap_for_formatter + :mod:`twisted` Module --------------------- diff --git a/docs/standard-library.rst b/docs/standard-library.rst index 3a08eb81..7925c731 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -43,16 +43,19 @@ Processors This processes and formats positional arguments (if any) passed to log methods in the same way the ``logging`` module would do, e.g. ``logger.info("Hello, %s", name)``. +``structlog`` also comes with :class:`~structlog.stdlib.ProcessorFormatter` which is a :class:`logging.Formatter` that enables you to format non-``structlog`` log entries using ``structlog`` renderers *and* multiplex ``structlog``’s output with different renderers (see below for an example). + + .. _stdlib-config: Suggested Configurations ------------------------ -Depending where you'd like to do your formatting, you can take one of two approaches: +Depending *where* you'd like to do your formatting, you can take one of three approaches: -Rendering Within :mod:`logging` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Rendering Using :mod:`logging`-based Formatters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: python @@ -101,6 +104,97 @@ Now both ``structlog`` and ``logging`` will emit JSON logs: {"message": "hello"} +Rendering Using ``structlog``-based Formatters Within :mod:`logging` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You can leave rendering for later and yet use ``structlog``’s renderers for it: + +.. code-block:: python + + import logging.config + import structlog + + timestamper = structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S") + pre_chain = [ + # Add the log level and a timestamp to the event_dict if the log entry + # is not from structlog. + structlog.stdlib.add_log_level, + timestamper, + ] + + logging.config.dictConfig({ + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "plain": { + "()": structlog.stdlib.ProcessorFormatter, + "processor": structlog.dev.ConsoleRenderer(colors=False), + "foreign_pre_chain": pre_chain, + }, + "colored": { + "()": structlog.stdlib.ProcessorFormatter, + "processor": structlog.dev.ConsoleRenderer(colors=True), + "foreign_pre_chain": pre_chain, + }, + }, + "handlers": { + "default": { + "level": "DEBUG", + "class": "logging.StreamHandler", + "formatter": "colored", + }, + "file": { + "level": "DEBUG", + "class": "logging.handlers.WatchedFileHandler", + "filename": "test.log", + "formatter": "plain", + }, + }, + "loggers": { + "": { + "handlers": ["default", "file"], + "level": "DEBUG", + "propagate": True, + }, + } + }) + structlog.configure( + processors=[ + structlog.stdlib.add_log_level, + structlog.stdlib.PositionalArgumentsFormatter(), + timestamper, + structlog.processors.StackInfoRenderer(), + structlog.processors.format_exc_info, + structlog.stdlib.ProcessorFormatter.wrap_for_formatter, + ], + context_class=dict, + logger_factory=structlog.stdlib.LoggerFactory(), + wrapper_class=structlog.stdlib.BoundLogger, + cache_logger_on_first_use=True, + ) + +This defines two formatters: one plain and one colored. +Both are run for each log entry. +Log entries that do not originate from ``structlog``, are additionally pre-processed using a cached ``timestamper`` and :func:`~structlog.stdlib.add_log_level`. + +.. code-block:: pycon + + >>> logging.getLogger().warning("bar") + 2017-03-06 11:49:27 [warning ] bar + + >>> structlog.get_logger("structlog").warning("foo", x=42) + 2017-03-06 11:49:32 [warning ] foo x=42 + + >>> print(open("test.log").read()) + 2017-03-06 11:49:27 [warning ] bar + 2017-03-06 11:49:32 [warning ] foo x=42 + +(sadly, you have to imagine the colors in the first two outputs) + +If you leave ``foreign_pre_chain`` `None`, formatting will be left to :mod:`logging`. +Meaning: you can define a ``format`` for :class:`~structlog.stdlib.ProcessorFormatter` too! + + Rendering Within ``structlog`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 281137e3..3dec78dd 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -365,3 +365,76 @@ def render_to_log_kwargs(wrapped_logger, method_name, event_dict): "msg": event_dict.pop("event"), "extra": event_dict, } + + +class ProcessorFormatter(logging.Formatter): + """ + Call ``structlog`` processors on :mod:`logging.LogRecord`\ s. + + This :class:`logging.Formatter` allows to configure :mod:`logging` to call + *processor* on ``structlog``-borne log entries (origin is determined solely + on the fact whether the ``msg`` field on the :class:`logging.LogRecord` is + a dict or not). + + This allows for two interesting use cases: + + #. You can format non-``structlog`` log entries. + #. You can multiplex log records into multiple :class:`logging.Handler`\ s. + + Please refer to :doc:`standard-library` for examples. + + :param callable processor: A ``structlog`` processor. + :param foreign_pre_chain: + If not `None`, it is used as an iterable of processors that is applied + to non-``structlog`` log entries before *processor*. If `None`, + formatting is left to :mod:`logging`. (default: `None`) + + :rtype: str + + .. versionadded:: 17.1.0 + """ + def __init__(self, processor, foreign_pre_chain=None, *args, **kwargs): + fmt = kwargs.pop("fmt", "%(message)s") + super(ProcessorFormatter, self).__init__(*args, fmt=fmt, **kwargs) + self.processor = processor + self.foreign_pre_chain = foreign_pre_chain + + def format(self, record): + """ + Extract ``structlog``'s `event_dict` from ``record.msg`` and format it. + """ + if isinstance(record.msg, dict): + # Both attached by wrap_for_formatter + logger = record._logger + meth_name = record._name + + # We need to copy because it's possible that the same record gets + # processed by multiple logging formatters. LogRecord.getMessage + # would transform our dict into a str. + ed = record.msg.copy() + else: + logger = None + meth_name = record.levelname.lower() + ed = {"event": record.getMessage()} + + # Non-structlog allows to run through a chain to prepare it for the + # final processor (e.g. adding timestamps and log levels). + for proc in self.foreign_pre_chain or (): + ed = proc(None, meth_name, ed) + + record.msg = self.processor(logger, meth_name, ed) + return super(ProcessorFormatter, self).format(record) + + @staticmethod + def wrap_for_formatter(logger, name, event_dict): + """ + Wrap *logger*, *name*, and *event_dict*. + + The result is later unpacked by :class:`ProcessorFormatter` when + formatting log entries. + + Use this static method as the renderer (i.e. final processor) if you + want to use :class:`ProcessorFormatter` in your :mod:`logging` + configuration. + """ + return (event_dict,), {"extra": {"_logger": logger, "_name": name}} diff --git a/tests/test_base.py b/tests/test_base.py index d51ff557..cde18cf0 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -119,7 +119,7 @@ def test_last_processor_returns_tuple(self): def test_last_processor_returns_dict(self): """ - If the final processor returns a dict, ``(), the_dict`` is returnend. + If the final processor returns a dict, ``(), the_dict`` is returned. """ logger = stub(msg=lambda *args, **kw: (args, kw)) b = build_bl(logger, processors=[lambda *_: {'event': 'foo'}]) @@ -145,6 +145,10 @@ def test_last_processor_returns_unknown_value(self): class TestProxying(object): def test_processor_raising_DropEvent_silently_aborts_chain(self, capsys): + """ + If a processor raises DropEvent, the chain is aborted and nothing is + proxied to the logger. + """ b = build_bl(processors=[raiser(DropEvent), raiser(ValueError)]) - b._proxy_to_logger('', None, x=5) - assert (('', '') == capsys.readouterr()) + b._proxy_to_logger("", None, x=5) + assert (("", "") == capsys.readouterr()) diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 7ed84015..2d901cce 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -7,23 +7,27 @@ import os import logging +import logging.config import pytest + from pretend import call_recorder -from structlog._loggers import ReturnLogger +from structlog import reset_defaults, configure, ReturnLogger, get_logger +from structlog.dev import ConsoleRenderer from structlog.exceptions import DropEvent from structlog.stdlib import ( BoundLogger, CRITICAL, LoggerFactory, PositionalArgumentsFormatter, + ProcessorFormatter, WARN, _FixedFindCallerLogger, add_log_level, add_logger_name, - render_to_log_kwargs, filter_by_level, + render_to_log_kwargs, ) from .additional_frame import additional_frame @@ -307,3 +311,117 @@ def test_add_extra_event_dict(self, event_dict): d = render_to_log_kwargs(None, None, event_dict) assert {"msg": "message", "extra": event_dict} == d + + +@pytest.fixture +def configure_for_pf(): + """ + Configure structlog to use ProcessorFormatter. + + Reset both structlog and logging setting after the test. + """ + configure( + processors=[ + add_log_level, + ProcessorFormatter.wrap_for_formatter, + ], + logger_factory=LoggerFactory(), + wrapper_class=BoundLogger, + ) + + yield + + logging.basicConfig() + reset_defaults() + + +def configure_logging(pre_chain): + """ + Configure logging to use ProcessorFormatter. + """ + return logging.config.dictConfig({ + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "plain": { + "()": ProcessorFormatter, + "processor": ConsoleRenderer(colors=False), + "foreign_pre_chain": pre_chain, + "format": "%(message)s [in %(funcName)s]" + } + }, + "handlers": { + "default": { + "level": "DEBUG", + "class": "logging.StreamHandler", + "formatter": "plain", + }, + }, + "loggers": { + "": { + "handlers": ["default"], + "level": "DEBUG", + "propagate": True, + }, + } + }) + + +class TestProcessorFormatter(object): + """ + These are all integration tests because they're all about integration. + """ + def test_foreign_delegate(self, configure_for_pf, capsys): + """ + If foreign_pre_chain is None, non-structlog log entries are delegated + to logging. + """ + configure_logging(None) + configure( + processors=[ + ProcessorFormatter.wrap_for_formatter, + ], + logger_factory=LoggerFactory(), + wrapper_class=BoundLogger, + ) + + logging.getLogger().warning("foo") + + assert ( + "", + "foo [in test_foreign_delegate]\n", + ) == capsys.readouterr() + + def test_foreign_pre_chain(self, configure_for_pf, capsys): + """ + If foreign_pre_chain is an iterable, it's used to pre-process + non-structlog log entries. + """ + configure_logging((add_log_level,)) + configure( + processors=[ + ProcessorFormatter.wrap_for_formatter, + ], + logger_factory=LoggerFactory(), + wrapper_class=BoundLogger, + ) + + logging.getLogger().warning("foo") + + assert ( + "", + "[warning ] foo [in test_foreign_pre_chain]\n", + ) == capsys.readouterr() + + def test_native(self, configure_for_pf, capsys): + """ + If the log entry comes from structlog, it's unpackaged and processed. + """ + configure_logging(None) + + get_logger().warning("foo") + + assert ( + "", + "[warning ] foo [in test_native]\n", + ) == capsys.readouterr() From 1d2d41c0c6c5059ffdf22f4b01e891fdeb6aab1d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 24 Apr 2017 12:55:07 +0200 Subject: [PATCH 0118/1520] 3.6 is the main thing now --- .travis.yml | 4 ++-- tox.ini | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4a39aee3..072276bf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,8 +30,8 @@ matrix: env: TOXENV=pypy-greenlets - python: "2.7" env: TOXENV=py27-colorama - - python: "3.5" - env: TOXENV=py35-colorama + - python: "3.6" + env: TOXENV=py36-colorama # Meta diff --git a/tox.ini b/tox.ini index 7394d90b..17d9ed94 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = {py27,py34,py35,py36,pypy}-{threads,greenlets},{py27,py35}-colorama,flake8,docs,readme,manifest,coverage-report +envlist = {py27,py34,py35,py36,pypy}-{threads,greenlets},{py27,py36}-colorama,flake8,docs,readme,manifest,coverage-report [testenv] @@ -8,7 +8,7 @@ deps = greenlets: greenlet twisted colorama: colorama - py34,py35: python-rapidjson + py36: python-rapidjson setenv = PYTHONHASHSEED = 0 commands = coverage run --parallel -m pytest {posargs} From 26ebc404272fd6efa90bf9a57f5bf0054ae0cc69 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 24 Apr 2017 12:55:17 +0200 Subject: [PATCH 0119/1520] Mention the new ProcessorFormatter in README --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index abf7dfae..f6a801f6 100644 --- a/README.rst +++ b/README.rst @@ -97,6 +97,7 @@ Output Easy to use and fast. - Use the **standard library**'s or **Twisted**'s logging modules for compatibility. In this case ``structlog`` works like a wrapper that formats a string and passes them off into existing systems that won't ever know that ``structlog`` even exists. + Or the other way round: ``structlog`` comes with a ``logging`` formatter that allows for processing third party log records. - Don't format it to a string at all! ``structlog`` passes you a dictionary and you can do with it whatever you want. Reported uses cases are sending them out via network or saving them in a database. From be0013596f205cbfda2bc302167c0d1f5e1c5554 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 24 Apr 2017 12:56:29 +0200 Subject: [PATCH 0120/1520] The FAQ is not worth it anymore --- docs/faq.rst | 62 -------------------------------------------------- docs/index.rst | 1 - 2 files changed, 63 deletions(-) delete mode 100644 docs/faq.rst diff --git a/docs/faq.rst b/docs/faq.rst deleted file mode 100644 index 246ccf1e..00000000 --- a/docs/faq.rst +++ /dev/null @@ -1,62 +0,0 @@ -Frequently Asked Questions -========================== - -.. testsetup:: * - - import structlog - structlog.configure( - processors=[structlog.processors.KeyValueRenderer()], - ) - -.. testcleanup:: * - - import structlog - structlog.reset_defaults() - -I try to bind key-value pairs but they don't appear in the log files? - ``structlog``\ 's loggers are *immutable*. - Meaning that you have to use the logger that is returned from ``bind()``: - - .. doctest:: - - >>> import structlog - >>> log = structlog.get_logger() - >>> log.bind(x=42) # doctest: +ELLIPSIS - ])> - >>> log.msg("hello") - event='hello' - >>> new_log = log.bind(x=42) - >>> new_log.msg("hello") - x=42 event='hello' - - -How can I make third party components log in JSON too? - Since Twisted's logging is nicely composable, ``structlog`` comes with `integration support `_ out of the box. - - The standard library is a bit more complicated and tough to solve universally. - But generally speaking, all you need is a handler that will redirect standard library logging into ``structlog``. - For example like this:: - - import logging - - class StructlogHandler(logging.Handler): - """ - Feeds all events back into structlog. - """ - def __init__(self, *args, **kw): - super(StructlogHandler, self).__init__(*args, **kw) - self._log = structlog.get_logger() - - def emit(self, record): - self._log.log(record.levelno, record.getMessage(), name=record.name) - - root_logger = logging.getLogger() - root_logger.addHandler(StructlogHandler()) - - There are two things to keep in mind: - - #. You can't log out using the standard library since that would create an infinite loop. - In other words you have to use for example ``PrintLogger`` for actual output (which is nothing wrong with). - #. You can't affect the logging of your parent process. - So for example if you're running a web application as `Gunicorn `_ workers, you have to configure Gunicorn's logging separately if you want it to write JSON logs. - In these cases a library like `python-json-logger `_ should come in handy. diff --git a/docs/index.rst b/docs/index.rst index a87a03ba..ee4eefa7 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -27,7 +27,6 @@ Basics processors examples development - faq Integration with Existing Systems From 160cb5cf48819ffd6b12a1c3459bc7bdf2234d5f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 24 Apr 2017 13:08:02 +0200 Subject: [PATCH 0121/1520] Wordsmith changelog --- CHANGELOG.rst | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index de3caade..54ffb512 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,14 +8,15 @@ The third digit is only for regressions. 17.1.0 (UNRELEASED) ------------------- -The main features of this release are multiple improvements in standard library's ``logging`` integration. +The main features of this release are massive improvements in standard library's ``logging`` integration. Have a look at the updated `standard library chapter `_ on how to use them! +Special thanks go to `Iva Kaneva `_, `sky-code `_, `insolite `_, and `Gilbert Gilb's `_ that made them possible. Backward-incompatible changes: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- The default renderer is ``structlog.dev.ConsoleRenderer`` now if you don't configure ``structlog``. +- The default renderer is ``structlog.dev.ConsoleRenderer`` if you don't configure ``structlog`` now. Colors are used if available and human-friendly timestamps are prepended. This is in line with our backward `compatibility policy `_ that explicitly excludes default settings. @@ -29,15 +30,16 @@ Changes: - Added ``structlog.stdlib.ProcessorFormatter`` which does the opposite: This allows you to run ``structlog`` processors on arbitrary ``logging.LogRecords``. `#79 `_ + `#105 `_ - UNIX epoch timestamps from ``structlog.processors.TimeStamper`` are more precise now. -- Add *repr_native_str* to ``structlog.processors.KeyValueRenderer`` and ``structlog.dev.ConsoleRenderer``. +- Added *repr_native_str* to ``structlog.processors.KeyValueRenderer`` and ``structlog.dev.ConsoleRenderer``. This allows for human-readable non-ASCII output on Python 2 (``repr()`` on Python 2 haves like ``ascii()`` on Python 3 in that regard). As per compatibility policy, it's on (original behavior) in ``KeyValueRenderer`` and off (humand-friendly behavior) in ``ConsoleRenderer``. `#94 `_ -- Add *colors* argument to ``structlog.dev.ConsoleRenderer`` and make it the default renderer. +- Added *colors* argument to ``structlog.dev.ConsoleRenderer`` and made it the default renderer. `#78 `_ -- Fix bug with Python 3 and ``structlog.stdlib.BoundLogger.log()``. Error log level was not reproductible and was logged as exception - one time out of two. +- Fixed bug with Python 3 and ``structlog.stdlib.BoundLogger.log()``. + Error log level was not reproductible and was logged as exception one time out of two. `#92 `_ From e51318d3d36f8890c4d580d2c033ce9acd2a16d8 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 24 Apr 2017 13:11:14 +0200 Subject: [PATCH 0122/1520] There is and was no 16.2 --- CONTRIBUTING.rst | 2 +- src/structlog/__init__.py | 2 +- src/structlog/dev.py | 2 +- src/structlog/processors.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index a04388aa..5d65563e 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -38,7 +38,7 @@ Code :rtype: str """ -- If you add or change public APIs, tag the docstring using ``.. versionadded:: 16.0.0 WHAT`` or ``.. versionchanged:: 16.2.0 WHAT``. +- If you add or change public APIs, tag the docstring using ``.. versionadded:: 16.0.0 WHAT`` or ``.. versionchanged:: 17.1.0 WHAT``. - Prefer double quotes (``"``) over single quotes (``'``) unless the string contains double quotes itself. diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 4db89a30..ccb19827 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -45,7 +45,7 @@ twisted = None -__version__ = "16.2.0.dev0" +__version__ = "17.1.0.dev0" __title__ = "structlog" __description__ = "Structured Logging for Python" diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 0bd48519..1c2fd103 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -111,7 +111,7 @@ class ConsoleRenderer(object): .. versionadded:: 16.0 .. versionadded:: 16.1 *colors* - .. versionadded:: 16.2 *repr_native_str* + .. versionadded:: 17.1 *repr_native_str* """ def __init__(self, pad_event=_EVENT_WIDTH, colors=True, repr_native_str=False): diff --git a/src/structlog/processors.py b/src/structlog/processors.py index def39637..7cee40bb 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -40,7 +40,7 @@ class KeyValueRenderer(object): .. versionadded:: 0.2.0 *key_order* .. versionadded:: 16.1.0 *drop_missing* - .. versionadded:: 16.2.0 *repr_native_str* + .. versionadded:: 17.1.0 *repr_native_str* """ def __init__(self, sort_keys=False, key_order=None, drop_missing=False, repr_native_str=True): From 774a18a50e8e74ff5d77c5e4a0a49d6c12cfe507 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 24 Apr 2017 13:14:08 +0200 Subject: [PATCH 0123/1520] Fix links --- CONTRIBUTING.rst | 4 ++-- docs/standard-library.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 5d65563e..f328ef2c 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -112,8 +112,8 @@ Thank you for considering contributing to ``structlog``! .. _`Code of Conduct`: https://github.com/hynek/structlog/blob/master/CODE_OF_CONDUCT.rst .. _changelog: https://github.com/hynek/structlog/blob/master/CHANGELOG.rst .. _`backward compatibility`: https://structlog.readthedocs.io/en/latest/backward-compatibility.html -.. _`tox`: https://testrun.org/tox/ -.. _pyenv: https://github.com/yyuu/pyenv +.. _tox: https://tox.readthedocs.io/ +.. _pyenv: https://github.com/pyenv/pyenv .. _reStructuredText: http://sphinx-doc.org/rest.html .. _semantic newlines: http://rhodesmill.org/brandon/2012/one-sentence-per-line/ .. _CI: https://travis-ci.org/hynek/structlog/ diff --git a/docs/standard-library.rst b/docs/standard-library.rst index 7925c731..3bfe3653 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -245,4 +245,4 @@ In this case *only* your own logs are formatted as JSON: >>> logging.getLogger("test").warning("hello") hello -.. _`12 factor app`: http://12factor.net/logs +.. _`12 factor app`: https://12factor.net/logs From 15850b735209d3fb9bf0f2b61c71dd57e5fd73a4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 24 Apr 2017 13:23:16 +0200 Subject: [PATCH 0124/1520] Bring CONTRIBUTING.rst up to date --- CONTRIBUTING.rst | 55 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index f328ef2c..2739cda7 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -4,7 +4,8 @@ How To Contribute First off, thank you for considering contributing to ``structlog``! It's people like *you* who make it is such a great tool for everyone. -Here are a few guidelines to get you started (but don't be afraid to open half-finished PRs and ask questions if something is unclear!): +This document is mainly to help you to get started by codifying tribal knowledge and expectations and make it more accessible to everyone. +But don't be afraid to open half-finished PRs and ask questions if something is unclear! Workflow @@ -32,7 +33,7 @@ Code def func(x): """ - Does something. + Do something. :param str x: A very important parameter. @@ -70,29 +71,71 @@ Documentation This is a sentence. This is another sentence. -- If you start a new section, add two blank lines before and one blank line after the header: +- If you start a new section, add two blank lines before and one blank line after the header except if two headers follow immediately after each other: .. code-block:: rst Last line of previous section. + Header of New Top Section + ------------------------- + Header of New Section ^^^^^^^^^^^^^^^^^^^^^ First line of new section. - If your change is noteworthy, add an entry to the changelog_. - Use present tense, `semantic newlines`_, and add a link to your pull request: + Use `semantic newlines`_, and add a link to your pull request: .. code-block:: rst - - Add awesome new feature. + - Added ``structlog.func()``. The feature really *is* awesome. [`#1 `_] - - Fix nasty bug. + - ``structlog.func()`` now doesn't crash the Large Hadron Collider anymore. The bug really *was* nasty. [`#2 `_] + +Local Development Environment +----------------------------- + +You can (and should) run our test suite using tox_ however you’ll probably want a more traditional environment too. +We highly recommend to develop using the latest Python 3 release because you're more likely to catch certain bugs earlier. + +First create a `virtual environment `_. +It’s out of scope for this document to list all the ways to manage virtual environments in Python but if you don’t have already a pet way, take some time to look at tools like `pew `_, `virtualfish `_, and `virtualenvwrapper `_. + +Next get an up to date checkout of the ``structlog`` repository: + +.. code-block:: bash + + git checkout git@github.com:hynek/structlog.git + +Change into the newly created directory and **after activating your virtual environment** install an editable version of ``structlog``: + +.. code-block:: bash + + cd structlog + pip install -e . + +If you run the virtual environment’s Python and try to ``import structlog`` it should work! + +To run the test suite, you'll need our development dependencies which can be installed using + +.. code-block:: bash + + pip install -r dev-requirements.txt + +At this point + +.. code-block:: bash + + python -m pytest + +should work and pass! + **** Again, this list is mainly to help you to get started by codifying tribal knowledge and expectations. From 50a04af4ab4323753f6768371e2709beddd3fe6a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 24 Apr 2017 13:27:46 +0200 Subject: [PATCH 0125/1520] Some more docs polish --- CHANGELOG.rst | 2 +- CONTRIBUTING.rst | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 54ffb512..00354c6c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -16,7 +16,7 @@ Special thanks go to `Iva Kaneva `_, `sky-code `_ that explicitly excludes default settings. diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 2739cda7..096dd23c 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -90,11 +90,11 @@ Documentation .. code-block:: rst - - Added ``structlog.func()``. - The feature really *is* awesome. + - Added ``structlog.func()`` that does foo. + It's pretty cool. [`#1 `_] - ``structlog.func()`` now doesn't crash the Large Hadron Collider anymore. - The bug really *was* nasty. + That was a nasty bug! [`#2 `_] From e4731ba2fb250e7aa386dc293797446dbd58d862 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 24 Apr 2017 13:38:38 +0200 Subject: [PATCH 0126/1520] Remove positional args even if they are falsey Fixes #82 --- CHANGELOG.rst | 2 ++ src/structlog/stdlib.py | 8 ++++---- tests/test_stdlib.py | 11 +++++++++++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 00354c6c..110511ba 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -41,6 +41,8 @@ Changes: - Fixed bug with Python 3 and ``structlog.stdlib.BoundLogger.log()``. Error log level was not reproductible and was logged as exception one time out of two. `#92 `_ +- Positional arguments are now removed even if they are empty. + `#82 `_ ---- diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 3dec78dd..88c57354 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -263,7 +263,7 @@ def __init__(self, remove_positional_args=True): self.remove_positional_args = remove_positional_args def __call__(self, _, __, event_dict): - args = event_dict.get('positional_args') + args = event_dict.get("positional_args") # Mimick the formatting behaviour of the stdlib's logging # module, which accepts both positional arguments and a single @@ -272,9 +272,9 @@ def __call__(self, _, __, event_dict): if args: if len(args) == 1 and isinstance(args[0], dict) and args[0]: args = args[0] - event_dict['event'] = event_dict['event'] % args - if self.remove_positional_args: - del event_dict['positional_args'] + event_dict["event"] = event_dict["event"] % args + if self.remove_positional_args and args is not None: + del event_dict["positional_args"] return event_dict diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 2d901cce..15aca38e 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -266,6 +266,17 @@ def test_nop_no_args(self): formatter = PositionalArgumentsFormatter() assert {} == formatter(None, None, {}) + def test_args_removed_if_empty(self): + """ + If remove_positional_args is True and positional_args is (), still + remove them. + + Regression test for https://github.com/hynek/structlog/issues/82. + """ + formatter = PositionalArgumentsFormatter() + + assert {} == formatter(None, None, {"positional_args": ()}) + class TestAddLogLevel(object): def test_log_level_added(self): From 6234089e1d35e507091bebe2e26f760de85a61f6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 24 Apr 2017 13:46:08 +0200 Subject: [PATCH 0127/1520] Add original author of the ProcessorFormatter And sort them alphabetically using :sort so we don't play any favors. :) --- CHANGELOG.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 110511ba..183d322b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -10,7 +10,13 @@ The third digit is only for regressions. The main features of this release are massive improvements in standard library's ``logging`` integration. Have a look at the updated `standard library chapter `_ on how to use them! -Special thanks go to `Iva Kaneva `_, `sky-code `_, `insolite `_, and `Gilbert Gilb's `_ that made them possible. +Special thanks go to +`Fabian Büchler `_, +`Gilbert Gilb's `_, +`Iva Kaneva `_, +`insolite `_, +and `sky-code `_, +that made them possible. Backward-incompatible changes: From a787b72db065170a42627cb255062b2038c8023f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 24 Apr 2017 13:51:44 +0200 Subject: [PATCH 0128/1520] Prepare 17.1.0 --- CHANGELOG.rst | 2 +- src/structlog/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 183d322b..a4cd0c23 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,7 +5,7 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. -17.1.0 (UNRELEASED) +17.1.0 (2017-04-24) ------------------- The main features of this release are massive improvements in standard library's ``logging`` integration. diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index ccb19827..ca0369cb 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -45,7 +45,7 @@ twisted = None -__version__ = "17.1.0.dev0" +__version__ = "17.1.0" __title__ = "structlog" __description__ = "Structured Logging for Python" From 16039727d6f37c8455fea774bb1d330d9222a948 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 24 Apr 2017 13:59:15 +0200 Subject: [PATCH 0129/1520] Start new release cycle --- CHANGELOG.rst | 25 +++++++++++++++++++++++++ src/structlog/__init__.py | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a4cd0c23..c36d4f25 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,31 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. +17.2.0 (UNRELEASED) +------------------- + + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +*none* + + +Deprecations: +^^^^^^^^^^^^^ + +*none* + + +Changes: +^^^^^^^^ + +*none* + + +---- + + 17.1.0 (2017-04-24) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index ca0369cb..27c2a393 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -45,7 +45,7 @@ twisted = None -__version__ = "17.1.0" +__version__ = "17.2.0.dev0" __title__ = "structlog" __description__ = "Structured Logging for Python" From 91bbdf552ae8c5ca257b3252006340510e8e0351 Mon Sep 17 00:00:00 2001 From: Eli Boyarski Date: Mon, 24 Apr 2017 15:42:07 +0300 Subject: [PATCH 0130/1520] Typo fix (#106) --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c36d4f25..51e3966a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -64,7 +64,7 @@ Changes: `#105 `_ - UNIX epoch timestamps from ``structlog.processors.TimeStamper`` are more precise now. - Added *repr_native_str* to ``structlog.processors.KeyValueRenderer`` and ``structlog.dev.ConsoleRenderer``. - This allows for human-readable non-ASCII output on Python 2 (``repr()`` on Python 2 haves like ``ascii()`` on Python 3 in that regard). + This allows for human-readable non-ASCII output on Python 2 (``repr()`` on Python 2 behaves like ``ascii()`` on Python 3 in that regard). As per compatibility policy, it's on (original behavior) in ``KeyValueRenderer`` and off (humand-friendly behavior) in ``ConsoleRenderer``. `#94 `_ - Added *colors* argument to ``structlog.dev.ConsoleRenderer`` and made it the default renderer. From 29631c36fba93825b456c296cedd7a86c382558c Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Wed, 26 Apr 2017 14:10:58 +0200 Subject: [PATCH 0131/1520] Add logo --- docs/_static/structlog_logo.png | Bin 0 -> 98810 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/_static/structlog_logo.png diff --git a/docs/_static/structlog_logo.png b/docs/_static/structlog_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..c3165fb63d4928ca628c87ebba6f7b8960c32ecb GIT binary patch literal 98810 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

  • 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 Date: Wed, 26 Apr 2017 14:20:43 +0200 Subject: [PATCH 0132/1520] Use the new logo --- AUTHORS.rst | 2 ++ README.rst | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/AUTHORS.rst b/AUTHORS.rst index 06cee70c..a9b577b7 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -8,3 +8,5 @@ The development is kindly supported by `Variomedia AG `_. Some of them disapprove of the addition of thread local context data. :) + +The ``structlog`` logo has been contributed by `Russell Keith-Magee `_. diff --git a/README.rst b/README.rst index f6a801f6..38b3f2ae 100644 --- a/README.rst +++ b/README.rst @@ -1,3 +1,8 @@ +.. image:: https://www.structlog.org/en/latest/_static/structlog_logo.png + :alt: structlog Logo + :width: 256px + :target: http://www.structlog.org/ + ======================================== structlog: Structured Logging for Python ======================================== From c0e4dbebe962feaa4ee5db69d43a6cba7cd7879c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 26 Apr 2017 14:28:17 +0200 Subject: [PATCH 0133/1520] Fix url --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 38b3f2ae..b3aac2e0 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -.. image:: https://www.structlog.org/en/latest/_static/structlog_logo.png +.. image:: http://www.structlog.org/en/latest/_static/structlog_logo.png :alt: structlog Logo :width: 256px :target: http://www.structlog.org/ From be3f12b699ecbc80e1236f4d9d77dfe5fc9ecde6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 26 Apr 2017 14:30:13 +0200 Subject: [PATCH 0134/1520] Use smaller log in README GitHub seems to ignore width. --- README.rst | 2 +- docs/_static/structlog_logo_small.png | Bin 0 -> 49112 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 docs/_static/structlog_logo_small.png diff --git a/README.rst b/README.rst index b3aac2e0..90a1f781 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -.. image:: http://www.structlog.org/en/latest/_static/structlog_logo.png +.. image:: http://www.structlog.org/en/latest/_static/structlog_logo_small.png :alt: structlog Logo :width: 256px :target: http://www.structlog.org/ diff --git a/docs/_static/structlog_logo_small.png b/docs/_static/structlog_logo_small.png new file mode 100644 index 0000000000000000000000000000000000000000..381dd90799568905d4f753c80d646a44a4df0cb2 GIT binary patch literal 49112 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%0D-KNI3edsf#Ro2U>;a>ag4(! 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 Z{{i4ITC)pm+3f%T002ovPDHLkV1nESQ#}9x literal 0 HcmV?d00001 From 5636314046792f1cc2510af27a379746bfe9dbf2 Mon Sep 17 00:00:00 2001 From: Arnaud Limbourg Date: Fri, 28 Apr 2017 10:31:12 +0200 Subject: [PATCH 0135/1520] Fix tiny typo (#108) --- docs/performance.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/performance.rst b/docs/performance.rst index e3f4ddca..4cb218b7 100644 --- a/docs/performance.rst +++ b/docs/performance.rst @@ -11,7 +11,7 @@ Here are a few hints how to get most out of ``structlog`` in production: configure(context_class=dict) - If you don't use automated parsing (you should!) and need predicable order of your keys for some reason, use the `key_order` argument of :class:`~structlog.processors.KeyValueRenderer`. + If you don't use automated parsing (you should!) and need predictable order of your keys for some reason, use the `key_order` argument of :class:`~structlog.processors.KeyValueRenderer`. #. Use a specific wrapper class instead of the generic one. ``structlog`` comes with ones for the :doc:`standard-library` and for :doc:`twisted`:: From ff7cf4ce1ea725a66e93d7d5d51ed5155fc20c52 Mon Sep 17 00:00:00 2001 From: Gilbert Gilb's Date: Sat, 13 May 2017 08:33:01 +0200 Subject: [PATCH 0136/1520] Fix add_logger_name processor not working in foreign_prechain. (#112) --- CHANGELOG.rst | 3 ++- src/structlog/stdlib.py | 10 +++++++-- tests/test_stdlib.py | 50 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 51e3966a..0a956468 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,7 +24,8 @@ Deprecations: Changes: ^^^^^^^^ -*none* +- ``structlog.stdlib.add_logger_name()`` now works in ``structlog.stdlib.ProcessorFormatter``'s ``foreign_pre_chain``. + `#112 `_ ---- diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 88c57354..4529e841 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -346,7 +346,11 @@ def add_logger_name(logger, method_name, event_dict): """ Add the logger name to the event dict. """ - event_dict['logger'] = logger.name + record = event_dict.get("_record") + if record is None: + event_dict["logger"] = logger.name + else: + event_dict["logger"] = record.name return event_dict @@ -415,13 +419,15 @@ def format(self, record): else: logger = None meth_name = record.levelname.lower() - ed = {"event": record.getMessage()} + ed = {"event": record.getMessage(), "_record": record} # Non-structlog allows to run through a chain to prepare it for the # final processor (e.g. adding timestamps and log levels). for proc in self.foreign_pre_chain or (): ed = proc(None, meth_name, ed) + del ed["_record"] + record.msg = self.processor(logger, meth_name, ed) return super(ProcessorFormatter, self).format(record) diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 15aca38e..423760ef 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -294,6 +294,26 @@ def test_log_level_alias_normalized(self): assert 'warning' == event_dict['level'] +@pytest.fixture +def log_record(): + """ + A LogRecord factory. + """ + def create_log_record(**kwargs): + defaults = { + "name": "sample-name", + "level": logging.INFO, + "pathname": None, + "lineno": None, + "msg": "sample-message", + "args": [], + "exc_info": None, + } + defaults.update(kwargs) + return logging.LogRecord(**defaults) + return create_log_record + + class TestAddLoggerName(object): def test_logger_name_added(self): """ @@ -304,6 +324,15 @@ def test_logger_name_added(self): event_dict = add_logger_name(logger, None, {}) assert name == event_dict["logger"] + def test_logger_name_added_with_record(self, log_record): + """ + The logger name is deduced from the LogRecord if provided. + """ + name = "sample-name" + record = log_record(name=name) + event_dict = add_logger_name(None, None, {"_record": record}) + assert name == event_dict["logger"] + class TestRenderToLogKW(object): def test_default(self): @@ -424,6 +453,27 @@ def test_foreign_pre_chain(self, configure_for_pf, capsys): "[warning ] foo [in test_foreign_pre_chain]\n", ) == capsys.readouterr() + def test_foreign_pre_chain_add_logger_name(self, configure_for_pf, capsys): + """ + foreign_pre_chain works with add_logger_name processor. + """ + configure_logging((add_logger_name,)) + configure( + processors=[ + ProcessorFormatter.wrap_for_formatter, + ], + logger_factory=LoggerFactory(), + wrapper_class=BoundLogger, + ) + + logging.getLogger("sample-name").warning("foo") + + assert ( + "", + "foo [sample-name] [in test_foreign_pr" + "e_chain_add_logger_name]\n", + ) == capsys.readouterr() + def test_native(self, configure_for_pf, capsys): """ If the log entry comes from structlog, it's unpackaged and processed. From 117ad7c47a8c93ab81f84c91364792a47ad88b60 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 15 May 2017 10:21:20 +0200 Subject: [PATCH 0137/1520] Clear args on LogRecords after rendering them in ProcessorFormatter (#117) --- CHANGELOG.rst | 4 ++++ src/structlog/stdlib.py | 1 + tests/test_stdlib.py | 16 ++++++++++++++++ 3 files changed, 21 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0a956468..b9dbfab1 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -26,6 +26,10 @@ Changes: - ``structlog.stdlib.add_logger_name()`` now works in ``structlog.stdlib.ProcessorFormatter``'s ``foreign_pre_chain``. `#112 `_ +- Clear log record args in ``structlog.stdlib.ProcessorFormatter`` after rendering. + This fix is for you if you tried to use it and got ``TypeError: not all arguments converted during string formatting`` exceptions. + `#116 `_ + `#117 `_ ---- diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 4529e841..fb7ad046 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -420,6 +420,7 @@ def format(self, record): logger = None meth_name = record.levelname.lower() ed = {"event": record.getMessage(), "_record": record} + record.args = () # Non-structlog allows to run through a chain to prepare it for the # final processor (e.g. adding timestamps and log levels). diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 423760ef..548ccfa7 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -432,6 +432,22 @@ def test_foreign_delegate(self, configure_for_pf, capsys): "foo [in test_foreign_delegate]\n", ) == capsys.readouterr() + def test_clears_args(self, capsys, configure_for_pf): + """ + We render our log records before sending it back to logging. Therefore + we must clear `LogRecord.args` otherwise the user gets an + `TypeError: not all arguments converted during string formatting.` if + they use positional formatting in stdlib logging. + """ + configure_logging(None) + + logging.getLogger().warning("hello %s.", "world") + + assert ( + "", + "hello world. [in test_clears_args]\n", + ) == capsys.readouterr() + def test_foreign_pre_chain(self, configure_for_pf, capsys): """ If foreign_pre_chain is an iterable, it's used to pre-process From 32a1ad248ff36d5fbca02bb1aa9f4925fd679b01 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 15 May 2017 17:31:45 +0200 Subject: [PATCH 0138/1520] Fix exc_info and race condition in ProcessorFormatter (#118) --- CHANGELOG.rst | 3 ++ src/structlog/stdlib.py | 31 ++++++++++- tests/test_stdlib.py | 113 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b9dbfab1..bf6e162a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,6 +24,9 @@ Deprecations: Changes: ^^^^^^^^ +- ``structlog.stdlib.ProcessorFormatter`` now accepts *keep_exc_info* and *keep_stack_info* arguments to control what to do with this information on log records. + Most likely you want them both to be ``False`` therefore it's the default. + `#109 `_ - ``structlog.stdlib.add_logger_name()`` now works in ``structlog.stdlib.ProcessorFormatter``'s ``foreign_pre_chain``. `#112 `_ - Clear log record args in ``structlog.stdlib.ProcessorFormatter`` after rendering. diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index fb7ad046..38f2c235 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -373,7 +373,7 @@ def render_to_log_kwargs(wrapped_logger, method_name, event_dict): class ProcessorFormatter(logging.Formatter): """ - Call ``structlog`` processors on :mod:`logging.LogRecord`\ s. + Call ``structlog`` processors on :class:`logging.LogRecord`\ s. This :class:`logging.Formatter` allows to configure :mod:`logging` to call *processor* on ``structlog``-borne log entries (origin is determined solely @@ -392,21 +392,34 @@ class ProcessorFormatter(logging.Formatter): If not `None`, it is used as an iterable of processors that is applied to non-``structlog`` log entries before *processor*. If `None`, formatting is left to :mod:`logging`. (default: `None`) + :param bool keep_exc_info: ``exc_info`` on :class:`logging.LogRecord`\ s is + added to the ``event_dict`` and removed afterwards. Set this to + ``True`` to keep it on the :class:`logging.LogRecord`. (default: False) + :param bool keep_stack_info: Same as *keep_exc_info* except for Python 3's + ``stack_info``. :rtype: str .. versionadded:: 17.1.0 + .. versionadded:: 17.2.0 *keep_exc_info* and *keep_stack_info* """ - def __init__(self, processor, foreign_pre_chain=None, *args, **kwargs): + def __init__(self, processor, foreign_pre_chain=None, + keep_exc_info=False, keep_stack_info=False, *args, **kwargs): fmt = kwargs.pop("fmt", "%(message)s") super(ProcessorFormatter, self).__init__(*args, fmt=fmt, **kwargs) self.processor = processor self.foreign_pre_chain = foreign_pre_chain + self.keep_exc_info = keep_exc_info + # The and clause saves us checking for PY3 in the formatter. + self.keep_stack_info = keep_stack_info and PY3 def format(self, record): """ Extract ``structlog``'s `event_dict` from ``record.msg`` and format it. """ + # Make a shallow copy of the record to let other handlers/formatters + # process the original one + record = logging.makeLogRecord(record.__dict__) if isinstance(record.msg, dict): # Both attached by wrap_for_formatter logger = record._logger @@ -422,6 +435,20 @@ def format(self, record): ed = {"event": record.getMessage(), "_record": record} record.args = () + # Add stack-related attributes to event_dict and unset them + # on the record copy so that the base implementation wouldn't + # append stacktraces to the output. + if record.exc_info: + ed["exc_info"] = record.exc_info + if PY3 and record.stack_info: + ed["stack_info"] = record.stack_info + + if not self.keep_exc_info: + record.exc_text = None + record.exc_info = None + if not self.keep_stack_info: + record.stack_info = None + # Non-structlog allows to run through a chain to prepare it for the # final processor (e.g. adding timestamps and log levels). for proc in self.foreign_pre_chain or (): diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 548ccfa7..ae33ba9f 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -7,6 +7,7 @@ import os import logging +import collections import logging.config import pytest @@ -15,6 +16,7 @@ from structlog import reset_defaults, configure, ReturnLogger, get_logger from structlog.dev import ConsoleRenderer +from structlog.processors import JSONRenderer from structlog.exceptions import DropEvent from structlog.stdlib import ( BoundLogger, @@ -490,6 +492,117 @@ def test_foreign_pre_chain_add_logger_name(self, configure_for_pf, capsys): "e_chain_add_logger_name]\n", ) == capsys.readouterr() + def test_foreign_pre_chain_gets_exc_info(self, configure_for_pf, capsys): + """ + If non-structlog record contains exc_info, foreign_pre_chain functions + have access to it. + """ + test_processor = call_recorder(lambda l, m, event_dict: event_dict) + configure_logging((test_processor,)) + configure( + processors=[ + ProcessorFormatter.wrap_for_formatter, + ], + logger_factory=LoggerFactory(), + wrapper_class=BoundLogger, + ) + + try: + raise RuntimeError("oh noo") + except Exception: + logging.getLogger().exception("okay") + + event_dict = test_processor.calls[0].args[2] + assert "exc_info" in event_dict + assert isinstance(event_dict["exc_info"], tuple) + + def test_other_handlers_get_original_record(self, configure_for_pf, + capsys): + """ + Logging handlers that come after the handler with ProcessorFormatter + should receive original, unmodified record. + """ + configure_logging(None) + + handler1 = logging.StreamHandler() + handler1.setFormatter(ProcessorFormatter(JSONRenderer())) + handler2 = type("", (), {})() + handler2.handle = call_recorder(lambda record: None) + handler2.level = logging.INFO + logger = logging.getLogger() + logger.addHandler(handler1) + logger.addHandler(handler2) + + logger.info("meh") + + assert 1 == len(handler2.handle.calls) + handler2_record = handler2.handle.calls[0].args[0] + assert "meh" == handler2_record.msg + + @pytest.mark.parametrize("keep", [True, False]) + def test_formatter_unsets_exc_info(self, configure_for_pf, capsys, keep): + """ + Stack traces doesn't get printed outside of the json document when + keep_exc_info are set to False but preserved if set to True. + """ + configure_logging(None) + logger = logging.getLogger() + + def format_exc_info_fake(logger, name, event_dict): + event_dict = collections.OrderedDict(event_dict) + del event_dict["exc_info"] + event_dict["exception"] = "Exception!" + return event_dict + + formatter = ProcessorFormatter( + processor=JSONRenderer(), + keep_stack_info=keep, + keep_exc_info=keep, + foreign_pre_chain=[format_exc_info_fake], + ) + logger.handlers[0].setFormatter(formatter) + + try: + raise RuntimeError("oh noo") + except Exception: + logging.getLogger().exception("seen worse") + + out, err = capsys.readouterr() + assert "" == out + if keep is False: + assert ( + '{"event": "seen worse", "exception": "Exception!"}\n' + ) == err + else: + assert "Traceback (most recent call last):" in err + + @pytest.mark.parametrize("keep", [True, False]) + @py3_only + def test_formatter_unsets_stack_info(self, configure_for_pf, capsys, keep): + """ + Stack traces doesn't get printed outside of the json document when + keep_stack_info are set to False but preserved if set to True. + """ + configure_logging(None) + logger = logging.getLogger() + + formatter = ProcessorFormatter( + processor=JSONRenderer(), + keep_stack_info=keep, + keep_exc_info=keep, + foreign_pre_chain=[], + ) + logger.handlers[0].setFormatter(formatter) + + logging.getLogger().warn("have a stack trace", stack_info=True) + + out, err = capsys.readouterr() + assert "" == out + if keep is False: + assert 1 == err.count("Stack (most recent call last):") + else: + assert 2 == err.count("Stack (most recent call last):") + def test_native(self, configure_for_pf, capsys): """ If the log entry comes from structlog, it's unpackaged and processed. From db2e573ff3018ad08b1f18e56d27de59f00f9e3a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 15 May 2017 17:34:28 +0200 Subject: [PATCH 0139/1520] Prepare 17.2.0 --- CHANGELOG.rst | 2 +- src/structlog/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index bf6e162a..4d67b506 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,7 +5,7 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. -17.2.0 (UNRELEASED) +17.2.0 (2017-05-15) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 27c2a393..42b6bdc4 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -45,7 +45,7 @@ twisted = None -__version__ = "17.2.0.dev0" +__version__ = "17.2.0" __title__ = "structlog" __description__ = "Structured Logging for Python" From 86e116c8ef40cad65fde3c8526b60131b11ba9b9 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 15 May 2017 17:51:56 +0200 Subject: [PATCH 0140/1520] Start new release cycle --- CHANGELOG.rst | 25 +++++++++++++++++++++++++ src/structlog/__init__.py | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4d67b506..09ecb8d0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,31 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. +17.3.0 (UNRELEASED) +------------------- + + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +*none* + + +Deprecations: +^^^^^^^^^^^^^ + +*none* + + +Changes: +^^^^^^^^ + +*none* + + +---- + + 17.2.0 (2017-05-15) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 42b6bdc4..443d6668 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -45,7 +45,7 @@ twisted = None -__version__ = "17.2.0" +__version__ = "17.3.0.dev0" __title__ = "structlog" __description__ = "Structured Logging for Python" From c9fb1e3d0d9ff02a8f9a93509abefa8321b0ee5f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 26 May 2017 17:10:01 -0700 Subject: [PATCH 0141/1520] Pin sphinx Some really weird error is popping up --- docs-requirements.txt | 2 +- tox.ini | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/docs-requirements.txt b/docs-requirements.txt index ddd60f88..4f2d2a4e 100644 --- a/docs-requirements.txt +++ b/docs-requirements.txt @@ -1,4 +1,4 @@ -e . -sphinx +sphinx<1.6 sphinx_rtd_theme twisted diff --git a/tox.ini b/tox.ini index 17d9ed94..d3aefa72 100644 --- a/tox.ini +++ b/tox.ini @@ -25,9 +25,7 @@ commands = flake8 src tests setup.py docs/conf.py basepython = python3.6 setenv = PYTHONHASHSEED = 0 -deps = - sphinx - twisted +deps = -rdocs-requirements.txt commands = sphinx-build -W -b html -d {envtmpdir}/doctrees docs docs/_build/html sphinx-build -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html From 783ffb951eb8378f1cce90f482a1b5f0d42d7fe2 Mon Sep 17 00:00:00 2001 From: Dima Kurguzov Date: Sat, 27 May 2017 03:23:17 +0300 Subject: [PATCH 0142/1520] Fix typo (#122) --- docs/code_examples/flask_/some_module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/code_examples/flask_/some_module.py b/docs/code_examples/flask_/some_module.py index 6605a728..fa226c6a 100644 --- a/docs/code_examples/flask_/some_module.py +++ b/docs/code_examples/flask_/some_module.py @@ -7,5 +7,5 @@ def some_function(): # later then: logger.error('user did something', something='shot_in_foot') # gives you: - # event='user did something 'request_id='ffcdc44f-b952-4b5f-95e6-0f1f3a9ee5fd' something='shot_in_foot' + # event='user did something' request_id='ffcdc44f-b952-4b5f-95e6-0f1f3a9ee5fd' something='shot_in_foot' From 1944bcafa584b78c8e06f4509895bd2d5b8906db Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 22 Jun 2017 12:28:53 +0200 Subject: [PATCH 0143/1520] Check for explicit None Ref #110 --- CHANGELOG.rst | 3 ++- src/structlog/_base.py | 4 ++-- tests/test_base.py | 15 +++++++++++++-- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 09ecb8d0..ed8bda10 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,7 +24,8 @@ Deprecations: Changes: ^^^^^^^^ -*none* +- Empty strings are valid events now. + `#110 `_ ---- diff --git a/src/structlog/_base.py b/src/structlog/_base.py index 084f0487..68e1e5ff 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -130,8 +130,8 @@ def _process_event(self, method_name, event, event_kw): """ event_dict = self._context.copy() event_dict.update(**event_kw) - if event: - event_dict['event'] = event + if event is not None: + event_dict["event"] = event for proc in self._processors: event_dict = proc(self._logger, method_name, event_dict) if isinstance(event_dict, string_types): diff --git a/tests/test_base.py b/tests/test_base.py index cde18cf0..156204e7 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -20,8 +20,8 @@ def build_bl(logger=None, processors=None, context=None): Convenience function to build BoundLoggerBases with sane defaults. """ return BoundLoggerBase( - logger or ReturnLogger(), - processors or _CONFIG.default_processors, + logger if logger is not None else ReturnLogger(), + processors if processors is not None else _CONFIG.default_processors, context if context is not None else _CONFIG.default_context_class(), ) @@ -75,6 +75,17 @@ def test_unbind(self): class TestProcessing(object): + def test_event_empty_string(self): + """ + Empty strings are a valid event. + """ + b = build_bl(processors=[], context={}) + + args, kw = b._process_event("meth", "", {"foo": "bar"}) + + assert () == args + assert {"event": "", "foo": "bar"} == kw + def test_copies_context_before_processing(self): """ BoundLoggerBase._process_event() gets called before relaying events From ddad83ffd8a45fd7f4f82f57df428f3b2ecdcf2a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 10 Aug 2017 14:03:07 +0200 Subject: [PATCH 0144/1520] Adapt to GH behavior --- CONTRIBUTING.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 096dd23c..56b18e5e 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -18,8 +18,7 @@ Workflow This is a hard rule; patches with missing tests or documentation can't be accepted. - Make sure your changes pass our CI_. You won't get any feedback until it's green unless you ask for it. -- Once you've addressed review feedback, make sure to bump the pull request with a short note. - Maintainers don’t receive notifications when you push new commits. +- Once you've addressed review feedback, make sure to bump the pull request with a short note, so we know you're done. - Don’t break `backward compatibility`_. From e2e126678174942eb29f307c268c9ad6973711b3 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 10 Aug 2017 14:04:16 +0200 Subject: [PATCH 0145/1520] Better wording --- CONTRIBUTING.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 56b18e5e..d6727b0d 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -15,7 +15,7 @@ Workflow Please submit as many fixes for typos and grammar bloopers as you can! - Try to limit each pull request to *one* change only. - *Always* add tests and docs for your code. - This is a hard rule; patches with missing tests or documentation can't be accepted. + This is a hard rule; patches with missing tests or documentation can't be merged. - Make sure your changes pass our CI_. You won't get any feedback until it's green unless you ask for it. - Once you've addressed review feedback, make sure to bump the pull request with a short note, so we know you're done. From cc342ffd889211238e6e8ac6b567bff7178d1cc4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 17 Aug 2017 10:41:08 +0200 Subject: [PATCH 0146/1520] Use logo and nicer theme in docs --- docs-requirements.txt | 1 - docs/conf.py | 16 ++++++---------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/docs-requirements.txt b/docs-requirements.txt index 4f2d2a4e..20a49ed6 100644 --- a/docs-requirements.txt +++ b/docs-requirements.txt @@ -1,4 +1,3 @@ -e . sphinx<1.6 -sphinx_rtd_theme twisted diff --git a/docs/conf.py b/docs/conf.py index c82d14f9..fc4a4bc1 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -17,11 +17,6 @@ import os import re -try: - import sphinx_rtd_theme -except ImportError: - sphinx_rtd_theme = None - here = os.path.abspath(os.path.dirname(__file__)) @@ -129,11 +124,12 @@ def find_version(*file_paths): # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -if sphinx_rtd_theme: - html_theme = "sphinx_rtd_theme" - html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] -else: - html_theme = "default" +html_theme = "alabaster" +html_theme_options = { + "font_family": "Palatino, Georgia, serif", + "font_size": "18px", +} +html_logo = "_static/structlog_logo_small.png" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the From f1e47c23700843afd7c6a4c29af7ff6426c74452 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 17 Aug 2017 10:54:01 +0200 Subject: [PATCH 0147/1520] Pin Sphinx to 1.6.x --- docs-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs-requirements.txt b/docs-requirements.txt index 20a49ed6..508c10d6 100644 --- a/docs-requirements.txt +++ b/docs-requirements.txt @@ -1,3 +1,3 @@ -e . -sphinx<1.6 +sphinx>=1.6.3,<=1.7.0 twisted From 6c77b4025c820ea0f2ab50485e06e6cbe76ba014 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 17 Aug 2017 20:54:41 +0200 Subject: [PATCH 0148/1520] Turns out we still can't use Sphinx 1.6 :( --- docs-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs-requirements.txt b/docs-requirements.txt index 508c10d6..0285cf9c 100644 --- a/docs-requirements.txt +++ b/docs-requirements.txt @@ -1,3 +1,3 @@ -e . -sphinx>=1.6.3,<=1.7.0 +sphinx<1.6.0 twisted From ba18db4682864f96c5481e821e4747bd3a195b62 Mon Sep 17 00:00:00 2001 From: Brandon W Maister Date: Sat, 19 Aug 2017 02:34:24 -0500 Subject: [PATCH 0149/1520] Add docs around using ProcessorFormatter (#140) This adds a (I think) gentler introduction to the way that ProcessorFormatter works. The existing dictConfig remains. I wasn't sure if I should maybe add another couple of headings to the docs to make it more clear, we're already at the maximum nesting level in sphinx so it won't show up in the ToC anyway. I think that if this had existed I wouldn't have opened #138 --- docs/standard-library.rst | 84 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/docs/standard-library.rst b/docs/standard-library.rst index 3bfe3653..f6b5e3b4 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -107,7 +107,89 @@ Now both ``structlog`` and ``logging`` will emit JSON logs: Rendering Using ``structlog``-based Formatters Within :mod:`logging` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -You can leave rendering for later and yet use ``structlog``’s renderers for it: +``structlog`` comes with a :class:`~structlog.stdlib.ProcessorFormatter` that can be used as a :class:`~logging.Formatter` in any stdlib :mod:`Handler ` object. + +The :class:`~structlog.stdlib.ProcessorFormatter` has two parts to its API: + +#. The :meth:`~structlog.stdlib.ProcessorFormatter.wrap_for_formatter` method must be used as the last processor in :func:`structlog.configure`, + it converts the the processed event dict to something that the ``ProcessorFormatter`` understands. +#. The :class:`~structlog.stdlib.ProcessorFormatter` itself, + which can wrap any structlog renderer to handle the output of both structlog and stdlib events. + +Thus, the simplest possible configuration looks like the following: + +.. code-block:: python + + import logging + import structlog + + structlog.configure( + processors=[ + structlog.stdlib.ProcessorFormatter.wrap_for_formatter, + ], + logger_factory=structlog.stdlib.LoggerFactory(), + ) + + formatter = structlog.stdlib.ProcessorFormatter( + processor=structlog.dev.ConsoleRenderer(), + ) + + handler = logging.StreamHandler() + handler.setFormatter(formatter) + root_logger = logging.getLogger() + root_logger.addHandler(handler) + root_logger.setLevel(logging.INFO) + +which will allow both of these to work in other modules: + +.. code-block:: pycon + + >>> import logging + >>> import structlog + + >>> logging.getLogger('stdlog').info('woo') + woo + >>> structlog.get_logger('structlog').info('amazing', events='oh yes') + amazing events=oh yes + +Of course, you probably want timestamps and log levels in your output. +The :class:`~structlog.stdlib.ProcessorFormatter` has a ``foreign_pre_chain`` argument which is responsible for adding properties to events from the standard library, +and which should in general match the ``processors`` argument to :func:`structlog.configure`. + +For example, to add timestamps, log levels, and traceback handling to your logs you should do: + +.. code-block:: python + + timestamper = structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S") + shared_processors = [ + structlog.stdlib.add_log_level, + timestamper, + ] + + structlog.configure( + processors=shared_processors + [ + structlog.stdlib.ProcessorFormatter.wrap_for_formatter, + ], + logger_factory=structlog.stdlib.LoggerFactory(), + cache_logger_on_first_use=True, + ) + + formatter = structlog.stdlib.ProcessorFormatter( + processor=structlog.dev.ConsoleRenderer(), + foreign_pre_chain=shared_processors, + ) + +which (given the same ``logging.*`` calls as in the previous example) will result in: + +.. code-block:: pycon + + >>> logging.getLogger('stdlog').info('woo') + 2017-03-06 14:59:20 [info ] woo + >>> structlog.get_logger('structlog').info('amazing', events='oh yes') + 2017-03-06 14:59:20 [info ] amazing events=oh yes + +This allows you to set up some sophisticated logging configs. +For example, to use the standard library's :func:`~logging.config.dictConfig` to log colored logs to the console and colorless logs to a file you could do: .. code-block:: python From 1e5d909280391489d0413ce11e581b9e41f8f17e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 19 Aug 2017 09:40:41 +0200 Subject: [PATCH 0150/1520] Minor wordsmithing for consistency --- docs/standard-library.rst | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/standard-library.rst b/docs/standard-library.rst index f6b5e3b4..505518ba 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -114,7 +114,7 @@ The :class:`~structlog.stdlib.ProcessorFormatter` has two parts to its API: #. The :meth:`~structlog.stdlib.ProcessorFormatter.wrap_for_formatter` method must be used as the last processor in :func:`structlog.configure`, it converts the the processed event dict to something that the ``ProcessorFormatter`` understands. #. The :class:`~structlog.stdlib.ProcessorFormatter` itself, - which can wrap any structlog renderer to handle the output of both structlog and stdlib events. + which can wrap any ``structlog`` renderer to handle the output of both ``structlog`` and standard library events. Thus, the simplest possible configuration looks like the following: @@ -153,8 +153,7 @@ which will allow both of these to work in other modules: amazing events=oh yes Of course, you probably want timestamps and log levels in your output. -The :class:`~structlog.stdlib.ProcessorFormatter` has a ``foreign_pre_chain`` argument which is responsible for adding properties to events from the standard library, -and which should in general match the ``processors`` argument to :func:`structlog.configure`. +The :class:`~structlog.stdlib.ProcessorFormatter` has a ``foreign_pre_chain`` argument which is responsible for adding properties to events from the standard library -- i.e. that do not originate from a ``structlog`` logger -- and which should in general match the ``processors`` argument to :func:`structlog.configure` so you get a consistent output. For example, to add timestamps, log levels, and traceback handling to your logs you should do: @@ -188,8 +187,8 @@ which (given the same ``logging.*`` calls as in the previous example) will resul >>> structlog.get_logger('structlog').info('amazing', events='oh yes') 2017-03-06 14:59:20 [info ] amazing events=oh yes -This allows you to set up some sophisticated logging configs. -For example, to use the standard library's :func:`~logging.config.dictConfig` to log colored logs to the console and colorless logs to a file you could do: +This allows you to set up some sophisticated logging configurations. +For example, to use the standard library's :func:`~logging.config.dictConfig` to log colored logs to the console and plain logs to a file you could do: .. code-block:: python From d25ea4fb5c705ad2d129a81d5dff4485ce711845 Mon Sep 17 00:00:00 2001 From: Maia McCormick Date: Mon, 25 Sep 2017 08:13:45 -0400 Subject: [PATCH 0151/1520] [DOCS] fix threadlocal docs to provide correct example (#143) --- docs/thread-local.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/thread-local.rst b/docs/thread-local.rst index 6f20e9b0..03abe3cf 100644 --- a/docs/thread-local.rst +++ b/docs/thread-local.rst @@ -61,13 +61,12 @@ Within one thread, every instance of the returned class will have a *common* ins -Then use an instance of the generated class as the context class:: +To enable thread local context, then, use the generated class as the context class:: - configure(context_class=WrappedDictClass()) + configure(context_class=WrappedDictClass) .. note:: - **Remember**: the instance of the class *doesn't* matter. - Only the class *type* matters because *all* instances of one class *share* the *same* data. + Creation of a new ``BoundLogger`` initializes the logger's context as ``context_class(initial_values)``, and then adds any values passed via ``.bind()``. As all instances of a wrapped dict-like class share the same data, in the case above, the new logger's context will contain all previously bound values in addition to the new ones. :func:`structlog.threadlocal.wrap_dict` returns always a completely *new* wrapped class: From 6e319a587828f2f5ba4187d23d181b22dc1e90eb Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 25 Sep 2017 14:15:03 +0200 Subject: [PATCH 0152/1520] Semantic newline --- docs/thread-local.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/thread-local.rst b/docs/thread-local.rst index 03abe3cf..a3864798 100644 --- a/docs/thread-local.rst +++ b/docs/thread-local.rst @@ -61,12 +61,13 @@ Within one thread, every instance of the returned class will have a *common* ins -To enable thread local context, then, use the generated class as the context class:: +To enable thread local context use the generated class as the context class:: configure(context_class=WrappedDictClass) .. note:: - Creation of a new ``BoundLogger`` initializes the logger's context as ``context_class(initial_values)``, and then adds any values passed via ``.bind()``. As all instances of a wrapped dict-like class share the same data, in the case above, the new logger's context will contain all previously bound values in addition to the new ones. + Creation of a new ``BoundLogger`` initializes the logger's context as ``context_class(initial_values)``, and then adds any values passed via ``.bind()``. + As all instances of a wrapped dict-like class share the same data, in the case above, the new logger's context will contain all previously bound values in addition to the new ones. :func:`structlog.threadlocal.wrap_dict` returns always a completely *new* wrapped class: From 9c6e69a3e945d56a08a17cc617606b03b09558bd Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Wed, 15 Nov 2017 10:27:52 +0100 Subject: [PATCH 0153/1520] twisted: don't encapsulate failures twice (#145) * twisted: don't encapsulate failures twice If a failure is already a Failure instance, don't encapsulate it into a Failure. Keep it as is. Fix #144 * twisted: run tests with older versions of Twisted In versions < 17, Failure is not a subclass of BaseException, while it is in versions > 17. --- .travis.yml | 2 ++ CHANGELOG.rst | 3 ++- src/structlog/twisted.py | 2 +- tox.ini | 6 +++--- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 072276bf..7afbd87c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,6 +32,8 @@ matrix: env: TOXENV=py27-colorama - python: "3.6" env: TOXENV=py36-colorama + - python: "3.6" + env: TOXENV=py36-oldtwisted # Meta diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ed8bda10..56fe9e8a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -26,7 +26,8 @@ Changes: - Empty strings are valid events now. `#110 `_ - +- Do not encapsulate Twisted failures twice with newer versions of Twisted. + `#144 `_ ---- diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index dc2199b0..0fe1e342 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -107,7 +107,7 @@ def _extractStuffAndWhy(eventDict): _stuff = Failure() # Either we used the error ourselves or the user supplied one for # formatting. Avoid log.err() to dump another traceback into the log. - if isinstance(_stuff, BaseException): + if isinstance(_stuff, BaseException) and not isinstance(_stuff, Failure): _stuff = Failure(_stuff) if PY2: sys.exc_clear() diff --git a/tox.ini b/tox.ini index d3aefa72..56b7ed16 100644 --- a/tox.ini +++ b/tox.ini @@ -1,19 +1,19 @@ [tox] -envlist = {py27,py34,py35,py36,pypy}-{threads,greenlets},{py27,py36}-colorama,flake8,docs,readme,manifest,coverage-report +envlist = {py27,py34,py35,py36,pypy}-{threads,greenlets},{py27,py36}-{colorama,oldtwisted},flake8,docs,readme,manifest,coverage-report [testenv] deps = -rdev-requirements.txt greenlets: greenlet - twisted + threads,greenlets,colorama: twisted + oldtwisted: twisted < 17 colorama: colorama py36: python-rapidjson setenv = PYTHONHASHSEED = 0 commands = coverage run --parallel -m pytest {posargs} - [testenv:flake8] basepython = python3.6 skip_install = true From 0263e811438d5f1d604447488dd445bb434ec4e8 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 15 Nov 2017 10:37:25 +0100 Subject: [PATCH 0154/1520] Make flake8 happy --- tests/test_base.py | 7 +++++-- tests/test_config.py | 5 +++-- tests/test_loggers.py | 6 ++++-- tests/test_stdlib.py | 5 +++-- tox.ini | 1 + 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/tests/test_base.py b/tests/test_base.py index 156204e7..96ef5680 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -28,8 +28,11 @@ def build_bl(logger=None, processors=None, context=None): class TestBinding(object): def test_repr(self): - l = build_bl(processors=[1, 2, 3], context={}) - assert '' == repr(l) + bl = build_bl(processors=[1, 2, 3], context={}) + + assert ( + "" + ) == repr(bl) def test_binds_independently(self): """ diff --git a/tests/test_config.py b/tests/test_config.py index b5b86449..3ec8ebd5 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -262,8 +262,9 @@ def test_empty_processors(self): """ # We need to do a bind such that we get an actual logger and not just # a lazy proxy. - l = wrap_logger(object(), processors=[]).new() - assert [] == l._processors + logger = wrap_logger(object(), processors=[]).new() + + assert [] == logger._processors def test_wrap_returns_proxy(self): assert isinstance(wrap_logger(None), BoundLoggerLazyProxy) diff --git a/tests/test_loggers.py b/tests/test_loggers.py index 28b5a8cf..8d819a92 100644 --- a/tests/test_loggers.py +++ b/tests/test_loggers.py @@ -83,14 +83,16 @@ def test_does_not_cache(self): Due to doctest weirdness, we must not re-use PrintLoggers. """ f = PrintLoggerFactory() + assert f() is not f() def test_passes_file(self): """ If a file is passed to the factory, it get passed on to the logger. """ - l = PrintLoggerFactory(sys.stderr)() - assert sys.stderr is l._file + pl = PrintLoggerFactory(sys.stderr)() + + assert sys.stderr is pl._file def test_ignores_args(self): """ diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index ae33ba9f..efd245ae 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -122,8 +122,9 @@ def test_positional_argument_avoids_guessing(self): If a positional argument is passed to the factory, it's used as the name instead of guessing. """ - l = LoggerFactory()('foo') - assert 'foo' == l.name + lf = LoggerFactory()("foo") + + assert "foo" == lf.name class TestFilterByLevel(object): diff --git a/tox.ini b/tox.ini index 56b7ed16..27cc2e10 100644 --- a/tox.ini +++ b/tox.ini @@ -14,6 +14,7 @@ setenv = PYTHONHASHSEED = 0 commands = coverage run --parallel -m pytest {posargs} + [testenv:flake8] basepython = python3.6 skip_install = true From de3fe96826e8c32fa170ab0b1bf46b9f379dc0d4 Mon Sep 17 00:00:00 2001 From: Piotr Popieluch Date: Wed, 15 Nov 2017 11:37:21 +0100 Subject: [PATCH 0155/1520] Skip simplejson test if module is not installed. (#146) --- tests/test_processors.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/test_processors.py b/tests/test_processors.py index 04e9fdf5..1e413d36 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -11,9 +11,13 @@ import sys import pytest -import simplejson import six +try: + import simplejson +except ImportError: + simplejson = None + try: import rapidjson except ImportError: @@ -167,6 +171,7 @@ def test_serializer(self): assert {"a": 42} == jr(None, None, obj) + @pytest.mark.skipif(simplejson is None, reason="simplejson is missing.") def test_simplejson(self, event_dict): """ Integration test with simplejson. From 82805c75fa0137bec65971bdf9416857529a9260 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 15 Nov 2017 12:16:40 +0100 Subject: [PATCH 0156/1520] Use a fresher PyPy --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7afbd87c..2d56cdbb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,9 +24,9 @@ matrix: env: TOXENV=py36-threads - python: "3.6" env: TOXENV=py36-greenlets - - python: "pypy" + - python: "pypy2.7-5.8.0" env: TOXENV=pypy-threads - - python: "pypy" + - python: "pypy2.7-5.8.0" env: TOXENV=pypy-greenlets - python: "2.7" env: TOXENV=py27-colorama From 4357e6e4d9c7d6ceea408435908830b353eba10b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 15 Nov 2017 12:23:50 +0100 Subject: [PATCH 0157/1520] Test on pypy3 too --- .travis.yml | 4 ++++ tox.ini | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2d56cdbb..c1311010 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,6 +28,10 @@ matrix: env: TOXENV=pypy-threads - python: "pypy2.7-5.8.0" env: TOXENV=pypy-greenlets + - python: "pypy3.5-5.8.0" + env: TOXENV=pypy3-threads + - python: "pypy3.5-5.8.0" + env: TOXENV=pypy3-greenlets - python: "2.7" env: TOXENV=py27-colorama - python: "3.6" diff --git a/tox.ini b/tox.ini index 27cc2e10..c9fd5ad5 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = {py27,py34,py35,py36,pypy}-{threads,greenlets},{py27,py36}-{colorama,oldtwisted},flake8,docs,readme,manifest,coverage-report +envlist = {py27,py34,py35,py36,pypy,pypy3}-{threads,greenlets},{py27,py36}-{colorama,oldtwisted},flake8,docs,readme,manifest,coverage-report [testenv] From 44a53363ec6c85588eb2fb920fab9a1e16f6d57a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 26 Nov 2017 15:47:46 +0100 Subject: [PATCH 0158/1520] Add a short logging intro to stdlib docs --- docs/standard-library.rst | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/docs/standard-library.rst b/docs/standard-library.rst index 505518ba..eb0009df 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -8,6 +8,28 @@ If you run into incompatibilities, it is a *bug* so please take the time to `rep If you're a heavy :mod:`logging` user, your `help `_ to ensure a better compatibility would be highly appreciated! +Just Enough ``logging`` +----------------------- + +If you want to use ``structlog`` with :mod:`logging`, you still have to have at least fleeting understanding on how the standard library operates because ``structlog`` will *not* do any magic things in the background for you. +Most importantly you have *configure* the :mod:`logging` system *additionally* to configuring ``structlog``. + +Usually it is enough to use:: + + import logging + import sys + + logging.basicConfig( + format="%(message)s", + stream=sys.stdout, + level=logging.INFO, + ) + +This will send all log messages with the `log level `_ ``logging.INFO`` and above (that means that e.g. :func:`logging.debug` calls are ignored) to standard out without any special formatting by the standard library. + +If you require more complex behavior, please refer to the standard library's :mod:`logging` documentation. + + Concrete Bound Logger --------------------- From 22f0ae50607a0cb024361599f84610ce290deb99 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 2 Dec 2017 08:32:10 +0100 Subject: [PATCH 0159/1520] Fix tests for pytest 3.3 --- dev-requirements.txt | 2 +- tests/test_stdlib.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dev-requirements.txt b/dev-requirements.txt index e8165ec7..a94faf12 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -2,5 +2,5 @@ coverage freezegun>=0.2.8 pretend -pytest +pytest>=3.3.0 simplejson diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index efd245ae..81d92aa5 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -81,7 +81,7 @@ def test_ignores_frames(self): name is not from structlog or one of the configurable other names. """ assert '__main__' == additional_frame(LoggerFactory( - ignore_frame_names=['tests.', '_pytest.']) + ignore_frame_names=["tests.", "_pytest.", "pluggy"]) ).name def test_deduces_correct_caller(self): From e4305d90c27469892d74721a453b680a4991d95d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 2 Dec 2017 10:10:37 +0100 Subject: [PATCH 0160/1520] Use test extra require --- CONTRIBUTING.rst | 10 ++-------- dev-requirements.txt | 7 +------ setup.py | 7 +++++++ tox.ini | 2 +- 4 files changed, 11 insertions(+), 15 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index d6727b0d..621e5749 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -112,21 +112,15 @@ Next get an up to date checkout of the ``structlog`` repository: git checkout git@github.com:hynek/structlog.git -Change into the newly created directory and **after activating your virtual environment** install an editable version of ``structlog``: +Change into the newly created directory and **after activating your virtual environment** install an editable version of ``structlog`` along with its test dependencies: .. code-block:: bash cd structlog - pip install -e . + pip install -e .[test] If you run the virtual environment’s Python and try to ``import structlog`` it should work! -To run the test suite, you'll need our development dependencies which can be installed using - -.. code-block:: bash - - pip install -r dev-requirements.txt - At this point .. code-block:: bash diff --git a/dev-requirements.txt b/dev-requirements.txt index a94faf12..a4af5aa1 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,6 +1 @@ --e . -coverage -freezegun>=0.2.8 -pretend -pytest>=3.3.0 -simplejson +-e .[test] diff --git a/setup.py b/setup.py index 63b7605d..b5ac84b8 100644 --- a/setup.py +++ b/setup.py @@ -34,6 +34,13 @@ INSTALL_REQUIRES = ["six"] EXTRAS_REQUIRE = { "dev": ["colorama"], + "test": [ + "coverage", + "freezegun>=0.2.8", + "pretend", + "pytest>=3.3.0", + "simplejson", + ] } ############################################################################### diff --git a/tox.ini b/tox.ini index c9fd5ad5..f1c81f94 100644 --- a/tox.ini +++ b/tox.ini @@ -4,7 +4,7 @@ envlist = {py27,py34,py35,py36,pypy,pypy3}-{threads,greenlets},{py27,py36}-{colo [testenv] deps = - -rdev-requirements.txt + .[test] greenlets: greenlet threads,greenlets,colorama: twisted oldtwisted: twisted < 17 From c7a59257cab8a008ebf2b8e363612e2b1ef33f75 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 12 Dec 2017 16:10:03 +0100 Subject: [PATCH 0161/1520] Use proper link syntax --- src/structlog/stdlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 38f2c235..01eee846 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -252,7 +252,7 @@ class PositionalArgumentsFormatter(object): used for keyword placeholders in the `event` string, otherwise it will be used for positional placeholders. - `positional_args` is populated by `structlog.stdlib.BoundLogger` or + `positional_args` is populated by :class:`structlog.stdlib.BoundLogger` or can be set manually. The `remove_positional_args` flag can be set to `False` to keep the From 90ba9cfada8d7bc557057b580dd0de161659c29e Mon Sep 17 00:00:00 2001 From: sb98052 Date: Sat, 20 Jan 2018 03:18:20 -0500 Subject: [PATCH 0162/1520] Send colored logs to non-tty destinations (#141) --- CHANGELOG.rst | 3 +++ src/structlog/dev.py | 14 +++++++++++--- tests/test_dev.py | 23 +++++++++++++++++++++++ tests/test_twisted.py | 9 +++++---- 4 files changed, 42 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 56fe9e8a..975d343d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -28,6 +28,9 @@ Changes: `#110 `_ - Do not encapsulate Twisted failures twice with newer versions of Twisted. `#144 `_ +- ``structlog.dev.ConsoleRenderer`` now accepts a *force_colors* argument to output colored logs even if the destination is not a tty. + Use this option if your logs are stored in files that are intended to be streamed to the console. + ---- diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 1c2fd103..a4181f5f 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -99,6 +99,9 @@ class ConsoleRenderer(object): :param int pad_event: Pad the event to this many characters. :param bool colors: Use colors for a nicer output. + :param bool force_colors: Force colors even for non-tty destinations. + Use this option if your logs are stored in a file that is meant + to be streamed to the console. :param bool repr_native_str: When ``True``, :func:`repr()` is also applied to native strings (i.e. unicode on Python 3 and bytes on Python 2). Setting this to ``False`` is useful if you want to have human-readable @@ -114,7 +117,7 @@ class ConsoleRenderer(object): .. versionadded:: 17.1 *repr_native_str* """ def __init__(self, pad_event=_EVENT_WIDTH, colors=True, - repr_native_str=False): + force_colors=False, repr_native_str=False): if colors is True: if colorama is None: raise SystemError( @@ -124,7 +127,12 @@ def __init__(self, pad_event=_EVENT_WIDTH, colors=True, ) ) - colorama.init() + if force_colors: + colorama.deinit() + colorama.init(strip=False) + else: + colorama.init() + styles = _ColorfulStyles else: styles = _PlainStyles @@ -168,7 +176,7 @@ def __call__(self, _, __, event_dict): # can be a number if timestamp is UNIXy self._styles.timestamp + str(ts) + self._styles.reset + " " ) - level = event_dict.pop("level", None) + level = event_dict.pop("level", None) if level is not None: sio.write( "[" + self._level_to_color[level] + diff --git a/tests/test_dev.py b/tests/test_dev.py index b9c4394f..89b65f0b 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -228,6 +228,29 @@ def test_colorama_colors_false(self): assert dev._PlainStyles is plain_cr._styles assert "[info ] event foo=bar" == rv + def test_colorama_force_colors(self, styles, padded): + """ + If force_colors is True, use colors even if + the destination is non-tty. + """ + cr = dev.ConsoleRenderer( + colors=dev._has_colorama, force_colors=dev._has_colorama) + + rv = cr(None, None, { + "event": "test", "level": "critical", "foo": "bar" + }) + + assert ( + "[" + dev.RED + styles.bright + + dev._pad("critical", cr._longest_level) + + styles.reset + "] " + + padded + + styles.kv_key + "foo" + styles.reset + "=" + + styles.kv_value + "bar" + styles.reset + ) == rv + + assert not dev._has_colorama or dev._ColorfulStyles is cr._styles + @pytest.mark.parametrize("rns", [True, False]) def test_repr_native_str(self, rns): """ diff --git a/tests/test_twisted.py b/tests/test_twisted.py index 0cda3b77..35611914 100644 --- a/tests/test_twisted.py +++ b/tests/test_twisted.py @@ -115,13 +115,13 @@ def test_handlesFailures(self): """ f = Failure(ValueError()) assert ( - (f, "foo", {}) == + ({'value': f}, "foo", {}) == _extractStuffAndWhy({"_why": "foo", - "_stuff": f}) + "_stuff": {'value': f}}) ) assert ( - (f, None, {}) == - _extractStuffAndWhy({"_stuff": f}) + ({'value': f}, None, {}) == + _extractStuffAndWhy({"_stuff": {'value': f}}) ) def test_handlesMissingFailure(self): @@ -154,6 +154,7 @@ class TestEventAdapter(object): """ Some tests here are redundant because they predate _extractStuffAndWhy. """ + def test_EventAdapterFormatsLog(self): la = EventAdapter(_render_repr) assert "{'foo': 'bar'}" == la(None, 'msg', {'foo': 'bar'}) From d22eaec276daa1d34420cae30d08ff1c01e28950 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 20 Jan 2018 11:01:54 +0100 Subject: [PATCH 0163/1520] Random modernizations --- .../CODE_OF_CONDUCT.rst | 6 ++-- CONTRIBUTING.rst => .github/CONTRIBUTING.rst | 16 +++++++-- .readthedocs.yml | 6 ++++ .travis.yml | 10 +++--- CHANGELOG.rst | 5 +-- MANIFEST.in | 10 ++++-- dev-requirements.txt | 1 - docs-requirements.txt | 3 -- docs/conf.py | 4 ++- docs/contributing.rst | 2 +- docs/getting-started.rst | 2 +- docs/processors.rst | 2 +- setup.cfg | 24 +++++++++++-- setup.py | 10 ++++-- src/structlog/__init__.py | 34 +++++-------------- src/structlog/_base.py | 4 +-- src/structlog/_config.py | 11 ++---- src/structlog/dev.py | 2 ++ src/structlog/processors.py | 4 +-- src/structlog/stdlib.py | 4 +-- src/structlog/threadlocal.py | 1 + src/structlog/twisted.py | 6 ++-- tests/test_config.py | 17 +++------- tests/test_frames.py | 4 +-- tests/test_loggers.py | 7 ++-- tests/test_processors.py | 34 ++++++++----------- tests/test_stdlib.py | 25 +++++--------- tests/test_threadlocal.py | 3 +- tests/test_twisted.py | 20 ++++------- tox.ini | 25 ++++++++++---- 30 files changed, 151 insertions(+), 151 deletions(-) rename CODE_OF_CONDUCT.rst => .github/CODE_OF_CONDUCT.rst (83%) rename CONTRIBUTING.rst => .github/CONTRIBUTING.rst (96%) create mode 100644 .readthedocs.yml delete mode 100644 dev-requirements.txt delete mode 100644 docs-requirements.txt diff --git a/CODE_OF_CONDUCT.rst b/.github/CODE_OF_CONDUCT.rst similarity index 83% rename from CODE_OF_CONDUCT.rst rename to .github/CODE_OF_CONDUCT.rst index fa8b5bb2..56e8914c 100644 --- a/CODE_OF_CONDUCT.rst +++ b/.github/CODE_OF_CONDUCT.rst @@ -4,7 +4,7 @@ Contributor Covenant Code of Conduct Our Pledge ---------- -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. Our Standards ------------- @@ -43,7 +43,7 @@ Enforcement ----------- Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hs@ox.cx. -all complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. +All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. @@ -52,4 +52,4 @@ Project maintainers who do not follow or enforce the Code of Conduct in good fai Attribution ----------- -This Code of Conduct is adapted from the `Contributor Covenant `_, version 1.4, available at http://contributor-covenant.org/version/1/4. +This Code of Conduct is adapted from the `Contributor Covenant `_, version 1.4, available at . diff --git a/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst similarity index 96% rename from CONTRIBUTING.rst rename to .github/CONTRIBUTING.rst index 621e5749..66ce8be0 100644 --- a/CONTRIBUTING.rst +++ b/.github/CONTRIBUTING.rst @@ -112,12 +112,12 @@ Next get an up to date checkout of the ``structlog`` repository: git checkout git@github.com:hynek/structlog.git -Change into the newly created directory and **after activating your virtual environment** install an editable version of ``structlog`` along with its test dependencies: +Change into the newly created directory and **after activating your virtual environment** install an editable version of ``structlog`` along with its test and docs dependencies: .. code-block:: bash cd structlog - pip install -e .[test] + pip install -e .[tests,docs] If you run the virtual environment’s Python and try to ``import structlog`` it should work! @@ -127,7 +127,17 @@ At this point python -m pytest -should work and pass! +should work and pass + +and + +.. code-block:: bash + + cd docs + make html + + +should build docs in ``docs/_build/html``. **** diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 00000000..a4b6f431 --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,6 @@ +--- +python: + version: 3 + pip_install: true + extra_requirements: + - docs diff --git a/.travis.yml b/.travis.yml index c1311010..0d78a2f2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,5 @@ +dist: trusty +group: travis_latest sudo: false cache: directories: @@ -24,13 +26,13 @@ matrix: env: TOXENV=py36-threads - python: "3.6" env: TOXENV=py36-greenlets - - python: "pypy2.7-5.8.0" + - python: "pypy" env: TOXENV=pypy-threads - - python: "pypy2.7-5.8.0" + - python: "pypy" env: TOXENV=pypy-greenlets - - python: "pypy3.5-5.8.0" + - python: "pypy3" env: TOXENV=pypy3-threads - - python: "pypy3.5-5.8.0" + - python: "pypy3" env: TOXENV=pypy3-greenlets - python: "2.7" env: TOXENV=py27-colorama diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 975d343d..a0f4c53c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,7 +5,7 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. -17.3.0 (UNRELEASED) +18.1.0 (UNRELEASED) ------------------- @@ -28,8 +28,9 @@ Changes: `#110 `_ - Do not encapsulate Twisted failures twice with newer versions of Twisted. `#144 `_ -- ``structlog.dev.ConsoleRenderer`` now accepts a *force_colors* argument to output colored logs even if the destination is not a tty. +- ``structlog.dev.ConsoleRenderer`` now accepts a *force_colors* argument to output colored logs even if the destination is not a tty. Use this option if your logs are stored in files that are intended to be streamed to the console. + `#141 `_ ---- diff --git a/MANIFEST.in b/MANIFEST.in index 81c5a1f8..271faebf 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,9 +1,13 @@ -include LICENSE LICENSE.apache2 LICENSE.mit .coveragerc conftest.py +include LICENSE LICENSE.apache2 LICENSE.mit .coveragerc conftest.py .readthedocs.yml include *.rst -include *.txt -include .travis.yml +recursive-include .github *.rst + include tox.ini graft tests recursive-exclude tests *.pyc + graft docs prune docs/_build + +# Don't package GitHub-specific files. +exclude .github/*.md .travis.yml diff --git a/dev-requirements.txt b/dev-requirements.txt deleted file mode 100644 index a4af5aa1..00000000 --- a/dev-requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e .[test] diff --git a/docs-requirements.txt b/docs-requirements.txt deleted file mode 100644 index 0285cf9c..00000000 --- a/docs-requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ --e . -sphinx<1.6.0 -twisted diff --git a/docs/conf.py b/docs/conf.py index fc4a4bc1..0c4936b1 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -126,8 +126,10 @@ def find_version(*file_paths): # a list of builtin themes. html_theme = "alabaster" html_theme_options = { - "font_family": "Palatino, Georgia, serif", + "font_family": '"Avenir Next", Calibri, "PT Sans", sans-serif', + "head_font_family": '"Avenir Next", Calibri, "PT Sans", sans-serif', "font_size": "18px", + "page_width": "980px", } html_logo = "_static/structlog_logo_small.png" diff --git a/docs/contributing.rst b/docs/contributing.rst index 46281822..8fbb03c9 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -1,3 +1,3 @@ .. _contributing: -.. include:: ../CONTRIBUTING.rst +.. include:: ../.github/CONTRIBUTING.rst diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 907dc1a3..42d1f0d4 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -111,7 +111,7 @@ To make this common case as simple as possible, ``structlog`` comes with some to >>> from structlog.stdlib import LoggerFactory >>> configure(logger_factory=LoggerFactory()) # doctest: +SKIP >>> log = get_logger() - >>> log.warn('it works!', difficulty='easy') # doctest: +SKIP + >>> log.warning('it works!', difficulty='easy') # doctest: +SKIP WARNING:structlog...:difficulty='easy' event='it works!' In other words, you tell ``structlog`` that you would like to use the standard library logger factory and keep calling :func:`~structlog.get_logger` like before. diff --git a/docs/processors.rst b/docs/processors.rst index ffc46832..505f30ae 100644 --- a/docs/processors.rst +++ b/docs/processors.rst @@ -20,7 +20,7 @@ Each processors receives three positional arguments: **method_name** The name of the wrapped method. - If you called ``log.warn('foo')``, it will be ``"warn"``. + If you called ``log.warning('foo')``, it will be ``"warning"``. **event_dict** Current context together with the current event. diff --git a/setup.cfg b/setup.cfg index ce5783da..31e050ba 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,9 +1,27 @@ +[bdist_wheel] +# we're pure-python +universal = 1 + + +[metadata] +# ensure LICENSE is included in wheel metadata +license_file = LICENSE + + [tool:pytest] minversion = 3.0 strict = true addopts = -ra testpaths = tests +filterwarnings = + once::Warning -[bdist_wheel] -# we're pure-python -universal = 1 + +[isort] +atomic=true +lines_after_imports=2 +lines_between_types=1 +multi_line_output=5 +not_skip=__init__.py + +known_first_party=structlog diff --git a/setup.py b/setup.py index b5ac84b8..9e6b7c17 100644 --- a/setup.py +++ b/setup.py @@ -2,12 +2,12 @@ # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. -from setuptools import setup, find_packages - import codecs import os import re +from setuptools import find_packages, setup + ############################################################################### @@ -34,12 +34,16 @@ INSTALL_REQUIRES = ["six"] EXTRAS_REQUIRE = { "dev": ["colorama"], - "test": [ + "tests": [ "coverage", "freezegun>=0.2.8", "pretend", "pytest>=3.3.0", "simplejson", + ], + "docs": [ + "sphinx<1.6.0", + "twisted", ] } diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 443d6668..35660565 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -8,35 +8,17 @@ from __future__ import absolute_import, division, print_function -from structlog import ( - dev, - processors, - stdlib, - threadlocal, -) -from structlog._base import ( - BoundLoggerBase, -) +from structlog import dev, processors, stdlib, threadlocal +from structlog._base import BoundLoggerBase from structlog._config import ( - configure, - configure_once, - getLogger, - get_logger, - reset_defaults, - wrap_logger, -) -from structlog.exceptions import ( - DropEvent, -) -from structlog._generic import ( - BoundLogger + configure, configure_once, get_logger, getLogger, reset_defaults, + wrap_logger ) +from structlog._generic import BoundLogger from structlog._loggers import ( - PrintLogger, - PrintLoggerFactory, - ReturnLogger, - ReturnLoggerFactory, + PrintLogger, PrintLoggerFactory, ReturnLogger, ReturnLoggerFactory ) +from structlog.exceptions import DropEvent try: @@ -45,7 +27,7 @@ twisted = None -__version__ = "17.3.0.dev0" +__version__ = "18.1.0.dev0" __title__ = "structlog" __description__ = "Structured Logging for Python" diff --git a/src/structlog/_base.py b/src/structlog/_base.py index 68e1e5ff..c590d073 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -8,10 +8,10 @@ from __future__ import absolute_import, division, print_function -from structlog.exceptions import DropEvent - from six import string_types +from structlog.exceptions import DropEvent + class BoundLoggerBase(object): """ diff --git a/src/structlog/_config.py b/src/structlog/_config.py index cd64f493..b87f13ae 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -13,15 +13,10 @@ from collections import OrderedDict from ._generic import BoundLogger -from ._loggers import ( - PrintLoggerFactory, -) +from ._loggers import PrintLoggerFactory from .dev import ConsoleRenderer, _has_colorama -from .processors import ( - StackInfoRenderer, - TimeStamper, - format_exc_info, -) +from .processors import StackInfoRenderer, TimeStamper, format_exc_info + _BUILTIN_DEFAULT_PROCESSORS = [ StackInfoRenderer(), diff --git a/src/structlog/dev.py b/src/structlog/dev.py index a4181f5f..caad94a5 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -10,6 +10,7 @@ from six import StringIO + try: import colorama except ImportError: @@ -115,6 +116,7 @@ class ConsoleRenderer(object): .. versionadded:: 16.0 .. versionadded:: 16.1 *colors* .. versionadded:: 17.1 *repr_native_str* + .. versionadded:: 18.1 *force_colors* """ def __init__(self, pad_event=_EVENT_WIDTH, colors=True, force_colors=False, repr_native_str=False): diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 7cee40bb..5001d493 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -17,9 +17,7 @@ import six from structlog._frames import ( - _find_first_app_frame_and_name, - _format_exception, - _format_stack, + _find_first_app_frame_and_name, _format_exception, _format_stack ) diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 01eee846..53d82454 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -13,12 +13,12 @@ import logging +from six import PY3 + from structlog._base import BoundLoggerBase from structlog._frames import _find_first_app_frame_and_name, _format_stack from structlog.exceptions import DropEvent -from six import PY3 - class _FixedFindCallerLogger(logging.Logger): """ diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index 281a5612..da856b30 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -13,6 +13,7 @@ from structlog._config import BoundLoggerLazyProxy + try: from greenlet import getcurrent except ImportError: diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index 0fe1e342..a2601a2c 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -15,6 +15,7 @@ import sys from six import PY2, string_types + from twisted.python import log from twisted.python.failure import Failure from twisted.python.log import ILogObserver, textFromEventDict @@ -23,10 +24,7 @@ from ._base import BoundLoggerBase from ._config import _BUILTIN_DEFAULT_PROCESSORS from ._utils import until_not_interrupted -from .processors import ( - # can't import processors module without risking circular imports - JSONRenderer as GenericJSONRenderer, -) +from .processors import JSONRenderer as GenericJSONRenderer class BoundLogger(BoundLoggerBase): diff --git a/tests/test_config.py b/tests/test_config.py index 3ec8ebd5..5fd50b06 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -8,22 +8,15 @@ import pytest -from pretend import call_recorder, call, stub +from pretend import call, call_recorder, stub from six import PY3 from structlog._base import BoundLoggerBase from structlog._config import ( - BoundLoggerLazyProxy, - _CONFIG, - _BUILTIN_DEFAULT_CONTEXT_CLASS, - _BUILTIN_DEFAULT_PROCESSORS, - _BUILTIN_DEFAULT_LOGGER_FACTORY, - _BUILTIN_DEFAULT_WRAPPER_CLASS, - configure, - configure_once, - get_logger, - reset_defaults, - wrap_logger, + _BUILTIN_DEFAULT_CONTEXT_CLASS, _BUILTIN_DEFAULT_LOGGER_FACTORY, + _BUILTIN_DEFAULT_PROCESSORS, _BUILTIN_DEFAULT_WRAPPER_CLASS, _CONFIG, + BoundLoggerLazyProxy, configure, configure_once, get_logger, + reset_defaults, wrap_logger ) diff --git a/tests/test_frames.py b/tests/test_frames.py index db04a4aa..4dd95bc3 100644 --- a/tests/test_frames.py +++ b/tests/test_frames.py @@ -13,9 +13,7 @@ import structlog._frames from structlog._frames import ( - _find_first_app_frame_and_name, - _format_exception, - _format_stack, + _find_first_app_frame_and_name, _format_exception, _format_stack ) diff --git a/tests/test_loggers.py b/tests/test_loggers.py index 8d819a92..71218b94 100644 --- a/tests/test_loggers.py +++ b/tests/test_loggers.py @@ -10,11 +10,8 @@ from six.moves import cStringIO as StringIO from structlog._loggers import ( - PrintLogger, - PrintLoggerFactory, - ReturnLogger, - ReturnLoggerFactory, - WRITE_LOCKS, + WRITE_LOCKS, PrintLogger, PrintLoggerFactory, ReturnLogger, + ReturnLoggerFactory ) from structlog.stdlib import _NAME_TO_LEVEL diff --git a/tests/test_processors.py b/tests/test_processors.py index 1e413d36..97fdf38c 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -13,37 +13,31 @@ import pytest import six -try: - import simplejson -except ImportError: - simplejson = None - -try: - import rapidjson -except ImportError: - rapidjson = None - from freezegun import freeze_time import structlog from structlog.processors import ( - ExceptionPrettyPrinter, - JSONRenderer, - KeyValueRenderer, - StackInfoRenderer, - TimeStamper, - UnicodeDecoder, - UnicodeEncoder, - _figure_out_exc_info, - _json_fallback_handler, - format_exc_info, + ExceptionPrettyPrinter, JSONRenderer, KeyValueRenderer, StackInfoRenderer, + TimeStamper, UnicodeDecoder, UnicodeEncoder, _figure_out_exc_info, + _json_fallback_handler, format_exc_info ) from structlog.threadlocal import wrap_dict from .utils import py3_only +try: + import simplejson +except ImportError: + simplejson = None + +try: + import rapidjson +except ImportError: + rapidjson = None + + class TestKeyValueRenderer(object): def test_sort_keys(self, event_dict): """ diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 81d92aa5..5e615e45 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -4,32 +4,23 @@ from __future__ import absolute_import, division, print_function -import os - -import logging import collections +import logging import logging.config +import os import pytest from pretend import call_recorder -from structlog import reset_defaults, configure, ReturnLogger, get_logger +from structlog import ReturnLogger, configure, get_logger, reset_defaults from structlog.dev import ConsoleRenderer -from structlog.processors import JSONRenderer from structlog.exceptions import DropEvent +from structlog.processors import JSONRenderer from structlog.stdlib import ( - BoundLogger, - CRITICAL, - LoggerFactory, - PositionalArgumentsFormatter, - ProcessorFormatter, - WARN, - _FixedFindCallerLogger, - add_log_level, - add_logger_name, - filter_by_level, - render_to_log_kwargs, + CRITICAL, WARN, BoundLogger, LoggerFactory, PositionalArgumentsFormatter, + ProcessorFormatter, _FixedFindCallerLogger, add_log_level, add_logger_name, + filter_by_level, render_to_log_kwargs ) from .additional_frame import additional_frame @@ -595,7 +586,7 @@ def test_formatter_unsets_stack_info(self, configure_for_pf, capsys, keep): ) logger.handlers[0].setFormatter(formatter) - logging.getLogger().warn("have a stack trace", stack_info=True) + logging.getLogger().warning("have a stack trace", stack_info=True) out, err = capsys.readouterr() assert "" == out diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py index 055d7b64..8cf43e90 100644 --- a/tests/test_threadlocal.py +++ b/tests/test_threadlocal.py @@ -13,7 +13,8 @@ from structlog._base import BoundLoggerBase from structlog._config import wrap_logger from structlog._loggers import ReturnLogger -from structlog.threadlocal import as_immutable, wrap_dict, tmp_bind +from structlog.threadlocal import as_immutable, tmp_bind, wrap_dict + try: import greenlet diff --git a/tests/test_twisted.py b/tests/test_twisted.py index 35611914..cfd586c5 100644 --- a/tests/test_twisted.py +++ b/tests/test_twisted.py @@ -12,24 +12,18 @@ from pretend import call_recorder from six import PY3 -from six.moves import cStringIO as StringIO -from twisted.python.failure import Failure, NoCurrentExceptionError -from twisted.python.log import ILogObserver -from structlog._config import _CONFIG +from six.moves import cStringIO as StringIO from structlog import ReturnLogger +from structlog._config import _CONFIG from structlog.processors import KeyValueRenderer from structlog.twisted import ( - BoundLogger, - EventAdapter, - JSONLogObserverWrapper, - JSONRenderer, - LoggerFactory, - PlainFileLogObserver, - ReprWrapper, - _extractStuffAndWhy, - plainJSONStdOutLogger, + BoundLogger, EventAdapter, JSONLogObserverWrapper, JSONRenderer, + LoggerFactory, PlainFileLogObserver, ReprWrapper, _extractStuffAndWhy, + plainJSONStdOutLogger ) +from twisted.python.failure import Failure, NoCurrentExceptionError +from twisted.python.log import ILogObserver def test_LoggerFactory(): diff --git a/tox.ini b/tox.ini index f1c81f94..acfbab5b 100644 --- a/tox.ini +++ b/tox.ini @@ -1,10 +1,10 @@ [tox] -envlist = {py27,py34,py35,py36,pypy,pypy3}-{threads,greenlets},{py27,py36}-{colorama,oldtwisted},flake8,docs,readme,manifest,coverage-report +envlist = isort,{py27,py34,py35,py36,pypy,pypy3}-{threads,greenlets},{py27,py36}-{colorama,oldtwisted},flake8,docs,readme,manifest,coverage-report [testenv] +extras = tests deps = - .[test] greenlets: greenlet threads,greenlets,colorama: twisted oldtwisted: twisted < 17 @@ -17,16 +17,29 @@ commands = coverage run --parallel -m pytest {posargs} [testenv:flake8] basepython = python3.6 -skip_install = true -deps = flake8 -commands = flake8 src tests setup.py docs/conf.py +extras = tests +deps = + flake8 + flake8-isort +commands = flake8 src tests setup.py conftest.py docs/conf.py + + +[testenv:isort] +basepython = python3.6 +extras = tests +# Needs a full install so isort can determine own/foreign imports. +deps = + isort +commands = + isort --recursive setup.py conftest.py src tests [testenv:docs] basepython = python3.6 +extras = + docs setenv = PYTHONHASHSEED = 0 -deps = -rdocs-requirements.txt commands = sphinx-build -W -b html -d {envtmpdir}/doctrees docs docs/_build/html sphinx-build -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html From 5f914792f31d14bb8c27b9d04f33a77f639ad33e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 20 Jan 2018 12:23:15 +0100 Subject: [PATCH 0164/1520] More polish --- .github/CONTRIBUTING.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst index 66ce8be0..b72ee1ed 100644 --- a/.github/CONTRIBUTING.rst +++ b/.github/CONTRIBUTING.rst @@ -56,7 +56,7 @@ Tests - To run the test suite, all you need is a recent tox_. It will ensure the test suite runs with all dependencies against all Python versions just as it will on Travis CI. - If you lack some Python versions, you can can always limit the environments like ``tox -e py27,py35`` (in that case you may want to look into pyenv_, which makes it very easy to install many different Python versions in parallel). + If you lack some Python versions, you can can make it a non-failure using ``tox --skip-missing-interpreters`` (in that case you may want to look into pyenv_ that makes it very easy to install many different Python versions in parallel). - Write `good test docstrings`_. @@ -155,7 +155,7 @@ Thank you for considering contributing to ``structlog``! .. _`PEP 8`: https://www.python.org/dev/peps/pep-0008/ .. _`PEP 257`: https://www.python.org/dev/peps/pep-0257/ .. _`good test docstrings`: https://jml.io/pages/test-docstrings.html -.. _`Code of Conduct`: https://github.com/hynek/structlog/blob/master/CODE_OF_CONDUCT.rst +.. _`Code of Conduct`: https://github.com/hynek/structlog/blob/master/.github/CODE_OF_CONDUCT.rst .. _changelog: https://github.com/hynek/structlog/blob/master/CHANGELOG.rst .. _`backward compatibility`: https://structlog.readthedocs.io/en/latest/backward-compatibility.html .. _tox: https://tox.readthedocs.io/ From 5a3d3e59805f1e2b82738e14f73d1ff395b24f3a Mon Sep 17 00:00:00 2001 From: Brandon W Maister Date: Sat, 20 Jan 2018 08:57:52 -0500 Subject: [PATCH 0165/1520] Allow using upper-case levels in ConsoleRenderer (#139) --- CHANGELOG.rst | 4 +++- docs/api.rst | 1 + src/structlog/dev.py | 53 +++++++++++++++++++++++++++++++++++--------- tests/test_dev.py | 26 ++++++++++++++++++++++ 4 files changed, 72 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a0f4c53c..551015a8 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -30,7 +30,9 @@ Changes: `#144 `_ - ``structlog.dev.ConsoleRenderer`` now accepts a *force_colors* argument to output colored logs even if the destination is not a tty. Use this option if your logs are stored in files that are intended to be streamed to the console. - `#141 `_ +- ``structlog.dev.ConsoleRenderer`` now allows you to override the colors for individual levels, as well as to add new levels by adjusting the style map. + See the docs for ``ConsoleRenderer.default_level_styles`` for usage. + `#139 ` ---- diff --git a/docs/api.rst b/docs/api.rst index b8f3cba7..8ac7b95e 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -63,6 +63,7 @@ API Reference .. automodule:: structlog.dev .. autoclass:: ConsoleRenderer + :members: default_level_styles :mod:`threadlocal` Module diff --git a/src/structlog/dev.py b/src/structlog/dev.py index caad94a5..85dd7951 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -108,6 +108,9 @@ class ConsoleRenderer(object): Setting this to ``False`` is useful if you want to have human-readable non-ASCII output on Python 2. The `event` key is *never* :func:`repr()` -ed. + :param dict level_styles: When present, use these styles for colors. This + must be a dict from level names (strings) to colorama styles. The + default is the output of :meth:`ConsoleRenderer.default_level_styles` Requires the colorama_ package if *colors* is ``True``. @@ -117,9 +120,10 @@ class ConsoleRenderer(object): .. versionadded:: 16.1 *colors* .. versionadded:: 17.1 *repr_native_str* .. versionadded:: 18.1 *force_colors* + .. versionadded:: 18.1 *level_styles* """ def __init__(self, pad_event=_EVENT_WIDTH, colors=True, - force_colors=False, repr_native_str=False): + force_colors=False, repr_native_str=False, level_styles=None): if colors is True: if colorama is None: raise SystemError( @@ -141,16 +145,11 @@ def __init__(self, pad_event=_EVENT_WIDTH, colors=True, self._styles = styles self._pad_event = pad_event - self._level_to_color = { - "critical": styles.level_critical, - "exception": styles.level_exception, - "error": styles.level_error, - "warn": styles.level_warn, - "warning": styles.level_warn, - "info": styles.level_info, - "debug": styles.level_debug, - "notset": styles.level_notset, - } + + if level_styles is None: + self._level_to_color = self.default_level_styles(colors) + else: + self._level_to_color = level_styles for key in self._level_to_color.keys(): self._level_to_color[key] += styles.bright @@ -221,3 +220,35 @@ def __call__(self, _, __, event_dict): sio.write("\n" + exc) return sio.getvalue() + + @staticmethod + def default_level_styles(colors=True): + """ + Get the default styles for log levels + + This is intended to be used with :class:`ConsoleRenderer`'s + ``level_styles`` parameter. For example, if you are adding + custom levels in your home-grown + :func:`~structlog.stdlib.add_log_level` you could do:: + + my_styles = ConsoleRenderer.default_level_styles() + my_styles["EVERYTHING_IS_ON_FIRE"] = my_styles["critical"] + renderer = ConsoleRenderer(level_styles=my_styles) + + :param bool colors: Whether to use colorful styles. This must match the + `colors` parameter to :class:`ConsoleRenderer`. Default: True. + """ + if colors: + styles = _ColorfulStyles + else: + styles = _PlainStyles + return { + "critical": styles.level_critical, + "exception": styles.level_exception, + "error": styles.level_error, + "warn": styles.level_warn, + "warning": styles.level_warn, + "info": styles.level_info, + "debug": styles.level_debug, + "notset": styles.level_notset, + } diff --git a/tests/test_dev.py b/tests/test_dev.py index 89b65f0b..d44c4d0c 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -100,6 +100,32 @@ def test_level(self, cr, styles, padded): styles.kv_value + "bar" + styles.reset ) == rv + def test_init_accepts_overriding_levels(self, styles, padded): + """ + Stdlib levels are rendered aligned, in brackets, and color coded. + """ + my_styles = dev.ConsoleRenderer.default_level_styles( + colors=dev._has_colorama + ) + my_styles["MY_OH_MY"] = my_styles["critical"] + cr = dev.ConsoleRenderer( + colors=dev._has_colorama, level_styles=my_styles + ) + + # this would blow up if the level_styles override failed + rv = cr(None, None, { + "event": "test", "level": "MY_OH_MY", "foo": "bar" + }) + + assert ( + "[" + dev.RED + styles.bright + + dev._pad("MY_OH_MY", cr._longest_level) + + styles.reset + "] " + + padded + + styles.kv_key + "foo" + styles.reset + "=" + + styles.kv_value + "bar" + styles.reset + ) == rv + def test_logger_name(self, cr, styles, padded): """ Logger names are appended after the event. From ca328b70aa7fe976bab5119aad7fb4f35852f654 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 20 Jan 2018 15:03:56 +0100 Subject: [PATCH 0166/1520] Make default_level_style a verb --- CHANGELOG.rst | 6 +++--- docs/api.rst | 2 +- src/structlog/dev.py | 9 +++++---- tests/test_dev.py | 2 +- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 551015a8..ef6d1c8d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -30,9 +30,9 @@ Changes: `#144 `_ - ``structlog.dev.ConsoleRenderer`` now accepts a *force_colors* argument to output colored logs even if the destination is not a tty. Use this option if your logs are stored in files that are intended to be streamed to the console. -- ``structlog.dev.ConsoleRenderer`` now allows you to override the colors for individual levels, as well as to add new levels by adjusting the style map. - See the docs for ``ConsoleRenderer.default_level_styles`` for usage. - `#139 ` +- ``structlog.dev.ConsoleRenderer`` now accepts a *level_styles* argument for overriding the colors for individual levels, as well as to add new levels. + See the docs for ``ConsoleRenderer.get_default_level_styles()`` for usage. + `#139 `_ ---- diff --git a/docs/api.rst b/docs/api.rst index 8ac7b95e..547149c5 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -63,7 +63,7 @@ API Reference .. automodule:: structlog.dev .. autoclass:: ConsoleRenderer - :members: default_level_styles + :members: get_default_level_styles :mod:`threadlocal` Module diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 85dd7951..9f5443f4 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -110,7 +110,8 @@ class ConsoleRenderer(object): :func:`repr()` -ed. :param dict level_styles: When present, use these styles for colors. This must be a dict from level names (strings) to colorama styles. The - default is the output of :meth:`ConsoleRenderer.default_level_styles` + default can be obtained by calling + :meth:`ConsoleRenderer.get_default_level_styles` Requires the colorama_ package if *colors* is ``True``. @@ -147,7 +148,7 @@ def __init__(self, pad_event=_EVENT_WIDTH, colors=True, self._pad_event = pad_event if level_styles is None: - self._level_to_color = self.default_level_styles(colors) + self._level_to_color = self.get_default_level_styles(colors) else: self._level_to_color = level_styles @@ -222,7 +223,7 @@ def __call__(self, _, __, event_dict): return sio.getvalue() @staticmethod - def default_level_styles(colors=True): + def get_default_level_styles(colors=True): """ Get the default styles for log levels @@ -231,7 +232,7 @@ def default_level_styles(colors=True): custom levels in your home-grown :func:`~structlog.stdlib.add_log_level` you could do:: - my_styles = ConsoleRenderer.default_level_styles() + my_styles = ConsoleRenderer.get_default_level_styles() my_styles["EVERYTHING_IS_ON_FIRE"] = my_styles["critical"] renderer = ConsoleRenderer(level_styles=my_styles) diff --git a/tests/test_dev.py b/tests/test_dev.py index d44c4d0c..c753cced 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -104,7 +104,7 @@ def test_init_accepts_overriding_levels(self, styles, padded): """ Stdlib levels are rendered aligned, in brackets, and color coded. """ - my_styles = dev.ConsoleRenderer.default_level_styles( + my_styles = dev.ConsoleRenderer.get_default_level_styles( colors=dev._has_colorama ) my_styles["MY_OH_MY"] = my_styles["critical"] From 8dc9610f56c31956a28768f66d0228dd1ad4cccb Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 20 Jan 2018 16:02:07 +0100 Subject: [PATCH 0167/1520] Allow overriding exc_info in stdlib's exception method Fixes #149 --- CHANGELOG.rst | 2 ++ src/structlog/stdlib.py | 2 +- tests/test_stdlib.py | 20 +++++++++++++++----- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ef6d1c8d..b6cf0882 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -33,6 +33,8 @@ Changes: - ``structlog.dev.ConsoleRenderer`` now accepts a *level_styles* argument for overriding the colors for individual levels, as well as to add new levels. See the docs for ``ConsoleRenderer.get_default_level_styles()`` for usage. `#139 `_ +- ``structlog.stdlib.BoundLogger.exception()`` now uses the ``exc_info`` argument if it has been passed instead of setting it unconditionally to ``True``. + `#149 `_ ---- diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 53d82454..bb55245b 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -91,7 +91,7 @@ def exception(self, event=None, *args, **kw): Process event and call :meth:`logging.Logger.error` with the result, after setting ``exc_info`` to `True`. """ - kw['exc_info'] = True + kw.setdefault("exc_info", True) return self.error(event, *args, **kw) def log(self, level, event, *args, **kw): diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 5e615e45..929d4fff 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -210,12 +210,22 @@ def test_exception_exc_info(self): BoundLogger.exception sets exc_info=True. """ bl = BoundLogger(ReturnLogger(), [], {}) - assert ((), - {"exc_info": True, "event": "event"}) == bl.exception('event') - def test_exception_maps_to_error(self): - bl = BoundLogger(ReturnLogger(), [return_method_name], {}) - assert "error" == bl.exception("event") + assert ( + (), + {"exc_info": True, "event": "event"} + ) == bl.exception("event") + + def test_exception_exc_info_override(self): + """ + If *exc_info* is password to exception, it's used. + """ + bl = BoundLogger(ReturnLogger(), [], {}) + + assert ( + (), + {"exc_info": 42, "event": "event"} + ) == bl.exception("event", exc_info=42) class TestPositionalArgumentsFormatter(object): From 3a68db7c025d9e793800b0a72ff149304e978d0d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 20 Jan 2018 16:54:42 +0100 Subject: [PATCH 0168/1520] No I in a Team! --- docs/configuration.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.rst b/docs/configuration.rst index 1c50a57e..b3e16d9d 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -119,7 +119,7 @@ The :ref:`Twisted example ` shows how easy it is for Twisted. While neither allows for customization using parameters yet, they may do so in the future. Calling :func:`structlog.get_logger` without configuration gives you a perfectly useful :class:`structlog.PrintLogger` with the default values explained above. -I don't believe silent loggers are a sensible default. +We don't believe silent loggers are a sensible default. Where to Configure From e1c797bc66e9ee0771260f9fccff36af6d6c51ed Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 21 Jan 2018 09:17:13 +0100 Subject: [PATCH 0169/1520] Deprecate structlog[dev] You can't have structlog in requirements.txt/install_requires and at the same time structlog[dev] in dev-requiments.txt/extras_require anyways. --- CHANGELOG.rst | 4 +++- docs/getting-started.rst | 2 +- src/structlog/dev.py | 2 -- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b6cf0882..85feca40 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -18,7 +18,9 @@ Backward-incompatible changes: Deprecations: ^^^^^^^^^^^^^ -*none* +- The meaning of the ``structlog[dev]`` installation target will change from "colorful output" to "dependencies to develop ``structlog``" in 19.1.0. + + The main reason behind this decision is that it's impossible to have a ``structlog`` in your normal dependencies and additionally a ``structlog[dev]`` for developement (``pip`` will report an error). Changes: diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 42d1f0d4..32f1d606 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -14,7 +14,7 @@ Installation If you'd like colorful output in development (you know you do!), install using:: - $ pip install structlog[dev] + $ pip install structlog colorama Your First Log Entry diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 9f5443f4..bcf91476 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -24,8 +24,6 @@ _MISSING = ( "{who} requires the {package} package installed. " - "If you want to use the helpers from structlog.dev, it is strongly " - "recommended to install structlog using `pip install structlog[dev]`." ) _EVENT_WIDTH = 30 # pad the event name to so many characters From 15e30907e44003147d1b5f6811ddfaa8f61e0ecb Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 21 Jan 2018 10:03:13 +0100 Subject: [PATCH 0170/1520] Take Getting Started a bit further Ref #136 --- docs/getting-started.rst | 57 ++++++++++++++++++++++++++++++++++++---- tox.ini | 1 + 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 32f1d606..e3c9266a 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -33,11 +33,10 @@ And indeed, the simplest possible usage looks like this: Here, ``structlog`` takes full advantage of its hopefully useful default settings: - Output is sent to `standard out`_ instead of exploding into the user's face. - Yes, that seems a rather controversial attitude towards logging. - All keywords are formatted using :class:`structlog.dev.ConsoleRenderer`. That in turn uses `repr()`_ to serialize all values to strings. Thus, it's easy to add support for logging of your own objects\ [*]_. -- If you have `colorama `_ installed, it's even rendered in nice :doc:`colors `. +- If you have `colorama `_ installed, it's rendered in nice :doc:`colors `. It should be noted that even in most complex logging setups the example would still look just like that thanks to :ref:`configuration`. @@ -91,6 +90,55 @@ For ``structlog``, a log entry is just a dictionary called *event dict[ionary]*: If you're okay with giving up immutable local state for convenience, you can also use :ref:`thread/greenlet local storage ` for the context. +Manipulating Log Entries in Flight +---------------------------------- + +Now that your log events are dictionaries, it's also much easier to manipulate them than if it were plain strings. + +To fascilitate that, ``structlog`` has the concept of :doc:`processor chains `. +A processor is a callable like a function that receives the event dictionary along with two other arguments and returns a new event dictionary that may or may not differ from the one it got passed. +The next processor in the chain receives that returned dictionary instead of the original one. + +Let's assume you wanted to add a timestamp to every event dict. +The processor would look like this: + +.. doctest:: + + >>> import datetime + >>> def timestamper(_, __, event_dict): + ... event_dict["time"] = datetime.datetime.now().isoformat() + ... return event_dict + +Plain Python, plain dictionaries. +No you have to tell ``structlog`` about your processor by :doc:`configuring ` it: + +.. doctest:: + + >>> structlog.configure(processors=[timestamper, structlog.processors.KeyValueRenderer()]) + >>> structlog.get_logger().msg("hi") # doctest: +SKIP + event='hi' time='2018-01-21T09:37:36.976816' + + +Rendering +--------- + +Finally you want to have control over the actual format of your log entries. + +As you may have noticed in the previous section, renderers are just processors too. +It's also important to note, that they do not necessarily have to render your event dictionary to a string. +It depends on the *logger* that is wrapped by ``structlog`` what kind of input it should get. + +However, in most cases it's gonna be strings. + +So assuming you want to follow :doc:`best practices ` and render your event dictionary to JSON that is picked up by a log aggregation system like ELK or Graylog, ``structlog`` comes with batteries included -- you just have to tell it to use its :class:`~structlog.processors.JSONRenderer`: + +.. doctest:: + + >>> structlog.configure(processors=[structlog.processors.JSONRenderer()]) + >>> structlog.get_logger().msg("hi") + {"event": "hi"} + + .. _standard-library-lite: structlog and Standard Library's logging @@ -107,10 +155,9 @@ To make this common case as simple as possible, ``structlog`` comes with some to >>> import logging >>> logging.basicConfig() - >>> from structlog import get_logger, configure >>> from structlog.stdlib import LoggerFactory - >>> configure(logger_factory=LoggerFactory()) # doctest: +SKIP - >>> log = get_logger() + >>> structlog.configure(logger_factory=LoggerFactory()) # doctest: +SKIP + >>> log = structlog.get_logger() >>> log.warning('it works!', difficulty='easy') # doctest: +SKIP WARNING:structlog...:difficulty='easy' event='it works!' diff --git a/tox.ini b/tox.ini index acfbab5b..447f78cd 100644 --- a/tox.ini +++ b/tox.ini @@ -38,6 +38,7 @@ commands = basepython = python3.6 extras = docs +passenv = TERM setenv = PYTHONHASHSEED = 0 commands = From fa37e796ece03d50e9d97e361af7b8f8ba6ba4bf Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 21 Jan 2018 10:07:57 +0100 Subject: [PATCH 0171/1520] Braaand! --- docs/getting-started.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/getting-started.rst b/docs/getting-started.rst index e3c9266a..c2726b9e 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -141,8 +141,8 @@ So assuming you want to follow :doc:`best practices ` an .. _standard-library-lite: -structlog and Standard Library's logging ----------------------------------------- +``structlog`` and Standard Library's ``logging`` +------------------------------------------------ ``structlog``'s primary application isn't printing though. Instead, it's intended to wrap your *existing* loggers and **add** *structure* and *incremental context building* to them. From bffe439bd2b5951a86991ab96d5ecca73042fadc Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 22 Jan 2018 09:09:48 +0100 Subject: [PATCH 0172/1520] Streamline best practices --- docs/logging-best-practices.rst | 103 ++++++++------------------------ 1 file changed, 26 insertions(+), 77 deletions(-) diff --git a/docs/logging-best-practices.rst b/docs/logging-best-practices.rst index 441bdfad..78873c5a 100644 --- a/docs/logging-best-practices.rst +++ b/docs/logging-best-practices.rst @@ -1,109 +1,58 @@ Logging Best Practices ====================== -The best practice for you depends very much on your context. -To give you some pointers nevertheless, here are a few scenarios that may be applicable to you. - -Pull requests for further interesting approaches as well as refinements and more complete examples are very welcome. - - -Common Ideas ------------- - Logging is not a new concept and in no way special to Python. Logfiles have existed for decades and there's little reason to reinvent the wheel in our little world. -There are several concepts that are very well-solved in general and especially in heterogeneous environments, using special tooling for Python applications does more harm than good and makes the operations staff build dart board with your pictures. - Therefore let's rely on proven tools as much as possible and do only the absolutely necessary inside of Python\ [*]_. -A very nice approach is to simply log to `standard out`_ and let other tools take care of the rest. - -runit -^^^^^ - -One runner that makes this very easy is the venerable runit_ project which made it a part of its design: server processes don't detach but log to standard out instead. -There it gets processed by other software -- potentially by one of its own tools: svlogd_. -We use it extensively and it has proven itself extremely robust and capable; check out `this tutorial`_ if you'd like to try it. - -If you're not quite convinced and want an overview on running daemons, have a look at cue's `daemon showdown`_ that discusses the most common ones. - - -Local Logging -------------- - -There are basically two common ways to log to local logfiles: writing yourself into files and syslog. -Syslog -^^^^^^ +A simple but powerful approach is to log to unbuffered `standard out`_ and let other tools take care of the rest. +That can be your terminal window while developing, it can be systemd_ redirecting your log entries it to syslogd_, or your `cluster manager`_. +It doesn't matter where or how your application is running, it just works. -The simplest approach to logging is to forward your entries to the syslogd_. -Twisted, uwsgi, and runit support it directly. -It will happily add a timestamp and write wherever you tell it in its configuration. -You can also log from multiple processes into a single file and use your system's logrotate_ for log rotation. +This is why the popular `twelve-factor app methodology`_ suggests just that. -The only downside is that syslog has some quirks that show itself under high load like rate limits (`they can be switched off`_) and lost log entries. - - -runit's svlogd -^^^^^^^^^^^^^^ - -If you'll choose runit for running your daemons, svlogd_ is a nicer approach. -It receives the log entries via a UNIX pipe and acts on them which includes adding of parse-friendly timestamps in tai64n_ as well as filtering and log rotation. +.. [*] This is obviously a privileged UNIX-centric view but even Windows has tools and means for log management although we won't be able to discuss them here. Centralized Logging ------------------- -Nowadays you usually don't want your logfiles in compressed archives distributed over dozens -- if not thousands -- servers. -You want them at a single location; parsed and easy to query. - +Nowadays you usually don't want your logfiles in compressed archives distributed over dozens -- if not thousands -- servers or cluster nodes. +You want them in a single location; parsed, indexed and easy to search. -Syslog (Again!) -^^^^^^^^^^^^^^^ -The widely deployed syslog implementation rsyslog_ supports remote logging out-of-the-box. -Have a look at `this post`_ by Revolution Systems on the how. +ELK +^^^ -Since syslog is such a widespread solution, there are also ways to use it with basically any centralized product. +The ELK stack (Elasticsearch_, Logstash_, Kibana_) from Elastic is a great way to store, parse, and search your logs. +The way it works is that you have local log shippers like Filebeat_ that parse your log files and forward the log entries to your Logstash_ server. +Logstash parses the log entries and stores them in in Elasticsearch_. +Finally, you can view and search them in Kibana_. -Logstash with logstash-forwarder -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +If your log entries consist of a JSON dictionary, this is fairly easy and efficient. +All you have to do is to tell Logstash_ the name of you timestamp field. -Logstash_ is a great way to parse, save, and search your logs. -The general modus operandi is that you have log shippers that parse your log files and forward the log entries to your Logstash server and store is in elasticsearch_. -If your log entries consist of a JSON dictionary (and perhaps a tai64n_ timestamp), this is pretty easy and efficient. - -If you can't decide on a log shipper, logstash-forwarder_ (formerly known as Lumberjack) works really well. -When Logstash's ``lumberjack`` input is configured to use ``codec => "json"``, having ``structlog`` output JSON is all you need. -See the documentation on the :doc:`standard-library` for an example configuration. - - -Graylog2 -^^^^^^^^ +Graylog +^^^^^^^ Graylog_ goes one step further. It not only supports everything those above do (and then some); you can also log directly JSON entries towards it -- optionally even through an AMQP server (like RabbitMQ_) for better reliability. Additionally, `Graylog's Extended Log Format`_ (GELF) allows for structured data which makes it an obvious choice to use together with ``structlog``. -.. [*] This is obviously a privileged UNIX-centric view but even Windows has tools and means for log management although we won't be able to discuss them here. - -.. _Graylog: http://graylog2.org +.. _Graylog: https://www.graylog.org/ +.. _Elastic: https://www.elastic.co/ .. _Logstash: https://www.elastic.co/products/logstash -.. _logstash-forwarder: https://github.com/elastic/logstash-forwarder -.. _RabbitMQ: http://www.rabbitmq.com +.. _Kibana: https://www.elastic.co/products/kibana +.. _Elasticsearch: https://www.elastic.co/products/elasticsearch .. _`Graylog's Extended Log Format`: http://docs.graylog.org/en/latest/pages/gelf.html -.. _`daemon showdown`: https://web.archive.org/web/20130907200323/http://tech.cueup.com/blog/2013/03/08/running-daemons/ .. _`standard out`: https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29 -.. _`they can be switched off`: http://blog.abhijeetr.com/2013/01/disable-rate-limiting-in-rsyslog-v5.html -.. _`this post`: http://www.revsys.com/blog/2010/aug/26/centralized-logging-fun-and-profit/ -.. _`this tutorial`: https://rubyists.github.io/2011/05/02/runit-for-ruby-and-everything-else.html -.. _logrotate: http://manpages.ubuntu.com/manpages/xenial/en/man8/logrotate.8.html -.. _rsyslog: http://www.rsyslog.com -.. _runit: http://smarden.org/runit/ -.. _svlogd: http://smarden.org/runit/svlogd.8.html .. _syslogd: https://en.wikipedia.org/wiki/Syslogd -.. _tai64n: http://cr.yp.to/daemontools/tai64n.html -.. _elasticsearch: https://www.elastic.co/products/elasticsearch +.. _`twelve-factor app methodology`: https://12factor.net/logs +.. _systemd: https://en.wikipedia.org/wiki/Systemd +.. _`cluster manager`: https://kubernetes.io/docs/concepts/cluster-administration/logging/ +.. _Filebeat: https://github.com/elastic/beats/tree/master/filebeat +.. _RabbitMQ: https://www.rabbitmq.com/ From 4dd04f40217e83d84dcb2f2fc63544f17e9c4504 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 22 Jan 2018 09:17:34 +0100 Subject: [PATCH 0173/1520] Clean up links --- CHANGELOG.rst | 4 ++-- README.rst | 2 +- docs/conf.py | 6 ------ docs/configuration.rst | 2 +- docs/license.rst | 2 +- docs/loggers.rst | 6 ++---- docs/performance.rst | 5 ++--- src/structlog/processors.py | 4 ++-- 8 files changed, 11 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 85feca40..217a95b0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -231,8 +231,8 @@ Changes: `#42 `_ - Pass positional arguments to stdlib wrapped loggers that use string formatting. `#19 `_ -- ``structlog`` is now dually licensed under the `Apache License, Version 2 `_ and the `MIT `_ license. - Therefore it is now legal to use structlog with `GPLv2 `_-licensed projects. +- ``structlog`` is now dually licensed under the `Apache License, Version 2 `_ and the `MIT `_ license. + Therefore it is now legal to use structlog with `GPLv2 `_-licensed projects. `#28 `_ - Add ``structlog.stdlib.BoundLogger.exception``. `#22 `_ diff --git a/README.rst b/README.rst index 90a1f781..36bbb033 100644 --- a/README.rst +++ b/README.rst @@ -113,7 +113,7 @@ Output Project Information =================== -``structlog`` is dual-licensed under `Apache License, version 2 `_ and `MIT `_, available from `PyPI `_, the source code can be found on `GitHub `_, the documentation at http://www.structlog.org/. +``structlog`` is dual-licensed under `Apache License, version 2 `_ and `MIT `_, available from `PyPI `_, the source code can be found on `GitHub `_, the documentation at http://www.structlog.org/. ``structlog`` targets Python 2.7, 3.4 and newer, and PyPy. diff --git a/docs/conf.py b/docs/conf.py index 0c4936b1..1a54ae95 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -326,12 +326,6 @@ def find_version(*file_paths): # epub_tocdup = True linkcheck_ignore = [ - # 404s for unknown reasons - r'http://graylog2.org.*', - # Times out way too often - r'http://www.rabbitmq.com', - # throws a 406 for unknown reasons - r'http://www.elasticsearch.org', ] # Twisted's trac tends to be slow diff --git a/docs/configuration.rst b/docs/configuration.rst index b3e16d9d..badc8b17 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -137,7 +137,7 @@ If you use standard library's logging, it makes sense to configure them next to See `Logging Application Errors `_. **Pyramid** - `Application constructor `_. + `Application constructor `_. **Twisted** The `plugin definition `_ is the best place. diff --git a/docs/license.rst b/docs/license.rst index fc176661..425ca847 100644 --- a/docs/license.rst +++ b/docs/license.rst @@ -1,7 +1,7 @@ License and Hall of Fame ======================== -``structlog`` is licensed both under the `Apache License, Version 2 `_ and the `MIT license `_. +``structlog`` is licensed both under the `Apache License, Version 2 `_ and the `MIT license `_. The reason for that is to be both protected against patent claims by own contributors and still allow the usage within GPLv2 software. For more legal details, see `this issue `_ on the bug tracker of PyCA's cryptography. diff --git a/docs/loggers.rst b/docs/loggers.rst index 6b7357d5..aea7fd32 100644 --- a/docs/loggers.rst +++ b/docs/loggers.rst @@ -86,16 +86,14 @@ Additionally, the following arguments are allowed too: Printing and Testing -------------------- -To save you the hassle of using standard library logging for simple standard out logging, ``structlog`` ships a :class:`~structlog.PrintLogger` that can log into arbitrary files -- including standard out (which is the default if no file is passed into the constructor): +To save you the hassle and slowdown of using standard library's ``logging`` for standard out logging, ``structlog`` ships a :class:`~structlog.PrintLogger` that can log into arbitrary files -- including standard out (which is the default if no file is passed into the constructor): .. doctest:: >>> from structlog import PrintLogger - >>> PrintLogger().info('hello world!') + >>> PrintLogger().info("hello world!") hello world! -It's handy for both examples and in combination with tools like `runit `_ or `stdout/stderr-forwarding `_. - Additionally -- mostly for unit testing -- ``structlog`` also ships with a logger that just returns whatever it gets passed into it: :class:`~structlog.ReturnLogger`. .. doctest:: diff --git a/docs/performance.rst b/docs/performance.rst index 4cb218b7..4772665c 100644 --- a/docs/performance.rst +++ b/docs/performance.rst @@ -36,11 +36,10 @@ Here are a few hints how to get most out of ``structlog`` in production: This has the only drawback is that later calls on :func:`~structlog.configure` don't have any effect on already cached loggers -- that shouldn't matter outside of testing though. #. Use a faster JSON serializer than the standard library. - Possible alternatives are among others simplejson_, UltraJSON_, or RapidJSON_ (Python 3 only):: + Possible alternatives are among others simplejson_ or RapidJSON_ (Python 3 only):: structlog.processors.JSONRenderer(serializer=rapidjson.dumps) .. _simplejson: https://simplejson.readthedocs.io/ -.. _UltraJSON: https://github.com/esnme/ultrajson/ -.. _RapidJSON: https://pypi.python.org/pypi/python-rapidjson/ +.. _RapidJSON: https://pypi.org/project/python-rapidjson/ diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 5001d493..42d69bd5 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -142,8 +142,8 @@ class JSONRenderer(object): :param callable serializer: A :func:`json.dumps`-compatible callable that will be used to format the string. This can be used to use alternative JSON encoders like `simplejson - `_ or `RapidJSON - `_ (faster but Python + `_ or `RapidJSON + `_ (faster but Python 3-only) (default: :func:`json.dumps`). .. versionadded:: 0.2.0 From 0c58d06535e583362be85fb8fa921e91a9c9504f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 22 Jan 2018 09:20:06 +0100 Subject: [PATCH 0174/1520] Paul's homepage is currently broken --- docs/why.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/why.rst b/docs/why.rst index 9c8200c7..9d6f1d85 100644 --- a/docs/why.rst +++ b/docs/why.rst @@ -11,7 +11,7 @@ Why… I believe these presumptions are **no longer correct** in server side software. - ---`Paul Querna `_ + ---`Paul Querna`_ Structured logging means that you don't write hard-to-parse and hard-to-keep-consistent prose in your logs but that you log *events* that happen in a *context* instead. @@ -38,3 +38,5 @@ Additionally, ``structlog`` offers you a flexible way to *filter* and *modify* y The possibilities include :class:`logging in JSON `, adding arbitrary meta data like :class:`timestamps `, counting events as metrics, or :ref:`dropping log entries ` caused by your monitoring system. ``structlog`` is also flexible enough to allow transparent :ref:`thread local ` storage for your context if you don't like the idea of local bindings as in the example above. + +.. _`Paul Querna`: https://web.archive.org/web/20170801134840/https://journal.paul.querna.org/articles/2011/12/26/log-for-machines-in-json/ From 9732ac660618e5c02375881db08e14ecb806f8bc Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 22 Jan 2018 10:43:45 +0100 Subject: [PATCH 0175/1520] Use dict for context by default if it's ordered --- CHANGELOG.rst | 1 + docs/getting-started.rst | 2 +- docs/loggers.rst | 3 ++- src/structlog/_config.py | 11 ++++++++++- tests/test_config.py | 20 ++++++++++++++++++++ 5 files changed, 34 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 217a95b0..30273910 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -37,6 +37,7 @@ Changes: `#139 `_ - ``structlog.stdlib.BoundLogger.exception()`` now uses the ``exc_info`` argument if it has been passed instead of setting it unconditionally to ``True``. `#149 `_ +- Default configuration now uses plain ``dict``\ s on Python 3.6+ and PyPy since they are ordered by default. ---- diff --git a/docs/getting-started.rst b/docs/getting-started.rst index c2726b9e..80594c3a 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -85,7 +85,7 @@ For ``structlog``, a log entry is just a dictionary called *event dict[ionary]*: - As soon as an *event* happens -- which is a dictionary too -- it is merged together with the *context* to an *event dict* and logged out. - If you don't like the concept of pre-building a context: just don't! Convenient key-value-based logging is great to have on its own. -- To keep as much order of the keys as possible, an :class:`collections.OrderedDict` is used for the context by default. +- To keep as much order of the keys as possible, an :class:`collections.OrderedDict` is used for the context by default for Pythons that do not have ordered dictionaries by default (notably all versions of CPython before 3.6). - The recommended way of binding values is the one in these examples: creating new loggers with a new context. If you're okay with giving up immutable local state for convenience, you can also use :ref:`thread/greenlet local storage ` for the context. diff --git a/docs/loggers.rst b/docs/loggers.rst index aea7fd32..619668eb 100644 --- a/docs/loggers.rst +++ b/docs/loggers.rst @@ -60,7 +60,8 @@ As you can see, it accepts one mandatory and a few optional arguments: The class to save your context in. Particularly useful for :ref:`thread local context storage `. - Default is :class:`collections.OrderedDict`. + On Python versions that have ordered dictionaries (Python 3.6+, PyPy) the default is a plain :class:`dict`. + For everything else it's :class:`collections.OrderedDict`. Additionally, the following arguments are allowed too: diff --git a/src/structlog/_config.py b/src/structlog/_config.py index b87f13ae..27958f8d 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -8,6 +8,8 @@ from __future__ import absolute_import, division, print_function +import platform +import sys import warnings from collections import OrderedDict @@ -24,7 +26,14 @@ TimeStamper(fmt="%Y-%m-%d %H:%M.%S", utc=False), ConsoleRenderer(colors=_has_colorama), ] -_BUILTIN_DEFAULT_CONTEXT_CLASS = OrderedDict +if ( + sys.version_info[:2] >= (3, 6) or + platform.python_implementation() == "PyPy" +): + # Python 3.6+ and PyPy have ordered dicts. + _BUILTIN_DEFAULT_CONTEXT_CLASS = dict +else: + _BUILTIN_DEFAULT_CONTEXT_CLASS = OrderedDict _BUILTIN_DEFAULT_WRAPPER_CLASS = BoundLogger _BUILTIN_DEFAULT_LOGGER_FACTORY = PrintLoggerFactory() _BUILTIN_CACHE_LOGGER_ON_FIRST_USE = False diff --git a/tests/test_config.py b/tests/test_config.py index 5fd50b06..f7c19e0d 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -4,8 +4,12 @@ from __future__ import absolute_import, division, print_function +import platform +import sys import warnings +from collections import OrderedDict + import pytest from pretend import call, call_recorder, stub @@ -34,6 +38,22 @@ class Wrapper(BoundLoggerBase): """ +def test_default_context_class(): + """ + Default context class is dict on Python 3.6+ and PyPy, OrderedDict + otherwise. + """ + if ( + platform.python_implementation() == "PyPy" or + sys.version_info[:2] >= (3, 6) + ): + cls = dict + else: + cls = OrderedDict + + assert cls is _BUILTIN_DEFAULT_CONTEXT_CLASS + + class TestConfigure(object): def teardown_method(self, method): reset_defaults() From e581832759bef8fc7e25bdd3bae659337945daa2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 22 Jan 2018 11:19:34 +0100 Subject: [PATCH 0176/1520] Simplify main docs page --- README.rst | 23 ++++++++++++++--------- docs/index.rst | 20 +++++++++++++++----- docs/twisted.rst | 4 ++++ docs/why.rst | 25 ++++++------------------- 4 files changed, 39 insertions(+), 33 deletions(-) diff --git a/README.rst b/README.rst index 36bbb033..19b7a58a 100644 --- a/README.rst +++ b/README.rst @@ -3,7 +3,6 @@ :width: 256px :target: http://www.structlog.org/ -======================================== structlog: Structured Logging for Python ======================================== @@ -21,16 +20,20 @@ structlog: Structured Logging for Python .. image:: https://www.irccloud.com/invite-svg?channel=%23structlog&hostname=irc.freenode.net&port=6697&ssl=1 :target: https://www.irccloud.com/invite?channel=%23structlog&hostname=irc.freenode.net&port=6697&ssl=1 -.. begin +.. -begin-short- ``structlog`` makes logging in Python less painful and more powerful by adding structure to your log entries. It's up to you whether you want ``structlog`` to take care about the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's ``logging`` module. *No* `monkey patching `_ involved in either case. +.. -end-short- + + +.. -begin-spiel- Easier Logging -============== +-------------- You can stop writing prose and start thinking in terms of an event that happens in the context of key/value pairs: @@ -45,7 +48,7 @@ Each log entry is a meaningful dictionary instead of an opaque string now! Data Binding -============ +------------ Since log entries are dictionaries, you can start binding and re-binding key/value pairs to your loggers to ensure they are present in every following logging call: @@ -58,7 +61,7 @@ Since log entries are dictionaries, you can start binding and re-binding key/val Powerful Pipelines -================== +------------------ Each log entry goes through a `processor pipeline `_ that is just a chain of functions that receive a dictionary and return a new dictionary that gets fed into the next function. That allows for simple but powerful data manipulation: @@ -80,7 +83,7 @@ There are `plenty of processors `_ and `MIT `_, available from `PyPI `_, the source code can be found on `GitHub `_, the documentation at http://www.structlog.org/. diff --git a/docs/index.rst b/docs/index.rst index ee4eefa7..5c27ed49 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -5,8 +5,15 @@ Structured Logging for Python Release v\ |version| (:doc:`What's new? `). .. include:: ../README.rst - :start-after: begin - :end-before: -end- + :start-after: -begin-short- + :end-before: -end-short- + + +First steps: + +- If you're not sure whether ``structlog`` is for you, have a look at :doc:`why`. +- If you can't wait to log your first entry, start at :doc:`getting-started` and then work yourself through the basic docs. +- Once you have basic grasp of how ``structlog`` works, acquaint yourself with the `integrations <#integration-with-existing-systems>`_ structlog is shipping with. User's Guide @@ -17,7 +24,7 @@ Basics ------ .. toctree:: - :maxdepth: 2 + :maxdepth: 1 why getting-started @@ -36,7 +43,7 @@ Integration with Existing Systems However it comes with special wrappers for the Python standard library and Twisted that are optimized for their respective underlying loggers and contain less magic. .. toctree:: - :maxdepth: 2 + :maxdepth: 1 standard-library twisted @@ -62,8 +69,11 @@ API Reference api +Project Information +=================== + .. include:: ../README.rst - :start-after: -end- + :start-after: -begin-meta- .. toctree:: :maxdepth: 1 diff --git a/docs/twisted.rst b/docs/twisted.rst index 2ad4b6f2..af064a20 100644 --- a/docs/twisted.rst +++ b/docs/twisted.rst @@ -5,6 +5,10 @@ Twisted Since :func:`sys.exc_clear` has been dropped in Python 3, there is currently no way to avoid multiple tracebacks in your log files if using ``structlog`` together with Twisted on Python 3. +.. note:: + + ``structlog`` currently only supports the legacy -- but still perfectly working -- Twisted logging system found in ``twisted.python.log``. + Concrete Bound Logger --------------------- diff --git a/docs/why.rst b/docs/why.rst index 9d6f1d85..c81c83ea 100644 --- a/docs/why.rst +++ b/docs/why.rst @@ -1,8 +1,9 @@ +==== Why… ==== …Structured Logging? ---------------------- +==================== I believe the widespread use of format strings in logging is based on two presumptions: @@ -17,26 +18,12 @@ Structured logging means that you don't write hard-to-parse and hard-to-keep-con …structlog? ------------- - -Because it's easy and you don't have to replace your underlying logger (but you can!) -- you just add structure to your log entries and format them to strings before they hit your real loggers. - -``structlog`` supports you with accepting key/value pairs as arguments, building your context as you go (e.g. if a user logs in, you bind their user name to your current logger) and log events when they happen (i.e. the user does something log-worthy): - -.. doctest:: - - >>> from structlog import get_logger - >>> log = get_logger() - >>> log = log.bind(user='anonymous', some_key=23) - >>> log = log.bind(user='hynek', another_key=42) - >>> log.info('user.logged_in', happy=True) # doctest: +SKIP - 2016-04-20 16:20.13 user.logged_in another_key=42 happy=True some_key=23 user='hynek' +=========== -This ability to bind key/values pairs to a logger frees you from using conditionals, closures, or boilerplate methods to log out all relevant data. +.. include:: ../README.rst + :start-after: -begin-spiel- + :end-before: -end-spiel- -Additionally, ``structlog`` offers you a flexible way to *filter* and *modify* your log entries using so called :ref:`processors ` before the entry is passed to your real logger. -The possibilities include :class:`logging in JSON `, adding arbitrary meta data like :class:`timestamps `, counting events as metrics, or :ref:`dropping log entries ` caused by your monitoring system. -``structlog`` is also flexible enough to allow transparent :ref:`thread local ` storage for your context if you don't like the idea of local bindings as in the example above. .. _`Paul Querna`: https://web.archive.org/web/20170801134840/https://journal.paul.querna.org/articles/2011/12/26/log-for-machines-in-json/ From f2a01251ef374e252b7fa524d250d8d5a99217b8 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 22 Jan 2018 11:22:11 +0100 Subject: [PATCH 0177/1520] Nobody cares about monkey patching --- README.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/README.rst b/README.rst index 19b7a58a..99716629 100644 --- a/README.rst +++ b/README.rst @@ -25,7 +25,6 @@ structlog: Structured Logging for Python ``structlog`` makes logging in Python less painful and more powerful by adding structure to your log entries. It's up to you whether you want ``structlog`` to take care about the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's ``logging`` module. -*No* `monkey patching `_ involved in either case. .. -end-short- From 05f6d8468d26dc64c6d4c45e757a842b18c2413b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 22 Jan 2018 11:23:17 +0100 Subject: [PATCH 0178/1520] Braaand --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 99716629..474ebcb2 100644 --- a/README.rst +++ b/README.rst @@ -3,8 +3,8 @@ :width: 256px :target: http://www.structlog.org/ -structlog: Structured Logging for Python -======================================== +``structlog``: Structured Logging for Python +============================================ .. image:: https://readthedocs.org/projects/structlog/badge/?version=stable :target: https://structlog.readthedocs.io/en/stable/?badge=stable From d4543dba9fda5da6e30ce2efa7bfb3cfd47825ae Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 22 Jan 2018 12:05:31 +0100 Subject: [PATCH 0179/1520] Add structlog.get_config and structlog.is_configured This allows for configuration introspection. Fixes #128 --- CHANGELOG.rst | 2 ++ docs/api.rst | 4 +++ docs/configuration.rst | 30 ++++++++++++++++--- src/structlog/__init__.py | 8 +++-- src/structlog/_config.py | 62 ++++++++++++++++++++++++++++----------- tests/test_config.py | 36 ++++++++++++++++------- 6 files changed, 107 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 30273910..74ae8c19 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -38,6 +38,8 @@ Changes: - ``structlog.stdlib.BoundLogger.exception()`` now uses the ``exc_info`` argument if it has been passed instead of setting it unconditionally to ``True``. `#149 `_ - Default configuration now uses plain ``dict``\ s on Python 3.6+ and PyPy since they are ordered by default. +- Added ``structlog.is_configured()`` to check whether or not ``structlog`` has been configured. +- Added ``structlog.get_config()`` to introspect current configuration. ---- diff --git a/docs/api.rst b/docs/api.rst index 547149c5..08f5dda3 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -38,6 +38,10 @@ API Reference .. autofunction:: reset_defaults +.. autofunction:: is_configured + +.. autofunction:: get_config + .. autoclass:: BoundLogger :members: new, bind, unbind diff --git a/docs/configuration.rst b/docs/configuration.rst index badc8b17..1f38de26 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -8,7 +8,7 @@ Global Defaults --------------- To make logging as unintrusive and straight-forward to use as possible, ``structlog`` comes with a plethora of configuration options and convenience functions. -Let me start at the end and introduce you to the ultimate convenience function that relies purely on configuration: :func:`structlog.get_logger` (and its Twisted-friendly alias :func:`structlog.getLogger`). +Let me start at the end and introduce you to the ultimate convenience function that relies purely on configuration: :func:`structlog.get_logger` (and its camelCase-friendly alias :func:`structlog.getLogger` for y'all Twisted and Zope aficionados). The goal is to reduce your per-file logging boilerplate to:: @@ -17,7 +17,7 @@ The goal is to reduce your per-file logging boilerplate to:: while still giving you the full power via configuration. -To achieve that you'll have to call :func:`structlog.configure` on app initialization (of course, only if you're not content with the defaults). +To achieve that you'll have to call :func:`structlog.configure` on app initialization. The :ref:`example ` from the previous chapter could thus have been written as following: .. testcleanup:: * @@ -25,6 +25,11 @@ The :ref:`example ` from the previous chapter could thus have been written import structlog structlog.reset_defaults() +.. testsetup:: * + + import structlog + structlog.reset_defaults() + .. testsetup:: config_wrap_logger, config_get_logger from structlog import PrintLogger, configure, reset_defaults, wrap_logger, get_logger @@ -53,16 +58,33 @@ In fact, it could even be written like because :class:`~structlog.processors.PrintLogger` is the default ``LoggerFactory`` used (see :ref:`logger-factories`). +You can call :func:`structlog.configure` repeatedly and only set one or more settings -- the rest will not be affected. + ``structlog`` tries to behave in the least surprising way when it comes to handling defaults and configuration: #. Arguments passed to :func:`structlog.wrap_logger` *always* take the highest precedence over configuration. That means that you can overwrite whatever you've configured for each logger respectively. -#. If you leave them on `None`, ``structlog`` will check whether you've configured default values using :func:`structlog.configure` and uses them if so. -#. If you haven't configured or passed anything at all, the default fallback values are used which means :class:`collections.OrderedDict` for context and ``[``:class:`~structlog.processors.StackInfoRenderer`, :func:`~structlog.processors.format_exc_info`, :class:`~structlog.processors.KeyValueRenderer`\ ``]`` for the processor chain, and `False` for `cache_logger_on_first_use`. +#. If you leave them on ``None``, ``structlog`` will check whether you've configured default values using :func:`structlog.configure` and uses them if so. +#. If you haven't configured or passed anything at all, the default fallback values try to be convenient and development-friendly. If necessary, you can always reset your global configuration back to default values using :func:`structlog.reset_defaults`. That can be handy in tests. +At any time, you can check whether and how ``structlog`` is configured: + +.. doctest:: + + >>> structlog.is_configured() + False + >>> class MyDict(dict): pass + >>> structlog.configure(context_class=MyDict) + >>> structlog.is_configured() + True + >>> cfg = structlog.get_config() + >>> cfg["context_class"] + + + .. note:: Since you will call :func:`structlog.wrap_logger` (or one of the ``get_logger()`` functions) most likely at import time and thus before you had a chance to configure ``structlog``, they return a **proxy** that returns a correct wrapped logger on first ``bind()``/``new()``. diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 35660565..c9e20b0a 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -11,8 +11,8 @@ from structlog import dev, processors, stdlib, threadlocal from structlog._base import BoundLoggerBase from structlog._config import ( - configure, configure_once, get_logger, getLogger, reset_defaults, - wrap_logger + configure, configure_once, get_config, get_logger, getLogger, + is_configured, reset_defaults, wrap_logger ) from structlog._generic import BoundLogger from structlog._loggers import ( @@ -50,9 +50,11 @@ "ReturnLoggerFactory", "configure", "configure_once", + "dev", "getLogger", + "get_config", "get_logger", - "dev", + "is_configured", "processors", "reset_defaults", "stdlib", diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 27958f8d..190a233a 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -57,6 +57,40 @@ class _Configuration(object): """ +def is_configured(): + """ + Return whether ``structlog`` has been configured. + + If ``False``, ``structlog`` is running with builtin defaults. + + :rtype: bool + + .. versionadded: 18.1 + """ + return _CONFIG.is_configured + + +def get_config(): + """ + Get a dictionary with the current configuration. + + .. note:: + + Changes to the returned dictionary do *not* affect ``structlog``. + + :rtype: dict + + .. versionadded: 18.1 + """ + return { + "processors": _CONFIG.default_processors, + "context_class": _CONFIG.default_context_class, + "wrapper_class": _CONFIG.default_wrapper_class, + "logger_factory": _CONFIG.logger_factory, + "cache_logger_on_first_use": _CONFIG.cache_logger_on_first_use, + } + + def get_logger(*args, **initial_values): """ Convenience function that returns a logger according to configuration. @@ -139,9 +173,11 @@ def configure(processors=None, wrapper_class=None, context_class=None, They are used if :func:`wrap_logger` has been called without arguments. - Also sets the global class attribute :attr:`is_configured` to `True` on - first call. Can be called several times, keeping an argument at `None` - leaves is unchanged from the current setting. + Can be called several times, keeping an argument at `None` leaves is + unchanged from the current setting. + + After calling for the first time, :func:`is_configured` starts returning + ``True``. Use :func:`reset_defaults` to undo your changes. @@ -163,11 +199,11 @@ def configure(processors=None, wrapper_class=None, context_class=None, _CONFIG.is_configured = True if processors is not None: _CONFIG.default_processors = processors - if wrapper_class: + if wrapper_class is not None: _CONFIG.default_wrapper_class = wrapper_class - if context_class: + if context_class is not None: _CONFIG.default_context_class = context_class - if logger_factory: + if logger_factory is not None: _CONFIG.logger_factory = logger_factory if cache_logger_on_first_use is not None: _CONFIG.cache_logger_on_first_use = cache_logger_on_first_use @@ -180,7 +216,7 @@ def configure_once(*args, **kw): It does *not* matter whether is was configured using :func:`configure` or :func:`configure_once` before. - Raises a RuntimeWarning if repeated configuration is attempted. + Raises a :class:`RuntimeWarning` if repeated configuration is attempted. """ if not _CONFIG.is_configured: configure(*args, **kw) @@ -190,17 +226,9 @@ def configure_once(*args, **kw): def reset_defaults(): """ - Resets global default values to builtins. - - That means [:class:`~structlog.processors.StackInfoRenderer`, - :func:`~structlog.processors.format_exc_info`, - :class:`~structlog.processors.TimeStamper`, - :class:`~structlog.dev.ConsoleRenderer`] for *processors*, - :class:`~structlog.BoundLogger` for *wrapper_class*, ``OrderedDict`` for - *context_class*, :class:`~structlog.PrintLoggerFactory` for - *logger_factory*, and `False` for *cache_logger_on_first_use*. + Resets global default values to builtin defaults. - Also sets the global class attribute :attr:`is_configured` to `False`. + :func:`is_configured` starts returning ``False`` afterwards. """ _CONFIG.is_configured = False _CONFIG.default_processors = _BUILTIN_DEFAULT_PROCESSORS[:] diff --git a/tests/test_config.py b/tests/test_config.py index f7c19e0d..dddc9542 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -15,12 +15,13 @@ from pretend import call, call_recorder, stub from six import PY3 +import structlog + from structlog._base import BoundLoggerBase from structlog._config import ( _BUILTIN_DEFAULT_CONTEXT_CLASS, _BUILTIN_DEFAULT_LOGGER_FACTORY, _BUILTIN_DEFAULT_PROCESSORS, _BUILTIN_DEFAULT_WRAPPER_CLASS, _CONFIG, - BoundLoggerLazyProxy, configure, configure_once, get_logger, - reset_defaults, wrap_logger + BoundLoggerLazyProxy, configure, configure_once, get_logger, wrap_logger ) @@ -56,20 +57,38 @@ def test_default_context_class(): class TestConfigure(object): def teardown_method(self, method): - reset_defaults() + structlog.reset_defaults() + + def test_get_config_is_configured(self): + """ + Return value of structlog.get_config() works as input for + structlog.configure(). is_configured() reflects the state of + configuration. + """ + assert False is structlog.is_configured() + + structlog.configure(**structlog.get_config()) + + assert True is structlog.is_configured() + + structlog.reset_defaults() + + assert False is structlog.is_configured() def test_configure_all(self, proxy): x = stub() configure(processors=[x], context_class=dict) b = proxy.bind() + assert [x] == b._processors assert dict is b._context.__class__ def test_reset(self, proxy): x = stub() configure(processors=[x], context_class=dict, wrapper_class=Wrapper) - reset_defaults() + structlog.reset_defaults() b = proxy.bind() + assert [x] != b._processors assert _BUILTIN_DEFAULT_PROCESSORS == b._processors assert isinstance(b, _BUILTIN_DEFAULT_WRAPPER_CLASS) @@ -95,11 +114,6 @@ def test_configure_sets_is_configured(self): configure() assert True is _CONFIG.is_configured - def test_rest_resets_is_configured(self): - configure() - reset_defaults() - assert False is _CONFIG.is_configured - def test_configures_logger_factory(self): def f(): pass @@ -110,7 +124,7 @@ def f(): class TestBoundLoggerLazyProxy(object): def teardown_method(self, method): - reset_defaults() + structlog.reset_defaults() def test_repr(self): p = BoundLoggerLazyProxy( @@ -260,7 +274,7 @@ def foo(self): class TestFunctions(object): def teardown_method(self, method): - reset_defaults() + structlog.reset_defaults() def test_wrap_passes_args(self): logger = object() From 3b20000cd07dd2c128608746ba33c34e3519bd08 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 22 Jan 2018 12:37:33 +0100 Subject: [PATCH 0180/1520] Some configuration polish --- docs/configuration.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/configuration.rst b/docs/configuration.rst index 1f38de26..95b68711 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -87,9 +87,10 @@ At any time, you can check whether and how ``structlog`` is configured: .. note:: - Since you will call :func:`structlog.wrap_logger` (or one of the ``get_logger()`` functions) most likely at import time and thus before you had a chance to configure ``structlog``, they return a **proxy** that returns a correct wrapped logger on first ``bind()``/``new()``. + Since you will call :func:`structlog.get_logger` most likely in module scope, they run at import time before you had a chance to configure ``structlog``. + Hence they return a **lazy proxy** that returns a correct wrapped logger on first ``bind()``/``new()``. - Therefore, you must not call ``new()`` or ``bind()`` in module scope! + Therefore, you must never call ``new()`` or ``bind()`` in module or class scope becauce otherwise you will receive a logger configured with ``structlog``'s default values. Use :func:`~structlog.get_logger`\ 's ``initial_values`` to achieve pre-populated contexts. To enable you to log with the module-global logger, it will create a temporary BoundLogger and relay the log calls to it on *each call*. @@ -140,7 +141,7 @@ The :ref:`Twisted example ` shows how easy it is for Twisted. `LoggerFactory()`-style factories always need to get passed as *instances* like in the examples above. While neither allows for customization using parameters yet, they may do so in the future. -Calling :func:`structlog.get_logger` without configuration gives you a perfectly useful :class:`structlog.PrintLogger` with the default values explained above. +Calling :func:`structlog.get_logger` without configuration gives you a perfectly useful :class:`structlog.PrintLogger`. We don't believe silent loggers are a sensible default. From 0da95b406a98316500bad90264810a34db60aa3a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 22 Jan 2018 13:26:30 +0100 Subject: [PATCH 0181/1520] Single quotes are disgusting --- docs/api.rst | 22 +++++------ docs/code_examples/flask_/some_module.py | 3 +- .../getting-started/imaginary_web.py | 14 +++---- .../getting-started/imaginary_web_better.py | 16 ++++---- .../processors/conditional_dropper.py | 8 ++-- docs/code_examples/twisted_echo.py | 2 +- docs/configuration.rst | 10 ++--- docs/custom-wrappers.rst | 12 +++--- docs/development.rst | 2 +- docs/examples.rst | 12 +++--- docs/getting-started.rst | 6 +-- docs/loggers.rst | 14 +++---- docs/performance.rst | 2 +- docs/processors.rst | 19 +++++----- docs/standard-library.rst | 8 ++-- docs/thread-local.rst | 6 +-- docs/twisted.rst | 2 +- src/structlog/_base.py | 8 ++-- src/structlog/_loggers.py | 13 +++---- src/structlog/processors.py | 36 +++++++++--------- src/structlog/stdlib.py | 38 +++++++++---------- tests/test_loggers.py | 30 ++++++++++----- 22 files changed, 145 insertions(+), 138 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 08f5dda3..684c223b 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -105,7 +105,7 @@ API Reference .. doctest:: >>> from structlog.processors import JSONRenderer - >>> JSONRenderer(sort_keys=True)(None, None, {'a': 42, 'b': [1, 2, 3]}) + >>> JSONRenderer(sort_keys=True)(None, None, {"a": 42, "b": [1, 2, 3]}) '{"a": 42, "b": [1, 2, 3]}' Bound objects are attempted to be serialize using a ``__structlog__`` method. @@ -115,14 +115,14 @@ API Reference >>> class C1(object): ... def __structlog__(self): - ... return ['C1!'] + ... return ["C1!"] ... def __repr__(self): - ... return '__structlog__ took precedence' + ... return "__structlog__ took precedence" >>> class C2(object): ... def __repr__(self): - ... return 'No __structlog__, so this is used.' + ... return "No __structlog__, so this is used." >>> from structlog.processors import JSONRenderer - >>> JSONRenderer(sort_keys=True)(None, None, {'c1': C1(), 'c2': C2()}) + >>> JSONRenderer(sort_keys=True)(None, None, {"c1": C1(), "c2": C2()}) '{"c1": ["C1!"], "c2": "No __structlog__, so this is used."}' Please note that additionally to strings, you can also return any type the standard library JSON module knows about -- like in this example a list. @@ -133,10 +133,10 @@ API Reference .. doctest:: >>> from structlog.processors import KeyValueRenderer - >>> KeyValueRenderer(sort_keys=True)(None, None, {'a': 42, 'b': [1, 2, 3]}) + >>> KeyValueRenderer(sort_keys=True)(None, None, {"a": 42, "b": [1, 2, 3]}) 'a=42 b=[1, 2, 3]' - >>> KeyValueRenderer(key_order=['b', 'a'])(None, None, - ... {'a': 42, 'b': [1, 2, 3]}) + >>> KeyValueRenderer(key_order=["b", "a"])(None, None, + ... {"a": 42, "b": [1, 2, 3]}) 'b=[1, 2, 3] a=42' @@ -152,7 +152,7 @@ API Reference >>> try: ... raise ValueError ... except ValueError: - ... format_exc_info(None, None, {'exc_info': True})# doctest: +ELLIPSIS + ... format_exc_info(None, None, {"exc_info": True}) # doctest: +ELLIPSIS {'exception': 'Traceback (most recent call last):... .. autoclass:: StackInfoRenderer @@ -166,9 +166,9 @@ API Reference >>> from structlog.processors import TimeStamper >>> TimeStamper()(None, None, {}) # doctest: +SKIP {'timestamp': 1378994017} - >>> TimeStamper(fmt='iso')(None, None, {}) # doctest: +SKIP + >>> TimeStamper(fmt="iso")(None, None, {}) # doctest: +SKIP {'timestamp': '2013-09-12T13:54:26.996778Z'} - >>> TimeStamper(fmt='%Y', key='year')(None, None, {}) # doctest: +SKIP + >>> TimeStamper(fmt="%Y", key="year")(None, None, {}) # doctest: +SKIP {'year': '2013'} diff --git a/docs/code_examples/flask_/some_module.py b/docs/code_examples/flask_/some_module.py index fa226c6a..21d94a2e 100644 --- a/docs/code_examples/flask_/some_module.py +++ b/docs/code_examples/flask_/some_module.py @@ -5,7 +5,6 @@ def some_function(): # later then: - logger.error('user did something', something='shot_in_foot') + logger.error("user did something", something="shot_in_foot") # gives you: # event='user did something' request_id='ffcdc44f-b952-4b5f-95e6-0f1f3a9ee5fd' something='shot_in_foot' - diff --git a/docs/code_examples/getting-started/imaginary_web.py b/docs/code_examples/getting-started/imaginary_web.py index be31eada..5f156178 100644 --- a/docs/code_examples/getting-started/imaginary_web.py +++ b/docs/code_examples/getting-started/imaginary_web.py @@ -4,14 +4,14 @@ def view(request): - user_agent = request.get('HTTP_USER_AGENT', 'UNKNOWN') + user_agent = request.get("HTTP_USER_AGENT", "UNKNOWN") peer_ip = request.client_addr if something: - log.msg('something', user_agent=user_agent, peer_ip=peer_ip) - return 'something' + log.msg("something", user_agent=user_agent, peer_ip=peer_ip) + return "something" elif something_else: - log.msg('something_else', user_agent=user_agent, peer_ip=peer_ip) - return 'something_else' + log.msg("something_else", user_agent=user_agent, peer_ip=peer_ip) + return "something_else" else: - log.msg('else', user_agent=user_agent, peer_ip=peer_ip) - return 'else' + log.msg("else", user_agent=user_agent, peer_ip=peer_ip) + return "else" diff --git a/docs/code_examples/getting-started/imaginary_web_better.py b/docs/code_examples/getting-started/imaginary_web_better.py index 62857225..a0e04620 100644 --- a/docs/code_examples/getting-started/imaginary_web_better.py +++ b/docs/code_examples/getting-started/imaginary_web_better.py @@ -5,18 +5,18 @@ def view(request): log = logger.bind( - user_agent=request.get('HTTP_USER_AGENT', 'UNKNOWN'), + user_agent=request.get("HTTP_USER_AGENT", "UNKNOWN"), peer_ip=request.client_addr, ) - foo = request.get('foo') + foo = request.get("foo") if foo: log = log.bind(foo=foo) if something: - log.msg('something') - return 'something' + log.msg("something") + return "something" elif something_else: - log.msg('something_else') - return 'something_else' + log.msg("something_else") + return "something_else" else: - log.msg('else') - return 'else' + log.msg("else") + return "else" diff --git a/docs/code_examples/processors/conditional_dropper.py b/docs/code_examples/processors/conditional_dropper.py index 754f1e1c..c40022dd 100644 --- a/docs/code_examples/processors/conditional_dropper.py +++ b/docs/code_examples/processors/conditional_dropper.py @@ -7,15 +7,15 @@ def __init__(self, peer_to_ignore): def __call__(self, logger, method_name, event_dict): """ - >>> cd = ConditionalDropper('127.0.0.1') - >>> cd(None, None, {'event': 'foo', 'peer': '10.0.0.1'}) + >>> cd = ConditionalDropper("127.0.0.1") + >>> cd(None, None, {"event": "foo", "peer": "10.0.0.1"}) {'peer': '10.0.0.1', 'event': 'foo'} - >>> cd(None, None, {'event': 'foo', 'peer': '127.0.0.1'}) + >>> cd(None, None, {"event": "foo", "peer": "127.0.0.1"}) Traceback (most recent call last): ... DropEvent """ - if event_dict.get('peer') == self._peer_to_ignore: + if event_dict.get("peer") == self._peer_to_ignore: raise DropEvent else: return event_dict diff --git a/docs/code_examples/twisted_echo.py b/docs/code_examples/twisted_echo.py index 77bffeaf..69978c0c 100644 --- a/docs/code_examples/twisted_echo.py +++ b/docs/code_examples/twisted_echo.py @@ -32,7 +32,7 @@ def dataReceived(self, data): self._counter.inc() log = self._log.bind(data=data) self.transport.write(data) - log.msg('echoed data!') + log.msg("echoed data!") if __name__ == "__main__": diff --git a/docs/configuration.rst b/docs/configuration.rst index 95b68711..96fa0985 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -35,14 +35,14 @@ The :ref:`example ` from the previous chapter could thus have been written from structlog import PrintLogger, configure, reset_defaults, wrap_logger, get_logger from structlog.threadlocal import wrap_dict def proc(logger, method_name, event_dict): - print('I got called with', event_dict) + print("I got called with", event_dict) return repr(event_dict) .. doctest:: config_wrap_logger >>> configure(processors=[proc], context_class=dict) >>> log = wrap_logger(PrintLogger()) - >>> log.msg('hello world') + >>> log.msg("hello world") I got called with {'event': 'hello world'} {'event': 'hello world'} @@ -52,7 +52,7 @@ In fact, it could even be written like >>> configure(processors=[proc], context_class=dict) >>> log = get_logger() - >>> log.msg('hello world') + >>> log.msg("hello world") I got called with {'event': 'hello world'} {'event': 'hello world'} @@ -113,7 +113,7 @@ But you can also pass in an instance of a class with a ``__call__`` method for m :func:`structlog.get_logger` can optionally take positional parameters. These will be passed to the logger factories. -For example, if you use run ``structlog.get_logger('a name')`` and configure ``structlog`` to use the standard library :class:`~structlog.stdlib.LoggerFactory` which has support for positional parameters, the returned logger will have the name ``'a name'``. +For example, if you use run ``structlog.get_logger("a name")`` and configure ``structlog`` to use the standard library :class:`~structlog.stdlib.LoggerFactory` which has support for positional parameters, the returned logger will have the name ``"a name"``. When writing custom logger factories, they should always accept positional parameters even if they don't use them. That makes sure that loggers are interchangeable. @@ -129,7 +129,7 @@ So all it takes to use ``structlog`` with standard library logging is this:: >>> from structlog.stdlib import LoggerFactory >>> configure(logger_factory=LoggerFactory()) >>> log = get_logger() - >>> log.critical('this is too easy!') + >>> log.critical("this is too easy!") event='this is too easy!' By using ``structlog``'s :class:`structlog.stdlib.LoggerFactory`, it is also ensured that variables like function names and line numbers are expanded correctly in your log format. diff --git a/docs/custom-wrappers.rst b/docs/custom-wrappers.rst index ca266034..f17ca813 100644 --- a/docs/custom-wrappers.rst +++ b/docs/custom-wrappers.rst @@ -36,16 +36,16 @@ It's much easier to demonstrate with an example: >>> from structlog import BoundLoggerBase, PrintLogger, wrap_logger >>> class SemanticLogger(BoundLoggerBase): ... def msg(self, event, **kw): - ... if not 'status' in kw: - ... return self._proxy_to_logger('msg', event, status='ok', **kw) + ... if not "status" in kw: + ... return self._proxy_to_logger("msg", event, status="ok", **kw) ... else: - ... return self._proxy_to_logger('msg', event, **kw) + ... return self._proxy_to_logger("msg", event, **kw) ... ... def user_error(self, event, **kw): - ... self.msg(event, status='user_error', **kw) + ... self.msg(event, status="user_error", **kw) >>> log = wrap_logger(PrintLogger(), wrapper_class=SemanticLogger) - >>> log = log.bind(user='fprefect') - >>> log.user_error('user.forgot_towel') + >>> log = log.bind(user="fprefect") + >>> log.user_error("user.forgot_towel") user='fprefect' status='user_error' event='user.forgot_towel' You can observe the following: diff --git a/docs/development.rst b/docs/development.rst index 14e95642..36972dc3 100644 --- a/docs/development.rst +++ b/docs/development.rst @@ -11,7 +11,7 @@ The highlight is :class:`structlog.dev.ConsoleRenderer` that offers nicely align To use it, just add it as a renderer to your processor chain. It will recognize logger names, log levels, time stamps, stack infos, and tracebacks as produced by ``structlog``'s processors and render them in special ways. -Suggested configuration for standard library logging: +``structlog``'s default configuration already uses it, but if you want to use it along with standard library logging, we suggest the following configuration: .. code-block:: python diff --git a/docs/examples.rst b/docs/examples.rst index de236152..59d42ed8 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -71,14 +71,14 @@ Here you go: >>> from structlog import wrap_logger >>> from structlog.processors import JSONRenderer >>> from structlog.stdlib import filter_by_level - >>> logging.basicConfig(stream=sys.stdout, format='%(message)s') + >>> logging.basicConfig(stream=sys.stdout, format="%(message)s") >>> def add_timestamp(_, __, event_dict): - ... event_dict['timestamp'] = datetime.datetime.utcnow() + ... event_dict["timestamp"] = datetime.datetime.utcnow() ... return event_dict >>> def censor_password(_, __, event_dict): - ... pw = event_dict.get('password') + ... pw = event_dict.get("password") ... if pw: - ... event_dict['password'] = '*CENSORED*' + ... event_dict["password"] = "*CENSORED*" ... return event_dict >>> log = wrap_logger( ... logging.getLogger(__name__), @@ -89,8 +89,8 @@ Here you go: ... JSONRenderer(indent=1, sort_keys=True) ... ] ... ) - >>> log.info('something.filtered') - >>> log.warning('something.not_filtered', password='secret') # doctest: +ELLIPSIS + >>> log.info("something.filtered") + >>> log.warning("something.not_filtered", password="secret") # doctest: +ELLIPSIS { "event": "something.not_filtered", "password": "*CENSORED*", diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 80594c3a..c46c4beb 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -32,7 +32,7 @@ And indeed, the simplest possible usage looks like this: Here, ``structlog`` takes full advantage of its hopefully useful default settings: -- Output is sent to `standard out`_ instead of exploding into the user's face. +- Output is sent to `standard out`_ instead of exploding into the user's face or doing nothing. - All keywords are formatted using :class:`structlog.dev.ConsoleRenderer`. That in turn uses `repr()`_ to serialize all values to strings. Thus, it's easy to add support for logging of your own objects\ [*]_. @@ -41,7 +41,7 @@ Here, ``structlog`` takes full advantage of its hopefully useful default setting It should be noted that even in most complex logging setups the example would still look just like that thanks to :ref:`configuration`. .. note:: - For brewity and to enable doctests, all further examples in ``structlog``\ 's documentation use the more simplistic :class:`structlog.processors.KeyValueRenderer()` without timestamps. + For brewity and to enable doctests, all further examples in ``structlog``'s documentation use the more simplistic :class:`structlog.processors.KeyValueRenderer()` without timestamps. There you go, structured logging! However, this alone wouldn't warrant its own package. @@ -158,7 +158,7 @@ To make this common case as simple as possible, ``structlog`` comes with some to >>> from structlog.stdlib import LoggerFactory >>> structlog.configure(logger_factory=LoggerFactory()) # doctest: +SKIP >>> log = structlog.get_logger() - >>> log.warning('it works!', difficulty='easy') # doctest: +SKIP + >>> log.warning("it works!", difficulty="easy") # doctest: +SKIP WARNING:structlog...:difficulty='easy' event='it works!' In other words, you tell ``structlog`` that you would like to use the standard library logger factory and keep calling :func:`~structlog.get_logger` like before. diff --git a/docs/loggers.rst b/docs/loggers.rst index 619668eb..4839d1f3 100644 --- a/docs/loggers.rst +++ b/docs/loggers.rst @@ -26,22 +26,22 @@ For that there is the :func:`structlog.wrap_logger` function (or the convenience ... def msg(self, message): ... print(message) >>> def proc(logger, method_name, event_dict): - ... print('I got called with', event_dict) + ... print("I got called with", event_dict) ... return repr(event_dict) >>> log = wrap_logger(PrintLogger(), processors=[proc], context_class=dict) >>> log2 = log.bind(x=42) >>> log == log2 False - >>> log.msg('hello world') + >>> log.msg("hello world") I got called with {'event': 'hello world'} {'event': 'hello world'} - >>> log2.msg('hello world') + >>> log2.msg("hello world") I got called with {'x': 42, 'event': 'hello world'} {'x': 42, 'event': 'hello world'} - >>> log3 = log2.unbind('x') + >>> log3 = log2.unbind("x") >>> log == log3 True - >>> log3.msg('nothing bound anymore', foo='but you can structure the event too') + >>> log3.msg("nothing bound anymore", foo="but you can structure the event too") I got called with {'foo': 'but you can structure the event too', 'event': 'nothing bound anymore'} {'foo': 'but you can structure the event too', 'event': 'nothing bound anymore'} @@ -102,10 +102,10 @@ Additionally -- mostly for unit testing -- ``structlog`` also ships with a logge >>> from structlog import ReturnLogger >>> ReturnLogger().msg(42) == 42 True - >>> obj = ['hi'] + >>> obj = ["hi"] >>> ReturnLogger().msg(obj) is obj True - >>> ReturnLogger().msg('hello', when='again') + >>> ReturnLogger().msg("hello", when="again") (('hello',), {'when': 'again'}) diff --git a/docs/performance.rst b/docs/performance.rst index 4772665c..5a91c326 100644 --- a/docs/performance.rst +++ b/docs/performance.rst @@ -27,7 +27,7 @@ Here are a few hints how to get most out of ``structlog`` in production: def f(): log = logger.bind() for i in range(1000000000): - log.info('iterated', i=i) + log.info("iterated", i=i) #. Set the `cache_logger_on_first_use` option to `True` so the aforementioned on-demand loggers will be assembled only once and cached for future uses:: diff --git a/docs/processors.rst b/docs/processors.rst index 505f30ae..e83afaee 100644 --- a/docs/processors.rst +++ b/docs/processors.rst @@ -20,11 +20,11 @@ Each processors receives three positional arguments: **method_name** The name of the wrapped method. - If you called ``log.warning('foo')``, it will be ``"warning"``. + If you called ``log.warning("foo")``, it will be ``"warning"``. **event_dict** Current context together with the current event. - If the context was ``{'a': 42}`` and the event is ``"foo"``, the initial ``event_dict`` will be ``{'a':42, 'event': 'foo'}``. + If the context was ``{"a": 42}`` and the event is ``"foo"``, the initial ``event_dict`` will be ``{"a":42, "event": "foo"}``. The return value of each processor is passed on to the next one as ``event_dict`` until finally the return value of the last processor gets passed into the wrapped logging method. @@ -41,15 +41,15 @@ If you set up your logger like: logger = wrap_logger(wrapped_logger, processors=[f1, f2, f3, f4]) log = logger.new(x=42) -and call ``log.msg('some_event', y=23)``, it results in the following call chain: +and call ``log.msg("some_event", y=23)``, it results in the following call chain: .. code:: python wrapped_logger.msg( - f4(wrapped_logger, 'msg', - f3(wrapped_logger, 'msg', - f2(wrapped_logger, 'msg', - f1(wrapped_logger, 'msg', {'event': 'some_event', 'x': 42, 'y': 23}) + f4(wrapped_logger, "msg", + f3(wrapped_logger, "msg", + f2(wrapped_logger, "msg", + f1(wrapped_logger, "msg", {"event": "some_event", "x": 42, "y": 23}) ) ) ) @@ -100,7 +100,7 @@ It can return one of three types: - A tuple of ``(args, kwargs)`` that are passed as ``log_method(*args, **kwargs)``. - A dictionary which is passed as ``log_method(**kwargs)``. -Therefore ``return 'hello world'`` is a shortcut for ``return (('hello world',), {})`` (the example in :ref:`chains` assumes this shortcut has been taken). +Therefore ``return "hello world"`` is a shortcut for ``return (("hello world",), {})`` (the example in :ref:`chains` assumes this shortcut has been taken). This should give you enough power to use ``structlog`` with any logging system while writing agnostic processors that operate on dictionaries. @@ -121,8 +121,7 @@ For a list of shipped processors, check out the :ref:`API documentation ` Third Party Packages -------------------- -Since processors are self-contained callables, -it's easy to write your own and to share them in separate packages. +Since processors are self-contained callables, it's easy to write your own and to share them in separate packages. The following processor packages are known to be currently available on PyPI: - `structlog-pretty `_: Processors for prettier output -- a code syntax highlighter, JSON and XML prettifiers, a multiline string printer, and a numeric value rounder. diff --git a/docs/standard-library.rst b/docs/standard-library.rst index eb0009df..878aa5a1 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -169,9 +169,9 @@ which will allow both of these to work in other modules: >>> import logging >>> import structlog - >>> logging.getLogger('stdlog').info('woo') + >>> logging.getLogger("stdlog").info("woo") woo - >>> structlog.get_logger('structlog').info('amazing', events='oh yes') + >>> structlog.get_logger("structlog").info("amazing", events="oh yes") amazing events=oh yes Of course, you probably want timestamps and log levels in your output. @@ -204,9 +204,9 @@ which (given the same ``logging.*`` calls as in the previous example) will resul .. code-block:: pycon - >>> logging.getLogger('stdlog').info('woo') + >>> logging.getLogger("stdlog").info("woo") 2017-03-06 14:59:20 [info ] woo - >>> structlog.get_logger('structlog').info('amazing', events='oh yes') + >>> structlog.get_logger("structlog").info("amazing", events="oh yes") 2017-03-06 14:59:20 [info ] amazing events=oh yes This allows you to set up some sophisticated logging configurations. diff --git a/docs/thread-local.rst b/docs/thread-local.rst index a3864798..43144637 100644 --- a/docs/thread-local.rst +++ b/docs/thread-local.rst @@ -49,10 +49,10 @@ Within one thread, every instance of the returned class will have a *common* ins >>> from structlog.threadlocal import wrap_dict >>> WrappedDictClass = wrap_dict(dict) - >>> d1 = WrappedDictClass({'a': 1}) - >>> d2 = WrappedDictClass({'b': 2}) + >>> d1 = WrappedDictClass({"a": 1}) + >>> d2 = WrappedDictClass({"b": 2}) >>> d3 = WrappedDictClass() - >>> d3['c'] = 3 + >>> d3["c"] = 3 >>> d1 is d3 False >>> d1 == d2 == d3 == WrappedDictClass() diff --git a/docs/twisted.rst b/docs/twisted.rst index af064a20..e8cef276 100644 --- a/docs/twisted.rst +++ b/docs/twisted.rst @@ -36,7 +36,7 @@ Processors def onError(fail): failure = fail.trap(MoonExploded) - log.err(failure, _why='event-that-happend') + log.err(failure, _why="event-that-happend") will still work as expected. diff --git a/src/structlog/_base.py b/src/structlog/_base.py index c590d073..5d1a4c39 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -112,8 +112,8 @@ def _process_event(self, method_name, event, event_kw): :param event: The event -- usually the first positional argument to a logger. :param event_kw: Additional event keywords. For example if someone - calls ``log.msg('foo', bar=42)``, *event* would to be ``'foo'`` - and *event_kw* ``{'bar': 42}``. + calls ``log.msg("foo", bar=42)``, *event* would to be ``"foo"`` + and *event_kw* ``{"bar": 42}``. :raises: :class:`structlog.DropEvent` if log entry should be dropped. :raises: :class:`ValueError` if the final processor doesn't return a string, tuple, or a dict. @@ -163,8 +163,8 @@ def _proxy_to_logger(self, method_name, event=None, **event_kw): :param event: The event -- usually the first positional argument to a logger. :param event_kw: Additional event keywords. For example if someone - calls ``log.msg('foo', bar=42)``, *event* would to be ``'foo'`` - and *event_kw* ``{'bar': 42}``. + calls ``log.msg("foo", bar=42)``, *event* would to be ``"foo"`` + and *event_kw* ``{"bar": 42}``. .. note:: diff --git a/src/structlog/_loggers.py b/src/structlog/_loggers.py index 1419fbec..742daf5b 100644 --- a/src/structlog/_loggers.py +++ b/src/structlog/_loggers.py @@ -43,12 +43,11 @@ class PrintLogger(object): :param file file: File to print to. (default: stdout) >>> from structlog import PrintLogger - >>> PrintLogger().msg('hello') + >>> PrintLogger().msg("hello") hello - Useful if you just capture your stdout with tools like `runit - `_ or if you `forward your stderr to syslog - `_. + Useful if you follow + :doc:`current logging best practices `. Also very useful for testing and examples since logging is finicky in doctests. @@ -101,12 +100,12 @@ class ReturnLogger(object): Return the arguments that it's called with. >>> from structlog import ReturnLogger - >>> ReturnLogger().msg('hello') + >>> ReturnLogger().msg("hello") 'hello' - >>> ReturnLogger().msg('hello', when='again') + >>> ReturnLogger().msg("hello", when="again") (('hello',), {'when': 'again'}) - Useful for unit tests. + Useful for testing. .. versionchanged:: 0.3.0 Allow for arbitrary arguments and keyword arguments to be passed in. diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 42d69bd5..9c1cba85 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -65,7 +65,7 @@ def ordered_items(event_dict): def ordered_items(event_dict): return sorted(event_dict.items()) else: - ordered_items = operator.methodcaller('items') + ordered_items = operator.methodcaller("items") self._ordered_items = ordered_items @@ -80,7 +80,7 @@ def _repr(inst): self._repr = _repr def __call__(self, _, __, event_dict): - return ' '.join(k + '=' + self._repr(v) + return " ".join(k + "=" + self._repr(v) for k, v in self._ordered_items(event_dict)) @@ -88,16 +88,16 @@ class UnicodeEncoder(object): """ Encode unicode values in `event_dict`. - :param str encoding: Encoding to encode to (default: ``'utf-8'``). + :param str encoding: Encoding to encode to (default: ``"utf-8"``). :param str errors: How to cope with encoding errors (default - ``'backslashreplace'``). + ``"backslashreplace"``). Useful if you're running Python 2 as otherwise ``u"abc"`` will be rendered as ``'u"abc"'``. Just put it in the processor chain before the renderer. """ - def __init__(self, encoding='utf-8', errors='backslashreplace'): + def __init__(self, encoding="utf-8", errors="backslashreplace"): self._encoding = encoding self._errors = errors @@ -112,9 +112,9 @@ class UnicodeDecoder(object): """ Decode byte string values in `event_dict`. - :param str encoding: Encoding to decode from (default: ``'utf-8'``). + :param str encoding: Encoding to decode from (default: ``"utf-8"``). :param str errors: How to cope with encoding errors (default: - ``'replace'``). + ``"replace"``). Useful if you're running Python 3 as otherwise ``b"abc"`` will be rendered as ``'b"abc"'``. @@ -123,7 +123,7 @@ class UnicodeDecoder(object): .. versionadded:: 15.4.0 """ - def __init__(self, encoding='utf-8', errors='replace'): + def __init__(self, encoding="utf-8", errors="replace"): self._encoding = encoding self._errors = errors @@ -192,9 +192,9 @@ def format_exc_info(logger, name, event_dict): If there is no ``exc_info`` key, the *event_dict* is not touched. This behavior is analogue to the one of the stdlib's logging. """ - exc_info = event_dict.pop('exc_info', None) + exc_info = event_dict.pop("exc_info", None) if exc_info: - event_dict['exception'] = _format_exception( + event_dict["exception"] = _format_exception( _figure_out_exc_info(exc_info) ) return event_dict @@ -215,19 +215,19 @@ class TimeStamper(object): :param bool utc: Whether timestamp should be in UTC or local time. :param str key: Target key in `event_dict` for added timestamps. """ - def __new__(cls, fmt=None, utc=True, key='timestamp'): + def __new__(cls, fmt=None, utc=True, key="timestamp"): if fmt is None and not utc: - raise ValueError('UNIX timestamps are always UTC.') + raise ValueError("UNIX timestamps are always UTC.") - now_method = getattr(datetime.datetime, 'utcnow' if utc else 'now') + now_method = getattr(datetime.datetime, "utcnow" if utc else "now") if fmt is None: def stamper(self, _, __, event_dict): event_dict[key] = time.time() return event_dict - elif fmt.upper() == 'ISO': + elif fmt.upper() == "ISO": if utc: def stamper(self, _, __, event_dict): - event_dict[key] = now_method().isoformat() + 'Z' + event_dict[key] = now_method().isoformat() + "Z" return event_dict else: def stamper(self, _, __, event_dict): @@ -238,7 +238,7 @@ def stamper(self, _, __, event_dict): event_dict[key] = now_method().strftime(fmt) return event_dict - return type('TimeStamper', (object,), {'__call__': stamper})() + return type("TimeStamper", (object,), {"__call__": stamper})() def _figure_out_exc_info(v): @@ -309,8 +309,8 @@ class StackInfoRenderer(object): .. versionadded:: 0.4.0 """ def __call__(self, logger, name, event_dict): - if event_dict.pop('stack_info', None): - event_dict['stack'] = _format_stack( + if event_dict.pop("stack_info", None): + event_dict["stack"] = _format_stack( _find_first_app_frame_and_name()[0] ) return event_dict diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index bb55245b..38508ef7 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -30,7 +30,7 @@ def findCaller(self, stack_info=False): info is populated for wrapping stdlib. This logger gets set as the default one when using LoggerFactory. """ - f, name = _find_first_app_frame_and_name(['logging']) + f, name = _find_first_app_frame_and_name(["logging"]) if PY3: if stack_info: sinfo = _format_stack(f) @@ -58,19 +58,19 @@ def debug(self, event=None, *args, **kw): """ Process event and call :meth:`logging.Logger.debug` with the result. """ - return self._proxy_to_logger('debug', event, *args, **kw) + return self._proxy_to_logger("debug", event, *args, **kw) def info(self, event=None, *args, **kw): """ Process event and call :meth:`logging.Logger.info` with the result. """ - return self._proxy_to_logger('info', event, *args, **kw) + return self._proxy_to_logger("info", event, *args, **kw) def warning(self, event=None, *args, **kw): """ Process event and call :meth:`logging.Logger.warning` with the result. """ - return self._proxy_to_logger('warning', event, *args, **kw) + return self._proxy_to_logger("warning", event, *args, **kw) warn = warning @@ -78,13 +78,13 @@ def error(self, event=None, *args, **kw): """ Process event and call :meth:`logging.Logger.error` with the result. """ - return self._proxy_to_logger('error', event, *args, **kw) + return self._proxy_to_logger("error", event, *args, **kw) def critical(self, event=None, *args, **kw): """ Process event and call :meth:`logging.Logger.critical` with the result. """ - return self._proxy_to_logger('critical', event, *args, **kw) + return self._proxy_to_logger("critical", event, *args, **kw) def exception(self, event=None, *args, **kw): """ @@ -113,7 +113,7 @@ def _proxy_to_logger(self, method_name, event, *event_args, that the stdblib's support for format strings can be used. """ if event_args: - event_kw['positional_args'] = event_args + event_kw["positional_args"] = event_args return super(BoundLogger, self)._proxy_to_logger(method_name, event=event, **event_kw) @@ -208,8 +208,8 @@ class LoggerFactory(object): :param ignore_frame_names: When guessing the name of a logger, skip frames whose names *start* with one of these. For example, in pyramid applications you'll want to set it to - ``['venusian', 'pyramid.config']``. - :type ignore_frame_names: `list` of `str` + ``["venusian", "pyramid.config"]``. + :type ignore_frame_names: ``list`` of ``str`` """ def __init__(self, ignore_frame_names=None): self._ignore = ignore_frame_names @@ -222,8 +222,8 @@ def __call__(self, *args): If an optional argument is passed, it will be used as the logger name instead of guesswork. This optional argument would be passed from the :func:`structlog.get_logger` call. For example - ``structlog.get_logger('foo')`` would cause this method to be called - with ``'foo'`` as its first positional argument. + ``structlog.get_logger("foo")`` would cause this method to be called + with ``"foo"`` as its first positional argument. :rtype: logging.Logger @@ -289,14 +289,14 @@ def __call__(self, _, __, event_dict): NOTSET = 0 _NAME_TO_LEVEL = { - 'critical': CRITICAL, - 'exception': ERROR, - 'error': ERROR, - 'warn': WARNING, - 'warning': WARNING, - 'info': INFO, - 'debug': DEBUG, - 'notset': NOTSET, + "critical": CRITICAL, + "exception": ERROR, + "error": ERROR, + "warn": WARNING, + "warning": WARNING, + "info": INFO, + "debug": DEBUG, + "notset": NOTSET, } _LEVEL_TO_NAME = dict( diff --git a/tests/test_loggers.py b/tests/test_loggers.py index 71218b94..94494877 100644 --- a/tests/test_loggers.py +++ b/tests/test_loggers.py @@ -30,7 +30,8 @@ def test_prints_to_stdout_by_default(self, capsys): Instantiating without arguments gives conveniently a logger to standard out. """ - PrintLogger().msg('hello') + PrintLogger().msg("hello") + out, err = capsys.readouterr() assert 'hello\n' == out assert '' == err @@ -39,13 +40,14 @@ def test_prints_to_correct_file(self, tmpdir, capsys): """ Supplied files are respected. """ - f = tmpdir.join('test.log') - fo = f.open('w') - PrintLogger(fo).msg('hello') + f = tmpdir.join("test.log") + fo = f.open("w") + PrintLogger(fo).msg("hello") out, err = capsys.readouterr() - assert '' == out == err + + assert "" == out == err fo.close() - assert 'hello\n' == f.read() + assert "hello\n" == f.read() def test_repr(self): """ @@ -60,8 +62,11 @@ def test_lock(self): Creating a logger adds a lock to WRITE_LOCKS. """ sio = StringIO() + assert sio not in WRITE_LOCKS + PrintLogger(sio) + assert sio in WRITE_LOCKS @pytest.mark.parametrize("method", STDLIB_MSG_METHODS) @@ -70,8 +75,10 @@ def test_stdlib_methods_support(self, method): PrintLogger implements methods of stdlib loggers. """ sio = StringIO() - getattr(PrintLogger(sio), method)('hello') - assert 'hello' in sio.getvalue() + + getattr(PrintLogger(sio), method)("hello") + + assert "hello" in sio.getvalue() class TestPrintLoggerFactory(object): @@ -105,13 +112,15 @@ def test_stdlib_methods_support(self, method): """ ReturnLogger implements methods of stdlib loggers. """ - v = getattr(ReturnLogger(), method)('hello') - assert 'hello' == v + v = getattr(ReturnLogger(), method)("hello") + + assert "hello" == v class TestReturnLoggerFactory(object): def test_builds_returnloggers(self): f = ReturnLoggerFactory() + assert isinstance(f(), ReturnLogger) def test_caches(self): @@ -120,6 +129,7 @@ def test_caches(self): each call. """ f = ReturnLoggerFactory() + assert f() is f() def test_ignores_args(self): From 00e5128a4e3d51220b7321577373be7ec0ce831f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 27 Jan 2018 08:49:06 +0100 Subject: [PATCH 0182/1520] Make python-rapidjson a conditional tests dependency That way devs are more likely to have it in their local setup. --- setup.py | 1 + tests/test_processors.py | 47 +++++++++++++++++++++++++++++----------- tox.ini | 1 - 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/setup.py b/setup.py index 9e6b7c17..6c3cc19a 100644 --- a/setup.py +++ b/setup.py @@ -39,6 +39,7 @@ "freezegun>=0.2.8", "pretend", "pytest>=3.3.0", + "python-rapidjson; python_version>='3.6'", "simplejson", ], "docs": [ diff --git a/tests/test_processors.py b/tests/test_processors.py index 97fdf38c..a52a4811 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -176,7 +176,8 @@ def test_simplejson(self, event_dict): 'a': '', 'b': [3, 4], 'x': 7, 'y': 'test', 'z': [1, 2] } == json.loads(jr(None, None, event_dict)) - @pytest.mark.skipif(rapidjson is None, reason="rapidjson is missing.") + @pytest.mark.skipif(rapidjson is None, + reason="python-rapidjson is missing.") def test_rapidjson(self, event_dict): """ Integration test with python-rapidjson. @@ -189,46 +190,66 @@ def test_rapidjson(self, event_dict): class TestTimeStamper(object): - def test_disallowsNonUTCUNIXTimestamps(self): + def test_disallows_non_utc_unix_timestamps(self): + """ + A asking for a UNIX timestamp with a timezone that's not UTC raises a + ValueError. + """ with pytest.raises(ValueError) as e: TimeStamper(utc=False) - assert 'UNIX timestamps are always UTC.' == e.value.args[0] - def test_insertsUTCUNIXTimestampByDefault(self): + assert "UNIX timestamps are always UTC." == e.value.args[0] + + def test_inserts_utc_unix_timestamp_by_default(self): """ Per default a float UNIX timestamp is used. """ ts = TimeStamper() d = ts(None, None, {}) + # freezegun doesn't work with time.time. :( - assert isinstance(d['timestamp'], float) + assert isinstance(d["timestamp"], float) @freeze_time('1980-03-25 16:00:00') def test_local(self): - ts = TimeStamper(fmt='iso', utc=False) + """ + Timestamp in local timezone work. We can't add a timezone to the + string without additional libraries. + """ + ts = TimeStamper(fmt="iso", utc=False) d = ts(None, None, {}) - assert '1980-03-25T16:00:00' == d['timestamp'] + + assert "1980-03-25T16:00:00" == d["timestamp"] @freeze_time('1980-03-25 16:00:00') def test_formats(self): - ts = TimeStamper(fmt='%Y') + """ + The fmt string is respected. + """ + ts = TimeStamper(fmt="%Y") d = ts(None, None, {}) - assert '1980' == d['timestamp'] + + assert "1980" == d["timestamp"] @freeze_time('1980-03-25 16:00:00') def test_adds_Z_to_iso(self): - ts = TimeStamper(fmt='iso', utc=True) + """ + stdlib's isoformat is buggy, so we fix it. + """ + ts = TimeStamper(fmt="iso", utc=True) d = ts(None, None, {}) - assert '1980-03-25T16:00:00Z' == d['timestamp'] + + assert "1980-03-25T16:00:00Z" == d["timestamp"] @freeze_time('1980-03-25 16:00:00') def test_key_can_be_specified(self): """ Timestamp is stored with the specified key. """ - ts = TimeStamper(fmt='%m', key='month') + ts = TimeStamper(fmt="%m", key="month") d = ts(None, None, {}) - assert '03' == d['month'] + + assert "03" == d["month"] class TestFormatExcInfo(object): diff --git a/tox.ini b/tox.ini index 447f78cd..563fb76a 100644 --- a/tox.ini +++ b/tox.ini @@ -9,7 +9,6 @@ deps = threads,greenlets,colorama: twisted oldtwisted: twisted < 17 colorama: colorama - py36: python-rapidjson setenv = PYTHONHASHSEED = 0 commands = coverage run --parallel -m pytest {posargs} From a73fbd3a9c3cafb11f43168582083f839b883034 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 27 Jan 2018 09:00:39 +0100 Subject: [PATCH 0183/1520] Prepare 18.1.0 --- CHANGELOG.rst | 2 +- src/structlog/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 74ae8c19..57efddee 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,7 +5,7 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. -18.1.0 (UNRELEASED) +18.1.0 (2018-01-27) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index c9e20b0a..4374269d 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -27,7 +27,7 @@ twisted = None -__version__ = "18.1.0.dev0" +__version__ = "18.1.0" __title__ = "structlog" __description__ = "Structured Logging for Python" From 88bee5c695ae0e06a5de0a875b4a98caf8a542b1 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 27 Jan 2018 09:11:34 +0100 Subject: [PATCH 0184/1520] Start new development cycle --- CHANGELOG.rst | 25 +++++++++++++++++++++++++ src/structlog/__init__.py | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 57efddee..5487fb09 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,31 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. +18.2.0 (UNRELEASED) +------------------- + + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +*none* + + +Deprecations: +^^^^^^^^^^^^^ + +*none* + + +Changes: +^^^^^^^^ + +*none* + + +---- + + 18.1.0 (2018-01-27) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 4374269d..78b3edfe 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -27,7 +27,7 @@ twisted = None -__version__ = "18.1.0" +__version__ = "18.2.0.dev0" __title__ = "structlog" __description__ = "Structured Logging for Python" From 40f332f2c69986011609ea7371138b415b1a6769 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 27 Jan 2018 15:31:40 +0100 Subject: [PATCH 0185/1520] Make logger intro more approachable --- docs/_static/BoundLogger.svg | 62 ++++++++++++++++++++++++++++++++++++ docs/configuration.rst | 21 ++++++------ docs/getting-started.rst | 2 +- docs/loggers.rst | 46 ++++++++++++++++++++------ 4 files changed, 112 insertions(+), 19 deletions(-) create mode 100644 docs/_static/BoundLogger.svg diff --git a/docs/_static/BoundLogger.svg b/docs/_static/BoundLogger.svg new file mode 100644 index 00000000..fdebc3e6 --- /dev/null +++ b/docs/_static/BoundLogger.svg @@ -0,0 +1,62 @@ + + + + Produced by OmniGraffle 7.6.1 + 2018-01-27 14:28:12 +0000 + + + + + + + + + + + + + + + Canvas 1 + + + Layer 1 + + + + BoundLogger + + + + + { + "user": "Guido", + "ip": "8.8.8.8", + } + + + Context + + + + + - censor_ip() + - add_timestamp() + - format_to_json() + + + Pr + ocessors + + + + + logging.Logger + + + W + rapped Logger + + + + diff --git a/docs/configuration.rst b/docs/configuration.rst index 96fa0985..6cf458dd 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -8,7 +8,7 @@ Global Defaults --------------- To make logging as unintrusive and straight-forward to use as possible, ``structlog`` comes with a plethora of configuration options and convenience functions. -Let me start at the end and introduce you to the ultimate convenience function that relies purely on configuration: :func:`structlog.get_logger` (and its camelCase-friendly alias :func:`structlog.getLogger` for y'all Twisted and Zope aficionados). +Let's start at the end and introduce the ultimate convenience function that relies purely on configuration: :func:`structlog.get_logger`. The goal is to reduce your per-file logging boilerplate to:: @@ -17,8 +17,8 @@ The goal is to reduce your per-file logging boilerplate to:: while still giving you the full power via configuration. -To achieve that you'll have to call :func:`structlog.configure` on app initialization. -The :ref:`example ` from the previous chapter could thus have been written as following: +To that end you'll have to call :func:`structlog.configure` on app initialization. +Thus the :ref:`example ` from the previous chapter could have been written as following: .. testcleanup:: * @@ -38,25 +38,28 @@ The :ref:`example ` from the previous chapter could thus have been written print("I got called with", event_dict) return repr(event_dict) -.. doctest:: config_wrap_logger +.. doctest:: config_get_logger >>> configure(processors=[proc], context_class=dict) - >>> log = wrap_logger(PrintLogger()) + >>> log = get_logger() >>> log.msg("hello world") I got called with {'event': 'hello world'} {'event': 'hello world'} -In fact, it could even be written like +because :class:`~structlog.processors.PrintLogger` is the default ``LoggerFactory`` used (see :ref:`logger-factories`). -.. doctest:: config_get_logger +Configuration also applies to :func:`~structlog.wrap_logger` because that's what's used internally: + +.. doctest:: config_wrap_logger >>> configure(processors=[proc], context_class=dict) - >>> log = get_logger() + >>> log = wrap_logger(PrintLogger()) >>> log.msg("hello world") I got called with {'event': 'hello world'} {'event': 'hello world'} -because :class:`~structlog.processors.PrintLogger` is the default ``LoggerFactory`` used (see :ref:`logger-factories`). + +----- You can call :func:`structlog.configure` repeatedly and only set one or more settings -- the rest will not be affected. diff --git a/docs/getting-started.rst b/docs/getting-started.rst index c46c4beb..db4cb7b1 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -169,7 +169,7 @@ Since ``structlog`` is mainly used together with standard library's logging, the Liked what you saw? ------------------- -Now you're all set for the rest of the user's guide. +Now you're all set for the rest of the user's guide and can start reading about :doc:`bound loggers ` -- the heart of ``structlog``. If you want to see more code, make sure to check out the :ref:`examples`! .. [*] In production, you're more likely to use :class:`~structlog.processors.JSONRenderer` that can also be customized using a ``__structlog__`` method so you don't have to change your repr methods to something they weren't originally intended for. diff --git a/docs/loggers.rst b/docs/loggers.rst index 4839d1f3..b73ed5d0 100644 --- a/docs/loggers.rst +++ b/docs/loggers.rst @@ -7,15 +7,46 @@ Bound Loggers The center of ``structlog`` is the immutable log wrapper :class:`~structlog.BoundLogger`. -All it does is: +.. image:: _static/BoundLogger.svg -- Keep a *context dictionary* and a *logger* that it's wrapping, -- recreate itself with (optional) *additional* context data (the :func:`~structlog.BoundLogger.bind` and :func:`~structlog.BoundLogger.new` methods), -- recreate itself with *less* data (:func:`~structlog.BoundLogger.unbind`), -- and finally relay *all* other method calls to the wrapped logger\ [*]_ after processing the log entry with the configured chain of :ref:`processors `. +What it does is: + +- Store a *context dictionary* with key-value pairs that should be part of every log entry, +- store a list of :ref:`processors ` that are called on every log entry, +- and store a *logger* that it's wrapping. + This *can* be :class:`logging.Logger` but absolutely doesn't have to. + +To manipulate the context dictionary, it offers to: + +- Recreate itself with (optional) *additional* context data: :func:`~structlog.BoundLogger.bind` and :func:`~structlog.BoundLogger.new`. +- Recreate itself with *less* context data: :func:`~structlog.BoundLogger.unbind`. + +In any case, the original bound logger or its context are never mutated. + +Finally, if you call *any other* method on :class:`~structlog.BoundLogger`, it will: + +#. Make a copy of the context -- now it becomes the *event dictionary*, +#. Add the keyword arguments of the method call to the event dict. +#. Add a new key ``event`` with the value of the first positional argument of the method call to the event dict. +#. Run the processors on the event dict. + Each processor receives the result of its predecessor. +#. Finally it takes the result of the final processor and calls the method with the same name that got called on the bound logger on ther wrapped logger\ [1]_. + For flexibility, the final processor can return either a string that is passed directly as a positional parameter, or a tuple ``(args, kwargs)`` that are passed as ``wrapped_logger.log_method(*args, **kwargs)``. + + +.. [1] Since this is slightly magicy, ``structlog`` comes with concrete loggers for the :doc:`standard-library` and :doc:`twisted` that offer you explicit APIs for the supported logging methods but behave identically like the generic BoundLogger otherwise. + Of course, you are free to implement your own bound loggers too. + + +Creation +-------- You won't be instantiating it yourself though. -For that there is the :func:`structlog.wrap_logger` function (or the convenience function :func:`structlog.get_logger` we'll discuss in a minute): +In practice you will configure ``structlog`` as explained in the :doc:`next chapter ` and then just call :func:`structlog.get_logger`. + + +In some rare cases you may not want to do that. +For that times there is the :func:`structlog.wrap_logger` function that can be used to wrap a logger without any global state (i.e. configuration): .. _proc: @@ -107,6 +138,3 @@ Additionally -- mostly for unit testing -- ``structlog`` also ships with a logge True >>> ReturnLogger().msg("hello", when="again") (('hello',), {'when': 'again'}) - - -.. [*] Since this is slightly magicy, ``structlog`` comes with concrete loggers for the :doc:`standard-library` and :doc:`twisted` that offer you explicit APIs for the supported logging methods but behave identically like the generic BoundLogger otherwise. From a454cf8f4ba48a724e1e86d288af2399a4ce6c7e Mon Sep 17 00:00:00 2001 From: Sam Park Date: Thu, 15 Feb 2018 22:37:03 -0800 Subject: [PATCH 0186/1520] Add log level numbers (#151) * Add log level numbers * PR fixes - Reorder new method's position in docs and code - Fix unrelated isort issues - Some more docs to explain what/how this works - Use `"`s v `'`s * Change changelog to point to method * Revert "Change changelog to point to method" Doesn't work. Doesn't like `:meth:` This reverts commit 2cb8bcb4f37d03da58868f3b4364f534ed481570. --- CHANGELOG.rst | 3 ++- docs/api.rst | 2 ++ docs/standard-library.rst | 9 +++++++++ src/structlog/stdlib.py | 20 ++++++++++++++++++++ tests/test_loggers.py | 1 + tests/test_stdlib.py | 17 ++++++++++++++--- tests/test_twisted.py | 2 +- 7 files changed, 49 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5487fb09..7b8b6253 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,7 +24,8 @@ Deprecations: Changes: ^^^^^^^^ -*none* +- Added ``structlog.stdlib.add_log_level_number`` processor to add level number of log level to the event dictionary. Can be used to simplify log filtering. + `#151 `_ ---- diff --git a/docs/api.rst b/docs/api.rst index 684c223b..c9b77eb6 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -189,6 +189,8 @@ API Reference .. autofunction:: add_log_level +.. autofunction:: add_log_level_number + .. autofunction:: add_logger_name .. autoclass:: PositionalArgumentsFormatter diff --git a/docs/standard-library.rst b/docs/standard-library.rst index 878aa5a1..05b5a063 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -61,6 +61,15 @@ Processors :func:`~structlog.stdlib.add_log_level`: Adds the log level to the event dictionary under the key ``level``. +:func:`~structlog.stdlib.add_log_level_number`: + Adds the log level number to the event dictionary under the key ``level_number``. + Log level numbers map to the log level names. The Python stdlib uses them for filtering logic. This adds the same numbers so users can leverage similar filtering. Compare:: + + level in ("warning", "error", "critical") + level_number >= 30 + + The mapping of names to numbers is in :data:`~structlog.stdlib._NAME_TO_LEVEL` + :class:`~structlog.stdlib.PositionalArgumentsFormatter`: This processes and formats positional arguments (if any) passed to log methods in the same way the ``logging`` module would do, e.g. ``logger.info("Hello, %s", name)``. diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 38508ef7..07e26e57 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -342,6 +342,26 @@ def add_log_level(logger, method_name, event_dict): return event_dict +def add_log_level_number(logger, method_name, event_dict): + """ + Add the log level number to the event dict. + + Log level numbers map to the log level names. The Python stdlib uses them + for filtering logic. This adds the same numbers so users can leverage + similar filtering. Compare:: + + level in ("warning", "error", "critical") + level_number >= 30 + + The mapping of names to numbers is in + :data:`~structlog.stdlib._NAME_TO_LEVEL`. + + .. versionadded:: 18.2.0 + """ + event_dict["level_number"] = _NAME_TO_LEVEL[method_name] + return event_dict + + def add_logger_name(logger, method_name, event_dict): """ Add the logger name to the event dict. diff --git a/tests/test_loggers.py b/tests/test_loggers.py index 94494877..5b6f8d8a 100644 --- a/tests/test_loggers.py +++ b/tests/test_loggers.py @@ -9,6 +9,7 @@ import pytest from six.moves import cStringIO as StringIO + from structlog._loggers import ( WRITE_LOCKS, PrintLogger, PrintLoggerFactory, ReturnLogger, ReturnLoggerFactory diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 929d4fff..0720bdc6 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -18,9 +18,10 @@ from structlog.exceptions import DropEvent from structlog.processors import JSONRenderer from structlog.stdlib import ( - CRITICAL, WARN, BoundLogger, LoggerFactory, PositionalArgumentsFormatter, - ProcessorFormatter, _FixedFindCallerLogger, add_log_level, add_logger_name, - filter_by_level, render_to_log_kwargs + _NAME_TO_LEVEL, CRITICAL, WARN, BoundLogger, LoggerFactory, + PositionalArgumentsFormatter, ProcessorFormatter, _FixedFindCallerLogger, + add_log_level, add_log_level_number, add_logger_name, filter_by_level, + render_to_log_kwargs ) from .additional_frame import additional_frame @@ -282,6 +283,16 @@ def test_args_removed_if_empty(self): assert {} == formatter(None, None, {"positional_args": ()}) +class TestAddLogLevelNumber(object): + @pytest.mark.parametrize('level, number', _NAME_TO_LEVEL.items()) + def test_log_level_number_added(self, level, number): + """ + The log level number is added to the event dict. + """ + event_dict = add_log_level_number(None, level, {}) + assert number == event_dict['level_number'] + + class TestAddLogLevel(object): def test_log_level_added(self): """ diff --git a/tests/test_twisted.py b/tests/test_twisted.py index cfd586c5..51a09abd 100644 --- a/tests/test_twisted.py +++ b/tests/test_twisted.py @@ -12,8 +12,8 @@ from pretend import call_recorder from six import PY3 - from six.moves import cStringIO as StringIO + from structlog import ReturnLogger from structlog._config import _CONFIG from structlog.processors import KeyValueRenderer From 6199a5414e5c5feb88b2d9bd66f529e0f59df2d9 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 16 Feb 2018 08:00:50 +0100 Subject: [PATCH 0187/1520] Polish --- CHANGELOG.rst | 3 ++- docs/standard-library.rst | 5 ++++- setup.cfg | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7b8b6253..a0d32d40 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,7 +24,8 @@ Deprecations: Changes: ^^^^^^^^ -- Added ``structlog.stdlib.add_log_level_number`` processor to add level number of log level to the event dictionary. Can be used to simplify log filtering. +- Added ``structlog.stdlib.add_log_level_number`` processor to add level number of log level to the event dictionary. + Can be used to simplify log filtering. `#151 `_ diff --git a/docs/standard-library.rst b/docs/standard-library.rst index 05b5a063..62c2e91c 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -63,7 +63,10 @@ Processors :func:`~structlog.stdlib.add_log_level_number`: Adds the log level number to the event dictionary under the key ``level_number``. - Log level numbers map to the log level names. The Python stdlib uses them for filtering logic. This adds the same numbers so users can leverage similar filtering. Compare:: + Log level numbers map to the log level names. + The Python stdlib uses them for filtering logic. + This adds the same numbers so users can leverage similar filtering. + Compare:: level in ("warning", "error", "critical") level_number >= 30 diff --git a/setup.cfg b/setup.cfg index 31e050ba..180edd76 100644 --- a/setup.cfg +++ b/setup.cfg @@ -25,3 +25,4 @@ multi_line_output=5 not_skip=__init__.py known_first_party=structlog +known_third_party=six From 38841503567bd892fb643f5ff53cfd454006d125 Mon Sep 17 00:00:00 2001 From: Stefan van der Walt Date: Tue, 13 Mar 2018 23:26:46 -0700 Subject: [PATCH 0188/1520] Fix typo in docs (#153) --- docs/getting-started.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started.rst b/docs/getting-started.rst index db4cb7b1..29ddf48f 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -41,7 +41,7 @@ Here, ``structlog`` takes full advantage of its hopefully useful default setting It should be noted that even in most complex logging setups the example would still look just like that thanks to :ref:`configuration`. .. note:: - For brewity and to enable doctests, all further examples in ``structlog``'s documentation use the more simplistic :class:`structlog.processors.KeyValueRenderer()` without timestamps. + For brevity and to enable doctests, all further examples in ``structlog``'s documentation use the more simplistic :class:`structlog.processors.KeyValueRenderer()` without timestamps. There you go, structured logging! However, this alone wouldn't warrant its own package. From 50e677fbbfee630c5e2602292e4c63a1568c4552 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 3 Apr 2018 04:07:21 -0700 Subject: [PATCH 0189/1520] Fix typo (#158) ...even though I enjoy a good brew --- docs/api.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api.rst b/docs/api.rst index c9b77eb6..3dfe186e 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -4,7 +4,7 @@ API Reference ============= .. note:: - The examples here use a very simplified configuration using the minimalistic :class:`structlog.processors.KeyValueRenderer` for brewity and to enable doctests. + The examples here use a very simplified configuration using the minimalistic :class:`structlog.processors.KeyValueRenderer` for brevity and to enable doctests. The output is going to be different (nicer!) with default configuration. From a071e9a3fe4242169acf239419b271c6a4cebd68 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 3 Apr 2018 04:16:44 -0700 Subject: [PATCH 0190/1520] Fix grammar (#159) --- docs/processors.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/processors.rst b/docs/processors.rst index e83afaee..5ca16e47 100644 --- a/docs/processors.rst +++ b/docs/processors.rst @@ -63,7 +63,7 @@ Parsing human-readable timestamps is tedious, not so `UNIX timestamps Date: Tue, 3 Apr 2018 04:29:21 -0700 Subject: [PATCH 0191/1520] more grammar fixes (#160) --- docs/standard-library.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/standard-library.rst b/docs/standard-library.rst index 62c2e91c..fbb99e62 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -12,7 +12,7 @@ Just Enough ``logging`` ----------------------- If you want to use ``structlog`` with :mod:`logging`, you still have to have at least fleeting understanding on how the standard library operates because ``structlog`` will *not* do any magic things in the background for you. -Most importantly you have *configure* the :mod:`logging` system *additionally* to configuring ``structlog``. +Most importantly you have to *configure* the :mod:`logging` system *additionally* to configuring ``structlog``. Usually it is enough to use:: @@ -53,7 +53,7 @@ Processors :func:`~structlog.stdlib.filter_by_level`: Checks the log entry's log level against the configuration of standard library's logging. Log entries below the threshold get silently dropped. - Put it at the beginning of your processing chain to avoid expensive operations happen in the first place. + Put it at the beginning of your processing chain to avoid expensive operations from happening in the first place. :func:`~structlog.stdlib.add_logger_name`: Adds the name of the logger to the event dictionary under the key ``logger``. @@ -304,9 +304,9 @@ Log entries that do not originate from ``structlog``, are additionally pre-proce 2017-03-06 11:49:27 [warning ] bar 2017-03-06 11:49:32 [warning ] foo x=42 -(sadly, you have to imagine the colors in the first two outputs) +(Sadly, you have to imagine the colors in the first two outputs.) -If you leave ``foreign_pre_chain`` `None`, formatting will be left to :mod:`logging`. +If you leave ``foreign_pre_chain`` as `None`, formatting will be left to :mod:`logging`. Meaning: you can define a ``format`` for :class:`~structlog.stdlib.ProcessorFormatter` too! @@ -337,7 +337,7 @@ A basic configuration to output structured logs in JSON format looks like this: cache_logger_on_first_use=True, ) -(if you're still runnning Python 2, replace :class:`~structlog.processors.UnicodeDecoder` through :class:`~structlog.processors.UnicodeEncoder`) +(If you're still runnning Python 2, replace :class:`~structlog.processors.UnicodeDecoder` through :class:`~structlog.processors.UnicodeEncoder`.) To make your program behave like a proper `12 factor app`_ that outputs only JSON to ``stdout``, configure the ``logging`` module like this:: From 0996688f68511523115b60fd0c9870a544d3a9c0 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 3 Apr 2018 04:40:17 -0700 Subject: [PATCH 0192/1520] minor grammar fix (#161) --- docs/logging-best-practices.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/logging-best-practices.rst b/docs/logging-best-practices.rst index 78873c5a..33f42932 100644 --- a/docs/logging-best-practices.rst +++ b/docs/logging-best-practices.rst @@ -18,8 +18,8 @@ This is why the popular `twelve-factor app methodology`_ suggests just that. Centralized Logging ------------------- -Nowadays you usually don't want your logfiles in compressed archives distributed over dozens -- if not thousands -- servers or cluster nodes. -You want them in a single location; parsed, indexed and easy to search. +Nowadays you usually don't want your logfiles in compressed archives distributed over dozens -- if not thousands -- of servers or cluster nodes. +You want them in a single location; parsed, indexed, and easy to search. ELK From 419e29502b8cebdbb74d3929e7092ed972d93adb Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 3 Apr 2018 04:50:36 -0700 Subject: [PATCH 0193/1520] moar grammar fixes (#162) --- docs/custom-wrappers.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/custom-wrappers.rst b/docs/custom-wrappers.rst index f17ca813..1725cbc2 100644 --- a/docs/custom-wrappers.rst +++ b/docs/custom-wrappers.rst @@ -52,9 +52,9 @@ You can observe the following: - The wrapped logger can be found in the instance variable :attr:`structlog.BoundLoggerBase._logger`. - The helper method :func:`structlog.BoundLoggerBase._proxy_to_logger` that is a DRY_ convenience function that runs the processor chain, handles possible :exc:`~structlog.DropEvent`\ s and calls a named function on :attr:`~structlog.BoundLoggerBase._logger`. -- You can run the chain by hand though using :func:`structlog.BoundLoggerBase._process_event` . +- You can run the chain by hand through using :func:`structlog.BoundLoggerBase._process_event` . -These two methods and one attribute is all you need to write own wrapper classes. +These two methods and one attribute are all you need to write own wrapper classes. .. _DRY: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself From 8b854e7faa93741914c3510e714760b2d07c222f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 5 Apr 2018 11:44:44 +0200 Subject: [PATCH 0194/1520] Ignore .pytest_cache/ --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 76de8bc3..14f1b314 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ dist docs/_build *.pyc .cache +.pytest_cache/ From 950bfdc75deda14ae1061254b51471a570b562a1 Mon Sep 17 00:00:00 2001 From: Kai Groner Date: Sat, 21 Apr 2018 02:22:24 -0400 Subject: [PATCH 0195/1520] Make default=_json_fallback_handlerer overridable in JSONRenderer. (#163) * Add failing JSONRenderer test for a custom fallback handler. * Make default=_json_fallback_handlerer overridable in JSONRenderer. --- src/structlog/processors.py | 4 ++-- tests/test_processors.py | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 9c1cba85..e5bbe28b 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -153,12 +153,12 @@ class JSONRenderer(object): ``serializer`` parameter. """ def __init__(self, serializer=json.dumps, **dumps_kw): + dumps_kw.setdefault('default', _json_fallback_handler) self._dumps_kw = dumps_kw self._dumps = serializer def __call__(self, logger, name, event_dict): - return self._dumps(event_dict, default=_json_fallback_handler, - **self._dumps_kw) + return self._dumps(event_dict, **self._dumps_kw) def _json_fallback_handler(obj): diff --git a/tests/test_processors.py b/tests/test_processors.py index a52a4811..879b03c0 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -165,6 +165,15 @@ def test_serializer(self): assert {"a": 42} == jr(None, None, obj) + def test_custom_fallback(self): + """ + A custom fallback handler can be used. + """ + jr = JSONRenderer(default=lambda x: repr(x)[::-1]) + d = {'date': datetime.date(1980, 3, 25)} + + assert '{"date": ")52 ,3 ,0891(etad.emitetad"}' == jr(None, None, d) + @pytest.mark.skipif(simplejson is None, reason="simplejson is missing.") def test_simplejson(self, event_dict): """ From 40d1f379897f4abf5611fb10aa856cfcc811e8bd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 21 Apr 2018 08:37:29 +0200 Subject: [PATCH 0196/1520] Document #163 Fixes #77 --- CHANGELOG.rst | 3 +++ docs/api.rst | 2 ++ src/structlog/processors.py | 10 ++++++++-- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a0d32d40..a1200f05 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -27,6 +27,9 @@ Changes: - Added ``structlog.stdlib.add_log_level_number`` processor to add level number of log level to the event dictionary. Can be used to simplify log filtering. `#151 `_ +- ``structlog.processors.JSONRenderer`` now allows for overwriting the *default* argument of its serializer. + `#77 `_ + `#163 `_ ---- diff --git a/docs/api.rst b/docs/api.rst index 3dfe186e..2705f0b0 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -127,6 +127,8 @@ API Reference Please note that additionally to strings, you can also return any type the standard library JSON module knows about -- like in this example a list. + If you choose to pass a *default* parameter as part of *json_kw*, support for ``__structlog__`` is disabled. + This can be useful when used together with more elegant serialization methods like :func:`functools.singledispatch`: `Better Python Object Serialization `_. .. autoclass:: KeyValueRenderer diff --git a/src/structlog/processors.py b/src/structlog/processors.py index e5bbe28b..39dfac63 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -138,7 +138,9 @@ class JSONRenderer(object): """ Render the `event_dict` using ``serializer(event_dict, **json_kw)``. - :param dict json_kw: Are passed unmodified to *serializer*. + :param dict json_kw: Are passed unmodified to *serializer*. If *default* + is passed, it will disable support for ``__structlog__``-based + serialization. :param callable serializer: A :func:`json.dumps`-compatible callable that will be used to format the string. This can be used to use alternative JSON encoders like `simplejson @@ -150,7 +152,11 @@ class JSONRenderer(object): Support for ``__structlog__`` serialization method. .. versionadded:: 15.4.0 - ``serializer`` parameter. + *serializer* parameter. + + .. versionadded:: 18.2.0 + Serializer's *default* parameter can be overwritten now. + """ def __init__(self, serializer=json.dumps, **dumps_kw): dumps_kw.setdefault('default', _json_fallback_handler) From 26877699dc5799f7250ed012f726b08dc295161e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 21 Apr 2018 10:03:55 +0200 Subject: [PATCH 0197/1520] Test future Pythons too --- .travis.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.travis.yml b/.travis.yml index 0d78a2f2..f804ee83 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,8 @@ language: python matrix: + fast_finish: true + include: - python: "2.7" env: TOXENV=py27-threads @@ -41,6 +43,15 @@ matrix: - python: "3.6" env: TOXENV=py36-oldtwisted + # Prevent breakage by a new releases + - python: "3.6-dev" + env: TOXENV=py36-threads + - python: "3.6-dev" + env: TOXENV=py36-greenlets + - python: "3.7-dev" + env: TOXENV=py37-threads + - python: "3.7-dev" + env: TOXENV=py37-greenlets # Meta - python: "3.6" @@ -52,6 +63,10 @@ matrix: - python: "3.6" env: TOXENV=readme + allow_failures: + - python: "3.6-dev" + - python: "3.7-dev" + install: - pip install tox From 21b3d16ee1a0130a80753767fd94c8bb874e01ec Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 7 Jun 2018 15:42:57 +0200 Subject: [PATCH 0198/1520] Fade to black --- .github/CONTRIBUTING.rst | 21 +- .pre-commit-config.yaml | 19 ++ .travis.yml | 2 +- MANIFEST.in | 2 +- conftest.py | 1 + docs/code_examples/flask_/some_module.py | 1 + docs/code_examples/flask_/webapp.py | 16 +- .../getting-started/imaginary_web.py | 1 + .../getting-started/imaginary_web_better.py | 1 + docs/code_examples/twisted_echo.py | 4 +- docs/conf.py | 64 ++-- setup.cfg | 5 +- setup.py | 26 +- src/structlog/__init__.py | 15 +- src/structlog/_base.py | 9 +- src/structlog/_config.py | 65 ++-- src/structlog/_frames.py | 4 +- src/structlog/_generic.py | 1 + src/structlog/_loggers.py | 8 +- src/structlog/dev.py | 68 ++-- src/structlog/processors.py | 43 ++- src/structlog/stdlib.py | 51 +-- src/structlog/threadlocal.py | 13 +- src/structlog/twisted.py | 82 +++-- tests/test_base.py | 76 +++-- tests/test_config.py | 80 +++-- tests/test_dev.py | 114 ++++--- tests/test_frames.py | 56 ++-- tests/test_generic.py | 18 +- tests/test_loggers.py | 19 +- tests/test_processors.py | 228 ++++++++------ tests/test_stdlib.py | 296 ++++++++++-------- tests/test_threadlocal.py | 100 ++++-- tests/test_twisted.py | 211 +++++++------ tests/test_utils.py | 5 +- tox.ini | 17 +- 36 files changed, 1033 insertions(+), 709 deletions(-) create mode 100644 .pre-commit-config.yaml diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst index b72ee1ed..a2ec911d 100644 --- a/.github/CONTRIBUTING.rst +++ b/.github/CONTRIBUTING.rst @@ -39,13 +39,14 @@ Code :rtype: str """ - If you add or change public APIs, tag the docstring using ``.. versionadded:: 16.0.0 WHAT`` or ``.. versionchanged:: 17.1.0 WHAT``. -- Prefer double quotes (``"``) over single quotes (``'``) unless the string contains double quotes itself. +- We use the black_ code style with a line length of 79 characters. + This means that as long as you have working pre-commit_ hooks (see below), you don't have to spend any time on formatting you code. Tests ----- -- Write your asserts as ``expected == actual`` to line them up nicely: +- Write your asserts as ``expected == actual`` to line them up nicely and leave an empty line before them: .. code-block:: python @@ -139,6 +140,19 @@ and should build docs in ``docs/_build/html``. +Next it's important to activate our pre-commit_ hooks so black_ and isort_ run automatically before committing your code. +Since pre-commit_ is installed along with other dependencies above, all you have to do is to run + +.. code-block:: bash + + precommit install + +Now you should be able to run + +.. code-block:: bash + + pre-commit run --all-files + **** Again, this list is mainly to help you to get started by codifying tribal knowledge and expectations. @@ -163,3 +177,6 @@ Thank you for considering contributing to ``structlog``! .. _reStructuredText: http://sphinx-doc.org/rest.html .. _semantic newlines: http://rhodesmill.org/brandon/2012/one-sentence-per-line/ .. _CI: https://travis-ci.org/hynek/structlog/ +.. _black: https://github.com/ambv/black +.. _pre-commit: https://pre-commit.com/ +.. _isort: https://github.com/timothycrosley/isort diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..1f808b49 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,19 @@ +repos: + - repo: https://github.com/ambv/black + rev: stable + hooks: + - id: black + args: [--line-length=79] + types: [python] + language_version: python3.6 + - repo: https://github.com/asottile/seed-isort-config + rev: v1.0.0 + hooks: + - id: seed-isort-config + language_version: python3.6 + - repo: https://github.com/pre-commit/mirrors-isort + rev: v4.3.4 + hooks: + - id: isort + types: [python] + language_version: python3.6 diff --git a/.travis.yml b/.travis.yml index f804ee83..272113ba 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,7 +55,7 @@ matrix: # Meta - python: "3.6" - env: TOXENV=flake8 + env: TOXENV=lint - python: "3.6" env: TOXENV=manifest - python: "3.6" diff --git a/MANIFEST.in b/MANIFEST.in index 271faebf..d003a6ff 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -10,4 +10,4 @@ graft docs prune docs/_build # Don't package GitHub-specific files. -exclude .github/*.md .travis.yml +exclude .github/*.md .travis.yml .pre-commit-config.yaml diff --git a/conftest.py b/conftest.py index 26b319ce..0e87c7aa 100644 --- a/conftest.py +++ b/conftest.py @@ -24,6 +24,7 @@ def event_dict(): """ An example event dictionary with multiple value types w/o the event itself. """ + class A(object): def __repr__(self): return "" diff --git a/docs/code_examples/flask_/some_module.py b/docs/code_examples/flask_/some_module.py index 21d94a2e..e7c158a6 100644 --- a/docs/code_examples/flask_/some_module.py +++ b/docs/code_examples/flask_/some_module.py @@ -1,5 +1,6 @@ from structlog import get_logger + logger = get_logger() diff --git a/docs/code_examples/flask_/webapp.py b/docs/code_examples/flask_/webapp.py index 594c84bb..1253600b 100644 --- a/docs/code_examples/flask_/webapp.py +++ b/docs/code_examples/flask_/webapp.py @@ -3,10 +3,11 @@ import uuid import flask -import structlog from some_module import some_function +import structlog + logger = structlog.get_logger() app = flask.Flask(__name__) @@ -14,9 +15,7 @@ @app.route("/login", methods=["POST", "GET"]) def some_route(): - log = logger.new( - request_id=str(uuid.uuid4()), - ) + log = logger.new(request_id=str(uuid.uuid4())) # do something # ... log.info("user logged in", user="test-user") @@ -27,17 +26,16 @@ def some_route(): # ... return "logged in!" + if __name__ == "__main__": logging.basicConfig( - format="%(message)s", - stream=sys.stdout, - level=logging.INFO, + format="%(message)s", stream=sys.stdout, level=logging.INFO ) structlog.configure( processors=[ structlog.processors.KeyValueRenderer( - key_order=["event", "request_id"], - ), + key_order=["event", "request_id"] + ) ], context_class=structlog.threadlocal.wrap_dict(dict), logger_factory=structlog.stdlib.LoggerFactory(), diff --git a/docs/code_examples/getting-started/imaginary_web.py b/docs/code_examples/getting-started/imaginary_web.py index 5f156178..14494bd8 100644 --- a/docs/code_examples/getting-started/imaginary_web.py +++ b/docs/code_examples/getting-started/imaginary_web.py @@ -1,5 +1,6 @@ from structlog import get_logger + log = get_logger() diff --git a/docs/code_examples/getting-started/imaginary_web_better.py b/docs/code_examples/getting-started/imaginary_web_better.py index a0e04620..ffd34337 100644 --- a/docs/code_examples/getting-started/imaginary_web_better.py +++ b/docs/code_examples/getting-started/imaginary_web_better.py @@ -1,5 +1,6 @@ from structlog import get_logger + logger = get_logger() diff --git a/docs/code_examples/twisted_echo.py b/docs/code_examples/twisted_echo.py index 69978c0c..48100365 100644 --- a/docs/code_examples/twisted_echo.py +++ b/docs/code_examples/twisted_echo.py @@ -1,11 +1,13 @@ import sys import uuid -import structlog import twisted from twisted.internet import protocol, reactor +import structlog + + logger = structlog.getLogger() diff --git a/docs/conf.py b/docs/conf.py index 1a54ae95..802445f7 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -21,17 +21,18 @@ here = os.path.abspath(os.path.dirname(__file__)) # We want an image in the README and include the README in the docs. -suppress_warnings = ['image.nonlocal_uri'] +suppress_warnings = ["image.nonlocal_uri"] def read(*parts): - return codecs.open(os.path.join(here, *parts), 'r').read() + return codecs.open(os.path.join(here, *parts), "r").read() def find_version(*file_paths): version_file = read(*file_paths) - version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", - version_file, re.M) + version_match = re.search( + r"^__version__ = ['\"]([^'\"]*)['\"]", version_file, re.M + ) if version_match: return version_match.group(1) raise RuntimeError("Unable to find version string.") @@ -50,28 +51,28 @@ def find_version(*file_paths): # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.doctest', - 'sphinx.ext.intersphinx', - 'sphinx.ext.viewcode', + "sphinx.ext.autodoc", + "sphinx.ext.doctest", + "sphinx.ext.intersphinx", + "sphinx.ext.viewcode", ] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. # source_encoding = 'utf-8-sig' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = u'structlog' +project = u"structlog" author = u"Hynek Schlawack" -copyright = u'2013, {author}'.format(author=author) +copyright = u"2013, {author}".format(author=author) # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -94,9 +95,7 @@ def find_version(*file_paths): # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = [ - '_build', -] +exclude_patterns = ["_build"] # The reST default role (used for this markup: `text`) to use for all # documents. @@ -114,7 +113,7 @@ def find_version(*file_paths): # show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] @@ -160,7 +159,7 @@ def find_version(*file_paths): # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. @@ -204,7 +203,7 @@ def find_version(*file_paths): # html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = 'structlogdoc' +htmlhelp_basename = "structlogdoc" # -- Options for LaTeX output ------------------------------------------------- @@ -212,10 +211,8 @@ def find_version(*file_paths): latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. # 'preamble': '', } @@ -224,8 +221,7 @@ def find_version(*file_paths): # (source start file, target name, title, author, documentclass # [howto/manual]). latex_documents = [ - ('index', 'structlog.tex', u'structlog Documentation', - u'Author', 'manual'), + ("index", "structlog.tex", u"structlog Documentation", u"Author", "manual") ] # The name of an image file (relative to this directory) to place at the top of @@ -254,8 +250,7 @@ def find_version(*file_paths): # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'structlog', u'structlog Documentation', - [u'Author'], 1) + ("index", "structlog", u"structlog Documentation", [u"Author"], 1) ] # If true, show URL addresses after external links. @@ -268,9 +263,15 @@ def find_version(*file_paths): # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index', 'structlog', u'structlog Documentation', - u'Author', 'structlog', 'One line description of project.', - 'Miscellaneous'), + ( + "index", + "structlog", + u"structlog Documentation", + u"Author", + "structlog", + "One line description of project.", + "Miscellaneous", + ) ] # Documents to append as an appendix to all manuals. @@ -325,12 +326,9 @@ def find_version(*file_paths): # Allow duplicate toc entries. # epub_tocdup = True -linkcheck_ignore = [ -] +linkcheck_ignore = [] # Twisted's trac tends to be slow linkcheck_timeout = 300 -intersphinx_mapping = { - 'https://docs.python.org/3': None, -} +intersphinx_mapping = {"https://docs.python.org/3": None} diff --git a/setup.cfg b/setup.cfg index 180edd76..0953b156 100644 --- a/setup.cfg +++ b/setup.cfg @@ -19,10 +19,11 @@ filterwarnings = [isort] atomic=true +include_trailing_comma=true lines_after_imports=2 lines_between_types=1 -multi_line_output=5 +multi_line_output=3 not_skip=__init__.py known_first_party=structlog -known_third_party=six +known_third_party=colorama,flask,freezegun,greenlet,pretend,pytest,rapidjson,setuptools,simplejson,six,some_module,structlog,twisted,zope diff --git a/setup.py b/setup.py index 6c3cc19a..6fe418df 100644 --- a/setup.py +++ b/setup.py @@ -42,10 +42,7 @@ "python-rapidjson; python_version>='3.6'", "simplejson", ], - "docs": [ - "sphinx<1.6.0", - "twisted", - ] + "docs": ["sphinx<1.6.0", "twisted"], } ############################################################################### @@ -80,8 +77,7 @@ def find_meta(meta): Extract __*meta*__ from META_FILE. """ meta_match = re.search( - r"^__{meta}__ = ['\"]([^'\"]*)['\"]".format(meta=meta), - META_FILE, re.M + r"^__{meta}__ = ['\"]([^'\"]*)['\"]".format(meta=meta), META_FILE, re.M ) if meta_match: return meta_match.group(1) @@ -90,14 +86,16 @@ def find_meta(meta): VERSION = find_meta("version") LONG = ( - read("README.rst") + "\n\n" + - "Release Information\n" + - "===================\n\n" + - re.search("(\d+.\d.\d \(.*?\)\n.*?)\n\n\n----\n\n\n", - read("CHANGELOG.rst"), re.S).group(1) + - "\n\n`Full changelog " + - "`_.\n\n" + - read("AUTHORS.rst") + read("README.rst") + + "\n\n" + + "Release Information\n" + + "===================\n\n" + + re.search( + "(\d+.\d.\d \(.*?\)\n.*?)\n\n\n----\n\n\n", read("CHANGELOG.rst"), re.S + ).group(1) + + "\n\n`Full changelog " + + "`_.\n\n" + + read("AUTHORS.rst") ) if __name__ == "__main__": diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 78b3edfe..60b808c7 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -11,12 +11,21 @@ from structlog import dev, processors, stdlib, threadlocal from structlog._base import BoundLoggerBase from structlog._config import ( - configure, configure_once, get_config, get_logger, getLogger, - is_configured, reset_defaults, wrap_logger + configure, + configure_once, + get_config, + get_logger, + getLogger, + is_configured, + reset_defaults, + wrap_logger, ) from structlog._generic import BoundLogger from structlog._loggers import ( - PrintLogger, PrintLoggerFactory, ReturnLogger, ReturnLoggerFactory + PrintLogger, + PrintLoggerFactory, + ReturnLogger, + ReturnLoggerFactory, ) from structlog.exceptions import DropEvent diff --git a/src/structlog/_base.py b/src/structlog/_base.py index 5d1a4c39..2bbec409 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -25,6 +25,7 @@ class BoundLoggerBase(object): See also :doc:`custom-wrappers`. """ + _logger = None """ Wrapped logger. @@ -42,10 +43,8 @@ def __init__(self, logger, processors, context): self._context = context def __repr__(self): - return '<{0}(context={1!r}, processors={2!r})>'.format( - self.__class__.__name__, - self._context, - self._processors, + return "<{0}(context={1!r}, processors={2!r})>".format( + self.__class__.__name__, self._context, self._processors ) def __eq__(self, other): @@ -69,7 +68,7 @@ def bind(self, **new_values): return self.__class__( self._logger, self._processors, - self._context.__class__(self._context, **new_values) + self._context.__class__(self._context, **new_values), ) def unbind(self, *keys): diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 190a233a..99835eeb 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -27,8 +27,8 @@ ConsoleRenderer(colors=_has_colorama), ] if ( - sys.version_info[:2] >= (3, 6) or - platform.python_implementation() == "PyPy" + sys.version_info[:2] >= (3, 6) + or platform.python_implementation() == "PyPy" ): # Python 3.6+ and PyPy have ordered dicts. _BUILTIN_DEFAULT_CONTEXT_CLASS = dict @@ -43,6 +43,7 @@ class _Configuration(object): """ Global defaults. """ + is_configured = False default_processors = _BUILTIN_DEFAULT_PROCESSORS[:] default_context_class = _BUILTIN_DEFAULT_CONTEXT_CLASS @@ -128,9 +129,15 @@ def get_logger(*args, **initial_values): """ -def wrap_logger(logger, processors=None, wrapper_class=None, - context_class=None, cache_logger_on_first_use=None, - logger_factory_args=None, **initial_values): +def wrap_logger( + logger, + processors=None, + wrapper_class=None, + context_class=None, + cache_logger_on_first_use=None, + logger_factory_args=None, + **initial_values +): """ Create a new bound logger for an arbitrary *logger*. @@ -166,8 +173,13 @@ def wrap_logger(logger, processors=None, wrapper_class=None, ) -def configure(processors=None, wrapper_class=None, context_class=None, - logger_factory=None, cache_logger_on_first_use=None): +def configure( + processors=None, + wrapper_class=None, + context_class=None, + logger_factory=None, + cache_logger_on_first_use=None, +): """ Configures the **global** defaults. @@ -221,7 +233,7 @@ def configure_once(*args, **kw): if not _CONFIG.is_configured: configure(*args, **kw) else: - warnings.warn('Repeated configuration attempted.', RuntimeWarning) + warnings.warn("Repeated configuration attempted.", RuntimeWarning) def reset_defaults(): @@ -253,9 +265,17 @@ class BoundLoggerLazyProxy(object): .. versionchanged:: 0.4.0 Added support for `logger_factory_args`. """ - def __init__(self, logger, wrapper_class=None, processors=None, - context_class=None, cache_logger_on_first_use=None, - initial_values=None, logger_factory_args=None): + + def __init__( + self, + logger, + wrapper_class=None, + processors=None, + context_class=None, + cache_logger_on_first_use=None, + initial_values=None, + logger_factory_args=None, + ): self._logger = logger self._wrapper_class = wrapper_class self._processors = processors @@ -266,11 +286,11 @@ def __init__(self, logger, wrapper_class=None, processors=None, def __repr__(self): return ( - ''.format(self) + "".format(self) ) def bind(self, **new_values): @@ -290,11 +310,7 @@ def bind(self, **new_values): procs = _CONFIG.default_processors else: procs = self._processors - logger = cls( - _logger, - processors=procs, - context=ctx, - ) + logger = cls(_logger, processors=procs, context=ctx) def finalized_bind(**new_values): """ @@ -305,10 +321,9 @@ def finalized_bind(**new_values): else: return logger - if ( - self._cache_logger_on_first_use is True or - (self._cache_logger_on_first_use is None and - _CONFIG.cache_logger_on_first_use is True) + if self._cache_logger_on_first_use is True or ( + self._cache_logger_on_first_use is None + and _CONFIG.cache_logger_on_first_use is True ): self.bind = finalized_bind return finalized_bind(**new_values) diff --git a/src/structlog/_frames.py b/src/structlog/_frames.py index 5c8e5ccb..247637f7 100644 --- a/src/structlog/_frames.py +++ b/src/structlog/_frames.py @@ -52,10 +52,10 @@ def _format_stack(frame): Pretty-print the stack of `frame` like logging would. """ sio = StringIO() - sio.write('Stack (most recent call last):\n') + sio.write("Stack (most recent call last):\n") traceback.print_stack(frame, file=sio) sinfo = sio.getvalue() - if sinfo[-1] == '\n': + if sinfo[-1] == "\n": sinfo = sinfo[:-1] sio.close() return sinfo diff --git a/src/structlog/_generic.py b/src/structlog/_generic.py index b2b43a42..5da44e88 100644 --- a/src/structlog/_generic.py +++ b/src/structlog/_generic.py @@ -25,6 +25,7 @@ class BoundLogger(BoundLoggerBase): Not intended to be instantiated by yourself. See :func:`~structlog.wrap_logger` and :func:`~structlog.get_logger`. """ + def __getattr__(self, method_name): """ If not done so yet, wrap the desired logger method & cache the result. diff --git a/src/structlog/_loggers.py b/src/structlog/_loggers.py index 742daf5b..26ba0ed2 100644 --- a/src/structlog/_loggers.py +++ b/src/structlog/_loggers.py @@ -26,6 +26,7 @@ class PrintLoggerFactory(object): .. versionadded:: 0.4.0 """ + def __init__(self, file=None): self._file = file @@ -52,6 +53,7 @@ class PrintLogger(object): Also very useful for testing and examples since logging is finicky in doctests. """ + def __init__(self, file=None): self._file = file or sys.stdout self._write = self._file.write @@ -64,14 +66,14 @@ def __init__(self, file=None): self._lock = lock def __repr__(self): - return ''.format(self._file) + return "".format(self._file) def msg(self, message): """ Print *message*. """ with self._lock: - until_not_interrupted(self._write, message + '\n') + until_not_interrupted(self._write, message + "\n") until_not_interrupted(self._flush) log = debug = info = warn = warning = msg @@ -88,6 +90,7 @@ class ReturnLoggerFactory(object): .. versionadded:: 0.4.0 """ + def __init__(self): self._logger = ReturnLogger() @@ -110,6 +113,7 @@ class ReturnLogger(object): .. versionchanged:: 0.3.0 Allow for arbitrary arguments and keyword arguments to be passed in. """ + def msg(self, *args, **kw): """ Return tuple of ``args, kw`` or just ``args[0]`` if only one arg passed diff --git a/src/structlog/dev.py b/src/structlog/dev.py index bcf91476..1bab0a49 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -17,14 +17,10 @@ colorama = None -__all__ = [ - "ConsoleRenderer", -] +__all__ = ["ConsoleRenderer"] -_MISSING = ( - "{who} requires the {package} package installed. " -) +_MISSING = "{who} requires the {package} package installed. " _EVENT_WIDTH = 30 # pad the event name to so many characters @@ -52,8 +48,9 @@ def _pad(s, l): else: _has_colorama = False - RESET_ALL = BRIGHT = DIM = RED = BLUE = CYAN = MAGENTA = YELLOW = GREEN = \ - RED_BACK = "" + RESET_ALL = ( + BRIGHT + ) = DIM = RED = BLUE = CYAN = MAGENTA = YELLOW = GREEN = RED_BACK = "" class _ColorfulStyles(object): @@ -121,14 +118,21 @@ class ConsoleRenderer(object): .. versionadded:: 18.1 *force_colors* .. versionadded:: 18.1 *level_styles* """ - def __init__(self, pad_event=_EVENT_WIDTH, colors=True, - force_colors=False, repr_native_str=False, level_styles=None): + + def __init__( + self, + pad_event=_EVENT_WIDTH, + colors=True, + force_colors=False, + repr_native_str=False, + level_styles=None, + ): if colors is True: if colorama is None: raise SystemError( _MISSING.format( who=self.__class__.__name__ + " with `colors=True`", - package="colorama" + package="colorama", ) ) @@ -152,19 +156,20 @@ def __init__(self, pad_event=_EVENT_WIDTH, colors=True, for key in self._level_to_color.keys(): self._level_to_color[key] += styles.bright - self._longest_level = len(max( - self._level_to_color.keys(), - key=lambda e: len(e) - )) + self._longest_level = len( + max(self._level_to_color.keys(), key=lambda e: len(e)) + ) if repr_native_str is True: self._repr = repr else: + def _repr(inst): if isinstance(inst, str): return inst else: return repr(inst) + self._repr = _repr def __call__(self, _, __, event_dict): @@ -174,14 +179,19 @@ def __call__(self, _, __, event_dict): if ts is not None: sio.write( # can be a number if timestamp is UNIXy - self._styles.timestamp + str(ts) + self._styles.reset + " " + self._styles.timestamp + + str(ts) + + self._styles.reset + + " " ) level = event_dict.pop("level", None) if level is not None: sio.write( - "[" + self._level_to_color[level] + - _pad(level, self._longest_level) + - self._styles.reset + "] " + "[" + + self._level_to_color[level] + + _pad(level, self._longest_level) + + self._styles.reset + + "] " ) event = event_dict.pop("event") @@ -194,19 +204,25 @@ def __call__(self, _, __, event_dict): logger_name = event_dict.pop("logger", None) if logger_name is not None: sio.write( - "[" + self._styles.logger_name + self._styles.bright + - logger_name + self._styles.reset + - "] " + "[" + + self._styles.logger_name + + self._styles.bright + + logger_name + + self._styles.reset + + "] " ) stack = event_dict.pop("stack", None) exc = event_dict.pop("exception", None) sio.write( " ".join( - self._styles.kv_key + key + self._styles.reset + - "=" + - self._styles.kv_value + self._repr(event_dict[key]) + - self._styles.reset + self._styles.kv_key + + key + + self._styles.reset + + "=" + + self._styles.kv_value + + self._repr(event_dict[key]) + + self._styles.reset for key in sorted(event_dict.keys()) ) ) diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 39dfac63..1f426ea0 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -17,7 +17,9 @@ import six from structlog._frames import ( - _find_first_app_frame_and_name, _format_exception, _format_stack + _find_first_app_frame_and_name, + _format_exception, + _format_stack, ) @@ -40,10 +42,17 @@ class KeyValueRenderer(object): .. versionadded:: 16.1.0 *drop_missing* .. versionadded:: 17.1.0 *repr_native_str* """ - def __init__(self, sort_keys=False, key_order=None, drop_missing=False, - repr_native_str=True): + + def __init__( + self, + sort_keys=False, + key_order=None, + drop_missing=False, + repr_native_str=True, + ): # Use an optimized version for each case. if key_order and sort_keys: + def ordered_items(event_dict): items = [] for key in key_order: @@ -52,7 +61,9 @@ def ordered_items(event_dict): items.append((key, value)) items += sorted(event_dict.items()) return items + elif key_order: + def ordered_items(event_dict): items = [] for key in key_order: @@ -61,9 +72,12 @@ def ordered_items(event_dict): items.append((key, value)) items += event_dict.items() return items + elif sort_keys: + def ordered_items(event_dict): return sorted(event_dict.items()) + else: ordered_items = operator.methodcaller("items") @@ -72,16 +86,19 @@ def ordered_items(event_dict): if repr_native_str is True: self._repr = repr else: + def _repr(inst): if isinstance(inst, str): return inst else: return repr(inst) + self._repr = _repr def __call__(self, _, __, event_dict): - return " ".join(k + "=" + self._repr(v) - for k, v in self._ordered_items(event_dict)) + return " ".join( + k + "=" + self._repr(v) for k, v in self._ordered_items(event_dict) + ) class UnicodeEncoder(object): @@ -97,6 +114,7 @@ class UnicodeEncoder(object): Just put it in the processor chain before the renderer. """ + def __init__(self, encoding="utf-8", errors="backslashreplace"): self._encoding = encoding self._errors = errors @@ -123,6 +141,7 @@ class UnicodeDecoder(object): .. versionadded:: 15.4.0 """ + def __init__(self, encoding="utf-8", errors="replace"): self._encoding = encoding self._errors = errors @@ -158,8 +177,9 @@ class JSONRenderer(object): Serializer's *default* parameter can be overwritten now. """ + def __init__(self, serializer=json.dumps, **dumps_kw): - dumps_kw.setdefault('default', _json_fallback_handler) + dumps_kw.setdefault("default", _json_fallback_handler) self._dumps_kw = dumps_kw self._dumps = serializer @@ -173,6 +193,7 @@ def _json_fallback_handler(obj): """ # circular imports :( from structlog.threadlocal import _ThreadLocalDictWrapper + if isinstance(obj, _ThreadLocalDictWrapper): return obj._dict else: @@ -221,25 +242,33 @@ class TimeStamper(object): :param bool utc: Whether timestamp should be in UTC or local time. :param str key: Target key in `event_dict` for added timestamps. """ + def __new__(cls, fmt=None, utc=True, key="timestamp"): if fmt is None and not utc: raise ValueError("UNIX timestamps are always UTC.") now_method = getattr(datetime.datetime, "utcnow" if utc else "now") if fmt is None: + def stamper(self, _, __, event_dict): event_dict[key] = time.time() return event_dict + elif fmt.upper() == "ISO": if utc: + def stamper(self, _, __, event_dict): event_dict[key] = now_method().isoformat() + "Z" return event_dict + else: + def stamper(self, _, __, event_dict): event_dict[key] = now_method().isoformat() return event_dict + else: + def stamper(self, _, __, event_dict): event_dict[key] = now_method().strftime(fmt) return event_dict @@ -285,6 +314,7 @@ class ExceptionPrettyPrinter(object): .. versionchanged:: 16.0.0 Added support for passing exceptions as ``exc_info`` on Python 3. """ + def __init__(self, file=None): if file is not None: self._file = file @@ -314,6 +344,7 @@ class StackInfoRenderer(object): .. versionadded:: 0.4.0 """ + def __call__(self, logger, name, event_dict): if event_dict.pop("stack_info", None): event_dict["stack"] = _format_stack( diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 07e26e57..5b5aa51b 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -24,6 +24,7 @@ class _FixedFindCallerLogger(logging.Logger): """ Change the behavior of findCaller to cope with structlog's extra frames. """ + def findCaller(self, stack_info=False): """ Finds the first caller frame outside of structlog so that the caller @@ -54,6 +55,7 @@ class BoundLogger(BoundLoggerBase): ) """ + def debug(self, event=None, *args, **kw): """ Process event and call :meth:`logging.Logger.debug` with the result. @@ -103,8 +105,7 @@ def log(self, level, event, *args, **kw): fatal = critical - def _proxy_to_logger(self, method_name, event, *event_args, - **event_kw): + def _proxy_to_logger(self, method_name, event, *event_args, **event_kw): """ Propagate a method call to the wrapped logger. @@ -114,9 +115,9 @@ def _proxy_to_logger(self, method_name, event, *event_args, """ if event_args: event_kw["positional_args"] = event_args - return super(BoundLogger, self)._proxy_to_logger(method_name, - event=event, - **event_kw) + return super(BoundLogger, self)._proxy_to_logger( + method_name, event=event, **event_kw + ) # # Pass-through methods to mimick the stdlib's logger interface. @@ -134,13 +135,15 @@ def findCaller(self, stack_info=False): """ return self._logger.findCaller(stack_info=stack_info) - def makeRecord(self, name, level, fn, lno, msg, args, - exc_info, func=None, extra=None): + def makeRecord( + self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None + ): """ Calls :meth:`logging.Logger.makeRecord` with unmodified arguments. """ - return self._logger.makeRecord(name, level, fn, lno, msg, args, - exc_info, func=func, extra=extra) + return self._logger.makeRecord( + name, level, fn, lno, msg, args, exc_info, func=func, extra=extra + ) def handle(self, record): """ @@ -211,6 +214,7 @@ class LoggerFactory(object): ``["venusian", "pyramid.config"]``. :type ignore_frame_names: ``list`` of ``str`` """ + def __init__(self, ignore_frame_names=None): self._ignore = ignore_frame_names logging.setLoggerClass(_FixedFindCallerLogger) @@ -259,6 +263,7 @@ class PositionalArgumentsFormatter(object): `positional_args` key in the event dict; by default it will be removed from the event dict after formatting a message. """ + def __init__(self, remove_positional_args=True): self.remove_positional_args = remove_positional_args @@ -300,8 +305,9 @@ def __call__(self, _, __, event_dict): } _LEVEL_TO_NAME = dict( - (v, k) for k, v in _NAME_TO_LEVEL.items() - if k not in ("warn", "exception", "notset", ) + (v, k) + for k, v in _NAME_TO_LEVEL.items() + if k not in ("warn", "exception", "notset") ) @@ -334,11 +340,11 @@ def add_log_level(logger, method_name, event_dict): """ Add the log level to the event dict. """ - if method_name == 'warn': + if method_name == "warn": # The stdlib has an alias - method_name = 'warning' + method_name = "warning" - event_dict['level'] = method_name + event_dict["level"] = method_name return event_dict @@ -385,10 +391,7 @@ def render_to_log_kwargs(wrapped_logger, method_name, event_dict): .. versionadded:: 17.1.0 """ - return { - "msg": event_dict.pop("event"), - "extra": event_dict, - } + return {"msg": event_dict.pop("event"), "extra": event_dict} class ProcessorFormatter(logging.Formatter): @@ -423,8 +426,16 @@ class ProcessorFormatter(logging.Formatter): .. versionadded:: 17.1.0 .. versionadded:: 17.2.0 *keep_exc_info* and *keep_stack_info* """ - def __init__(self, processor, foreign_pre_chain=None, - keep_exc_info=False, keep_stack_info=False, *args, **kwargs): + + def __init__( + self, + processor, + foreign_pre_chain=None, + keep_exc_info=False, + keep_stack_info=False, + *args, + **kwargs + ): fmt = kwargs.pop("fmt", "%(message)s") super(ProcessorFormatter, self).__init__(*args, fmt=fmt, **kwargs) self.processor = processor diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index da856b30..d6eea3a9 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -25,6 +25,7 @@ class ThreadLocal(object): """ threading.local() replacement for greenlets. """ + def __init__(self): self.__dict__["_weakdict"] = WeakKeyDictionary() @@ -57,8 +58,9 @@ def wrap_dict(dict_class): :rtype: `type` """ - Wrapped = type('WrappedDict-' + str(uuid.uuid4()), - (_ThreadLocalDictWrapper,), {}) + Wrapped = type( + "WrappedDict-" + str(uuid.uuid4()), (_ThreadLocalDictWrapper,), {} + ) Wrapped._tl = ThreadLocal() Wrapped._dict_class = dict_class return Wrapped @@ -78,9 +80,7 @@ def as_immutable(logger): try: ctx = logger._context._tl.dict_.__class__(logger._context._dict) bl = logger.__class__( - logger._logger, - processors=logger._processors, - context={}, + logger._logger, processors=logger._processors, context={} ) bl._context = ctx return bl @@ -112,6 +112,7 @@ class _ThreadLocalDictWrapper(object): Use :func:`wrap` to instantiate and use :func:`structlog._loggers.BoundLogger.new` to clear the context. """ + def __init__(self, *args, **kw): """ We cheat. A context dict gets never recreated. @@ -135,7 +136,7 @@ def _dict(self): return self.__class__._tl.dict_ def __repr__(self): - return '<{0}({1!r})>'.format(self.__class__.__name__, self._dict) + return "<{0}({1!r})>".format(self.__class__.__name__, self._dict) def __eq__(self, other): # Same class == same dictionary diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index a2601a2c..67c39e8c 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -15,7 +15,6 @@ import sys from six import PY2, string_types - from twisted.python import log from twisted.python.failure import Failure from twisted.python.log import ILogObserver, textFromEventDict @@ -41,6 +40,7 @@ class BoundLogger(BoundLoggerBase): ) """ + def msg(self, event=None, **kw): """ Process event and call ``log.msg()`` with the result. @@ -62,6 +62,7 @@ class LoggerFactory(object): >>> from structlog.twisted import LoggerFactory >>> configure(logger_factory=LoggerFactory()) """ + def __call__(self, *args): """ Positional arguments are silently ignored. @@ -84,20 +85,17 @@ def _extractStuffAndWhy(eventDict): **Modifies** *eventDict*! """ - _stuff = eventDict.pop('_stuff', None) - _why = eventDict.pop('_why', None) - event = eventDict.pop('event', None) - if ( - isinstance(_stuff, _FAIL_TYPES) and - isinstance(event, _FAIL_TYPES) - ): - raise ValueError('Both _stuff and event contain an Exception/Failure.') + _stuff = eventDict.pop("_stuff", None) + _why = eventDict.pop("_why", None) + event = eventDict.pop("event", None) + if isinstance(_stuff, _FAIL_TYPES) and isinstance(event, _FAIL_TYPES): + raise ValueError("Both _stuff and event contain an Exception/Failure.") # `log.err('event', _why='alsoEvent')` is ambiguous. if _why and isinstance(event, string_types): - raise ValueError('Both `_why` and `event` supplied.') + raise ValueError("Both `_why` and `event` supplied.") # Two failures are ambiguous too. if not isinstance(_stuff, _FAIL_TYPES) and isinstance(event, _FAIL_TYPES): - _why = _why or 'error' + _why = _why or "error" _stuff = event if isinstance(event, string_types): _why = event @@ -125,6 +123,7 @@ class ReprWrapper(object): Note the extra quotes in the unwrapped example. """ + def __init__(self, string): self.string = string @@ -132,8 +131,9 @@ def __eq__(self, other): """ Check for equality, actually just for tests. """ - return isinstance(other, self.__class__) \ - and self.string == other.string + return ( + isinstance(other, self.__class__) and self.string == other.string + ) def __repr__(self): return self.string @@ -160,18 +160,24 @@ class JSONRenderer(GenericJSONRenderer): Use together with a :class:`JSONLogObserverWrapper`-wrapped Twisted logger like :func:`plainJSONStdOutLogger` for pure-JSON logs. """ + def __call__(self, logger, name, eventDict): _stuff, _why, eventDict = _extractStuffAndWhy(eventDict) - if name == 'err': - eventDict['event'] = _why + if name == "err": + eventDict["event"] = _why if isinstance(_stuff, Failure): - eventDict['exception'] = _stuff.getTraceback(detail='verbose') + eventDict["exception"] = _stuff.getTraceback(detail="verbose") _stuff.cleanFailure() else: - eventDict['event'] = _why - return ((ReprWrapper( - GenericJSONRenderer.__call__(self, logger, name, eventDict) - ),), {'_structlog': True}) + eventDict["event"] = _why + return ( + ( + ReprWrapper( + GenericJSONRenderer.__call__(self, logger, name, eventDict) + ), + ), + {"_structlog": True}, + ) @implementer(ILogObserver) @@ -187,12 +193,13 @@ class PlainFileLogObserver(object): .. versionadded:: 0.2.0 """ + def __init__(self, file): self._write = file.write self._flush = file.flush def __call__(self, eventDict): - until_not_interrupted(self._write, textFromEventDict(eventDict) + '\n') + until_not_interrupted(self._write, textFromEventDict(eventDict) + "\n") until_not_interrupted(self._flush) @@ -208,16 +215,21 @@ class JSONLogObserverWrapper(object): .. versionadded:: 0.2.0 """ + def __init__(self, observer): self._observer = observer def __call__(self, eventDict): - if '_structlog' not in eventDict: - eventDict['message'] = (json.dumps({ - 'event': textFromEventDict(eventDict), - 'system': eventDict.get('system'), - }),) - eventDict['_structlog'] = True + if "_structlog" not in eventDict: + eventDict["message"] = ( + json.dumps( + { + "event": textFromEventDict(eventDict), + "system": eventDict.get("system"), + } + ), + ) + eventDict["_structlog"] = True return self._observer(eventDict) @@ -262,6 +274,7 @@ class EventAdapter(object): for the actual formatting as an constructor argument in order to be able to fully support the original behaviors of ``log.msg()`` and ``log.err()``. """ + def __init__(self, dictRenderer=None): """ :param dictRenderer: A processor used to format the log message. @@ -269,16 +282,19 @@ def __init__(self, dictRenderer=None): self._dictRenderer = dictRenderer or _BUILTIN_DEFAULT_PROCESSORS[-1] def __call__(self, logger, name, eventDict): - if name == 'err': + if name == "err": # This aspires to handle the following cases correctly: # - log.err(failure, _why='event', **kw) # - log.err('event', **kw) # - log.err(_stuff=failure, _why='event', **kw) _stuff, _why, eventDict = _extractStuffAndWhy(eventDict) - eventDict['event'] = _why - return ((), { - '_stuff': _stuff, - '_why': self._dictRenderer(logger, name, eventDict), - }) + eventDict["event"] = _why + return ( + (), + { + "_stuff": _stuff, + "_why": self._dictRenderer(logger, name, eventDict), + }, + ) else: return self._dictRenderer(logger, name, eventDict) diff --git a/tests/test_base.py b/tests/test_base.py index 96ef5680..48c804dc 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -30,9 +30,9 @@ class TestBinding(object): def test_repr(self): bl = build_bl(processors=[1, 2, 3], context={}) - assert ( - "" - ) == repr(bl) + assert ("") == repr( + bl + ) def test_binds_independently(self): """ @@ -40,40 +40,52 @@ def test_binds_independently(self): """ b = build_bl(processors=[KeyValueRenderer(sort_keys=True)]) b = b.bind(x=42, y=23) - b1 = b.bind(foo='bar') - b2 = b.bind(foo='qux') + b1 = b.bind(foo="bar") + b2 = b.bind(foo="qux") + assert b._context != b1._context != b2._context def test_new_clears_state(self): b = build_bl() b = b.bind(x=42) - assert 42 == b._context['x'] + + assert 42 == b._context["x"] + b = b.bind() - assert 42 == b._context['x'] + + assert 42 == b._context["x"] + b = b.new() - assert 'x' not in b._context + + assert "x" not in b._context def test_comparison(self): b = build_bl() + assert b == b.bind() assert b is not b.bind() assert b != b.bind(x=5) - assert b != 'test' + assert b != "test" def test_bind_keeps_class(self): class Wrapper(BoundLoggerBase): pass + b = Wrapper(None, [], {}) + assert isinstance(b.bind(), Wrapper) def test_new_keeps_class(self): class Wrapper(BoundLoggerBase): pass + b = Wrapper(None, [], {}) + assert isinstance(b.new(), Wrapper) def test_unbind(self): - b = build_bl().bind(x=42, y=23).unbind('x', 'y') + b = build_bl().bind(x=42, y=23).unbind("x", "y") + assert {} == b._context @@ -94,18 +106,20 @@ def test_copies_context_before_processing(self): BoundLoggerBase._process_event() gets called before relaying events to wrapped loggers. """ + def chk(_, __, event_dict): assert b._context is not event_dict - return '' + return "" b = build_bl(processors=[chk]) - assert (('',), {}) == b._process_event('', 'event', {}) - assert 'event' not in b._context + + assert (("",), {}) == b._process_event("", "event", {}) + assert "event" not in b._context def test_chain_does_not_swallow_all_exceptions(self): b = build_bl(processors=[raiser(ValueError)]) with pytest.raises(ValueError): - b._process_event('', 'boom', {}) + b._process_event("", "boom", {}) def test_last_processor_returns_string(self): """ @@ -113,34 +127,29 @@ def test_last_processor_returns_string(self): returned. """ logger = stub(msg=lambda *args, **kw: (args, kw)) - b = build_bl(logger, processors=[lambda *_: 'foo']) - assert ( - (('foo',), {}) == - b._process_event('', 'foo', {}) - ) + b = build_bl(logger, processors=[lambda *_: "foo"]) + + assert (("foo",), {}) == b._process_event("", "foo", {}) def test_last_processor_returns_tuple(self): """ If the final processor returns a tuple, it is just passed through. """ logger = stub(msg=lambda *args, **kw: (args, kw)) - b = build_bl(logger, processors=[lambda *_: (('foo',), - {'key': 'value'})]) - assert ( - (('foo',), {'key': 'value'}) == - b._process_event('', 'foo', {}) + b = build_bl( + logger, processors=[lambda *_: (("foo",), {"key": "value"})] ) + assert (("foo",), {"key": "value"}) == b._process_event("", "foo", {}) + def test_last_processor_returns_dict(self): """ If the final processor returns a dict, ``(), the_dict`` is returned. """ logger = stub(msg=lambda *args, **kw: (args, kw)) - b = build_bl(logger, processors=[lambda *_: {'event': 'foo'}]) - assert ( - ((), {'event': 'foo'}) == - b._process_event('', 'foo', {}) - ) + b = build_bl(logger, processors=[lambda *_: {"event": "foo"}]) + + assert ((), {"event": "foo"}) == b._process_event("", "foo", {}) def test_last_processor_returns_unknown_value(self): """ @@ -150,11 +159,9 @@ def test_last_processor_returns_unknown_value(self): logger = stub(msg=lambda *args, **kw: (args, kw)) b = build_bl(logger, processors=[lambda *_: object()]) with pytest.raises(ValueError) as exc: - b._process_event('', 'foo', {}) + b._process_event("", "foo", {}) - assert ( - exc.value.args[0].startswith("Last processor didn't return") - ) + assert exc.value.args[0].startswith("Last processor didn't return") class TestProxying(object): @@ -165,4 +172,5 @@ def test_processor_raising_DropEvent_silently_aborts_chain(self, capsys): """ b = build_bl(processors=[raiser(DropEvent), raiser(ValueError)]) b._proxy_to_logger("", None, x=5) - assert (("", "") == capsys.readouterr()) + + assert ("", "") == capsys.readouterr() diff --git a/tests/test_config.py b/tests/test_config.py index dddc9542..45c93f04 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -19,9 +19,16 @@ from structlog._base import BoundLoggerBase from structlog._config import ( - _BUILTIN_DEFAULT_CONTEXT_CLASS, _BUILTIN_DEFAULT_LOGGER_FACTORY, - _BUILTIN_DEFAULT_PROCESSORS, _BUILTIN_DEFAULT_WRAPPER_CLASS, _CONFIG, - BoundLoggerLazyProxy, configure, configure_once, get_logger, wrap_logger + _BUILTIN_DEFAULT_CONTEXT_CLASS, + _BUILTIN_DEFAULT_LOGGER_FACTORY, + _BUILTIN_DEFAULT_PROCESSORS, + _BUILTIN_DEFAULT_WRAPPER_CLASS, + _CONFIG, + BoundLoggerLazyProxy, + configure, + configure_once, + get_logger, + wrap_logger, ) @@ -44,9 +51,9 @@ def test_default_context_class(): Default context class is dict on Python 3.6+ and PyPy, OrderedDict otherwise. """ - if ( - platform.python_implementation() == "PyPy" or - sys.version_info[:2] >= (3, 6) + if platform.python_implementation() == "PyPy" or sys.version_info[:2] >= ( + 3, + 6, ): cls = dict else: @@ -128,16 +135,18 @@ def teardown_method(self, method): def test_repr(self): p = BoundLoggerLazyProxy( - None, processors=[1, 2, 3], context_class=dict, - initial_values={'foo': 42}, logger_factory_args=(4, 5), + None, + processors=[1, 2, 3], + context_class=dict, + initial_values={"foo": 42}, + logger_factory_args=(4, 5), ) assert ( ", " "initial_values={'foo': 42}, " - "logger_factory_args=(4, 5))>" - % ('class' if PY3 else 'type',) + "logger_factory_args=(4, 5))>" % ("class" if PY3 else "type",) ) == repr(p) def test_returns_bound_logger_on_bind(self, proxy): @@ -147,8 +156,9 @@ def test_returns_bound_logger_on_new(self, proxy): assert isinstance(proxy.new(), BoundLoggerBase) def test_prefers_args_over_config(self): - p = BoundLoggerLazyProxy(None, processors=[1, 2, 3], - context_class=dict) + p = BoundLoggerLazyProxy( + None, processors=[1, 2, 3], context_class=dict + ) b = p.bind() assert isinstance(b._context, dict) assert [1, 2, 3] == b._processors @@ -159,6 +169,7 @@ def __init__(self, *args, **kw): def update(self, *args, **kw): pass + configure(processors=[4, 5, 6], context_class=Class) b = p.bind() assert not isinstance(b._context, Class) @@ -170,20 +181,20 @@ def test_falls_back_to_config(self, proxy): assert _CONFIG.default_processors == b._processors def test_bind_honors_initial_values(self): - p = BoundLoggerLazyProxy(None, initial_values={'a': 1, 'b': 2}) + p = BoundLoggerLazyProxy(None, initial_values={"a": 1, "b": 2}) b = p.bind() - assert {'a': 1, 'b': 2} == b._context + assert {"a": 1, "b": 2} == b._context b = p.bind(c=3) - assert {'a': 1, 'b': 2, 'c': 3} == b._context + assert {"a": 1, "b": 2, "c": 3} == b._context def test_bind_binds_new_values(self, proxy): b = proxy.bind(c=3) - assert {'c': 3} == b._context + assert {"c": 3} == b._context def test_unbind_unbinds_from_initial_values(self): - p = BoundLoggerLazyProxy(None, initial_values={'a': 1, 'b': 2}) - b = p.unbind('a') - assert {'b': 2} == b._context + p = BoundLoggerLazyProxy(None, initial_values={"a": 1, "b": 2}) + b = p.unbind("a") + assert {"b": 2} == b._context def test_honors_wrapper_class(self): p = BoundLoggerLazyProxy(None, wrapper_class=Wrapper) @@ -196,16 +207,16 @@ def test_honors_wrapper_from_config(self, proxy): assert isinstance(b, Wrapper) def test_new_binds_only_initial_values_impolicit_ctx_class(self, proxy): - proxy = BoundLoggerLazyProxy(None, initial_values={'a': 1, 'b': 2}) + proxy = BoundLoggerLazyProxy(None, initial_values={"a": 1, "b": 2}) b = proxy.new(foo=42) - assert {'a': 1, 'b': 2, 'foo': 42} == b._context + assert {"a": 1, "b": 2, "foo": 42} == b._context def test_new_binds_only_initial_values_explicit_ctx_class(self, proxy): - proxy = BoundLoggerLazyProxy(None, - initial_values={'a': 1, 'b': 2}, - context_class=dict) + proxy = BoundLoggerLazyProxy( + None, initial_values={"a": 1, "b": 2}, context_class=dict + ) b = proxy.new(foo=42) - assert {'a': 1, 'b': 2, 'foo': 42} == b._context + assert {"a": 1, "b": 2, "foo": 42} == b._context def test_rebinds_bind_method(self, proxy): """ @@ -244,8 +255,10 @@ def test_bind_doesnt_cache_logger(self): Calling configure() changes BoundLoggerLazyProxys immediately. Previous uses of the BoundLoggerLazyProxy don't interfere. """ + class F(object): "New logger factory with a new attribute" + def a(self, *args): return 5 @@ -261,13 +274,13 @@ def test_emphemeral(self): Calling an unknown method proxy creates a new wrapped bound logger first. """ + class Foo(BoundLoggerBase): def foo(self): return 42 + proxy = BoundLoggerLazyProxy( - None, - wrapper_class=Foo, - cache_logger_on_first_use=False, + None, wrapper_class=Foo, cache_logger_on_first_use=False ) assert 42 == proxy.foo() @@ -304,12 +317,13 @@ def test_configure_once_issues_warning_on_repeated_call(self): configure_once() assert 1 == len(warns) assert RuntimeWarning == warns[0].category - assert 'Repeated configuration attempted.' == warns[0].message.args[0] + assert "Repeated configuration attempted." == warns[0].message.args[0] def test_get_logger_configures_according_to_config(self): b = get_logger().bind() - assert isinstance(b._logger, - _BUILTIN_DEFAULT_LOGGER_FACTORY().__class__) + assert isinstance( + b._logger, _BUILTIN_DEFAULT_LOGGER_FACTORY().__class__ + ) assert _BUILTIN_DEFAULT_PROCESSORS == b._processors assert isinstance(b, _BUILTIN_DEFAULT_WRAPPER_CLASS) assert _BUILTIN_DEFAULT_CONTEXT_CLASS == b._context.__class__ @@ -321,5 +335,5 @@ def test_get_logger_passes_positional_arguments_to_logger_factory(self): """ factory = call_recorder(lambda *args: object()) configure(logger_factory=factory) - get_logger('test').bind(x=42) - assert [call('test')] == factory.calls + get_logger("test").bind(x=42) + assert [call("test")] == factory.calls diff --git a/tests/test_dev.py b/tests/test_dev.py index c753cced..18a5653c 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -39,9 +39,7 @@ def styles(cr): @pytest.fixture def padded(styles): return ( - styles.bright + - dev._pad("test", dev._EVENT_WIDTH) + - styles.reset + " " + styles.bright + dev._pad("test", dev._EVENT_WIDTH) + styles.reset + " " ) @@ -79,18 +77,17 @@ def test_timestamp(self, cr, styles, unpadded): """ rv = cr(None, None, {"event": "test", "timestamp": 42}) - assert ( - styles.timestamp + "42" + styles.reset + " " + unpadded - ) == rv + assert (styles.timestamp + "42" + styles.reset + " " + unpadded) == rv def test_level(self, cr, styles, padded): """ Levels are rendered aligned, in square brackets, and color coded. """ - rv = cr(None, None, { - "event": "test", "level": "critical", "foo": "bar" - }) + rv = cr( + None, None, {"event": "test", "level": "critical", "foo": "bar"} + ) + # fmt: off assert ( "[" + dev.RED + styles.bright + dev._pad("critical", cr._longest_level) + @@ -99,6 +96,7 @@ def test_level(self, cr, styles, padded): styles.kv_key + "foo" + styles.reset + "=" + styles.kv_value + "bar" + styles.reset ) == rv + # fmt: on def test_init_accepts_overriding_levels(self, styles, padded): """ @@ -113,10 +111,11 @@ def test_init_accepts_overriding_levels(self, styles, padded): ) # this would blow up if the level_styles override failed - rv = cr(None, None, { - "event": "test", "level": "MY_OH_MY", "foo": "bar" - }) + rv = cr( + None, None, {"event": "test", "level": "MY_OH_MY", "foo": "bar"} + ) + # fmt: off assert ( "[" + dev.RED + styles.bright + dev._pad("MY_OH_MY", cr._longest_level) + @@ -125,6 +124,7 @@ def test_init_accepts_overriding_levels(self, styles, padded): styles.kv_key + "foo" + styles.reset + "=" + styles.kv_value + "bar" + styles.reset ) == rv + # fmt: on def test_logger_name(self, cr, styles, padded): """ @@ -132,22 +132,22 @@ def test_logger_name(self, cr, styles, padded): """ rv = cr(None, None, {"event": "test", "logger": "some_module"}) + # fmt: off assert ( padded + "[" + dev.BLUE + styles.bright + "some_module" + styles.reset + "] " ) == rv + # fmt: on def test_key_values(self, cr, styles, padded): """ Key-value pairs go sorted alphabetically to the end. """ - rv = cr(None, None, { - "event": "test", - "key": "value", - "foo": "bar", - }) + rv = cr(None, None, {"event": "test", "key": "value", "foo": "bar"}) + + # fmt: off assert ( padded + styles.kv_key + "foo" + styles.reset + "=" + @@ -157,6 +157,7 @@ def test_key_values(self, cr, styles, padded): styles.kv_value + "value" + styles.reset ) == rv + # fmt: on def test_exception(self, cr, padded): """ @@ -164,38 +165,28 @@ def test_exception(self, cr, padded): """ exc = "Traceback:\nFake traceback...\nFakeError: yolo" - rv = cr(None, None, { - "event": "test", - "exception": exc - }) + rv = cr(None, None, {"event": "test", "exception": exc}) - assert ( - padded + "\n" + exc - ) == rv + assert (padded + "\n" + exc) == rv def test_stack_info(self, cr, padded): """ Stack traces are rendered after a new line. """ stack = "fake stack" - rv = cr(None, None, { - "event": "test", - "stack": stack - }) + rv = cr(None, None, {"event": "test", "stack": stack}) - assert ( - padded + "\n" + stack - ) == rv + assert (padded + "\n" + stack) == rv def test_pad_event_param(self, styles): """ `pad_event` parameter works. """ - rv = dev.ConsoleRenderer(42, dev._has_colorama)(None, None, { - "event": "test", - "foo": "bar" - }) + rv = dev.ConsoleRenderer(42, dev._has_colorama)( + None, None, {"event": "test", "foo": "bar"} + ) + # fmt: off assert ( styles.bright + dev._pad("test", 42) + @@ -203,6 +194,7 @@ def test_pad_event_param(self, styles): styles.kv_key + "foo" + styles.reset + "=" + styles.kv_value + "bar" + styles.reset ) == rv + # fmt: on def test_everything(self, cr, styles, padded): """ @@ -211,17 +203,22 @@ def test_everything(self, cr, styles, padded): exc = "Traceback:\nFake traceback...\nFakeError: yolo" stack = "fake stack trace" - rv = cr(None, None, { - "event": "test", - "exception": exc, - "key": "value", - "foo": "bar", - "timestamp": "13:13", - "logger": "some_module", - "level": "error", - "stack": stack, - }) + rv = cr( + None, + None, + { + "event": "test", + "exception": exc, + "key": "value", + "foo": "bar", + "timestamp": "13:13", + "logger": "some_module", + "level": "error", + "stack": stack, + }, + ) + # fmt: off assert ( styles.timestamp + "13:13" + styles.reset + " [" + styles.level_error + styles.bright + @@ -240,6 +237,7 @@ def test_everything(self, cr, styles, padded): "\n" + stack + "\n\n" + "=" * 79 + "\n" + "\n" + exc ) == rv + # fmt: on def test_colorama_colors_false(self): """ @@ -247,25 +245,26 @@ def test_colorama_colors_false(self): """ plain_cr = dev.ConsoleRenderer(colors=False) - rv = plain_cr(None, None, { - "event": "event", "level": "info", "foo": "bar" - }) + rv = plain_cr( + None, None, {"event": "event", "level": "info", "foo": "bar"} + ) assert dev._PlainStyles is plain_cr._styles assert "[info ] event foo=bar" == rv def test_colorama_force_colors(self, styles, padded): """ - If force_colors is True, use colors even if - the destination is non-tty. + If force_colors is True, use colors even if the destination is non-tty. """ cr = dev.ConsoleRenderer( - colors=dev._has_colorama, force_colors=dev._has_colorama) + colors=dev._has_colorama, force_colors=dev._has_colorama + ) - rv = cr(None, None, { - "event": "test", "level": "critical", "foo": "bar" - }) + rv = cr( + None, None, {"event": "test", "level": "critical", "foo": "bar"} + ) + # fmt: off assert ( "[" + dev.RED + styles.bright + dev._pad("critical", cr._longest_level) + @@ -274,6 +273,7 @@ def test_colorama_force_colors(self, styles, padded): styles.kv_key + "foo" + styles.reset + "=" + styles.kv_value + "bar" + styles.reset ) == rv + # fmt: on assert not dev._has_colorama or dev._ColorfulStyles is cr._styles @@ -283,10 +283,8 @@ def test_repr_native_str(self, rns): repr_native_str=False doesn't repr on native strings. "event" is never repr'ed. """ - rv = dev.ConsoleRenderer( - colors=False, repr_native_str=rns)(None, None, { - "event": "哈", "key": 42, "key2": "哈", - } + rv = dev.ConsoleRenderer(colors=False, repr_native_str=rns)( + None, None, {"event": "哈", "key": 42, "key2": "哈"} ) cnt = rv.count("哈") diff --git a/tests/test_frames.py b/tests/test_frames.py index 4dd95bc3..6b452b7a 100644 --- a/tests/test_frames.py +++ b/tests/test_frames.py @@ -13,7 +13,9 @@ import structlog._frames from structlog._frames import ( - _find_first_app_frame_and_name, _format_exception, _format_stack + _find_first_app_frame_and_name, + _format_exception, + _format_stack, ) @@ -22,22 +24,24 @@ def test_ignores_structlog_by_default(self, monkeypatch): """ No matter what you pass in, structlog frames get always ignored. """ - f1 = stub(f_globals={'__name__': 'test'}, f_back=None) - f2 = stub(f_globals={'__name__': 'structlog.blubb'}, f_back=f1) - monkeypatch.setattr(structlog._frames.sys, '_getframe', lambda: f2) + f1 = stub(f_globals={"__name__": "test"}, f_back=None) + f2 = stub(f_globals={"__name__": "structlog.blubb"}, f_back=f1) + monkeypatch.setattr(structlog._frames.sys, "_getframe", lambda: f2) f, n = _find_first_app_frame_and_name() - assert ((f1, 'test') == (f, n)) + + assert (f1, "test") == (f, n) def test_ignoring_of_additional_frame_names_works(self, monkeypatch): """ Additional names are properly ignored too. """ - f1 = stub(f_globals={'__name__': 'test'}, f_back=None) - f2 = stub(f_globals={'__name__': 'ignored.bar'}, f_back=f1) - f3 = stub(f_globals={'__name__': 'structlog.blubb'}, f_back=f2) - monkeypatch.setattr(structlog._frames.sys, '_getframe', lambda: f3) - f, n = _find_first_app_frame_and_name(additional_ignores=['ignored']) - assert ((f1, 'test') == (f, n)) + f1 = stub(f_globals={"__name__": "test"}, f_back=None) + f2 = stub(f_globals={"__name__": "ignored.bar"}, f_back=f1) + f3 = stub(f_globals={"__name__": "structlog.blubb"}, f_back=f2) + monkeypatch.setattr(structlog._frames.sys, "_getframe", lambda: f3) + f, n = _find_first_app_frame_and_name(additional_ignores=["ignored"]) + + assert (f1, "test") == (f, n) def test_tolerates_missing_name(self, monkeypatch): """ @@ -46,36 +50,40 @@ def test_tolerates_missing_name(self, monkeypatch): f1 = stub(f_globals={}, f_back=None) monkeypatch.setattr(structlog._frames.sys, "_getframe", lambda: f1) f, n = _find_first_app_frame_and_name() - assert ((f1, "?") == (f, n)) + + assert (f1, "?") == (f, n) def test_tolerates_name_explicitly_None_oneframe(self, monkeypatch): """ Use ``?`` if `f_globals` has a `None` valued `__name__` key """ - f1 = stub(f_globals={'__name__': None}, f_back=None) + f1 = stub(f_globals={"__name__": None}, f_back=None) monkeypatch.setattr(structlog._frames.sys, "_getframe", lambda: f1) f, n = _find_first_app_frame_and_name() - assert ((f1, "?") == (f, n)) + + assert (f1, "?") == (f, n) def test_tolerates_name_explicitly_None_manyframe(self, monkeypatch): """ Use ``?`` if `f_globals` has a `None` valued `__name__` key, multiple frames up. """ - f1 = stub(f_globals={'__name__': None}, f_back=None) - f2 = stub(f_globals={'__name__': 'structlog.blubb'}, f_back=f1) + f1 = stub(f_globals={"__name__": None}, f_back=None) + f2 = stub(f_globals={"__name__": "structlog.blubb"}, f_back=f1) monkeypatch.setattr(structlog._frames.sys, "_getframe", lambda: f2) f, n = _find_first_app_frame_and_name() - assert ((f1, "?") == (f, n)) + + assert (f1, "?") == (f, n) def test_tolerates_f_back_is_None(self, monkeypatch): """ Use ``?`` if all frames are in ignored frames. """ - f1 = stub(f_globals={'__name__': 'structlog'}, f_back=None) + f1 = stub(f_globals={"__name__": "structlog"}, f_back=None) monkeypatch.setattr(structlog._frames.sys, "_getframe", lambda: f1) f, n = _find_first_app_frame_and_name() - assert ((f1, "?") == (f, n)) + + assert (f1, "?") == (f, n) @pytest.fixture @@ -110,10 +118,11 @@ def test_no_trailing_nl(self, exc_info, monkeypatch): one nothing is removed. """ from structlog._frames import traceback + monkeypatch.setattr( - traceback, "print_exception", - lambda *a: a[-1].write("foo") + traceback, "print_exception", lambda *a: a[-1].write("foo") ) + assert "foo" == _format_exception(exc_info) @@ -138,8 +147,9 @@ def test_no_trailing_nl(self, monkeypatch): one nothing is removed. """ from structlog._frames import traceback + monkeypatch.setattr( - traceback, "print_stack", - lambda frame, file: file.write("foo") + traceback, "print_stack", lambda frame, file: file.write("foo") ) + assert _format_stack(sys._getframe()).endswith("foo") diff --git a/tests/test_generic.py b/tests/test_generic.py index 6099ef3b..3f234425 100644 --- a/tests/test_generic.py +++ b/tests/test_generic.py @@ -11,10 +11,10 @@ class TestLogger(object): def log(self, msg): - return 'log', msg + return "log", msg def gol(self, msg): - return 'gol', msg + return "gol", msg class TestGenericBoundLogger(object): @@ -27,9 +27,12 @@ def test_caches(self): _CONFIG.default_processors, _CONFIG.default_context_class(), ) - assert 'msg' not in b.__dict__ - b.msg('foo') - assert 'msg' in b.__dict__ + + assert "msg" not in b.__dict__ + + b.msg("foo") + + assert "msg" in b.__dict__ def test_proxies_anything(self): """ @@ -41,5 +44,6 @@ def test_proxies_anything(self): _CONFIG.default_processors, _CONFIG.default_context_class(), ) - assert 'log', 'foo' == b.log('foo') - assert 'gol', 'bar' == b.gol('bar') + + assert "log", "foo" == b.log("foo") + assert "gol", "bar" == b.gol("bar") diff --git a/tests/test_loggers.py b/tests/test_loggers.py index 5b6f8d8a..19d16a41 100644 --- a/tests/test_loggers.py +++ b/tests/test_loggers.py @@ -11,18 +11,21 @@ from six.moves import cStringIO as StringIO from structlog._loggers import ( - WRITE_LOCKS, PrintLogger, PrintLoggerFactory, ReturnLogger, - ReturnLoggerFactory + WRITE_LOCKS, + PrintLogger, + PrintLoggerFactory, + ReturnLogger, + ReturnLoggerFactory, ) from structlog.stdlib import _NAME_TO_LEVEL def test_return_logger(): - obj = ['hello'] + obj = ["hello"] assert obj is ReturnLogger().msg(obj) -STDLIB_MSG_METHODS = [m for m in _NAME_TO_LEVEL if m != 'notset'] +STDLIB_MSG_METHODS = [m for m in _NAME_TO_LEVEL if m != "notset"] class TestPrintLogger(object): @@ -34,8 +37,8 @@ def test_prints_to_stdout_by_default(self, capsys): PrintLogger().msg("hello") out, err = capsys.readouterr() - assert 'hello\n' == out - assert '' == err + assert "hello\n" == out + assert "" == err def test_prints_to_correct_file(self, tmpdir, capsys): """ @@ -54,9 +57,7 @@ def test_repr(self): """ __repr__ makes sense. """ - assert repr(PrintLogger()).startswith( - " b=[3, 4] x=7 y='test' z=(1, 2)" == - KeyValueRenderer(sort_keys=True)(None, None, event_dict) - ) + rv = KeyValueRenderer(sort_keys=True)(None, None, event_dict) + + assert r"a= b=[3, 4] x=7 y='test' z=(1, 2)" == rv def test_order_complete(self, event_dict): """ Orders keys according to key_order. """ - assert ( - r"y='test' b=[3, 4] a= z=(1, 2) x=7" == - KeyValueRenderer(key_order=['y', 'b', 'a', 'z', 'x']) - (None, None, event_dict) + rv = KeyValueRenderer(key_order=["y", "b", "a", "z", "x"])( + None, None, event_dict ) + assert r"y='test' b=[3, 4] a= z=(1, 2) x=7" == rv + def test_order_missing(self, event_dict): """ Missing keys get rendered as None. """ - assert ( - r"c=None y='test' b=[3, 4] a= z=(1, 2) x=7" == - KeyValueRenderer(key_order=['c', 'y', 'b', 'a', 'z', 'x']) - (None, None, event_dict) + rv = KeyValueRenderer(key_order=["c", "y", "b", "a", "z", "x"])( + None, None, event_dict ) + assert r"c=None y='test' b=[3, 4] a= z=(1, 2) x=7" == rv + def test_order_missing_dropped(self, event_dict): """ Missing keys get dropped """ - assert ( - r"y='test' b=[3, 4] a= z=(1, 2) x=7" == - KeyValueRenderer(key_order=['c', 'y', 'b', 'a', 'z', 'x'], - drop_missing=True) - (None, None, event_dict) - ) + rv = KeyValueRenderer( + key_order=["c", "y", "b", "a", "z", "x"], drop_missing=True + )(None, None, event_dict) + + assert r"y='test' b=[3, 4] a= z=(1, 2) x=7" == rv def test_order_extra(self, event_dict): """ Extra keys get sorted if sort_keys=True. """ - event_dict['B'] = 'B' - event_dict['A'] = 'A' + event_dict["B"] = "B" + event_dict["A"] = "A" + + rv = KeyValueRenderer( + key_order=["c", "y", "b", "a", "z", "x"], sort_keys=True + )(None, None, event_dict) + assert ( - r"c=None y='test' b=[3, 4] a= z=(1, 2) x=7 A='A' B='B'" == - KeyValueRenderer(key_order=['c', 'y', 'b', 'a', 'z', 'x'], - sort_keys=True) - (None, None, event_dict) - ) + r"c=None y='test' b=[3, 4] a= z=(1, 2) x=7 A='A' B='B'" + ) == rv def test_order_sorted_missing_dropped(self, event_dict): """ Keys get sorted if sort_keys=True and extras get dropped. """ - event_dict['B'] = 'B' - event_dict['A'] = 'A' - assert ( - r"y='test' b=[3, 4] a= z=(1, 2) x=7 A='A' B='B'" == - KeyValueRenderer(key_order=['c', 'y', 'b', 'a', 'z', 'x'], - sort_keys=True, drop_missing=True) - (None, None, event_dict) - ) + event_dict["B"] = "B" + event_dict["A"] = "A" + + rv = KeyValueRenderer( + key_order=["c", "y", "b", "a", "z", "x"], + sort_keys=True, + drop_missing=True, + )(None, None, event_dict) + + assert r"y='test' b=[3, 4] a= z=(1, 2) x=7 A='A' B='B'" == rv def test_random_order(self, event_dict): """ No special ordering doesn't blow up. """ rv = KeyValueRenderer()(None, None, event_dict) + assert isinstance(rv, str) @pytest.mark.parametrize("rns", [True, False]) @@ -117,9 +127,9 @@ def test_repr_native_str(self, rns): """ repr_native_str=False doesn't repr on native strings. """ - rv = KeyValueRenderer(repr_native_str=rns)(None, None, { - "event": "哈", "key": 42, "key2": "哈", - }) + rv = KeyValueRenderer(repr_native_str=rns)( + None, None, {"event": "哈", "key": 42, "key2": "哈"} + ) cnt = rv.count("哈") if rns and six.PY2: @@ -133,26 +143,32 @@ def test_renders_json(self, event_dict): """ Renders a predictable JSON string. """ + rv = JSONRenderer(sort_keys=True)(None, None, event_dict) + assert ( - r'{"a": "", "b": [3, 4], "x": 7, "y": "test", "z": ' - r'[1, 2]}' == - JSONRenderer(sort_keys=True)(None, None, event_dict) - ) + r'{"a": "", "b": [3, 4], "x": 7, ' + r'"y": "test", "z": ' + r"[1, 2]}" + ) == rv def test_FallbackEncoder_handles_ThreadLocalDictWrapped_dicts(self): """ Our fallback handling handles properly ThreadLocalDictWrapper values. """ - s = json.dumps(wrap_dict(dict)({'a': 42}), - default=_json_fallback_handler) + s = json.dumps( + wrap_dict(dict)({"a": 42}), default=_json_fallback_handler + ) + assert '{"a": 42}' == s def test_FallbackEncoder_falls_back(self): """ The fallback handler uses repr if it doesn't know the type. """ - s = json.dumps({'date': datetime.date(1980, 3, 25)}, - default=_json_fallback_handler) + s = json.dumps( + {"date": datetime.date(1980, 3, 25)}, + default=_json_fallback_handler, + ) assert '{"date": "datetime.date(1980, 3, 25)"}' == s @@ -170,7 +186,7 @@ def test_custom_fallback(self): A custom fallback handler can be used. """ jr = JSONRenderer(default=lambda x: repr(x)[::-1]) - d = {'date': datetime.date(1980, 3, 25)} + d = {"date": datetime.date(1980, 3, 25)} assert '{"date": ")52 ,3 ,0891(etad.emitetad"}' == jr(None, None, d) @@ -182,11 +198,16 @@ def test_simplejson(self, event_dict): jr = JSONRenderer(serializer=simplejson.dumps) assert { - 'a': '', 'b': [3, 4], 'x': 7, 'y': 'test', 'z': [1, 2] + "a": "", + "b": [3, 4], + "x": 7, + "y": "test", + "z": [1, 2], } == json.loads(jr(None, None, event_dict)) - @pytest.mark.skipif(rapidjson is None, - reason="python-rapidjson is missing.") + @pytest.mark.skipif( + rapidjson is None, reason="python-rapidjson is missing." + ) def test_rapidjson(self, event_dict): """ Integration test with python-rapidjson. @@ -194,7 +215,11 @@ def test_rapidjson(self, event_dict): jr = JSONRenderer(serializer=rapidjson.dumps) assert { - 'a': '', 'b': [3, 4], 'x': 7, 'y': 'test', 'z': [1, 2] + "a": "", + "b": [3, 4], + "x": 7, + "y": "test", + "z": [1, 2], } == json.loads(jr(None, None, event_dict)) @@ -219,7 +244,7 @@ def test_inserts_utc_unix_timestamp_by_default(self): # freezegun doesn't work with time.time. :( assert isinstance(d["timestamp"], float) - @freeze_time('1980-03-25 16:00:00') + @freeze_time("1980-03-25 16:00:00") def test_local(self): """ Timestamp in local timezone work. We can't add a timezone to the @@ -230,7 +255,7 @@ def test_local(self): assert "1980-03-25T16:00:00" == d["timestamp"] - @freeze_time('1980-03-25 16:00:00') + @freeze_time("1980-03-25 16:00:00") def test_formats(self): """ The fmt string is respected. @@ -240,7 +265,7 @@ def test_formats(self): assert "1980" == d["timestamp"] - @freeze_time('1980-03-25 16:00:00') + @freeze_time("1980-03-25 16:00:00") def test_adds_Z_to_iso(self): """ stdlib's isoformat is buggy, so we fix it. @@ -250,7 +275,7 @@ def test_adds_Z_to_iso(self): assert "1980-03-25T16:00:00Z" == d["timestamp"] - @freeze_time('1980-03-25 16:00:00') + @freeze_time("1980-03-25 16:00:00") def test_key_can_be_specified(self): """ Timestamp is stored with the specified key. @@ -266,10 +291,13 @@ def test_formats_tuple(self, monkeypatch): """ If exc_info is a tuple, it is used. """ - monkeypatch.setattr(structlog.processors, - "_format_exception", - lambda exc_info: exc_info) + monkeypatch.setattr( + structlog.processors, + "_format_exception", + lambda exc_info: exc_info, + ) d = format_exc_info(None, None, {"exc_info": (None, None, 42)}) + assert {"exception": (None, None, 42)} == d def test_gets_exc_info_on_bool(self): @@ -279,20 +307,23 @@ def test_gets_exc_info_on_bool(self): # monkeypatching sys.exc_info makes currently py.test return 1 on # success. try: - raise ValueError('test') + raise ValueError("test") except ValueError: d = format_exc_info(None, None, {"exc_info": True}) + assert "exc_info" not in d - assert "raise ValueError('test')\nValueError: test" in d["exception"] + assert 'raise ValueError("test")\nValueError: test' in d["exception"] @py3_only def test_exception_on_py3(self, monkeypatch): """ Passing excetions as exc_info is valid on Python 3. """ - monkeypatch.setattr(structlog.processors, - "_format_exception", - lambda exc_info: exc_info) + monkeypatch.setattr( + structlog.processors, + "_format_exception", + lambda exc_info: exc_info, + ) try: raise ValueError("test") except ValueError as e: @@ -306,9 +337,10 @@ def test_exception_without_traceback(self): """ If an Exception is missing a traceback, render it anyway. """ - rv = format_exc_info(None, None, { - "exc_info": Exception("no traceback!") - }) + rv = format_exc_info( + None, None, {"exc_info": Exception("no traceback!")} + ) + assert {"exception": "Exception: no traceback!"} == rv @@ -318,6 +350,7 @@ def test_encodes(self): Unicode strings get encoded (as UTF-8 by default). """ ue = UnicodeEncoder() + assert {"foo": b"b\xc3\xa4r"} == ue(None, None, {"foo": u"b\xe4r"}) def test_passes_arguments(self): @@ -325,6 +358,7 @@ def test_passes_arguments(self): Encoding options are passed into the encoding call. """ ue = UnicodeEncoder("latin1", "xmlcharrefreplace") + assert {"foo": b"–"} == ue(None, None, {"foo": u"\u2013"}) def test_bytes_nop(self): @@ -332,6 +366,7 @@ def test_bytes_nop(self): If the string is already bytes, don't do anything. """ ue = UnicodeEncoder() + assert {"foo": b"b\xc3\xa4r"} == ue(None, None, {"foo": b"b\xc3\xa4r"}) @@ -341,6 +376,7 @@ def test_decodes(self): Byte strings get decoded (as UTF-8 by default). """ ud = UnicodeDecoder() + assert {"foo": u"b\xe4r"} == ud(None, None, {"foo": b"b\xc3\xa4r"}) def test_passes_arguments(self): @@ -348,6 +384,7 @@ def test_passes_arguments(self): Encoding options are passed into the encoding call. """ ud = UnicodeDecoder("utf-8", "ignore") + assert {"foo": u""} == ud(None, None, {"foo": b"\xa1\xa4"}) def test_bytes_nop(self): @@ -355,6 +392,7 @@ def test_bytes_nop(self): If the value is already unicode, don't do anything. """ ud = UnicodeDecoder() + assert {"foo": u"b\u2013r"} == ud(None, None, {"foo": u"b\u2013r"}) @@ -364,6 +402,7 @@ def test_stdout_by_default(self): If no file is supplied, use stdout. """ epp = ExceptionPrettyPrinter() + assert sys.stdout is epp._file def test_prints_exception(self, sio): @@ -375,12 +414,13 @@ def test_prints_exception(self, sio): try: raise ValueError except ValueError: - ed = format_exc_info(None, None, {'exc_info': True}) + ed = format_exc_info(None, None, {"exc_info": True}) epp(None, None, ed) out = sio.getvalue() - assert 'test_prints_exception' in out - assert 'raise ValueError' in out + + assert "test_prints_exception" in out + assert "raise ValueError" in out def test_removes_exception_after_printing(self, sio): """ @@ -390,10 +430,13 @@ def test_removes_exception_after_printing(self, sio): try: raise ValueError except ValueError: - ed = format_exc_info(None, None, {'exc_info': True}) - assert 'exception' in ed + ed = format_exc_info(None, None, {"exc_info": True}) + + assert "exception" in ed + new_ed = epp(None, None, ed) - assert 'exception' not in new_ed + + assert "exception" not in new_ed def test_handles_exc_info(self, sio): """ @@ -403,11 +446,12 @@ def test_handles_exc_info(self, sio): try: raise ValueError except ValueError: - epp(None, None, {'exc_info': True}) + epp(None, None, {"exc_info": True}) out = sio.getvalue() - assert 'test_handles_exc_info' in out - assert 'raise ValueError' in out + + assert "test_handles_exc_info" in out + assert "raise ValueError" in out def test_removes_exc_info_after_printing(self, sio): """ @@ -417,8 +461,9 @@ def test_removes_exc_info_after_printing(self, sio): try: raise ValueError except ValueError: - ed = epp(None, None, {'exc_info': True}) - assert 'exc_info' not in ed + ed = epp(None, None, {"exc_info": True}) + + assert "exc_info" not in ed def test_nop_if_no_exception(self, sio): """ @@ -426,7 +471,8 @@ def test_nop_if_no_exception(self, sio): """ epp = ExceptionPrettyPrinter(sio) epp(None, None, {}) - assert '' == sio.getvalue() + + assert "" == sio.getvalue() def test_own_exc_info(self, sio): """ @@ -439,6 +485,7 @@ def test_own_exc_info(self, sio): ei = sys.exc_info() epp(None, None, {"exc_info": ei}) + assert "XXX" in sio.getvalue() @py3_only @@ -451,6 +498,7 @@ def test_exception_on_py3(self, sio): raise ValueError("XXX") except ValueError as e: epp(None, None, {"exc_info": e}) + assert "XXX" in sio.getvalue() @@ -464,31 +512,32 @@ def test_removes_stack_info(self, sir): """ The `stack_info` key is removed from `event_dict`. """ - ed = sir(None, None, {'stack_info': True}) - assert 'stack_info' not in ed + ed = sir(None, None, {"stack_info": True}) + + assert "stack_info" not in ed def test_adds_stack_if_asked(self, sir): """ If `stack_info` is true, `stack` is added. """ - ed = sir(None, None, {'stack_info': True}) - assert 'stack' in ed + ed = sir(None, None, {"stack_info": True}) + + assert "stack" in ed def test_renders_correct_stack(self, sir): - ed = sir(None, None, {'stack_info': True}) - assert "ed = sir(None, None, {'stack_info': True})" in ed['stack'] + ed = sir(None, None, {"stack_info": True}) + + assert 'ed = sir(None, None, {"stack_info": True})' in ed["stack"] class TestFigureOutExcInfo(object): - @pytest.mark.parametrize('true_value', [ - True, 1, 1.1 - ]) + @pytest.mark.parametrize("true_value", [True, 1, 1.1]) def test_obtains_exc_info_on_True(self, true_value): """ If the passed argument evaluates to True obtain exc_info ourselves. """ try: - 0/0 + 0 / 0 except Exception: assert sys.exc_info() == _figure_out_exc_info(true_value) else: @@ -501,4 +550,5 @@ def test_py3_exception_no_traceback(self): traceback. """ e = ValueError() + assert (e.__class__, e, None) == _figure_out_exc_info(e) diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 0720bdc6..d27de0bc 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -18,10 +18,19 @@ from structlog.exceptions import DropEvent from structlog.processors import JSONRenderer from structlog.stdlib import ( - _NAME_TO_LEVEL, CRITICAL, WARN, BoundLogger, LoggerFactory, - PositionalArgumentsFormatter, ProcessorFormatter, _FixedFindCallerLogger, - add_log_level, add_log_level_number, add_logger_name, filter_by_level, - render_to_log_kwargs + _NAME_TO_LEVEL, + CRITICAL, + WARN, + BoundLogger, + LoggerFactory, + PositionalArgumentsFormatter, + ProcessorFormatter, + _FixedFindCallerLogger, + add_log_level, + add_log_level_number, + add_logger_name, + filter_by_level, + render_to_log_kwargs, ) from .additional_frame import additional_frame @@ -32,11 +41,7 @@ def build_bl(logger=None, processors=None, context=None): """ Convenience function to build BoundLogger with sane defaults. """ - return BoundLogger( - logger or ReturnLogger(), - processors, - {} - ) + return BoundLogger(logger or ReturnLogger(), processors, {}) def return_method_name(_, method_name, __): @@ -62,51 +67,62 @@ def test_deduces_correct_name(self): The factory isn't called directly but from structlog._config so deducing has to be slightly smarter. """ - assert 'tests.additional_frame' == ( + assert "tests.additional_frame" == ( additional_frame(LoggerFactory()).name ) - assert 'tests.test_stdlib' == LoggerFactory()().name + assert "tests.test_stdlib" == LoggerFactory()().name def test_ignores_frames(self): """ The name guesser walks up the frames until it reaches a frame whose name is not from structlog or one of the configurable other names. """ - assert '__main__' == additional_frame(LoggerFactory( - ignore_frame_names=["tests.", "_pytest.", "pluggy"]) - ).name + assert ( + "__main__" + == additional_frame( + LoggerFactory( + ignore_frame_names=["tests.", "_pytest.", "pluggy"] + ) + ).name + ) def test_deduces_correct_caller(self): - logger = _FixedFindCallerLogger('test') + logger = _FixedFindCallerLogger("test") file_name, line_number, func_name = logger.findCaller()[:3] + assert file_name == os.path.realpath(__file__) - assert func_name == 'test_deduces_correct_caller' + assert func_name == "test_deduces_correct_caller" @py3_only def test_stack_info(self): - logger = _FixedFindCallerLogger('test') + logger = _FixedFindCallerLogger("test") testing, is_, fun, stack_info = logger.findCaller(stack_info=True) - assert 'testing, is_, fun' in stack_info + + assert "testing, is_, fun" in stack_info @py3_only def test_no_stack_info_by_default(self): - logger = _FixedFindCallerLogger('test') + logger = _FixedFindCallerLogger("test") testing, is_, fun, stack_info = logger.findCaller() + assert None is stack_info def test_find_caller(self, monkeypatch): logger = LoggerFactory()() log_handle = call_recorder(lambda x: None) - monkeypatch.setattr(logger, 'handle', log_handle) - logger.error('Test') + monkeypatch.setattr(logger, "handle", log_handle) + logger.error("Test") log_record = log_handle.calls[0].args[0] - assert log_record.funcName == 'test_find_caller' + + assert log_record.funcName == "test_find_caller" assert log_record.name == __name__ assert log_record.filename == os.path.basename(__file__) def test_sets_correct_logger(self): assert logging.getLoggerClass() is logging.Logger + LoggerFactory() + assert logging.getLoggerClass() is _FixedFindCallerLogger def test_positional_argument_avoids_guessing(self): @@ -124,33 +140,36 @@ def test_filters_lower_levels(self): logger = logging.Logger(__name__) logger.setLevel(CRITICAL) with pytest.raises(DropEvent): - filter_by_level(logger, 'warn', {}) + filter_by_level(logger, "warn", {}) def test_passes_higher_levels(self): logger = logging.Logger(__name__) logger.setLevel(WARN) - event_dict = {'event': 'test'} - assert event_dict is filter_by_level(logger, 'warn', event_dict) - assert event_dict is filter_by_level(logger, 'error', event_dict) - assert event_dict is filter_by_level(logger, 'exception', event_dict) + event_dict = {"event": "test"} + + assert event_dict is filter_by_level(logger, "warn", event_dict) + assert event_dict is filter_by_level(logger, "error", event_dict) + assert event_dict is filter_by_level(logger, "exception", event_dict) class TestBoundLogger(object): - @pytest.mark.parametrize(('method_name'), [ - 'debug', 'info', 'warning', 'error', 'critical', - ]) + @pytest.mark.parametrize( + ("method_name"), ["debug", "info", "warning", "error", "critical"] + ) def test_proxies_to_correct_method(self, method_name): """ The basic proxied methods are proxied to the correct counterparts. """ bl = BoundLogger(ReturnLogger(), [return_method_name], {}) - assert method_name == getattr(bl, method_name)('event') + + assert method_name == getattr(bl, method_name)("event") def test_proxies_exception(self): """ BoundLogger.exception is proxied to Logger.error. """ bl = BoundLogger(ReturnLogger(), [return_method_name], {}) + assert "error" == bl.exception("event") def test_proxies_log(self): @@ -158,6 +177,7 @@ def test_proxies_log(self): BoundLogger.exception.log() is proxied to the apropriate method. """ bl = BoundLogger(ReturnLogger(), [return_method_name], {}) + assert "critical" == bl.log(50, "event") assert "debug" == bl.log(10, "event") @@ -166,24 +186,38 @@ def test_positional_args_proxied(self): Positional arguments supplied are proxied as kwarg. """ bl = BoundLogger(ReturnLogger(), [], {}) - args, kwargs = bl.debug('event', 'foo', bar='baz') - assert 'baz' == kwargs.get('bar') - assert ('foo',) == kwargs.get('positional_args') - - @pytest.mark.parametrize('method_name,method_args', [ - ('addHandler', [None]), - ('removeHandler', [None]), - ('hasHandlers', None), - ('callHandlers', [None]), - ('handle', [None]), - ('setLevel', [None]), - ('getEffectiveLevel', None), - ('isEnabledFor', [None]), - ('findCaller', None), - ('makeRecord', ['name', 'debug', 'test_func', '1', - 'test msg', ['foo'], False]), - ('getChild', [None]), - ]) + args, kwargs = bl.debug("event", "foo", bar="baz") + + assert "baz" == kwargs.get("bar") + assert ("foo",) == kwargs.get("positional_args") + + @pytest.mark.parametrize( + "method_name,method_args", + [ + ("addHandler", [None]), + ("removeHandler", [None]), + ("hasHandlers", None), + ("callHandlers", [None]), + ("handle", [None]), + ("setLevel", [None]), + ("getEffectiveLevel", None), + ("isEnabledFor", [None]), + ("findCaller", None), + ( + "makeRecord", + [ + "name", + "debug", + "test_func", + "1", + "test msg", + ["foo"], + False, + ], + ), + ("getChild", [None]), + ], + ) def test_stdlib_passthrough_methods(self, method_name, method_args): """ stdlib logger methods are also available in stdlib BoundLogger. @@ -193,17 +227,20 @@ def test_stdlib_passthrough_methods(self, method_name, method_args): def validate(*args, **kw): called_stdlib_method[0] = True - stdlib_logger = logging.getLogger('Test') + stdlib_logger = logging.getLogger("Test") stdlib_logger_method = getattr(stdlib_logger, method_name, None) if stdlib_logger_method: setattr(stdlib_logger, method_name, validate) bl = BoundLogger(stdlib_logger, [], {}) bound_logger_method = getattr(bl, method_name) + assert bound_logger_method is not None + if method_args: bound_logger_method(*method_args) else: bound_logger_method() + assert called_stdlib_method[0] is True def test_exception_exc_info(self): @@ -212,10 +249,9 @@ def test_exception_exc_info(self): """ bl = BoundLogger(ReturnLogger(), [], {}) - assert ( - (), - {"exc_info": True, "event": "event"} - ) == bl.exception("event") + assert ((), {"exc_info": True, "event": "event"}) == bl.exception( + "event" + ) def test_exception_exc_info_override(self): """ @@ -223,10 +259,9 @@ def test_exception_exc_info_override(self): """ bl = BoundLogger(ReturnLogger(), [], {}) - assert ( - (), - {"exc_info": 42, "event": "event"} - ) == bl.exception("event", exc_info=42) + assert ((), {"exc_info": 42, "event": "event"}) == bl.exception( + "event", exc_info=42 + ) class TestPositionalArgumentsFormatter(object): @@ -235,21 +270,28 @@ def test_formats_tuple(self): Positional arguments as simple types are rendered. """ formatter = PositionalArgumentsFormatter() - event_dict = formatter(None, None, {'event': '%d %d %s', - 'positional_args': (1, 2, 'test')}) - assert '1 2 test' == event_dict['event'] - assert 'positional_args' not in event_dict + event_dict = formatter( + None, + None, + {"event": "%d %d %s", "positional_args": (1, 2, "test")}, + ) + + assert "1 2 test" == event_dict["event"] + assert "positional_args" not in event_dict def test_formats_dict(self): """ Positional arguments as dict are rendered. """ formatter = PositionalArgumentsFormatter() - event_dict = formatter(None, None, {'event': '%(foo)s bar', - 'positional_args': ( - {'foo': 'bar'},)}) - assert 'bar bar' == event_dict['event'] - assert 'positional_args' not in event_dict + event_dict = formatter( + None, + None, + {"event": "%(foo)s bar", "positional_args": ({"foo": "bar"},)}, + ) + + assert "bar bar" == event_dict["event"] + assert "positional_args" not in event_dict def test_positional_args_retained(self): """ @@ -257,18 +299,22 @@ def test_positional_args_retained(self): argument is set to False. """ formatter = PositionalArgumentsFormatter(remove_positional_args=False) - positional_args = (1, 2, 'test') + positional_args = (1, 2, "test") event_dict = formatter( - None, None, - {'event': '%d %d %s', 'positional_args': positional_args}) - assert 'positional_args' in event_dict - assert positional_args == event_dict['positional_args'] + None, + None, + {"event": "%d %d %s", "positional_args": positional_args}, + ) + + assert "positional_args" in event_dict + assert positional_args == event_dict["positional_args"] def test_nop_no_args(self): """ If no positional args are passed, nothing happens. """ formatter = PositionalArgumentsFormatter() + assert {} == formatter(None, None, {}) def test_args_removed_if_empty(self): @@ -284,13 +330,14 @@ def test_args_removed_if_empty(self): class TestAddLogLevelNumber(object): - @pytest.mark.parametrize('level, number', _NAME_TO_LEVEL.items()) + @pytest.mark.parametrize("level, number", _NAME_TO_LEVEL.items()) def test_log_level_number_added(self, level, number): """ The log level number is added to the event dict. """ event_dict = add_log_level_number(None, level, {}) - assert number == event_dict['level_number'] + + assert number == event_dict["level_number"] class TestAddLogLevel(object): @@ -298,15 +345,17 @@ def test_log_level_added(self): """ The log level is added to the event dict. """ - event_dict = add_log_level(None, 'error', {}) - assert 'error' == event_dict['level'] + event_dict = add_log_level(None, "error", {}) + + assert "error" == event_dict["level"] def test_log_level_alias_normalized(self): """ The normalized name of the log level is added to the event dict. """ - event_dict = add_log_level(None, 'warn', {}) - assert 'warning' == event_dict['level'] + event_dict = add_log_level(None, "warn", {}) + + assert "warning" == event_dict["level"] @pytest.fixture @@ -314,6 +363,7 @@ def log_record(): """ A LogRecord factory. """ + def create_log_record(**kwargs): defaults = { "name": "sample-name", @@ -326,6 +376,7 @@ def create_log_record(**kwargs): } defaults.update(kwargs) return logging.LogRecord(**defaults) + return create_log_record @@ -337,6 +388,7 @@ def test_logger_name_added(self): name = "sample-name" logger = logging.getLogger(name) event_dict = add_logger_name(logger, None, {}) + assert name == event_dict["logger"] def test_logger_name_added_with_record(self, log_record): @@ -346,6 +398,7 @@ def test_logger_name_added_with_record(self, log_record): name = "sample-name" record = log_record(name=name) event_dict = add_logger_name(None, None, {"_record": record}) + assert name == event_dict["logger"] @@ -376,10 +429,7 @@ def configure_for_pf(): Reset both structlog and logging setting after the test. """ configure( - processors=[ - add_log_level, - ProcessorFormatter.wrap_for_formatter, - ], + processors=[add_log_level, ProcessorFormatter.wrap_for_formatter], logger_factory=LoggerFactory(), wrapper_class=BoundLogger, ) @@ -394,38 +444,41 @@ def configure_logging(pre_chain): """ Configure logging to use ProcessorFormatter. """ - return logging.config.dictConfig({ - "version": 1, - "disable_existing_loggers": False, - "formatters": { - "plain": { - "()": ProcessorFormatter, - "processor": ConsoleRenderer(colors=False), - "foreign_pre_chain": pre_chain, - "format": "%(message)s [in %(funcName)s]" - } - }, - "handlers": { - "default": { - "level": "DEBUG", - "class": "logging.StreamHandler", - "formatter": "plain", + return logging.config.dictConfig( + { + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "plain": { + "()": ProcessorFormatter, + "processor": ConsoleRenderer(colors=False), + "foreign_pre_chain": pre_chain, + "format": "%(message)s [in %(funcName)s]", + } }, - }, - "loggers": { - "": { - "handlers": ["default"], - "level": "DEBUG", - "propagate": True, + "handlers": { + "default": { + "level": "DEBUG", + "class": "logging.StreamHandler", + "formatter": "plain", + } + }, + "loggers": { + "": { + "handlers": ["default"], + "level": "DEBUG", + "propagate": True, + } }, } - }) + ) class TestProcessorFormatter(object): """ These are all integration tests because they're all about integration. """ + def test_foreign_delegate(self, configure_for_pf, capsys): """ If foreign_pre_chain is None, non-structlog log entries are delegated @@ -433,19 +486,14 @@ def test_foreign_delegate(self, configure_for_pf, capsys): """ configure_logging(None) configure( - processors=[ - ProcessorFormatter.wrap_for_formatter, - ], + processors=[ProcessorFormatter.wrap_for_formatter], logger_factory=LoggerFactory(), wrapper_class=BoundLogger, ) logging.getLogger().warning("foo") - assert ( - "", - "foo [in test_foreign_delegate]\n", - ) == capsys.readouterr() + assert ("", "foo [in test_foreign_delegate]\n") == capsys.readouterr() def test_clears_args(self, capsys, configure_for_pf): """ @@ -470,9 +518,7 @@ def test_foreign_pre_chain(self, configure_for_pf, capsys): """ configure_logging((add_log_level,)) configure( - processors=[ - ProcessorFormatter.wrap_for_formatter, - ], + processors=[ProcessorFormatter.wrap_for_formatter], logger_factory=LoggerFactory(), wrapper_class=BoundLogger, ) @@ -490,9 +536,7 @@ def test_foreign_pre_chain_add_logger_name(self, configure_for_pf, capsys): """ configure_logging((add_logger_name,)) configure( - processors=[ - ProcessorFormatter.wrap_for_formatter, - ], + processors=[ProcessorFormatter.wrap_for_formatter], logger_factory=LoggerFactory(), wrapper_class=BoundLogger, ) @@ -513,9 +557,7 @@ def test_foreign_pre_chain_gets_exc_info(self, configure_for_pf, capsys): test_processor = call_recorder(lambda l, m, event_dict: event_dict) configure_logging((test_processor,)) configure( - processors=[ - ProcessorFormatter.wrap_for_formatter, - ], + processors=[ProcessorFormatter.wrap_for_formatter], logger_factory=LoggerFactory(), wrapper_class=BoundLogger, ) @@ -526,11 +568,13 @@ def test_foreign_pre_chain_gets_exc_info(self, configure_for_pf, capsys): logging.getLogger().exception("okay") event_dict = test_processor.calls[0].args[2] + assert "exc_info" in event_dict assert isinstance(event_dict["exc_info"], tuple) - def test_other_handlers_get_original_record(self, configure_for_pf, - capsys): + def test_other_handlers_get_original_record( + self, configure_for_pf, capsys + ): """ Logging handlers that come after the handler with ProcessorFormatter should receive original, unmodified record. @@ -549,7 +593,9 @@ def test_other_handlers_get_original_record(self, configure_for_pf, logger.info("meh") assert 1 == len(handler2.handle.calls) + handler2_record = handler2.handle.calls[0].args[0] + assert "meh" == handler2_record.msg @pytest.mark.parametrize("keep", [True, False]) @@ -581,7 +627,9 @@ def format_exc_info_fake(logger, name, event_dict): logging.getLogger().exception("seen worse") out, err = capsys.readouterr() + assert "" == out + if keep is False: assert ( '{"event": "seen worse", "exception": "Exception!"}\n' @@ -610,7 +658,9 @@ def test_formatter_unsets_stack_info(self, configure_for_pf, capsys, keep): logging.getLogger().warning("have a stack trace", stack_info=True) out, err = capsys.readouterr() + assert "" == out + if keep is False: assert 1 == err.count("Stack (most recent call last):") else: diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py index 8cf43e90..d08df743 100644 --- a/tests/test_threadlocal.py +++ b/tests/test_threadlocal.py @@ -53,11 +53,13 @@ def test_bind(self, log): tmp_bind does not modify the thread-local state. """ log = log.bind(y=23) - with tmp_bind(log, x=42, y='foo') as tmp_log: - assert { - 'y': 'foo', 'x': 42 - } == tmp_log._context._dict == log._context._dict - assert {'y': 23} == log._context._dict + with tmp_bind(log, x=42, y="foo") as tmp_log: + assert ( + {"y": "foo", "x": 42} + == tmp_log._context._dict + == log._context._dict + ) + assert {"y": 23} == log._context._dict def test_bind_exc(self, log): """ @@ -65,12 +67,15 @@ def test_bind_exc(self, log): """ log = log.bind(y=23) with pytest.raises(ValueError): - with tmp_bind(log, x=42, y='foo') as tmp_log: - assert { - 'y': 'foo', 'x': 42 - } == tmp_log._context._dict == log._context._dict + with tmp_bind(log, x=42, y="foo") as tmp_log: + assert ( + {"y": "foo", "x": 42} + == tmp_log._context._dict + == log._context._dict + ) raise ValueError - assert {'y': 23} == log._context._dict + + assert {"y": 23} == log._context._dict class TestAsImmutable(object): @@ -80,10 +85,13 @@ def test_does_not_affect_global(self, log): """ log = log.new(x=42) il = as_immutable(log) + assert isinstance(il._context, dict) + il = il.bind(y=23) - assert {'x': 42, 'y': 23} == il._context - assert {'x': 42} == log._context._dict + + assert {"x": 42, "y": 23} == il._context + assert {"x": 42} == log._context._dict def test_converts_proxy(self, log): """ @@ -91,6 +99,7 @@ def test_converts_proxy(self, log): logger. """ il = as_immutable(log) + assert isinstance(il._context, dict) assert isinstance(il, BoundLoggerBase) @@ -99,6 +108,7 @@ def test_idempotency(self, log): as_immutable on an as_immutable logger works. """ il = as_immutable(log) + assert isinstance(as_immutable(il), BoundLoggerBase) @@ -110,74 +120,89 @@ def test_wrap_returns_distinct_classes(self): """ D1 = wrap_dict(dict) D2 = wrap_dict(dict) + assert D1 != D2 assert D1 is not D2 + D1.x = 42 D2.x = 23 + assert D1.x != D2.x - @pytest.mark.skipif(greenlet is not None, - reason="Don't mix threads and greenlets.") + @pytest.mark.skipif( + greenlet is not None, reason="Don't mix threads and greenlets." + ) def test_is_thread_local(self, D): """ The context is *not* shared between threads. """ + class TestThread(threading.Thread): def __init__(self, d): self._d = d threading.Thread.__init__(self) def run(self): - assert 'tl' not in self._d._dict - self._d['tl'] = 23 + assert "tl" not in self._d._dict + + self._d["tl"] = 23 + d = wrap_dict(dict)() - d['tl'] = 42 + d["tl"] = 42 t = TestThread(d) t.start() t.join() - assert 42 == d._dict['tl'] + + assert 42 == d._dict["tl"] def test_context_is_global_to_thread(self, D): """ The context is shared between all instances of a wrapped class. """ - d1 = D({'a': 42}) - d2 = D({'b': 23}) + d1 = D({"a": 42}) + d2 = D({"b": 23}) d3 = D() - assert {'a': 42, 'b': 23} == d1._dict == d2._dict == d3._dict + + assert {"a": 42, "b": 23} == d1._dict == d2._dict == d3._dict assert d1 == d2 == d3 + D_ = wrap_dict(dict) - d_ = D_({'a': 42, 'b': 23}) + d_ = D_({"a": 42, "b": 23}) + assert d1 != d_ def test_init_with_itself_works(self, D): """ Initializing with an instance of the wrapped class will use its values. """ - d = D({'a': 42}) - assert {'a': 42, 'b': 23} == D(d, b=23)._dict + d = D({"a": 42}) + + assert {"a": 42, "b": 23} == D(d, b=23)._dict def test_iter_works(self, D): """ ___iter__ is proxied to the wrapped class. """ - d = D({'a': 42}) - assert ['a'] == list(iter(d)) + d = D({"a": 42}) + + assert ["a"] == list(iter(d)) def test_non_dunder_proxy_works(self, D): """ Calls to a non-dunder method get proxied to the wrapped class. """ - d = D({'a': 42}) + d = D({"a": 42}) d.clear() + assert 0 == len(d) def test_repr(self, D): """ ___repr__ takes the repr of the wrapped class into account. """ - r = repr(D({'a': 42})) - assert r.startswith('") @pytest.mark.skipif(greenlet is None, reason="Needs greenlet.") @@ -186,13 +211,15 @@ def test_is_greenlet_local(self, D): Context is shared between greenlets. """ d = wrap_dict(dict)() - d['switch'] = 42 + d["switch"] = 42 def run(): - assert 'x' not in d._dict - d['switch'] = 23 + assert "x" not in d._dict + + d["switch"] = 23 greenlet.greenlet(run).switch() + assert 42 == d._dict["switch"] def test_delattr(self, D): @@ -200,8 +227,10 @@ def test_delattr(self, D): ___delattr__ is proxied to the wrapped class. """ d = D() - d['delattr'] = 42 + d["delattr"] = 42 + assert 42 == d._dict["delattr"] + del d.__class__._tl.dict_ def test_delattr_missing(self, D): @@ -209,8 +238,10 @@ def test_delattr_missing(self, D): __delattr__ on an inexisting attribute raises AttributeError. """ d = D() + with pytest.raises(AttributeError) as e: d._tl.__delattr__("does_not_exist") + assert "does_not_exist" == e.value.args[0] def test_del(self, D): @@ -219,8 +250,11 @@ def test_del(self, D): """ d = D() d["del"] = 13 + assert 13 == d._dict["del"] + del d["del"] + assert "del" not in d._dict def test_new_class(self, D): diff --git a/tests/test_twisted.py b/tests/test_twisted.py index 51a09abd..1c7bdd35 100644 --- a/tests/test_twisted.py +++ b/tests/test_twisted.py @@ -13,21 +13,28 @@ from pretend import call_recorder from six import PY3 from six.moves import cStringIO as StringIO +from twisted.python.failure import Failure, NoCurrentExceptionError +from twisted.python.log import ILogObserver from structlog import ReturnLogger from structlog._config import _CONFIG from structlog.processors import KeyValueRenderer from structlog.twisted import ( - BoundLogger, EventAdapter, JSONLogObserverWrapper, JSONRenderer, - LoggerFactory, PlainFileLogObserver, ReprWrapper, _extractStuffAndWhy, - plainJSONStdOutLogger + BoundLogger, + EventAdapter, + JSONLogObserverWrapper, + JSONRenderer, + LoggerFactory, + PlainFileLogObserver, + ReprWrapper, + _extractStuffAndWhy, + plainJSONStdOutLogger, ) -from twisted.python.failure import Failure, NoCurrentExceptionError -from twisted.python.log import ILogObserver def test_LoggerFactory(): from twisted.python import log + assert log is LoggerFactory()() @@ -52,6 +59,7 @@ def test_msg(self): log.msg renders correctly. """ bl = build_bl() + assert "foo=42 event='event'" == bl.msg("event", foo=42) def test_errVanilla(self): @@ -59,24 +67,30 @@ def test_errVanilla(self): log.err renders correctly if no failure is attached. """ bl = build_bl() + assert "foo=42 event='event'" == bl.err("event", foo=42) def test_errWithFailure(self): """ Failures are correctly injected into the log entries. """ - bl = build_bl(processors=[ - EventAdapter(dictRenderer=KeyValueRenderer()) - ]) + bl = build_bl( + processors=[EventAdapter(dictRenderer=KeyValueRenderer())] + ) try: raise ValueError except ValueError: # Use str() for comparison to avoid tricky # deep-compares of Failures. - assert str(((), { - '_stuff': Failure(ValueError()), - '_why': "foo=42 event='event'", - })) == str(bl.err('event', foo=42)) + assert str( + ( + (), + { + "_stuff": Failure(ValueError()), + "_why": "foo=42 event='event'", + }, + ) + ) == str(bl.err("event", foo=42)) class TestExtractStuffAndWhy(object): @@ -85,11 +99,16 @@ def test_extractFailsOnTwoFailures(self): Raise ValueError if both _stuff and event contain exceptions. """ with pytest.raises(ValueError) as e: - _extractStuffAndWhy({'_stuff': Failure(ValueError()), - 'event': Failure(TypeError())}) + _extractStuffAndWhy( + { + "_stuff": Failure(ValueError()), + "event": Failure(TypeError()), + } + ) + assert ( - "Both _stuff and event contain an Exception/Failure." == - e.value.args[0] + "Both _stuff and event contain an Exception/Failure." + == e.value.args[0] ) def test_failsOnConflictingEventAnd_why(self): @@ -97,35 +116,28 @@ def test_failsOnConflictingEventAnd_why(self): Raise ValueError if both _why and event are in the event_dict. """ with pytest.raises(ValueError) as e: - _extractStuffAndWhy({'_why': 'foo', 'event': 'bar'}) - assert ( - "Both `_why` and `event` supplied." == - e.value.args[0] - ) + _extractStuffAndWhy({"_why": "foo", "event": "bar"}) + + assert "Both `_why` and `event` supplied." == e.value.args[0] def test_handlesFailures(self): """ Extracts failures and events. """ f = Failure(ValueError()) - assert ( - ({'value': f}, "foo", {}) == - _extractStuffAndWhy({"_why": "foo", - "_stuff": {'value': f}}) + + assert ({"value": f}, "foo", {}) == _extractStuffAndWhy( + {"_why": "foo", "_stuff": {"value": f}} ) - assert ( - ({'value': f}, None, {}) == - _extractStuffAndWhy({"_stuff": {'value': f}}) + assert ({"value": f}, None, {}) == _extractStuffAndWhy( + {"_stuff": {"value": f}} ) def test_handlesMissingFailure(self): """ Missing failures extract a None. """ - assert ( - (None, "foo", {}) == - _extractStuffAndWhy({"event": "foo"}) - ) + assert (None, "foo", {}) == _extractStuffAndWhy({"event": "foo"}) @pytest.mark.xfail(PY3, reason="Py3 does not allow for cleaning exc_info") def test_recognizesErrorsAndCleansThem(self): @@ -138,8 +150,10 @@ def test_recognizesErrorsAndCleansThem(self): raise ValueError except ValueError: f = Failure() - _stuff, _why, ed = _extractStuffAndWhy({'event': 'foo'}) + _stuff, _why, ed = _extractStuffAndWhy({"event": "foo"}) + assert _stuff.value is f.value + with pytest.raises(NoCurrentExceptionError): Failure() @@ -151,80 +165,75 @@ class TestEventAdapter(object): def test_EventAdapterFormatsLog(self): la = EventAdapter(_render_repr) - assert "{'foo': 'bar'}" == la(None, 'msg', {'foo': 'bar'}) + + assert "{'foo': 'bar'}" == la(None, "msg", {"foo": "bar"}) def test_transforms_whyIntoEvent(self): """ log.err(_stuff=exc, _why='foo') makes the output 'event="foo"' """ la = EventAdapter(_render_repr) - error = ValueError('test') - rv = la(None, 'err', { - '_stuff': error, - '_why': 'foo', - 'event': None, - }) + error = ValueError("test") + rv = la(None, "err", {"_stuff": error, "_why": "foo", "event": None}) + assert () == rv[0] - assert isinstance(rv[1]['_stuff'], Failure) - assert error == rv[1]['_stuff'].value - assert "{'event': 'foo'}" == rv[1]['_why'] + assert isinstance(rv[1]["_stuff"], Failure) + assert error == rv[1]["_stuff"].value + assert "{'event': 'foo'}" == rv[1]["_why"] def test_worksUsualCase(self): """ log.err(exc, _why='foo') makes the output 'event="foo"' """ la = EventAdapter(_render_repr) - error = ValueError('test') - rv = la(None, 'err', {'event': error, '_why': 'foo'}) + error = ValueError("test") + rv = la(None, "err", {"event": error, "_why": "foo"}) + assert () == rv[0] - assert isinstance(rv[1]['_stuff'], Failure) - assert error == rv[1]['_stuff'].value - assert "{'event': 'foo'}" == rv[1]['_why'] + assert isinstance(rv[1]["_stuff"], Failure) + assert error == rv[1]["_stuff"].value + assert "{'event': 'foo'}" == rv[1]["_why"] def test_allKeywords(self): """ log.err(_stuff=exc, _why='event') """ la = EventAdapter(_render_repr) - error = ValueError('test') - rv = la(None, 'err', {'_stuff': error, '_why': 'foo'}) + error = ValueError("test") + rv = la(None, "err", {"_stuff": error, "_why": "foo"}) + assert () == rv[0] - assert isinstance(rv[1]['_stuff'], Failure) - assert error == rv[1]['_stuff'].value - assert "{'event': 'foo'}" == rv[1]['_why'] + assert isinstance(rv[1]["_stuff"], Failure) + assert error == rv[1]["_stuff"].value + assert "{'event': 'foo'}" == rv[1]["_why"] def test_noFailure(self): """ log.err('event') """ la = EventAdapter(_render_repr) - assert ((), { - '_stuff': None, - '_why': "{'event': 'someEvent'}", - }) == la(None, 'err', { - 'event': 'someEvent' - }) + + assert ((), {"_stuff": None, "_why": "{'event': 'someEvent'}"}) == la( + None, "err", {"event": "someEvent"} + ) def test_noFailureWithKeyword(self): """ log.err(_why='event') """ la = EventAdapter(_render_repr) - assert ((), { - '_stuff': None, - '_why': "{'event': 'someEvent'}", - }) == la(None, 'err', { - '_why': 'someEvent' - }) + + assert ((), {"_stuff": None, "_why": "{'event': 'someEvent'}"}) == la( + None, "err", {"_why": "someEvent"} + ) def test_catchesConflictingEventAnd_why(self): la = EventAdapter(_render_repr) + with pytest.raises(ValueError) as e: - la(None, 'err', { - 'event': 'someEvent', - '_why': 'someReason', - }) - assert 'Both `_why` and `event` supplied.' == e.value.args[0] + la(None, "err", {"event": "someEvent", "_why": "someReason"}) + + assert "Both `_why` and `event` supplied." == e.value.args[0] @pytest.fixture @@ -241,36 +250,44 @@ def test_dumpsKWsAreHandedThrough(self, jr): JSONRenderer allows for setting arguments that are passed to json.dumps(). Make sure they are passed. """ - d = OrderedDict(x='foo') - d.update(a='bar') + d = OrderedDict(x="foo") + d.update(a="bar") jr_sorted = JSONRenderer(sort_keys=True) - assert jr_sorted(None, 'err', d) != jr(None, 'err', d) + + assert jr_sorted(None, "err", d) != jr(None, "err", d) def test_handlesMissingFailure(self, jr): """ Calling err without an actual failure works and returns the event as a string wrapped in ReprWrapper. """ - assert ReprWrapper( - '{"event": "foo"}' - ) == jr(None, "err", {"event": "foo"})[0][0] - assert ReprWrapper( - '{"event": "foo"}' - ) == jr(None, "err", {"_why": "foo"})[0][0] + assert ( + ReprWrapper('{"event": "foo"}') + == jr(None, "err", {"event": "foo"})[0][0] + ) + assert ( + ReprWrapper('{"event": "foo"}') + == jr(None, "err", {"_why": "foo"})[0][0] + ) def test_msgWorksToo(self, jr): """ msg renders the event as a string and wraps it using ReprWrapper. """ - assert ReprWrapper( - '{"event": "foo"}' - ) == jr(None, 'msg', {'_why': 'foo'})[0][0] + assert ( + ReprWrapper('{"event": "foo"}') + == jr(None, "msg", {"_why": "foo"})[0][0] + ) def test_handlesFailure(self, jr): - rv = jr(None, 'err', {'event': Failure(ValueError())})[0][0].string - assert 'Failure: {0}.ValueError'.format("builtins" - if PY3 - else "exceptions") in rv + rv = jr(None, "err", {"event": Failure(ValueError())})[0][0].string + + assert ( + "Failure: {0}.ValueError".format( + "builtins" if PY3 else "exceptions" + ) + in rv + ) assert '"event": "error"' in rv def test_setsStructLogField(self, jr): @@ -278,7 +295,7 @@ def test_setsStructLogField(self, jr): Formatted entries are marked so they can be identified without guessing for example in JSONLogObserverWrapper. """ - assert {'_structlog': True} == jr(None, 'msg', {'_why': 'foo'})[1] + assert {"_structlog": True} == jr(None, "msg", {"_why": "foo"})[1] class TestReprWrapper(object): @@ -295,9 +312,11 @@ def test_isLogObserver(self): def test_writesOnlyMessageWithLF(self): sio = StringIO() - PlainFileLogObserver(sio)({'system': 'some system', - 'message': ('hello',)}) - assert 'hello\n' == sio.getvalue() + PlainFileLogObserver(sio)( + {"system": "some system", "message": ("hello",)} + ) + + assert "hello\n" == sio.getvalue() class TestJSONObserverWrapper(object): @@ -309,7 +328,8 @@ def test_callsWrappedObserver(self): The wrapper always runs the wrapped observer in the end. """ o = call_recorder(lambda *a, **kw: None) - JSONLogObserverWrapper(o)({'message': ('hello',)}) + JSONLogObserverWrapper(o)({"message": ("hello",)}) + assert 1 == len(o.calls) def test_jsonifiesPlainLogEntries(self): @@ -318,15 +338,16 @@ def test_jsonifiesPlainLogEntries(self): now. """ o = call_recorder(lambda *a, **kw: None) - JSONLogObserverWrapper(o)({'message': ('hello',), 'system': '-'}) - msg = json.loads(o.calls[0].args[0]['message'][0]) - assert msg == {'event': 'hello', 'system': '-'} + JSONLogObserverWrapper(o)({"message": ("hello",), "system": "-"}) + msg = json.loads(o.calls[0].args[0]["message"][0]) + + assert msg == {"event": "hello", "system": "-"} def test_leavesStructLogAlone(self): """ Entries that are formatted by JSONRenderer are left alone. """ - d = {'message': ('hello',), '_structlog': True} + d = {"message": ("hello",), "_structlog": True} def verify(eventDict): assert d == eventDict diff --git a/tests/test_utils.py b/tests/test_utils.py index 60f83fb9..ee793038 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -17,12 +17,13 @@ class TestUntilNotInterrupted(object): def test_passes_arguments_and_returns_return_value(self): def returner(*args, **kw): return args, kw - assert ((42,), {'x': 23}) == until_not_interrupted(returner, 42, x=23) + + assert ((42,), {"x": 23}) == until_not_interrupted(returner, 42, x=23) def test_leaves_unrelated_exceptions_through(self): exc = IOError with pytest.raises(exc): - until_not_interrupted(raiser(exc('not EINTR'))) + until_not_interrupted(raiser(exc("not EINTR"))) def test_retries_on_EINTR(self): calls = [0] diff --git a/tox.ini b/tox.ini index 563fb76a..c36f8bcd 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = isort,{py27,py34,py35,py36,pypy,pypy3}-{threads,greenlets},{py27,py36}-{colorama,oldtwisted},flake8,docs,readme,manifest,coverage-report +envlist = {py27,py34,py35,py36,pypy,pypy3}-{threads,greenlets},{py27,py36}-{colorama,oldtwisted},lint,docs,readme,manifest,coverage-report [testenv] @@ -14,23 +14,16 @@ setenv = commands = coverage run --parallel -m pytest {posargs} -[testenv:flake8] +[testenv:lint] basepython = python3.6 extras = tests deps = flake8 flake8-isort -commands = flake8 src tests setup.py conftest.py docs/conf.py - - -[testenv:isort] -basepython = python3.6 -extras = tests -# Needs a full install so isort can determine own/foreign imports. -deps = - isort + black commands = - isort --recursive setup.py conftest.py src tests + flake8 src tests setup.py conftest.py docs/conf.py + black --check --quiet --line-length 79 setup.py conftest.py src tests [testenv:docs] From 8884eee17eeb6ced6379b5fd31deef7223cb21be Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 7 Jun 2018 16:19:19 +0200 Subject: [PATCH 0199/1520] Add badge --- .pre-commit-config.yaml | 2 -- README.rst | 4 ++++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1f808b49..2d748ca8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,10 +10,8 @@ repos: rev: v1.0.0 hooks: - id: seed-isort-config - language_version: python3.6 - repo: https://github.com/pre-commit/mirrors-isort rev: v4.3.4 hooks: - id: isort types: [python] - language_version: python3.6 diff --git a/README.rst b/README.rst index 474ebcb2..c7799ee4 100644 --- a/README.rst +++ b/README.rst @@ -20,6 +20,10 @@ .. image:: https://www.irccloud.com/invite-svg?channel=%23structlog&hostname=irc.freenode.net&port=6697&ssl=1 :target: https://www.irccloud.com/invite?channel=%23structlog&hostname=irc.freenode.net&port=6697&ssl=1 +.. image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/ambv/black + :alt: Code style: black + .. -begin-short- ``structlog`` makes logging in Python less painful and more powerful by adding structure to your log entries. From 5168507d30a335d3f31c6009ce58129361bc2c9b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 7 Jun 2018 16:27:49 +0200 Subject: [PATCH 0200/1520] Unpin sphinx It seems to work now? --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6fe418df..2f3889f4 100644 --- a/setup.py +++ b/setup.py @@ -42,7 +42,7 @@ "python-rapidjson; python_version>='3.6'", "simplejson", ], - "docs": ["sphinx<1.6.0", "twisted"], + "docs": ["sphinx", "twisted"], } ############################################################################### From 6c10b995e0d045098229115cf586337ae8238dcd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 7 Jun 2018 16:38:11 +0200 Subject: [PATCH 0201/1520] Fix typo --- docs/getting-started.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 29ddf48f..c9401896 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -110,7 +110,7 @@ The processor would look like this: ... return event_dict Plain Python, plain dictionaries. -No you have to tell ``structlog`` about your processor by :doc:`configuring ` it: +Now you have to tell ``structlog`` about your processor by :doc:`configuring ` it: .. doctest:: From cb0d17918de2fe139ba3449f07b10c819f028ae5 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 16 Jun 2018 10:22:30 +0200 Subject: [PATCH 0202/1520] Polish contributing --- .github/CONTRIBUTING.rst | 28 +++++++++++++++------------- .pre-commit-config.yaml | 4 ++-- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst index a2ec911d..fe232b46 100644 --- a/.github/CONTRIBUTING.rst +++ b/.github/CONTRIBUTING.rst @@ -39,8 +39,9 @@ Code :rtype: str """ - If you add or change public APIs, tag the docstring using ``.. versionadded:: 16.0.0 WHAT`` or ``.. versionchanged:: 17.1.0 WHAT``. -- We use the black_ code style with a line length of 79 characters. - This means that as long as you have working pre-commit_ hooks (see below), you don't have to spend any time on formatting you code. +- We use isort_ to sort our imports, and we follow the Black_ code style with a line length of 79 characters. + As long as you run our full tox suite before committing, or install our pre-commit_ hooks (ideally you'll do both -- see below "Local Development Environment"), you won't have to spend any time on formatting your code at all. + If you don't, CI will catch it for you -- but that seems like a waste of your time! Tests @@ -101,7 +102,8 @@ Documentation Local Development Environment ----------------------------- -You can (and should) run our test suite using tox_ however you’ll probably want a more traditional environment too. +You can (and should) run our test suite using tox_. +However, you’ll probably want a more traditional environment as well. We highly recommend to develop using the latest Python 3 release because you're more likely to catch certain bugs earlier. First create a `virtual environment `_. @@ -111,14 +113,14 @@ Next get an up to date checkout of the ``structlog`` repository: .. code-block:: bash - git checkout git@github.com:hynek/structlog.git + $ git checkout git@github.com:hynek/structlog.git -Change into the newly created directory and **after activating your virtual environment** install an editable version of ``structlog`` along with its test and docs dependencies: +Change into the newly created directory and **after activating your virtual environment** install an editable version of ``structlog`` along with its test and docs dependencies: .. code-block:: bash - cd structlog - pip install -e .[tests,docs] + $ cd structlog + $ pip install -e .[tests,docs] pre-commit If you run the virtual environment’s Python and try to ``import structlog`` it should work! @@ -126,7 +128,7 @@ At this point .. code-block:: bash - python -m pytest + $ python -m pytest should work and pass @@ -134,8 +136,8 @@ and .. code-block:: bash - cd docs - make html + $ cd docs + $ make html should build docs in ``docs/_build/html``. @@ -145,13 +147,13 @@ Since pre-commit_ is installed along with other dependencies above, all you have .. code-block:: bash - precommit install + $ pre-commit install -Now you should be able to run +You can also run them anytime using: .. code-block:: bash - pre-commit run --all-files + $ pre-commit run --all-files **** diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2d748ca8..c985a3a3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,13 +1,13 @@ repos: - repo: https://github.com/ambv/black - rev: stable + rev: 18.6b2 hooks: - id: black args: [--line-length=79] types: [python] language_version: python3.6 - repo: https://github.com/asottile/seed-isort-config - rev: v1.0.0 + rev: v1.0.1 hooks: - id: seed-isort-config - repo: https://github.com/pre-commit/mirrors-isort From 88856884718ed38b55a9c6c85e7e14841cb43503 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 16 Jun 2018 10:49:04 +0200 Subject: [PATCH 0203/1520] Add pre-commit to tox --- tox.ini | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index c36f8bcd..7e6f3c17 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,13 @@ [tox] -envlist = {py27,py34,py35,py36,pypy,pypy3}-{threads,greenlets},{py27,py36}-{colorama,oldtwisted},lint,docs,readme,manifest,coverage-report +envlist = pre-commit,lint,{py27,py34,py35,py36,pypy,pypy3}-{threads,greenlets},{py27,py36}-{colorama,oldtwisted},docs,readme,manifest,coverage-report + + +[testenv:pre-commit] +skip_install = true +basepython = python3.6 +deps = pre-commit +passenv = HOMEPATH # needed on Windows +commands = pre-commit run --all-files --verbose [testenv] From 8efd41a74bdc759983fc9bd2f3c1331ab9a45e5d Mon Sep 17 00:00:00 2001 From: Michal Bultrowicz Date: Thu, 21 Jun 2018 12:29:37 +0200 Subject: [PATCH 0204/1520] Fix typo in logging-best-practices. (#169) --- docs/logging-best-practices.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/logging-best-practices.rst b/docs/logging-best-practices.rst index 33f42932..20339ee0 100644 --- a/docs/logging-best-practices.rst +++ b/docs/logging-best-practices.rst @@ -32,7 +32,7 @@ Logstash parses the log entries and stores them in in Elasticsearch_. Finally, you can view and search them in Kibana_. If your log entries consist of a JSON dictionary, this is fairly easy and efficient. -All you have to do is to tell Logstash_ the name of you timestamp field. +All you have to do is to tell Logstash_ the name of your timestamp field. Graylog From 57150d08bc15c748894a85d5571555e880e7389b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 21 Jun 2018 12:32:06 +0200 Subject: [PATCH 0205/1520] Stop codecov from commenting --- MANIFEST.in | 4 ++-- codecov.yml | 10 ++++++++++ pyproject.toml | 6 ++++++ tox.ini | 2 +- 4 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 codecov.yml create mode 100644 pyproject.toml diff --git a/MANIFEST.in b/MANIFEST.in index d003a6ff..ce5155d4 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,4 @@ -include LICENSE LICENSE.apache2 LICENSE.mit .coveragerc conftest.py .readthedocs.yml +include LICENSE LICENSE.apache2 LICENSE.mit .coveragerc conftest.py .readthedocs.yml pyproject.toml include *.rst recursive-include .github *.rst @@ -10,4 +10,4 @@ graft docs prune docs/_build # Don't package GitHub-specific files. -exclude .github/*.md .travis.yml .pre-commit-config.yaml +exclude .github/*.md .travis.yml .pre-commit-config.yaml codecov.yml diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000..60a1e5c1 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,10 @@ +--- +comment: false +coverage: + status: + patch: + default: + target: "100" + project: + default: + target: "100" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..ee41185b --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,6 @@ +[build-system] +requires = ["setuptools", "wheel"] + + +[tool.black] +line-length = 79 diff --git a/tox.ini b/tox.ini index 7e6f3c17..feb9979d 100644 --- a/tox.ini +++ b/tox.ini @@ -31,7 +31,7 @@ deps = black commands = flake8 src tests setup.py conftest.py docs/conf.py - black --check --quiet --line-length 79 setup.py conftest.py src tests + black --check --quiet setup.py conftest.py src tests docs/conf.py [testenv:docs] From 8f2eb06ff4806b8275c5f1dc9271ce85c11bd605 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 21 Jun 2018 13:23:05 +0200 Subject: [PATCH 0206/1520] Add relbars --- README.rst | 2 +- docs/conf.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index c7799ee4..1a6da25f 100644 --- a/README.rst +++ b/README.rst @@ -7,7 +7,7 @@ ============================================ .. image:: https://readthedocs.org/projects/structlog/badge/?version=stable - :target: https://structlog.readthedocs.io/en/stable/?badge=stable + :target: http://www.structlog.org/en/stable/?badge=stable :alt: Documentation Status .. image:: https://travis-ci.org/hynek/structlog.svg?branch=master diff --git a/docs/conf.py b/docs/conf.py index 802445f7..71298e9c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -129,6 +129,7 @@ def find_version(*file_paths): "head_font_family": '"Avenir Next", Calibri, "PT Sans", sans-serif', "font_size": "18px", "page_width": "980px", + "show_relbars": True, } html_logo = "_static/structlog_logo_small.png" From 4d0c3d5e3af156774e1e9e4176cff1f9b4e26da5 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 22 Jun 2018 09:39:40 +0200 Subject: [PATCH 0207/1520] Fix TimeStamper autodoc --- docs/api.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api.rst b/docs/api.rst index 2705f0b0..3a93f2d3 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -161,7 +161,7 @@ API Reference .. autoclass:: ExceptionPrettyPrinter -.. autoclass:: TimeStamper(fmt=None, utc=True) +.. autoclass:: TimeStamper(fmt=None, utc=True, key="timestamp") .. doctest:: From e8b0218cd73eccf1fdb80b49977b801fdac39110 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 23 Jun 2018 13:58:07 +0200 Subject: [PATCH 0208/1520] Update pre-commit --- .pre-commit-config.yaml | 4 +--- README.rst | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c985a3a3..6167756c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,10 +1,8 @@ repos: - repo: https://github.com/ambv/black - rev: 18.6b2 + rev: 18.6b4 hooks: - id: black - args: [--line-length=79] - types: [python] language_version: python3.6 - repo: https://github.com/asottile/seed-isort-config rev: v1.0.1 diff --git a/README.rst b/README.rst index 1a6da25f..60fde990 100644 --- a/README.rst +++ b/README.rst @@ -14,8 +14,8 @@ :target: https://travis-ci.org/hynek/structlog .. image:: https://codecov.io/github/hynek/structlog/branch/master/graph/badge.svg - :target: https://codecov.io/github/hynek/structlog - :alt: Test Coverage + :target: https://codecov.io/github/hynek/structlog + :alt: Test Coverage .. image:: https://www.irccloud.com/invite-svg?channel=%23structlog&hostname=irc.freenode.net&port=6697&ssl=1 :target: https://www.irccloud.com/invite?channel=%23structlog&hostname=irc.freenode.net&port=6697&ssl=1 From e406d047ef3f2d45cb7f05ad6fe904de57ea8152 Mon Sep 17 00:00:00 2001 From: Manuel Mendez <708570+mmlb@users.noreply.github.com> Date: Wed, 4 Jul 2018 16:28:54 -0400 Subject: [PATCH 0209/1520] docs: fix minor typo and grammar (#172) --- docs/logging-best-practices.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/logging-best-practices.rst b/docs/logging-best-practices.rst index 20339ee0..bfd6841c 100644 --- a/docs/logging-best-practices.rst +++ b/docs/logging-best-practices.rst @@ -7,7 +7,7 @@ Logfiles have existed for decades and there's little reason to reinvent the whee Therefore let's rely on proven tools as much as possible and do only the absolutely necessary inside of Python\ [*]_. A simple but powerful approach is to log to unbuffered `standard out`_ and let other tools take care of the rest. -That can be your terminal window while developing, it can be systemd_ redirecting your log entries it to syslogd_, or your `cluster manager`_. +That can be your terminal window while developing, it can be systemd_ redirecting your log entries to syslogd_, or your `cluster manager`_. It doesn't matter where or how your application is running, it just works. This is why the popular `twelve-factor app methodology`_ suggests just that. @@ -39,7 +39,7 @@ Graylog ^^^^^^^ Graylog_ goes one step further. -It not only supports everything those above do (and then some); you can also log directly JSON entries towards it -- optionally even through an AMQP server (like RabbitMQ_) for better reliability. +It not only supports everything those above do (and then some); you can also directly log JSON entries towards it -- optionally even through an AMQP server (like RabbitMQ_) for better reliability. Additionally, `Graylog's Extended Log Format`_ (GELF) allows for structured data which makes it an obvious choice to use together with ``structlog``. From fd01af7acb0c2e6d3cd0caa78972c66b932ad120 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 5 Jul 2018 14:47:50 +0200 Subject: [PATCH 0210/1520] Add try_unbind() Ref #171 --- .travis.yml | 8 ++++++++ CHANGELOG.rst | 4 +++- src/structlog/_base.py | 16 ++++++++++++++++ tests/test_base.py | 26 ++++++++++++++++++++++++++ tox.ini | 2 +- 5 files changed, 54 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 272113ba..bd048b4d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,6 +28,14 @@ matrix: env: TOXENV=py36-threads - python: "3.6" env: TOXENV=py36-greenlets + - python: "3.7" + env: TOXENV=py37-threads + dist: xenial + sudo: true + - python: "3.7" + env: TOXENV=py37-greenlets + dist: xenial + sudo: true - python: "pypy" env: TOXENV=pypy-threads - python: "pypy" diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a1200f05..b53b8e86 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,12 +24,14 @@ Deprecations: Changes: ^^^^^^^^ -- Added ``structlog.stdlib.add_log_level_number`` processor to add level number of log level to the event dictionary. +- Added ``structlog.stdlib.add_log_level_number()`` processor that adds the level *number* to the event dictionary. Can be used to simplify log filtering. `#151 `_ - ``structlog.processors.JSONRenderer`` now allows for overwriting the *default* argument of its serializer. `#77 `_ `#163 `_ +- Added ``try_unbind()`` that works like ``unbind()`` but doesn't raise a ``KeyError`` if one of the keys is missing. + `#171 `_ ---- diff --git a/src/structlog/_base.py b/src/structlog/_base.py index 2bbec409..30116f64 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -84,6 +84,22 @@ def unbind(self, *keys): del bl._context[key] return bl + def try_unbind(self, *keys): + """ + Like :meth:`unbind`, but best effort: missing keys are ignored. + + :rtype: `self.__class__` + + .. versionadded:: 18.2.0 + """ + bl = self.bind() + for key in keys: + try: + del bl._context[key] + except KeyError: + pass + return bl + def new(self, **new_values): """ Clear context and binds *initial_values* using :func:`bind`. diff --git a/tests/test_base.py b/tests/test_base.py index 48c804dc..28ffcfa9 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -84,10 +84,36 @@ class Wrapper(BoundLoggerBase): assert isinstance(b.new(), Wrapper) def test_unbind(self): + """ + unbind() removes keys from context. + """ b = build_bl().bind(x=42, y=23).unbind("x", "y") assert {} == b._context + def test_unbind_fail(self): + """ + unbind() raises KeyError if the key is missing. + """ + with pytest.raises(KeyError): + build_bl().bind(x=42, y=23).unbind("x", "z") + + def test_try_unbind(self): + """ + try_unbind() removes keys from context. + """ + b = build_bl().bind(x=42, y=23).try_unbind("x", "y") + + assert {} == b._context + + def test_try_unbind_fail(self): + """ + try_unbind() does nothing if the key is missing. + """ + b = build_bl().bind(x=42, y=23).try_unbind("x", "z") + + assert {"y": 23} == b._context + class TestProcessing(object): def test_event_empty_string(self): diff --git a/tox.ini b/tox.ini index feb9979d..c4e95777 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = pre-commit,lint,{py27,py34,py35,py36,pypy,pypy3}-{threads,greenlets},{py27,py36}-{colorama,oldtwisted},docs,readme,manifest,coverage-report +envlist = pre-commit,lint,{py27,py34,py35,py36,py37,pypy,pypy3}-{threads,greenlets},{py27,py36}-{colorama,oldtwisted},docs,readme,manifest,coverage-report [testenv:pre-commit] From 2946e1776855594354f64e77c55f4717e77f2cc6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 14 Jul 2018 13:42:23 +0200 Subject: [PATCH 0211/1520] Add missing trove classifier --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 2f3889f4..d3a62f82 100644 --- a/setup.py +++ b/setup.py @@ -26,6 +26,7 @@ "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Programming Language :: Python", From dce2f1c36e4a62372954022ad95bac4cc482465a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 14 Jul 2018 13:52:46 +0200 Subject: [PATCH 0212/1520] Use Rust's wording to clarify dual license --- LICENSE | 13 ++++++++++--- docs/license.rst | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/LICENSE b/LICENSE index 788e8412..0ee13911 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,10 @@ -This software is made available under the terms of *either* of the licenses -found in LICENSE.apache or LICENSE.mit. Contributions to structlog are made -under the terms of *both* these licenses. +Licensed under either of + +- Apache License, Version 2.0 (LICENSE.apache or ) +- or MIT license (LICENSE.mit or ) + +at your option. + +Any contribution intentionally submitted for inclusion in the work by you, as +defined in the Apache-2.0 license, shall be dual licensed as above, without any +additional terms or conditions. diff --git a/docs/license.rst b/docs/license.rst index 425ca847..4fa7423f 100644 --- a/docs/license.rst +++ b/docs/license.rst @@ -4,7 +4,7 @@ License and Hall of Fame ``structlog`` is licensed both under the `Apache License, Version 2 `_ and the `MIT license `_. The reason for that is to be both protected against patent claims by own contributors and still allow the usage within GPLv2 software. -For more legal details, see `this issue `_ on the bug tracker of PyCA's cryptography. +For more legal details, see `this issue `_ on the bug tracker of PyCA's `cryptography` project. The full license texts can be also found in the source code repository: From fbd3a6583a7b7e1970d2f92bcc5d8e0239ea79b5 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 28 Jul 2018 14:30:50 +0100 Subject: [PATCH 0213/1520] Add a little more info on Django config And link #175. Fixes #175 --- docs/configuration.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/configuration.rst b/docs/configuration.rst index 6cf458dd..6880ece3 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -156,8 +156,10 @@ Ideally as late as possible but *before* non-framework (i.e. your) code is execu If you use standard library's logging, it makes sense to configure them next to each other. **Django** - Django has to date unfortunately no concept of an application assembler or "app is done" hooks. - Therefore the bottom of your ``settings.py`` will have to do. + ``settings.py`` together with your other logging configuration. + + For per-request loggers with bound request IDs, you can write a simple middleware. + See `this case study `_ for more concrete information. **Flask** See `Logging Application Errors `_. From 3de782c3d0135f7248e62aa1105a6d8ea3a818d2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 28 Jul 2018 15:00:35 +0100 Subject: [PATCH 0214/1520] Link a more relevant flask document --- docs/configuration.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.rst b/docs/configuration.rst index 6880ece3..99c1f428 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -162,7 +162,7 @@ If you use standard library's logging, it makes sense to configure them next to See `this case study `_ for more concrete information. **Flask** - See `Logging Application Errors `_. + See `Logging `_. **Pyramid** `Application constructor `_. From 0442a95daf482c68f870239a2535fad3ce908351 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 5 Sep 2018 09:49:35 +0200 Subject: [PATCH 0215/1520] Fix fixture usage --- .pre-commit-config.yaml | 2 +- tests/test_threadlocal.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6167756c..93b065dd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,7 +5,7 @@ repos: - id: black language_version: python3.6 - repo: https://github.com/asottile/seed-isort-config - rev: v1.0.1 + rev: v1.2.0 hooks: - id: seed-isort-config - repo: https://github.com/pre-commit/mirrors-isort diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py index d08df743..be379499 100644 --- a/tests/test_threadlocal.py +++ b/tests/test_threadlocal.py @@ -31,11 +31,11 @@ def D(): @pytest.fixture -def log(): +def log(logger): """ Returns a ReturnLogger with a freshly wrapped OrderedDict. """ - return wrap_logger(logger(), context_class=wrap_dict(OrderedDict)) + return wrap_logger(logger, context_class=wrap_dict(OrderedDict)) @pytest.fixture From 4ab7e2f709302f884e9ba909249befeda24a0623 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 5 Sep 2018 10:25:17 +0200 Subject: [PATCH 0216/1520] Move to https, point people to SO instead of IRC --- .github/CONTRIBUTING.rst | 9 +++++++++ AUTHORS.rst | 2 +- CHANGELOG.rst | 4 ++-- README.rst | 35 +++++++++++++++++++---------------- setup.py | 2 +- src/structlog/__init__.py | 2 +- 6 files changed, 33 insertions(+), 21 deletions(-) diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst index fe232b46..4b67b886 100644 --- a/.github/CONTRIBUTING.rst +++ b/.github/CONTRIBUTING.rst @@ -8,6 +8,15 @@ This document is mainly to help you to get started by codifying tribal knowledge But don't be afraid to open half-finished PRs and ask questions if something is unclear! +Support +------- + +In case you'd like to help out but don't want to deal with GitHub, there's a great opportunity: +help your fellow developers on `StackOverflow `_! + +The offical tag is ``structlog`` and helping out in support frees us up to improve ``structlog`` instead! + + Workflow -------- diff --git a/AUTHORS.rst b/AUTHORS.rst index a9b577b7..f9ee04d0 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -2,7 +2,7 @@ Authors ======= ``structlog`` is written and maintained by `Hynek Schlawack `_. -It’s inspired by previous work done by `Jean-Paul Calderone `_ and `David Reid `_. +It’s inspired by previous work done by `Jean-Paul Calderone `_ and `David Reid `_. The development is kindly supported by `Variomedia AG `_. diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b53b8e86..7bf64018 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -114,7 +114,7 @@ Changes: ------------------- The main features of this release are massive improvements in standard library's ``logging`` integration. -Have a look at the updated `standard library chapter `_ on how to use them! +Have a look at the updated `standard library chapter `_ on how to use them! Special thanks go to `Fabian Büchler `_, `Gilbert Gilb's `_, @@ -129,7 +129,7 @@ Backward-incompatible changes: - The default renderer now is ``structlog.dev.ConsoleRenderer`` if you don't configure ``structlog``. Colors are used if available and human-friendly timestamps are prepended. - This is in line with our backward `compatibility policy `_ that explicitly excludes default settings. + This is in line with our backward `compatibility policy `_ that explicitly excludes default settings. Changes: diff --git a/README.rst b/README.rst index 60fde990..d12f3cc5 100644 --- a/README.rst +++ b/README.rst @@ -1,13 +1,13 @@ -.. image:: http://www.structlog.org/en/latest/_static/structlog_logo_small.png +.. image:: https://www.structlog.org/en/latest/_static/structlog_logo_small.png :alt: structlog Logo :width: 256px - :target: http://www.structlog.org/ + :target: https://www.structlog.org/ ``structlog``: Structured Logging for Python ============================================ .. image:: https://readthedocs.org/projects/structlog/badge/?version=stable - :target: http://www.structlog.org/en/stable/?badge=stable + :target: https://www.structlog.org/en/stable/?badge=stable :alt: Documentation Status .. image:: https://travis-ci.org/hynek/structlog.svg?branch=master @@ -17,9 +17,6 @@ :target: https://codecov.io/github/hynek/structlog :alt: Test Coverage -.. image:: https://www.irccloud.com/invite-svg?channel=%23structlog&hostname=irc.freenode.net&port=6697&ssl=1 - :target: https://www.irccloud.com/invite?channel=%23structlog&hostname=irc.freenode.net&port=6697&ssl=1 - .. image:: https://img.shields.io/badge/code%20style-black-000000.svg :target: https://github.com/ambv/black :alt: Code style: black @@ -66,7 +63,7 @@ Since log entries are dictionaries, you can start binding and re-binding key/val Powerful Pipelines ------------------ -Each log entry goes through a `processor pipeline `_ that is just a chain of functions that receive a dictionary and return a new dictionary that gets fed into the next function. +Each log entry goes through a `processor pipeline `_ that is just a chain of functions that receive a dictionary and return a new dictionary that gets fed into the next function. That allows for simple but powerful data manipulation: .. code-block:: python @@ -76,12 +73,12 @@ That allows for simple but powerful data manipulation: event_dict["timestamp"] = time.time() return event_dict -There are `plenty of processors `_ for most common tasks coming with ``structlog``: +There are `plenty of processors `_ for most common tasks coming with ``structlog``: -- Collectors of `call stack information `_ ("How did this log entry happen?"), -- …and `exceptions `_ ("What happened‽"). +- Collectors of `call stack information `_ ("How did this log entry happen?"), +- …and `exceptions `_ ("What happened‽"). - Unicode encoders/decoders. -- Flexible `timestamping `_. +- Flexible `timestamping `_. @@ -91,8 +88,8 @@ Formatting ``structlog`` is completely flexible about *how* the resulting log entry is emitted. Since each log entry is a dictionary, it can be formatted to **any** format: -- A colorful key/value format for `local development `_, -- `JSON `_ for easy parsing, +- A colorful key/value format for `local development `_, +- `JSON `_ for easy parsing, - or some standard format you have parsers for like nginx or Apache httpd. Internally, formatters are processors whose return value (usually a string) is passed into loggers that are responsible for the output of your message. @@ -116,13 +113,19 @@ Output .. -end-spiel- +Getting Help +------------ + +Please use the ``structlog`` tag on `StackOverflow `_ to get help. + +Answering questions of your fellow developers is also great way to help the project! + + Project Information ------------------- .. -begin-meta- -``structlog`` is dual-licensed under `Apache License, version 2 `_ and `MIT `_, available from `PyPI `_, the source code can be found on `GitHub `_, the documentation at http://www.structlog.org/. +``structlog`` is dual-licensed under `Apache License, version 2 `_ and `MIT `_, available from `PyPI `_, the source code can be found on `GitHub `_, the documentation at https://www.structlog.org/. ``structlog`` targets Python 2.7, 3.4 and newer, and PyPy. - -If you need any help, visit us on ``#structlog`` on `Freenode `_! diff --git a/setup.py b/setup.py index d3a62f82..fa21a988 100644 --- a/setup.py +++ b/setup.py @@ -95,7 +95,7 @@ def find_meta(meta): "(\d+.\d.\d \(.*?\)\n.*?)\n\n\n----\n\n\n", read("CHANGELOG.rst"), re.S ).group(1) + "\n\n`Full changelog " - + "`_.\n\n" + + "`_.\n\n" + read("AUTHORS.rst") ) diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 60b808c7..326fa71d 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -40,7 +40,7 @@ __title__ = "structlog" __description__ = "Structured Logging for Python" -__uri__ = "http://www.structlog.org/" +__uri__ = "https://www.structlog.org/" __author__ = "Hynek Schlawack" __email__ = "hs@ox.cx" From a40860e4837c3cc69262ab7b4554a8320e329f01 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 5 Sep 2018 10:51:59 +0200 Subject: [PATCH 0217/1520] Limit tests a bit --- .travis.yml | 38 ++++++++++++++++---------------------- tox.ini | 2 +- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/.travis.yml b/.travis.yml index bd048b4d..84f18b7f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,42 +14,36 @@ matrix: include: - python: "2.7" env: TOXENV=py27-threads - - python: "2.7" - env: TOXENV=py27-greenlets - python: "3.4" env: TOXENV=py34-threads - - python: "3.4" - env: TOXENV=py34-greenlets - python: "3.5" env: TOXENV=py35-threads - - python: "3.5" - env: TOXENV=py35-greenlets - python: "3.6" env: TOXENV=py36-threads - - python: "3.6" - env: TOXENV=py36-greenlets - python: "3.7" env: TOXENV=py37-threads - dist: xenial - sudo: true - - python: "3.7" - env: TOXENV=py37-greenlets - dist: xenial - sudo: true - python: "pypy" env: TOXENV=pypy-threads - python: "pypy" - env: TOXENV=pypy-greenlets - - python: "pypy3" env: TOXENV=pypy3-threads - - python: "pypy3" - env: TOXENV=pypy3-greenlets + - python: "2.7" + env: TOXENV=py27-greenlets - python: "2.7" env: TOXENV=py27-colorama - - python: "3.6" - env: TOXENV=py36-colorama - - python: "3.6" - env: TOXENV=py36-oldtwisted + - python: "2.7" + env: TOXENV=py27-oldtwisted + - python: "3.7" + env: TOXENV=py37-greenlets + - python: "3.7" + env: TOXENV=py37-colorama + - python: "3.7" + env: TOXENV=py37-oldtwisted + - python: "pypy" + env: TOXENV=pypy-greenlets + - python: "pypy" + env: TOXENV=pypy-colorama + - python: "pypy" + env: TOXENV=pypy-oldtwisted # Prevent breakage by a new releases - python: "3.6-dev" diff --git a/tox.ini b/tox.ini index c4e95777..c89dc68b 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = pre-commit,lint,{py27,py34,py35,py36,py37,pypy,pypy3}-{threads,greenlets},{py27,py36}-{colorama,oldtwisted},docs,readme,manifest,coverage-report +envlist = pre-commit,lint,{py27,py34,py35,py36,py37,pypy,pypy3}-threads,{py27,py37,pypy}-{greenlets,colorama,oldtwisted},docs,readme,manifest,coverage-report [testenv:pre-commit] From 26d2fe06eee1f302810b55291291757520339dd8 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 5 Sep 2018 11:01:33 +0200 Subject: [PATCH 0218/1520] fix 3.7 builds --- .travis.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.travis.yml b/.travis.yml index 84f18b7f..5093ac65 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,6 +22,8 @@ matrix: env: TOXENV=py36-threads - python: "3.7" env: TOXENV=py37-threads + dist: xenial + sudo: true - python: "pypy" env: TOXENV=pypy-threads - python: "pypy" @@ -34,10 +36,16 @@ matrix: env: TOXENV=py27-oldtwisted - python: "3.7" env: TOXENV=py37-greenlets + dist: xenial + sudo: true - python: "3.7" env: TOXENV=py37-colorama + dist: xenial + sudo: true - python: "3.7" env: TOXENV=py37-oldtwisted + dist: xenial + sudo: true - python: "pypy" env: TOXENV=pypy-greenlets - python: "pypy" @@ -52,8 +60,12 @@ matrix: env: TOXENV=py36-greenlets - python: "3.7-dev" env: TOXENV=py37-threads + dist: xenial + sudo: true - python: "3.7-dev" env: TOXENV=py37-greenlets + dist: xenial + sudo: true # Meta - python: "3.6" From 28b991d9ae49fd2290ad024b9de4921a0864395d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 5 Sep 2018 11:07:07 +0200 Subject: [PATCH 0219/1520] fix pypy3 build --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5093ac65..fbe3f945 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,7 @@ matrix: sudo: true - python: "pypy" env: TOXENV=pypy-threads - - python: "pypy" + - python: "pypy3" env: TOXENV=pypy3-threads - python: "2.7" env: TOXENV=py27-greenlets From cb67574a1f5a629d7f2ea0f6c8c5248b145026e0 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 5 Sep 2018 11:10:17 +0200 Subject: [PATCH 0220/1520] Adapt headlines --- README.rst | 18 +++++++++--------- docs/index.rst | 5 +---- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/README.rst b/README.rst index d12f3cc5..4be23fa1 100644 --- a/README.rst +++ b/README.rst @@ -3,6 +3,7 @@ :width: 256px :target: https://www.structlog.org/ +============================================ ``structlog``: Structured Logging for Python ============================================ @@ -33,7 +34,7 @@ It's up to you whether you want ``structlog`` to take care about the **output** .. -begin-spiel- Easier Logging --------------- +============== You can stop writing prose and start thinking in terms of an event that happens in the context of key/value pairs: @@ -48,7 +49,7 @@ Each log entry is a meaningful dictionary instead of an opaque string now! Data Binding ------------- +============ Since log entries are dictionaries, you can start binding and re-binding key/value pairs to your loggers to ensure they are present in every following logging call: @@ -61,7 +62,7 @@ Since log entries are dictionaries, you can start binding and re-binding key/val Powerful Pipelines ------------------- +================== Each log entry goes through a `processor pipeline `_ that is just a chain of functions that receive a dictionary and return a new dictionary that gets fed into the next function. That allows for simple but powerful data manipulation: @@ -83,7 +84,7 @@ There are `plenty of processors `_ to get help. @@ -122,9 +124,7 @@ Answering questions of your fellow developers is also great way to help the proj Project Information -------------------- - -.. -begin-meta- +=================== ``structlog`` is dual-licensed under `Apache License, version 2 `_ and `MIT `_, available from `PyPI `_, the source code can be found on `GitHub `_, the documentation at https://www.structlog.org/. diff --git a/docs/index.rst b/docs/index.rst index 5c27ed49..22a51dd1 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -13,7 +13,7 @@ First steps: - If you're not sure whether ``structlog`` is for you, have a look at :doc:`why`. - If you can't wait to log your first entry, start at :doc:`getting-started` and then work yourself through the basic docs. -- Once you have basic grasp of how ``structlog`` works, acquaint yourself with the `integrations <#integration-with-existing-systems>`_ structlog is shipping with. +- Once you have basic grasp of how ``structlog`` works, acquaint yourself with the `integrations <#integration-with-existing-systems>`_ ``structlog`` is shipping with. User's Guide @@ -69,9 +69,6 @@ API Reference api -Project Information -=================== - .. include:: ../README.rst :start-after: -begin-meta- From eed056459e01165d47cbf37c138596d4ae2c0079 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 5 Sep 2018 11:33:24 +0200 Subject: [PATCH 0221/1520] Prepare 18.2.0 --- CHANGELOG.rst | 2 +- src/structlog/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7bf64018..41c92180 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,7 +5,7 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. -18.2.0 (UNRELEASED) +18.2.0 (2018-09-05) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 326fa71d..5a1a626b 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -36,7 +36,7 @@ twisted = None -__version__ = "18.2.0.dev0" +__version__ = "18.2.0" __title__ = "structlog" __description__ = "Structured Logging for Python" From 61a504eef1ef6250df0554d4d58304cf1f57835a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 5 Sep 2018 11:45:16 +0200 Subject: [PATCH 0222/1520] Start new development cycle --- CHANGELOG.rst | 25 +++++++++++++++++++++++++ src/structlog/__init__.py | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 41c92180..e559786c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,31 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. +18.3.0 (UNRELEASED) +------------------- + + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +*none* + + +Deprecations: +^^^^^^^^^^^^^ + +*none* + + +Changes: +^^^^^^^^ + +*none* + + +---- + + 18.2.0 (2018-09-05) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 5a1a626b..ce5c2e34 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -36,7 +36,7 @@ twisted = None -__version__ = "18.2.0" +__version__ = "18.3.0.dev0" __title__ = "structlog" __description__ = "Structured Logging for Python" From fe95138584c7c8a26cd0aefde26abd5b8ab193c1 Mon Sep 17 00:00:00 2001 From: Augusto Hack Date: Fri, 21 Sep 2018 13:58:17 +0200 Subject: [PATCH 0223/1520] typo fix (#180) s/becauce/because/ --- docs/configuration.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.rst b/docs/configuration.rst index 99c1f428..0cb2f385 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -93,7 +93,7 @@ At any time, you can check whether and how ``structlog`` is configured: Since you will call :func:`structlog.get_logger` most likely in module scope, they run at import time before you had a chance to configure ``structlog``. Hence they return a **lazy proxy** that returns a correct wrapped logger on first ``bind()``/``new()``. - Therefore, you must never call ``new()`` or ``bind()`` in module or class scope becauce otherwise you will receive a logger configured with ``structlog``'s default values. + Therefore, you must never call ``new()`` or ``bind()`` in module or class scope because otherwise you will receive a logger configured with ``structlog``'s default values. Use :func:`~structlog.get_logger`\ 's ``initial_values`` to achieve pre-populated contexts. To enable you to log with the module-global logger, it will create a temporary BoundLogger and relay the log calls to it on *each call*. From fb87c2fb2fb4f905f2ed9978a3aeef760b045ca0 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 4 Oct 2018 13:51:08 +0200 Subject: [PATCH 0224/1520] Typo --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 4be23fa1..b5adffe2 100644 --- a/README.rst +++ b/README.rst @@ -94,7 +94,7 @@ Since each log entry is a dictionary, it can be formatted to **any** format: - or some standard format you have parsers for like nginx or Apache httpd. Internally, formatters are processors whose return value (usually a string) is passed into loggers that are responsible for the output of your message. -``structlog`` comes with multiple useful formatters out of-the-box. +``structlog`` comes with multiple useful formatters out-of-the-box. Output From 46e6552929c463f0dc411b5f039d8d8c30fe421d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 4 Oct 2018 14:04:35 +0200 Subject: [PATCH 0225/1520] Update black --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 93b065dd..659e4ddd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/ambv/black - rev: 18.6b4 + rev: 18.9b0 hooks: - id: black language_version: python3.6 From 1198adcb88a457b518ba21712929b4f83872045b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 8 Oct 2018 18:36:49 +0200 Subject: [PATCH 0226/1520] Add fatal to PrintLogger fixes #181 --- src/structlog/_loggers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/_loggers.py b/src/structlog/_loggers.py index 26ba0ed2..fca3b979 100644 --- a/src/structlog/_loggers.py +++ b/src/structlog/_loggers.py @@ -77,7 +77,7 @@ def msg(self, message): until_not_interrupted(self._flush) log = debug = info = warn = warning = msg - failure = err = error = critical = exception = msg + fatal = failure = err = error = critical = exception = msg class ReturnLoggerFactory(object): From 3147ea837ea0c050ff09bf0da945a2e04f81fbb6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 8 Oct 2018 19:47:44 +0200 Subject: [PATCH 0227/1520] Add fatal to ReturnLogger too --- CHANGELOG.rst | 3 ++- docs/api.rst | 4 ++-- src/structlog/_loggers.py | 2 +- tox.ini | 1 + 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e559786c..b51cb7b2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,7 +24,8 @@ Deprecations: Changes: ^^^^^^^^ -*none* +- ``structlog.ReturnLogger`` and ``structlog.PrintLogger`` now have a ``fatal()`` log method. + `#181 `_ ---- diff --git a/docs/api.rst b/docs/api.rst index 3a93f2d3..de46bf5a 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -46,12 +46,12 @@ API Reference :members: new, bind, unbind .. autoclass:: PrintLogger - :members: msg, err, debug, info, warning, error, critical, log, failure + :members: msg, err, debug, info, warning, error, critical, log, failure, fatal .. autoclass:: PrintLoggerFactory .. autoclass:: ReturnLogger - :members: msg, err, debug, info, warning, error, critical, log, failure + :members: msg, err, debug, info, warning, error, critical, log, failure, fatal .. autoclass:: ReturnLoggerFactory diff --git a/src/structlog/_loggers.py b/src/structlog/_loggers.py index fca3b979..e91cc74c 100644 --- a/src/structlog/_loggers.py +++ b/src/structlog/_loggers.py @@ -125,4 +125,4 @@ def msg(self, *args, **kw): return args, kw log = debug = info = warn = warning = msg - failure = err = error = critical = exception = msg + fatal = failure = err = error = critical = exception = msg diff --git a/tox.ini b/tox.ini index c89dc68b..aa1f8117 100644 --- a/tox.ini +++ b/tox.ini @@ -61,6 +61,7 @@ commands = check-manifest [testenv:coverage-report] +basepython = python3.6 deps = coverage skip_install = true commands = From 3f3fb34f9be8f767c8b2367f4cbe4d2441e196a7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Dec 2018 07:58:40 +0100 Subject: [PATCH 0228/1520] Clarify scope of best practices fixes #191 --- docs/logging-best-practices.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/logging-best-practices.rst b/docs/logging-best-practices.rst index bfd6841c..515f08b7 100644 --- a/docs/logging-best-practices.rst +++ b/docs/logging-best-practices.rst @@ -1,6 +1,11 @@ +====================== Logging Best Practices ====================== + +Servers +======= + Logging is not a new concept and in no way special to Python. Logfiles have existed for decades and there's little reason to reinvent the wheel in our little world. From 77449d5b94090d47af660792d0a74c99d3afebe3 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Dec 2018 08:42:55 +0100 Subject: [PATCH 0229/1520] More pre-commit and update CI stuff --- .pre-commit-config.yaml | 19 +++++++++-- .travis.yml | 35 +++++++++++--------- conftest.py | 2 +- docs/_static/BoundLogger.svg | 2 +- docs/standard-library.rst | 2 +- setup.cfg | 2 +- setup.py | 4 ++- src/structlog/_loggers.py | 4 +-- src/structlog/stdlib.py | 2 +- tox.ini | 62 +++++++++++++++++++++++++----------- 10 files changed, 89 insertions(+), 45 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 659e4ddd..d44aa733 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,13 +3,26 @@ repos: rev: 18.9b0 hooks: - id: black - language_version: python3.6 + language_version: python3.7 + # override until resolved: https://github.com/ambv/black/issues/402 + files: \.pyi?$ + types: [] - repo: https://github.com/asottile/seed-isort-config - rev: v1.2.0 + rev: v1.5.0 hooks: - id: seed-isort-config - repo: https://github.com/pre-commit/mirrors-isort rev: v4.3.4 hooks: - id: isort - types: [python] + language_version: python3.7 + + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v2.0.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: debug-statements + - id: flake8 + language_version: python3.7 + exclude: docs/code_examples diff --git a/.travis.yml b/.travis.yml index fbe3f945..af1e60d9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -dist: trusty +dist: xenial group: travis_latest sudo: false cache: @@ -12,7 +12,16 @@ matrix: fast_finish: true include: + # lint + - python: "3.7" + stage: lint + env: TOXENV=lint + - python: "3.7" + env: TOXENV=manifest + + # test - python: "2.7" + stage: test env: TOXENV=py27-threads - python: "3.4" env: TOXENV=py34-threads @@ -22,12 +31,12 @@ matrix: env: TOXENV=py36-threads - python: "3.7" env: TOXENV=py37-threads - dist: xenial - sudo: true - python: "pypy" env: TOXENV=pypy-threads + dist: trusty - python: "pypy3" env: TOXENV=pypy3-threads + dist: trusty - python: "2.7" env: TOXENV=py27-greenlets - python: "2.7" @@ -48,10 +57,13 @@ matrix: sudo: true - python: "pypy" env: TOXENV=pypy-greenlets + dist: trusty - python: "pypy" env: TOXENV=pypy-colorama + dist: trusty - python: "pypy" env: TOXENV=pypy-oldtwisted + dist: trusty # Prevent breakage by a new releases - python: "3.6-dev" @@ -60,22 +72,15 @@ matrix: env: TOXENV=py36-greenlets - python: "3.7-dev" env: TOXENV=py37-threads - dist: xenial - sudo: true - python: "3.7-dev" env: TOXENV=py37-greenlets - dist: xenial - sudo: true - # Meta - - python: "3.6" - env: TOXENV=lint - - python: "3.6" - env: TOXENV=manifest - - python: "3.6" + # docs + - python: "3.7" + stage: docs env: TOXENV=docs - - python: "3.6" - env: TOXENV=readme + - python: "3.7" + env: TOXENV=pypi-description allow_failures: - python: "3.6-dev" diff --git a/conftest.py b/conftest.py index 0e87c7aa..082b3443 100644 --- a/conftest.py +++ b/conftest.py @@ -27,6 +27,6 @@ def event_dict(): class A(object): def __repr__(self): - return "" + return r"" return {"a": A(), "b": [3, 4], "x": 7, "y": "test", "z": (1, 2)} diff --git a/docs/_static/BoundLogger.svg b/docs/_static/BoundLogger.svg index fdebc3e6..7716b38d 100644 --- a/docs/_static/BoundLogger.svg +++ b/docs/_static/BoundLogger.svg @@ -1,7 +1,7 @@ - Produced by OmniGraffle 7.6.1 + Produced by OmniGraffle 7.6.1 2018-01-27 14:28:12 +0000 diff --git a/docs/standard-library.rst b/docs/standard-library.rst index fbb99e62..a7ef80a4 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -67,7 +67,7 @@ Processors The Python stdlib uses them for filtering logic. This adds the same numbers so users can leverage similar filtering. Compare:: - + level in ("warning", "error", "critical") level_number >= 30 diff --git a/setup.cfg b/setup.cfg index 0953b156..07868d43 100644 --- a/setup.cfg +++ b/setup.cfg @@ -26,4 +26,4 @@ multi_line_output=3 not_skip=__init__.py known_first_party=structlog -known_third_party=colorama,flask,freezegun,greenlet,pretend,pytest,rapidjson,setuptools,simplejson,six,some_module,structlog,twisted,zope +known_third_party=flask,freezegun,pretend,pytest,setuptools,six,some_module,twisted,zope diff --git a/setup.py b/setup.py index fa21a988..8bcf1a77 100644 --- a/setup.py +++ b/setup.py @@ -92,7 +92,9 @@ def find_meta(meta): + "Release Information\n" + "===================\n\n" + re.search( - "(\d+.\d.\d \(.*?\)\n.*?)\n\n\n----\n\n\n", read("CHANGELOG.rst"), re.S + r"(\d+.\d.\d \(.*?\)\n.*?)\n\n\n----\n\n\n", + read("CHANGELOG.rst"), + re.S, ).group(1) + "\n\n`Full changelog " + "`_.\n\n" diff --git a/src/structlog/_loggers.py b/src/structlog/_loggers.py index e91cc74c..b9146cfa 100644 --- a/src/structlog/_loggers.py +++ b/src/structlog/_loggers.py @@ -15,7 +15,7 @@ class PrintLoggerFactory(object): - """ + r""" Produce :class:`PrintLogger`\ s. To be used with :func:`structlog.configure`\ 's `logger_factory`. @@ -81,7 +81,7 @@ def msg(self, message): class ReturnLoggerFactory(object): - """ + r""" Produce and cache :class:`ReturnLogger`\ s. To be used with :func:`structlog.configure`\ 's `logger_factory`. diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 5b5aa51b..cfd7e9c2 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -395,7 +395,7 @@ def render_to_log_kwargs(wrapped_logger, method_name, event_dict): class ProcessorFormatter(logging.Formatter): - """ + r""" Call ``structlog`` processors on :class:`logging.LogRecord`\ s. This :class:`logging.Formatter` allows to configure :mod:`logging` to call diff --git a/tox.ini b/tox.ini index aa1f8117..b06188d6 100644 --- a/tox.ini +++ b/tox.ini @@ -1,10 +1,10 @@ [tox] -envlist = pre-commit,lint,{py27,py34,py35,py36,py37,pypy,pypy3}-threads,{py27,py37,pypy}-{greenlets,colorama,oldtwisted},docs,readme,manifest,coverage-report +envlist = lint,{py27,py34,py35,py36,py37,pypy,pypy3}-threads,{py27,py37,pypy}-{greenlets,colorama,oldtwisted},docs,pypi-description,manifest,coverage-report -[testenv:pre-commit] +[testenv:lint] +basepython = python3.7 skip_install = true -basepython = python3.6 deps = pre-commit passenv = HOMEPATH # needed on Windows commands = pre-commit run --all-files --verbose @@ -17,25 +17,45 @@ deps = threads,greenlets,colorama: twisted oldtwisted: twisted < 17 colorama: colorama +setenv = + PYTHONHASHSEED = 0 +commands = python -m pytest {posargs} + + +[testenv:py37-threads] +deps = twisted setenv = PYTHONHASHSEED = 0 commands = coverage run --parallel -m pytest {posargs} -[testenv:lint] -basepython = python3.6 -extras = tests +[testenv:py37-greenlets] deps = - flake8 - flake8-isort - black -commands = - flake8 src tests setup.py conftest.py docs/conf.py - black --check --quiet setup.py conftest.py src tests docs/conf.py + greenlet + twisted +setenv = + PYTHONHASHSEED = 0 +commands = coverage run --parallel -m pytest {posargs} + + +[testenv:py27-threads] +deps = twisted +setenv = + PYTHONHASHSEED = 0 +commands = coverage run --parallel -m pytest {posargs} + + +[testenv:py27-colorama] +deps = + colorama + twisted +setenv = + PYTHONHASHSEED = 0 +commands = coverage run --parallel -m pytest {posargs} [testenv:docs] -basepython = python3.6 +basepython = python3.7 extras = docs passenv = TERM @@ -46,22 +66,26 @@ commands = sphinx-build -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html -[testenv:readme] -basepython = python3.6 -deps = readme_renderer +[testenv:pypi-description] +basepython = python3.7 skip_install = true -commands = python setup.py check -r -s +deps = + twine + pip >= 18.0.0 +commands = + pip wheel -w {envtmpdir}/build --no-deps . + twine check {envtmpdir}/build/* [testenv:manifest] -basepython = python3.6 +basepython = python3.7 skip_install = true deps = check-manifest commands = check-manifest [testenv:coverage-report] -basepython = python3.6 +basepython = python3.7 deps = coverage skip_install = true commands = From eccf8d9bb043f4a88f507020e709840be111b841 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Dec 2018 08:46:12 +0100 Subject: [PATCH 0230/1520] Only run -dev tests for current release --- .travis.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index af1e60d9..99264a2f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -66,10 +66,6 @@ matrix: dist: trusty # Prevent breakage by a new releases - - python: "3.6-dev" - env: TOXENV=py36-threads - - python: "3.6-dev" - env: TOXENV=py36-greenlets - python: "3.7-dev" env: TOXENV=py37-threads - python: "3.7-dev" @@ -83,7 +79,6 @@ matrix: env: TOXENV=pypi-description allow_failures: - - python: "3.6-dev" - python: "3.7-dev" From 4056a495332582af5b1362fffcefd0bdc80d40a7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 17 Jan 2019 08:19:16 +0100 Subject: [PATCH 0231/1520] fix link --- .github/CONTRIBUTING.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst index 4b67b886..8029cdb3 100644 --- a/.github/CONTRIBUTING.rst +++ b/.github/CONTRIBUTING.rst @@ -182,7 +182,7 @@ Thank you for considering contributing to ``structlog``! .. _`good test docstrings`: https://jml.io/pages/test-docstrings.html .. _`Code of Conduct`: https://github.com/hynek/structlog/blob/master/.github/CODE_OF_CONDUCT.rst .. _changelog: https://github.com/hynek/structlog/blob/master/CHANGELOG.rst -.. _`backward compatibility`: https://structlog.readthedocs.io/en/latest/backward-compatibility.html +.. _`backward compatibility`: https://www.structlog.org/en/latest/backward-compatibility.html .. _tox: https://tox.readthedocs.io/ .. _pyenv: https://github.com/pyenv/pyenv .. _reStructuredText: http://sphinx-doc.org/rest.html From 6cad331c6eba89239feb00b0b136d7e9167f3fa4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 17 Jan 2019 08:20:11 +0100 Subject: [PATCH 0232/1520] drop sudos --- .travis.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 99264a2f..586d86ad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ dist: xenial group: travis_latest -sudo: false cache: directories: - $HOME/.cache/pip @@ -45,16 +44,10 @@ matrix: env: TOXENV=py27-oldtwisted - python: "3.7" env: TOXENV=py37-greenlets - dist: xenial - sudo: true - python: "3.7" env: TOXENV=py37-colorama - dist: xenial - sudo: true - python: "3.7" env: TOXENV=py37-oldtwisted - dist: xenial - sudo: true - python: "pypy" env: TOXENV=pypy-greenlets dist: trusty From 8933021eecb5d3ba0c2ffa3c36a4fbddbdcfba21 Mon Sep 17 00:00:00 2001 From: Ricardo Pinto Date: Thu, 17 Jan 2019 11:22:02 +0000 Subject: [PATCH 0233/1520] Added brackets to list comprehension, fixing this exception: (#174) * Added brackets to list comprehension, fixing this exception: Traceback (most recent call last): File "/Users/ricardopinto/a_project/env/lib/python3.6/site-packages/structlog/_frames.py", line 42, in while any(name.startswith(i) for i in ignores): SystemError: error return without exception set * Replaced `[]` with `tuple()` for efficiency. --- src/structlog/_frames.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/_frames.py b/src/structlog/_frames.py index 247637f7..6350d1d8 100644 --- a/src/structlog/_frames.py +++ b/src/structlog/_frames.py @@ -38,7 +38,7 @@ def _find_first_app_frame_and_name(additional_ignores=None): ignores = ["structlog"] + (additional_ignores or []) f = sys._getframe() name = f.f_globals.get("__name__") or "?" - while any(name.startswith(i) for i in ignores): + while any(tuple(name.startswith(i) for i in ignores)): if f.f_back is None: name = "?" break From 1ba0fd43411a7b4ad0a7f7e20ac40c20d0b30924 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 17 Jan 2019 12:23:03 +0100 Subject: [PATCH 0234/1520] Add changelog item --- CHANGELOG.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b51cb7b2..923b58b6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -26,6 +26,9 @@ Changes: - ``structlog.ReturnLogger`` and ``structlog.PrintLogger`` now have a ``fatal()`` log method. `#181 `_ +- Under certain (rather unclear) circumstances, the frame extraction could throw an ``SystemError: error return without exception set``. + A workaround has been added. + `#174 `_ ---- From 9ef7959cb34c7129d1477b721cc5ca177b77670b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 2 Feb 2019 10:18:15 +0100 Subject: [PATCH 0235/1520] Update pre-commit --- .pre-commit-config.yaml | 14 ++++++++++---- tox.ini | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d44aa733..f73209c3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,10 +7,19 @@ repos: # override until resolved: https://github.com/ambv/black/issues/402 files: \.pyi?$ types: [] + + - repo: https://gitlab.com/pycqa/flake8 + rev: '3.7.3' + hooks: + - id: flake8 + language_version: python3.7 + exclude: docs/code_examples + - repo: https://github.com/asottile/seed-isort-config rev: v1.5.0 hooks: - id: seed-isort-config + - repo: https://github.com/pre-commit/mirrors-isort rev: v4.3.4 hooks: @@ -18,11 +27,8 @@ repos: language_version: python3.7 - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v2.0.0 + rev: v2.1.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: debug-statements - - id: flake8 - language_version: python3.7 - exclude: docs/code_examples diff --git a/tox.ini b/tox.ini index b06188d6..54703933 100644 --- a/tox.ini +++ b/tox.ini @@ -7,7 +7,7 @@ basepython = python3.7 skip_install = true deps = pre-commit passenv = HOMEPATH # needed on Windows -commands = pre-commit run --all-files --verbose +commands = pre-commit run --all-files [testenv] From 8917d5d70489a07068482dd213d131ecd9b283b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Za=C5=A5ko?= Date: Sat, 2 Feb 2019 10:21:33 +0100 Subject: [PATCH 0236/1520] Make ProcessorFormatter able to log dict (#189) Closes #188, --- src/structlog/stdlib.py | 4 ++-- tests/test_stdlib.py | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index cfd7e9c2..fff4e28c 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -451,7 +451,7 @@ def format(self, record): # Make a shallow copy of the record to let other handlers/formatters # process the original one record = logging.makeLogRecord(record.__dict__) - if isinstance(record.msg, dict): + try: # Both attached by wrap_for_formatter logger = record._logger meth_name = record._name @@ -460,7 +460,7 @@ def format(self, record): # processed by multiple logging formatters. LogRecord.getMessage # would transform our dict into a str. ed = record.msg.copy() - else: + except AttributeError: logger = None meth_name = record.levelname.lower() ed = {"event": record.getMessage(), "_record": record} diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index d27de0bc..c85e5ad5 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -495,7 +495,7 @@ def test_foreign_delegate(self, configure_for_pf, capsys): assert ("", "foo [in test_foreign_delegate]\n") == capsys.readouterr() - def test_clears_args(self, capsys, configure_for_pf): + def test_clears_args(self, configure_for_pf, capsys): """ We render our log records before sending it back to logging. Therefore we must clear `LogRecord.args` otherwise the user gets an @@ -511,6 +511,19 @@ def test_clears_args(self, capsys, configure_for_pf): "hello world. [in test_clears_args]\n", ) == capsys.readouterr() + def test_log_dict(self, configure_for_pf, capsys): + """ + Test that dicts can be logged with std library loggers. + """ + configure_logging(None) + + logging.getLogger().warning({"foo": "bar"}) + + assert ( + "", + "{'foo': 'bar'} [in test_log_dict]\n", + ) == capsys.readouterr() + def test_foreign_pre_chain(self, configure_for_pf, capsys): """ If foreign_pre_chain is an iterable, it's used to pre-process From 44ccae2a63f22f52755429780b1feaeb5b9c455e Mon Sep 17 00:00:00 2001 From: Will Rouesnel Date: Sat, 2 Feb 2019 10:40:24 +0100 Subject: [PATCH 0237/1520] Add another test for logging dicts Scraped from #188 --- tests/test_stdlib.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index c85e5ad5..c02e3f6e 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -562,6 +562,28 @@ def test_foreign_pre_chain_add_logger_name(self, configure_for_pf, capsys): "e_chain_add_logger_name]\n", ) == capsys.readouterr() + def test_foreign_chain_can_pass_dictionaries_without_excepting( + self, configure_for_pf, capsys + ): + """ + If a foreign logger passes a dictionary to a logging function, + check we correctly identify that it did not come from structlog. + """ + configure_logging(None) + configure( + processors=[ProcessorFormatter.wrap_for_formatter], + logger_factory=LoggerFactory(), + wrapper_class=BoundLogger, + ) + + logging.getLogger().warning({"foo": "bar"}) + + assert ( + "", + "{'foo': 'bar'} [in " + "test_foreign_chain_can_pass_dictionaries_without_excepting]\n", + ) == capsys.readouterr() + def test_foreign_pre_chain_gets_exc_info(self, configure_for_pf, capsys): """ If non-structlog record contains exc_info, foreign_pre_chain functions From 05c9885e0463384ca8f586f8b832827bab43bf54 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 2 Feb 2019 10:45:53 +0100 Subject: [PATCH 0238/1520] Add changelog entry for #189 --- CHANGELOG.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 923b58b6..8cec86c5 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -29,6 +29,11 @@ Changes: - Under certain (rather unclear) circumstances, the frame extraction could throw an ``SystemError: error return without exception set``. A workaround has been added. `#174 `_ +- ``structlog`` now tolerates passing through ``dict``\ s to stdlib logging. + `#187 `_ + `#188 `_ + `#189 `_ + ---- From d6b7da7a5903bbc9889e0c15aba6c1d2b5e19c09 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 2 Feb 2019 10:56:34 +0100 Subject: [PATCH 0239/1520] Change meaning of dev install target for consistency with other projects --- .github/CONTRIBUTING.rst | 8 +++++--- .gitignore | 1 + CHANGELOG.rst | 3 ++- setup.py | 4 +++- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst index 8029cdb3..fa3cc5ef 100644 --- a/.github/CONTRIBUTING.rst +++ b/.github/CONTRIBUTING.rst @@ -129,7 +129,7 @@ Change into the newly created directory and **after activating your virtual envi .. code-block:: bash $ cd structlog - $ pip install -e .[tests,docs] pre-commit + $ pip install -e .[dev] If you run the virtual environment’s Python and try to ``import structlog`` it should work! @@ -151,8 +151,7 @@ and should build docs in ``docs/_build/html``. -Next it's important to activate our pre-commit_ hooks so black_ and isort_ run automatically before committing your code. -Since pre-commit_ is installed along with other dependencies above, all you have to do is to run +To avoid committing code that violates our style guide, we strongly advise you to install pre-commit_ [#f1]_ hooks: .. code-block:: bash @@ -164,6 +163,9 @@ You can also run them anytime using: $ pre-commit run --all-files +.. [#f1] pre-commit should have been installed into your virtualenv automatically when you ran ``pip install -e '.[dev]'`` above. + If pre-commit is missing, it may be that you need to re-run ``pip install -e '.[dev]'``. + **** Again, this list is mainly to help you to get started by codifying tribal knowledge and expectations. diff --git a/.gitignore b/.gitignore index 14f1b314..3389b0b0 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ docs/_build *.pyc .cache .pytest_cache/ +pip-wheel-metadata/ diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8cec86c5..dfb585ad 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,7 +12,8 @@ The third digit is only for regressions. Backward-incompatible changes: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -*none* +- As announced in 18.1.0, ``pip install -e .[dev]`` now installs all development dependencies. + Sorry for the inconveniences this undoubtedly will cause! Deprecations: diff --git a/setup.py b/setup.py index 8bcf1a77..a8959018 100644 --- a/setup.py +++ b/setup.py @@ -34,7 +34,6 @@ ] INSTALL_REQUIRES = ["six"] EXTRAS_REQUIRE = { - "dev": ["colorama"], "tests": [ "coverage", "freezegun>=0.2.8", @@ -45,6 +44,9 @@ ], "docs": ["sphinx", "twisted"], } +EXTRAS_REQUIRE["dev"] = ( + EXTRAS_REQUIRE["tests"] + EXTRAS_REQUIRE["docs"] + ["pre-commit"] +) ############################################################################### From 8bd031429eecafee6f2d5d56dda47e318b9ed5a1 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 2 Feb 2019 13:57:00 +0100 Subject: [PATCH 0240/1520] There won't be a 18.3 --- CHANGELOG.rst | 2 +- src/structlog/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index dfb585ad..c4fe4df1 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,7 +5,7 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. -18.3.0 (UNRELEASED) +19.1.0 (UNRELEASED) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index ce5c2e34..b20b4180 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -36,7 +36,7 @@ twisted = None -__version__ = "18.3.0.dev0" +__version__ = "19.1.0.dev0" __title__ = "structlog" __description__ = "Structured Logging for Python" From 8a606b64fdf77526ffa4af44185ebc708e895cd4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 2 Feb 2019 14:07:58 +0100 Subject: [PATCH 0241/1520] Fix links --- .github/CONTRIBUTING.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst index fa3cc5ef..52ef5605 100644 --- a/.github/CONTRIBUTING.rst +++ b/.github/CONTRIBUTING.rst @@ -187,8 +187,8 @@ Thank you for considering contributing to ``structlog``! .. _`backward compatibility`: https://www.structlog.org/en/latest/backward-compatibility.html .. _tox: https://tox.readthedocs.io/ .. _pyenv: https://github.com/pyenv/pyenv -.. _reStructuredText: http://sphinx-doc.org/rest.html -.. _semantic newlines: http://rhodesmill.org/brandon/2012/one-sentence-per-line/ +.. _reStructuredText: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html +.. _semantic newlines: https://rhodesmill.org/brandon/2012/one-sentence-per-line/ .. _CI: https://travis-ci.org/hynek/structlog/ .. _black: https://github.com/ambv/black .. _pre-commit: https://pre-commit.com/ From 92f46e5ff2d014c8e7e6a11166165a3e6dc1288b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 2 Feb 2019 14:10:05 +0100 Subject: [PATCH 0242/1520] Prepare 19.1.0 --- CHANGELOG.rst | 2 +- src/structlog/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c4fe4df1..20596c45 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,7 +5,7 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. -19.1.0 (UNRELEASED) +19.1.0 (2019-02-02) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index b20b4180..77086db5 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -36,7 +36,7 @@ twisted = None -__version__ = "19.1.0.dev0" +__version__ = "19.1.0" __title__ = "structlog" __description__ = "Structured Logging for Python" From 1468a34661d2035198ff3eb925883a8b8d959919 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 2 Feb 2019 14:29:15 +0100 Subject: [PATCH 0243/1520] Start new development cycle --- CHANGELOG.rst | 25 +++++++++++++++++++++++++ src/structlog/__init__.py | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 20596c45..969b5477 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,31 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. +19.2.0 (UNRELEASED) +------------------- + + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +*none* + + +Deprecations: +^^^^^^^^^^^^^ + +*none* + + +Changes: +^^^^^^^^ + +*none* + + +---- + + 19.1.0 (2019-02-02) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 77086db5..6b6124a9 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -36,7 +36,7 @@ twisted = None -__version__ = "19.1.0" +__version__ = "19.2.0.dev0" __title__ = "structlog" __description__ = "Structured Logging for Python" From 17e9947694a050af08355dfa29848e1e8496a047 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 9 Feb 2019 15:46:27 +0100 Subject: [PATCH 0244/1520] Use isolated builds --- pyproject.toml | 1 + tox.ini | 1 + 2 files changed, 2 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index ee41185b..223ae2e3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,6 @@ [build-system] requires = ["setuptools", "wheel"] +build-backend = "setuptools.build_meta" [tool.black] diff --git a/tox.ini b/tox.ini index 54703933..c15abd3b 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,6 @@ [tox] envlist = lint,{py27,py34,py35,py36,py37,pypy,pypy3}-threads,{py27,py37,pypy}-{greenlets,colorama,oldtwisted},docs,pypi-description,manifest,coverage-report +isolated_build = True [testenv:lint] From c0aeab5f3ada09b7079d7ba7dc66314e1d8d2792 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 11 Feb 2019 09:08:48 +0100 Subject: [PATCH 0245/1520] Be more explicit about setuptools requirements --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 223ae2e3..cc4975fb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools", "wheel"] +requires = ["setuptools>=40.6.0", "wheel"] build-backend = "setuptools.build_meta" From bbb558dd605522c4baece3e383e49bb5666f12b0 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 7 Mar 2019 08:28:44 +0100 Subject: [PATCH 0246/1520] Add long_description_content_type --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index a8959018..79cf25f2 100644 --- a/setup.py +++ b/setup.py @@ -115,6 +115,7 @@ def find_meta(meta): maintainer=find_meta("author"), maintainer_email=find_meta("email"), long_description=LONG, + long_description_content_type="text/x-rst", keywords=KEYWORDS, packages=PACKAGES, package_dir={"": "src"}, From 5c377ad18e44a8649b183c7647e3137a0417903b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 7 Mar 2019 08:30:58 +0100 Subject: [PATCH 0247/1520] pre-commit autoupdate --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f73209c3..c9118290 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,19 +9,19 @@ repos: types: [] - repo: https://gitlab.com/pycqa/flake8 - rev: '3.7.3' + rev: 3.7.7 hooks: - id: flake8 language_version: python3.7 exclude: docs/code_examples - repo: https://github.com/asottile/seed-isort-config - rev: v1.5.0 + rev: v1.7.0 hooks: - id: seed-isort-config - repo: https://github.com/pre-commit/mirrors-isort - rev: v4.3.4 + rev: v4.3.12 hooks: - id: isort language_version: python3.7 From 53ec2bbd011c9c2fad77bfb310ba102b4c3abcac Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 7 Mar 2019 08:32:48 +0100 Subject: [PATCH 0248/1520] Add link to wiki --- README.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.rst b/README.rst index b5adffe2..ac60d41d 100644 --- a/README.rst +++ b/README.rst @@ -128,4 +128,6 @@ Project Information ``structlog`` is dual-licensed under `Apache License, version 2 `_ and `MIT `_, available from `PyPI `_, the source code can be found on `GitHub `_, the documentation at https://www.structlog.org/. +We collect useful third party extension in `our wiki `_. + ``structlog`` targets Python 2.7, 3.4 and newer, and PyPy. From 2d93231dda33bbfd15bb2c581358bf1df25b615a Mon Sep 17 00:00:00 2001 From: Marat Sharafutdinov Date: Wed, 13 Mar 2019 17:10:53 +0300 Subject: [PATCH 0249/1520] Pass-through stdlib's logger attributes (#198) --- src/structlog/stdlib.py | 45 ++++++++++++++++++++++++++++++++++++++++- tests/test_stdlib.py | 15 ++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index fff4e28c..95ef0fdb 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -120,9 +120,52 @@ def _proxy_to_logger(self, method_name, event, *event_args, **event_kw): ) # - # Pass-through methods to mimick the stdlib's logger interface. + # Pass-through attributes and methods to mimick the stdlib's logger + # interface. # + @property + def name(self): + """ + Returns :attr:`logging.Logger.name` + """ + return self._logger.name + + @property + def level(self): + """ + Returns :attr:`logging.Logger.level` + """ + return self._logger.level + + @property + def parent(self): + """ + Returns :attr:`logging.Logger.parent` + """ + return self._logger.parent + + @property + def propagate(self): + """ + Returns :attr:`logging.Logger.propagate` + """ + return self._logger.propagate + + @property + def handlers(self): + """ + Returns :attr:`logging.Logger.handlers` + """ + return self._logger.handlers + + @property + def disabled(self): + """ + Returns :attr:`logging.Logger.disabled` + """ + return self._logger.disabled + def setLevel(self, level): """ Calls :meth:`logging.Logger.setLevel` with unmodified arguments. diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index c02e3f6e..d0209b9e 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -191,6 +191,21 @@ def test_positional_args_proxied(self): assert "baz" == kwargs.get("bar") assert ("foo",) == kwargs.get("positional_args") + @pytest.mark.parametrize( + "attribute_name", + ["name", "level", "parent", "propagate", "handlers", "disabled"], + ) + def test_stdlib_passthrough_attributes(self, attribute_name): + """ + stdlib logger attributes are also available in stdlib BoundLogger. + """ + stdlib_logger = logging.getLogger("Test") + stdlib_logger_attribute = getattr(stdlib_logger, attribute_name) + bl = BoundLogger(stdlib_logger, [], {}) + bound_logger_attribute = getattr(bl, attribute_name) + + assert bound_logger_attribute == stdlib_logger_attribute + @pytest.mark.parametrize( "method_name,method_args", [ From 17bae83787cd21224942014b84e08af732bb902e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 13 Mar 2019 09:38:45 -0500 Subject: [PATCH 0250/1520] Add changelog entry for #198 --- CHANGELOG.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 969b5477..82d41452 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,7 +24,9 @@ Deprecations: Changes: ^^^^^^^^ -*none* +- Added more pass-through properties to ``structlog.stdlib.BoundLogger``. + To makes it easier to use it as a drop-in replacement for ``logging.Logger``. + `#198 `_ ---- From 802d0f90c4e170e2b7b85d77a006c92d30585285 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 13 Mar 2019 09:39:05 -0500 Subject: [PATCH 0251/1520] Mention pass-through properties on stdlib.BaseLogger --- src/structlog/stdlib.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 95ef0fdb..7c4849a9 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -54,6 +54,9 @@ class BoundLogger(BoundLoggerBase): wrapper_class=structlog.stdlib.BoundLogger, ) + It also contains a bunch of properties that pass-through to the wrapped + :class:`logging.Logger` which should make it work as a drop-in + replacement. """ def debug(self, event=None, *args, **kw): From 0d20303e1b2ce8d801f2081c5dbb65ea7d26b830 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 13 Mar 2019 09:42:23 -0500 Subject: [PATCH 0252/1520] pre-commit autoupdate --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c9118290..a6375b6b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,7 +21,7 @@ repos: - id: seed-isort-config - repo: https://github.com/pre-commit/mirrors-isort - rev: v4.3.12 + rev: v4.3.15 hooks: - id: isort language_version: python3.7 From 28e2f56b0650e448ae73e6da99efee4692667e34 Mon Sep 17 00:00:00 2001 From: Carson Ip Date: Thu, 21 Mar 2019 21:58:54 +0800 Subject: [PATCH 0253/1520] Fix minor typo in error (#202) --- src/structlog/_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/_base.py b/src/structlog/_base.py index 30116f64..3b5c4610 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -159,7 +159,7 @@ def _process_event(self, method_name, event, event_kw): return (), event_dict else: raise ValueError( - "Last processor didn't return an approriate value. Allowed " + "Last processor didn't return an appropriate value. Allowed " "return values are a dict, a tuple of (args, kwargs), or a " "string." ) From cc063e0fbc8c395559255c788509a3759f419cec Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 22 Mar 2019 10:46:18 -0500 Subject: [PATCH 0254/1520] Fix defaults in logger docs & explain exc handling in ConsoleRenderer --- docs/loggers.rst | 2 +- src/structlog/dev.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/loggers.rst b/docs/loggers.rst index b73ed5d0..6b5375bb 100644 --- a/docs/loggers.rst +++ b/docs/loggers.rst @@ -85,7 +85,7 @@ As you can see, it accepts one mandatory and a few optional arguments: **processors** A list of callables that can :ref:`filter, mutate, and format ` the log entry before it gets passed to the wrapped logger. - Default is ``[``:func:`~structlog.processors.format_exc_info`, :class:`~structlog.processors.KeyValueRenderer`\ ``]``. + Default is ``[``:class:`~structlog.processors.StackInfoRenderer`, :func:`~structlog.processors.format_exc_info`, :class:`~structlog.processors.TimeStamper`, :class:`~structlog.dev.ConsoleRenderer`\ ``]``. **context_class** The class to save your context in. diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 1bab0a49..ccf0d439 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -93,6 +93,10 @@ class ConsoleRenderer(object): """ Render `event_dict` nicely aligned, possibly in colors, and ordered. + If `event_dict` contains an ``exception`` key (for example from + :func:`~structlog.processors.format_exc_info`), it will be rendered *after* + the log line. + :param int pad_event: Pad the event to this many characters. :param bool colors: Use colors for a nicer output. :param bool force_colors: Force colors even for non-tty destinations. From 55293fb36966e416029d402fd8423af13ba488f1 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 25 Mar 2019 16:45:14 -0500 Subject: [PATCH 0255/1520] try out codeship (#203) --- README.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.rst b/README.rst index ac60d41d..e12ff857 100644 --- a/README.rst +++ b/README.rst @@ -11,6 +11,10 @@ :target: https://www.structlog.org/en/stable/?badge=stable :alt: Documentation Status +.. image:: https://app.codeship.com/projects/f42efe20-315c-0137-fe9f-1ea91b8f8a10/status?branch=master + :target: https://app.codeship.com/projects/332013 + :alt: Codeship Status for hynek/structlog + .. image:: https://travis-ci.org/hynek/structlog.svg?branch=master :target: https://travis-ci.org/hynek/structlog From a2fc57e8985ebe491be5fbce39529682ba9666c0 Mon Sep 17 00:00:00 2001 From: Piotr Popieluch Date: Wed, 8 May 2019 23:35:46 +0200 Subject: [PATCH 0256/1520] Python 3.8 support (#208) * Python 3.8 support * Travis: test for 3.8-dev instead of 3.7-dev --- .travis.yml | 10 +++++----- src/structlog/stdlib.py | 2 +- tox.ini | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 586d86ad..a7452435 100644 --- a/.travis.yml +++ b/.travis.yml @@ -59,10 +59,10 @@ matrix: dist: trusty # Prevent breakage by a new releases - - python: "3.7-dev" - env: TOXENV=py37-threads - - python: "3.7-dev" - env: TOXENV=py37-greenlets + - python: "3.8-dev" + env: TOXENV=py38-threads + - python: "3.8-dev" + env: TOXENV=py38-greenlets # docs - python: "3.7" @@ -72,7 +72,7 @@ matrix: env: TOXENV=pypi-description allow_failures: - - python: "3.7-dev" + - python: "3.8-dev" install: diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 7c4849a9..f9641b45 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -25,7 +25,7 @@ class _FixedFindCallerLogger(logging.Logger): Change the behavior of findCaller to cope with structlog's extra frames. """ - def findCaller(self, stack_info=False): + def findCaller(self, stack_info=False, stacklevel=1): """ Finds the first caller frame outside of structlog so that the caller info is populated for wrapping stdlib. diff --git a/tox.ini b/tox.ini index c15abd3b..81962bf4 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = lint,{py27,py34,py35,py36,py37,pypy,pypy3}-threads,{py27,py37,pypy}-{greenlets,colorama,oldtwisted},docs,pypi-description,manifest,coverage-report +envlist = lint,{py27,py34,py35,py36,py37,py38,pypy,pypy3}-threads,{py27,py37,pypy}-{greenlets,colorama,oldtwisted},docs,pypi-description,manifest,coverage-report isolated_build = True From abcf0d23d09b8d4ecc3c0acfd4bc2fd6cb438cc8 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 8 May 2019 23:32:07 -0400 Subject: [PATCH 0257/1520] Run 3.8 only on demand --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 81962bf4..c15abd3b 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = lint,{py27,py34,py35,py36,py37,py38,pypy,pypy3}-threads,{py27,py37,pypy}-{greenlets,colorama,oldtwisted},docs,pypi-description,manifest,coverage-report +envlist = lint,{py27,py34,py35,py36,py37,pypy,pypy3}-threads,{py27,py37,pypy}-{greenlets,colorama,oldtwisted},docs,pypi-description,manifest,coverage-report isolated_build = True From f2b7eb291ce1d81a9963aefc4f36c65bc4c4de35 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 8 May 2019 23:32:55 -0400 Subject: [PATCH 0258/1520] No more codeship --- README.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.rst b/README.rst index e12ff857..ac60d41d 100644 --- a/README.rst +++ b/README.rst @@ -11,10 +11,6 @@ :target: https://www.structlog.org/en/stable/?badge=stable :alt: Documentation Status -.. image:: https://app.codeship.com/projects/f42efe20-315c-0137-fe9f-1ea91b8f8a10/status?branch=master - :target: https://app.codeship.com/projects/332013 - :alt: Codeship Status for hynek/structlog - .. image:: https://travis-ci.org/hynek/structlog.svg?branch=master :target: https://travis-ci.org/hynek/structlog From 9c8814c44f9bd718ba1c4565b85f2406d6c0928e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 20 May 2019 11:18:15 +0200 Subject: [PATCH 0259/1520] Set up CI with Azure Pipelines (#213) * Set up CI with Azure Pipelines [skip ci] * Update azure-pipelines.yml * Update azure-pipelines.yml * Update MANIFEST.in * Update azure-pipelines.yml * Update azure-pipelines.yml * Update azure-pipelines.yml * Update azure-pipelines.yml * Update setup.py * Update tox.ini * Update README.rst * Delete .travis.yml --- .travis.yml | 96 --------------------------------------------- MANIFEST.in | 2 +- README.rst | 5 ++- azure-pipelines.yml | 96 +++++++++++++++++++++++++++++++++++++++++++++ setup.py | 3 ++ tox.ini | 2 +- 6 files changed, 104 insertions(+), 100 deletions(-) delete mode 100644 .travis.yml create mode 100644 azure-pipelines.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index a7452435..00000000 --- a/.travis.yml +++ /dev/null @@ -1,96 +0,0 @@ -dist: xenial -group: travis_latest -cache: - directories: - - $HOME/.cache/pip - -language: python - - -matrix: - fast_finish: true - - include: - # lint - - python: "3.7" - stage: lint - env: TOXENV=lint - - python: "3.7" - env: TOXENV=manifest - - # test - - python: "2.7" - stage: test - env: TOXENV=py27-threads - - python: "3.4" - env: TOXENV=py34-threads - - python: "3.5" - env: TOXENV=py35-threads - - python: "3.6" - env: TOXENV=py36-threads - - python: "3.7" - env: TOXENV=py37-threads - - python: "pypy" - env: TOXENV=pypy-threads - dist: trusty - - python: "pypy3" - env: TOXENV=pypy3-threads - dist: trusty - - python: "2.7" - env: TOXENV=py27-greenlets - - python: "2.7" - env: TOXENV=py27-colorama - - python: "2.7" - env: TOXENV=py27-oldtwisted - - python: "3.7" - env: TOXENV=py37-greenlets - - python: "3.7" - env: TOXENV=py37-colorama - - python: "3.7" - env: TOXENV=py37-oldtwisted - - python: "pypy" - env: TOXENV=pypy-greenlets - dist: trusty - - python: "pypy" - env: TOXENV=pypy-colorama - dist: trusty - - python: "pypy" - env: TOXENV=pypy-oldtwisted - dist: trusty - - # Prevent breakage by a new releases - - python: "3.8-dev" - env: TOXENV=py38-threads - - python: "3.8-dev" - env: TOXENV=py38-greenlets - - # docs - - python: "3.7" - stage: docs - env: TOXENV=docs - - python: "3.7" - env: TOXENV=pypi-description - - allow_failures: - - python: "3.8-dev" - - -install: - - pip install tox - - -script: - - tox - - -before_install: - - pip install codecov - - -after_success: - - tox -e coverage-report - - codecov - - -notifications: - email: false diff --git a/MANIFEST.in b/MANIFEST.in index ce5155d4..97e66733 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -10,4 +10,4 @@ graft docs prune docs/_build # Don't package GitHub-specific files. -exclude .github/*.md .travis.yml .pre-commit-config.yaml codecov.yml +exclude .github/*.md azure-pipelines.yml .pre-commit-config.yaml codecov.yml diff --git a/README.rst b/README.rst index ac60d41d..936ce0fd 100644 --- a/README.rst +++ b/README.rst @@ -11,8 +11,9 @@ :target: https://www.structlog.org/en/stable/?badge=stable :alt: Documentation Status -.. image:: https://travis-ci.org/hynek/structlog.svg?branch=master - :target: https://travis-ci.org/hynek/structlog +.. image:: https://dev.azure.com/the-hynek/structlog/_apis/build/status/hynek.structlog?branchName=master + :target: https://dev.azure.com/the-hynek/structlog/_build?definitionId=1 + :alt: CI Status .. image:: https://codecov.io/github/hynek/structlog/branch/master/graph/badge.svg :target: https://codecov.io/github/hynek/structlog diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 00000000..1481389c --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,96 @@ + +# Don't have two build jobs for each pull request. +trigger: +- master + +jobs: + - job: 'Test' + pool: + vmImage: 'ubuntu-latest' + strategy: + matrix: + Lint: + TOXENV: lint + python.version: '3.7' + Manifest: + TOXENV: manifest + python.version: '3.7' + + py27-colorama: + TOXENV: py27-colorama + python.version: '2.7' + py27-greenlets: + TOXENV: py27-greenlets + python.version: '2.7' + py27-oldtwisted: + TOXENV: py27-oldtwisted + python.version: '2.7' + py27-threads: + TOXENV: py27-threads + python.version: '2.7' + py34-threads: + TOXENV: py34-threads + python.version: '3.4' + py35-threads: + TOXENV: py35-threads + python.version: '3.5' + py36-threads: + TOXENV: py36-threads + python.version: '3.6' + py37-colorama: + TOXENV: py37-colorama + python.version: '3.7' + py37-greenlets: + TOXENV: py37-greenlets + python.version: '3.7' + py37-oldtwisted: + TOXENV: py37-oldtwisted + python.version: '3.7' + py37-threads: + TOXENV: py37-threads + python.version: '3.7' + pypy-colorama: + TOXENV: pypy-colorama + python.version: pypy2 + pypy-greenlets: + TOXENV: pypy-greenlets + python.version: pypy2 + pypy-oldtwisted: + TOXENV: pypy-oldtwisted + python.version: pypy2 + pypy-threads: + TOXENV: pypy-threads + python.version: pypy2 + pypy3-threads: + TOXENV: pypy3-threads + python.version: pypy3 + +# py38-greenlets: +# TOXENV: py38-greenlets +# python.version: 3.8-dev +# py38-threads: +# TOXENV: py38-threads +# python.version: 3.8-dev + + Docs: + python.version: '3.7' + TOXENV: docs + PyPI-Description: + python.version: '3.7' + TOXENV: pypi-description + + steps: + - task: UsePythonVersion@0 + inputs: + versionSpec: '$(python.version)' + architecture: 'x64' + + - script: python -m pip install --upgrade tox codecov + displayName: install tox + - script: env STRUCTLOG_AP_TEST_EXTRAS=azure-pipelines tox + displayName: run tox + - script: | + coverage combine + codecov -t $(CODECOV_TOKEN) + displayName: Report Coverage + condition: succeeded() diff --git a/setup.py b/setup.py index 79cf25f2..ebc22f87 100644 --- a/setup.py +++ b/setup.py @@ -47,6 +47,9 @@ EXTRAS_REQUIRE["dev"] = ( EXTRAS_REQUIRE["tests"] + EXTRAS_REQUIRE["docs"] + ["pre-commit"] ) +EXTRAS_REQUIRE["azure-pipelines"] = EXTRAS_REQUIRE["tests"] + [ + "pytest-azurepipelines" +] ############################################################################### diff --git a/tox.ini b/tox.ini index c15abd3b..81305985 100644 --- a/tox.ini +++ b/tox.ini @@ -12,7 +12,7 @@ commands = pre-commit run --all-files [testenv] -extras = tests +extras = {env:STRUCTLOG_AP_TEST_EXTRAS:tests} deps = greenlets: greenlet threads,greenlets,colorama: twisted From a7430bb32d4f13df29937ee46d81fb0687278a24 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 20 May 2019 11:33:58 +0200 Subject: [PATCH 0260/1520] Link getting started from readme Fixes #211 --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index 936ce0fd..4efd709b 100644 --- a/README.rst +++ b/README.rst @@ -31,6 +31,7 @@ It's up to you whether you want ``structlog`` to take care about the **output** .. -end-short- +Once you feel inspired to try it out, check out our friendly `Getting Started tutorial `_ that also contains detailed installation instructions! .. -begin-spiel- From a81304bf7198530e4b44b332fd6e5ae7055d1c41 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 20 May 2019 12:42:49 +0200 Subject: [PATCH 0261/1520] Clarify that default console output is colorful Fixes #212 --- docs/development.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/development.rst b/docs/development.rst index 36972dc3..57bdb6cf 100644 --- a/docs/development.rst +++ b/docs/development.rst @@ -3,7 +3,7 @@ Development To make development a more pleasurable experience, ``structlog`` comes with the :mod:`structlog.dev` module. -The highlight is :class:`structlog.dev.ConsoleRenderer` that offers nicely aligned and colorful console output while in development: +The highlight is :class:`structlog.dev.ConsoleRenderer` that offers nicely aligned and colorful (requires the `colorama module `_ installed) console output while in development: .. figure:: _static/console_renderer.png :alt: Colorful console output by ConsoleRenderer. @@ -11,7 +11,8 @@ The highlight is :class:`structlog.dev.ConsoleRenderer` that offers nicely align To use it, just add it as a renderer to your processor chain. It will recognize logger names, log levels, time stamps, stack infos, and tracebacks as produced by ``structlog``'s processors and render them in special ways. -``structlog``'s default configuration already uses it, but if you want to use it along with standard library logging, we suggest the following configuration: +``structlog``'s default configuration already uses :class:`~structlog.dev.ConsoleRenderer`, therefore if you want nice colorful output on the console, you don't have to do anything except installing colorama. +If you want to use it along with standard library logging, we suggest the following configuration: .. code-block:: python From d12cb0b5f7f39a7a1b046d783215e9f0f9b1df17 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 31 May 2019 10:15:27 +0200 Subject: [PATCH 0262/1520] Update azure-pipelines.yml --- azure-pipelines.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 1481389c..9c762d81 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -86,11 +86,13 @@ jobs: architecture: 'x64' - script: python -m pip install --upgrade tox codecov - displayName: install tox + displayName: install tox & codecov - script: env STRUCTLOG_AP_TEST_EXTRAS=azure-pipelines tox displayName: run tox - script: | coverage combine - codecov -t $(CODECOV_TOKEN) + codecov + env: + CODECOV_TOKEN: $(CODECOV_TOKEN) displayName: Report Coverage condition: succeeded() From 10b37cbbf3a8cc824f3e5a49738f52e5604e58bc Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 31 May 2019 11:34:18 +0200 Subject: [PATCH 0263/1520] Clarify diff btw AP vars and env vars --- azure-pipelines.yml | 54 +++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 9c762d81..0b56f649 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -10,74 +10,74 @@ jobs: strategy: matrix: Lint: - TOXENV: lint - python.version: '3.7' + tox.env: lint + python.version: '3.7' Manifest: - TOXENV: manifest - python.version: '3.7' + tox.env: manifest + python.version: '3.7' py27-colorama: - TOXENV: py27-colorama + tox.env: py27-colorama python.version: '2.7' py27-greenlets: - TOXENV: py27-greenlets + tox.env: py27-greenlets python.version: '2.7' py27-oldtwisted: - TOXENV: py27-oldtwisted + tox.env: py27-oldtwisted python.version: '2.7' py27-threads: - TOXENV: py27-threads + tox.env: py27-threads python.version: '2.7' py34-threads: - TOXENV: py34-threads + tox.env: py34-threads python.version: '3.4' py35-threads: - TOXENV: py35-threads + tox.env: py35-threads python.version: '3.5' py36-threads: - TOXENV: py36-threads + tox.env: py36-threads python.version: '3.6' py37-colorama: - TOXENV: py37-colorama + tox.env: py37-colorama python.version: '3.7' py37-greenlets: - TOXENV: py37-greenlets + tox.env: py37-greenlets python.version: '3.7' py37-oldtwisted: - TOXENV: py37-oldtwisted + tox.env: py37-oldtwisted python.version: '3.7' py37-threads: - TOXENV: py37-threads + tox.env: py37-threads python.version: '3.7' pypy-colorama: - TOXENV: pypy-colorama + tox.env: pypy-colorama python.version: pypy2 pypy-greenlets: - TOXENV: pypy-greenlets + tox.env: pypy-greenlets python.version: pypy2 pypy-oldtwisted: - TOXENV: pypy-oldtwisted + tox.env: pypy-oldtwisted python.version: pypy2 pypy-threads: - TOXENV: pypy-threads + tox.env: pypy-threads python.version: pypy2 pypy3-threads: - TOXENV: pypy3-threads + tox.env: pypy3-threads python.version: pypy3 # py38-greenlets: -# TOXENV: py38-greenlets +# tox.env: py38-greenlets # python.version: 3.8-dev # py38-threads: -# TOXENV: py38-threads +# tox.env: py38-threads # python.version: 3.8-dev Docs: python.version: '3.7' - TOXENV: docs + tox.env: docs PyPI-Description: python.version: '3.7' - TOXENV: pypi-description + tox.env: pypi-description steps: - task: UsePythonVersion@0 @@ -87,12 +87,14 @@ jobs: - script: python -m pip install --upgrade tox codecov displayName: install tox & codecov - - script: env STRUCTLOG_AP_TEST_EXTRAS=azure-pipelines tox + - script: tox -e $(tox.env) displayName: run tox + env: + TOX_AP_TEST_EXTRAS: azure-pipelines - script: | coverage combine codecov env: - CODECOV_TOKEN: $(CODECOV_TOKEN) + CODECOV_TOKEN: $(codecov.token) displayName: Report Coverage condition: succeeded() From e0284f41be9ca6230c212180e512ea8fab2dcab5 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 31 May 2019 11:34:59 +0200 Subject: [PATCH 0264/1520] Update tox.ini --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 81305985..767ddbb6 100644 --- a/tox.ini +++ b/tox.ini @@ -12,7 +12,7 @@ commands = pre-commit run --all-files [testenv] -extras = {env:STRUCTLOG_AP_TEST_EXTRAS:tests} +extras = {env:TOX_AP_TEST_EXTRAS:tests} deps = greenlets: greenlet threads,greenlets,colorama: twisted From adcffa5894364a54e5e856f69ae4da01ce22028f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 31 May 2019 13:50:44 +0200 Subject: [PATCH 0265/1520] Get rid of Travis for good --- .github/CONTRIBUTING.rst | 4 ++-- x | 0 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 x diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst index 52ef5605..26fbf874 100644 --- a/.github/CONTRIBUTING.rst +++ b/.github/CONTRIBUTING.rst @@ -66,7 +66,7 @@ Tests assert "foo" == x._a_private_attribute - To run the test suite, all you need is a recent tox_. - It will ensure the test suite runs with all dependencies against all Python versions just as it will on Travis CI. + It will ensure the test suite runs with all dependencies against all Python versions just as it will in our CI. If you lack some Python versions, you can can make it a non-failure using ``tox --skip-missing-interpreters`` (in that case you may want to look into pyenv_ that makes it very easy to install many different Python versions in parallel). - Write `good test docstrings`_. @@ -189,7 +189,7 @@ Thank you for considering contributing to ``structlog``! .. _pyenv: https://github.com/pyenv/pyenv .. _reStructuredText: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html .. _semantic newlines: https://rhodesmill.org/brandon/2012/one-sentence-per-line/ -.. _CI: https://travis-ci.org/hynek/structlog/ +.. _CI: https://dev.azure.com/the-hynek/structlog/_build?definitionId=1 .. _black: https://github.com/ambv/black .. _pre-commit: https://pre-commit.com/ .. _isort: https://github.com/timothycrosley/isort diff --git a/x b/x new file mode 100644 index 00000000..e69de29b From 80b38ba31a29aff1ddd4d88ba39714ecbe7a5705 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 31 May 2019 16:20:22 +0200 Subject: [PATCH 0266/1520] Oops --- x | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 x diff --git a/x b/x deleted file mode 100644 index e69de29b..00000000 From c642479136e13824b5e8367aa5c6e94eee4801c2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 31 May 2019 16:26:22 +0200 Subject: [PATCH 0267/1520] Add badge Actually just coming up with reasons to naturally trigger a build. --- README.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.rst b/README.rst index 4efd709b..b467bc05 100644 --- a/README.rst +++ b/README.rst @@ -7,6 +7,10 @@ ``structlog``: Structured Logging for Python ============================================ +.. image:: https://img.shields.io/pypi/v/structlog.svg + :target: https://pypi.org/project/structlog/ + :alt: PyPI + .. image:: https://readthedocs.org/projects/structlog/badge/?version=stable :target: https://www.structlog.org/en/stable/?badge=stable :alt: Documentation Status From ce24dcb4de9c5493eb210bb55fb13df4abe79f2a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 31 May 2019 18:41:22 +0200 Subject: [PATCH 0268/1520] Get ourselves Python 3.8-dev --- azure-pipelines.yml | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 0b56f649..3711f93a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -49,6 +49,9 @@ jobs: py37-threads: tox.env: py37-threads python.version: '3.7' + py38-threads: + tox.env: py38-threads + python.version: '3.8' pypy-colorama: tox.env: pypy-colorama python.version: pypy2 @@ -80,20 +83,37 @@ jobs: tox.env: pypi-description steps: + - task: UsePythonVersion@0 + displayName: Get Python for Python utils. + inputs: + versionSpec: '3.7' + addToPath: false + name: pyTools + + - script: $(pyTools.pythonLocation)/bin/pip install --upgrade tox codecov + displayName: Install Python-based tools. + - task: UsePythonVersion@0 inputs: versionSpec: '$(python.version)' architecture: 'x64' + condition: ne(variables['python.version'], '3.8') + displayName: Get Python for tests. - - script: python -m pip install --upgrade tox codecov - displayName: install tox & codecov - - script: tox -e $(tox.env) - displayName: run tox + - script: | + sudo add-apt-repository ppa:deadsnakes + sudo apt-get update + sudo apt-get install -y --no-install-recommends python3.8-dev python3.8-distutils + condition: eq(variables['python.version'], '3.8') + displayName: Install Python 3.8 from the deadsnakes PPA. + - script: '$(pyTools.pythonLocation)/bin/tox -e $(tox.env)' env: TOX_AP_TEST_EXTRAS: azure-pipelines + displayName: run tox -e $(tox.env) + - script: | - coverage combine - codecov + '$(pyTools.pythonLocation)/bin/coverage combine' + '$(pyTools.pythonLocation)/bin/codecov' env: CODECOV_TOKEN: $(codecov.token) displayName: Report Coverage From ed0a2a6b4079d2838d63ef02e24d5713ce31470d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 31 May 2019 18:43:32 +0200 Subject: [PATCH 0269/1520] Empty line --- azure-pipelines.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 3711f93a..5f7faa7b 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -106,6 +106,7 @@ jobs: sudo apt-get install -y --no-install-recommends python3.8-dev python3.8-distutils condition: eq(variables['python.version'], '3.8') displayName: Install Python 3.8 from the deadsnakes PPA. + - script: '$(pyTools.pythonLocation)/bin/tox -e $(tox.env)' env: TOX_AP_TEST_EXTRAS: azure-pipelines From 34335b4598fcc143947e79ff6b2f95a52bc28348 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 31 May 2019 18:58:40 +0200 Subject: [PATCH 0270/1520] Looks like we can't install Twisted in 3.8 --- azure-pipelines.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5f7faa7b..f12fb3b8 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -49,9 +49,10 @@ jobs: py37-threads: tox.env: py37-threads python.version: '3.7' - py38-threads: - tox.env: py38-threads - python.version: '3.8' + # Twisted is currently broken on 3.8. + # py38-threads: + # tox.env: py38-threads + # python.version: '3.8' pypy-colorama: tox.env: pypy-colorama python.version: pypy2 From b08fe6af130ab10273841192052049280eaf303b Mon Sep 17 00:00:00 2001 From: Jules Robichaud-Gagnon Date: Sun, 2 Jun 2019 02:26:17 -0400 Subject: [PATCH 0271/1520] Add reference to django-structlog (#205) * Add reference to django-structlog * Refer to the wiki for django Third-Party Extension --- docs/configuration.rst | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/configuration.rst b/docs/configuration.rst index 0cb2f385..d0af9edd 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -156,10 +156,7 @@ Ideally as late as possible but *before* non-framework (i.e. your) code is execu If you use standard library's logging, it makes sense to configure them next to each other. **Django** - ``settings.py`` together with your other logging configuration. - - For per-request loggers with bound request IDs, you can write a simple middleware. - See `this case study `_ for more concrete information. + See `Third-Party Extensions `_ in the wiki. **Flask** See `Logging `_. From a89009a079120f98edf2ad8316f249e8c3e25bd9 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 2 Jun 2019 09:22:05 +0200 Subject: [PATCH 0272/1520] Try to use the active Python for coverage For some reason, 2.7 is failing to find its coverage when using the pyTools one. --- azure-pipelines.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f12fb3b8..fb06c54a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -114,8 +114,9 @@ jobs: displayName: run tox -e $(tox.env) - script: | - '$(pyTools.pythonLocation)/bin/coverage combine' - '$(pyTools.pythonLocation)/bin/codecov' + python -m pip install coverage + coverage combine + $(pyTools.pythonLocation)/bin/codecov env: CODECOV_TOKEN: $(codecov.token) displayName: Report Coverage From 218f5607d7d927605782c4db743ec06b0cee51c0 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 11 Jun 2019 08:19:54 +0200 Subject: [PATCH 0273/1520] Use 3.7 from deadsnakes AP's 3.7 is still broken. --- azure-pipelines.yml | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index fb06c54a..d3b96a24 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -85,38 +85,60 @@ jobs: steps: - task: UsePythonVersion@0 - displayName: Get Python for Python utils. + displayName: Get Python for Python tools. inputs: - versionSpec: '3.7' + versionSpec: '3.6' addToPath: false name: pyTools - - script: $(pyTools.pythonLocation)/bin/pip install --upgrade tox codecov + - script: $(pyTools.pythonLocation)/bin/pip install --upgrade tox displayName: Install Python-based tools. - task: UsePythonVersion@0 inputs: versionSpec: '$(python.version)' architecture: 'x64' - condition: ne(variables['python.version'], '3.8') - displayName: Get Python for tests. + condition: not(in(variables['python.version'], '3.7', '3.8')) + displayName: Use cached Python $(python.version) for tests. - script: | sudo add-apt-repository ppa:deadsnakes sudo apt-get update - sudo apt-get install -y --no-install-recommends python3.8-dev python3.8-distutils - condition: eq(variables['python.version'], '3.8') - displayName: Install Python 3.8 from the deadsnakes PPA. + sudo apt-get install -y --no-install-recommends python$(python.version)-dev python$(python.version)-distutils + condition: in(variables['python.version'], '3.7', '3.8') + displayName: Install Python $(python.version) from the deadsnakes PPA for tests. - - script: '$(pyTools.pythonLocation)/bin/tox -e $(tox.env)' + - script: $(pyTools.pythonLocation)/bin/tox -e $(tox.env) env: TOX_AP_TEST_EXTRAS: azure-pipelines displayName: run tox -e $(tox.env) - script: | - python -m pip install coverage + if [ ! -f .coverage.* ]; then + echo No coverage data found. + exit 0 + fi + + # codecov shells out to "coverage" and avoiding 'sudo pip' allows for + # package caching. + PATH=$HOME/.local/bin:$PATH + + case "$(python.version)" in + "pypy2") PY=pypy ;; + "pypy3") PY=pypy3 ;; + *) PY=python$(python.version) ;; + esac + + # Python 3.8 needs an up-to-date pip. + if [ "$(python.version)" = "3.8" ]; then + curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py + $PY get-pip.py --user + fi + + $PY -m pip install --user coverage codecov + coverage combine - $(pyTools.pythonLocation)/bin/codecov + codecov env: CODECOV_TOKEN: $(codecov.token) displayName: Report Coverage From ea3a99df5dc8522ee6db9980c03fa8357271d6f7 Mon Sep 17 00:00:00 2001 From: Lorenzo Cestaro Date: Tue, 11 Jun 2019 08:37:03 +0200 Subject: [PATCH 0274/1520] Fix typo in getting-started.rst (#217) --- docs/getting-started.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started.rst b/docs/getting-started.rst index c9401896..efbc86b7 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -95,7 +95,7 @@ Manipulating Log Entries in Flight Now that your log events are dictionaries, it's also much easier to manipulate them than if it were plain strings. -To fascilitate that, ``structlog`` has the concept of :doc:`processor chains `. +To facilitate that, ``structlog`` has the concept of :doc:`processor chains `. A processor is a callable like a function that receives the event dictionary along with two other arguments and returns a new event dictionary that may or may not differ from the one it got passed. The next processor in the chain receives that returned dictionary instead of the original one. From 00f54c13e7fbda60a86319c77c9ed7d57c74ca50 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 17 Jun 2019 15:57:44 +0200 Subject: [PATCH 0275/1520] Add Markus' talk for spiel --- README.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.rst b/README.rst index b467bc05..a8853f7f 100644 --- a/README.rst +++ b/README.rst @@ -39,6 +39,9 @@ Once you feel inspired to try it out, check out our friendly `Getting Started tu .. -begin-spiel- +If you prefer videos over reading, check out this DjangoCon Europe 2019 talk by `Markus Holtermann `_: "`Logging Rethought 2: The Actions of Frank Taylor Jr. `_". + + Easier Logging ============== From 8a8e110b215e687bbc1955d8c042fa88b1d5cbdd Mon Sep 17 00:00:00 2001 From: Andy Kluger Date: Wed, 19 Jun 2019 14:22:57 -0400 Subject: [PATCH 0276/1520] Show the default processor list configuration in getting-started (#216) * Add example configuration call to show the default processor list, right in the quick start * Use semantic newlines in rst, as per the contributing guidelines * include entire default config parameters in structlog.configure example * precede configuration defaults with a reminder to keep the getting-started docs in sync with any future changes * Add comment to default config example, noting that OrderedDicts are used if dict itself is unordered --- docs/getting-started.rst | 16 ++++++++++++++++ src/structlog/_config.py | 5 +++++ 2 files changed, 21 insertions(+) diff --git a/docs/getting-started.rst b/docs/getting-started.rst index efbc86b7..b7c9e28d 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -39,6 +39,22 @@ Here, ``structlog`` takes full advantage of its hopefully useful default setting - If you have `colorama `_ installed, it's rendered in nice :doc:`colors `. It should be noted that even in most complex logging setups the example would still look just like that thanks to :ref:`configuration`. +Using the defaults, as above, is equivalent to:: + + import structlog + structlog.configure( + processors=[ + structlog.processors.StackInfoRenderer(), + structlog.processors.format_exc_info, + structlog.processors.TimeStamper(), + structlog.dev.ConsoleRenderer() + ], + wrapper_class=structlog.BoundLogger, + context_class=dict, # or OrderedDict if the runtime's dict is unordered (e.g. Python <3.6) + logger_factory=structlog.PrintLoggerFactory(), + cache_logger_on_first_use=False + ) + log = structlog.get_logger() .. note:: For brevity and to enable doctests, all further examples in ``structlog``'s documentation use the more simplistic :class:`structlog.processors.KeyValueRenderer()` without timestamps. diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 99835eeb..a9855dfb 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -20,6 +20,11 @@ from .processors import StackInfoRenderer, TimeStamper, format_exc_info +""" +.. note:: + + Any changes to these defaults must be reflected in :doc:`getting-started`. +""" _BUILTIN_DEFAULT_PROCESSORS = [ StackInfoRenderer(), format_exc_info, From a28d34c3663a391ee10093e840262b610ba9da47 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 23 Jun 2019 08:38:08 +0200 Subject: [PATCH 0277/1520] Looks like AP fixed 3.7 --- azure-pipelines.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d3b96a24..926c7fdc 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -87,7 +87,7 @@ jobs: - task: UsePythonVersion@0 displayName: Get Python for Python tools. inputs: - versionSpec: '3.6' + versionSpec: '3.7' addToPath: false name: pyTools @@ -98,14 +98,14 @@ jobs: inputs: versionSpec: '$(python.version)' architecture: 'x64' - condition: not(in(variables['python.version'], '3.7', '3.8')) + condition: not(in(variables['python.version'], '3.8')) displayName: Use cached Python $(python.version) for tests. - script: | sudo add-apt-repository ppa:deadsnakes sudo apt-get update sudo apt-get install -y --no-install-recommends python$(python.version)-dev python$(python.version)-distutils - condition: in(variables['python.version'], '3.7', '3.8') + condition: in(variables['python.version'], '3.8') displayName: Install Python $(python.version) from the deadsnakes PPA for tests. - script: $(pyTools.pythonLocation)/bin/tox -e $(tox.env) From dd36ab7e4fb9458be77942aa4a36f7e7dd84d5ab Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 6 Aug 2019 20:19:01 +0200 Subject: [PATCH 0278/1520] Drop Python 3.4 Downloads are below 1%, it's unsupported by Python core. --- CHANGELOG.rst | 5 ++++- README.rst | 2 +- azure-pipelines.yml | 3 --- setup.py | 1 - tox.ini | 2 +- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 82d41452..f6440154 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,7 +12,10 @@ The third digit is only for regressions. Backward-incompatible changes: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -*none* +- Python 3.4 is not supported anymore. + It has been unsupported by the Python core team for a while now and its PyPI downloads are negligible. + + It's very unlikely that ``structlog`` will break under 3.4 anytime soon, but we don't test it anymore. Deprecations: diff --git a/README.rst b/README.rst index a8853f7f..fb4b9b09 100644 --- a/README.rst +++ b/README.rst @@ -139,4 +139,4 @@ Project Information We collect useful third party extension in `our wiki `_. -``structlog`` targets Python 2.7, 3.4 and newer, and PyPy. +``structlog`` targets Python 2.7, 3.5 and newer, and PyPy. diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 926c7fdc..17334a63 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -28,9 +28,6 @@ jobs: py27-threads: tox.env: py27-threads python.version: '2.7' - py34-threads: - tox.env: py34-threads - python.version: '3.4' py35-threads: tox.env: py35-threads python.version: '3.5' diff --git a/setup.py b/setup.py index ebc22f87..e263954d 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,6 @@ "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", diff --git a/tox.ini b/tox.ini index 767ddbb6..a6c52182 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = lint,{py27,py34,py35,py36,py37,pypy,pypy3}-threads,{py27,py37,pypy}-{greenlets,colorama,oldtwisted},docs,pypi-description,manifest,coverage-report +envlist = lint,{py27,py35,py36,py37,pypy,pypy3}-threads,{py27,py37,pypy}-{greenlets,colorama,oldtwisted},docs,pypi-description,manifest,coverage-report isolated_build = True From 0a3222d09a766d36cac530336ade620b9efc8a89 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 6 Aug 2019 21:06:10 +0200 Subject: [PATCH 0279/1520] pre-commit autoupdate --- .pre-commit-config.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a6375b6b..80e8a8c8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/ambv/black - rev: 18.9b0 + rev: 19.3b0 hooks: - id: black language_version: python3.7 @@ -9,25 +9,25 @@ repos: types: [] - repo: https://gitlab.com/pycqa/flake8 - rev: 3.7.7 + rev: 3.7.8 hooks: - id: flake8 language_version: python3.7 exclude: docs/code_examples - repo: https://github.com/asottile/seed-isort-config - rev: v1.7.0 + rev: v1.9.2 hooks: - id: seed-isort-config - repo: https://github.com/pre-commit/mirrors-isort - rev: v4.3.15 + rev: v4.3.21 hooks: - id: isort language_version: python3.7 - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v2.1.0 + rev: v2.3.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer From 0e209d95652c0f9b2943bf0334d74f4964fc7f13 Mon Sep 17 00:00:00 2001 From: Rastislav Rabatin Date: Thu, 15 Aug 2019 10:31:29 +0100 Subject: [PATCH 0280/1520] Add logger argument to ProcessorFormatter (#219) * Add logger argument to ProcessorFormatter * Add a test * Update CHANGELOG * Fix linting * Revert "Add a test" This reverts commit 8088d6f48599d8354f78140a3989ac0ad0b4fc20. * Revert "Revert "Add a test"" This reverts commit 4d7e3ea507f8a14170ddcbba5e87d80c6d482df2. * Use double backticks * Improve docstring based on the comments --- CHANGELOG.rst | 2 ++ src/structlog/stdlib.py | 14 ++++++++++---- tests/test_stdlib.py | 22 +++++++++++++++++++++- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f6440154..fec9f9d2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -30,6 +30,8 @@ Changes: - Added more pass-through properties to ``structlog.stdlib.BoundLogger``. To makes it easier to use it as a drop-in replacement for ``logging.Logger``. `#198 `_ +- ``ProcessorFormatter`` takes logger object as an optional keyword argument. + This fixes a bug when using ProcessorFormatter with ``stuctlog.stdlib.filter_by_level``. ---- diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index f9641b45..86ada285 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -465,12 +465,16 @@ class ProcessorFormatter(logging.Formatter): added to the ``event_dict`` and removed afterwards. Set this to ``True`` to keep it on the :class:`logging.LogRecord`. (default: False) :param bool keep_stack_info: Same as *keep_exc_info* except for Python 3's - ``stack_info``. + ``stack_info``. (default: False) + :param logger: Logger which we want to push through the ``structlog`` + processor chain. This parameter is necessary for some of the + processors like `filter_by_level`. (default: None) :rtype: str .. versionadded:: 17.1.0 .. versionadded:: 17.2.0 *keep_exc_info* and *keep_stack_info* + .. versionadded:: 19.2.0 *logger* """ def __init__( @@ -479,6 +483,7 @@ def __init__( foreign_pre_chain=None, keep_exc_info=False, keep_stack_info=False, + logger=None, *args, **kwargs ): @@ -489,6 +494,7 @@ def __init__( self.keep_exc_info = keep_exc_info # The and clause saves us checking for PY3 in the formatter. self.keep_stack_info = keep_stack_info and PY3 + self.logger = logger def format(self, record): """ @@ -499,7 +505,7 @@ def format(self, record): record = logging.makeLogRecord(record.__dict__) try: # Both attached by wrap_for_formatter - logger = record._logger + logger = self.logger if self.logger is not None else record._logger meth_name = record._name # We need to copy because it's possible that the same record gets @@ -507,7 +513,7 @@ def format(self, record): # would transform our dict into a str. ed = record.msg.copy() except AttributeError: - logger = None + logger = self.logger meth_name = record.levelname.lower() ed = {"event": record.getMessage(), "_record": record} record.args = () @@ -529,7 +535,7 @@ def format(self, record): # Non-structlog allows to run through a chain to prepare it for the # final processor (e.g. adding timestamps and log levels). for proc in self.foreign_pre_chain or (): - ed = proc(None, meth_name, ed) + ed = proc(logger, meth_name, ed) del ed["_record"] diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index d0209b9e..e9abb08d 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -455,7 +455,7 @@ def configure_for_pf(): reset_defaults() -def configure_logging(pre_chain): +def configure_logging(pre_chain, logger=None): """ Configure logging to use ProcessorFormatter. """ @@ -469,6 +469,7 @@ def configure_logging(pre_chain): "processor": ConsoleRenderer(colors=False), "foreign_pre_chain": pre_chain, "format": "%(message)s [in %(funcName)s]", + "logger": logger, } }, "handlers": { @@ -728,3 +729,22 @@ def test_native(self, configure_for_pf, capsys): "", "[warning ] foo [in test_native]\n", ) == capsys.readouterr() + + def test_foreign_pre_chain_filter_by_level(self, configure_for_pf, capsys): + """ + foreign_pre_chain works with filter_by_level processor. + """ + logger = logging.getLogger() + configure_logging((filter_by_level,), logger=logger) + configure( + processors=[ProcessorFormatter.wrap_for_formatter], + logger_factory=LoggerFactory(), + wrapper_class=BoundLogger, + ) + + logger.warning("foo") + + assert ( + "", + "foo [in test_foreign_pre_chain_filter_by_level]\n", + ) == capsys.readouterr() From 84da16ab69c4e6cded3a4e890ad04ca6e3333620 Mon Sep 17 00:00:00 2001 From: Dan Villiom Podlaski Christiansen Date: Thu, 15 Aug 2019 11:46:08 +0200 Subject: [PATCH 0281/1520] ConsoleRenderer: default to colorless when colorama is unavailable (#215) 'colorama' isn't a direct dependency of 'structlog', and as such it might not be available. The console renderer should still work when it isn't, though. --- src/structlog/dev.py | 2 +- tests/test_dev.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index ccf0d439..4a630f2a 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -126,7 +126,7 @@ class ConsoleRenderer(object): def __init__( self, pad_event=_EVENT_WIDTH, - colors=True, + colors=_has_colorama, force_colors=False, repr_native_str=False, level_styles=None, diff --git a/tests/test_dev.py b/tests/test_dev.py index 18a5653c..69e5631f 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -56,7 +56,7 @@ def test_missing_colorama(self): colorama is missing. """ with pytest.raises(SystemError) as e: - dev.ConsoleRenderer() + dev.ConsoleRenderer(colors=True) assert ( "ConsoleRenderer with `colors=True` requires the colorama package " From aeb3fc49f5e17dfc146535b74f0f8082286dcf3c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 15 Aug 2019 11:36:09 +0200 Subject: [PATCH 0282/1520] Minor changelog polish --- CHANGELOG.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index fec9f9d2..b823a79d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -30,8 +30,9 @@ Changes: - Added more pass-through properties to ``structlog.stdlib.BoundLogger``. To makes it easier to use it as a drop-in replacement for ``logging.Logger``. `#198 `_ -- ``ProcessorFormatter`` takes logger object as an optional keyword argument. - This fixes a bug when using ProcessorFormatter with ``stuctlog.stdlib.filter_by_level``. +- ``structlog.stdlib.ProcessorFormatter`` now takes a logger object as an optional keyword argument. + This makes ``ProcessorFormatter`` work properly with ``stuctlog.stdlib.filter_by_level()``. +- ``structlog.dev.ConsoleRenderer`` now uses no colors by default, if ``colorama`` is not available. ---- From c07c78f978e928fb90601bc6d5c99f05f8312e42 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 15 Aug 2019 12:01:55 +0200 Subject: [PATCH 0283/1520] Add missing links to PRs --- CHANGELOG.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b823a79d..88508441 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -32,7 +32,9 @@ Changes: `#198 `_ - ``structlog.stdlib.ProcessorFormatter`` now takes a logger object as an optional keyword argument. This makes ``ProcessorFormatter`` work properly with ``stuctlog.stdlib.filter_by_level()``. + `#219 `_ - ``structlog.dev.ConsoleRenderer`` now uses no colors by default, if ``colorama`` is not available. + `#215 `_ ---- From 3b534afd4f27067502ebacd686cb190c26c6e5f8 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 15 Aug 2019 12:11:24 +0200 Subject: [PATCH 0284/1520] Initialize colorama lazily --- CHANGELOG.rst | 2 ++ src/structlog/dev.py | 19 +++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 88508441..fc575d5d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -35,6 +35,8 @@ Changes: `#219 `_ - ``structlog.dev.ConsoleRenderer`` now uses no colors by default, if ``colorama`` is not available. `#215 `_ +- ``structlog.dev.ConsoleRenderer`` now initializes ``colorama`` lazily, to prevent accidental side-effects just by importing ``structlog``. + `#210 `_ ---- diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 4a630f2a..ebb37c12 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -121,6 +121,9 @@ class ConsoleRenderer(object): .. versionadded:: 17.1 *repr_native_str* .. versionadded:: 18.1 *force_colors* .. versionadded:: 18.1 *level_styles* + .. versionchanged:: 18.2 + ``colorama`` now initializes lazily to avoid unwanted initializations as + ``ConsoleRenderer`` is used by default. """ def __init__( @@ -131,6 +134,7 @@ def __init__( repr_native_str=False, level_styles=None, ): + self._force_colors = self._init_colorama = False if colors is True: if colorama is None: raise SystemError( @@ -140,11 +144,9 @@ def __init__( ) ) + self._init_colorama = True if force_colors: - colorama.deinit() - colorama.init(strip=False) - else: - colorama.init() + self._force_colors = True styles = _ColorfulStyles else: @@ -177,6 +179,15 @@ def _repr(inst): self._repr = _repr def __call__(self, _, __, event_dict): + # Initialize lazily to prevent import side-effects. + if self._init_colorama: + if self._force_colors: + colorama.deinit() + colorama.init(strip=False) + else: + colorama.init() + + self._init_colorama = False sio = StringIO() ts = event_dict.pop("timestamp", None) From 27e149ba3a153f87aba60581421974df35d7596f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 19 Sep 2019 14:58:43 +0200 Subject: [PATCH 0285/1520] Document Python 3.8 support --- CHANGELOG.rst | 1 + setup.py | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index fc575d5d..c4dd29ca 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -27,6 +27,7 @@ Deprecations: Changes: ^^^^^^^^ +- Python 3.8 support for ``structlog.stdlib``. - Added more pass-through properties to ``structlog.stdlib.BoundLogger``. To makes it easier to use it as a drop-in replacement for ``logging.Logger``. `#198 `_ diff --git a/setup.py b/setup.py index e263954d..89fd7df0 100644 --- a/setup.py +++ b/setup.py @@ -26,6 +26,7 @@ "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Programming Language :: Python", From de4ef4e73ba85db7d47a1ac75700bf8598206ddc Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 21 Sep 2019 10:42:23 +0200 Subject: [PATCH 0286/1520] Add dev.set_exc_info Fixes #130,#200 --- CHANGELOG.rst | 5 ++++- docs/api.rst | 2 ++ docs/getting-started.rst | 1 + src/structlog/_config.py | 3 ++- src/structlog/dev.py | 20 ++++++++++++++++++++ tests/test_dev.py | 24 ++++++++++++++++++++++++ 6 files changed, 53 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c4dd29ca..fa0d0d23 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -27,7 +27,7 @@ Deprecations: Changes: ^^^^^^^^ -- Python 3.8 support for ``structlog.stdlib``. +- Full Python 3.8 support for ``structlog.stdlib``. - Added more pass-through properties to ``structlog.stdlib.BoundLogger``. To makes it easier to use it as a drop-in replacement for ``logging.Logger``. `#198 `_ @@ -38,6 +38,9 @@ Changes: `#215 `_ - ``structlog.dev.ConsoleRenderer`` now initializes ``colorama`` lazily, to prevent accidental side-effects just by importing ``structlog``. `#210 `_ +- Added new processor ``structlog.dev.set_exc_info()`` that will set ``exc_info=True`` if the method's name is `exception` and ``exc_info`` isn't set at all. + *This is only necessary when the standard library integration is not used*. + It fixes the problem that in the default configuration, ``structlog.get_logger().exception("hi")`` in an ``except`` block would not print the exception without passing ``exc_info=True`` to it explicitly. ---- diff --git a/docs/api.rst b/docs/api.rst index de46bf5a..6e011529 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -69,6 +69,8 @@ API Reference .. autoclass:: ConsoleRenderer :members: get_default_level_styles +.. autofunction:: set_exc_info + :mod:`threadlocal` Module ------------------------- diff --git a/docs/getting-started.rst b/docs/getting-started.rst index b7c9e28d..454f886e 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -45,6 +45,7 @@ Using the defaults, as above, is equivalent to:: structlog.configure( processors=[ structlog.processors.StackInfoRenderer(), + structlog.dev.set_exc_info, structlog.processors.format_exc_info, structlog.processors.TimeStamper(), structlog.dev.ConsoleRenderer() diff --git a/src/structlog/_config.py b/src/structlog/_config.py index a9855dfb..ee217a31 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -16,7 +16,7 @@ from ._generic import BoundLogger from ._loggers import PrintLoggerFactory -from .dev import ConsoleRenderer, _has_colorama +from .dev import ConsoleRenderer, _has_colorama, set_exc_info from .processors import StackInfoRenderer, TimeStamper, format_exc_info @@ -27,6 +27,7 @@ """ _BUILTIN_DEFAULT_PROCESSORS = [ StackInfoRenderer(), + set_exc_info, format_exc_info, TimeStamper(fmt="%Y-%m-%d %H:%M.%S", utc=False), ConsoleRenderer(colors=_has_colorama), diff --git a/src/structlog/dev.py b/src/structlog/dev.py index ebb37c12..4f59d2b1 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -282,3 +282,23 @@ def get_default_level_styles(colors=True): "debug": styles.level_debug, "notset": styles.level_notset, } + + +_SENTINEL = object() + + +def set_exc_info(_, method_name, event_dict): + """ + Set ``event_dict["exc_info"] = True`` if *method_name* is ``"exception"``. + + Do nothing if the name is different or ``exc_info`` is already set. + """ + if ( + method_name != "exception" + or event_dict.get("exc_info", _SENTINEL) is not _SENTINEL + ): + return event_dict + + event_dict["exc_info"] = True + + return event_dict diff --git a/tests/test_dev.py b/tests/test_dev.py index 69e5631f..cadc9b8e 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -292,3 +292,27 @@ def test_repr_native_str(self, rns): assert 1 == cnt else: assert 2 == cnt + + +class TestSetExcInfo(object): + def test_wrong_name(self): + """ + Do nothing if name is not exception. + """ + assert {} == dev.set_exc_info(None, "foo", {}) + + @pytest.mark.parametrize("ei", [False, None, ()]) + def test_already_set(self, ei): + """ + Do nothing if exc_info is already set. + """ + assert {"exc_info": ei} == dev.set_exc_info( + None, "foo", {"exc_info": ei} + ) + + def test_set_it(self): + """ + Set exc_info to True if its not set and if the method name is + exception. + """ + assert {"exc_info": True} == dev.set_exc_info(None, "exception", {}) From c85856bc17334dd91d16c7a1d815f0e1ad8d05ad Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 21 Sep 2019 11:24:17 +0200 Subject: [PATCH 0287/1520] Add missing issue #s --- CHANGELOG.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index fa0d0d23..a3a50190 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -41,6 +41,10 @@ Changes: - Added new processor ``structlog.dev.set_exc_info()`` that will set ``exc_info=True`` if the method's name is `exception` and ``exc_info`` isn't set at all. *This is only necessary when the standard library integration is not used*. It fixes the problem that in the default configuration, ``structlog.get_logger().exception("hi")`` in an ``except`` block would not print the exception without passing ``exc_info=True`` to it explicitly. + `#130 `_ + `#173 `_ + `#200 `_ + `#204 `_ ---- From 1a8825cfaf820a831201b15dff674fa5857d4647 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 21 Sep 2019 11:27:26 +0200 Subject: [PATCH 0288/1520] Add a bunch of commas for nicer readability --- CHANGELOG.rst | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a3a50190..18a48a9c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -41,9 +41,9 @@ Changes: - Added new processor ``structlog.dev.set_exc_info()`` that will set ``exc_info=True`` if the method's name is `exception` and ``exc_info`` isn't set at all. *This is only necessary when the standard library integration is not used*. It fixes the problem that in the default configuration, ``structlog.get_logger().exception("hi")`` in an ``except`` block would not print the exception without passing ``exc_info=True`` to it explicitly. - `#130 `_ - `#173 `_ - `#200 `_ + `#130 `_, + `#173 `_, + `#200 `_, `#204 `_ @@ -76,12 +76,11 @@ Changes: A workaround has been added. `#174 `_ - ``structlog`` now tolerates passing through ``dict``\ s to stdlib logging. - `#187 `_ - `#188 `_ + `#187 `_, + `#188 `_, `#189 `_ - ---- @@ -108,7 +107,7 @@ Changes: Can be used to simplify log filtering. `#151 `_ - ``structlog.processors.JSONRenderer`` now allows for overwriting the *default* argument of its serializer. - `#77 `_ + `#77 `_, `#163 `_ - Added ``try_unbind()`` that works like ``unbind()`` but doesn't raise a ``KeyError`` if one of the keys is missing. `#171 `_ @@ -183,7 +182,7 @@ Changes: `#112 `_ - Clear log record args in ``structlog.stdlib.ProcessorFormatter`` after rendering. This fix is for you if you tried to use it and got ``TypeError: not all arguments converted during string formatting`` exceptions. - `#116 `_ + `#116 `_, `#117 `_ @@ -220,7 +219,7 @@ Changes: `#98 `_ - Added ``structlog.stdlib.ProcessorFormatter`` which does the opposite: This allows you to run ``structlog`` processors on arbitrary ``logging.LogRecords``. - `#79 `_ + `#79 `_, `#105 `_ - UNIX epoch timestamps from ``structlog.processors.TimeStamper`` are more precise now. - Added *repr_native_str* to ``structlog.processors.KeyValueRenderer`` and ``structlog.dev.ConsoleRenderer``. From 2b57d5239240e9611744240b09058fe3f1003ddd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 21 Sep 2019 11:30:32 +0200 Subject: [PATCH 0289/1520] Use a staticmethod to make ConsoleLogger serializable ref #126 --- CHANGELOG.rst | 2 ++ src/structlog/dev.py | 17 ++++++++++------- tests/test_dev.py | 16 ++++++++++++++++ 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 18a48a9c..c2a63ef2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -45,6 +45,8 @@ Changes: `#173 `_, `#200 `_, `#204 `_ +- ``structlog.dev.ConsoleLogger`` is now serializable using ``pickle``. + `#126 `_ ---- diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 4f59d2b1..9e4913bb 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -169,14 +169,17 @@ def __init__( if repr_native_str is True: self._repr = repr else: + self._repr = self._repr_no_str - def _repr(inst): - if isinstance(inst, str): - return inst - else: - return repr(inst) - - self._repr = _repr + @staticmethod + def _repr_no_str(inst): + """ + Apply repr only to non-strings. + """ + if isinstance(inst, str): + return inst + else: + return repr(inst) def __call__(self, _, __, event_dict): # Initialize lazily to prevent import side-effects. diff --git a/tests/test_dev.py b/tests/test_dev.py index cadc9b8e..aaed4694 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -6,6 +6,8 @@ from __future__ import absolute_import, division, print_function +import pickle + import pytest import six @@ -293,6 +295,20 @@ def test_repr_native_str(self, rns): else: assert 2 == cnt + @pytest.mark.parametrize("repr_native_str", [True, False]) + @pytest.mark.parametrize("force_colors", [True, False]) + def test_pickle(self, repr_native_str, force_colors): + """ + ConsoleRenderer can be pickled and unpickled. + """ + r = dev.ConsoleRenderer( + repr_native_str=repr_native_str, force_colors=force_colors + ) + + assert r(None, None, {"event": "foo"}) == pickle.loads( + pickle.dumps(r) + )(None, None, {"event": "foo"}) + class TestSetExcInfo(object): def test_wrong_name(self): From 7875f592b2b68da5e437ad434dcd7c4d7dffe3ed Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 21 Sep 2019 11:52:35 +0200 Subject: [PATCH 0290/1520] Simplify ConsoleRenderer repr handling The other version doesn't work on Python 2. --- src/structlog/dev.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 9e4913bb..64a8a72c 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -166,20 +166,20 @@ def __init__( max(self._level_to_color.keys(), key=lambda e: len(e)) ) - if repr_native_str is True: - self._repr = repr - else: - self._repr = self._repr_no_str + self._repr_native_str = repr_native_str - @staticmethod - def _repr_no_str(inst): + def _repr(self, val): """ - Apply repr only to non-strings. + Determine representation of *val* depending on its type & + self._repr_native_str. """ - if isinstance(inst, str): - return inst + if self._repr_native_str is True: + return repr(val) + + if isinstance(val, str): + return val else: - return repr(inst) + return repr(val) def __call__(self, _, __, event_dict): # Initialize lazily to prevent import side-effects. From 82d78c20ffe1750e0ab5d95e72598d5821c1899c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 21 Sep 2019 13:05:11 +0200 Subject: [PATCH 0291/1520] Make TimeStamper and BoundLoggerLazyProxy can be pickled now ref #126 --- CHANGELOG.rst | 2 +- src/structlog/_config.py | 13 +++++++ src/structlog/dev.py | 3 +- src/structlog/processors.py | 72 +++++++++++++++++++++++++------------ tests/test_config.py | 9 +++++ tests/test_processors.py | 19 ++++++++++ 6 files changed, 94 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c2a63ef2..575d3743 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -45,7 +45,7 @@ Changes: `#173 `_, `#200 `_, `#204 `_ -- ``structlog.dev.ConsoleLogger`` is now serializable using ``pickle``. +- The configuration, ``structlog.processor.TimeStamper`` and ``structlog.dev.ConsoleLogger`` can now be serialized using ``pickle``. `#126 `_ diff --git a/src/structlog/_config.py b/src/structlog/_config.py index ee217a31..84428757 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -360,3 +360,16 @@ def __getattr__(self, name): """ bl = self.bind() return getattr(bl, name) + + def __getstate__(self): + """ + Out __getattr__ magic makes this necessary. + """ + return self.__dict__ + + def __setstate__(self, state): + """ + Out __getattr__ magic makes this necessary. + """ + for k, v in state.items(): + setattr(self, k, v) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 64a8a72c..01606506 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -121,9 +121,10 @@ class ConsoleRenderer(object): .. versionadded:: 17.1 *repr_native_str* .. versionadded:: 18.1 *force_colors* .. versionadded:: 18.1 *level_styles* - .. versionchanged:: 18.2 + .. versionchanged:: 19.2 ``colorama`` now initializes lazily to avoid unwanted initializations as ``ConsoleRenderer`` is used by default. + .. versionchanged:: 19.2 Can be pickled now. """ def __init__( diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 1f426ea0..6ec54917 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -240,40 +240,68 @@ class TimeStamper(object): `_, or `None` for a `UNIX timestamp `_. :param bool utc: Whether timestamp should be in UTC or local time. - :param str key: Target key in `event_dict` for added timestamps. + :param str key: Target key in *event_dict* for added timestamps. + + .. versionchanged:: 19.2 Can be pickled now. """ - def __new__(cls, fmt=None, utc=True, key="timestamp"): - if fmt is None and not utc: - raise ValueError("UNIX timestamps are always UTC.") + __slots__ = ("_stamper", "fmt", "utc", "key") + + def __init__(self, fmt=None, utc=True, key="timestamp"): + self.fmt, self.utc, self.key = fmt, utc, key - now_method = getattr(datetime.datetime, "utcnow" if utc else "now") - if fmt is None: + self._stamper = _make_stamper(fmt, utc, key) + + def __call__(self, _, __, event_dict): + return self._stamper(event_dict) - def stamper(self, _, __, event_dict): - event_dict[key] = time.time() - return event_dict + def __getstate__(self): + return {"fmt": self.fmt, "utc": self.utc, "key": self.key} - elif fmt.upper() == "ISO": - if utc: + def __setstate__(self, state): + self.fmt = state["fmt"] + self.utc = state["utc"] + self.key = state["key"] - def stamper(self, _, __, event_dict): - event_dict[key] = now_method().isoformat() + "Z" - return event_dict + self._stamper = _make_stamper(**state) - else: - def stamper(self, _, __, event_dict): - event_dict[key] = now_method().isoformat() - return event_dict +def _make_stamper(fmt, utc, key): + """ + Create a stamper function. + """ + if fmt is None and not utc: + raise ValueError("UNIX timestamps are always UTC.") + + now = getattr(datetime.datetime, "utcnow" if utc else "now") + if fmt is None: + + def stamper_unix(event_dict): + event_dict[key] = time.time() + return event_dict + + return stamper_unix + elif fmt.upper() == "ISO": + + def stamper_iso_local(event_dict): + event_dict[key] = now().isoformat() + return event_dict + + def stamper_iso_utc(event_dict): + event_dict[key] = now().isoformat() + "Z" + return event_dict + + if utc: + return stamper_iso_utc else: + return stamper_iso_local - def stamper(self, _, __, event_dict): - event_dict[key] = now_method().strftime(fmt) - return event_dict + def stamper_fmt(event_dict): + event_dict[key] = now().strftime(fmt) + return event_dict - return type("TimeStamper", (object,), {"__call__": stamper})() + return stamper_fmt def _figure_out_exc_info(v): diff --git a/tests/test_config.py b/tests/test_config.py index 45c93f04..350b98df 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -4,6 +4,7 @@ from __future__ import absolute_import, division, print_function +import pickle import platform import sys import warnings @@ -284,6 +285,14 @@ def foo(self): ) assert 42 == proxy.foo() + def test_pickle(self): + """ + Can be pickled and unpickled. + """ + assert repr(BoundLoggerLazyProxy(None)) == repr( + pickle.loads(pickle.dumps(BoundLoggerLazyProxy(None))) + ) + class TestFunctions(object): def teardown_method(self, method): diff --git a/tests/test_processors.py b/tests/test_processors.py index 66a36a2f..96d60a96 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -8,6 +8,7 @@ import datetime import json +import pickle import sys import pytest @@ -285,6 +286,24 @@ def test_key_can_be_specified(self): assert "03" == d["month"] + @freeze_time("1980-03-25 16:00:00") + @pytest.mark.parametrize("fmt", [None, "%Y"]) + @pytest.mark.parametrize("utc", [True, False]) + @pytest.mark.parametrize("key", [None, "other-key"]) + def test_pickle(self, fmt, utc, key): + """ + TimeStamper is serializable. + """ + # UNIX timestamps must be UTC. + if fmt is None and not utc: + pytest.skip() + + ts = TimeStamper() + + assert ts(None, None, {}) == pickle.loads(pickle.dumps(ts))( + None, None, {} + ) + class TestFormatExcInfo(object): def test_formats_tuple(self, monkeypatch): From d85172bfbb2a002c462a6c31edd1b86c18ed496c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 21 Sep 2019 13:59:21 +0200 Subject: [PATCH 0292/1520] Make generic BoundLogger and PrintLogger pickleable ref #126 --- CHANGELOG.rst | 6 ++++- src/structlog/_generic.py | 13 +++++++++++ src/structlog/_loggers.py | 46 ++++++++++++++++++++++++++++++++++----- tests/test_config.py | 6 ++--- tests/test_generic.py | 20 +++++++++++++++++ tests/test_loggers.py | 25 +++++++++++++++++++++ 6 files changed, 107 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 575d3743..84961d09 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -45,7 +45,11 @@ Changes: `#173 `_, `#200 `_, `#204 `_ -- The configuration, ``structlog.processor.TimeStamper`` and ``structlog.dev.ConsoleLogger`` can now be serialized using ``pickle``. +- A best effort has been made to make as much of ``structlog`` pickleable as possible to make it friendlier with ``multiprocessing`` and similar libraries. + Some classes can only be pickled on Python 3 or using the `dill `_ library though and that is very unlikely to change. + + So far, the configuration proxy, ``structlog.processor.TimeStamper``, ``structlog.BoundLogger``, ``structlog.PrintLogger`` and ``structlog.dev.ConsoleLogger`` have been made pickelable. + Please report if you need any another class ported. `#126 `_ diff --git a/src/structlog/_generic.py b/src/structlog/_generic.py index 5da44e88..d7aa1e41 100644 --- a/src/structlog/_generic.py +++ b/src/structlog/_generic.py @@ -33,3 +33,16 @@ def __getattr__(self, method_name): wrapped = partial(self._proxy_to_logger, method_name) setattr(self, method_name, wrapped) return wrapped + + def __getstate__(self): + """ + Out __getattr__ magic makes this necessary. + """ + return self.__dict__ + + def __setstate__(self, state): + """ + Out __getattr__ magic makes this necessary. + """ + for k, v in state.items(): + setattr(self, k, v) diff --git a/src/structlog/_loggers.py b/src/structlog/_loggers.py index b9146cfa..34f06638 100644 --- a/src/structlog/_loggers.py +++ b/src/structlog/_loggers.py @@ -11,6 +11,8 @@ import sys import threading +from pickle import PicklingError + from structlog._utils import until_not_interrupted @@ -37,6 +39,17 @@ def __call__(self, *args): WRITE_LOCKS = {} +def _get_lock_for_file(file): + global WRITE_LOCKS + + lock = WRITE_LOCKS.get(file) + if lock is None: + lock = threading.Lock() + WRITE_LOCKS[file] = lock + + return lock + + class PrintLogger(object): """ Print events into a file. @@ -59,11 +72,34 @@ def __init__(self, file=None): self._write = self._file.write self._flush = self._file.flush - lock = WRITE_LOCKS.get(self._file) - if lock is None: - lock = threading.Lock() - WRITE_LOCKS[self._file] = lock - self._lock = lock + self._lock = _get_lock_for_file(self._file) + + def __getstate__(self): + """ + Out __getattr__ magic makes this necessary. + """ + if self._file is sys.stdout: + return "stdout" + + elif self._file is sys.stderr: + return "stderr" + + raise PicklingError( + "Only PrintLoggers to sys.stdout and sys.stderr can be pickled." + ) + + def __setstate__(self, state): + """ + Out __getattr__ magic makes this necessary. + """ + if state == "stdout": + self._file = sys.stdout + else: + self._file = sys.stderr + + self._write = self._file.write + self._flush = self._file.flush + self._lock = _get_lock_for_file(self._file) def __repr__(self): return "".format(self._file) diff --git a/tests/test_config.py b/tests/test_config.py index 350b98df..8880ec37 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -289,9 +289,9 @@ def test_pickle(self): """ Can be pickled and unpickled. """ - assert repr(BoundLoggerLazyProxy(None)) == repr( - pickle.loads(pickle.dumps(BoundLoggerLazyProxy(None))) - ) + bllp = BoundLoggerLazyProxy(None) + + assert repr(bllp) == repr(pickle.loads(pickle.dumps(bllp))) class TestFunctions(object): diff --git a/tests/test_generic.py b/tests/test_generic.py index 3f234425..7f425c73 100644 --- a/tests/test_generic.py +++ b/tests/test_generic.py @@ -4,6 +4,11 @@ from __future__ import absolute_import, division, print_function +import pickle + +import pytest +import six + from structlog._config import _CONFIG from structlog._generic import BoundLogger from structlog._loggers import ReturnLogger @@ -47,3 +52,18 @@ def test_proxies_anything(self): assert "log", "foo" == b.log("foo") assert "gol", "bar" == b.gol("bar") + + @pytest.mark.skipif(six.PY2, reason="Needs Py3 or dill.") + def test_pickle(self): + """ + Can be pickled and unpickled. + + Works only on Python 3: TypeError: can't pickle instancemethod objects + """ + b = BoundLogger( + ReturnLogger(), + _CONFIG.default_processors, + _CONFIG.default_context_class(), + ).bind(x=1) + + assert b.info("hi") == pickle.loads(pickle.dumps(b)).info("hi") diff --git a/tests/test_loggers.py b/tests/test_loggers.py index 19d16a41..1fb790c8 100644 --- a/tests/test_loggers.py +++ b/tests/test_loggers.py @@ -4,6 +4,7 @@ from __future__ import absolute_import, division, print_function +import pickle import sys import pytest @@ -82,6 +83,30 @@ def test_stdlib_methods_support(self, method): assert "hello" in sio.getvalue() + @pytest.mark.parametrize("file", [None, sys.stdout, sys.stderr]) + def test_pickle(self, file): + """ + Can be pickled and unpickled for stdout and stderr. + + Can't compare output because capsys et all would confuse the logic. + """ + pl = PrintLogger(file=file) + + assert pl._file is pickle.loads(pickle.dumps(pl))._file + assert pl._lock is pickle.loads(pickle.dumps(pl))._lock + + def test_pickle_not_stdout_stderr(self, tmpdir): + """ + PrintLoggers with differnt files than stdout/stderr raise a + PickingError. + """ + f = tmpdir.join("file.log") + f.write("") + pl = PrintLogger(file=f.open()) + + with pytest.raises(pickle.PicklingError, match="Only PrintLoggers to"): + pickle.dumps(pl) + class TestPrintLoggerFactory(object): def test_does_not_cache(self): From 895257b34215fd1a495ea086acf6909854f6513a Mon Sep 17 00:00:00 2001 From: Christopher Armstrong <227068+radix@users.noreply.github.com> Date: Mon, 23 Sep 2019 10:54:26 -0500 Subject: [PATCH 0293/1520] A newer, better thread-local API (#225) * Newer, better thread-locals * do NOT use greenlets in this; it turns out greenlet.getcurrent() does NOT return distinct values if you call it from separate python threads. Also reformat. * add unit tests * isort * don't use hasattr, which also solves the coverage problem * bike shedding * first pass at docs * add changelog and fix up a tiny bit of formatting in thread-local.rst * more formatting * oh, I was a little confused about the testsetup stuff. I wanted to showcase structlog.configure so I'll do that. * test docstrings * address docstring review in threadlocal.py * use ``bind()`` not bind * add autofunctions --- CHANGELOG.rst | 4 ++- docs/api.rst | 6 +++++ docs/thread-local.rst | 52 +++++++++++++++++++++++++++++++++++- src/structlog/threadlocal.py | 44 ++++++++++++++++++++++++++++++ tests/test_threadlocal.py | 48 ++++++++++++++++++++++++++++++++- 5 files changed, 151 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 84961d09..dfe1236f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -51,7 +51,9 @@ Changes: So far, the configuration proxy, ``structlog.processor.TimeStamper``, ``structlog.BoundLogger``, ``structlog.PrintLogger`` and ``structlog.dev.ConsoleLogger`` have been made pickelable. Please report if you need any another class ported. `#126 `_ - +- Added a new thread-local API that allows binding values to a thread-local context explicitly without affecting the default behavior of ``bind()``. + `#222 `_, + `#225 `_, ---- diff --git a/docs/api.rst b/docs/api.rst index 6e011529..231ee8ca 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -77,6 +77,12 @@ API Reference .. automodule:: structlog.threadlocal +.. autofunction:: merge_threadlocal_context + +.. autofunction:: clear_threadlocal + +.. autofunction:: bind_threadlocal + .. autofunction:: wrap_dict .. autofunction:: tmp_bind(logger, **tmp_values) diff --git a/docs/thread-local.rst b/docs/thread-local.rst index 43144637..18162108 100644 --- a/docs/thread-local.rst +++ b/docs/thread-local.rst @@ -30,7 +30,57 @@ If you are willing to do that, you should stick to it because `immutable state < Sooner or later, global state and mutable data lead to unpleasant surprises. However, in the case of conventional web development, we realize that passing loggers around seems rather cumbersome, intrusive, and generally against the mainstream culture. -And since it's more important that people actually *use* ``structlog`` than to be pure and snobby, ``structlog`` contains a dirty but convenient trick: thread local context storage which you may already know from `Flask `_: +And since it's more important that people actually *use* ``structlog`` than to be pure and snobby, ``structlog`` contains a couple of mechanisms to help here. + + +The ``merge_threadlocal_context`` processor +------------------------------------------- + +``structlog`` provides a simple set of functions that allow explicitly binding certain fields to a global (thread-local) context. +These functions are :func:`structlog.threadlocal.merge_threadlocal_context`, :func:`structlog.threadlocal.clear_threadlocal`, and :func:`structlog.threadlocal.bind_threadlocal`. + +The general flow of using these functions is: + +- Use :func:`structlog.configure` with :func:`structlog.threadlocal.merge_threadlocal_context` as your first processor. +- Call :func:`structlog.threadlocal.clear_threadlocal` at the beginning of your request handler (or whenever you want to reset the thread-local context). +- Call :func:`structlog.threadlocal.bind_threadlocal` as an alternative to :func:`structlog.BoundLogger.bind` when you want to bind a particular variable to the thread-local context. +- Use ``structlog`` as normal. + Loggers act as the always do, but the :func:`structlog.threadlocal.merge_threadlocal_context` processor ensures that any thread-local binds get included in all of your log messages. + +.. doctest:: + + >>> from structlog.threadlocal import ( + ... bind_threadlocal, + ... clear_threadlocal, + ... merge_threadlocal_context, + ... ) + >>> from structlog import configure + >>> configure( + ... processors=[ + ... merge_threadlocal_context, + ... structlog.processors.KeyValueRenderer(), + ... ] + ... ) + >>> log = structlog.get_logger() + >>> # At the top of your request handler (or, ideally, some general + >>> # middleware), clear the threadlocal context and bind some common + >>> # values: + >>> clear_threadlocal() + >>> bind_threadlocal(a=1) + >>> # Then use loggers as per normal + >>> # (perhaps by using structlog.get_logger() to create them). + >>> log.msg("hi") + a=1 event='hi' + >>> # And when we clear the threadlocal state again, it goes away. + >>> clear_threadlocal() + >>> log.msg("hi there") + event='hi there' + + +Thread-local contexts +--------------------- + +``structlog`` also provides thread local context storage which you may already know from `Flask `_: Thread local storage makes your logger's context global but *only within the current thread*\ [*]_. In the case of web frameworks this usually means that your context becomes global to the current request. diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index d6eea3a9..edbd6cfb 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -9,6 +9,7 @@ from __future__ import absolute_import, division, print_function import contextlib +import threading import uuid from structlog._config import BoundLoggerLazyProxy @@ -162,3 +163,46 @@ def __len__(self): def __getattr__(self, name): method = getattr(self._dict, name) return method + + +_CONTEXT = threading.local() + + +def merge_threadlocal_context(logger, method_name, event_dict): + """ + A processor that merges in a global (thread-local) context. + + Use this as your first processor in :func:`structlog.configure` to ensure + thread-local context is included in all log calls. + """ + context = _get_context().copy() + context.update(event_dict) + return context + + +def clear_threadlocal(): + """ + Clear the thread-local context. + + The typical use-case for this function is to invoke it early in + request-handling code. + """ + _CONTEXT.context = {} + + +def bind_threadlocal(**kwargs): + """ + Put keys and values into the thread-local context. + + Use this instead of :func:`~structlog.BoundLogger.bind` when you want some + context to be global (thread-local). + """ + _get_context().update(kwargs) + + +def _get_context(): + try: + return _CONTEXT.context + except AttributeError: + _CONTEXT.context = {} + return _CONTEXT.context diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py index be379499..c9b527d5 100644 --- a/tests/test_threadlocal.py +++ b/tests/test_threadlocal.py @@ -13,7 +13,14 @@ from structlog._base import BoundLoggerBase from structlog._config import wrap_logger from structlog._loggers import ReturnLogger -from structlog.threadlocal import as_immutable, tmp_bind, wrap_dict +from structlog.threadlocal import ( + as_immutable, + bind_threadlocal, + clear_threadlocal, + merge_threadlocal_context, + tmp_bind, + wrap_dict, +) try: @@ -262,3 +269,42 @@ def test_new_class(self, D): The context of a new wrapped class is empty. """ assert 0 == len(D()) + + +class TestNewThreadLocal(object): + def test_bind_and_merge(self): + """ + Binding a variable causes it to be included in the result of + merge_threadlocal_context. + """ + bind_threadlocal(a=1) + assert {"a": 1, "b": 2} == merge_threadlocal_context( + None, None, {"b": 2} + ) + + def test_clear(self): + """ + The thread-local context can be cleared, causing any previously bound + variables to not be included in merge_threadlocal_context's result. + """ + bind_threadlocal(a=1) + clear_threadlocal() + assert {"b": 2} == merge_threadlocal_context(None, None, {"b": 2}) + + def test_merge_works_without_bind(self): + """ + merge_threadlocal_context returns values as normal even when there has + been no previous calls to bind_threadlocal. + """ + assert {"b": 2} == merge_threadlocal_context(None, None, {"b": 2}) + + def test_multiple_binds(self): + """ + Multiple calls to bind_threadlocal accumulate values instead of + replacing them. + """ + bind_threadlocal(a=1, b=2) + bind_threadlocal(c=3) + assert {"a": 1, "b": 2, "c": 3} == merge_threadlocal_context( + None, None, {"b": 2} + ) From 7da6d508413b9df1bd4bdcb70f2353174de70472 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 23 Sep 2019 17:56:42 +0200 Subject: [PATCH 0294/1520] Fix minor style issues --- CHANGELOG.rst | 1 + docs/thread-local.rst | 4 ++-- tests/test_threadlocal.py | 3 +++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index dfe1236f..19bf1868 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -55,6 +55,7 @@ Changes: `#222 `_, `#225 `_, + ---- diff --git a/docs/thread-local.rst b/docs/thread-local.rst index 18162108..7311f81e 100644 --- a/docs/thread-local.rst +++ b/docs/thread-local.rst @@ -33,7 +33,7 @@ However, in the case of conventional web development, we realize that passing lo And since it's more important that people actually *use* ``structlog`` than to be pure and snobby, ``structlog`` contains a couple of mechanisms to help here. -The ``merge_threadlocal_context`` processor +The ``merge_threadlocal_context`` Processor ------------------------------------------- ``structlog`` provides a simple set of functions that allow explicitly binding certain fields to a global (thread-local) context. @@ -77,7 +77,7 @@ The general flow of using these functions is: event='hi there' -Thread-local contexts +Thread-local Contexts --------------------- ``structlog`` also provides thread local context storage which you may already know from `Flask `_: diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py index c9b527d5..3ef16da6 100644 --- a/tests/test_threadlocal.py +++ b/tests/test_threadlocal.py @@ -278,6 +278,7 @@ def test_bind_and_merge(self): merge_threadlocal_context. """ bind_threadlocal(a=1) + assert {"a": 1, "b": 2} == merge_threadlocal_context( None, None, {"b": 2} ) @@ -289,6 +290,7 @@ def test_clear(self): """ bind_threadlocal(a=1) clear_threadlocal() + assert {"b": 2} == merge_threadlocal_context(None, None, {"b": 2}) def test_merge_works_without_bind(self): @@ -305,6 +307,7 @@ def test_multiple_binds(self): """ bind_threadlocal(a=1, b=2) bind_threadlocal(c=3) + assert {"a": 1, "b": 2, "c": 3} == merge_threadlocal_context( None, None, {"b": 2} ) From 5a3599ee3c06c623593bd746959d2cfb771b600a Mon Sep 17 00:00:00 2001 From: Jonathan Meier Date: Tue, 15 Oct 2019 04:50:08 -0400 Subject: [PATCH 0295/1520] Allow foreign_pre_chain To Read Foreign Log Args (#228) * Update docs for new pass_foreign_args kwarg * Add test for pass_foreign_args * Add pass_foreign_args kwarg and functionality --- src/structlog/stdlib.py | 10 +++++++++- tests/test_stdlib.py | 26 +++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 86ada285..601a3025 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -469,12 +469,14 @@ class ProcessorFormatter(logging.Formatter): :param logger: Logger which we want to push through the ``structlog`` processor chain. This parameter is necessary for some of the processors like `filter_by_level`. (default: None) - + :param bool pass_foreign_args: If `True`, pass a foreign log record's + `args` to the event_dict under `positional_args` key. (default: False) :rtype: str .. versionadded:: 17.1.0 .. versionadded:: 17.2.0 *keep_exc_info* and *keep_stack_info* .. versionadded:: 19.2.0 *logger* + .. versionadded:: 19.2.0 *pass_foreign_args* """ def __init__( @@ -484,6 +486,7 @@ def __init__( keep_exc_info=False, keep_stack_info=False, logger=None, + pass_foreign_args=False, *args, **kwargs ): @@ -495,6 +498,7 @@ def __init__( # The and clause saves us checking for PY3 in the formatter. self.keep_stack_info = keep_stack_info and PY3 self.logger = logger + self.pass_foreign_args = pass_foreign_args def format(self, record): """ @@ -516,6 +520,10 @@ def format(self, record): logger = self.logger meth_name = record.levelname.lower() ed = {"event": record.getMessage(), "_record": record} + + if self.pass_foreign_args: + ed["positional_args"] = record.args + record.args = () # Add stack-related attributes to event_dict and unset them diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index e9abb08d..b34e21a6 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -455,7 +455,7 @@ def configure_for_pf(): reset_defaults() -def configure_logging(pre_chain, logger=None): +def configure_logging(pre_chain, logger=None, pass_foreign_args=False): """ Configure logging to use ProcessorFormatter. """ @@ -470,6 +470,7 @@ def configure_logging(pre_chain, logger=None): "foreign_pre_chain": pre_chain, "format": "%(message)s [in %(funcName)s]", "logger": logger, + "pass_foreign_args": pass_foreign_args, } }, "handlers": { @@ -527,6 +528,29 @@ def test_clears_args(self, configure_for_pf, capsys): "hello world. [in test_clears_args]\n", ) == capsys.readouterr() + def test_pass_foreign_args_true_sets_positional_args_key( + self, configure_for_pf, capsys + ): + """ + Test that when `pass_foreign_args` is `True` we set the + `positional_args` key in the `event_dict` before clearing args. + """ + test_processor = call_recorder(lambda l, m, event_dict: event_dict) + configure_logging((test_processor,), pass_foreign_args=True) + configure( + processors=[ProcessorFormatter.wrap_for_formatter], + logger_factory=LoggerFactory(), + wrapper_class=BoundLogger, + ) + + positional_args = {"foo": "bar"} + logging.getLogger().info("okay %(foo)s", positional_args) + + event_dict = test_processor.calls[0].args[2] + + assert "positional_args" in event_dict + assert positional_args == event_dict["positional_args"] + def test_log_dict(self, configure_for_pf, capsys): """ Test that dicts can be logged with std library loggers. From 026d9ff8b759dbd358d0dba1609fa003839754ba Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 15 Oct 2019 11:04:20 +0200 Subject: [PATCH 0296/1520] Minor polish for #228 --- CHANGELOG.rst | 3 +++ src/structlog/stdlib.py | 5 +++-- tests/test_stdlib.py | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 19bf1868..c6a1af36 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -54,6 +54,9 @@ Changes: - Added a new thread-local API that allows binding values to a thread-local context explicitly without affecting the default behavior of ``bind()``. `#222 `_, `#225 `_, +- Added ``pass_foreign_args`` argument to ``structlog.stdlib.ProcessorFormatter``. + It allows to pass a foreign log record's ``args`` attribute to the event dictionary under the ``positional_args`` key. + `#228 `_, ---- diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 601a3025..5a311efa 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -469,8 +469,9 @@ class ProcessorFormatter(logging.Formatter): :param logger: Logger which we want to push through the ``structlog`` processor chain. This parameter is necessary for some of the processors like `filter_by_level`. (default: None) - :param bool pass_foreign_args: If `True`, pass a foreign log record's - `args` to the event_dict under `positional_args` key. (default: False) + :param bool pass_foreign_args: If True, pass a foreign log record's + ``args`` attribute to the ``event_dict`` under ``positional_args`` key. + (default: False) :rtype: str .. versionadded:: 17.1.0 diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index b34e21a6..5ba3482b 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -532,8 +532,8 @@ def test_pass_foreign_args_true_sets_positional_args_key( self, configure_for_pf, capsys ): """ - Test that when `pass_foreign_args` is `True` we set the - `positional_args` key in the `event_dict` before clearing args. + If `pass_foreign_args` is `True` we set the `positional_args` key in + the `event_dict` before clearing args. """ test_processor = call_recorder(lambda l, m, event_dict: event_dict) configure_logging((test_processor,), pass_foreign_args=True) From d70394c3fe24ea687812cd1efca051aa97b7b853 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 15 Oct 2019 13:29:48 +0200 Subject: [PATCH 0297/1520] Ensure we're testing against all pickle versions --- tests/test_config.py | 5 +++-- tests/test_dev.py | 5 +++-- tests/test_generic.py | 5 +++-- tests/test_loggers.py | 14 +++++++++----- tests/test_processors.py | 5 +++-- 5 files changed, 21 insertions(+), 13 deletions(-) diff --git a/tests/test_config.py b/tests/test_config.py index 8880ec37..511facec 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -285,13 +285,14 @@ def foo(self): ) assert 42 == proxy.foo() - def test_pickle(self): + @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL)) + def test_pickle(self, proto): """ Can be pickled and unpickled. """ bllp = BoundLoggerLazyProxy(None) - assert repr(bllp) == repr(pickle.loads(pickle.dumps(bllp))) + assert repr(bllp) == repr(pickle.loads(pickle.dumps(bllp, proto))) class TestFunctions(object): diff --git a/tests/test_dev.py b/tests/test_dev.py index aaed4694..ee048a4f 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -297,7 +297,8 @@ def test_repr_native_str(self, rns): @pytest.mark.parametrize("repr_native_str", [True, False]) @pytest.mark.parametrize("force_colors", [True, False]) - def test_pickle(self, repr_native_str, force_colors): + @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL)) + def test_pickle(self, repr_native_str, force_colors, proto): """ ConsoleRenderer can be pickled and unpickled. """ @@ -306,7 +307,7 @@ def test_pickle(self, repr_native_str, force_colors): ) assert r(None, None, {"event": "foo"}) == pickle.loads( - pickle.dumps(r) + pickle.dumps(r, proto) )(None, None, {"event": "foo"}) diff --git a/tests/test_generic.py b/tests/test_generic.py index 7f425c73..d1568139 100644 --- a/tests/test_generic.py +++ b/tests/test_generic.py @@ -54,7 +54,8 @@ def test_proxies_anything(self): assert "gol", "bar" == b.gol("bar") @pytest.mark.skipif(six.PY2, reason="Needs Py3 or dill.") - def test_pickle(self): + @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL)) + def test_pickle(self, proto): """ Can be pickled and unpickled. @@ -66,4 +67,4 @@ def test_pickle(self): _CONFIG.default_context_class(), ).bind(x=1) - assert b.info("hi") == pickle.loads(pickle.dumps(b)).info("hi") + assert b.info("hi") == pickle.loads(pickle.dumps(b, proto)).info("hi") diff --git a/tests/test_loggers.py b/tests/test_loggers.py index 1fb790c8..272a9e42 100644 --- a/tests/test_loggers.py +++ b/tests/test_loggers.py @@ -84,7 +84,8 @@ def test_stdlib_methods_support(self, method): assert "hello" in sio.getvalue() @pytest.mark.parametrize("file", [None, sys.stdout, sys.stderr]) - def test_pickle(self, file): + @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL)) + def test_pickle(self, file, proto): """ Can be pickled and unpickled for stdout and stderr. @@ -92,10 +93,13 @@ def test_pickle(self, file): """ pl = PrintLogger(file=file) - assert pl._file is pickle.loads(pickle.dumps(pl))._file - assert pl._lock is pickle.loads(pickle.dumps(pl))._lock + rv = pickle.loads(pickle.dumps(pl, proto)) - def test_pickle_not_stdout_stderr(self, tmpdir): + assert pl._file is rv._file + assert pl._lock is rv._lock + + @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL)) + def test_pickle_not_stdout_stderr(self, tmpdir, proto): """ PrintLoggers with differnt files than stdout/stderr raise a PickingError. @@ -105,7 +109,7 @@ def test_pickle_not_stdout_stderr(self, tmpdir): pl = PrintLogger(file=f.open()) with pytest.raises(pickle.PicklingError, match="Only PrintLoggers to"): - pickle.dumps(pl) + pickle.dumps(pl, proto) class TestPrintLoggerFactory(object): diff --git a/tests/test_processors.py b/tests/test_processors.py index 96d60a96..e71db79e 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -290,7 +290,8 @@ def test_key_can_be_specified(self): @pytest.mark.parametrize("fmt", [None, "%Y"]) @pytest.mark.parametrize("utc", [True, False]) @pytest.mark.parametrize("key", [None, "other-key"]) - def test_pickle(self, fmt, utc, key): + @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL)) + def test_pickle(self, fmt, utc, key, proto): """ TimeStamper is serializable. """ @@ -300,7 +301,7 @@ def test_pickle(self, fmt, utc, key): ts = TimeStamper() - assert ts(None, None, {}) == pickle.loads(pickle.dumps(ts))( + assert ts(None, None, {}) == pickle.loads(pickle.dumps(ts, proto))( None, None, {} ) From ffa954686039f27425e5c8f7b2318ea332017da8 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 15 Oct 2019 13:30:18 +0200 Subject: [PATCH 0298/1520] Add py38 to the tox matrix --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index a6c52182..ed3dcc96 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = lint,{py27,py35,py36,py37,pypy,pypy3}-threads,{py27,py37,pypy}-{greenlets,colorama,oldtwisted},docs,pypi-description,manifest,coverage-report +envlist = lint,{py27,py35,py36,py37,py38,pypy,pypy3}-threads,{py27,py37,pypy}-{greenlets,colorama,oldtwisted},docs,pypi-description,manifest,coverage-report isolated_build = True From 8d3f31517caf2b877fb0dddaa61a81492d20c325 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 15 Oct 2019 13:30:58 +0200 Subject: [PATCH 0299/1520] pre-commit autoupdate --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 80e8a8c8..220f90d7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,7 +16,7 @@ repos: exclude: docs/code_examples - repo: https://github.com/asottile/seed-isort-config - rev: v1.9.2 + rev: v1.9.3 hooks: - id: seed-isort-config From 46b8b6460449a348e1d8116e97f819f582b926de Mon Sep 17 00:00:00 2001 From: John Carter Date: Wed, 16 Oct 2019 16:11:42 +1300 Subject: [PATCH 0300/1520] Force event to str in ConsoleRenderer (#221) * Force event to str in ConsoleRenderer Resolves #186 * Don't force unicode event to str on python 2 --- src/structlog/dev.py | 6 +++++- tests/test_dev.py | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 01606506..372f7fcf 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -8,7 +8,7 @@ from __future__ import absolute_import, division, print_function -from six import StringIO +from six import PY2, StringIO, string_types try: @@ -213,7 +213,11 @@ def __call__(self, _, __, event_dict): + "] " ) + # force event to str for compatibility with standard library event = event_dict.pop("event") + if not PY2 or not isinstance(event, string_types): + event = str(event) + if event_dict: event = _pad(event, self._pad_event) + self._styles.reset + " " else: diff --git a/tests/test_dev.py b/tests/test_dev.py index ee048a4f..11690ba1 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -81,6 +81,27 @@ def test_timestamp(self, cr, styles, unpadded): assert (styles.timestamp + "42" + styles.reset + " " + unpadded) == rv + def test_event_stringified(self, cr, styles, unpadded): + """ + Event is cast to string. + """ + not_a_string = Exception("test") + + rv = cr(None, None, {"event": not_a_string}) + + assert unpadded == rv + + @pytest.mark.skipif(not six.PY2, reason="Problem only exists on Python 2.") + @pytest.mark.parametrize("s", [u"\xc3\xa4".encode("utf-8"), u"ä", "ä"]) + def test_event_py2_only_stringify_non_strings(self, cr, s, styles): + """ + If event is a string type already, leave it be on Python 2. Running + str() on unicode strings with non-ascii characters raises an error. + """ + rv = cr(None, None, {"event": s}) + + assert styles.bright + s + styles.reset == rv + def test_level(self, cr, styles, padded): """ Levels are rendered aligned, in square brackets, and color coded. From 525a9348fcb384f046b4ead7653a0e539bb7d9cc Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 16 Oct 2019 10:55:55 +0200 Subject: [PATCH 0301/1520] TIL I can use license_file in the setup call too --- setup.cfg | 5 ----- setup.py | 1 + 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/setup.cfg b/setup.cfg index 07868d43..4b980e83 100644 --- a/setup.cfg +++ b/setup.cfg @@ -3,11 +3,6 @@ universal = 1 -[metadata] -# ensure LICENSE is included in wheel metadata -license_file = LICENSE - - [tool:pytest] minversion = 3.0 strict = true diff --git a/setup.py b/setup.py index 89fd7df0..2aef6d64 100644 --- a/setup.py +++ b/setup.py @@ -111,6 +111,7 @@ def find_meta(meta): name=NAME, description=find_meta("description"), license=find_meta("license"), + license_file="LICENSE", url=find_meta("uri"), version=VERSION, author=find_meta("author"), From b7293e9592e892368a96964a846ecb0d65b6f81f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 16 Oct 2019 11:31:40 +0200 Subject: [PATCH 0302/1520] It's not valid but pep517 will add licenses automagically --- setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.py b/setup.py index 2aef6d64..89fd7df0 100644 --- a/setup.py +++ b/setup.py @@ -111,7 +111,6 @@ def find_meta(meta): name=NAME, description=find_meta("description"), license=find_meta("license"), - license_file="LICENSE", url=find_meta("uri"), version=VERSION, author=find_meta("author"), From 5bd0b00aaa7361175b2d407597e3ffba5068f323 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 16 Oct 2019 11:57:42 +0200 Subject: [PATCH 0303/1520] Add changelog entry for #221 --- CHANGELOG.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c6a1af36..96c2566c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -48,7 +48,7 @@ Changes: - A best effort has been made to make as much of ``structlog`` pickleable as possible to make it friendlier with ``multiprocessing`` and similar libraries. Some classes can only be pickled on Python 3 or using the `dill `_ library though and that is very unlikely to change. - So far, the configuration proxy, ``structlog.processor.TimeStamper``, ``structlog.BoundLogger``, ``structlog.PrintLogger`` and ``structlog.dev.ConsoleLogger`` have been made pickelable. + So far, the configuration proxy, ``structlog.processor.TimeStamper``, ``structlog.BoundLogger``, ``structlog.PrintLogger`` and ``structlog.dev.ConsoleRenderer`` have been made pickelable. Please report if you need any another class ported. `#126 `_ - Added a new thread-local API that allows binding values to a thread-local context explicitly without affecting the default behavior of ``bind()``. @@ -57,6 +57,8 @@ Changes: - Added ``pass_foreign_args`` argument to ``structlog.stdlib.ProcessorFormatter``. It allows to pass a foreign log record's ``args`` attribute to the event dictionary under the ``positional_args`` key. `#228 `_, +- ``structlog.dev.ConsoleRenderer`` now calls ``str`` on the event value. + `#221 `_, ---- From 8f113717f9ecf022dd7c8b9b6c93db1c5be3c3e2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 16 Oct 2019 12:01:32 +0200 Subject: [PATCH 0304/1520] str is a function --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 96c2566c..76b2513c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -57,7 +57,7 @@ Changes: - Added ``pass_foreign_args`` argument to ``structlog.stdlib.ProcessorFormatter``. It allows to pass a foreign log record's ``args`` attribute to the event dictionary under the ``positional_args`` key. `#228 `_, -- ``structlog.dev.ConsoleRenderer`` now calls ``str`` on the event value. +- ``structlog.dev.ConsoleRenderer`` now calls ``str()`` on the event value. `#221 `_, From bbe32c3bcec18ebee366da6d72f12af7e232d46b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 16 Oct 2019 12:02:26 +0200 Subject: [PATCH 0305/1520] Fix stray commas --- CHANGELOG.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 76b2513c..2e0d1f3e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -56,9 +56,9 @@ Changes: `#225 `_, - Added ``pass_foreign_args`` argument to ``structlog.stdlib.ProcessorFormatter``. It allows to pass a foreign log record's ``args`` attribute to the event dictionary under the ``positional_args`` key. - `#228 `_, + `#228 `_ - ``structlog.dev.ConsoleRenderer`` now calls ``str()`` on the event value. - `#221 `_, + `#221 `_ ---- From c417d53d512d62fcf4fdcd7f967ff4cfdd59cfe8 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 16 Oct 2019 12:04:20 +0200 Subject: [PATCH 0306/1520] Missed a stray comma --- CHANGELOG.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2e0d1f3e..a05ae35c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -49,11 +49,11 @@ Changes: Some classes can only be pickled on Python 3 or using the `dill `_ library though and that is very unlikely to change. So far, the configuration proxy, ``structlog.processor.TimeStamper``, ``structlog.BoundLogger``, ``structlog.PrintLogger`` and ``structlog.dev.ConsoleRenderer`` have been made pickelable. - Please report if you need any another class ported. + Please report if you need any another class fixed. `#126 `_ - Added a new thread-local API that allows binding values to a thread-local context explicitly without affecting the default behavior of ``bind()``. `#222 `_, - `#225 `_, + `#225 `_ - Added ``pass_foreign_args`` argument to ``structlog.stdlib.ProcessorFormatter``. It allows to pass a foreign log record's ``args`` attribute to the event dictionary under the ``positional_args`` key. `#228 `_ From 381f94d4bf3d73d35f0b70cd025d0618b4f4dc3b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 16 Oct 2019 12:11:12 +0200 Subject: [PATCH 0307/1520] Fix a bunch of URLs --- .github/CONTRIBUTING.rst | 4 ++-- .pre-commit-config.yaml | 4 ++-- CHANGELOG.rst | 2 +- README.rst | 2 +- docs/configuration.rst | 2 +- docs/thread-local.rst | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst index 26fbf874..91ac5b3f 100644 --- a/.github/CONTRIBUTING.rst +++ b/.github/CONTRIBUTING.rst @@ -116,7 +116,7 @@ However, you’ll probably want a more traditional environment as well. We highly recommend to develop using the latest Python 3 release because you're more likely to catch certain bugs earlier. First create a `virtual environment `_. -It’s out of scope for this document to list all the ways to manage virtual environments in Python but if you don’t have already a pet way, take some time to look at tools like `pew `_, `virtualfish `_, and `virtualenvwrapper `_. +It’s out of scope for this document to list all the ways to manage virtual environments in Python but if you don’t have already a pet way, take some time to look at tools like `pew `_, `virtualfish `_, and `virtualenvwrapper `_. Next get an up to date checkout of the ``structlog`` repository: @@ -190,6 +190,6 @@ Thank you for considering contributing to ``structlog``! .. _reStructuredText: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html .. _semantic newlines: https://rhodesmill.org/brandon/2012/one-sentence-per-line/ .. _CI: https://dev.azure.com/the-hynek/structlog/_build?definitionId=1 -.. _black: https://github.com/ambv/black +.. _black: https://github.com/psf/black .. _pre-commit: https://pre-commit.com/ .. _isort: https://github.com/timothycrosley/isort diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 220f90d7..0fdf0678 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,10 +1,10 @@ repos: - - repo: https://github.com/ambv/black + - repo: https://github.com/psf/black rev: 19.3b0 hooks: - id: black language_version: python3.7 - # override until resolved: https://github.com/ambv/black/issues/402 + # override until resolved: https://github.com/psf/black/issues/402 files: \.pyi?$ types: [] diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a05ae35c..56f782c3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -293,7 +293,7 @@ Changes: - Be more more lenient about missing ``__name__``\ s. `#62 `_ - Add ``structlog.dev.ConsoleRenderer`` that renders the event dictionary aligned and with colors. -- Use `six `_ for compatibility. +- Use `six `_ for compatibility. - Add ``structlog.processors.UnicodeDecoder`` that will decode all byte string values in an event dictionary to Unicode. - Add ``serializer`` parameter to ``structlog.processors.JSONRenderer`` which allows for using different (possibly faster) JSON encoders than the standard library. diff --git a/README.rst b/README.rst index fb4b9b09..99c1fd17 100644 --- a/README.rst +++ b/README.rst @@ -24,7 +24,7 @@ :alt: Test Coverage .. image:: https://img.shields.io/badge/code%20style-black-000000.svg - :target: https://github.com/ambv/black + :target: https://github.com/psf/black :alt: Code style: black .. -begin-short- diff --git a/docs/configuration.rst b/docs/configuration.rst index d0af9edd..9175d42f 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -159,7 +159,7 @@ If you use standard library's logging, it makes sense to configure them next to See `Third-Party Extensions `_ in the wiki. **Flask** - See `Logging `_. + See `Logging `_. **Pyramid** `Application constructor `_. diff --git a/docs/thread-local.rst b/docs/thread-local.rst index 7311f81e..c0282d40 100644 --- a/docs/thread-local.rst +++ b/docs/thread-local.rst @@ -80,7 +80,7 @@ The general flow of using these functions is: Thread-local Contexts --------------------- -``structlog`` also provides thread local context storage which you may already know from `Flask `_: +``structlog`` also provides thread local context storage which you may already know from `Flask `_: Thread local storage makes your logger's context global but *only within the current thread*\ [*]_. In the case of web frameworks this usually means that your context becomes global to the current request. From 691a4896f18e9ea9c319849b54489cfe0dd7dc0b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 16 Oct 2019 12:21:53 +0200 Subject: [PATCH 0308/1520] Get rid of http --- README.rst | 2 +- docs/logging-best-practices.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 99c1fd17..3beca1e2 100644 --- a/README.rst +++ b/README.rst @@ -35,7 +35,7 @@ It's up to you whether you want ``structlog`` to take care about the **output** .. -end-short- -Once you feel inspired to try it out, check out our friendly `Getting Started tutorial `_ that also contains detailed installation instructions! +Once you feel inspired to try it out, check out our friendly `Getting Started tutorial `_ that also contains detailed installation instructions! .. -begin-spiel- diff --git a/docs/logging-best-practices.rst b/docs/logging-best-practices.rst index 515f08b7..82e7d7ba 100644 --- a/docs/logging-best-practices.rst +++ b/docs/logging-best-practices.rst @@ -53,7 +53,7 @@ Additionally, `Graylog's Extended Log Format`_ (GELF) allows for structured data .. _Logstash: https://www.elastic.co/products/logstash .. _Kibana: https://www.elastic.co/products/kibana .. _Elasticsearch: https://www.elastic.co/products/elasticsearch -.. _`Graylog's Extended Log Format`: http://docs.graylog.org/en/latest/pages/gelf.html +.. _`Graylog's Extended Log Format`: https://docs.graylog.org/en/latest/pages/gelf.html .. _`standard out`: https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29 .. _syslogd: https://en.wikipedia.org/wiki/Syslogd .. _`twelve-factor app methodology`: https://12factor.net/logs From b208253aa7f8f70fb90003f75dae10907319d4f7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 16 Oct 2019 12:22:52 +0200 Subject: [PATCH 0309/1520] Prepare 19.2.0 --- CHANGELOG.rst | 2 +- src/structlog/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 56f782c3..b04e28d4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,7 +5,7 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. -19.2.0 (UNRELEASED) +19.2.0 (2019-10-16) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 6b6124a9..92313109 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -36,7 +36,7 @@ twisted = None -__version__ = "19.2.0.dev0" +__version__ = "19.2.0" __title__ = "structlog" __description__ = "Structured Logging for Python" From 1dd813f221c3650ccc6ba62ffb09c3144e369b70 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 16 Oct 2019 12:34:29 +0200 Subject: [PATCH 0310/1520] Start new development cycle --- CHANGELOG.rst | 25 +++++++++++++++++++++++++ src/structlog/__init__.py | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b04e28d4..d9d4ccf9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,31 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. +19.3.0 (UNRELEASED) +------------------- + + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +*none* + + +Deprecations: +^^^^^^^^^^^^^ + +*none* + + +Changes: +^^^^^^^^ + +*none* + + +---- + + 19.2.0 (2019-10-16) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 92313109..e8024f86 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -36,7 +36,7 @@ twisted = None -__version__ = "19.2.0" +__version__ = "19.3.0.dev0" __title__ = "structlog" __description__ = "Structured Logging for Python" From bbe025acf4dee6f5e6ccfbbe83fb42549d203ba5 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 16 Oct 2019 20:05:30 +0200 Subject: [PATCH 0311/1520] Get rid of packaging confing in setup.cfg --- setup.cfg | 5 ----- setup.py | 1 + 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/setup.cfg b/setup.cfg index 4b980e83..1696c179 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,8 +1,3 @@ -[bdist_wheel] -# we're pure-python -universal = 1 - - [tool:pytest] minversion = 3.0 strict = true diff --git a/setup.py b/setup.py index 89fd7df0..ebaa08ca 100644 --- a/setup.py +++ b/setup.py @@ -126,4 +126,5 @@ def find_meta(meta): install_requires=INSTALL_REQUIRES, extras_require=EXTRAS_REQUIRE, zip_safe=False, + options={"bdist_wheel": {"universal": "1"}}, ) From 9f90b2689c475bbf13061c786f1dbfcecd6a2a37 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 16 Oct 2019 21:19:37 +0200 Subject: [PATCH 0312/1520] Get rid of setup.cfg --- .pre-commit-config.yaml | 1 + MANIFEST.in | 2 +- pyproject.toml | 12 ++++++++++++ pytest.ini | 7 +++++++ setup.cfg | 19 ------------------- 5 files changed, 21 insertions(+), 20 deletions(-) create mode 100644 pytest.ini delete mode 100644 setup.cfg diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0fdf0678..33c61e64 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,6 +24,7 @@ repos: rev: v4.3.21 hooks: - id: isort + additional_dependencies: [toml] language_version: python3.7 - repo: https://github.com/pre-commit/pre-commit-hooks diff --git a/MANIFEST.in b/MANIFEST.in index 97e66733..60c64811 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2,7 +2,7 @@ include LICENSE LICENSE.apache2 LICENSE.mit .coveragerc conftest.py .readthedocs include *.rst recursive-include .github *.rst -include tox.ini +include tox.ini pytest.ini graft tests recursive-exclude tests *.pyc diff --git a/pyproject.toml b/pyproject.toml index cc4975fb..7fd69784 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,3 +5,15 @@ build-backend = "setuptools.build_meta" [tool.black] line-length = 79 + + +[tool.isort] +atomic=true +include_trailing_comma=true +lines_after_imports=2 +lines_between_types=1 +multi_line_output=3 +not_skip="__init__.py" + +known_first_party="structlog" +known_third_party=["flask", "freezegun", "pretend", "pytest", "setuptools", "six", "some_module", "structlog", "twisted", "zope"] diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 00000000..aef3ec02 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,7 @@ +[tool:pytest] +minversion = 3.0 +strict = true +addopts = -ra +testpaths = tests +filterwarnings = + once::Warning diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 1696c179..00000000 --- a/setup.cfg +++ /dev/null @@ -1,19 +0,0 @@ -[tool:pytest] -minversion = 3.0 -strict = true -addopts = -ra -testpaths = tests -filterwarnings = - once::Warning - - -[isort] -atomic=true -include_trailing_comma=true -lines_after_imports=2 -lines_between_types=1 -multi_line_output=3 -not_skip=__init__.py - -known_first_party=structlog -known_third_party=flask,freezegun,pretend,pytest,setuptools,six,some_module,twisted,zope From 4d74f75f89b3418f9af677aa53bc11a7c16982d9 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 17 Oct 2019 13:29:47 +0200 Subject: [PATCH 0313/1520] Ah, why not. pytest & tox are related --- MANIFEST.in | 9 +++------ pytest.ini | 7 ------- tox.ini | 8 ++++++++ 3 files changed, 11 insertions(+), 13 deletions(-) delete mode 100644 pytest.ini diff --git a/MANIFEST.in b/MANIFEST.in index 60c64811..9b447873 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,13 +1,10 @@ -include LICENSE LICENSE.apache2 LICENSE.mit .coveragerc conftest.py .readthedocs.yml pyproject.toml +include LICENSE LICENSE.apache2 LICENSE.mit .coveragerc conftest.py include *.rst -recursive-include .github *.rst -include tox.ini pytest.ini +include *.ini *.yml *.yaml *.toml +graft .github graft tests recursive-exclude tests *.pyc graft docs prune docs/_build - -# Don't package GitHub-specific files. -exclude .github/*.md azure-pipelines.yml .pre-commit-config.yaml codecov.yml diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index aef3ec02..00000000 --- a/pytest.ini +++ /dev/null @@ -1,7 +0,0 @@ -[tool:pytest] -minversion = 3.0 -strict = true -addopts = -ra -testpaths = tests -filterwarnings = - once::Warning diff --git a/tox.ini b/tox.ini index ed3dcc96..20a092c2 100644 --- a/tox.ini +++ b/tox.ini @@ -1,3 +1,11 @@ +[pytest] +strict = true +addopts = -ra +testpaths = tests +filterwarnings = + once::Warning + + [tox] envlist = lint,{py27,py35,py36,py37,py38,pypy,pypy3}-threads,{py27,py37,pypy}-{greenlets,colorama,oldtwisted},docs,pypi-description,manifest,coverage-report isolated_build = True From ddb67f503250df26e7d58715962aefcbc67a1bb2 Mon Sep 17 00:00:00 2001 From: Stefane Fermigier Date: Thu, 24 Oct 2019 15:09:25 +0200 Subject: [PATCH 0314/1520] Fix typo in docstrings. (#231) --- src/structlog/_config.py | 4 ++-- src/structlog/_generic.py | 4 ++-- src/structlog/_loggers.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 84428757..b4d3273c 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -363,13 +363,13 @@ def __getattr__(self, name): def __getstate__(self): """ - Out __getattr__ magic makes this necessary. + Our __getattr__ magic makes this necessary. """ return self.__dict__ def __setstate__(self, state): """ - Out __getattr__ magic makes this necessary. + Our __getattr__ magic makes this necessary. """ for k, v in state.items(): setattr(self, k, v) diff --git a/src/structlog/_generic.py b/src/structlog/_generic.py index d7aa1e41..dfc73d22 100644 --- a/src/structlog/_generic.py +++ b/src/structlog/_generic.py @@ -36,13 +36,13 @@ def __getattr__(self, method_name): def __getstate__(self): """ - Out __getattr__ magic makes this necessary. + Our __getattr__ magic makes this necessary. """ return self.__dict__ def __setstate__(self, state): """ - Out __getattr__ magic makes this necessary. + Our __getattr__ magic makes this necessary. """ for k, v in state.items(): setattr(self, k, v) diff --git a/src/structlog/_loggers.py b/src/structlog/_loggers.py index 34f06638..a748bfb7 100644 --- a/src/structlog/_loggers.py +++ b/src/structlog/_loggers.py @@ -76,7 +76,7 @@ def __init__(self, file=None): def __getstate__(self): """ - Out __getattr__ magic makes this necessary. + Our __getattr__ magic makes this necessary. """ if self._file is sys.stdout: return "stdout" @@ -90,7 +90,7 @@ def __getstate__(self): def __setstate__(self, state): """ - Out __getattr__ magic makes this necessary. + Our __getattr__ magic makes this necessary. """ if state == "stdout": self._file = sys.stdout From 472e7511c4d153dc03089f26cbfee4bfd2eed6dd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 5 Dec 2019 15:21:53 +0100 Subject: [PATCH 0315/1520] Simplify expression --- src/structlog/processors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 6ec54917..d7b69207 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -312,7 +312,7 @@ def _figure_out_exc_info(v): :rtype: tuple """ if six.PY3 and isinstance(v, BaseException): - return (v.__class__, v, getattr(v, "__traceback__")) + return (v.__class__, v, v.__traceback__) elif isinstance(v, tuple): return v elif v: From 22f4d8eca5c2b4e95a0e856deac050fa96af0720 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 3 Jan 2020 09:34:56 +0100 Subject: [PATCH 0316/1520] Add 3.8 to CI (#237) * Add 3.8 to CI * Use cached 3.8 * Stop testing with 4 years old twisted --- azure-pipelines.yml | 40 +++++++++++++--------------------------- tox.ini | 3 +-- 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 17334a63..4b88c7d9 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -22,9 +22,6 @@ jobs: py27-greenlets: tox.env: py27-greenlets python.version: '2.7' - py27-oldtwisted: - tox.env: py27-oldtwisted - python.version: '2.7' py27-threads: tox.env: py27-threads python.version: '2.7' @@ -40,25 +37,21 @@ jobs: py37-greenlets: tox.env: py37-greenlets python.version: '3.7' - py37-oldtwisted: - tox.env: py37-oldtwisted - python.version: '3.7' py37-threads: tox.env: py37-threads python.version: '3.7' - # Twisted is currently broken on 3.8. - # py38-threads: - # tox.env: py38-threads - # python.version: '3.8' + py38-threads: + tox.env: py38-threads + python.version: '3.8' + py38-greenlets: + tox.env: py38-greenlets + python.version: '3.8' pypy-colorama: tox.env: pypy-colorama python.version: pypy2 pypy-greenlets: tox.env: pypy-greenlets python.version: pypy2 - pypy-oldtwisted: - tox.env: pypy-oldtwisted - python.version: pypy2 pypy-threads: tox.env: pypy-threads python.version: pypy2 @@ -66,13 +59,6 @@ jobs: tox.env: pypy3-threads python.version: pypy3 -# py38-greenlets: -# tox.env: py38-greenlets -# python.version: 3.8-dev -# py38-threads: -# tox.env: py38-threads -# python.version: 3.8-dev - Docs: python.version: '3.7' tox.env: docs @@ -95,15 +81,15 @@ jobs: inputs: versionSpec: '$(python.version)' architecture: 'x64' - condition: not(in(variables['python.version'], '3.8')) + # condition: not(in(variables['python.version'], '3.8')) displayName: Use cached Python $(python.version) for tests. - - script: | - sudo add-apt-repository ppa:deadsnakes - sudo apt-get update - sudo apt-get install -y --no-install-recommends python$(python.version)-dev python$(python.version)-distutils - condition: in(variables['python.version'], '3.8') - displayName: Install Python $(python.version) from the deadsnakes PPA for tests. + # - script: | + # sudo add-apt-repository ppa:deadsnakes + # sudo apt-get update + # sudo apt-get install -y --no-install-recommends python$(python.version)-dev python$(python.version)-distutils + # condition: in(variables['python.version'], '3.8') + # displayName: Install Python $(python.version) from the deadsnakes PPA for tests. - script: $(pyTools.pythonLocation)/bin/tox -e $(tox.env) env: diff --git a/tox.ini b/tox.ini index 20a092c2..f3d5e15f 100644 --- a/tox.ini +++ b/tox.ini @@ -7,7 +7,7 @@ filterwarnings = [tox] -envlist = lint,{py27,py35,py36,py37,py38,pypy,pypy3}-threads,{py27,py37,pypy}-{greenlets,colorama,oldtwisted},docs,pypi-description,manifest,coverage-report +envlist = lint,{py27,py35,py36,py37,py38,pypy,pypy3}-threads,{py27,py37,py38,pypy}-{greenlets,colorama},docs,pypi-description,manifest,coverage-report isolated_build = True @@ -24,7 +24,6 @@ extras = {env:TOX_AP_TEST_EXTRAS:tests} deps = greenlets: greenlet threads,greenlets,colorama: twisted - oldtwisted: twisted < 17 colorama: colorama setenv = PYTHONHASHSEED = 0 From f34659df5d67fe98aff9467f05570b31d189a241 Mon Sep 17 00:00:00 2001 From: Rob Galanakis Date: Mon, 6 Jan 2020 07:06:44 -0800 Subject: [PATCH 0317/1520] Add capture_logs context manager (#234) * Add capture_logs context manager See https://github.com/hynek/structlog/issues/14#issuecomment-563321043 for more context. It needed to go into its own file, rather than `dev`, because it relies on `_config` and `_config` relies on `dev`. * Rename _capture.py to testing.py * Add docstring to testing.LogCapture Co-authored-by: Hynek Schlawack --- CHANGELOG.rst | 3 +- docs/loggers.rst | 13 +++++++- src/structlog/__init__.py | 3 +- src/structlog/testing.py | 68 +++++++++++++++++++++++++++++++++++++++ tests/test_capture.py | 42 ++++++++++++++++++++++++ 5 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 src/structlog/testing.py create mode 100644 tests/test_capture.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d9d4ccf9..bd06531d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,7 +24,8 @@ Deprecations: Changes: ^^^^^^^^ -*none* +- Added a context manager for capturing logs, mostly to assist users who want to assert some logging happened during unit tests. + `#14 `_ ---- diff --git a/docs/loggers.rst b/docs/loggers.rst index 6b5375bb..60891008 100644 --- a/docs/loggers.rst +++ b/docs/loggers.rst @@ -126,7 +126,18 @@ To save you the hassle and slowdown of using standard library's ``logging`` for >>> PrintLogger().info("hello world!") hello world! -Additionally -- mostly for unit testing -- ``structlog`` also ships with a logger that just returns whatever it gets passed into it: :class:`~structlog.ReturnLogger`. +If you need functionality similar to ``unittest.TestCase.assertLogs``, or you want to capture all logs for some other reason, you can use the ``structlog.testing.capture_logs`` context manager: + +.. doctest:: + + >>> from structlog import get_logger + >>> from structlog.testing import capture_logs + >>> with capture_logs() as logs: + ... get_logger().bind(x="y").info("hello") + >>> logs + [{'x': 'y', 'event': 'hello', 'log_level': 'info'}] + +Additionally -- mostly for unit testing within ``structlog`` itself -- ``structlog`` also ships with a logger that just returns whatever it gets passed into it: :class:`~structlog.ReturnLogger`. .. doctest:: diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index e8024f86..6e6b9340 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -8,7 +8,7 @@ from __future__ import absolute_import, division, print_function -from structlog import dev, processors, stdlib, threadlocal +from structlog import dev, processors, stdlib, testing, threadlocal from structlog._base import BoundLoggerBase from structlog._config import ( configure, @@ -67,6 +67,7 @@ "processors", "reset_defaults", "stdlib", + "testing", "threadlocal", "twisted", "wrap_logger", diff --git a/src/structlog/testing.py b/src/structlog/testing.py new file mode 100644 index 00000000..590ff1f5 --- /dev/null +++ b/src/structlog/testing.py @@ -0,0 +1,68 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the MIT License. See the LICENSE file in the root of this +# repository for complete details. + +""" +Thin module holding capture_logs. +Ended up here since there were circular references +in other likely places (``dev`` module for example). +""" + +from contextlib import contextmanager + +from ._config import configure, get_config +from .exceptions import DropEvent + + +class LogCapture(object): + """ + Class for capturing log messages in its entries list. + Generally you should use :func:`structlog.testing.capture_logs`, + but you can use this class if you want to capture logs with other patterns. + For example, using ``pytest`` fixtures:: + + @pytest.fixture(scope='function') + def log_output(): + return LogCapture() + + + @pytest.fixture(scope='function', autouse=True) + def configure_structlog(log_output): + structlog.configure( + processors=[log_output] + ) + + def test_my_stuff(log_output): + do_something() + assert log_output.entries == [...] + + .. versionadded:: 19.3.0 + """ + + def __init__(self): + self.entries = [] + + def __call__(self, _, method_name, event_dict): + event_dict["log_level"] = method_name + self.entries.append(event_dict) + raise DropEvent + + +@contextmanager +def capture_logs(): + """ + Context manager that appends all logging statements to its yielded list + while it is active. + + .. versionadded:: 19.3.0 + """ + cap = LogCapture() + old_processors = get_config()["processors"] + try: + configure(processors=[cap]) + yield cap.entries + finally: + configure(processors=old_processors) + + +__all__ = ["LogCapture", "capture_logs"] diff --git a/tests/test_capture.py b/tests/test_capture.py new file mode 100644 index 00000000..1437b57d --- /dev/null +++ b/tests/test_capture.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- + +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the MIT License. See the LICENSE file in the root of this +# repository for complete details. + +from __future__ import absolute_import, division, print_function + +import pytest + +from structlog import _config, testing + + +class TestCaptureLogs(object): + @classmethod + def teardown_class(cls): + _config.reset_defaults() + + def test_captures_logs(self): + with testing.capture_logs() as logs: + _config.get_logger().bind(x="y").info("hello") + _config.get_logger().bind(a="b").info("goodbye") + assert [ + {"event": "hello", "log_level": "info", "x": "y"}, + {"a": "b", "event": "goodbye", "log_level": "info"}, + ] == logs + + def get_active_procs(self): + return _config.get_config()["processors"] + + def test_restores_processors_on_success(self): + orig_procs = self.get_active_procs() + with testing.capture_logs(): + assert orig_procs is not self.get_active_procs() + assert orig_procs is self.get_active_procs() + + def test_restores_processors_on_error(self): + orig_procs = self.get_active_procs() + with pytest.raises(NotImplementedError): + with testing.capture_logs(): + raise NotImplementedError("from test") + assert orig_procs is self.get_active_procs() From 1405ad80f8f007710b37e8cd6d0718ef095ae690 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 6 Jan 2020 16:08:57 +0100 Subject: [PATCH 0318/1520] There won't be a 19.3 --- CHANGELOG.rst | 2 +- src/structlog/__init__.py | 2 +- src/structlog/testing.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index bd06531d..f4a7b2ce 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,7 +5,7 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. -19.3.0 (UNRELEASED) +20.1.0 (UNRELEASED) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 6e6b9340..f7ee3a0c 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -36,7 +36,7 @@ twisted = None -__version__ = "19.3.0.dev0" +__version__ = "20.1.0.dev0" __title__ = "structlog" __description__ = "Structured Logging for Python" diff --git a/src/structlog/testing.py b/src/structlog/testing.py index 590ff1f5..ad9e069b 100644 --- a/src/structlog/testing.py +++ b/src/structlog/testing.py @@ -36,7 +36,7 @@ def test_my_stuff(log_output): do_something() assert log_output.entries == [...] - .. versionadded:: 19.3.0 + .. versionadded:: 20.1.0 """ def __init__(self): @@ -54,7 +54,7 @@ def capture_logs(): Context manager that appends all logging statements to its yielded list while it is active. - .. versionadded:: 19.3.0 + .. versionadded:: 20.1.0 """ cap = LogCapture() old_processors = get_config()["processors"] From 8c7ab5e1fa0d271f4cd4e073717d3087b8ee3301 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 6 Jan 2020 16:09:46 +0100 Subject: [PATCH 0319/1520] pre-commit autoupdate --- .pre-commit-config.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 33c61e64..fa2a927f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/psf/black - rev: 19.3b0 + rev: 19.10b0 hooks: - id: black language_version: python3.7 @@ -9,14 +9,14 @@ repos: types: [] - repo: https://gitlab.com/pycqa/flake8 - rev: 3.7.8 + rev: 3.7.9 hooks: - id: flake8 language_version: python3.7 exclude: docs/code_examples - repo: https://github.com/asottile/seed-isort-config - rev: v1.9.3 + rev: v1.9.4 hooks: - id: seed-isort-config @@ -28,7 +28,7 @@ repos: language_version: python3.7 - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v2.3.0 + rev: v2.4.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer From 6f0324196219833f0a8c850b9055e8e72b428ffc Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 6 Jan 2020 16:31:53 +0100 Subject: [PATCH 0320/1520] Apply a little polish to #234 --- CHANGELOG.rst | 4 ++- docs/api.rst | 9 ++++++ docs/loggers.rst | 2 +- src/structlog/testing.py | 13 +++++---- tests/{test_capture.py => test_testing.py} | 33 +++++++++++++++++----- 5 files changed, 46 insertions(+), 15 deletions(-) rename tests/{test_capture.py => test_testing.py} (57%) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f4a7b2ce..2b68e59a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,8 +24,10 @@ Deprecations: Changes: ^^^^^^^^ -- Added a context manager for capturing logs, mostly to assist users who want to assert some logging happened during unit tests. +- Added a new module ``structlog.testing`` for first class testing support. + The first entry is the context manager ``capture_logs()`` that allows to make assertions about structured log calls. `#14 `_ + `#234 `_ ---- diff --git a/docs/api.rst b/docs/api.rst index 231ee8ca..cd830697 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -72,6 +72,15 @@ API Reference .. autofunction:: set_exc_info +:mod:`testing` Module +--------------------- + +.. automodule:: structlog.testing + +.. autofunction:: capture_logs +.. autoclass:: LogCapture + + :mod:`threadlocal` Module ------------------------- diff --git a/docs/loggers.rst b/docs/loggers.rst index 60891008..7806ab30 100644 --- a/docs/loggers.rst +++ b/docs/loggers.rst @@ -126,7 +126,7 @@ To save you the hassle and slowdown of using standard library's ``logging`` for >>> PrintLogger().info("hello world!") hello world! -If you need functionality similar to ``unittest.TestCase.assertLogs``, or you want to capture all logs for some other reason, you can use the ``structlog.testing.capture_logs`` context manager: +If you need functionality similar to :meth:`unittest.TestCase.assertLogs`, or you want to capture all logs for some other reason, you can use the :func:`structlog.testing.capture_logs` context manager: .. doctest:: diff --git a/src/structlog/testing.py b/src/structlog/testing.py index ad9e069b..4284aa71 100644 --- a/src/structlog/testing.py +++ b/src/structlog/testing.py @@ -3,9 +3,7 @@ # repository for complete details. """ -Thin module holding capture_logs. -Ended up here since there were circular references -in other likely places (``dev`` module for example). +Testing helpers. """ from contextlib import contextmanager @@ -14,6 +12,9 @@ from .exceptions import DropEvent +__all__ = ["LogCapture", "capture_logs"] + + class LogCapture(object): """ Class for capturing log messages in its entries list. @@ -54,6 +55,9 @@ def capture_logs(): Context manager that appends all logging statements to its yielded list while it is active. + + Attention: this is **not** thread-safe! + .. versionadded:: 20.1.0 """ cap = LogCapture() @@ -63,6 +67,3 @@ def capture_logs(): yield cap.entries finally: configure(processors=old_processors) - - -__all__ = ["LogCapture", "capture_logs"] diff --git a/tests/test_capture.py b/tests/test_testing.py similarity index 57% rename from tests/test_capture.py rename to tests/test_testing.py index 1437b57d..1cc02107 100644 --- a/tests/test_capture.py +++ b/tests/test_testing.py @@ -8,35 +8,54 @@ import pytest -from structlog import _config, testing +from structlog import get_config, get_logger, reset_defaults, testing class TestCaptureLogs(object): @classmethod def teardown_class(cls): - _config.reset_defaults() + reset_defaults() def test_captures_logs(self): + """ + Log entries are captured and retain their structure. + """ with testing.capture_logs() as logs: - _config.get_logger().bind(x="y").info("hello") - _config.get_logger().bind(a="b").info("goodbye") + get_logger().bind(x="y").info("hello", answer=42) + get_logger().bind(a="b").info("goodbye", foo={"bar": "baz"}) assert [ - {"event": "hello", "log_level": "info", "x": "y"}, - {"a": "b", "event": "goodbye", "log_level": "info"}, + {"event": "hello", "log_level": "info", "x": "y", "answer": 42}, + { + "a": "b", + "event": "goodbye", + "log_level": "info", + "foo": {"bar": "baz"}, + }, ] == logs def get_active_procs(self): - return _config.get_config()["processors"] + return get_config()["processors"] def test_restores_processors_on_success(self): + """ + Processors are patched within the contextmanger and restored on + exit. + """ orig_procs = self.get_active_procs() + with testing.capture_logs(): assert orig_procs is not self.get_active_procs() + assert orig_procs is self.get_active_procs() def test_restores_processors_on_error(self): + """ + Processors are restored even on errors. + """ orig_procs = self.get_active_procs() + with pytest.raises(NotImplementedError): with testing.capture_logs(): raise NotImplementedError("from test") + assert orig_procs is self.get_active_procs() From f50641be07e7aa155383cac52332fb7bf3540a59 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 6 Jan 2020 16:45:39 +0100 Subject: [PATCH 0321/1520] Get rid of .coveragerc --- .coveragerc | 12 ------------ MANIFEST.in | 2 +- azure-pipelines.yml | 2 +- pyproject.toml | 12 ++++++++++++ setup.py | 2 +- tox.ini | 2 +- 6 files changed, 16 insertions(+), 16 deletions(-) delete mode 100644 .coveragerc diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 3c342ab0..00000000 --- a/.coveragerc +++ /dev/null @@ -1,12 +0,0 @@ -[run] -branch = True -source = structlog - -[paths] -source = - src/structlog - .tox/*/lib/python*/site-packages/structlog - .tox/pypy*/site-packages/structlog - -[report] -show_missing = True diff --git a/MANIFEST.in b/MANIFEST.in index 9b447873..b96b424d 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,4 @@ -include LICENSE LICENSE.apache2 LICENSE.mit .coveragerc conftest.py +include LICENSE LICENSE.apache2 LICENSE.mit conftest.py include *.rst include *.ini *.yml *.yaml *.toml diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 4b88c7d9..f17dd14e 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -118,7 +118,7 @@ jobs: $PY get-pip.py --user fi - $PY -m pip install --user coverage codecov + $PY -m pip install --user 'coverage[toml]' codecov coverage combine codecov diff --git a/pyproject.toml b/pyproject.toml index 7fd69784..abfe6401 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,6 +3,18 @@ requires = ["setuptools>=40.6.0", "wheel"] build-backend = "setuptools.build_meta" +[tool.coverage.run] +parallel = true +branch = true +source = ["structlog"] + +[tool.coverage.paths] +source = ["src", ".tox/*/site-packages"] + +[tool.coverage.report] +show_missing = true + + [tool.black] line-length = 79 diff --git a/setup.py b/setup.py index ebaa08ca..89935059 100644 --- a/setup.py +++ b/setup.py @@ -35,7 +35,7 @@ INSTALL_REQUIRES = ["six"] EXTRAS_REQUIRE = { "tests": [ - "coverage", + "coverage[toml]", "freezegun>=0.2.8", "pretend", "pytest>=3.3.0", diff --git a/tox.ini b/tox.ini index f3d5e15f..a7645a27 100644 --- a/tox.ini +++ b/tox.ini @@ -94,7 +94,7 @@ commands = check-manifest [testenv:coverage-report] basepython = python3.7 -deps = coverage +deps = coverage[toml] skip_install = true commands = coverage combine From 748fb3243676bd4bfeda02080d1aa3f778e66854 Mon Sep 17 00:00:00 2001 From: Markus Holtermann Date: Tue, 7 Jan 2020 11:11:25 +0100 Subject: [PATCH 0322/1520] Fix #201 - Add support for contextvars (#236) * Fix #201 - Add support for contextvars * fixup! Fix #201 - Add support for contextvars Co-authored-by: Hynek Schlawack --- conftest.py | 7 ++ docs/contextvars.rst | 70 ++++++++++++++++++ docs/index.rst | 1 + setup.py | 1 + src/structlog/contextvars.py | 68 ++++++++++++++++++ tests/test_contextvars.py | 135 +++++++++++++++++++++++++++++++++++ tox.ini | 4 +- 7 files changed, 284 insertions(+), 2 deletions(-) create mode 100644 docs/contextvars.rst create mode 100644 src/structlog/contextvars.py create mode 100644 tests/test_contextvars.py diff --git a/conftest.py b/conftest.py index 082b3443..2a9b20cd 100644 --- a/conftest.py +++ b/conftest.py @@ -6,6 +6,8 @@ from __future__ import absolute_import, division, print_function +import sys + import pytest from six.moves import cStringIO as StringIO @@ -30,3 +32,8 @@ def __repr__(self): return r"" return {"a": A(), "b": [3, 4], "x": 7, "y": "test", "z": (1, 2)} + + +collect_ignore = [] +if sys.version_info[:2] < (3, 7): + collect_ignore.extend(["tests/test_contextvars.py"]) diff --git a/docs/contextvars.rst b/docs/contextvars.rst new file mode 100644 index 00000000..230023d2 --- /dev/null +++ b/docs/contextvars.rst @@ -0,0 +1,70 @@ +.. _contextvars: + +contextvars +=========== + +.. testsetup:: * + + import structlog + +.. testcleanup:: * + + import structlog + structlog.reset_defaults() + +Historically, ``structlog`` only supported thread-local context binding. +With the introduction of ``contextvars`` in Python 3.7, there is now a way of having a global context that is local to the current context and even works in concurrent code. + +The ``merge_context_local`` Processor +------------------------------------- + +``structlog`` provides a set of functions to bind variables to a context-local context. +This context is safe to be used in asynchronous code. +The functions are: + +- :func:`structlog.contextvars.merge_context_local`, +- :func:`structlog.contextvars.clear_context_local`, +- :func:`structlog.contextvars.bind_context_local`, +- :func:`structlog.contextvars.unbind_context_local`, + +The general flow of using these functions is: + +- Use :func:`structlog.configure` with :func:`structlog.contextvars.merge_context_local` as your first processor. +- Call :func:`structlog.contextvars.clear_context_local` at the beginning of your request handler (or whenever you want to reset the context-local context). +- Call :func:`structlog.contextvars.bind_context_local` and :func:`structlog.contextvars.unbind_context_local` instead of :func:`structlog.BoundLogger.bind` and :func:`structlog.BoundLogger.unbind` when you want to (un)bind a particular variable to the context-local context. +- Use ``structlog`` as normal. + Loggers act as the always do, but the :func:`structlog.contextvars.merge_context_local` processor ensures that any context-local binds get included in all of your log messages. + +.. doctest:: + + >>> from structlog.contextvars import ( + ... bind_context_local, + ... clear_context_local, + ... merge_context_local, + ... unbind_context_local, + ... ) + >>> from structlog import configure + >>> configure( + ... processors=[ + ... merge_context_local, + ... structlog.processors.KeyValueRenderer(), + ... ] + ... ) + >>> log = structlog.get_logger() + >>> # At the top of your request handler (or, ideally, some general + >>> # middleware), clear the threadlocal context and bind some common + >>> # values: + >>> clear_context_local() + >>> bind_context_local(a=1, b=2) + >>> # Then use loggers as per normal + >>> # (perhaps by using structlog.get_logger() to create them). + >>> log.msg("hello") + a=1 b=2 event='hello' + >>> # Use unbind_context_local to remove a variable from the context + >>> unbind_context_local("b") + >>> log.msg("world") + a=1 event='world' + >>> # And when we clear the threadlocal state again, it goes away. + >>> clear_context_local() + >>> log.msg("hi there") + event='hi there' diff --git a/docs/index.rst b/docs/index.rst index 22a51dd1..eef96f43 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -31,6 +31,7 @@ Basics loggers configuration thread-local + contextvars processors examples development diff --git a/setup.py b/setup.py index 89935059..2cbffc38 100644 --- a/setup.py +++ b/setup.py @@ -39,6 +39,7 @@ "freezegun>=0.2.8", "pretend", "pytest>=3.3.0", + "pytest-asyncio; python_version>='3.7'", "python-rapidjson; python_version>='3.6'", "simplejson", ], diff --git a/src/structlog/contextvars.py b/src/structlog/contextvars.py new file mode 100644 index 00000000..5706e65a --- /dev/null +++ b/src/structlog/contextvars.py @@ -0,0 +1,68 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the MIT License. See the LICENSE file in the root of this +# repository for complete details. + +""" +Primitives to deal with a concurrency supporting context, as introduced in +Python 3.7 as ``contextvars``. +""" + +from __future__ import absolute_import, division, print_function + +import contextvars + + +_CONTEXT = contextvars.ContextVar("structlog_context") + + +def merge_context_local(logger, method_name, event_dict): + """ + A processor that merges in a global (context-local) context. + + Use this as your first processor in :func:`structlog.configure` to ensure + context-local context is included in all log calls. + """ + ctx = _get_context().copy() + ctx.update(event_dict) + return ctx + + +def clear_context_local(): + """ + Clear the context-local context. + + The typical use-case for this function is to invoke it early in request- + handling code. + """ + ctx = _get_context() + ctx.clear() + + +def bind_context_local(**kwargs): + """ + Put keys and values into the context-local context. + + Use this instead of :func:`~structlog.BoundLogger.bind` when you want some + context to be global (context-local). + """ + _get_context().update(kwargs) + + +def unbind_context_local(*args): + """ + Remove keys from the context-local context. + + Use this instead of :func:`~structlog.BoundLogger.unbind` when you want to + remove keys from a global (context-local) context. + """ + ctx = _get_context() + for key in args: + ctx.pop(key, None) + + +def _get_context(): + try: + return _CONTEXT.get() + except LookupError: + _CONTEXT.set({}) + return _CONTEXT.get() diff --git a/tests/test_contextvars.py b/tests/test_contextvars.py new file mode 100644 index 00000000..d5644331 --- /dev/null +++ b/tests/test_contextvars.py @@ -0,0 +1,135 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the MIT License. See the LICENSE file in the root of this +# repository for complete details. + +import pytest + +from structlog.contextvars import ( + bind_context_local, + clear_context_local, + merge_context_local, + unbind_context_local, +) + + +# All test coroutines will be treated as marked. +pytestmark = pytest.mark.asyncio + + +class TestNewContextvars(object): + async def test_bind(self, event_loop): + """ + Binding a variable causes it to be included in the result of + merge_context_local. + """ + + async def coro(): + bind_context_local(a=1) + return merge_context_local(None, None, {"b": 2}) + + assert {"a": 1, "b": 2} == await event_loop.create_task(coro()) + + async def test_multiple_binds(self, event_loop): + """ + Multiple calls to bind_context_local accumulate values instead of + replacing them. But they override redefined ones. + """ + + async def coro(): + bind_context_local(a=1, c=3) + bind_context_local(c=333, d=4) + return merge_context_local(None, None, {"b": 2}) + + assert { + "a": 1, + "b": 2, + "c": 333, + "d": 4, + } == await event_loop.create_task(coro()) + + async def test_nested_async_bind(self, event_loop): + """ + Context is passed correctly between "nested" concurrent operations. + """ + + async def coro(): + bind_context_local(a=1) + await event_loop.create_task(nested_coro()) + return merge_context_local(None, None, {"b": 2}) + + async def nested_coro(): + bind_context_local(c=3) + + assert {"a": 1, "b": 2, "c": 3} == await event_loop.create_task(coro()) + + async def test_merge_works_without_bind(self, event_loop): + """ + merge_context_local returns values as normal even when there has + been no previous calls to bind_context_local. + """ + + async def coro(): + return merge_context_local(None, None, {"b": 2}) + + assert {"b": 2} == await event_loop.create_task(coro()) + + async def test_merge_overrides_bind(self, event_loop): + """ + Variables included in merge_context_local override previously bound + variables. + """ + + async def coro(): + bind_context_local(a=1) + return merge_context_local(None, None, {"a": 111, "b": 2}) + + assert {"a": 111, "b": 2} == await event_loop.create_task(coro()) + + async def test_clear(self, event_loop): + """ + The context-local context can be cleared, causing any previously bound + variables to not be included in merge_context_local's result. + """ + + async def coro(): + bind_context_local(a=1) + clear_context_local() + return merge_context_local(None, None, {"b": 2}) + + assert {"b": 2} == await event_loop.create_task(coro()) + + async def test_clear_without_bind(self, event_loop): + """ + The context-local context can be cleared, causing any previously bound + variables to not be included in merge_context_local's result. + """ + + async def coro(): + clear_context_local() + return merge_context_local(None, None, {}) + + assert {} == await event_loop.create_task(coro()) + + async def test_undbind(self, event_loop): + """ + Unbinding a previously bound variable causes it to be removed from the + result of merge_context_local. + """ + + async def coro(): + bind_context_local(a=1) + unbind_context_local("a") + return merge_context_local(None, None, {"b": 2}) + + assert {"b": 2} == await event_loop.create_task(coro()) + + async def test_undbind_not_bound(self, event_loop): + """ + Unbinding a not bound variable causes doesn't raise an exception. + """ + + async def coro(): + unbind_context_local("a") + return merge_context_local(None, None, {"b": 2}) + + assert {"b": 2} == await event_loop.create_task(coro()) diff --git a/tox.ini b/tox.ini index a7645a27..4126254e 100644 --- a/tox.ini +++ b/tox.ini @@ -50,7 +50,7 @@ commands = coverage run --parallel -m pytest {posargs} deps = twisted setenv = PYTHONHASHSEED = 0 -commands = coverage run --parallel -m pytest {posargs} +commands = coverage run --parallel -m pytest --ignore=tests/test_contextvars.py {posargs} [testenv:py27-colorama] @@ -59,7 +59,7 @@ deps = twisted setenv = PYTHONHASHSEED = 0 -commands = coverage run --parallel -m pytest {posargs} +commands = coverage run --parallel -m pytest --ignore=tests/test_contextvars.py {posargs} [testenv:docs] From e3a6213afb2844572c8890693a83e142c41b1f0b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 7 Jan 2020 11:35:56 +0100 Subject: [PATCH 0323/1520] Add changelog for #236, do minor consistency adjustments The two `context` in merge_context_local_context may look weird but they refer to two different contexts... --- CHANGELOG.rst | 3 ++ conftest.py | 2 +- docs/api.rst | 11 ++++++ docs/contextvars.rst | 47 ++++++++++++------------- src/structlog/contextvars.py | 22 +++++++++--- src/structlog/threadlocal.py | 2 ++ tests/test_contextvars.py | 68 ++++++++++++++++++------------------ tox.ini | 4 +-- 8 files changed, 92 insertions(+), 67 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2b68e59a..72bf0f57 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,6 +24,9 @@ Deprecations: Changes: ^^^^^^^^ +- Added a new module ``structlog.contextvars`` that allows to have a global but context-local ``structlog`` context the same way as with ``structlog.threalocal`` since 19.2.0. + `#201 `_ + `#236 `_ - Added a new module ``structlog.testing`` for first class testing support. The first entry is the context manager ``capture_logs()`` that allows to make assertions about structured log calls. `#14 `_ diff --git a/conftest.py b/conftest.py index 2a9b20cd..944805cc 100644 --- a/conftest.py +++ b/conftest.py @@ -36,4 +36,4 @@ def __repr__(self): collect_ignore = [] if sys.version_info[:2] < (3, 7): - collect_ignore.extend(["tests/test_contextvars.py"]) + collect_ignore.append("tests/test_contextvars.py") diff --git a/docs/api.rst b/docs/api.rst index cd830697..5b76b74b 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -110,6 +110,17 @@ API Reference .. autofunction:: as_immutable +:mod:`contextvars` Module +------------------------- + +.. automodule:: structlog.contextvars + +.. autofunction:: merge_contextvars_context +.. autofunction:: clear_contextvars +.. autofunction:: bind_contextvars +.. autofunction:: unbind_contextvars + + .. _procs: :mod:`processors` Module diff --git a/docs/contextvars.rst b/docs/contextvars.rst index 230023d2..a23edb65 100644 --- a/docs/contextvars.rst +++ b/docs/contextvars.rst @@ -1,7 +1,7 @@ .. _contextvars: -contextvars -=========== +Context Variables +================= .. testsetup:: * @@ -13,40 +13,37 @@ contextvars structlog.reset_defaults() Historically, ``structlog`` only supported thread-local context binding. -With the introduction of ``contextvars`` in Python 3.7, there is now a way of having a global context that is local to the current context and even works in concurrent code. +With the introduction of :mod:`contextvars` in Python 3.7, there is now a way of having a global context that is local to the current context and even works in concurrent code such as code using :mod:`asyncio`. -The ``merge_context_local`` Processor -------------------------------------- - -``structlog`` provides a set of functions to bind variables to a context-local context. +For that ``structlog`` provides a set of functions to bind variables to a context-local context. This context is safe to be used in asynchronous code. The functions are: -- :func:`structlog.contextvars.merge_context_local`, -- :func:`structlog.contextvars.clear_context_local`, -- :func:`structlog.contextvars.bind_context_local`, -- :func:`structlog.contextvars.unbind_context_local`, +- :func:`structlog.contextvars.merge_contextvars_context`, +- :func:`structlog.contextvars.clear_contextvars`, +- :func:`structlog.contextvars.bind_contextvars`, +- :func:`structlog.contextvars.unbind_contextvars`, The general flow of using these functions is: -- Use :func:`structlog.configure` with :func:`structlog.contextvars.merge_context_local` as your first processor. -- Call :func:`structlog.contextvars.clear_context_local` at the beginning of your request handler (or whenever you want to reset the context-local context). -- Call :func:`structlog.contextvars.bind_context_local` and :func:`structlog.contextvars.unbind_context_local` instead of :func:`structlog.BoundLogger.bind` and :func:`structlog.BoundLogger.unbind` when you want to (un)bind a particular variable to the context-local context. +- Use :func:`structlog.configure` with :func:`structlog.contextvars.merge_contextvars_context` as your first processor. +- Call :func:`structlog.contextvars.clear_contextvars` at the beginning of your request handler (or whenever you want to reset the context-local context). +- Call :func:`structlog.contextvars.bind_contextvars` and :func:`structlog.contextvars.unbind_contextvars` instead of :func:`structlog.BoundLogger.bind` and :func:`structlog.BoundLogger.unbind` when you want to (un)bind a particular variable to the context-local context. - Use ``structlog`` as normal. - Loggers act as the always do, but the :func:`structlog.contextvars.merge_context_local` processor ensures that any context-local binds get included in all of your log messages. + Loggers act as the always do, but the :func:`structlog.contextvars.merge_contextvars_context` processor ensures that any context-local binds get included in all of your log messages. .. doctest:: >>> from structlog.contextvars import ( - ... bind_context_local, - ... clear_context_local, - ... merge_context_local, - ... unbind_context_local, + ... bind_contextvars, + ... clear_contextvars, + ... merge_contextvars_context, + ... unbind_contextvars, ... ) >>> from structlog import configure >>> configure( ... processors=[ - ... merge_context_local, + ... merge_contextvars_context, ... structlog.processors.KeyValueRenderer(), ... ] ... ) @@ -54,17 +51,17 @@ The general flow of using these functions is: >>> # At the top of your request handler (or, ideally, some general >>> # middleware), clear the threadlocal context and bind some common >>> # values: - >>> clear_context_local() - >>> bind_context_local(a=1, b=2) + >>> clear_contextvars() + >>> bind_contextvars(a=1, b=2) >>> # Then use loggers as per normal >>> # (perhaps by using structlog.get_logger() to create them). >>> log.msg("hello") a=1 b=2 event='hello' - >>> # Use unbind_context_local to remove a variable from the context - >>> unbind_context_local("b") + >>> # Use unbind_contextvars to remove a variable from the context + >>> unbind_contextvars("b") >>> log.msg("world") a=1 event='world' >>> # And when we clear the threadlocal state again, it goes away. - >>> clear_context_local() + >>> clear_contextvars() >>> log.msg("hi there") event='hi there' diff --git a/src/structlog/contextvars.py b/src/structlog/contextvars.py index 5706e65a..c780f5b4 100644 --- a/src/structlog/contextvars.py +++ b/src/structlog/contextvars.py @@ -4,7 +4,11 @@ """ Primitives to deal with a concurrency supporting context, as introduced in -Python 3.7 as ``contextvars``. +Python 3.7 as :mod:`contextvars`. + +.. versionadded:: 20.1.0 + +See :doc:`contextvars`. """ from __future__ import absolute_import, division, print_function @@ -15,45 +19,53 @@ _CONTEXT = contextvars.ContextVar("structlog_context") -def merge_context_local(logger, method_name, event_dict): +def merge_contextvars_context(logger, method_name, event_dict): """ A processor that merges in a global (context-local) context. Use this as your first processor in :func:`structlog.configure` to ensure context-local context is included in all log calls. + + .. versionadded:: 20.1.0 """ ctx = _get_context().copy() ctx.update(event_dict) return ctx -def clear_context_local(): +def clear_contextvars(): """ Clear the context-local context. The typical use-case for this function is to invoke it early in request- handling code. + + .. versionadded:: 20.1.0 """ ctx = _get_context() ctx.clear() -def bind_context_local(**kwargs): +def bind_contextvars(**kwargs): """ Put keys and values into the context-local context. Use this instead of :func:`~structlog.BoundLogger.bind` when you want some context to be global (context-local). + + .. versionadded:: 20.1.0 """ _get_context().update(kwargs) -def unbind_context_local(*args): +def unbind_contextvars(*args): """ Remove keys from the context-local context. Use this instead of :func:`~structlog.BoundLogger.unbind` when you want to remove keys from a global (context-local) context. + + .. versionadded:: 20.1.0 """ ctx = _get_context() for key in args: diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index edbd6cfb..ac7d0ad8 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -4,6 +4,8 @@ """ Primitives to keep context global but thread (and greenlet) local. + +See :doc:`thread-local`. """ from __future__ import absolute_import, division, print_function diff --git a/tests/test_contextvars.py b/tests/test_contextvars.py index d5644331..12572302 100644 --- a/tests/test_contextvars.py +++ b/tests/test_contextvars.py @@ -5,10 +5,10 @@ import pytest from structlog.contextvars import ( - bind_context_local, - clear_context_local, - merge_context_local, - unbind_context_local, + bind_contextvars, + clear_contextvars, + merge_contextvars_context, + unbind_contextvars, ) @@ -20,25 +20,25 @@ class TestNewContextvars(object): async def test_bind(self, event_loop): """ Binding a variable causes it to be included in the result of - merge_context_local. + merge_contextvars_context. """ async def coro(): - bind_context_local(a=1) - return merge_context_local(None, None, {"b": 2}) + bind_contextvars(a=1) + return merge_contextvars_context(None, None, {"b": 2}) assert {"a": 1, "b": 2} == await event_loop.create_task(coro()) async def test_multiple_binds(self, event_loop): """ - Multiple calls to bind_context_local accumulate values instead of + Multiple calls to bind_contextvars accumulate values instead of replacing them. But they override redefined ones. """ async def coro(): - bind_context_local(a=1, c=3) - bind_context_local(c=333, d=4) - return merge_context_local(None, None, {"b": 2}) + bind_contextvars(a=1, c=3) + bind_contextvars(c=333, d=4) + return merge_contextvars_context(None, None, {"b": 2}) assert { "a": 1, @@ -53,73 +53,73 @@ async def test_nested_async_bind(self, event_loop): """ async def coro(): - bind_context_local(a=1) + bind_contextvars(a=1) await event_loop.create_task(nested_coro()) - return merge_context_local(None, None, {"b": 2}) + return merge_contextvars_context(None, None, {"b": 2}) async def nested_coro(): - bind_context_local(c=3) + bind_contextvars(c=3) assert {"a": 1, "b": 2, "c": 3} == await event_loop.create_task(coro()) async def test_merge_works_without_bind(self, event_loop): """ - merge_context_local returns values as normal even when there has - been no previous calls to bind_context_local. + merge_contextvars_context returns values as normal even when there has + been no previous calls to bind_contextvars. """ async def coro(): - return merge_context_local(None, None, {"b": 2}) + return merge_contextvars_context(None, None, {"b": 2}) assert {"b": 2} == await event_loop.create_task(coro()) async def test_merge_overrides_bind(self, event_loop): """ - Variables included in merge_context_local override previously bound - variables. + Variables included in merge_contextvars_context override previously + bound variables. """ async def coro(): - bind_context_local(a=1) - return merge_context_local(None, None, {"a": 111, "b": 2}) + bind_contextvars(a=1) + return merge_contextvars_context(None, None, {"a": 111, "b": 2}) assert {"a": 111, "b": 2} == await event_loop.create_task(coro()) async def test_clear(self, event_loop): """ The context-local context can be cleared, causing any previously bound - variables to not be included in merge_context_local's result. + variables to not be included in merge_contextvars_context's result. """ async def coro(): - bind_context_local(a=1) - clear_context_local() - return merge_context_local(None, None, {"b": 2}) + bind_contextvars(a=1) + clear_contextvars() + return merge_contextvars_context(None, None, {"b": 2}) assert {"b": 2} == await event_loop.create_task(coro()) async def test_clear_without_bind(self, event_loop): """ The context-local context can be cleared, causing any previously bound - variables to not be included in merge_context_local's result. + variables to not be included in merge_contextvars_context's result. """ async def coro(): - clear_context_local() - return merge_context_local(None, None, {}) + clear_contextvars() + return merge_contextvars_context(None, None, {}) assert {} == await event_loop.create_task(coro()) async def test_undbind(self, event_loop): """ Unbinding a previously bound variable causes it to be removed from the - result of merge_context_local. + result of merge_contextvars_context. """ async def coro(): - bind_context_local(a=1) - unbind_context_local("a") - return merge_context_local(None, None, {"b": 2}) + bind_contextvars(a=1) + unbind_contextvars("a") + return merge_contextvars_context(None, None, {"b": 2}) assert {"b": 2} == await event_loop.create_task(coro()) @@ -129,7 +129,7 @@ async def test_undbind_not_bound(self, event_loop): """ async def coro(): - unbind_context_local("a") - return merge_context_local(None, None, {"b": 2}) + unbind_contextvars("a") + return merge_contextvars_context(None, None, {"b": 2}) assert {"b": 2} == await event_loop.create_task(coro()) diff --git a/tox.ini b/tox.ini index 4126254e..a7645a27 100644 --- a/tox.ini +++ b/tox.ini @@ -50,7 +50,7 @@ commands = coverage run --parallel -m pytest {posargs} deps = twisted setenv = PYTHONHASHSEED = 0 -commands = coverage run --parallel -m pytest --ignore=tests/test_contextvars.py {posargs} +commands = coverage run --parallel -m pytest {posargs} [testenv:py27-colorama] @@ -59,7 +59,7 @@ deps = twisted setenv = PYTHONHASHSEED = 0 -commands = coverage run --parallel -m pytest --ignore=tests/test_contextvars.py {posargs} +commands = coverage run --parallel -m pytest {posargs} [testenv:docs] From f9d14b9e900c6c004fcf0830c500b7f96c4df14b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 8 Jan 2020 09:21:16 +0100 Subject: [PATCH 0324/1520] Move ReturnLogger to testing It's still available from `structlog.__init__`. --- conftest.py | 10 ++++++++ docs/api.rst | 9 +++---- src/structlog/__init__.py | 10 +++----- src/structlog/_loggers.py | 48 ----------------------------------- src/structlog/testing.py | 48 +++++++++++++++++++++++++++++++++++ tests/test_base.py | 2 +- tests/test_generic.py | 2 +- tests/test_loggers.py | 53 +++------------------------------------ tests/test_testing.py | 43 +++++++++++++++++++++++++++++++ tests/test_threadlocal.py | 2 +- tests/utils.py | 4 +++ 11 files changed, 118 insertions(+), 113 deletions(-) diff --git a/conftest.py b/conftest.py index 944805cc..c32e1eb8 100644 --- a/conftest.py +++ b/conftest.py @@ -12,6 +12,8 @@ from six.moves import cStringIO as StringIO +from structlog.stdlib import _NAME_TO_LEVEL + @pytest.fixture def sio(): @@ -34,6 +36,14 @@ def __repr__(self): return {"a": A(), "b": [3, 4], "x": 7, "y": "test", "z": (1, 2)} +@pytest.fixture( + name="stdlib_log_method", + params=[m for m in _NAME_TO_LEVEL if m != "notset"], +) +def fixture_stdlib_log_methods(request): + return request.param + + collect_ignore = [] if sys.version_info[:2] < (3, 7): collect_ignore.append("tests/test_contextvars.py") diff --git a/docs/api.rst b/docs/api.rst index 5b76b74b..bf356816 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -50,11 +50,6 @@ API Reference .. autoclass:: PrintLoggerFactory -.. autoclass:: ReturnLogger - :members: msg, err, debug, info, warning, error, critical, log, failure, fatal - -.. autoclass:: ReturnLoggerFactory - .. autoexception:: DropEvent .. autoclass:: BoundLoggerBase @@ -79,6 +74,10 @@ API Reference .. autofunction:: capture_logs .. autoclass:: LogCapture +.. autoclass:: ReturnLogger + :members: msg, err, debug, info, warning, error, critical, log, failure, fatal + +.. autoclass:: ReturnLoggerFactory :mod:`threadlocal` Module diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index f7ee3a0c..4f52ae01 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -21,13 +21,9 @@ wrap_logger, ) from structlog._generic import BoundLogger -from structlog._loggers import ( - PrintLogger, - PrintLoggerFactory, - ReturnLogger, - ReturnLoggerFactory, -) +from structlog._loggers import PrintLogger, PrintLoggerFactory from structlog.exceptions import DropEvent +from structlog.testing import ReturnLogger, ReturnLoggerFactory try: @@ -46,7 +42,7 @@ __email__ = "hs@ox.cx" __license__ = "MIT or Apache License, Version 2.0" -__copyright__ = "Copyright (c) 2013 {0}".format(__author__) +__copyright__ = "Copyright (c) 2013 " + __author__ __all__ = [ diff --git a/src/structlog/_loggers.py b/src/structlog/_loggers.py index a748bfb7..64a0c58d 100644 --- a/src/structlog/_loggers.py +++ b/src/structlog/_loggers.py @@ -114,51 +114,3 @@ def msg(self, message): log = debug = info = warn = warning = msg fatal = failure = err = error = critical = exception = msg - - -class ReturnLoggerFactory(object): - r""" - Produce and cache :class:`ReturnLogger`\ s. - - To be used with :func:`structlog.configure`\ 's `logger_factory`. - - Positional arguments are silently ignored. - - .. versionadded:: 0.4.0 - """ - - def __init__(self): - self._logger = ReturnLogger() - - def __call__(self, *args): - return self._logger - - -class ReturnLogger(object): - """ - Return the arguments that it's called with. - - >>> from structlog import ReturnLogger - >>> ReturnLogger().msg("hello") - 'hello' - >>> ReturnLogger().msg("hello", when="again") - (('hello',), {'when': 'again'}) - - Useful for testing. - - .. versionchanged:: 0.3.0 - Allow for arbitrary arguments and keyword arguments to be passed in. - """ - - def msg(self, *args, **kw): - """ - Return tuple of ``args, kw`` or just ``args[0]`` if only one arg passed - """ - # Slightly convoluted for backwards compatibility. - if len(args) == 1 and not kw: - return args[0] - else: - return args, kw - - log = debug = info = warn = warning = msg - fatal = failure = err = error = critical = exception = msg diff --git a/src/structlog/testing.py b/src/structlog/testing.py index 4284aa71..6ec67154 100644 --- a/src/structlog/testing.py +++ b/src/structlog/testing.py @@ -67,3 +67,51 @@ def capture_logs(): yield cap.entries finally: configure(processors=old_processors) + + +class ReturnLoggerFactory(object): + r""" + Produce and cache :class:`ReturnLogger`\ s. + + To be used with :func:`structlog.configure`\ 's `logger_factory`. + + Positional arguments are silently ignored. + + .. versionadded:: 0.4.0 + """ + + def __init__(self): + self._logger = ReturnLogger() + + def __call__(self, *args): + return self._logger + + +class ReturnLogger(object): + """ + Return the arguments that it's called with. + + >>> from structlog import ReturnLogger + >>> ReturnLogger().msg("hello") + 'hello' + >>> ReturnLogger().msg("hello", when="again") + (('hello',), {'when': 'again'}) + + Useful for testing. + + .. versionchanged:: 0.3.0 + Allow for arbitrary arguments and keyword arguments to be passed in. + """ + + def msg(self, *args, **kw): + """ + Return tuple of ``args, kw`` or just ``args[0]`` if only one arg passed + """ + # Slightly convoluted for backwards compatibility. + if len(args) == 1 and not kw: + return args[0] + else: + return args, kw + + log = debug = info = warn = warning = msg + fatal = failure = err = error = critical = exception = msg diff --git a/tests/test_base.py b/tests/test_base.py index 28ffcfa9..c9040f27 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -10,9 +10,9 @@ from structlog._base import BoundLoggerBase from structlog._config import _CONFIG -from structlog._loggers import ReturnLogger from structlog.exceptions import DropEvent from structlog.processors import KeyValueRenderer +from structlog.testing import ReturnLogger def build_bl(logger=None, processors=None, context=None): diff --git a/tests/test_generic.py b/tests/test_generic.py index d1568139..4711c505 100644 --- a/tests/test_generic.py +++ b/tests/test_generic.py @@ -11,7 +11,7 @@ from structlog._config import _CONFIG from structlog._generic import BoundLogger -from structlog._loggers import ReturnLogger +from structlog.testing import ReturnLogger class TestLogger(object): diff --git a/tests/test_loggers.py b/tests/test_loggers.py index 272a9e42..40ab8f12 100644 --- a/tests/test_loggers.py +++ b/tests/test_loggers.py @@ -11,22 +11,9 @@ from six.moves import cStringIO as StringIO -from structlog._loggers import ( - WRITE_LOCKS, - PrintLogger, - PrintLoggerFactory, - ReturnLogger, - ReturnLoggerFactory, -) -from structlog.stdlib import _NAME_TO_LEVEL +from structlog._loggers import WRITE_LOCKS, PrintLogger, PrintLoggerFactory - -def test_return_logger(): - obj = ["hello"] - assert obj is ReturnLogger().msg(obj) - - -STDLIB_MSG_METHODS = [m for m in _NAME_TO_LEVEL if m != "notset"] +from .utils import stdlib_log_methods class TestPrintLogger(object): @@ -72,7 +59,7 @@ def test_lock(self): assert sio in WRITE_LOCKS - @pytest.mark.parametrize("method", STDLIB_MSG_METHODS) + @pytest.mark.parametrize("method", stdlib_log_methods) def test_stdlib_methods_support(self, method): """ PrintLogger implements methods of stdlib loggers. @@ -135,37 +122,3 @@ def test_ignores_args(self): the factory, they are not passed to the logger. """ PrintLoggerFactory()(1, 2, 3) - - -class ReturnLoggerTest(object): - @pytest.mark.parametrize("method", STDLIB_MSG_METHODS) - def test_stdlib_methods_support(self, method): - """ - ReturnLogger implements methods of stdlib loggers. - """ - v = getattr(ReturnLogger(), method)("hello") - - assert "hello" == v - - -class TestReturnLoggerFactory(object): - def test_builds_returnloggers(self): - f = ReturnLoggerFactory() - - assert isinstance(f(), ReturnLogger) - - def test_caches(self): - """ - There's no need to have several loggers so we return the same one on - each call. - """ - f = ReturnLoggerFactory() - - assert f() is f() - - def test_ignores_args(self): - """ - ReturnLogger doesn't take positional arguments. If any are passed to - the factory, they are not passed to the logger. - """ - ReturnLoggerFactory()(1, 2, 3) diff --git a/tests/test_testing.py b/tests/test_testing.py index 1cc02107..77d59117 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -9,6 +9,7 @@ import pytest from structlog import get_config, get_logger, reset_defaults, testing +from structlog.testing import ReturnLogger, ReturnLoggerFactory class TestCaptureLogs(object): @@ -59,3 +60,45 @@ def test_restores_processors_on_error(self): raise NotImplementedError("from test") assert orig_procs is self.get_active_procs() + + +class TestReturnLogger(object): + # @pytest.mark.parametrize("method", stdlib_log_methods) + def test_stdlib_methods_support(self, stdlib_log_method): + """ + ReturnLogger implements methods of stdlib loggers. + """ + v = getattr(ReturnLogger(), stdlib_log_method)("hello") + + assert "hello" == v + + def test_return_logger(self): + """ + Return logger returns exactly what's sent in. + """ + obj = ["hello"] + + assert obj is ReturnLogger().msg(obj) + + +class TestReturnLoggerFactory(object): + def test_builds_returnloggers(self): + f = ReturnLoggerFactory() + + assert isinstance(f(), ReturnLogger) + + def test_caches(self): + """ + There's no need to have several loggers so we return the same one on + each call. + """ + f = ReturnLoggerFactory() + + assert f() is f() + + def test_ignores_args(self): + """ + ReturnLogger doesn't take positional arguments. If any are passed to + the factory, they are not passed to the logger. + """ + ReturnLoggerFactory()(1, 2, 3) diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py index 3ef16da6..6661ccb9 100644 --- a/tests/test_threadlocal.py +++ b/tests/test_threadlocal.py @@ -12,7 +12,7 @@ from structlog._base import BoundLoggerBase from structlog._config import wrap_logger -from structlog._loggers import ReturnLogger +from structlog.testing import ReturnLogger from structlog.threadlocal import ( as_immutable, bind_threadlocal, diff --git a/tests/utils.py b/tests/utils.py index 65bd3b3c..cd4732da 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -11,6 +11,10 @@ import pytest import six +from structlog.stdlib import _NAME_TO_LEVEL + py3_only = pytest.mark.skipif(not six.PY3, reason="Python 3-only") py2_only = pytest.mark.skipif(not six.PY2, reason="Python 2-only") + +stdlib_log_methods = [m for m in _NAME_TO_LEVEL if m != "notset"] From f0a2a7d68acafee1b5314960016a15a0375d2159 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 8 Jan 2020 21:27:02 +0100 Subject: [PATCH 0325/1520] Parallel is set in the config now --- tox.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tox.ini b/tox.ini index a7645a27..455b0148 100644 --- a/tox.ini +++ b/tox.ini @@ -34,7 +34,7 @@ commands = python -m pytest {posargs} deps = twisted setenv = PYTHONHASHSEED = 0 -commands = coverage run --parallel -m pytest {posargs} +commands = coverage run -m pytest {posargs} [testenv:py37-greenlets] @@ -43,14 +43,14 @@ deps = twisted setenv = PYTHONHASHSEED = 0 -commands = coverage run --parallel -m pytest {posargs} +commands = coverage run -m pytest {posargs} [testenv:py27-threads] deps = twisted setenv = PYTHONHASHSEED = 0 -commands = coverage run --parallel -m pytest {posargs} +commands = coverage run -m pytest {posargs} [testenv:py27-colorama] @@ -59,7 +59,7 @@ deps = twisted setenv = PYTHONHASHSEED = 0 -commands = coverage run --parallel -m pytest {posargs} +commands = coverage run -m pytest {posargs} [testenv:docs] From 062aa214475f031596289170ea29e96e4157bd28 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 9 Jan 2020 10:42:18 +0100 Subject: [PATCH 0326/1520] Nicer yaml --- .pre-commit-config.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fa2a927f..a3ff8744 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,3 +1,5 @@ +--- + repos: - repo: https://github.com/psf/black rev: 19.10b0 From 0e6a3c6b9b18e57a86137c5b093289f003e2cc6d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 18 Jan 2020 16:13:47 +0100 Subject: [PATCH 0327/1520] Deprecate Python 2.7 and 3.5 --- CHANGELOG.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 72bf0f57..fe05562e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -18,7 +18,8 @@ Backward-incompatible changes: Deprecations: ^^^^^^^^^^^^^ -*none* +- This is the last version to support Python 2.7 (including PyPy) and 3.5. + All following versions will only support Python 3.6 or later. Changes: From e71fc13d6fca58266a0ee3b2622cdb7e11200a75 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 18 Jan 2020 19:35:19 +0100 Subject: [PATCH 0328/1520] Harmonize names (#240) Fixes #238 --- CHANGELOG.rst | 2 +- docs/api.rst | 4 ++-- docs/contextvars.rst | 10 +++++----- docs/thread-local.rst | 14 +++++++------- src/structlog/_base.py | 8 +++----- src/structlog/contextvars.py | 8 ++++---- src/structlog/threadlocal.py | 16 +++++++++++++++- tests/test_contextvars.py | 32 ++++++++++++++++---------------- tests/test_threadlocal.py | 23 ++++++++++++++--------- 9 files changed, 67 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index fe05562e..3ab315fd 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -25,7 +25,7 @@ Deprecations: Changes: ^^^^^^^^ -- Added a new module ``structlog.contextvars`` that allows to have a global but context-local ``structlog`` context the same way as with ``structlog.threalocal`` since 19.2.0. +- Added a new module ``structlog.contextvars`` that allows to have a global but context-local ``structlog`` context the same way as with ``structlog.threadlocal`` since 19.2.0. `#201 `_ `#236 `_ - Added a new module ``structlog.testing`` for first class testing support. diff --git a/docs/api.rst b/docs/api.rst index bf356816..f1f5220d 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -85,7 +85,7 @@ API Reference .. automodule:: structlog.threadlocal -.. autofunction:: merge_threadlocal_context +.. autofunction:: merge_threadlocal .. autofunction:: clear_threadlocal @@ -114,7 +114,7 @@ API Reference .. automodule:: structlog.contextvars -.. autofunction:: merge_contextvars_context +.. autofunction:: merge_contextvars .. autofunction:: clear_contextvars .. autofunction:: bind_contextvars .. autofunction:: unbind_contextvars diff --git a/docs/contextvars.rst b/docs/contextvars.rst index a23edb65..6add8a53 100644 --- a/docs/contextvars.rst +++ b/docs/contextvars.rst @@ -19,31 +19,31 @@ For that ``structlog`` provides a set of functions to bind variables to a contex This context is safe to be used in asynchronous code. The functions are: -- :func:`structlog.contextvars.merge_contextvars_context`, +- :func:`structlog.contextvars.merge_contextvars`, - :func:`structlog.contextvars.clear_contextvars`, - :func:`structlog.contextvars.bind_contextvars`, - :func:`structlog.contextvars.unbind_contextvars`, The general flow of using these functions is: -- Use :func:`structlog.configure` with :func:`structlog.contextvars.merge_contextvars_context` as your first processor. +- Use :func:`structlog.configure` with :func:`structlog.contextvars.merge_contextvars` as your first processor. - Call :func:`structlog.contextvars.clear_contextvars` at the beginning of your request handler (or whenever you want to reset the context-local context). - Call :func:`structlog.contextvars.bind_contextvars` and :func:`structlog.contextvars.unbind_contextvars` instead of :func:`structlog.BoundLogger.bind` and :func:`structlog.BoundLogger.unbind` when you want to (un)bind a particular variable to the context-local context. - Use ``structlog`` as normal. - Loggers act as the always do, but the :func:`structlog.contextvars.merge_contextvars_context` processor ensures that any context-local binds get included in all of your log messages. + Loggers act as the always do, but the :func:`structlog.contextvars.merge_contextvars` processor ensures that any context-local binds get included in all of your log messages. .. doctest:: >>> from structlog.contextvars import ( ... bind_contextvars, ... clear_contextvars, - ... merge_contextvars_context, + ... merge_contextvars, ... unbind_contextvars, ... ) >>> from structlog import configure >>> configure( ... processors=[ - ... merge_contextvars_context, + ... merge_contextvars, ... structlog.processors.KeyValueRenderer(), ... ] ... ) diff --git a/docs/thread-local.rst b/docs/thread-local.rst index c0282d40..fd9f5819 100644 --- a/docs/thread-local.rst +++ b/docs/thread-local.rst @@ -33,31 +33,31 @@ However, in the case of conventional web development, we realize that passing lo And since it's more important that people actually *use* ``structlog`` than to be pure and snobby, ``structlog`` contains a couple of mechanisms to help here. -The ``merge_threadlocal_context`` Processor -------------------------------------------- +The ``merge_threadlocal`` Processor +----------------------------------- ``structlog`` provides a simple set of functions that allow explicitly binding certain fields to a global (thread-local) context. -These functions are :func:`structlog.threadlocal.merge_threadlocal_context`, :func:`structlog.threadlocal.clear_threadlocal`, and :func:`structlog.threadlocal.bind_threadlocal`. +These functions are :func:`structlog.threadlocal.merge_threadlocal`, :func:`structlog.threadlocal.clear_threadlocal`, and :func:`structlog.threadlocal.bind_threadlocal`. The general flow of using these functions is: -- Use :func:`structlog.configure` with :func:`structlog.threadlocal.merge_threadlocal_context` as your first processor. +- Use :func:`structlog.configure` with :func:`structlog.threadlocal.merge_threadlocal` as your first processor. - Call :func:`structlog.threadlocal.clear_threadlocal` at the beginning of your request handler (or whenever you want to reset the thread-local context). - Call :func:`structlog.threadlocal.bind_threadlocal` as an alternative to :func:`structlog.BoundLogger.bind` when you want to bind a particular variable to the thread-local context. - Use ``structlog`` as normal. - Loggers act as the always do, but the :func:`structlog.threadlocal.merge_threadlocal_context` processor ensures that any thread-local binds get included in all of your log messages. + Loggers act as the always do, but the :func:`structlog.threadlocal.merge_threadlocal` processor ensures that any thread-local binds get included in all of your log messages. .. doctest:: >>> from structlog.threadlocal import ( ... bind_threadlocal, ... clear_threadlocal, - ... merge_threadlocal_context, + ... merge_threadlocal, ... ) >>> from structlog import configure >>> configure( ... processors=[ - ... merge_threadlocal_context, + ... merge_threadlocal, ... structlog.processors.KeyValueRenderer(), ... ] ... ) diff --git a/src/structlog/_base.py b/src/structlog/_base.py index 3b5c4610..23acbc1f 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -86,7 +86,7 @@ def unbind(self, *keys): def try_unbind(self, *keys): """ - Like :meth:`unbind`, but best effort: missing keys are ignored. + Like :meth:`unbind`, but best effort: missing keys are ignored. :rtype: `self.__class__` @@ -94,10 +94,8 @@ def try_unbind(self, *keys): """ bl = self.bind() for key in keys: - try: - del bl._context[key] - except KeyError: - pass + bl._context.pop(key, None) + return bl def new(self, **new_values): diff --git a/src/structlog/contextvars.py b/src/structlog/contextvars.py index c780f5b4..4fc0bd6b 100644 --- a/src/structlog/contextvars.py +++ b/src/structlog/contextvars.py @@ -19,7 +19,7 @@ _CONTEXT = contextvars.ContextVar("structlog_context") -def merge_contextvars_context(logger, method_name, event_dict): +def merge_contextvars(logger, method_name, event_dict): """ A processor that merges in a global (context-local) context. @@ -58,9 +58,9 @@ def bind_contextvars(**kwargs): _get_context().update(kwargs) -def unbind_contextvars(*args): +def unbind_contextvars(*keys): """ - Remove keys from the context-local context. + Remove *keys* from the context-local context if they are present. Use this instead of :func:`~structlog.BoundLogger.unbind` when you want to remove keys from a global (context-local) context. @@ -68,7 +68,7 @@ def unbind_contextvars(*args): .. versionadded:: 20.1.0 """ ctx = _get_context() - for key in args: + for key in keys: ctx.pop(key, None) diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index ac7d0ad8..c5e4a589 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -170,24 +170,36 @@ def __getattr__(self, name): _CONTEXT = threading.local() -def merge_threadlocal_context(logger, method_name, event_dict): +def merge_threadlocal(logger, method_name, event_dict): """ A processor that merges in a global (thread-local) context. Use this as your first processor in :func:`structlog.configure` to ensure thread-local context is included in all log calls. + + .. versionadded:: 19.2.0 + + .. versionchanged:: 20.1.0 + This function used to be called ``merge_threalocal_context`` and that + name is still kept around for backward compatability. """ context = _get_context().copy() context.update(event_dict) return context +# Alias that shouldn't be used anymore. +merge_threadlocal_context = merge_threadlocal + + def clear_threadlocal(): """ Clear the thread-local context. The typical use-case for this function is to invoke it early in request-handling code. + + .. versionadded:: 19.2.0 """ _CONTEXT.context = {} @@ -198,6 +210,8 @@ def bind_threadlocal(**kwargs): Use this instead of :func:`~structlog.BoundLogger.bind` when you want some context to be global (thread-local). + + .. versionadded:: 19.2.0 """ _get_context().update(kwargs) diff --git a/tests/test_contextvars.py b/tests/test_contextvars.py index 12572302..c9cf1b0c 100644 --- a/tests/test_contextvars.py +++ b/tests/test_contextvars.py @@ -7,7 +7,7 @@ from structlog.contextvars import ( bind_contextvars, clear_contextvars, - merge_contextvars_context, + merge_contextvars, unbind_contextvars, ) @@ -20,12 +20,12 @@ class TestNewContextvars(object): async def test_bind(self, event_loop): """ Binding a variable causes it to be included in the result of - merge_contextvars_context. + merge_contextvars. """ async def coro(): bind_contextvars(a=1) - return merge_contextvars_context(None, None, {"b": 2}) + return merge_contextvars(None, None, {"b": 2}) assert {"a": 1, "b": 2} == await event_loop.create_task(coro()) @@ -38,7 +38,7 @@ async def test_multiple_binds(self, event_loop): async def coro(): bind_contextvars(a=1, c=3) bind_contextvars(c=333, d=4) - return merge_contextvars_context(None, None, {"b": 2}) + return merge_contextvars(None, None, {"b": 2}) assert { "a": 1, @@ -55,7 +55,7 @@ async def test_nested_async_bind(self, event_loop): async def coro(): bind_contextvars(a=1) await event_loop.create_task(nested_coro()) - return merge_contextvars_context(None, None, {"b": 2}) + return merge_contextvars(None, None, {"b": 2}) async def nested_coro(): bind_contextvars(c=3) @@ -64,62 +64,62 @@ async def nested_coro(): async def test_merge_works_without_bind(self, event_loop): """ - merge_contextvars_context returns values as normal even when there has + merge_contextvars returns values as normal even when there has been no previous calls to bind_contextvars. """ async def coro(): - return merge_contextvars_context(None, None, {"b": 2}) + return merge_contextvars(None, None, {"b": 2}) assert {"b": 2} == await event_loop.create_task(coro()) async def test_merge_overrides_bind(self, event_loop): """ - Variables included in merge_contextvars_context override previously + Variables included in merge_contextvars override previously bound variables. """ async def coro(): bind_contextvars(a=1) - return merge_contextvars_context(None, None, {"a": 111, "b": 2}) + return merge_contextvars(None, None, {"a": 111, "b": 2}) assert {"a": 111, "b": 2} == await event_loop.create_task(coro()) async def test_clear(self, event_loop): """ The context-local context can be cleared, causing any previously bound - variables to not be included in merge_contextvars_context's result. + variables to not be included in merge_contextvars's result. """ async def coro(): bind_contextvars(a=1) clear_contextvars() - return merge_contextvars_context(None, None, {"b": 2}) + return merge_contextvars(None, None, {"b": 2}) assert {"b": 2} == await event_loop.create_task(coro()) async def test_clear_without_bind(self, event_loop): """ The context-local context can be cleared, causing any previously bound - variables to not be included in merge_contextvars_context's result. + variables to not be included in merge_contextvars's result. """ async def coro(): clear_contextvars() - return merge_contextvars_context(None, None, {}) + return merge_contextvars(None, None, {}) assert {} == await event_loop.create_task(coro()) async def test_undbind(self, event_loop): """ Unbinding a previously bound variable causes it to be removed from the - result of merge_contextvars_context. + result of merge_contextvars. """ async def coro(): bind_contextvars(a=1) unbind_contextvars("a") - return merge_contextvars_context(None, None, {"b": 2}) + return merge_contextvars(None, None, {"b": 2}) assert {"b": 2} == await event_loop.create_task(coro()) @@ -130,6 +130,6 @@ async def test_undbind_not_bound(self, event_loop): async def coro(): unbind_contextvars("a") - return merge_contextvars_context(None, None, {"b": 2}) + return merge_contextvars(None, None, {"b": 2}) assert {"b": 2} == await event_loop.create_task(coro()) diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py index 6661ccb9..c9867230 100644 --- a/tests/test_threadlocal.py +++ b/tests/test_threadlocal.py @@ -17,6 +17,7 @@ as_immutable, bind_threadlocal, clear_threadlocal, + merge_threadlocal, merge_threadlocal_context, tmp_bind, wrap_dict, @@ -272,33 +273,37 @@ def test_new_class(self, D): class TestNewThreadLocal(object): + def test_alias(self): + """ + We're keeping the old alias around. + """ + assert merge_threadlocal_context is merge_threadlocal + def test_bind_and_merge(self): """ Binding a variable causes it to be included in the result of - merge_threadlocal_context. + merge_threadlocal. """ bind_threadlocal(a=1) - assert {"a": 1, "b": 2} == merge_threadlocal_context( - None, None, {"b": 2} - ) + assert {"a": 1, "b": 2} == merge_threadlocal(None, None, {"b": 2}) def test_clear(self): """ The thread-local context can be cleared, causing any previously bound - variables to not be included in merge_threadlocal_context's result. + variables to not be included in merge_threadlocal's result. """ bind_threadlocal(a=1) clear_threadlocal() - assert {"b": 2} == merge_threadlocal_context(None, None, {"b": 2}) + assert {"b": 2} == merge_threadlocal(None, None, {"b": 2}) def test_merge_works_without_bind(self): """ - merge_threadlocal_context returns values as normal even when there has + merge_threadlocal returns values as normal even when there has been no previous calls to bind_threadlocal. """ - assert {"b": 2} == merge_threadlocal_context(None, None, {"b": 2}) + assert {"b": 2} == merge_threadlocal(None, None, {"b": 2}) def test_multiple_binds(self): """ @@ -308,6 +313,6 @@ def test_multiple_binds(self): bind_threadlocal(a=1, b=2) bind_threadlocal(c=3) - assert {"a": 1, "b": 2, "c": 3} == merge_threadlocal_context( + assert {"a": 1, "b": 2, "c": 3} == merge_threadlocal( None, None, {"b": 2} ) From 1988e517a037139290a182b421ea124c65f9eabd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 19 Jan 2020 08:13:26 +0100 Subject: [PATCH 0329/1520] Use web fonts in SVG --- docs/_static/BoundLogger.svg | 63 +----------------------------------- 1 file changed, 1 insertion(+), 62 deletions(-) diff --git a/docs/_static/BoundLogger.svg b/docs/_static/BoundLogger.svg index 7716b38d..1418058f 100644 --- a/docs/_static/BoundLogger.svg +++ b/docs/_static/BoundLogger.svg @@ -1,62 +1 @@ - - - - Produced by OmniGraffle 7.6.1 - 2018-01-27 14:28:12 +0000 - - - - - - - - - - - - - - - Canvas 1 - - - Layer 1 - - - - BoundLogger - - - - - { - "user": "Guido", - "ip": "8.8.8.8", - } - - - Context - - - - - - censor_ip() - - add_timestamp() - - format_to_json() - - - Pr - ocessors - - - - - logging.Logger - - - W - rapped Logger - - - - +BoundLogger{ "user": "Guido", "ip": "8.8.8.8", }Context- censor_ip() - add_timestamp() - format_to_json()Processorslogging.LoggerWrapped Logger From c7e93660888ca74db205a421b9120a476cd61610 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 19 Jan 2020 09:56:35 +0100 Subject: [PATCH 0330/1520] Stress where logging.Logger is coming from --- docs/loggers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/loggers.rst b/docs/loggers.rst index 7806ab30..c30a2620 100644 --- a/docs/loggers.rst +++ b/docs/loggers.rst @@ -14,7 +14,7 @@ What it does is: - Store a *context dictionary* with key-value pairs that should be part of every log entry, - store a list of :ref:`processors ` that are called on every log entry, - and store a *logger* that it's wrapping. - This *can* be :class:`logging.Logger` but absolutely doesn't have to. + This *can* be standard library's :class:`logging.Logger` but absolutely doesn't have to. To manipulate the context dictionary, it offers to: From da7f01e512d2434dc5bb4e27f227e831a7e6cd56 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 19 Jan 2020 10:56:14 +0100 Subject: [PATCH 0331/1520] Give testing a dedicated chapter --- docs/configuration.rst | 8 +++---- docs/index.rst | 1 + docs/loggers.rst | 38 +------------------------------- docs/testing.rst | 47 ++++++++++++++++++++++++++++++++++++++++ src/structlog/testing.py | 25 +++++---------------- 5 files changed, 58 insertions(+), 61 deletions(-) create mode 100644 docs/testing.rst diff --git a/docs/configuration.rst b/docs/configuration.rst index 9175d42f..f2e0bbc8 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -46,7 +46,7 @@ Thus the :ref:`example ` from the previous chapter could have been written I got called with {'event': 'hello world'} {'event': 'hello world'} -because :class:`~structlog.processors.PrintLogger` is the default ``LoggerFactory`` used (see :ref:`logger-factories`). +because :class:`~structlog.PrintLogger` is the default ``LoggerFactory`` (see :ref:`logger-factories`). Configuration also applies to :func:`~structlog.wrap_logger` because that's what's used internally: @@ -91,9 +91,9 @@ At any time, you can check whether and how ``structlog`` is configured: .. note:: Since you will call :func:`structlog.get_logger` most likely in module scope, they run at import time before you had a chance to configure ``structlog``. - Hence they return a **lazy proxy** that returns a correct wrapped logger on first ``bind()``/``new()``. + Therefore they return a **lazy proxy** that returns a correct wrapped logger on first ``bind()``/``new()``. - Therefore, you must never call ``new()`` or ``bind()`` in module or class scope because otherwise you will receive a logger configured with ``structlog``'s default values. + Thus, you must never call ``new()`` or ``bind()`` in module or class scope because otherwise you will receive a logger configured with ``structlog``'s default values. Use :func:`~structlog.get_logger`\ 's ``initial_values`` to achieve pre-populated contexts. To enable you to log with the module-global logger, it will create a temporary BoundLogger and relay the log calls to it on *each call*. @@ -141,7 +141,7 @@ The :ref:`Twisted example ` shows how easy it is for Twisted. .. note:: - `LoggerFactory()`-style factories always need to get passed as *instances* like in the examples above. + ``LoggerFactory``-style factories always need to get passed as *instances* like in the examples above. While neither allows for customization using parameters yet, they may do so in the future. Calling :func:`structlog.get_logger` without configuration gives you a perfectly useful :class:`structlog.PrintLogger`. diff --git a/docs/index.rst b/docs/index.rst index eef96f43..b13ee674 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -30,6 +30,7 @@ Basics getting-started loggers configuration + testing thread-local contextvars processors diff --git a/docs/loggers.rst b/docs/loggers.rst index c30a2620..680766eb 100644 --- a/docs/loggers.rst +++ b/docs/loggers.rst @@ -104,7 +104,7 @@ Additionally, the following arguments are allowed too: **initial_values** The values that new wrapped loggers are automatically constructed with. - Useful for example if you want to have the module name as part of the context. + Useful, for example, if you want to have the module name as part of the context. .. note:: @@ -113,39 +113,3 @@ Additionally, the following arguments are allowed too: What happens to it depends on the logger you wrap and your processors alone. This gives you the power to log directly to databases, log aggregation servers, web services, and whatnot. - - -Printing and Testing --------------------- - -To save you the hassle and slowdown of using standard library's ``logging`` for standard out logging, ``structlog`` ships a :class:`~structlog.PrintLogger` that can log into arbitrary files -- including standard out (which is the default if no file is passed into the constructor): - -.. doctest:: - - >>> from structlog import PrintLogger - >>> PrintLogger().info("hello world!") - hello world! - -If you need functionality similar to :meth:`unittest.TestCase.assertLogs`, or you want to capture all logs for some other reason, you can use the :func:`structlog.testing.capture_logs` context manager: - -.. doctest:: - - >>> from structlog import get_logger - >>> from structlog.testing import capture_logs - >>> with capture_logs() as logs: - ... get_logger().bind(x="y").info("hello") - >>> logs - [{'x': 'y', 'event': 'hello', 'log_level': 'info'}] - -Additionally -- mostly for unit testing within ``structlog`` itself -- ``structlog`` also ships with a logger that just returns whatever it gets passed into it: :class:`~structlog.ReturnLogger`. - -.. doctest:: - - >>> from structlog import ReturnLogger - >>> ReturnLogger().msg(42) == 42 - True - >>> obj = ["hi"] - >>> ReturnLogger().msg(obj) is obj - True - >>> ReturnLogger().msg("hello", when="again") - (('hello',), {'when': 'again'}) diff --git a/docs/testing.rst b/docs/testing.rst new file mode 100644 index 00000000..ec0d0c54 --- /dev/null +++ b/docs/testing.rst @@ -0,0 +1,47 @@ +Testing +------- + +``structlog`` comes with tools for testing the logging behavior of your application. + +If you need functionality similar to :meth:`unittest.TestCase.assertLogs`, or you want to capture all logs for some other reason, you can use the :func:`structlog.testing.capture_logs` context manager: + +.. doctest:: + + >>> from structlog import get_logger + >>> from structlog.testing import capture_logs + >>> with capture_logs() as cap_logs: + ... get_logger().bind(x="y").info("hello") + >>> cap_logs + [{'x': 'y', 'event': 'hello', 'log_level': 'info'}] + +You can build your own helpers using :class:`structlog.testing.LogCapture`. +For example a `pytest `_ fixture to capture log output could look like this:: + + @pytest.fixture(name="log_output") + def fixture_log_output(): + return LogCapture() + + @pytest.fixture(autouse=True) + def fixture_configure_structlog(log_output): + structlog.configure( + processors=[log_output] + ) + + def test_my_stuff(log_output): + do_something() + assert log_output.entries == [...] + +---- + +Additionally -- mostly for unit testing within ``structlog`` itself -- ``structlog`` also ships with a logger that just returns whatever it gets passed into it: :class:`~structlog.ReturnLogger`. + +.. doctest:: + + >>> from structlog import ReturnLogger + >>> ReturnLogger().msg(42) == 42 + True + >>> obj = ["hi"] + >>> ReturnLogger().msg(obj) is obj + True + >>> ReturnLogger().msg("hello", when="again") + (('hello',), {'when': 'again'}) diff --git a/src/structlog/testing.py b/src/structlog/testing.py index 6ec67154..fc9ea52a 100644 --- a/src/structlog/testing.py +++ b/src/structlog/testing.py @@ -3,7 +3,11 @@ # repository for complete details. """ -Testing helpers. +Helpers to test your application's logging behavior. + +.. versionadded:: 20.1.0 + +See :doc:`testing`. """ from contextlib import contextmanager @@ -20,22 +24,6 @@ class LogCapture(object): Class for capturing log messages in its entries list. Generally you should use :func:`structlog.testing.capture_logs`, but you can use this class if you want to capture logs with other patterns. - For example, using ``pytest`` fixtures:: - - @pytest.fixture(scope='function') - def log_output(): - return LogCapture() - - - @pytest.fixture(scope='function', autouse=True) - def configure_structlog(log_output): - structlog.configure( - processors=[log_output] - ) - - def test_my_stuff(log_output): - do_something() - assert log_output.entries == [...] .. versionadded:: 20.1.0 """ @@ -55,7 +43,6 @@ def capture_logs(): Context manager that appends all logging statements to its yielded list while it is active. - Attention: this is **not** thread-safe! .. versionadded:: 20.1.0 @@ -97,8 +84,6 @@ class ReturnLogger(object): >>> ReturnLogger().msg("hello", when="again") (('hello',), {'when': 'again'}) - Useful for testing. - .. versionchanged:: 0.3.0 Allow for arbitrary arguments and keyword arguments to be passed in. """ From 94df5bd24353582ab3b3954310fca574d94502a5 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 19 Jan 2020 13:41:45 +0100 Subject: [PATCH 0332/1520] Use default_role h/t @Julian --- docs/api.rst | 4 +-- docs/conf.py | 2 +- docs/configuration.rst | 20 +++++------ docs/contextvars.rst | 18 ++++------ docs/custom-wrappers.rst | 14 ++++---- docs/development.rst | 6 ++-- docs/examples.rst | 12 +++---- docs/getting-started.rst | 27 ++++++-------- docs/index.rst | 12 +++---- docs/license.rst | 2 +- docs/loggers.rst | 18 +++++----- docs/performance.rst | 4 +-- docs/processors.rst | 19 ++++------ docs/standard-library.rst | 70 ++++++++++++++++++------------------ docs/testing.rst | 6 ++-- docs/thread-local.rst | 45 ++++++++++------------- docs/twisted.rst | 18 +++++----- src/structlog/_base.py | 26 +++++++------- src/structlog/_config.py | 61 +++++++++++++++---------------- src/structlog/_loggers.py | 6 ++-- src/structlog/dev.py | 25 +++++++------ src/structlog/processors.py | 24 ++++++------- src/structlog/stdlib.py | 69 +++++++++++++++++------------------ src/structlog/testing.py | 6 ++-- src/structlog/threadlocal.py | 2 +- src/structlog/twisted.py | 37 +++++++++---------- 26 files changed, 264 insertions(+), 289 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index f1f5220d..6297572d 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -4,8 +4,8 @@ API Reference ============= .. note:: - The examples here use a very simplified configuration using the minimalistic :class:`structlog.processors.KeyValueRenderer` for brevity and to enable doctests. - The output is going to be different (nicer!) with default configuration. + The examples here use a very simplified configuration using the minimalistic `structlog.processors.KeyValueRenderer` for brevity and to enable doctests. + The output is going to be different (nicer!) with the default configuration. .. testsetup:: * diff --git a/docs/conf.py b/docs/conf.py index 71298e9c..2b97af17 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -99,7 +99,7 @@ def find_version(*file_paths): # The reST default role (used for this markup: `text`) to use for all # documents. -# default_role = None +default_role = "any" # If true, '()' will be appended to :func: etc. cross-reference text. # add_function_parentheses = True diff --git a/docs/configuration.rst b/docs/configuration.rst index f2e0bbc8..8f3b1ba7 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -1,5 +1,3 @@ -.. _configuration: - Configuration ============= @@ -90,7 +88,7 @@ At any time, you can check whether and how ``structlog`` is configured: .. note:: - Since you will call :func:`structlog.get_logger` most likely in module scope, they run at import time before you had a chance to configure ``structlog``. + Since you will call `structlog.get_logger` most likely in module scope, they run at import time before you had a chance to configure ``structlog``. Therefore they return a **lazy proxy** that returns a correct wrapped logger on first ``bind()``/``new()``. Thus, you must never call ``new()`` or ``bind()`` in module or class scope because otherwise you will receive a logger configured with ``structlog``'s default values. @@ -98,7 +96,7 @@ At any time, you can check whether and how ``structlog`` is configured: To enable you to log with the module-global logger, it will create a temporary BoundLogger and relay the log calls to it on *each call*. Therefore if you have nothing to bind but intend to do lots of log calls in a function, it makes sense performance-wise to create a local logger by calling ``bind()`` or ``new()`` without any parameters. - See also :doc:`performance`. + See also `performance`. .. _logger-factories: @@ -106,14 +104,14 @@ At any time, you can check whether and how ``structlog`` is configured: Logger Factories ---------------- -To make :func:`structlog.get_logger` work, one needs one more option that hasn't been discussed yet: ``logger_factory``. +To make `structlog.get_logger` work, one needs one more option that hasn't been discussed yet: ``logger_factory``. It is a callable that returns the logger that gets wrapped and returned. In the simplest case, it's a function that returns a logger -- or just a class. But you can also pass in an instance of a class with a ``__call__`` method for more complicated setups. .. versionadded:: 0.4.0 - :func:`structlog.get_logger` can optionally take positional parameters. + `structlog.get_logger` can optionally take positional parameters. These will be passed to the logger factories. For example, if you use run ``structlog.get_logger("a name")`` and configure ``structlog`` to use the standard library :class:`~structlog.stdlib.LoggerFactory` which has support for positional parameters, the returned logger will have the name ``"a name"``. @@ -123,8 +121,8 @@ That makes sure that loggers are interchangeable. For the common cases of standard library logging and Twisted logging, ``structlog`` comes with two factories built right in: -- :class:`structlog.stdlib.LoggerFactory` -- :class:`structlog.twisted.LoggerFactory` +- `structlog.stdlib.LoggerFactory` +- `structlog.twisted.LoggerFactory` So all it takes to use ``structlog`` with standard library logging is this:: @@ -135,7 +133,7 @@ So all it takes to use ``structlog`` with standard library logging is this:: >>> log.critical("this is too easy!") event='this is too easy!' -By using ``structlog``'s :class:`structlog.stdlib.LoggerFactory`, it is also ensured that variables like function names and line numbers are expanded correctly in your log format. +By using ``structlog``'s `structlog.stdlib.LoggerFactory`, it is also ensured that variables like function names and line numbers are expanded correctly in your log format. The :ref:`Twisted example ` shows how easy it is for Twisted. @@ -144,7 +142,7 @@ The :ref:`Twisted example ` shows how easy it is for Twisted. ``LoggerFactory``-style factories always need to get passed as *instances* like in the examples above. While neither allows for customization using parameters yet, they may do so in the future. -Calling :func:`structlog.get_logger` without configuration gives you a perfectly useful :class:`structlog.PrintLogger`. +Calling `structlog.get_logger` without configuration gives you a perfectly useful `structlog.PrintLogger`. We don't believe silent loggers are a sensible default. @@ -168,4 +166,4 @@ If you use standard library's logging, it makes sense to configure them next to The `plugin definition `_ is the best place. If your app is not a plugin, put it into your `tac file `_ (and then `learn `_ about plugins). -If you have no choice but *have* to configure on import time in module-global scope, or can't rule out for other reasons that that your :func:`structlog.configure` gets called more than once, ``structlog`` offers :func:`structlog.configure_once` that raises a warning if ``structlog`` has been configured before (no matter whether using :func:`structlog.configure` or :func:`~structlog.configure_once`) but doesn't change anything. +If you have no choice but *have* to configure on import time in module-global scope, or can't rule out for other reasons that that your `structlog.configure` gets called more than once, ``structlog`` offers `structlog.configure_once` that raises a warning if ``structlog`` has been configured before (no matter whether using `structlog.configure` or :func:`~structlog.configure_once`) but doesn't change anything. diff --git a/docs/contextvars.rst b/docs/contextvars.rst index 6add8a53..9ae15a78 100644 --- a/docs/contextvars.rst +++ b/docs/contextvars.rst @@ -15,22 +15,16 @@ Context Variables Historically, ``structlog`` only supported thread-local context binding. With the introduction of :mod:`contextvars` in Python 3.7, there is now a way of having a global context that is local to the current context and even works in concurrent code such as code using :mod:`asyncio`. -For that ``structlog`` provides a set of functions to bind variables to a context-local context. +For that ``structlog`` provides a the `structlog.contextvars` module with a set of functions to bind variables to a context-local context. This context is safe to be used in asynchronous code. -The functions are: -- :func:`structlog.contextvars.merge_contextvars`, -- :func:`structlog.contextvars.clear_contextvars`, -- :func:`structlog.contextvars.bind_contextvars`, -- :func:`structlog.contextvars.unbind_contextvars`, +The general flow is: -The general flow of using these functions is: - -- Use :func:`structlog.configure` with :func:`structlog.contextvars.merge_contextvars` as your first processor. -- Call :func:`structlog.contextvars.clear_contextvars` at the beginning of your request handler (or whenever you want to reset the context-local context). -- Call :func:`structlog.contextvars.bind_contextvars` and :func:`structlog.contextvars.unbind_contextvars` instead of :func:`structlog.BoundLogger.bind` and :func:`structlog.BoundLogger.unbind` when you want to (un)bind a particular variable to the context-local context. +- Use `structlog.configure` with `structlog.contextvars.merge_contextvars` as your first processor. +- Call `structlog.contextvars.clear_contextvars` at the beginning of your request handler (or whenever you want to reset the context-local context). +- Call `structlog.contextvars.bind_contextvars` and `structlog.contextvars.unbind_contextvars` instead of you bound logger's ``bind()`` and ``unbind()`` when you want to bind and unbind key-value pairs to the context-local context. - Use ``structlog`` as normal. - Loggers act as the always do, but the :func:`structlog.contextvars.merge_contextvars` processor ensures that any context-local binds get included in all of your log messages. + Loggers act as the always do, but the `structlog.contextvars.merge_contextvars` processor ensures that any context-local binds get included in all of your log messages. .. doctest:: diff --git a/docs/custom-wrappers.rst b/docs/custom-wrappers.rst index 1725cbc2..7133475d 100644 --- a/docs/custom-wrappers.rst +++ b/docs/custom-wrappers.rst @@ -14,14 +14,14 @@ Custom Wrappers structlog.reset_defaults() -``structlog`` comes with a generic bound logger called :class:`structlog.BoundLogger` that can be used to wrap any logger class you fancy. +``structlog`` comes with a generic bound logger called `structlog.BoundLogger` that can be used to wrap any logger class you fancy. It does so by intercepting unknown method names and proxying them to the wrapped logger. -This works fine, except that it has a performance penalty and the API of :class:`~structlog.BoundLogger` isn't clear from reading the documentation because large parts depend on the wrapped logger. +This works fine, except that it has a performance penalty and the API of `structlog.BoundLogger` isn't clear from reading the documentation because large parts depend on the wrapped logger. An additional reason is that you may want to have semantically meaningful log method names that add meta data to log entries as it is fit (see example below). -To solve that, ``structlog`` offers you to use an own wrapper class which you can configure using :func:`structlog.configure`. -And to make it easier for you, it comes with the class :class:`structlog.BoundLoggerBase` which takes care of all data binding duties so you just add your log methods if you choose to sub-class it. +To solve that, ``structlog`` offers you to use an own wrapper class which you can configure using `structlog.configure`. +And to make it easier for you, it comes with the class `structlog.BoundLoggerBase` which takes care of all data binding duties so you just add your log methods if you choose to sub-class it. .. _wrapper_class-example: @@ -50,9 +50,9 @@ It's much easier to demonstrate with an example: You can observe the following: -- The wrapped logger can be found in the instance variable :attr:`structlog.BoundLoggerBase._logger`. -- The helper method :func:`structlog.BoundLoggerBase._proxy_to_logger` that is a DRY_ convenience function that runs the processor chain, handles possible :exc:`~structlog.DropEvent`\ s and calls a named function on :attr:`~structlog.BoundLoggerBase._logger`. -- You can run the chain by hand through using :func:`structlog.BoundLoggerBase._process_event` . +- The wrapped logger can be found in the instance variable `structlog.BoundLoggerBase._logger`. +- The helper method `structlog.BoundLoggerBase._proxy_to_logger` that is a DRY_ convenience function that runs the processor chain, handles possible `DropEvent`\ s and calls a named function on `_logger`. +- You can run the chain by hand through using `structlog.BoundLoggerBase._process_event` . These two methods and one attribute are all you need to write own wrapper classes. diff --git a/docs/development.rst b/docs/development.rst index 57bdb6cf..84e162a4 100644 --- a/docs/development.rst +++ b/docs/development.rst @@ -1,9 +1,9 @@ Development =========== -To make development a more pleasurable experience, ``structlog`` comes with the :mod:`structlog.dev` module. +To make development a more pleasurable experience, ``structlog`` comes with the `structlog.dev` module. -The highlight is :class:`structlog.dev.ConsoleRenderer` that offers nicely aligned and colorful (requires the `colorama module `_ installed) console output while in development: +The highlight is `structlog.dev.ConsoleRenderer` that offers nicely aligned and colorful (requires the `colorama module `_ installed) console output while in development: .. figure:: _static/console_renderer.png :alt: Colorful console output by ConsoleRenderer. @@ -11,7 +11,7 @@ The highlight is :class:`structlog.dev.ConsoleRenderer` that offers nicely align To use it, just add it as a renderer to your processor chain. It will recognize logger names, log levels, time stamps, stack infos, and tracebacks as produced by ``structlog``'s processors and render them in special ways. -``structlog``'s default configuration already uses :class:`~structlog.dev.ConsoleRenderer`, therefore if you want nice colorful output on the console, you don't have to do anything except installing colorama. +``structlog``'s default configuration already uses `ConsoleRenderer`, therefore if you want nice colorful output on the console, you don't have to do anything except installing colorama. If you want to use it along with standard library logging, we suggest the following configuration: .. code-block:: python diff --git a/docs/examples.rst b/docs/examples.rst index 59d42ed8..c31bfa9f 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -1,5 +1,3 @@ -.. _examples: - Examples ======== @@ -21,11 +19,11 @@ In the simplest case, you bind a unique request ID to every incoming request so .. literalinclude:: code_examples/flask_/some_module.py :language: python -While wrapped loggers are *immutable* by default, this example demonstrates how to circumvent that using a thread local dict implementation for context data for convenience (hence the requirement for using `new()` for re-initializing the logger). +While wrapped loggers are *immutable* by default, this example demonstrates how to circumvent that using a thread local dict implementation for context data for convenience (hence the requirement for using ``new()`` for re-initializing the logger). -Please note that :class:`structlog.stdlib.LoggerFactory` is a totally magic-free class that just deduces the name of the caller's module and does a :func:`logging.getLogger` with it. -It's used by :func:`structlog.get_logger` to rid you of logging boilerplate in application code. -If you prefer to name your standard library loggers explicitly, a positional argument to :func:`~structlog.get_logger` gets passed to the factory and used as the name. +Please note that `structlog.stdlib.LoggerFactory` is a totally magic-free class that just deduces the name of the caller's module and does a `logging.getLogger` with it. +It's used by `structlog.get_logger` to rid you of logging boilerplate in application code. +If you prefer to name your standard library loggers explicitly, a positional argument to `get_logger` gets passed to the factory and used as the name. .. _twisted-example: @@ -60,7 +58,7 @@ This shows off the strength of keeping a dict of objects for context instead of Processors ---------- -:ref:`Processors` are a both simple and powerful feature of ``structlog``. +:doc:`processors` are a both simple and powerful feature of ``structlog``. So you want timestamps as part of the structure of the log entry, censor passwords, filter out log entries below your log level before they even get rendered, and get your output as JSON for convenient parsing? Here you go: diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 454f886e..63175032 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -1,5 +1,3 @@ -.. _getting-started: - Getting Started =============== @@ -33,12 +31,12 @@ And indeed, the simplest possible usage looks like this: Here, ``structlog`` takes full advantage of its hopefully useful default settings: - Output is sent to `standard out`_ instead of exploding into the user's face or doing nothing. -- All keywords are formatted using :class:`structlog.dev.ConsoleRenderer`. - That in turn uses `repr()`_ to serialize all values to strings. +- All keywords are formatted using `structlog.dev.ConsoleRenderer`. + That in turn uses `repr` to serialize all values to strings. Thus, it's easy to add support for logging of your own objects\ [*]_. -- If you have `colorama `_ installed, it's rendered in nice :doc:`colors `. +- If you have `colorama `_ installed, it's rendered in nice `colors `. -It should be noted that even in most complex logging setups the example would still look just like that thanks to :ref:`configuration`. +It should be noted that even in most complex logging setups the example would still look just like that thanks to `configuration`. Using the defaults, as above, is equivalent to:: import structlog @@ -58,7 +56,7 @@ Using the defaults, as above, is equivalent to:: log = structlog.get_logger() .. note:: - For brevity and to enable doctests, all further examples in ``structlog``'s documentation use the more simplistic :class:`structlog.processors.KeyValueRenderer()` without timestamps. + For brevity and to enable doctests, all further examples in ``structlog``'s documentation use the more simplistic `structlog.processors.KeyValueRenderer()` without timestamps. There you go, structured logging! However, this alone wouldn't warrant its own package. @@ -102,9 +100,9 @@ For ``structlog``, a log entry is just a dictionary called *event dict[ionary]*: - As soon as an *event* happens -- which is a dictionary too -- it is merged together with the *context* to an *event dict* and logged out. - If you don't like the concept of pre-building a context: just don't! Convenient key-value-based logging is great to have on its own. -- To keep as much order of the keys as possible, an :class:`collections.OrderedDict` is used for the context by default for Pythons that do not have ordered dictionaries by default (notably all versions of CPython before 3.6). +- To keep as much order of the keys as possible, an `collections.OrderedDict` is used for the context by default for Pythons that do not have ordered dictionaries by default (notably all versions of CPython before 3.6). - The recommended way of binding values is the one in these examples: creating new loggers with a new context. - If you're okay with giving up immutable local state for convenience, you can also use :ref:`thread/greenlet local storage ` for the context. + If you're okay with giving up immutable local state for convenience, you can also use `thread/greenlet local storage ` or :doc:`context variables ` for the context. Manipulating Log Entries in Flight @@ -127,7 +125,7 @@ The processor would look like this: ... return event_dict Plain Python, plain dictionaries. -Now you have to tell ``structlog`` about your processor by :doc:`configuring ` it: +Now you have to tell ``structlog`` about your processor by `configuring ` it: .. doctest:: @@ -147,7 +145,7 @@ It depends on the *logger* that is wrapped by ``structlog`` what kind of input i However, in most cases it's gonna be strings. -So assuming you want to follow :doc:`best practices ` and render your event dictionary to JSON that is picked up by a log aggregation system like ELK or Graylog, ``structlog`` comes with batteries included -- you just have to tell it to use its :class:`~structlog.processors.JSONRenderer`: +So assuming you want to follow `best practices ` and render your event dictionary to JSON that is picked up by a log aggregation system like ELK or Graylog, ``structlog`` comes with batteries included -- you just have to tell it to use its :class:`~structlog.processors.JSONRenderer`: .. doctest:: @@ -156,8 +154,6 @@ So assuming you want to follow :doc:`best practices ` an {"event": "hi"} -.. _standard-library-lite: - ``structlog`` and Standard Library's ``logging`` ------------------------------------------------ @@ -180,18 +176,17 @@ To make this common case as simple as possible, ``structlog`` comes with some to In other words, you tell ``structlog`` that you would like to use the standard library logger factory and keep calling :func:`~structlog.get_logger` like before. -Since ``structlog`` is mainly used together with standard library's logging, there's :doc:`more ` goodness to make it as fast and convenient as possible. +Since ``structlog`` is mainly used together with standard library's logging, there's `more ` goodness to make it as fast and convenient as possible. Liked what you saw? ------------------- Now you're all set for the rest of the user's guide and can start reading about :doc:`bound loggers ` -- the heart of ``structlog``. -If you want to see more code, make sure to check out the :ref:`examples`! +If you want to see more code, make sure to check out the `examples`! .. [*] In production, you're more likely to use :class:`~structlog.processors.JSONRenderer` that can also be customized using a ``__structlog__`` method so you don't have to change your repr methods to something they weren't originally intended for. .. _`standard out`: https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29 -.. _`repr()`: https://docs.python.org/2/reference/datamodel.html#object.__repr__ .. _recipe: https://docs.python.org/2/howto/logging-cookbook.html diff --git a/docs/index.rst b/docs/index.rst index b13ee674..d0f59fc1 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -2,7 +2,7 @@ Structured Logging for Python ============================= -Release v\ |version| (:doc:`What's new? `). +Release v\ |version| (`What's new? `). .. include:: ../README.rst :start-after: -begin-short- @@ -11,8 +11,8 @@ Release v\ |version| (:doc:`What's new? `). First steps: -- If you're not sure whether ``structlog`` is for you, have a look at :doc:`why`. -- If you can't wait to log your first entry, start at :doc:`getting-started` and then work yourself through the basic docs. +- If you're not sure whether ``structlog`` is for you, have a look at `why`. +- If you can't wait to log your first entry, start at `getting-started` and then work yourself through the basic docs. - Once you have basic grasp of how ``structlog`` works, acquaint yourself with the `integrations <#integration-with-existing-systems>`_ ``structlog`` is shipping with. @@ -86,6 +86,6 @@ API Reference Indices and tables ================== -- :ref:`genindex` -- :ref:`modindex` -- :ref:`search` +- `genindex` +- `modindex` +- `search` diff --git a/docs/license.rst b/docs/license.rst index 4fa7423f..ce16c9d7 100644 --- a/docs/license.rst +++ b/docs/license.rst @@ -4,7 +4,7 @@ License and Hall of Fame ``structlog`` is licensed both under the `Apache License, Version 2 `_ and the `MIT license `_. The reason for that is to be both protected against patent claims by own contributors and still allow the usage within GPLv2 software. -For more legal details, see `this issue `_ on the bug tracker of PyCA's `cryptography` project. +For more legal details, see `this issue `_ on the bug tracker of PyCA's ``cryptography`` project. The full license texts can be also found in the source code repository: diff --git a/docs/loggers.rst b/docs/loggers.rst index 680766eb..7242e17a 100644 --- a/docs/loggers.rst +++ b/docs/loggers.rst @@ -12,9 +12,9 @@ The center of ``structlog`` is the immutable log wrapper :class:`~structlog.Boun What it does is: - Store a *context dictionary* with key-value pairs that should be part of every log entry, -- store a list of :ref:`processors ` that are called on every log entry, +- store a list of :doc:`processors ` that are called on every log entry, - and store a *logger* that it's wrapping. - This *can* be standard library's :class:`logging.Logger` but absolutely doesn't have to. + This *can* be standard library's `logging.Logger` but absolutely doesn't have to. To manipulate the context dictionary, it offers to: @@ -34,7 +34,7 @@ Finally, if you call *any other* method on :class:`~structlog.BoundLogger`, it w For flexibility, the final processor can return either a string that is passed directly as a positional parameter, or a tuple ``(args, kwargs)`` that are passed as ``wrapped_logger.log_method(*args, **kwargs)``. -.. [1] Since this is slightly magicy, ``structlog`` comes with concrete loggers for the :doc:`standard-library` and :doc:`twisted` that offer you explicit APIs for the supported logging methods but behave identically like the generic BoundLogger otherwise. +.. [1] Since this is slightly magicy, ``structlog`` comes with concrete loggers for the `standard-library` and :doc:`twisted` that offer you explicit APIs for the supported logging methods but behave identically like the generic BoundLogger otherwise. Of course, you are free to implement your own bound loggers too. @@ -42,11 +42,11 @@ Creation -------- You won't be instantiating it yourself though. -In practice you will configure ``structlog`` as explained in the :doc:`next chapter ` and then just call :func:`structlog.get_logger`. +In practice you will configure ``structlog`` as explained in the `next chapter ` and then just call `structlog.get_logger`. In some rare cases you may not want to do that. -For that times there is the :func:`structlog.wrap_logger` function that can be used to wrap a logger without any global state (i.e. configuration): +For that times there is the `structlog.wrap_logger` function that can be used to wrap a logger without any global state (i.e. configuration): .. _proc: @@ -83,16 +83,16 @@ As you can see, it accepts one mandatory and a few optional arguments: If you wish to use a :ref:`configured logger factory `, set it to `None`. **processors** - A list of callables that can :ref:`filter, mutate, and format ` the log entry before it gets passed to the wrapped logger. + A list of callables that can :doc:`filter, mutate, and format ` the log entry before it gets passed to the wrapped logger. Default is ``[``:class:`~structlog.processors.StackInfoRenderer`, :func:`~structlog.processors.format_exc_info`, :class:`~structlog.processors.TimeStamper`, :class:`~structlog.dev.ConsoleRenderer`\ ``]``. **context_class** The class to save your context in. - Particularly useful for :ref:`thread local context storage `. + Particularly useful for `thread local context storage `. - On Python versions that have ordered dictionaries (Python 3.6+, PyPy) the default is a plain :class:`dict`. - For everything else it's :class:`collections.OrderedDict`. + On Python versions that have ordered dictionaries (Python 3.6+, PyPy) the default is a plain `dict`. + For everything else it's `collections.OrderedDict`. Additionally, the following arguments are allowed too: diff --git a/docs/performance.rst b/docs/performance.rst index 5a91c326..7985fb2e 100644 --- a/docs/performance.rst +++ b/docs/performance.rst @@ -11,7 +11,7 @@ Here are a few hints how to get most out of ``structlog`` in production: configure(context_class=dict) - If you don't use automated parsing (you should!) and need predictable order of your keys for some reason, use the `key_order` argument of :class:`~structlog.processors.KeyValueRenderer`. + If you don't use automated parsing (you should!) and need predictable order of your keys for some reason, use the *key_order* argument of :class:`~structlog.processors.KeyValueRenderer`. #. Use a specific wrapper class instead of the generic one. ``structlog`` comes with ones for the :doc:`standard-library` and for :doc:`twisted`:: @@ -30,7 +30,7 @@ Here are a few hints how to get most out of ``structlog`` in production: log.info("iterated", i=i) -#. Set the `cache_logger_on_first_use` option to `True` so the aforementioned on-demand loggers will be assembled only once and cached for future uses:: +#. Set the *cache_logger_on_first_use* option to `True` so the aforementioned on-demand loggers will be assembled only once and cached for future uses:: configure(cache_logger_on_first_use=True) diff --git a/docs/processors.rst b/docs/processors.rst index 5ca16e47..ff21ae2b 100644 --- a/docs/processors.rst +++ b/docs/processors.rst @@ -1,5 +1,3 @@ -.. _processors: - Processors ========== @@ -16,7 +14,7 @@ Each processors receives three positional arguments: **logger** Your wrapped logger object. - For example :class:`logging.Logger`. + For example `logging.Logger`. **method_name** The name of the wrapped method. @@ -63,13 +61,13 @@ Parsing human-readable timestamps is tedious, not so `UNIX timestamps `_ offer features like telling them “this is JSON, deal with it” instead of fiddling with regular expressions. +The probably most useful formatter for string based loggers is `structlog.processors.JSONRenderer`. +Advanced log aggregation and analysis tools like `logstash `_ offer features like telling them "this is JSON, deal with it" instead of fiddling with regular expressions. More examples can be found in the :ref:`examples ` chapter. For a list of shipped processors, check out the :ref:`API documentation `. @@ -122,8 +120,5 @@ Third Party Packages -------------------- Since processors are self-contained callables, it's easy to write your own and to share them in separate packages. -The following processor packages are known to be currently available on PyPI: - -- `structlog-pretty `_: Processors for prettier output -- a code syntax highlighter, JSON and XML prettifiers, a multiline string printer, and a numeric value rounder. -Please feel free to submit a pull request to extend this list with *your* package! +We collect those packages in our `GitHub Wiki `_ and encourage you to add your package too! diff --git a/docs/standard-library.rst b/docs/standard-library.rst index a7ef80a4..d8d939fe 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -1,18 +1,18 @@ Standard Library Logging ======================== -Ideally, ``structlog`` should be able to be used as a drop-in replacement for standard library's :mod:`logging` by wrapping it. -In other words, you should be able to replace your call to :func:`logging.getLogger` by a call to :func:`structlog.get_logger` and things should keep working as before (if ``structlog`` is configured right, see :ref:`stdlib-config` below). +Ideally, ``structlog`` should be able to be used as a drop-in replacement for standard library's `logging` by wrapping it. +In other words, you should be able to replace your call to `logging.getLogger` by a call to `structlog.get_logger` and things should keep working as before (if ``structlog`` is configured right, see `stdlib-config` below). If you run into incompatibilities, it is a *bug* so please take the time to `report it `_! -If you're a heavy :mod:`logging` user, your `help `_ to ensure a better compatibility would be highly appreciated! +If you're a heavy `logging` user, your `help `_ to ensure a better compatibility would be highly appreciated! Just Enough ``logging`` ----------------------- -If you want to use ``structlog`` with :mod:`logging`, you still have to have at least fleeting understanding on how the standard library operates because ``structlog`` will *not* do any magic things in the background for you. -Most importantly you have to *configure* the :mod:`logging` system *additionally* to configuring ``structlog``. +If you want to use ``structlog`` with `logging`, you still have to have at least fleeting understanding on how the standard library operates because ``structlog`` will *not* do any magic things in the background for you. +Most importantly you have to *configure* the `logging` system *additionally* to configuring ``structlog``. Usually it is enough to use:: @@ -25,19 +25,19 @@ Usually it is enough to use:: level=logging.INFO, ) -This will send all log messages with the `log level `_ ``logging.INFO`` and above (that means that e.g. :func:`logging.debug` calls are ignored) to standard out without any special formatting by the standard library. +This will send all log messages with the `log level `_ ``logging.INFO`` and above (that means that e.g. `logging.debug` calls are ignored) to standard out without any special formatting by the standard library. -If you require more complex behavior, please refer to the standard library's :mod:`logging` documentation. +If you require more complex behavior, please refer to the standard library's `logging` documentation. Concrete Bound Logger --------------------- -To make ``structlog``'s behavior less magicy, it ships with a standard library-specific wrapper class that has an explicit API instead of improvising: :class:`structlog.stdlib.BoundLogger`. -It behaves exactly like the generic :class:`structlog.BoundLogger` except: +To make ``structlog``'s behavior less magicy, it ships with a standard library-specific wrapper class that has an explicit API instead of improvising: `structlog.stdlib.BoundLogger`. +It behaves exactly like the generic `structlog.BoundLogger` except: - it's slightly faster due to less overhead, -- has an explicit API that mirrors the log methods of standard library's :class:`logging.Logger`, +- has an explicit API that mirrors the log methods of standard library's `logging.Logger`, - hence causing less cryptic error messages if you get method names wrong. @@ -46,22 +46,22 @@ Processors ``structlog`` comes with a few standard library-specific processors: -:func:`~structlog.stdlib.render_to_log_kwargs`: - Renders the event dictionary into keyword arguments for :func:`logging.log` that attaches everything except the `event` field to the *extra* argument. - This is useful if you want to render your log entries entirely within :mod:`logging`. +`render_to_log_kwargs`: + Renders the event dictionary into keyword arguments for `logging.log` that attaches everything except the ``event`` field to the *extra* argument. + This is useful if you want to render your log entries entirely within `logging`. -:func:`~structlog.stdlib.filter_by_level`: +`filter_by_level`: Checks the log entry's log level against the configuration of standard library's logging. Log entries below the threshold get silently dropped. Put it at the beginning of your processing chain to avoid expensive operations from happening in the first place. -:func:`~structlog.stdlib.add_logger_name`: +`add_logger_name`: Adds the name of the logger to the event dictionary under the key ``logger``. -:func:`~structlog.stdlib.add_log_level`: +`add_log_level`: Adds the log level to the event dictionary under the key ``level``. -:func:`~structlog.stdlib.add_log_level_number`: +`add_log_level_number`: Adds the log level number to the event dictionary under the key ``level_number``. Log level numbers map to the log level names. The Python stdlib uses them for filtering logic. @@ -71,13 +71,13 @@ Processors level in ("warning", "error", "critical") level_number >= 30 - The mapping of names to numbers is in :data:`~structlog.stdlib._NAME_TO_LEVEL` + The mapping of names to numbers is in ``structlog.stdlib._NAME_TO_LEVEL``. -:class:`~structlog.stdlib.PositionalArgumentsFormatter`: +`PositionalArgumentsFormatter`: This processes and formats positional arguments (if any) passed to log methods in the same way the ``logging`` module would do, e.g. ``logger.info("Hello, %s", name)``. -``structlog`` also comes with :class:`~structlog.stdlib.ProcessorFormatter` which is a :class:`logging.Formatter` that enables you to format non-``structlog`` log entries using ``structlog`` renderers *and* multiplex ``structlog``’s output with different renderers (see below for an example). +``structlog`` also comes with `ProcessorFormatter` which is a `logging.Formatter` that enables you to format non-``structlog`` log entries using ``structlog`` renderers *and* multiplex ``structlog``’s output with different renderers (see below for an example). .. _stdlib-config: @@ -88,8 +88,8 @@ Suggested Configurations Depending *where* you'd like to do your formatting, you can take one of three approaches: -Rendering Using :mod:`logging`-based Formatters -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Rendering Using `logging`-based Formatters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: python @@ -138,16 +138,16 @@ Now both ``structlog`` and ``logging`` will emit JSON logs: {"message": "hello"} -Rendering Using ``structlog``-based Formatters Within :mod:`logging` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Rendering Using ``structlog``-based Formatters Within `logging` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -``structlog`` comes with a :class:`~structlog.stdlib.ProcessorFormatter` that can be used as a :class:`~logging.Formatter` in any stdlib :mod:`Handler ` object. +``structlog`` comes with a `ProcessorFormatter` that can be used as a `logging.Formatter` in any stdlib `Handler ` object. -The :class:`~structlog.stdlib.ProcessorFormatter` has two parts to its API: +The `ProcessorFormatter` has two parts to its API: -#. The :meth:`~structlog.stdlib.ProcessorFormatter.wrap_for_formatter` method must be used as the last processor in :func:`structlog.configure`, +#. The `structlog.stdlib.ProcessorFormatter.wrap_for_formatter` method must be used as the last processor in `structlog.configure`, it converts the the processed event dict to something that the ``ProcessorFormatter`` understands. -#. The :class:`~structlog.stdlib.ProcessorFormatter` itself, +#. The `ProcessorFormatter` itself, which can wrap any ``structlog`` renderer to handle the output of both ``structlog`` and standard library events. Thus, the simplest possible configuration looks like the following: @@ -187,7 +187,7 @@ which will allow both of these to work in other modules: amazing events=oh yes Of course, you probably want timestamps and log levels in your output. -The :class:`~structlog.stdlib.ProcessorFormatter` has a ``foreign_pre_chain`` argument which is responsible for adding properties to events from the standard library -- i.e. that do not originate from a ``structlog`` logger -- and which should in general match the ``processors`` argument to :func:`structlog.configure` so you get a consistent output. +The `ProcessorFormatter` has a ``foreign_pre_chain`` argument which is responsible for adding properties to events from the standard library -- i.e. that do not originate from a ``structlog`` logger -- and which should in general match the ``processors`` argument to `structlog.configure` so you get a consistent output. For example, to add timestamps, log levels, and traceback handling to your logs you should do: @@ -222,7 +222,7 @@ which (given the same ``logging.*`` calls as in the previous example) will resul 2017-03-06 14:59:20 [info ] amazing events=oh yes This allows you to set up some sophisticated logging configurations. -For example, to use the standard library's :func:`~logging.config.dictConfig` to log colored logs to the console and plain logs to a file you could do: +For example, to use the standard library's `logging.config.dictConfig` to log colored logs to the console and plain logs to a file you could do: .. code-block:: python @@ -290,7 +290,7 @@ For example, to use the standard library's :func:`~logging.config.dictConfig` to This defines two formatters: one plain and one colored. Both are run for each log entry. -Log entries that do not originate from ``structlog``, are additionally pre-processed using a cached ``timestamper`` and :func:`~structlog.stdlib.add_log_level`. +Log entries that do not originate from ``structlog``, are additionally pre-processed using a cached ``timestamper`` and `add_log_level`. .. code-block:: pycon @@ -306,8 +306,8 @@ Log entries that do not originate from ``structlog``, are additionally pre-proce (Sadly, you have to imagine the colors in the first two outputs.) -If you leave ``foreign_pre_chain`` as `None`, formatting will be left to :mod:`logging`. -Meaning: you can define a ``format`` for :class:`~structlog.stdlib.ProcessorFormatter` too! +If you leave ``foreign_pre_chain`` as `None`, formatting will be left to `logging`. +Meaning: you can define a ``format`` for `ProcessorFormatter` too! Rendering Within ``structlog`` @@ -337,9 +337,9 @@ A basic configuration to output structured logs in JSON format looks like this: cache_logger_on_first_use=True, ) -(If you're still runnning Python 2, replace :class:`~structlog.processors.UnicodeDecoder` through :class:`~structlog.processors.UnicodeEncoder`.) +(If you're still runnning Python 2, replace `UnicodeDecoder` through `UnicodeEncoder`.) -To make your program behave like a proper `12 factor app`_ that outputs only JSON to ``stdout``, configure the ``logging`` module like this:: +To make your program behave like a proper `12 factor app`_ that outputs only JSON to ``stdout``, configure the `logging` module like this:: import logging import sys diff --git a/docs/testing.rst b/docs/testing.rst index ec0d0c54..c4e49910 100644 --- a/docs/testing.rst +++ b/docs/testing.rst @@ -3,7 +3,7 @@ Testing ``structlog`` comes with tools for testing the logging behavior of your application. -If you need functionality similar to :meth:`unittest.TestCase.assertLogs`, or you want to capture all logs for some other reason, you can use the :func:`structlog.testing.capture_logs` context manager: +If you need functionality similar to `unittest.TestCase.assertLogs`, or you want to capture all logs for some other reason, you can use the `structlog.testing.capture_logs` context manager: .. doctest:: @@ -14,7 +14,7 @@ If you need functionality similar to :meth:`unittest.TestCase.assertLogs`, or yo >>> cap_logs [{'x': 'y', 'event': 'hello', 'log_level': 'info'}] -You can build your own helpers using :class:`structlog.testing.LogCapture`. +You can build your own helpers using `structlog.testing.LogCapture`. For example a `pytest `_ fixture to capture log output could look like this:: @pytest.fixture(name="log_output") @@ -33,7 +33,7 @@ For example a `pytest `_ fixture to capture log output ---- -Additionally -- mostly for unit testing within ``structlog`` itself -- ``structlog`` also ships with a logger that just returns whatever it gets passed into it: :class:`~structlog.ReturnLogger`. +Additionally ``structlog`` also ships with a logger that just returns whatever it gets passed into it: `structlog.testing.ReturnLogger`. .. doctest:: diff --git a/docs/thread-local.rst b/docs/thread-local.rst index fd9f5819..d93b8015 100644 --- a/docs/thread-local.rst +++ b/docs/thread-local.rst @@ -1,5 +1,3 @@ -.. _threadlocal: - Thread Local Context ==================== @@ -24,28 +22,27 @@ Immutability ---David Reid The behavior of copying itself, adding new values, and returning the result is useful for applications that keep somehow their own context using classes or closures. -Twisted is a :ref:`fine example ` for that. +Twisted is a `fine example ` for that. Another possible approach is passing wrapped loggers around or log only within your view where you gather errors and events using return codes and exceptions. If you are willing to do that, you should stick to it because `immutable state `_ is a very good thing\ [*]_. Sooner or later, global state and mutable data lead to unpleasant surprises. However, in the case of conventional web development, we realize that passing loggers around seems rather cumbersome, intrusive, and generally against the mainstream culture. -And since it's more important that people actually *use* ``structlog`` than to be pure and snobby, ``structlog`` contains a couple of mechanisms to help here. +And since it's more important that people actually *use* ``structlog`` than to be pure and snobby, ``structlog`` contains ships with the `structlog.threadlocal` module and a couple of mechanisms to help here. The ``merge_threadlocal`` Processor ----------------------------------- -``structlog`` provides a simple set of functions that allow explicitly binding certain fields to a global (thread-local) context. -These functions are :func:`structlog.threadlocal.merge_threadlocal`, :func:`structlog.threadlocal.clear_threadlocal`, and :func:`structlog.threadlocal.bind_threadlocal`. +``structlog`` provides a simple set of functions that allow explicitly binding certain fields to a global (thread-local) context and merge them later using a processor into the event dict. The general flow of using these functions is: -- Use :func:`structlog.configure` with :func:`structlog.threadlocal.merge_threadlocal` as your first processor. -- Call :func:`structlog.threadlocal.clear_threadlocal` at the beginning of your request handler (or whenever you want to reset the thread-local context). -- Call :func:`structlog.threadlocal.bind_threadlocal` as an alternative to :func:`structlog.BoundLogger.bind` when you want to bind a particular variable to the thread-local context. +- Use `structlog.configure` with `structlog.threadlocal.merge_threadlocal` as your first processor. +- Call `structlog.threadlocal.clear_threadlocal` at the beginning of your request handler (or whenever you want to reset the thread-local context). +- Call `structlog.threadlocal.bind_threadlocal` as an alternative to your bound logger's ``bind()`` when you want to bind a particular variable to the thread-local context. - Use ``structlog`` as normal. - Loggers act as the always do, but the :func:`structlog.threadlocal.merge_threadlocal` processor ensures that any thread-local binds get included in all of your log messages. + Loggers act as they always do, but the `structlog.threadlocal.merge_threadlocal` processor ensures that any thread-local binds get included in all of your log messages. .. doctest:: @@ -80,18 +77,15 @@ The general flow of using these functions is: Thread-local Contexts --------------------- -``structlog`` also provides thread local context storage which you may already know from `Flask `_: - -Thread local storage makes your logger's context global but *only within the current thread*\ [*]_. -In the case of web frameworks this usually means that your context becomes global to the current request. +``structlog`` also provides thread-local context storage in a form that you may already know from `Flask `_ and that makes the *entire context* global to your thread or greenlet. -The following explanations may sound a bit confusing at first but the :ref:`Flask example ` illustrates how simple and elegant this works in practice. +This makes its behavior more difficult to reason about which is why we generally recomment to use the `merge_threadlocal` route. Wrapped Dicts -------------- +^^^^^^^^^^^^^ -In order to make your context thread local, ``structlog`` ships with a function that can wrap any dict-like class to make it usable for thread local storage: :func:`structlog.threadlocal.wrap_dict`. +In order to make your context thread-local, ``structlog`` ships with a function that can wrap any dict-like class to make it usable for thread-local storage: `structlog.threadlocal.wrap_dict`. Within one thread, every instance of the returned class will have a *common* instance of the wrapped dict-like class: @@ -119,7 +113,7 @@ To enable thread local context use the generated class as the context class:: Creation of a new ``BoundLogger`` initializes the logger's context as ``context_class(initial_values)``, and then adds any values passed via ``.bind()``. As all instances of a wrapped dict-like class share the same data, in the case above, the new logger's context will contain all previously bound values in addition to the new ones. -:func:`structlog.threadlocal.wrap_dict` returns always a completely *new* wrapped class: +`structlog.threadlocal.wrap_dict` returns always a completely *new* wrapped class: .. doctest:: @@ -134,7 +128,7 @@ To enable thread local context use the generated class as the context class:: WrappedDict-e0fc330e-e5eb-42ee-bcec-ffd7bd09ad09 -In order to be able to bind values temporarily to a logger, :mod:`structlog.threadlocal` comes with a `context manager `_: :func:`~structlog.threadlocal.tmp_bind`\ : +In order to be able to bind values temporarily to a logger, `structlog.threadlocal` comes with a `context manager `_: `structlog.threadlocal.tmp_bind`\ : .. testsetup:: ctx @@ -157,13 +151,13 @@ In order to be able to bind values temporarily to a logger, :mod:`structlog.thre The state before the ``with`` statement is saved and restored once it's left. -If you want to detach a logger from thread local data, there's :func:`structlog.threadlocal.as_immutable`. +If you want to detach a logger from thread local data, there's `structlog.threadlocal.as_immutable`. Downsides & Caveats -------------------- +~~~~~~~~~~~~~~~~~~~ -The convenience of having a thread local context comes at a price though: +The convenience of having a thread-local context comes at a price though: .. warning:: - If you can't rule out that your application re-uses threads, you *must* remember to **initialize your thread local context** at the start of each request using :func:`~structlog.BoundLogger.new` (instead of :func:`~structlog.BoundLogger.bind`). @@ -182,9 +176,10 @@ The convenience of having a thread local context comes at a price though: Although the state is saved in a global data structure, you still need the global wrapped logger produce a real bound logger. Otherwise each log call will result in an instantiation of a temporary BoundLogger. - See :ref:`configuration` for more details. -The general sentiment against thread locals is that they're hard to test. + See `configuration` for more details. + +The general sentiment against threadn-locals is that they're hard to test. In this case we feel like this is an acceptable trade-off. You can easily write deterministic tests using a call-capturing processor if you use the API properly (cf. warning above). @@ -193,5 +188,3 @@ This big red box is also what separates immutable local from mutable global data .. [*] In the spirit of Python's 'consenting adults', ``structlog`` doesn't enforce the immutability with technical means. However, if you don't meddle with undocumented data, the objects can be safely considered immutable. - -.. [*] Special care has been taken to detect and support greenlets properly. diff --git a/docs/twisted.rst b/docs/twisted.rst index e8cef276..f3dc25df 100644 --- a/docs/twisted.rst +++ b/docs/twisted.rst @@ -3,7 +3,7 @@ Twisted .. warning:: - Since :func:`sys.exc_clear` has been dropped in Python 3, there is currently no way to avoid multiple tracebacks in your log files if using ``structlog`` together with Twisted on Python 3. + Since ``sys.exc_clear`` has been dropped in Python 3, there is currently no way to avoid multiple tracebacks in your log files if using ``structlog`` together with Twisted on Python 3. .. note:: @@ -13,14 +13,14 @@ Twisted Concrete Bound Logger --------------------- -To make ``structlog``'s behavior less magicy, it ships with a Twisted-specific wrapper class that has an explicit API instead of improvising: :class:`structlog.twisted.BoundLogger`. -It behaves exactly like the generic :class:`structlog.BoundLogger` except: +To make ``structlog``'s behavior less magicy, it ships with a Twisted-specific wrapper class that has an explicit API instead of improvising: `structlog.twisted.BoundLogger`. +It behaves exactly like the generic `structlog.BoundLogger` except: - it's slightly faster due to less overhead, - has an explicit API (:func:`~structlog.twisted.BoundLogger.msg` and :func:`~structlog.twisted.BoundLogger.err`), - hence causing less cryptic error messages if you get method names wrong. -In order to avoid that ``structlog`` disturbs your CamelCase harmony, it comes with an alias for :func:`structlog.get_logger` called :func:`structlog.getLogger`. +In order to avoid that ``structlog`` disturbs your CamelCase harmony, it comes with an alias for `structlog.get_logger` called `structlog.getLogger`. Processors @@ -28,7 +28,7 @@ Processors ``structlog`` comes with two Twisted-specific processors: -:class:`~structlog.twisted.EventAdapter` +`structlog.twisted.EventAdapter` This is useful if you have an existing Twisted application and just want to wrap your loggers for now. It takes care of transforming your event dictionary into something `twisted.python.log.err `_ can digest. @@ -49,7 +49,7 @@ Processors Therefore ``structlog`` comes with: -:class:`~structlog.twisted.JSONRenderer` +`structlog.twisted.JSONRenderer` Goes a step further and circumvents Twisted logger's Exception/Failure handling and renders it itself as JSON strings. That gives you regular and simple-to-parse single-line JSON log entries no matter what happens. @@ -57,9 +57,9 @@ Processors Bending Foreign Logging To Your Will ------------------------------------ -``structlog`` comes with a wrapper for Twisted's log observers to ensure the rest of your logs are in JSON too: :func:`~structlog.twisted.JSONLogObserverWrapper`. +``structlog`` comes with a wrapper for Twisted's log observers to ensure the rest of your logs are in JSON too: `structlog.twisted.JSONLogObserverWrapper`. -What it does is determining whether a log entry has been formatted by :class:`~structlog.twisted.JSONRenderer` and if not, converts the log entry to JSON with `event` being the log message and putting Twisted's `system` into a second key. +What it does is determining whether a log entry has been formatted by `structlog.twisted.JSONRenderer` and if not, converts the log entry to JSON with ``event`` being the log message and putting Twisted's ``system`` into a second key. So for example:: @@ -72,7 +72,7 @@ becomes:: There is obviously some redundancy here. Also, I'm presuming that if you write out JSON logs, you're going to let something else parse them which makes the human-readable date entries more trouble than they're worth. -To get a clean log without timestamps and additional system fields (``[-]``), ``structlog`` comes with :class:`~structlog.twisted.PlainFileLogObserver` that writes only the plain message to a file and :func:`~structlog.twisted.plainJSONStdOutLogger` that composes it with the aforementioned :func:`~structlog.twisted.JSONLogObserverWrapper` and gives you a pure JSON log without any timestamps or other noise straight to `standard out`_:: +To get a clean log without timestamps and additional system fields (``[-]``), ``structlog`` comes with `structlog.twisted.PlainFileLogObserver` that writes only the plain message to a file and `structlog.twisted.plainJSONStdOutLogger` that composes it with the aforementioned `structlog.twisted.JSONLogObserverWrapper` and gives you a pure JSON log without any timestamps or other noise straight to `standard out`_:: $ twistd -n --logger structlog.twisted.plainJSONStdOutLogger web diff --git a/src/structlog/_base.py b/src/structlog/_base.py index 23acbc1f..084da1bc 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -23,7 +23,7 @@ class BoundLoggerBase(object): - :class:`structlog.twisted.BoundLogger`, - and :class:`structlog.stdlib.BoundLogger`. - See also :doc:`custom-wrappers`. + See also `custom-wrappers`. """ _logger = None @@ -34,7 +34,7 @@ class BoundLoggerBase(object): Despite underscore available **read-only** to custom wrapper classes. - See also :doc:`custom-wrappers`. + See also `custom-wrappers`. """ def __init__(self, logger, processors, context): @@ -63,7 +63,7 @@ def bind(self, **new_values): """ Return a new logger with *new_values* added to the existing ones. - :rtype: `self.__class__` + :rtype: ``self.__class__`` """ return self.__class__( self._logger, @@ -77,7 +77,7 @@ def unbind(self, *keys): :raises KeyError: If the key is not part of the context. - :rtype: `self.__class__` + :rtype: ``self.__class__`` """ bl = self.bind() for key in keys: @@ -88,7 +88,7 @@ def try_unbind(self, *keys): """ Like :meth:`unbind`, but best effort: missing keys are ignored. - :rtype: `self.__class__` + :rtype: ``self.__class__`` .. versionadded:: 18.2.0 """ @@ -103,10 +103,10 @@ def new(self, **new_values): Clear context and binds *initial_values* using :func:`bind`. Only necessary with dict implementations that keep global state like - those wrapped by :func:`structlog.threadlocal.wrap_dict` when threads + those wrapped by `structlog.threadlocal.wrap_dict` when threads are re-used. - :rtype: `self.__class__` + :rtype: ``self.__class__`` """ self._context.clear() return self.bind(**new_values) @@ -115,7 +115,7 @@ def new(self, **new_values): def _process_event(self, method_name, event, event_kw): """ - Combines creates an `event_dict` and runs the chain. + Combines creates an ``event_dict`` and runs the chain. Call it to combine your *event* and *context* into an event_dict and process using the processor chain. @@ -127,16 +127,16 @@ def _process_event(self, method_name, event, event_kw): :param event_kw: Additional event keywords. For example if someone calls ``log.msg("foo", bar=42)``, *event* would to be ``"foo"`` and *event_kw* ``{"bar": 42}``. - :raises: :class:`structlog.DropEvent` if log entry should be dropped. - :raises: :class:`ValueError` if the final processor doesn't return a + :raises: `structlog.DropEvent` if log entry should be dropped. + :raises: `ValueError` if the final processor doesn't return a string, tuple, or a dict. - :rtype: `tuple` of `(*args, **kw)` + :rtype: `tuple` of ``(*args, **kw)`` .. note:: Despite underscore available to custom wrapper classes. - See also :doc:`custom-wrappers`. + See also `custom-wrappers`. .. versionchanged:: 14.0.0 Allow final processor to return a `dict`. @@ -183,7 +183,7 @@ def _proxy_to_logger(self, method_name, event=None, **event_kw): Despite underscore available to custom wrapper classes. - See also :doc:`custom-wrappers`. + See also `custom-wrappers`. """ try: args, kw = self._process_event(method_name, event, event_kw) diff --git a/src/structlog/_config.py b/src/structlog/_config.py index b4d3273c..da9a32a5 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -23,7 +23,7 @@ """ .. note:: - Any changes to these defaults must be reflected in :doc:`getting-started`. + Any changes to these defaults must be reflected in `getting-started`. """ _BUILTIN_DEFAULT_PROCESSORS = [ StackInfoRenderer(), @@ -60,7 +60,7 @@ class _Configuration(object): _CONFIG = _Configuration() """ -Global defaults used when arguments to :func:`wrap_logger` are omitted. +Global defaults used when arguments to `wrap_logger` are omitted. """ @@ -68,7 +68,7 @@ def is_configured(): """ Return whether ``structlog`` has been configured. - If ``False``, ``structlog`` is running with builtin defaults. + If `False`, ``structlog`` is running with builtin defaults. :rtype: bool @@ -115,20 +115,20 @@ def get_logger(*args, **initial_values): :rtype: A proxy that creates a correctly configured bound logger when necessary. - See :ref:`configuration` for details. + See `configuration` for details. If you prefer CamelCase, there's an alias for your reading pleasure: - :func:`structlog.getLogger`. + `structlog.getLogger`. .. versionadded:: 0.4.0 - `args` + *args* """ return wrap_logger(None, logger_factory_args=args, **initial_values) getLogger = get_logger """ -CamelCase alias for :func:`structlog.get_logger`. +CamelCase alias for `structlog.get_logger`. This function is supposed to be in every source file -- we don't want it to stick out like a sore thumb in frameworks like Twisted or Zope. @@ -148,9 +148,9 @@ def wrap_logger( Create a new bound logger for an arbitrary *logger*. Default values for *processors*, *wrapper_class*, and *context_class* can - be set using :func:`configure`. + be set using `configure`. - If you set an attribute here, :func:`configure` calls have *no* effect for + If you set an attribute here, `configure` calls have *no* effect for the *respective* attribute. In other words: selective overwriting of the defaults while keeping some @@ -163,10 +163,10 @@ def wrap_logger( :rtype: A proxy that creates a correctly configured bound logger when necessary. - See :func:`configure` for the meaning of the rest of the arguments. + See `configure` for the meaning of the rest of the arguments. .. versionadded:: 0.4.0 - `logger_factory_args` + *logger_factory_args* """ return BoundLoggerLazyProxy( logger, @@ -189,30 +189,31 @@ def configure( """ Configures the **global** defaults. - They are used if :func:`wrap_logger` has been called without arguments. + They are used if `wrap_logger` or `get_logger` are called without + arguments. - Can be called several times, keeping an argument at `None` leaves is + Can be called several times, keeping an argument at `None` leaves it unchanged from the current setting. - After calling for the first time, :func:`is_configured` starts returning - ``True``. + After calling for the first time, `is_configured` starts returning + `True`. - Use :func:`reset_defaults` to undo your changes. + Use `reset_defaults` to undo your changes. :param list processors: List of processors. :param type wrapper_class: Class to use for wrapping loggers instead of - :class:`structlog.BoundLogger`. See :doc:`standard-library`, - :doc:`twisted`, and :doc:`custom-wrappers`. + `structlog.BoundLogger`. See `standard-library`, :doc:`twisted`, and + `custom-wrappers`. :param type context_class: Class to be used for internal context keeping. :param callable logger_factory: Factory to be called to create a new logger that shall be wrapped. :param bool cache_logger_on_first_use: `wrap_logger` doesn't return an actual wrapped logger but a proxy that assembles one when it's first used. If this option is set to `True`, this assembled logger is - cached. See :doc:`performance`. + cached. See `performance`. .. versionadded:: 0.3.0 - `cache_logger_on_first_use` + *cache_logger_on_first_use* """ _CONFIG.is_configured = True if processors is not None: @@ -231,10 +232,10 @@ def configure_once(*args, **kw): """ Configures iff structlog isn't configured yet. - It does *not* matter whether is was configured using :func:`configure` - or :func:`configure_once` before. + It does *not* matter whether is was configured using `configure` or + `configure_once` before. - Raises a :class:`RuntimeWarning` if repeated configuration is attempted. + Raises a `RuntimeWarning` if repeated configuration is attempted. """ if not _CONFIG.is_configured: configure(*args, **kw) @@ -246,7 +247,7 @@ def reset_defaults(): """ Resets global default values to builtin defaults. - :func:`is_configured` starts returning ``False`` afterwards. + `is_configured` starts returning `False` afterwards. """ _CONFIG.is_configured = False _CONFIG.default_processors = _BUILTIN_DEFAULT_PROCESSORS[:] @@ -258,18 +259,18 @@ def reset_defaults(): class BoundLoggerLazyProxy(object): """ - Instantiates a BoundLogger on first usage. + Instantiates a ``BoundLogger`` on first usage. Takes both configuration and instantiation parameters into account. - The only points where a BoundLogger changes state are bind(), unbind(), and - new() and that return the actual BoundLogger. + The only points where a BoundLogger changes state are ``bind()``, + ``unbind()``, and ``new()`` and that return the actual ``BoundLogger``. - If and only if configuration says so, that actual BoundLogger is cached on - first usage. + If and only if configuration says so, that actual ``BoundLogger`` is + cached on first usage. .. versionchanged:: 0.4.0 - Added support for `logger_factory_args`. + Added support for *logger_factory_args*. """ def __init__( diff --git a/src/structlog/_loggers.py b/src/structlog/_loggers.py index 64a0c58d..9e259fe4 100644 --- a/src/structlog/_loggers.py +++ b/src/structlog/_loggers.py @@ -18,9 +18,9 @@ class PrintLoggerFactory(object): r""" - Produce :class:`PrintLogger`\ s. + Produce `PrintLogger`\ s. - To be used with :func:`structlog.configure`\ 's `logger_factory`. + To be used with `structlog.configure`\ 's ``logger_factory``. :param file file: File to print to. (default: stdout) @@ -61,7 +61,7 @@ class PrintLogger(object): hello Useful if you follow - :doc:`current logging best practices `. + `current logging best practices `. Also very useful for testing and examples since logging is finicky in doctests. diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 372f7fcf..14c8df1a 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -91,9 +91,9 @@ class _PlainStyles(object): class ConsoleRenderer(object): """ - Render `event_dict` nicely aligned, possibly in colors, and ordered. + Render ``event_dict`` nicely aligned, possibly in colors, and ordered. - If `event_dict` contains an ``exception`` key (for example from + If ``event_dict`` contains an ``exception`` key (for example from :func:`~structlog.processors.format_exc_info`), it will be rendered *after* the log line. @@ -102,17 +102,17 @@ class ConsoleRenderer(object): :param bool force_colors: Force colors even for non-tty destinations. Use this option if your logs are stored in a file that is meant to be streamed to the console. - :param bool repr_native_str: When ``True``, :func:`repr()` is also applied + :param bool repr_native_str: When `True`, `repr` is also applied to native strings (i.e. unicode on Python 3 and bytes on Python 2). - Setting this to ``False`` is useful if you want to have human-readable - non-ASCII output on Python 2. The `event` key is *never* - :func:`repr()` -ed. + Setting this to `False` is useful if you want to have human-readable + non-ASCII output on Python 2. The ``event`` key is *never* + `repr` -ed. :param dict level_styles: When present, use these styles for colors. This must be a dict from level names (strings) to colorama styles. The default can be obtained by calling - :meth:`ConsoleRenderer.get_default_level_styles` + `ConsoleRenderer.get_default_level_styles` - Requires the colorama_ package if *colors* is ``True``. + Requires the colorama_ package if *colors* is `True`. .. _colorama: https://pypi.org/project/colorama/ @@ -264,17 +264,16 @@ def get_default_level_styles(colors=True): """ Get the default styles for log levels - This is intended to be used with :class:`ConsoleRenderer`'s - ``level_styles`` parameter. For example, if you are adding - custom levels in your home-grown - :func:`~structlog.stdlib.add_log_level` you could do:: + This is intended to be used with `ConsoleRenderer`'s ``level_styles`` + parameter. For example, if you are adding custom levels in your + home-grown :func:`~structlog.stdlib.add_log_level` you could do:: my_styles = ConsoleRenderer.get_default_level_styles() my_styles["EVERYTHING_IS_ON_FIRE"] = my_styles["critical"] renderer = ConsoleRenderer(level_styles=my_styles) :param bool colors: Whether to use colorful styles. This must match the - `colors` parameter to :class:`ConsoleRenderer`. Default: True. + *colors* parameter to `ConsoleRenderer`. Default: `True`. """ if colors: styles = _ColorfulStyles diff --git a/src/structlog/processors.py b/src/structlog/processors.py index d7b69207..fb5a5d46 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -25,7 +25,7 @@ class KeyValueRenderer(object): """ - Render `event_dict` as a list of ``Key=repr(Value)`` pairs. + Render ``event_dict`` as a list of ``Key=repr(Value)`` pairs. :param bool sort_keys: Whether to sort keys when formatting. :param list key_order: List of keys that should be rendered in this exact @@ -103,7 +103,7 @@ def __call__(self, _, __, event_dict): class UnicodeEncoder(object): """ - Encode unicode values in `event_dict`. + Encode unicode values in ``event_dict``. :param str encoding: Encoding to encode to (default: ``"utf-8"``). :param str errors: How to cope with encoding errors (default @@ -128,7 +128,7 @@ def __call__(self, logger, name, event_dict): class UnicodeDecoder(object): """ - Decode byte string values in `event_dict`. + Decode byte string values in ``event_dict``. :param str encoding: Encoding to decode from (default: ``"utf-8"``). :param str errors: How to cope with encoding errors (default: @@ -155,7 +155,7 @@ def __call__(self, logger, name, event_dict): class JSONRenderer(object): """ - Render the `event_dict` using ``serializer(event_dict, **json_kw)``. + Render the ``event_dict`` using ``serializer(event_dict, **json_kw)``. :param dict json_kw: Are passed unmodified to *serializer*. If *default* is passed, it will disable support for ``__structlog__``-based @@ -205,7 +205,7 @@ def _json_fallback_handler(obj): def format_exc_info(logger, name, event_dict): """ - Replace an `exc_info` field by an `exception` string field: + Replace an ``exc_info`` field by an ``exception`` string field: If *event_dict* contains the key ``exc_info``, there are two possible behaviors: @@ -229,12 +229,12 @@ def format_exc_info(logger, name, event_dict): class TimeStamper(object): """ - Add a timestamp to `event_dict`. + Add a timestamp to ``event_dict``. .. note:: You should let OS tools take care of timestamping. See also - :doc:`logging-best-practices`. + `logging-best-practices`. :param str fmt: strftime format string, or ``"iso"`` for `ISO 8601 `_, or `None` for a `UNIX @@ -323,19 +323,19 @@ def _figure_out_exc_info(v): class ExceptionPrettyPrinter(object): """ - Pretty print exceptions and remove them from the `event_dict`. + Pretty print exceptions and remove them from the ``event_dict``. :param file file: Target file for output (default: ``sys.stdout``). This processor is mostly for development and testing so you can read exceptions properly formatted. - It behaves like :func:`format_exc_info` except it removes the exception + It behaves like `format_exc_info` except it removes the exception data from the event dictionary after printing it. It's tolerant to having `format_exc_info` in front of itself in the processor chain but doesn't require it. In other words, it handles both - `exception` as well as `exc_info` keys. + ``exception`` as well as ``exc_info`` keys. .. versionadded:: 0.4.0 @@ -362,12 +362,12 @@ def __call__(self, logger, name, event_dict): class StackInfoRenderer(object): """ - Add stack information with key `stack` if `stack_info` is true. + Add stack information with key ``stack`` if ``stack_info`` is `True`. Useful when you want to attach a stack dump to a log entry without involving an exception. - It works analogously to the `stack_info` argument of the Python 3 standard + It works analogously to the *stack_info* argument of the Python 3 standard library logging but works on both 2 and 3. .. versionadded:: 0.4.0 diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 5a311efa..675b19bf 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -22,13 +22,15 @@ class _FixedFindCallerLogger(logging.Logger): """ - Change the behavior of findCaller to cope with structlog's extra frames. + Change the behavior of `logging.Logger.findCaller` to cope with + ``structlog``'s extra frames. """ def findCaller(self, stack_info=False, stacklevel=1): """ Finds the first caller frame outside of structlog so that the caller info is populated for wrapping stdlib. + This logger gets set as the default one when using LoggerFactory. """ f, name = _find_first_app_frame_and_name(["logging"]) @@ -44,7 +46,8 @@ def findCaller(self, stack_info=False, stacklevel=1): class BoundLogger(BoundLoggerBase): """ - Python Standard Library version of :class:`structlog.BoundLogger`. + Python Standard Library version of `structlog.BoundLogger`. + Works exactly like the generic one except that it takes advantage of knowing the logging methods in advance. @@ -55,25 +58,24 @@ class BoundLogger(BoundLoggerBase): ) It also contains a bunch of properties that pass-through to the wrapped - :class:`logging.Logger` which should make it work as a drop-in - replacement. + `logging.Logger` which should make it work as a drop-in replacement. """ def debug(self, event=None, *args, **kw): """ - Process event and call :meth:`logging.Logger.debug` with the result. + Process event and call `logging.Logger.debug` with the result. """ return self._proxy_to_logger("debug", event, *args, **kw) def info(self, event=None, *args, **kw): """ - Process event and call :meth:`logging.Logger.info` with the result. + Process event and call `logging.Logger.info` with the result. """ return self._proxy_to_logger("info", event, *args, **kw) def warning(self, event=None, *args, **kw): """ - Process event and call :meth:`logging.Logger.warning` with the result. + Process event and call `logging.Logger.warning` with the result. """ return self._proxy_to_logger("warning", event, *args, **kw) @@ -81,19 +83,19 @@ def warning(self, event=None, *args, **kw): def error(self, event=None, *args, **kw): """ - Process event and call :meth:`logging.Logger.error` with the result. + Process event and call `logging.Logger.error` with the result. """ return self._proxy_to_logger("error", event, *args, **kw) def critical(self, event=None, *args, **kw): """ - Process event and call :meth:`logging.Logger.critical` with the result. + Process event and call `logging.Logger.critical` with the result. """ return self._proxy_to_logger("critical", event, *args, **kw) def exception(self, event=None, *args, **kw): """ - Process event and call :meth:`logging.Logger.error` with the result, + Process event and call `logging.Logger.error` with the result, after setting ``exc_info`` to `True`. """ kw.setdefault("exc_info", True) @@ -101,8 +103,8 @@ def exception(self, event=None, *args, **kw): def log(self, level, event, *args, **kw): """ - Process event and call the appropriate logging method depending on - `level`. + Process *event* and call the appropriate logging method depending on + *level*. """ return self._proxy_to_logger(_LEVEL_TO_NAME[level], event, *args, **kw) @@ -113,7 +115,7 @@ def _proxy_to_logger(self, method_name, event, *event_args, **event_kw): Propagate a method call to the wrapped logger. This is the same as the superclass implementation, except that - it also preserves positional arguments in the `event_dict` so + it also preserves positional arguments in the ``event_dict`` so that the stdblib's support for format strings can be used. """ if event_args: @@ -292,21 +294,21 @@ def __call__(self, *args): class PositionalArgumentsFormatter(object): """ - Apply stdlib-like string formatting to the `event` key. + Apply stdlib-like string formatting to the ``event`` key. - If the `positional_args` key in the event dict is set, it must - contain a tuple that is used for formatting (using the `%s` string - formatting operator) of the value from the `event` key. This works + If the ``positional_args`` key in the event dict is set, it must + contain a tuple that is used for formatting (using the ``%s`` string + formatting operator) of the value from the ``event`` key. This works in the same way as the stdlib handles arguments to the various log methods: if the tuple contains only a single `dict` argument it is - used for keyword placeholders in the `event` string, otherwise it + used for keyword placeholders in the ``event`` string, otherwise it will be used for positional placeholders. - `positional_args` is populated by :class:`structlog.stdlib.BoundLogger` or + ``positional_args`` is populated by `structlog.stdlib.BoundLogger` or can be set manually. - The `remove_positional_args` flag can be set to `False` to keep the - `positional_args` key in the event dict; by default it will be + The *remove_positional_args* flag can be set to `False` to keep the + ``positional_args`` key in the event dict; by default it will be removed from the event dict after formatting a message. """ @@ -428,12 +430,12 @@ def add_logger_name(logger, method_name, event_dict): def render_to_log_kwargs(wrapped_logger, method_name, event_dict): """ - Render `event_dict` into keyword arguments for :func:`logging.log`. + Render ``event_dict`` into keyword arguments for `logging.log`. - The `event` field is translated into `msg` and the rest of the `event_dict` - is added as `extra`. + The ``event`` field is translated into ``msg`` and the rest of the + *event_dict* is added as ``extra``. - This allows you to defer formatting to :mod:`logging`. + This allows you to defer formatting to `logging`. .. versionadded:: 17.1.0 """ @@ -442,17 +444,17 @@ def render_to_log_kwargs(wrapped_logger, method_name, event_dict): class ProcessorFormatter(logging.Formatter): r""" - Call ``structlog`` processors on :class:`logging.LogRecord`\ s. + Call ``structlog`` processors on :`logging.LogRecord`\ s. - This :class:`logging.Formatter` allows to configure :mod:`logging` to call + This `logging.Formatter` allows to configure :mod:`logging` to call *processor* on ``structlog``-borne log entries (origin is determined solely - on the fact whether the ``msg`` field on the :class:`logging.LogRecord` is + on the fact whether the ``msg`` field on the `logging.LogRecord` is a dict or not). This allows for two interesting use cases: #. You can format non-``structlog`` log entries. - #. You can multiplex log records into multiple :class:`logging.Handler`\ s. + #. You can multiplex log records into multiple `logging.Handler`\ s. Please refer to :doc:`standard-library` for examples. @@ -461,9 +463,9 @@ class ProcessorFormatter(logging.Formatter): If not `None`, it is used as an iterable of processors that is applied to non-``structlog`` log entries before *processor*. If `None`, formatting is left to :mod:`logging`. (default: `None`) - :param bool keep_exc_info: ``exc_info`` on :class:`logging.LogRecord`\ s is + :param bool keep_exc_info: ``exc_info`` on `logging.LogRecord`\ s is added to the ``event_dict`` and removed afterwards. Set this to - ``True`` to keep it on the :class:`logging.LogRecord`. (default: False) + ``True`` to keep it on the `logging.LogRecord`. (default: False) :param bool keep_stack_info: Same as *keep_exc_info* except for Python 3's ``stack_info``. (default: False) :param logger: Logger which we want to push through the ``structlog`` @@ -556,11 +558,10 @@ def wrap_for_formatter(logger, name, event_dict): """ Wrap *logger*, *name*, and *event_dict*. - The result is later unpacked by :class:`ProcessorFormatter` when + The result is later unpacked by `ProcessorFormatter` when formatting log entries. Use this static method as the renderer (i.e. final processor) if you - want to use :class:`ProcessorFormatter` in your :mod:`logging` - configuration. + want to use `ProcessorFormatter` in your `logging` configuration. """ return (event_dict,), {"extra": {"_logger": logger, "_name": name}} diff --git a/src/structlog/testing.py b/src/structlog/testing.py index fc9ea52a..9bdfd2c9 100644 --- a/src/structlog/testing.py +++ b/src/structlog/testing.py @@ -22,7 +22,7 @@ class LogCapture(object): """ Class for capturing log messages in its entries list. - Generally you should use :func:`structlog.testing.capture_logs`, + Generally you should use `structlog.testing.capture_logs`, but you can use this class if you want to capture logs with other patterns. .. versionadded:: 20.1.0 @@ -58,9 +58,9 @@ def capture_logs(): class ReturnLoggerFactory(object): r""" - Produce and cache :class:`ReturnLogger`\ s. + Produce and cache `ReturnLogger`\ s. - To be used with :func:`structlog.configure`\ 's `logger_factory`. + To be used with `structlog.configure`\ 's *logger_factory*. Positional arguments are silently ignored. diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index c5e4a589..c4dddf89 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -5,7 +5,7 @@ """ Primitives to keep context global but thread (and greenlet) local. -See :doc:`thread-local`. +See `thread-local`. """ from __future__ import absolute_import, division, print_function diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index 67c39e8c..aed91e17 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -28,7 +28,7 @@ class BoundLogger(BoundLoggerBase): """ - Twisted-specific version of :class:`structlog.BoundLogger`. + Twisted-specific version of `structlog.BoundLogger`. Works exactly like the generic one except that it takes advantage of knowing the logging methods in advance. @@ -81,7 +81,7 @@ def __call__(self, *args): def _extractStuffAndWhy(eventDict): """ Removes all possible *_why*s and *_stuff*s, analyzes exc_info and returns - a tuple of `(_stuff, _why, eventDict)`. + a tuple of ``(_stuff, _why, eventDict)``. **Modifies** *eventDict*! """ @@ -112,9 +112,10 @@ def _extractStuffAndWhy(eventDict): class ReprWrapper(object): """ - Wrap a string and return it as the __repr__. + Wrap a string and return it as the ``__repr__``. - This is needed for log.err() that calls repr() on _stuff: + This is needed for ``twisted.python.log.err`` that calls `repr` on + ``_stuff``: >>> repr("foo") "'foo'" @@ -129,7 +130,7 @@ def __init__(self, string): def __eq__(self, other): """ - Check for equality, actually just for tests. + Check for equality, just for tests. """ return ( isinstance(other, self.__class__) and self.string == other.string @@ -141,24 +142,24 @@ def __repr__(self): class JSONRenderer(GenericJSONRenderer): """ - Behaves like :class:`structlog.processors.JSONRenderer` except that it - formats tracebacks and failures itself if called with `err()`. + Behaves like `structlog.processors.JSONRenderer` except that it + formats tracebacks and failures itself if called with ``err()``. .. note:: - This ultimately means that the messages get logged out using `msg()`, - and *not* `err()` which renders failures in separate lines. + This ultimately means that the messages get logged out using ``msg()``, + and *not* ``err()`` which renders failures in separate lines. Therefore it will break your tests that contain assertions using `flushLoggedErrors `_. - *Not* an adapter like :class:`EventAdapter` but a real formatter. Nor does - it require to be adapted using it. + *Not* an adapter like `EventAdapter` but a real formatter. Also does *not* + require to be adapted using it. - Use together with a :class:`JSONLogObserverWrapper`-wrapped Twisted logger - like :func:`plainJSONStdOutLogger` for pure-JSON logs. + Use together with a `JSONLogObserverWrapper`-wrapped Twisted logger like + `plainJSONStdOutLogger` for pure-JSON logs. """ def __call__(self, logger, name, eventDict): @@ -206,7 +207,7 @@ def __call__(self, eventDict): @implementer(ILogObserver) class JSONLogObserverWrapper(object): """ - Wrap a log *observer* and render non-:class:`JSONRenderer` entries to JSON. + Wrap a log *observer* and render non-`JSONRenderer` entries to JSON. :param ILogObserver observer: Twisted log observer to wrap. For example :class:`PlainFileObserver` or Twisted's stock `FileLogObserver @@ -237,7 +238,7 @@ def plainJSONStdOutLogger(): """ Return a logger that writes only the message to stdout. - Transforms non-:class:`~structlog.twisted.JSONRenderer` messages to JSON. + Transforms non-`JSONRenderer` messages to JSON. Ideal for JSONifying log entries from Twisted plugins and libraries that are outside of your control:: @@ -250,8 +251,8 @@ def plainJSONStdOutLogger(): {"event": "Starting factory ", ...} ... - Composes :class:`PlainFileLogObserver` and :class:`JSONLogObserverWrapper` - to a usable logger. + Composes `PlainFileLogObserver` and `JSONLogObserverWrapper` to a usable + logger. .. versionadded:: 0.2.0 """ @@ -270,7 +271,7 @@ class EventAdapter(object): log message. Please note that structlog comes with a dedicated :class:`JSONRenderer`. - **Must** be the last processor in the chain and requires a `dictRenderer` + **Must** be the last processor in the chain and requires a *dictRenderer* for the actual formatting as an constructor argument in order to be able to fully support the original behaviors of ``log.msg()`` and ``log.err()``. """ From 51e414e98bc2c4eafe12821f1c88750d3e0cfab4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 19 Jan 2020 16:09:47 +0100 Subject: [PATCH 0333/1520] Run Sphinx in nit-pick mode --- docs/Makefile | 2 +- docs/api.rst | 32 ++++++++++++++++---------------- docs/conf.py | 7 +++++++ src/structlog/_config.py | 4 ++-- src/structlog/_loggers.py | 6 ++++-- src/structlog/processors.py | 5 +++-- src/structlog/stdlib.py | 3 +-- src/structlog/twisted.py | 4 ++-- tox.ini | 4 ++-- 9 files changed, 38 insertions(+), 29 deletions(-) diff --git a/docs/Makefile b/docs/Makefile index 61b678e3..ba04941d 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -42,7 +42,7 @@ clean: -rm -rf $(BUILDDIR)/* html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + $(SPHINXBUILD) -n -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." diff --git a/docs/api.rst b/docs/api.rst index 6297572d..6633e832 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -23,8 +23,8 @@ API Reference .. module:: structlog -:mod:`structlog` Package ------------------------- +`structlog` Package +------------------- .. autofunction:: get_logger @@ -56,8 +56,8 @@ API Reference :members: new, bind, unbind, _logger, _process_event, _proxy_to_logger -:mod:`dev` Module ------------------ +`structlog.dev` Module +---------------------- .. automodule:: structlog.dev @@ -67,8 +67,8 @@ API Reference .. autofunction:: set_exc_info -:mod:`testing` Module ---------------------- +`structlog.testing` Module +-------------------------- .. automodule:: structlog.testing @@ -80,8 +80,8 @@ API Reference .. autoclass:: ReturnLoggerFactory -:mod:`threadlocal` Module -------------------------- +`structlog.threadlocal` Module +------------------------------ .. automodule:: structlog.threadlocal @@ -109,8 +109,8 @@ API Reference .. autofunction:: as_immutable -:mod:`contextvars` Module -------------------------- +`structlog.contextvars` Module +------------------------------ .. automodule:: structlog.contextvars @@ -122,8 +122,8 @@ API Reference .. _procs: -:mod:`processors` Module ------------------------- +`structlog.processors` Module +----------------------------- .. automodule:: structlog.processors @@ -201,8 +201,8 @@ API Reference {'year': '2013'} -:mod:`stdlib` Module --------------------- +`structlog.stdlib` Module +------------------------- .. automodule:: structlog.stdlib @@ -228,8 +228,8 @@ API Reference :members: wrap_for_formatter -:mod:`twisted` Module ---------------------- +`structlog.twisted` Module +-------------------------- .. automodule:: structlog.twisted diff --git a/docs/conf.py b/docs/conf.py index 2b97af17..96f63f0e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -101,6 +101,13 @@ def find_version(*file_paths): # documents. default_role = "any" +nitpick_ignore = [ + ("py:class", "callable"), + ("py:class", "file object"), + ("py:class", "ILogObserver"), + ("py:class", "PlainFileObserver"), +] + # If true, '()' will be appended to :func: etc. cross-reference text. # add_function_parentheses = True diff --git a/src/structlog/_config.py b/src/structlog/_config.py index da9a32a5..e990f7d8 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -112,7 +112,7 @@ def get_logger(*args, **initial_values): mean. :param initial_values: Values that are used to pre-populate your contexts. - :rtype: A proxy that creates a correctly configured bound logger when + :returns: A proxy that creates a correctly configured bound logger when necessary. See `configuration` for details. @@ -160,7 +160,7 @@ def wrap_logger( :param tuple logger_factory_args: Values that are passed unmodified as ``*logger_factory_args`` to the logger factory if not `None`. - :rtype: A proxy that creates a correctly configured bound logger when + :returns: A proxy that creates a correctly configured bound logger when necessary. See `configure` for the meaning of the rest of the arguments. diff --git a/src/structlog/_loggers.py b/src/structlog/_loggers.py index 9e259fe4..5293b418 100644 --- a/src/structlog/_loggers.py +++ b/src/structlog/_loggers.py @@ -22,7 +22,8 @@ class PrintLoggerFactory(object): To be used with `structlog.configure`\ 's ``logger_factory``. - :param file file: File to print to. (default: stdout) + :param file: File to print to. (default: stdout) + :type file: file object Positional arguments are silently ignored. @@ -54,7 +55,8 @@ class PrintLogger(object): """ Print events into a file. - :param file file: File to print to. (default: stdout) + :param file: File to print to. (default: stdout) + :type file: file object >>> from structlog import PrintLogger >>> PrintLogger().msg("hello") diff --git a/src/structlog/processors.py b/src/structlog/processors.py index fb5a5d46..e98201de 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -325,12 +325,13 @@ class ExceptionPrettyPrinter(object): """ Pretty print exceptions and remove them from the ``event_dict``. - :param file file: Target file for output (default: ``sys.stdout``). + :param file: Target file for output (default: ``sys.stdout``). + :type file: file object This processor is mostly for development and testing so you can read exceptions properly formatted. - It behaves like `format_exc_info` except it removes the exception + It behaves like format_exc_info` except it removes the exception data from the event dictionary after printing it. It's tolerant to having `format_exc_info` in front of itself in the diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 675b19bf..2430dd00 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -407,8 +407,7 @@ def add_log_level_number(logger, method_name, event_dict): level in ("warning", "error", "critical") level_number >= 30 - The mapping of names to numbers is in - :data:`~structlog.stdlib._NAME_TO_LEVEL`. + The mapping of names to numbers is in ``structlog.stdlib._NAME_TO_LEVEL``. .. versionadded:: 18.2.0 """ diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index aed91e17..0a5c9861 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -189,8 +189,8 @@ class PlainFileLogObserver(object): Great to just print JSON to stdout where you catch it with something like runit. - :param file file: File to print to. - + :param file: File to print to. + :type file: file object .. versionadded:: 0.2.0 """ diff --git a/tox.ini b/tox.ini index 455b0148..e6aab2dc 100644 --- a/tox.ini +++ b/tox.ini @@ -70,8 +70,8 @@ passenv = TERM setenv = PYTHONHASHSEED = 0 commands = - sphinx-build -W -b html -d {envtmpdir}/doctrees docs docs/_build/html - sphinx-build -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html + sphinx-build -n -T -W -b html -d {envtmpdir}/doctrees docs docs/_build/html + sphinx-build -n -T -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html [testenv:pypi-description] From 971a621a9bb582d79dd8cfe1df4c5b4bb75ee8ce Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 25 Jan 2020 12:07:19 +0100 Subject: [PATCH 0334/1520] Add pull request template --- .github/PULL_REQUEST_TEMPLATE.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..2648a078 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,14 @@ +# Pull Request Check List + +This is just a friendly reminder about the most common mistakes. Please make sure that you tick all boxes. But please read our [contribution guide](https://www.structlog.org/en/latest/contributing.html) at least once, it will save you unnecessary review cycles! + +If an item doesn't apply to your pull request, **check it anyway** to make it apparent that there's nothing left to do. + +- [ ] Added **tests** for changed code. +- [ ] Updated **documentation** for changed code. + - [ ] New functions/classes have to be added to `docs/api.rst` by hand. + - [ ] Changed/added classes/methods/functions have appropriate `versionadded`, `versionchanged`, or `deprecated` [directives](http://www.sphinx-doc.org/en/stable/markup/para.html#directive-versionadded). Find the appropriate next version in our [``__init__.py``](https://github.com/hynek/structlog/blob/master/src/structlog/__init__.py) file. +- [ ] Documentation in `.rst` files is written using [semantic newlines](https://rhodesmill.org/brandon/2012/one-sentence-per-line/). +- [ ] Changes (and possible deprecations) are documented in the [changelog](https://github.com/hynek/structlog/blob/master/CHANGELOG.rst). + +If you have *any* questions to *any* of the points above, just **submit and ask**! This checklist is here to *help* you, not to deter you from contributing! From ce4e51a5de0744b968a275da87946cc602a84864 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 25 Jan 2020 03:23:25 -0800 Subject: [PATCH 0335/1520] add unbind_threadlocal and try_unbind_threadlocal methods (#239) * add unbind_threadlocal and try_unbind_threadlocal methods for "new" threadlocal context * match threadlocal.unbind to contextvars.unbind behavior Co-authored-by: Hynek Schlawack --- src/structlog/threadlocal.py | 9 +++++++++ tests/test_threadlocal.py | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index c4dddf89..9b53dd49 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -216,6 +216,15 @@ def bind_threadlocal(**kwargs): _get_context().update(kwargs) +def unbind_threadlocal(*keys): + """ + Tries to remove bound *keys* from threadlocal logging context if present. + """ + context = _get_context() + for key in keys: + context.pop(key, None) + + def _get_context(): try: return _CONTEXT.context diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py index c9867230..7f0fb700 100644 --- a/tests/test_threadlocal.py +++ b/tests/test_threadlocal.py @@ -20,6 +20,7 @@ merge_threadlocal, merge_threadlocal_context, tmp_bind, + unbind_threadlocal, wrap_dict, ) @@ -316,3 +317,21 @@ def test_multiple_binds(self): assert {"a": 1, "b": 2, "c": 3} == merge_threadlocal( None, None, {"b": 2} ) + + def test_unbind_threadlocal(self): + """ + Test that unbinding from threadlocal works for keys that exist + and does not raise error when they do not exist. + + """ + + clear_threadlocal() + bind_threadlocal(a=234, b=34) + assert {"a": 234, "b": 34} == merge_threadlocal_context(None, None, {}) + + unbind_threadlocal("a") + + assert {"b": 34} == merge_threadlocal_context(None, None, {}) + + unbind_threadlocal("non-existing-key") + assert {"b": 34} == merge_threadlocal_context(None, None, {}) From 4dc1c6910995fd29e7d84baad0e595f557800f8c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 25 Jan 2020 12:34:02 +0100 Subject: [PATCH 0336/1520] Add changelog entry for #239 --- CHANGELOG.rst | 6 ++++-- src/structlog/threadlocal.py | 2 ++ tests/test_threadlocal.py | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 3ab315fd..6b97804e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -26,12 +26,14 @@ Changes: ^^^^^^^^ - Added a new module ``structlog.contextvars`` that allows to have a global but context-local ``structlog`` context the same way as with ``structlog.threadlocal`` since 19.2.0. - `#201 `_ + `#201 `_, `#236 `_ - Added a new module ``structlog.testing`` for first class testing support. The first entry is the context manager ``capture_logs()`` that allows to make assertions about structured log calls. - `#14 `_ + `#14 `_, `#234 `_ +- Added ``structlog.threadlocal.unbind_threadlocal()``. + `#239 `_ ---- diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index 9b53dd49..ed5f5ed3 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -219,6 +219,8 @@ def bind_threadlocal(**kwargs): def unbind_threadlocal(*keys): """ Tries to remove bound *keys* from threadlocal logging context if present. + + .. versionadded:: 20.1.0 """ context = _get_context() for key in keys: diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py index 7f0fb700..a0d54805 100644 --- a/tests/test_threadlocal.py +++ b/tests/test_threadlocal.py @@ -322,7 +322,6 @@ def test_unbind_threadlocal(self): """ Test that unbinding from threadlocal works for keys that exist and does not raise error when they do not exist. - """ clear_threadlocal() @@ -334,4 +333,5 @@ def test_unbind_threadlocal(self): assert {"b": 34} == merge_threadlocal_context(None, None, {}) unbind_threadlocal("non-existing-key") + assert {"b": 34} == merge_threadlocal_context(None, None, {}) From 9fe6a93ceaa2611817fedd88a716d34712f2259c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 25 Jan 2020 14:43:09 +0100 Subject: [PATCH 0337/1520] Prevent lazy logger to be detected as an abstract method Fixes #229 --- CHANGELOG.rst | 2 ++ src/structlog/_config.py | 2 ++ tests/test_config.py | 18 +++++++++++++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 6b97804e..c0eb807f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -34,6 +34,8 @@ Changes: `#234 `_ - Added ``structlog.threadlocal.unbind_threadlocal()``. `#239 `_ +- The logger created by ``structlog.get_logger()`` is not detected as an abstract method anymore when attached to an abstract base class. + `#229 `_, ---- diff --git a/src/structlog/_config.py b/src/structlog/_config.py index e990f7d8..03983f91 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -359,6 +359,8 @@ def __getattr__(self, name): If a logging method if called on a lazy proxy, we have to create an ephemeral BoundLogger first. """ + if name == "__isabstractmethod__": + raise AttributeError bl = self.bind() return getattr(bl, name) diff --git a/tests/test_config.py b/tests/test_config.py index 511facec..4d902bb1 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -4,6 +4,7 @@ from __future__ import absolute_import, division, print_function +import abc import pickle import platform import sys @@ -14,7 +15,7 @@ import pytest from pretend import call, call_recorder, stub -from six import PY3 +from six import PY3, add_metaclass import structlog @@ -47,6 +48,21 @@ class Wrapper(BoundLoggerBase): """ +def test_lazy_logger_is_not_detected_as_abstract_method(): + """ + If someone defines an attribute on an ABC with a logger, that logger is not + detected as an abstract method. + + See https://github.com/hynek/structlog/issues/229 + """ + + @add_metaclass(abc.ABCMeta) + class Foo(object): + log = structlog.get_logger() + + Foo() + + def test_default_context_class(): """ Default context class is dict on Python 3.6+ and PyPy, OrderedDict From e0d8f45f9b97efecbb66d18f2009906d3f496a2a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 25 Jan 2020 14:52:42 +0100 Subject: [PATCH 0338/1520] Add a comma for readability --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c0eb807f..afd77e9d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -34,7 +34,7 @@ Changes: `#234 `_ - Added ``structlog.threadlocal.unbind_threadlocal()``. `#239 `_ -- The logger created by ``structlog.get_logger()`` is not detected as an abstract method anymore when attached to an abstract base class. +- The logger created by ``structlog.get_logger()`` is not detected as an abstract method anymore, when attached to an abstract base class. `#229 `_, From 5072caced858a834bf7d205e96a887bf03e1f82a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 25 Jan 2020 14:55:59 +0100 Subject: [PATCH 0339/1520] Remove trailing comma --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index afd77e9d..a6d9d3e7 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -35,7 +35,7 @@ Changes: - Added ``structlog.threadlocal.unbind_threadlocal()``. `#239 `_ - The logger created by ``structlog.get_logger()`` is not detected as an abstract method anymore, when attached to an abstract base class. - `#229 `_, + `#229 `_ ---- From a1da7e5bfb475b061aad073d3e8c9d01e25a42b2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 28 Jan 2020 11:56:50 +0100 Subject: [PATCH 0340/1520] Don't be lazy on Windows (#242) * Don't be lazy on Windows Fixes #232 * Add PR # --- CHANGELOG.rst | 3 +++ src/structlog/dev.py | 29 ++++++++++++++++++++--------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a6d9d3e7..9ef2e153 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -36,6 +36,9 @@ Changes: `#239 `_ - The logger created by ``structlog.get_logger()`` is not detected as an abstract method anymore, when attached to an abstract base class. `#229 `_ +- ``colorama`` isn't initialized lazily on Windows anymore because it breaks rendering. + `#232 `_, + `#242 `_ ---- diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 14c8df1a..d036569b 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -8,6 +8,8 @@ from __future__ import absolute_import, division, print_function +import sys + from six import PY2, StringIO, string_types @@ -19,6 +21,7 @@ __all__ = ["ConsoleRenderer"] +_IS_WINDOWS = sys.platform == "win32" _MISSING = "{who} requires the {package} package installed. " _EVENT_WIDTH = 30 # pad the event name to so many characters @@ -125,6 +128,8 @@ class ConsoleRenderer(object): ``colorama`` now initializes lazily to avoid unwanted initializations as ``ConsoleRenderer`` is used by default. .. versionchanged:: 19.2 Can be pickled now. + .. versionchanged:: 20.1 ``colorama`` does not initialize lazily on Windows + anymore because it breaks rendering. """ def __init__( @@ -145,9 +150,12 @@ def __init__( ) ) - self._init_colorama = True - if force_colors: - self._force_colors = True + if _IS_WINDOWS: # pragma: no cover + _init_colorama(self._force_colors) + else: + self._init_colorama = True + if force_colors: + self._force_colors = True styles = _ColorfulStyles else: @@ -185,12 +193,7 @@ def _repr(self, val): def __call__(self, _, __, event_dict): # Initialize lazily to prevent import side-effects. if self._init_colorama: - if self._force_colors: - colorama.deinit() - colorama.init(strip=False) - else: - colorama.init() - + _init_colorama(self._force_colors) self._init_colorama = False sio = StringIO() @@ -291,6 +294,14 @@ def get_default_level_styles(colors=True): } +def _init_colorama(force): + if force: + colorama.deinit() + colorama.init(strip=False) + else: + colorama.init() + + _SENTINEL = object() From 8f03c4a602f8873567a7bc75133159e178ba3e47 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 28 Jan 2020 12:10:49 +0100 Subject: [PATCH 0341/1520] Make pip install -e . work on Windows (#243) --- azure-pipelines.yml | 23 +++++++++++++++++++++++ setup.py | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f17dd14e..06ee73e6 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -126,3 +126,26 @@ jobs: CODECOV_TOKEN: $(codecov.token) displayName: Report Coverage condition: succeeded() + + + # Make sure contributors can use Windows. + - job: 'Windows' + pool: + vmImage: 'windows-latest' + strategy: + matrix: + py38: + python.version: '3.8' + + steps: + - task: UsePythonVersion@0 + inputs: + versionSpec: '$(python.version)' + architecture: 'x64' + displayName: Use cached Python $(python.version) for tests. + + - script: python -m pip install -e .[dev] + displayName: Install package in dev mode. + + - script: python -m pytest + displayName: Run tests. diff --git a/setup.py b/setup.py index 2cbffc38..c407eda4 100644 --- a/setup.py +++ b/setup.py @@ -98,7 +98,7 @@ def find_meta(meta): + "Release Information\n" + "===================\n\n" + re.search( - r"(\d+.\d.\d \(.*?\)\n.*?)\n\n\n----\n\n\n", + r"(\d+.\d.\d \(.*?\)\r?\n.*?)\r?\n\r?\n\r?\n----\r?\n\r?\n\r?\n", read("CHANGELOG.rst"), re.S, ).group(1) From 81fefd78e7b610cbebe3d850884a71a44d70acef Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 28 Jan 2020 12:35:07 +0100 Subject: [PATCH 0342/1520] Prepare 20.1.0 --- CHANGELOG.rst | 2 +- src/structlog/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9ef2e153..03560309 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,7 +5,7 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. -20.1.0 (UNRELEASED) +20.1.0 (2020-01-28) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 4f52ae01..2f24fc63 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -32,7 +32,7 @@ twisted = None -__version__ = "20.1.0.dev0" +__version__ = "20.1.0" __title__ = "structlog" __description__ = "Structured Logging for Python" From 40a2d628fed56e1cafcf85ebadc46f8f575e5abe Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 28 Jan 2020 12:43:59 +0100 Subject: [PATCH 0343/1520] Start new development cycle --- CHANGELOG.rst | 25 +++++++++++++++++++++++++ src/structlog/__init__.py | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 03560309..7e9c913d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,31 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. +20.2.0 (UNRELEASED) +------------------- + + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +*none* + + +Deprecations: +^^^^^^^^^^^^^ + +*none* + + +Changes: +^^^^^^^^ + +*none* + + +---- + + 20.1.0 (2020-01-28) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 2f24fc63..cd1c294c 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -32,7 +32,7 @@ twisted = None -__version__ = "20.1.0" +__version__ = "20.2.0.dev0" __title__ = "structlog" __description__ = "Structured Logging for Python" From f65309d4f66fbd44c09288a485107d725c3da1d4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 28 Jan 2020 19:08:30 +0100 Subject: [PATCH 0344/1520] Drop support for Python 2.7 and 3.5 (#244) * Drop support for Python 2.7 and 3.5 * Add PR # --- CHANGELOG.rst | 4 +- README.rst | 5 +- azure-pipelines.yml | 40 ++++------------ conftest.py | 17 ++++--- .../processors/conditional_dropper.py | 2 +- docs/code_examples/twisted_echo.py | 2 +- docs/conf.py | 18 +++---- docs/getting-started.rst | 2 +- pyproject.toml | 2 +- setup.py | 13 +++-- src/structlog/__init__.py | 1 - src/structlog/_base.py | 9 ++-- src/structlog/_config.py | 18 ++----- src/structlog/_frames.py | 4 +- src/structlog/_generic.py | 1 - src/structlog/_loggers.py | 7 ++- src/structlog/_utils.py | 3 +- src/structlog/contextvars.py | 1 - src/structlog/dev.py | 12 ++--- src/structlog/processors.py | 22 ++++----- src/structlog/stdlib.py | 38 ++++++--------- src/structlog/testing.py | 6 +-- src/structlog/threadlocal.py | 7 ++- src/structlog/twisted.py | 19 ++++---- tests/additional_frame.py | 2 - tests/test_base.py | 7 ++- tests/test_config.py | 19 ++++---- tests/test_contextvars.py | 2 +- tests/test_dev.py | 28 ++--------- tests/test_frames.py | 7 ++- tests/test_generic.py | 7 +-- tests/test_loggers.py | 9 ++-- tests/test_processors.py | 46 +++++++----------- tests/test_stdlib.py | 26 +++++----- tests/test_testing.py | 9 ++-- tests/test_threadlocal.py | 9 ++-- tests/test_twisted.py | 47 +++++-------------- tests/test_utils.py | 5 +- tests/utils.py | 8 ---- tox.ini | 21 +++------ 40 files changed, 178 insertions(+), 327 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7e9c913d..df887578 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,7 +12,9 @@ The third digit is only for regressions. Backward-incompatible changes: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -*none* +- Python 2.7 and 3.5 aren't supported anymore. + The package meta data should ensure that you keep getting 20.1.0 on those versions. + `#244 `_ Deprecations: diff --git a/README.rst b/README.rst index 3beca1e2..1e8bedde 100644 --- a/README.rst +++ b/README.rst @@ -139,4 +139,7 @@ Project Information We collect useful third party extension in `our wiki `_. -``structlog`` targets Python 2.7, 3.5 and newer, and PyPy. +``structlog`` targets Python 3.6 and newer, and PyPy3. + +If you need support for older Python versions, the last release with support for Python 2.7 and 3.5 was `20.1.0 `_. +The package meta data should ensure that you get the correct version. diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 06ee73e6..c16af9b5 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,4 +1,4 @@ - +--- # Don't have two build jobs for each pull request. trigger: - master @@ -16,48 +16,27 @@ jobs: tox.env: manifest python.version: '3.7' - py27-colorama: - tox.env: py27-colorama - python.version: '2.7' - py27-greenlets: - tox.env: py27-greenlets - python.version: '2.7' - py27-threads: - tox.env: py27-threads - python.version: '2.7' - py35-threads: - tox.env: py35-threads - python.version: '3.5' py36-threads: tox.env: py36-threads python.version: '3.6' - py37-colorama: - tox.env: py37-colorama - python.version: '3.7' - py37-greenlets: - tox.env: py37-greenlets - python.version: '3.7' py37-threads: tox.env: py37-threads python.version: '3.7' py38-threads: tox.env: py38-threads python.version: '3.8' + pypy3-threads: + tox.env: pypy3-threads + python.version: pypy3 py38-greenlets: tox.env: py38-greenlets python.version: '3.8' - pypy-colorama: - tox.env: pypy-colorama - python.version: pypy2 - pypy-greenlets: - tox.env: pypy-greenlets - python.version: pypy2 - pypy-threads: - tox.env: pypy-threads - python.version: pypy2 - pypy3-threads: - tox.env: pypy3-threads + pypy3-greenlets: + tox.env: pypy3-greenlets python.version: pypy3 + py38-colorama: + tox.env: py38-colorama + python.version: '3.8' Docs: python.version: '3.7' @@ -107,7 +86,6 @@ jobs: PATH=$HOME/.local/bin:$PATH case "$(python.version)" in - "pypy2") PY=pypy ;; "pypy3") PY=pypy3 ;; *) PY=python$(python.version) ;; esac diff --git a/conftest.py b/conftest.py index c32e1eb8..e4767b2f 100644 --- a/conftest.py +++ b/conftest.py @@ -1,20 +1,23 @@ -# -*- coding: utf-8 -*- - # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. -from __future__ import absolute_import, division, print_function import sys -import pytest +from io import StringIO -from six.moves import cStringIO as StringIO +import pytest from structlog.stdlib import _NAME_TO_LEVEL +try: + import twisted +except ImportError: + twisted = None + + @pytest.fixture def sio(): """ @@ -29,7 +32,7 @@ def event_dict(): An example event dictionary with multiple value types w/o the event itself. """ - class A(object): + class A: def __repr__(self): return r"" @@ -47,3 +50,5 @@ def fixture_stdlib_log_methods(request): collect_ignore = [] if sys.version_info[:2] < (3, 7): collect_ignore.append("tests/test_contextvars.py") +if twisted is None: + collect_ignore.append("tests/test_twisted.py") diff --git a/docs/code_examples/processors/conditional_dropper.py b/docs/code_examples/processors/conditional_dropper.py index c40022dd..e22034da 100644 --- a/docs/code_examples/processors/conditional_dropper.py +++ b/docs/code_examples/processors/conditional_dropper.py @@ -1,7 +1,7 @@ from structlog import DropEvent -class ConditionalDropper(object): +class ConditionalDropper: def __init__(self, peer_to_ignore): self._peer_to_ignore = peer_to_ignore diff --git a/docs/code_examples/twisted_echo.py b/docs/code_examples/twisted_echo.py index 48100365..cf4b803b 100644 --- a/docs/code_examples/twisted_echo.py +++ b/docs/code_examples/twisted_echo.py @@ -11,7 +11,7 @@ logger = structlog.getLogger() -class Counter(object): +class Counter: i = 0 def inc(self): diff --git a/docs/conf.py b/docs/conf.py index 96f63f0e..9d6ecc45 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. @@ -70,9 +68,9 @@ def find_version(*file_paths): master_doc = "index" # General information about the project. -project = u"structlog" -author = u"Hynek Schlawack" -copyright = u"2013, {author}".format(author=author) +project = "structlog" +author = "Hynek Schlawack" +copyright = f"2013, {author}" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -229,7 +227,7 @@ def find_version(*file_paths): # (source start file, target name, title, author, documentclass # [howto/manual]). latex_documents = [ - ("index", "structlog.tex", u"structlog Documentation", u"Author", "manual") + ("index", "structlog.tex", "structlog Documentation", "Author", "manual") ] # The name of an image file (relative to this directory) to place at the top of @@ -257,9 +255,7 @@ def find_version(*file_paths): # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - ("index", "structlog", u"structlog Documentation", [u"Author"], 1) -] +man_pages = [("index", "structlog", "structlog Documentation", ["Author"], 1)] # If true, show URL addresses after external links. # man_show_urls = False @@ -274,8 +270,8 @@ def find_version(*file_paths): ( "index", "structlog", - u"structlog Documentation", - u"Author", + "structlog Documentation", + "Author", "structlog", "One line description of project.", "Miscellaneous", diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 63175032..08d9cb59 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -49,7 +49,7 @@ Using the defaults, as above, is equivalent to:: structlog.dev.ConsoleRenderer() ], wrapper_class=structlog.BoundLogger, - context_class=dict, # or OrderedDict if the runtime's dict is unordered (e.g. Python <3.6) + context_class=dict, logger_factory=structlog.PrintLoggerFactory(), cache_logger_on_first_use=False ) diff --git a/pyproject.toml b/pyproject.toml index abfe6401..8449db9f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,4 +28,4 @@ multi_line_output=3 not_skip="__init__.py" known_first_party="structlog" -known_third_party=["flask", "freezegun", "pretend", "pytest", "setuptools", "six", "some_module", "structlog", "twisted", "zope"] +known_third_party=["flask", "freezegun", "pretend", "pytest", "setuptools", "some_module", "structlog", "twisted", "zope"] diff --git a/setup.py b/setup.py index c407eda4..a7e9c232 100644 --- a/setup.py +++ b/setup.py @@ -20,10 +20,7 @@ "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", @@ -32,7 +29,8 @@ "Programming Language :: Python", "Topic :: Software Development :: Libraries :: Python Modules", ] -INSTALL_REQUIRES = ["six"] +PYTHON_REQUIRES = ">=3.6" +INSTALL_REQUIRES = [] EXTRAS_REQUIRE = { "tests": [ "coverage[toml]", @@ -40,7 +38,7 @@ "pretend", "pytest>=3.3.0", "pytest-asyncio; python_version>='3.7'", - "python-rapidjson; python_version>='3.6'", + "python-rapidjson", "simplejson", ], "docs": ["sphinx", "twisted"], @@ -84,11 +82,11 @@ def find_meta(meta): Extract __*meta*__ from META_FILE. """ meta_match = re.search( - r"^__{meta}__ = ['\"]([^'\"]*)['\"]".format(meta=meta), META_FILE, re.M + fr"^__{meta}__ = ['\"]([^'\"]*)['\"]", META_FILE, re.M ) if meta_match: return meta_match.group(1) - raise RuntimeError("Unable to find __{meta}__ string.".format(meta=meta)) + raise RuntimeError(f"Unable to find __{meta}__ string.") VERSION = find_meta("version") @@ -124,6 +122,7 @@ def find_meta(meta): packages=PACKAGES, package_dir={"": "src"}, classifiers=CLASSIFIERS, + python_requires=PYTHON_REQUIRES, install_requires=INSTALL_REQUIRES, extras_require=EXTRAS_REQUIRE, zip_safe=False, diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index cd1c294c..fdd703e4 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -6,7 +6,6 @@ Structured logging for Python. """ -from __future__ import absolute_import, division, print_function from structlog import dev, processors, stdlib, testing, threadlocal from structlog._base import BoundLoggerBase diff --git a/src/structlog/_base.py b/src/structlog/_base.py index 084da1bc..f455a226 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -6,14 +6,11 @@ Logger wrapper and helper class. """ -from __future__ import absolute_import, division, print_function - -from six import string_types from structlog.exceptions import DropEvent -class BoundLoggerBase(object): +class BoundLoggerBase: """ Immutable context carrier. @@ -43,7 +40,7 @@ def __init__(self, logger, processors, context): self._context = context def __repr__(self): - return "<{0}(context={1!r}, processors={2!r})>".format( + return "<{}(context={!r}, processors={!r})>".format( self.__class__.__name__, self._context, self._processors ) @@ -147,7 +144,7 @@ def _process_event(self, method_name, event, event_kw): event_dict["event"] = event for proc in self._processors: event_dict = proc(self._logger, method_name, event_dict) - if isinstance(event_dict, string_types): + if isinstance(event_dict, str): return (event_dict,), {} elif isinstance(event_dict, tuple): # In this case we assume that the last processor returned a tuple diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 03983f91..5557d9b3 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -6,14 +6,9 @@ Global state department. Don't reload this module or everything breaks. """ -from __future__ import absolute_import, division, print_function -import platform -import sys import warnings -from collections import OrderedDict - from ._generic import BoundLogger from ._loggers import PrintLoggerFactory from .dev import ConsoleRenderer, _has_colorama, set_exc_info @@ -32,20 +27,13 @@ TimeStamper(fmt="%Y-%m-%d %H:%M.%S", utc=False), ConsoleRenderer(colors=_has_colorama), ] -if ( - sys.version_info[:2] >= (3, 6) - or platform.python_implementation() == "PyPy" -): - # Python 3.6+ and PyPy have ordered dicts. - _BUILTIN_DEFAULT_CONTEXT_CLASS = dict -else: - _BUILTIN_DEFAULT_CONTEXT_CLASS = OrderedDict +_BUILTIN_DEFAULT_CONTEXT_CLASS = dict _BUILTIN_DEFAULT_WRAPPER_CLASS = BoundLogger _BUILTIN_DEFAULT_LOGGER_FACTORY = PrintLoggerFactory() _BUILTIN_CACHE_LOGGER_ON_FIRST_USE = False -class _Configuration(object): +class _Configuration: """ Global defaults. """ @@ -257,7 +245,7 @@ def reset_defaults(): _CONFIG.cache_logger_on_first_use = _BUILTIN_CACHE_LOGGER_ON_FIRST_USE -class BoundLoggerLazyProxy(object): +class BoundLoggerLazyProxy: """ Instantiates a ``BoundLogger`` on first usage. diff --git a/src/structlog/_frames.py b/src/structlog/_frames.py index 6350d1d8..a4899d08 100644 --- a/src/structlog/_frames.py +++ b/src/structlog/_frames.py @@ -2,12 +2,10 @@ # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. -from __future__ import absolute_import, division, print_function - import sys import traceback -from six.moves import cStringIO as StringIO +from io import StringIO def _format_exception(exc_info): diff --git a/src/structlog/_generic.py b/src/structlog/_generic.py index dfc73d22..77f2d7b7 100644 --- a/src/structlog/_generic.py +++ b/src/structlog/_generic.py @@ -6,7 +6,6 @@ Generic bound logger that can wrap anything. """ -from __future__ import absolute_import, division, print_function from functools import partial diff --git a/src/structlog/_loggers.py b/src/structlog/_loggers.py index 5293b418..c36dba98 100644 --- a/src/structlog/_loggers.py +++ b/src/structlog/_loggers.py @@ -6,7 +6,6 @@ Logger wrapper and helper class. """ -from __future__ import absolute_import, division, print_function import sys import threading @@ -16,7 +15,7 @@ from structlog._utils import until_not_interrupted -class PrintLoggerFactory(object): +class PrintLoggerFactory: r""" Produce `PrintLogger`\ s. @@ -51,7 +50,7 @@ def _get_lock_for_file(file): return lock -class PrintLogger(object): +class PrintLogger: """ Print events into a file. @@ -104,7 +103,7 @@ def __setstate__(self, state): self._lock = _get_lock_for_file(self._file) def __repr__(self): - return "".format(self._file) + return f"" def msg(self, message): """ diff --git a/src/structlog/_utils.py b/src/structlog/_utils.py index b601b0d7..77f5a44c 100644 --- a/src/structlog/_utils.py +++ b/src/structlog/_utils.py @@ -6,7 +6,6 @@ Generic utilities. """ -from __future__ import absolute_import, division, print_function import errno @@ -22,7 +21,7 @@ def until_not_interrupted(f, *args, **kw): while True: try: return f(*args, **kw) - except (IOError, OSError) as e: + except OSError as e: if e.args[0] == errno.EINTR: continue raise diff --git a/src/structlog/contextvars.py b/src/structlog/contextvars.py index 4fc0bd6b..77d6bb61 100644 --- a/src/structlog/contextvars.py +++ b/src/structlog/contextvars.py @@ -11,7 +11,6 @@ See :doc:`contextvars`. """ -from __future__ import absolute_import, division, print_function import contextvars diff --git a/src/structlog/dev.py b/src/structlog/dev.py index d036569b..dd95a324 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -6,11 +6,9 @@ Helpers that make development with ``structlog`` more pleasant. """ -from __future__ import absolute_import, division, print_function - import sys -from six import PY2, StringIO, string_types +from io import StringIO try: @@ -56,7 +54,7 @@ def _pad(s, l): ) = DIM = RED = BLUE = CYAN = MAGENTA = YELLOW = GREEN = RED_BACK = "" -class _ColorfulStyles(object): +class _ColorfulStyles: reset = RESET_ALL bright = BRIGHT @@ -74,7 +72,7 @@ class _ColorfulStyles(object): kv_value = MAGENTA -class _PlainStyles(object): +class _PlainStyles: reset = "" bright = "" @@ -92,7 +90,7 @@ class _PlainStyles(object): kv_value = "" -class ConsoleRenderer(object): +class ConsoleRenderer: """ Render ``event_dict`` nicely aligned, possibly in colors, and ordered. @@ -218,7 +216,7 @@ def __call__(self, _, __, event_dict): # force event to str for compatibility with standard library event = event_dict.pop("event") - if not PY2 or not isinstance(event, string_types): + if not isinstance(event, str): event = str(event) if event_dict: diff --git a/src/structlog/processors.py b/src/structlog/processors.py index e98201de..95071132 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -6,16 +6,12 @@ Processors useful regardless of the logging framework. """ -from __future__ import absolute_import, division, print_function - import datetime import json import operator import sys import time -import six - from structlog._frames import ( _find_first_app_frame_and_name, _format_exception, @@ -23,7 +19,7 @@ ) -class KeyValueRenderer(object): +class KeyValueRenderer: """ Render ``event_dict`` as a list of ``Key=repr(Value)`` pairs. @@ -101,7 +97,7 @@ def __call__(self, _, __, event_dict): ) -class UnicodeEncoder(object): +class UnicodeEncoder: """ Encode unicode values in ``event_dict``. @@ -121,12 +117,12 @@ def __init__(self, encoding="utf-8", errors="backslashreplace"): def __call__(self, logger, name, event_dict): for key, value in event_dict.items(): - if isinstance(value, six.text_type): + if isinstance(value, str): event_dict[key] = value.encode(self._encoding, self._errors) return event_dict -class UnicodeDecoder(object): +class UnicodeDecoder: """ Decode byte string values in ``event_dict``. @@ -153,7 +149,7 @@ def __call__(self, logger, name, event_dict): return event_dict -class JSONRenderer(object): +class JSONRenderer: """ Render the ``event_dict`` using ``serializer(event_dict, **json_kw)``. @@ -227,7 +223,7 @@ def format_exc_info(logger, name, event_dict): return event_dict -class TimeStamper(object): +class TimeStamper: """ Add a timestamp to ``event_dict``. @@ -311,7 +307,7 @@ def _figure_out_exc_info(v): :rtype: tuple """ - if six.PY3 and isinstance(v, BaseException): + if isinstance(v, BaseException): return (v.__class__, v, v.__traceback__) elif isinstance(v, tuple): return v @@ -321,7 +317,7 @@ def _figure_out_exc_info(v): return v -class ExceptionPrettyPrinter(object): +class ExceptionPrettyPrinter: """ Pretty print exceptions and remove them from the ``event_dict``. @@ -361,7 +357,7 @@ def __call__(self, logger, name, event_dict): return event_dict -class StackInfoRenderer(object): +class StackInfoRenderer: """ Add stack information with key ``stack`` if ``stack_info`` is `True`. diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 2430dd00..edaeccdd 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -9,12 +9,8 @@ See also :doc:`structlog's standard library support `. """ -from __future__ import absolute_import, division, print_function - import logging -from six import PY3 - from structlog._base import BoundLoggerBase from structlog._frames import _find_first_app_frame_and_name, _format_stack from structlog.exceptions import DropEvent @@ -34,14 +30,11 @@ def findCaller(self, stack_info=False, stacklevel=1): This logger gets set as the default one when using LoggerFactory. """ f, name = _find_first_app_frame_and_name(["logging"]) - if PY3: - if stack_info: - sinfo = _format_stack(f) - else: - sinfo = None - return f.f_code.co_filename, f.f_lineno, f.f_code.co_name, sinfo + if stack_info: + sinfo = _format_stack(f) else: - return f.f_code.co_filename, f.f_lineno, f.f_code.co_name + sinfo = None + return f.f_code.co_filename, f.f_lineno, f.f_code.co_name, sinfo class BoundLogger(BoundLoggerBase): @@ -120,9 +113,7 @@ def _proxy_to_logger(self, method_name, event, *event_args, **event_kw): """ if event_args: event_kw["positional_args"] = event_args - return super(BoundLogger, self)._proxy_to_logger( - method_name, event=event, **event_kw - ) + return super()._proxy_to_logger(method_name, event=event, **event_kw) # # Pass-through attributes and methods to mimick the stdlib's logger @@ -245,7 +236,7 @@ def getChild(self, suffix): return self._logger.getChild(suffix) -class LoggerFactory(object): +class LoggerFactory: """ Build a standard library logger when an *instance* is called. @@ -292,7 +283,7 @@ def __call__(self, *args): return logging.getLogger(name) -class PositionalArgumentsFormatter(object): +class PositionalArgumentsFormatter: """ Apply stdlib-like string formatting to the ``event`` key. @@ -352,11 +343,11 @@ def __call__(self, _, __, event_dict): "notset": NOTSET, } -_LEVEL_TO_NAME = dict( - (v, k) +_LEVEL_TO_NAME = { + v: k for k, v in _NAME_TO_LEVEL.items() if k not in ("warn", "exception", "notset") -) +} def filter_by_level(logger, name, event_dict): @@ -493,12 +484,11 @@ def __init__( **kwargs ): fmt = kwargs.pop("fmt", "%(message)s") - super(ProcessorFormatter, self).__init__(*args, fmt=fmt, **kwargs) + super().__init__(*args, fmt=fmt, **kwargs) self.processor = processor self.foreign_pre_chain = foreign_pre_chain self.keep_exc_info = keep_exc_info - # The and clause saves us checking for PY3 in the formatter. - self.keep_stack_info = keep_stack_info and PY3 + self.keep_stack_info = keep_stack_info self.logger = logger self.pass_foreign_args = pass_foreign_args @@ -533,7 +523,7 @@ def format(self, record): # append stacktraces to the output. if record.exc_info: ed["exc_info"] = record.exc_info - if PY3 and record.stack_info: + if record.stack_info: ed["stack_info"] = record.stack_info if not self.keep_exc_info: @@ -550,7 +540,7 @@ def format(self, record): del ed["_record"] record.msg = self.processor(logger, meth_name, ed) - return super(ProcessorFormatter, self).format(record) + return super().format(record) @staticmethod def wrap_for_formatter(logger, name, event_dict): diff --git a/src/structlog/testing.py b/src/structlog/testing.py index 9bdfd2c9..205a9c7a 100644 --- a/src/structlog/testing.py +++ b/src/structlog/testing.py @@ -19,7 +19,7 @@ __all__ = ["LogCapture", "capture_logs"] -class LogCapture(object): +class LogCapture: """ Class for capturing log messages in its entries list. Generally you should use `structlog.testing.capture_logs`, @@ -56,7 +56,7 @@ def capture_logs(): configure(processors=old_processors) -class ReturnLoggerFactory(object): +class ReturnLoggerFactory: r""" Produce and cache `ReturnLogger`\ s. @@ -74,7 +74,7 @@ def __call__(self, *args): return self._logger -class ReturnLogger(object): +class ReturnLogger: """ Return the arguments that it's called with. diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index ed5f5ed3..b667416d 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -8,7 +8,6 @@ See `thread-local`. """ -from __future__ import absolute_import, division, print_function import contextlib import threading @@ -24,7 +23,7 @@ else: from weakref import WeakKeyDictionary - class ThreadLocal(object): + class ThreadLocal: """ threading.local() replacement for greenlets. """ @@ -104,7 +103,7 @@ def tmp_bind(logger, **tmp_values): logger._context.update(saved) -class _ThreadLocalDictWrapper(object): +class _ThreadLocalDictWrapper: """ Wrap a dict-like class and keep the state *global* but *thread-local*. @@ -139,7 +138,7 @@ def _dict(self): return self.__class__._tl.dict_ def __repr__(self): - return "<{0}({1!r})>".format(self.__class__.__name__, self._dict) + return f"<{self.__class__.__name__}({self._dict!r})>" def __eq__(self, other): # Same class == same dictionary diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index 0a5c9861..fd2b442c 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -9,12 +9,10 @@ See also :doc:`structlog's Twisted support `. """ -from __future__ import absolute_import, division, print_function import json import sys -from six import PY2, string_types from twisted.python import log from twisted.python.failure import Failure from twisted.python.log import ILogObserver, textFromEventDict @@ -54,7 +52,7 @@ def err(self, event=None, **kw): return self._proxy_to_logger("err", event, **kw) -class LoggerFactory(object): +class LoggerFactory: """ Build a Twisted logger when an *instance* is called. @@ -91,13 +89,13 @@ def _extractStuffAndWhy(eventDict): if isinstance(_stuff, _FAIL_TYPES) and isinstance(event, _FAIL_TYPES): raise ValueError("Both _stuff and event contain an Exception/Failure.") # `log.err('event', _why='alsoEvent')` is ambiguous. - if _why and isinstance(event, string_types): + if _why and isinstance(event, str): raise ValueError("Both `_why` and `event` supplied.") # Two failures are ambiguous too. if not isinstance(_stuff, _FAIL_TYPES) and isinstance(event, _FAIL_TYPES): _why = _why or "error" _stuff = event - if isinstance(event, string_types): + if isinstance(event, str): _why = event if not _stuff and sys.exc_info() != (None, None, None): _stuff = Failure() @@ -105,12 +103,11 @@ def _extractStuffAndWhy(eventDict): # formatting. Avoid log.err() to dump another traceback into the log. if isinstance(_stuff, BaseException) and not isinstance(_stuff, Failure): _stuff = Failure(_stuff) - if PY2: - sys.exc_clear() + return _stuff, _why, eventDict -class ReprWrapper(object): +class ReprWrapper: """ Wrap a string and return it as the ``__repr__``. @@ -182,7 +179,7 @@ def __call__(self, logger, name, eventDict): @implementer(ILogObserver) -class PlainFileLogObserver(object): +class PlainFileLogObserver: """ Write only the the plain message without timestamps or anything else. @@ -205,7 +202,7 @@ def __call__(self, eventDict): @implementer(ILogObserver) -class JSONLogObserverWrapper(object): +class JSONLogObserverWrapper: """ Wrap a log *observer* and render non-`JSONRenderer` entries to JSON. @@ -259,7 +256,7 @@ def plainJSONStdOutLogger(): return JSONLogObserverWrapper(PlainFileLogObserver(sys.stdout)) -class EventAdapter(object): +class EventAdapter: """ Adapt an ``event_dict`` to Twisted logging system. diff --git a/tests/additional_frame.py b/tests/additional_frame.py index c8ee8ebe..c7a46a60 100644 --- a/tests/additional_frame.py +++ b/tests/additional_frame.py @@ -9,8 +9,6 @@ to skip a frame. Calling them here emulates that. """ -from __future__ import absolute_import, division, print_function - def additional_frame(callable): return callable() diff --git a/tests/test_base.py b/tests/test_base.py index c9040f27..008a9f69 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -2,7 +2,6 @@ # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. -from __future__ import absolute_import, division, print_function import pytest @@ -26,7 +25,7 @@ def build_bl(logger=None, processors=None, context=None): ) -class TestBinding(object): +class TestBinding: def test_repr(self): bl = build_bl(processors=[1, 2, 3], context={}) @@ -115,7 +114,7 @@ def test_try_unbind_fail(self): assert {"y": 23} == b._context -class TestProcessing(object): +class TestProcessing: def test_event_empty_string(self): """ Empty strings are a valid event. @@ -190,7 +189,7 @@ def test_last_processor_returns_unknown_value(self): assert exc.value.args[0].startswith("Last processor didn't return") -class TestProxying(object): +class TestProxying: def test_processor_raising_DropEvent_silently_aborts_chain(self, capsys): """ If a processor raises DropEvent, the chain is aborted and nothing is diff --git a/tests/test_config.py b/tests/test_config.py index 4d902bb1..3e4ac500 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -2,7 +2,6 @@ # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. -from __future__ import absolute_import, division, print_function import abc import pickle @@ -15,7 +14,6 @@ import pytest from pretend import call, call_recorder, stub -from six import PY3, add_metaclass import structlog @@ -56,8 +54,7 @@ def test_lazy_logger_is_not_detected_as_abstract_method(): See https://github.com/hynek/structlog/issues/229 """ - @add_metaclass(abc.ABCMeta) - class Foo(object): + class Foo(metaclass=abc.ABCMeta): log = structlog.get_logger() Foo() @@ -79,7 +76,7 @@ def test_default_context_class(): assert cls is _BUILTIN_DEFAULT_CONTEXT_CLASS -class TestConfigure(object): +class TestConfigure: def teardown_method(self, method): structlog.reset_defaults() @@ -146,7 +143,7 @@ def f(): assert f is _CONFIG.logger_factory -class TestBoundLoggerLazyProxy(object): +class TestBoundLoggerLazyProxy: def teardown_method(self, method): structlog.reset_defaults() @@ -161,9 +158,9 @@ def test_repr(self): assert ( ", " + "context_class=, " "initial_values={'foo': 42}, " - "logger_factory_args=(4, 5))>" % ("class" if PY3 else "type",) + "logger_factory_args=(4, 5))>" ) == repr(p) def test_returns_bound_logger_on_bind(self, proxy): @@ -180,7 +177,7 @@ def test_prefers_args_over_config(self): assert isinstance(b._context, dict) assert [1, 2, 3] == b._processors - class Class(object): + class Class: def __init__(self, *args, **kw): pass @@ -273,7 +270,7 @@ def test_bind_doesnt_cache_logger(self): Previous uses of the BoundLoggerLazyProxy don't interfere. """ - class F(object): + class F: "New logger factory with a new attribute" def a(self, *args): @@ -311,7 +308,7 @@ def test_pickle(self, proto): assert repr(bllp) == repr(pickle.loads(pickle.dumps(bllp, proto))) -class TestFunctions(object): +class TestFunctions: def teardown_method(self, method): structlog.reset_defaults() diff --git a/tests/test_contextvars.py b/tests/test_contextvars.py index c9cf1b0c..538507f7 100644 --- a/tests/test_contextvars.py +++ b/tests/test_contextvars.py @@ -16,7 +16,7 @@ pytestmark = pytest.mark.asyncio -class TestNewContextvars(object): +class TestNewContextvars: async def test_bind(self, event_loop): """ Binding a variable causes it to be included in the result of diff --git a/tests/test_dev.py b/tests/test_dev.py index 11690ba1..e20f4d9b 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -1,20 +1,15 @@ -# -*- coding: utf-8 -*- - # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. -from __future__ import absolute_import, division, print_function - import pickle import pytest -import six from structlog import dev -class TestPad(object): +class TestPad: def test_normal(self): """ If chars are missing, adequate number of " " are added. @@ -50,7 +45,7 @@ def unpadded(styles): return styles.bright + "test" + styles.reset -class TestConsoleRenderer(object): +class TestConsoleRenderer: @pytest.mark.skipif(dev._has_colorama, reason="Colorama must be missing.") def test_missing_colorama(self): """ @@ -91,17 +86,6 @@ def test_event_stringified(self, cr, styles, unpadded): assert unpadded == rv - @pytest.mark.skipif(not six.PY2, reason="Problem only exists on Python 2.") - @pytest.mark.parametrize("s", [u"\xc3\xa4".encode("utf-8"), u"ä", "ä"]) - def test_event_py2_only_stringify_non_strings(self, cr, s, styles): - """ - If event is a string type already, leave it be on Python 2. Running - str() on unicode strings with non-ascii characters raises an error. - """ - rv = cr(None, None, {"event": s}) - - assert styles.bright + s + styles.reset == rv - def test_level(self, cr, styles, padded): """ Levels are rendered aligned, in square brackets, and color coded. @@ -311,10 +295,8 @@ def test_repr_native_str(self, rns): ) cnt = rv.count("哈") - if rns and six.PY2: - assert 1 == cnt - else: - assert 2 == cnt + + assert 2 == cnt @pytest.mark.parametrize("repr_native_str", [True, False]) @pytest.mark.parametrize("force_colors", [True, False]) @@ -332,7 +314,7 @@ def test_pickle(self, repr_native_str, force_colors, proto): )(None, None, {"event": "foo"}) -class TestSetExcInfo(object): +class TestSetExcInfo: def test_wrong_name(self): """ Do nothing if name is not exception. diff --git a/tests/test_frames.py b/tests/test_frames.py index 6b452b7a..5fa273ce 100644 --- a/tests/test_frames.py +++ b/tests/test_frames.py @@ -2,7 +2,6 @@ # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. -from __future__ import absolute_import, division, print_function import sys @@ -19,7 +18,7 @@ ) -class TestFindFirstAppFrameAndName(object): +class TestFindFirstAppFrameAndName: def test_ignores_structlog_by_default(self, monkeypatch): """ No matter what you pass in, structlog frames get always ignored. @@ -97,7 +96,7 @@ def exc_info(): return sys.exc_info() -class TestFormatException(object): +class TestFormatException: def test_returns_str(self, exc_info): """ Always returns a native string. @@ -126,7 +125,7 @@ def test_no_trailing_nl(self, exc_info, monkeypatch): assert "foo" == _format_exception(exc_info) -class TestFormatStack(object): +class TestFormatStack: def test_returns_str(self): """ Always returns a native string. diff --git a/tests/test_generic.py b/tests/test_generic.py index 4711c505..2de22982 100644 --- a/tests/test_generic.py +++ b/tests/test_generic.py @@ -2,19 +2,17 @@ # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. -from __future__ import absolute_import, division, print_function import pickle import pytest -import six from structlog._config import _CONFIG from structlog._generic import BoundLogger from structlog.testing import ReturnLogger -class TestLogger(object): +class TestLogger: def log(self, msg): return "log", msg @@ -22,7 +20,7 @@ def gol(self, msg): return "gol", msg -class TestGenericBoundLogger(object): +class TestGenericBoundLogger: def test_caches(self): """ __getattr__() gets called only once per logger method. @@ -53,7 +51,6 @@ def test_proxies_anything(self): assert "log", "foo" == b.log("foo") assert "gol", "bar" == b.gol("bar") - @pytest.mark.skipif(six.PY2, reason="Needs Py3 or dill.") @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL)) def test_pickle(self, proto): """ diff --git a/tests/test_loggers.py b/tests/test_loggers.py index 40ab8f12..8743d044 100644 --- a/tests/test_loggers.py +++ b/tests/test_loggers.py @@ -2,21 +2,20 @@ # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. -from __future__ import absolute_import, division, print_function import pickle import sys -import pytest +from io import StringIO -from six.moves import cStringIO as StringIO +import pytest from structlog._loggers import WRITE_LOCKS, PrintLogger, PrintLoggerFactory from .utils import stdlib_log_methods -class TestPrintLogger(object): +class TestPrintLogger: def test_prints_to_stdout_by_default(self, capsys): """ Instantiating without arguments gives conveniently a logger to standard @@ -99,7 +98,7 @@ def test_pickle_not_stdout_stderr(self, tmpdir, proto): pickle.dumps(pl, proto) -class TestPrintLoggerFactory(object): +class TestPrintLoggerFactory: def test_does_not_cache(self): """ Due to doctest weirdness, we must not re-use PrintLoggers. diff --git a/tests/test_processors.py b/tests/test_processors.py index e71db79e..a1e6f00d 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -1,10 +1,7 @@ -# -*- coding: utf-8 -*- - # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. -from __future__ import absolute_import, division, print_function import datetime import json @@ -12,7 +9,6 @@ import sys import pytest -import six from freezegun import freeze_time @@ -32,8 +28,6 @@ ) from structlog.threadlocal import wrap_dict -from .utils import py3_only - try: import simplejson @@ -46,7 +40,7 @@ rapidjson = None -class TestKeyValueRenderer(object): +class TestKeyValueRenderer: def test_sort_keys(self, event_dict): """ Keys are sorted if sort_keys is set. @@ -133,13 +127,10 @@ def test_repr_native_str(self, rns): ) cnt = rv.count("哈") - if rns and six.PY2: - assert 0 == cnt - else: - assert 2 == cnt + assert 2 == cnt -class TestJSONRenderer(object): +class TestJSONRenderer: def test_renders_json(self, event_dict): """ Renders a predictable JSON string. @@ -224,7 +215,7 @@ def test_rapidjson(self, event_dict): } == json.loads(jr(None, None, event_dict)) -class TestTimeStamper(object): +class TestTimeStamper: def test_disallows_non_utc_unix_timestamps(self): """ A asking for a UNIX timestamp with a timezone that's not UTC raises a @@ -306,7 +297,7 @@ def test_pickle(self, fmt, utc, key, proto): ) -class TestFormatExcInfo(object): +class TestFormatExcInfo: def test_formats_tuple(self, monkeypatch): """ If exc_info is a tuple, it is used. @@ -334,10 +325,9 @@ def test_gets_exc_info_on_bool(self): assert "exc_info" not in d assert 'raise ValueError("test")\nValueError: test' in d["exception"] - @py3_only def test_exception_on_py3(self, monkeypatch): """ - Passing excetions as exc_info is valid on Python 3. + Passing exceptions as exc_info is valid on Python 3. """ monkeypatch.setattr( structlog.processors, @@ -348,11 +338,11 @@ def test_exception_on_py3(self, monkeypatch): raise ValueError("test") except ValueError as e: d = format_exc_info(None, None, {"exc_info": e}) + assert {"exception": (ValueError, e, e.__traceback__)} == d else: pytest.fail("Exception not raised.") - @py3_only def test_exception_without_traceback(self): """ If an Exception is missing a traceback, render it anyway. @@ -364,14 +354,14 @@ def test_exception_without_traceback(self): assert {"exception": "Exception: no traceback!"} == rv -class TestUnicodeEncoder(object): +class TestUnicodeEncoder: def test_encodes(self): """ Unicode strings get encoded (as UTF-8 by default). """ ue = UnicodeEncoder() - assert {"foo": b"b\xc3\xa4r"} == ue(None, None, {"foo": u"b\xe4r"}) + assert {"foo": b"b\xc3\xa4r"} == ue(None, None, {"foo": "b\xe4r"}) def test_passes_arguments(self): """ @@ -379,7 +369,7 @@ def test_passes_arguments(self): """ ue = UnicodeEncoder("latin1", "xmlcharrefreplace") - assert {"foo": b"–"} == ue(None, None, {"foo": u"\u2013"}) + assert {"foo": b"–"} == ue(None, None, {"foo": "\u2013"}) def test_bytes_nop(self): """ @@ -390,14 +380,14 @@ def test_bytes_nop(self): assert {"foo": b"b\xc3\xa4r"} == ue(None, None, {"foo": b"b\xc3\xa4r"}) -class TestUnicodeDecoder(object): +class TestUnicodeDecoder: def test_decodes(self): """ Byte strings get decoded (as UTF-8 by default). """ ud = UnicodeDecoder() - assert {"foo": u"b\xe4r"} == ud(None, None, {"foo": b"b\xc3\xa4r"}) + assert {"foo": "b\xe4r"} == ud(None, None, {"foo": b"b\xc3\xa4r"}) def test_passes_arguments(self): """ @@ -405,7 +395,7 @@ def test_passes_arguments(self): """ ud = UnicodeDecoder("utf-8", "ignore") - assert {"foo": u""} == ud(None, None, {"foo": b"\xa1\xa4"}) + assert {"foo": ""} == ud(None, None, {"foo": b"\xa1\xa4"}) def test_bytes_nop(self): """ @@ -413,10 +403,10 @@ def test_bytes_nop(self): """ ud = UnicodeDecoder() - assert {"foo": u"b\u2013r"} == ud(None, None, {"foo": u"b\u2013r"}) + assert {"foo": "b\u2013r"} == ud(None, None, {"foo": "b\u2013r"}) -class TestExceptionPrettyPrinter(object): +class TestExceptionPrettyPrinter: def test_stdout_by_default(self): """ If no file is supplied, use stdout. @@ -508,7 +498,6 @@ def test_own_exc_info(self, sio): assert "XXX" in sio.getvalue() - @py3_only def test_exception_on_py3(self, sio): """ On Python 3, it's also legal to pass an Exception. @@ -527,7 +516,7 @@ def sir(): return StackInfoRenderer() -class TestStackInfoRenderer(object): +class TestStackInfoRenderer: def test_removes_stack_info(self, sir): """ The `stack_info` key is removed from `event_dict`. @@ -550,7 +539,7 @@ def test_renders_correct_stack(self, sir): assert 'ed = sir(None, None, {"stack_info": True})' in ed["stack"] -class TestFigureOutExcInfo(object): +class TestFigureOutExcInfo: @pytest.mark.parametrize("true_value", [True, 1, 1.1]) def test_obtains_exc_info_on_True(self, true_value): """ @@ -563,7 +552,6 @@ def test_obtains_exc_info_on_True(self, true_value): else: pytest.fail("Exception not raised.") - @py3_only def test_py3_exception_no_traceback(self): """ Exceptions without tracebacks are simply returned with None for diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 5ba3482b..89d9b534 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -2,7 +2,6 @@ # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. -from __future__ import absolute_import, division, print_function import collections import logging @@ -34,7 +33,6 @@ ) from .additional_frame import additional_frame -from .utils import py3_only def build_bl(logger=None, processors=None, context=None): @@ -51,7 +49,7 @@ def return_method_name(_, method_name, __): return method_name -class TestLoggerFactory(object): +class TestLoggerFactory: def setup_method(self, method): """ The stdlib logger factory modifies global state to fix caller @@ -93,14 +91,15 @@ def test_deduces_correct_caller(self): assert file_name == os.path.realpath(__file__) assert func_name == "test_deduces_correct_caller" - @py3_only def test_stack_info(self): + """ + If we ask for stack_info, it will returned. + """ logger = _FixedFindCallerLogger("test") testing, is_, fun, stack_info = logger.findCaller(stack_info=True) assert "testing, is_, fun" in stack_info - @py3_only def test_no_stack_info_by_default(self): logger = _FixedFindCallerLogger("test") testing, is_, fun, stack_info = logger.findCaller() @@ -135,7 +134,7 @@ def test_positional_argument_avoids_guessing(self): assert "foo" == lf.name -class TestFilterByLevel(object): +class TestFilterByLevel: def test_filters_lower_levels(self): logger = logging.Logger(__name__) logger.setLevel(CRITICAL) @@ -152,7 +151,7 @@ def test_passes_higher_levels(self): assert event_dict is filter_by_level(logger, "exception", event_dict) -class TestBoundLogger(object): +class TestBoundLogger: @pytest.mark.parametrize( ("method_name"), ["debug", "info", "warning", "error", "critical"] ) @@ -279,7 +278,7 @@ def test_exception_exc_info_override(self): ) -class TestPositionalArgumentsFormatter(object): +class TestPositionalArgumentsFormatter: def test_formats_tuple(self): """ Positional arguments as simple types are rendered. @@ -344,7 +343,7 @@ def test_args_removed_if_empty(self): assert {} == formatter(None, None, {"positional_args": ()}) -class TestAddLogLevelNumber(object): +class TestAddLogLevelNumber: @pytest.mark.parametrize("level, number", _NAME_TO_LEVEL.items()) def test_log_level_number_added(self, level, number): """ @@ -355,7 +354,7 @@ def test_log_level_number_added(self, level, number): assert number == event_dict["level_number"] -class TestAddLogLevel(object): +class TestAddLogLevel: def test_log_level_added(self): """ The log level is added to the event dict. @@ -395,7 +394,7 @@ def create_log_record(**kwargs): return create_log_record -class TestAddLoggerName(object): +class TestAddLoggerName: def test_logger_name_added(self): """ The logger name is added to the event dict. @@ -417,7 +416,7 @@ def test_logger_name_added_with_record(self, log_record): assert name == event_dict["logger"] -class TestRenderToLogKW(object): +class TestRenderToLogKW: def test_default(self): """ Translates `event` to `msg` and handles otherwise empty `event_dict`s. @@ -491,7 +490,7 @@ def configure_logging(pre_chain, logger=None, pass_foreign_args=False): ) -class TestProcessorFormatter(object): +class TestProcessorFormatter: """ These are all integration tests because they're all about integration. """ @@ -713,7 +712,6 @@ def format_exc_info_fake(logger, name, event_dict): assert "Traceback (most recent call last):" in err @pytest.mark.parametrize("keep", [True, False]) - @py3_only def test_formatter_unsets_stack_info(self, configure_for_pf, capsys, keep): """ Stack traces doesn't get printed outside of the json document when diff --git a/tests/test_testing.py b/tests/test_testing.py index 77d59117..8237ad88 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -1,10 +1,7 @@ -# -*- coding: utf-8 -*- - # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. -from __future__ import absolute_import, division, print_function import pytest @@ -12,7 +9,7 @@ from structlog.testing import ReturnLogger, ReturnLoggerFactory -class TestCaptureLogs(object): +class TestCaptureLogs: @classmethod def teardown_class(cls): reset_defaults() @@ -62,7 +59,7 @@ def test_restores_processors_on_error(self): assert orig_procs is self.get_active_procs() -class TestReturnLogger(object): +class TestReturnLogger: # @pytest.mark.parametrize("method", stdlib_log_methods) def test_stdlib_methods_support(self, stdlib_log_method): """ @@ -81,7 +78,7 @@ def test_return_logger(self): assert obj is ReturnLogger().msg(obj) -class TestReturnLoggerFactory(object): +class TestReturnLoggerFactory: def test_builds_returnloggers(self): f = ReturnLoggerFactory() diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py index a0d54805..685a7bba 100644 --- a/tests/test_threadlocal.py +++ b/tests/test_threadlocal.py @@ -2,7 +2,6 @@ # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. -from __future__ import absolute_import, division, print_function import threading @@ -56,7 +55,7 @@ def logger(): return ReturnLogger() -class TestTmpBind(object): +class TestTmpBind: def test_bind(self, log): """ tmp_bind does not modify the thread-local state. @@ -87,7 +86,7 @@ def test_bind_exc(self, log): assert {"y": 23} == log._context._dict -class TestAsImmutable(object): +class TestAsImmutable: def test_does_not_affect_global(self, log): """ A logger from as_mutable is independent from thread local state. @@ -121,7 +120,7 @@ def test_idempotency(self, log): assert isinstance(as_immutable(il), BoundLoggerBase) -class TestThreadLocalDict(object): +class TestThreadLocalDict: def test_wrap_returns_distinct_classes(self): """ Each call to wrap_dict returns a distinct new class whose context is @@ -273,7 +272,7 @@ def test_new_class(self, D): assert 0 == len(D()) -class TestNewThreadLocal(object): +class TestNewThreadLocal: def test_alias(self): """ We're keeping the old alias around. diff --git a/tests/test_twisted.py b/tests/test_twisted.py index 1c7bdd35..a3a71e42 100644 --- a/tests/test_twisted.py +++ b/tests/test_twisted.py @@ -2,18 +2,16 @@ # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. -from __future__ import absolute_import, division, print_function import json from collections import OrderedDict +from io import StringIO import pytest from pretend import call_recorder -from six import PY3 -from six.moves import cStringIO as StringIO -from twisted.python.failure import Failure, NoCurrentExceptionError +from twisted.python.failure import Failure from twisted.python.log import ILogObserver from structlog import ReturnLogger @@ -53,7 +51,7 @@ def build_bl(logger=None, processors=None, context=None): ) -class TestBoundLogger(object): +class TestBoundLogger: def test_msg(self): """ log.msg renders correctly. @@ -93,7 +91,7 @@ def test_errWithFailure(self): ) == str(bl.err("event", foo=42)) -class TestExtractStuffAndWhy(object): +class TestExtractStuffAndWhy: def test_extractFailsOnTwoFailures(self): """ Raise ValueError if both _stuff and event contain exceptions. @@ -139,26 +137,8 @@ def test_handlesMissingFailure(self): """ assert (None, "foo", {}) == _extractStuffAndWhy({"event": "foo"}) - @pytest.mark.xfail(PY3, reason="Py3 does not allow for cleaning exc_info") - def test_recognizesErrorsAndCleansThem(self): - """ - If no error is supplied, the environment is checked for one. If one is - found, it's used and cleared afterwards so log.err doesn't add it as - well. - """ - try: - raise ValueError - except ValueError: - f = Failure() - _stuff, _why, ed = _extractStuffAndWhy({"event": "foo"}) - - assert _stuff.value is f.value - with pytest.raises(NoCurrentExceptionError): - Failure() - - -class TestEventAdapter(object): +class TestEventAdapter: """ Some tests here are redundant because they predate _extractStuffAndWhy. """ @@ -244,7 +224,7 @@ def jr(): return JSONRenderer() -class TestJSONRenderer(object): +class TestJSONRenderer: def test_dumpsKWsAreHandedThrough(self, jr): """ JSONRenderer allows for setting arguments that are passed to @@ -282,12 +262,7 @@ def test_msgWorksToo(self, jr): def test_handlesFailure(self, jr): rv = jr(None, "err", {"event": Failure(ValueError())})[0][0].string - assert ( - "Failure: {0}.ValueError".format( - "builtins" if PY3 else "exceptions" - ) - in rv - ) + assert "Failure: builtins.ValueError" in rv assert '"event": "error"' in rv def test_setsStructLogField(self, jr): @@ -298,7 +273,7 @@ def test_setsStructLogField(self, jr): assert {"_structlog": True} == jr(None, "msg", {"_why": "foo"})[1] -class TestReprWrapper(object): +class TestReprWrapper: def test_repr(self): """ The repr of the wrapped string is the vanilla string without quotes. @@ -306,7 +281,7 @@ def test_repr(self): assert "foo" == repr(ReprWrapper("foo")) -class TestPlainFileLogObserver(object): +class TestPlainFileLogObserver: def test_isLogObserver(self): assert ILogObserver.providedBy(PlainFileLogObserver(StringIO())) @@ -319,7 +294,7 @@ def test_writesOnlyMessageWithLF(self): assert "hello\n" == sio.getvalue() -class TestJSONObserverWrapper(object): +class TestJSONObserverWrapper: def test_IsAnObserver(self): assert ILogObserver.implementedBy(JSONLogObserverWrapper) @@ -355,6 +330,6 @@ def verify(eventDict): JSONLogObserverWrapper(verify)(d) -class TestPlainJSONStdOutLogger(object): +class TestPlainJSONStdOutLogger: def test_isLogObserver(self): assert ILogObserver.providedBy(plainJSONStdOutLogger()) diff --git a/tests/test_utils.py b/tests/test_utils.py index ee793038..3e537e29 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -2,7 +2,6 @@ # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. -from __future__ import absolute_import, division, print_function import errno @@ -13,7 +12,7 @@ from structlog._utils import until_not_interrupted -class TestUntilNotInterrupted(object): +class TestUntilNotInterrupted: def test_passes_arguments_and_returns_return_value(self): def returner(*args, **kw): return args, kw @@ -31,7 +30,7 @@ def test_retries_on_EINTR(self): def raise_on_first_three(): if calls[0] < 3: calls[0] += 1 - raise IOError(errno.EINTR) + raise OSError(errno.EINTR) until_not_interrupted(raise_on_first_three) diff --git a/tests/utils.py b/tests/utils.py index cd4732da..7f3cf50f 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -6,15 +6,7 @@ Shared test utilities. """ -from __future__ import absolute_import, division, print_function - -import pytest -import six - from structlog.stdlib import _NAME_TO_LEVEL -py3_only = pytest.mark.skipif(not six.PY3, reason="Python 3-only") -py2_only = pytest.mark.skipif(not six.PY2, reason="Python 2-only") - stdlib_log_methods = [m for m in _NAME_TO_LEVEL if m != "notset"] diff --git a/tox.ini b/tox.ini index e6aab2dc..e78ecf95 100644 --- a/tox.ini +++ b/tox.ini @@ -7,7 +7,7 @@ filterwarnings = [tox] -envlist = lint,{py27,py35,py36,py37,py38,pypy,pypy3}-threads,{py27,py37,py38,pypy}-{greenlets,colorama},docs,pypi-description,manifest,coverage-report +envlist = lint,{py36,py37,py38,pypy3}-threads,{py38,pypy3}-greenlets,py38-colorama,docs,pypi-description,manifest,coverage-report isolated_build = True @@ -24,7 +24,6 @@ extras = {env:TOX_AP_TEST_EXTRAS:tests} deps = greenlets: greenlet threads,greenlets,colorama: twisted - colorama: colorama setenv = PYTHONHASHSEED = 0 commands = python -m pytest {posargs} @@ -37,26 +36,18 @@ setenv = commands = coverage run -m pytest {posargs} -[testenv:py37-greenlets] +[testenv:py38-colorama] deps = - greenlet - twisted -setenv = - PYTHONHASHSEED = 0 -commands = coverage run -m pytest {posargs} - - -[testenv:py27-threads] -deps = twisted + colorama setenv = PYTHONHASHSEED = 0 commands = coverage run -m pytest {posargs} -[testenv:py27-colorama] +[testenv:py38-greenlets] deps = - colorama - twisted + greenlet + twisted setenv = PYTHONHASHSEED = 0 commands = coverage run -m pytest {posargs} From 2a1f9c64bb406885ef6213cc4f866b9ffafd546f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 28 Jan 2020 20:14:49 +0100 Subject: [PATCH 0345/1520] Drop object from doc classes --- docs/api.rst | 4 ++-- docs/loggers.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 6633e832..f0dae729 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -140,12 +140,12 @@ API Reference .. doctest:: - >>> class C1(object): + >>> class C1: ... def __structlog__(self): ... return ["C1!"] ... def __repr__(self): ... return "__structlog__ took precedence" - >>> class C2(object): + >>> class C2: ... def __repr__(self): ... return "No __structlog__, so this is used." >>> from structlog.processors import JSONRenderer diff --git a/docs/loggers.rst b/docs/loggers.rst index 7242e17a..6c990754 100644 --- a/docs/loggers.rst +++ b/docs/loggers.rst @@ -53,7 +53,7 @@ For that times there is the `structlog.wrap_logger` function that can be used to .. doctest:: >>> from structlog import wrap_logger - >>> class PrintLogger(object): + >>> class PrintLogger: ... def msg(self, message): ... print(message) >>> def proc(logger, method_name, event_dict): From 47b699337aaeb6e4bcd39907e7ac0b1fff26156e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 28 Jan 2020 20:15:11 +0100 Subject: [PATCH 0346/1520] Make contextvars available on structlog/__init__.py --- src/structlog/__init__.py | 8 +++++++- tox.ini | 7 +++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index fdd703e4..4994037b 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -27,9 +27,14 @@ try: from structlog import twisted -except ImportError: # pragma: nocover +except ImportError: twisted = None +try: + from structlog import contextvars +except ImportError: + contextvars = None + __version__ = "20.2.0.dev0" @@ -54,6 +59,7 @@ "ReturnLoggerFactory", "configure", "configure_once", + "contextvars", "dev", "getLogger", "get_config", diff --git a/tox.ini b/tox.ini index e78ecf95..da37992c 100644 --- a/tox.ini +++ b/tox.ini @@ -29,6 +29,13 @@ setenv = commands = python -m pytest {posargs} +[testenv:py36-threads] +deps = twisted +setenv = + PYTHONHASHSEED = 0 +commands = coverage run -m pytest {posargs} + + [testenv:py37-threads] deps = twisted setenv = From 34a4804622057bfa2ae415d83c5d406c402a4164 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 25 Feb 2020 13:38:54 +0100 Subject: [PATCH 0347/1520] Doesn't hurt trying --- README.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.rst b/README.rst index 1e8bedde..a304f8d6 100644 --- a/README.rst +++ b/README.rst @@ -27,6 +27,10 @@ :target: https://github.com/psf/black :alt: Code style: black +.. image:: https://www.ko-fi.com/img/githubbutton_sm.svg + :target: https://ko-fi.com/the_hynek + :alt: Support this project by buying me a coffee! + .. -begin-short- ``structlog`` makes logging in Python less painful and more powerful by adding structure to your log entries. From e4295048b629164ebf5044c7f2034fea69f382ee Mon Sep 17 00:00:00 2001 From: Ofek Lev Date: Wed, 26 Feb 2020 11:09:27 -0500 Subject: [PATCH 0348/1520] Recommend another JSON library (#247) * Recommend another JSON library * Update performance.rst --- docs/performance.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/performance.rst b/docs/performance.rst index 7985fb2e..b98e591d 100644 --- a/docs/performance.rst +++ b/docs/performance.rst @@ -36,10 +36,11 @@ Here are a few hints how to get most out of ``structlog`` in production: This has the only drawback is that later calls on :func:`~structlog.configure` don't have any effect on already cached loggers -- that shouldn't matter outside of testing though. #. Use a faster JSON serializer than the standard library. - Possible alternatives are among others simplejson_ or RapidJSON_ (Python 3 only):: + Possible alternatives are among others simplejson_, orjson_, or RapidJSON_:: structlog.processors.JSONRenderer(serializer=rapidjson.dumps) .. _simplejson: https://simplejson.readthedocs.io/ +.. _orjson: https://github.com/ijl/orjson .. _RapidJSON: https://pypi.org/project/python-rapidjson/ From 9d2544a04cc84e38a7146f738fa2e63a41fae8a8 Mon Sep 17 00:00:00 2001 From: Timost Date: Wed, 4 Mar 2020 05:30:41 +0100 Subject: [PATCH 0349/1520] docs/standard-library.rst: fix typo (#250) --- docs/standard-library.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/standard-library.rst b/docs/standard-library.rst index d8d939fe..0155737e 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -146,7 +146,7 @@ Rendering Using ``structlog``-based Formatters Within `logging` The `ProcessorFormatter` has two parts to its API: #. The `structlog.stdlib.ProcessorFormatter.wrap_for_formatter` method must be used as the last processor in `structlog.configure`, - it converts the the processed event dict to something that the ``ProcessorFormatter`` understands. + it converts the processed event dict to something that the ``ProcessorFormatter`` understands. #. The `ProcessorFormatter` itself, which can wrap any ``structlog`` renderer to handle the output of both ``structlog`` and standard library events. From a5768fac27a4769fb9ed605736f7e2f27e80bb93 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 7 Mar 2020 06:50:58 +0100 Subject: [PATCH 0350/1520] Ensure tests pass in any order. --- setup.py | 3 ++- tests/test_stdlib.py | 5 +++-- tests/test_threadlocal.py | 5 +++++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index a7e9c232..5a60d6be 100644 --- a/setup.py +++ b/setup.py @@ -36,8 +36,9 @@ "coverage[toml]", "freezegun>=0.2.8", "pretend", - "pytest>=3.3.0", "pytest-asyncio; python_version>='3.7'", + "pytest-randomly", + "pytest>=3.3.0", "python-rapidjson", "simplejson", ], diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 89d9b534..bcaef7b8 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -118,8 +118,9 @@ def test_find_caller(self, monkeypatch): assert log_record.filename == os.path.basename(__file__) def test_sets_correct_logger(self): - assert logging.getLoggerClass() is logging.Logger - + """ + Calling LoggerFactory ensures that Logger.findCaller gets patched. + """ LoggerFactory() assert logging.getLoggerClass() is _FixedFindCallerLogger diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py index 685a7bba..6a70330f 100644 --- a/tests/test_threadlocal.py +++ b/tests/test_threadlocal.py @@ -284,6 +284,7 @@ def test_bind_and_merge(self): Binding a variable causes it to be included in the result of merge_threadlocal. """ + clear_threadlocal() bind_threadlocal(a=1) assert {"a": 1, "b": 2} == merge_threadlocal(None, None, {"b": 2}) @@ -303,6 +304,8 @@ def test_merge_works_without_bind(self): merge_threadlocal returns values as normal even when there has been no previous calls to bind_threadlocal. """ + clear_threadlocal() + assert {"b": 2} == merge_threadlocal(None, None, {"b": 2}) def test_multiple_binds(self): @@ -310,6 +313,7 @@ def test_multiple_binds(self): Multiple calls to bind_threadlocal accumulate values instead of replacing them. """ + clear_threadlocal() bind_threadlocal(a=1, b=2) bind_threadlocal(c=3) @@ -325,6 +329,7 @@ def test_unbind_threadlocal(self): clear_threadlocal() bind_threadlocal(a=234, b=34) + assert {"a": 234, "b": 34} == merge_threadlocal_context(None, None, {}) unbind_threadlocal("a") From 36eeb18c043319f43c33364331a4a5cfcd326bde Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 8 Mar 2020 09:43:55 +0100 Subject: [PATCH 0351/1520] Move to GitHub Actions (#251) --- .github/CONTRIBUTING.rst | 2 +- .github/workflows/main.yml | 84 ++++++++++++++++++++++++ .pre-commit-config.yaml | 6 +- .readthedocs.yml | 13 ++-- README.rst | 4 +- azure-pipelines.yml | 129 ------------------------------------- setup.py | 3 - tox.ini | 31 +++++---- 8 files changed, 116 insertions(+), 156 deletions(-) create mode 100644 .github/workflows/main.yml delete mode 100644 azure-pipelines.yml diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst index 91ac5b3f..395dcb2d 100644 --- a/.github/CONTRIBUTING.rst +++ b/.github/CONTRIBUTING.rst @@ -189,7 +189,7 @@ Thank you for considering contributing to ``structlog``! .. _pyenv: https://github.com/pyenv/pyenv .. _reStructuredText: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html .. _semantic newlines: https://rhodesmill.org/brandon/2012/one-sentence-per-line/ -.. _CI: https://dev.azure.com/the-hynek/structlog/_build?definitionId=1 +.. _CI: https://github.com/hynek/structlog/actions?query=workflow%3ACI .. _black: https://github.com/psf/black .. _pre-commit: https://pre-commit.com/ .. _isort: https://github.com/timothycrosley/isort diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 00000000..fcbb2d0c --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,84 @@ +--- +name: CI + +on: + push: + branches: ["master"] + pull_request: + branches: ["master"] + +jobs: + tests: + name: "Python ${{ matrix.python-version }}" + runs-on: "ubuntu-latest" + env: + USING_COVERAGE: '3.6,3.8' + + strategy: + matrix: + python-version: ["3.6", "3.7", "3.8", "pypy3"] + + steps: + - uses: "actions/checkout@v2" + - uses: "actions/setup-python@v1" + with: + python-version: "${{ matrix.python-version }}" + - name: "Install dependencies" + run: | + set -xe + python -VV + python -m site + python -m pip install --upgrade pip setuptools wheel + python -m pip install --upgrade coverage[toml] virtualenv tox tox-gh-actions + + - name: "Run tox targets for ${{ matrix.python-version }}" + run: "python -m tox" + + - name: "Combine coverage" + run: | + set -xe + python -m coverage combine + python -m coverage xml + if: "contains(env.USING_COVERAGE, matrix.python-version)" + - name: Upload coverage to Codecov + if: "contains(env.USING_COVERAGE, matrix.python-version)" + uses: "codecov/codecov-action@v1" + with: + fail_ci_if_error: true + + package: + name: "Build & verify package" + runs-on: "ubuntu-latest" + + steps: + - uses: "actions/checkout@v2" + - uses: "actions/setup-python@v1" + with: + python-version: "3.8" + + - name: "Install pep517 and twine" + run: "python -m pip install pep517 twine" + - name: "Build package" + run: "python -m pep517.build --source --binary ." + - name: "List result" + run: "ls -l dist" + - name: "Check long_description" + run: "python -m twine check dist/*" + + install-dev: + strategy: + matrix: + os: ["ubuntu-latest", "windows-latest", "macos-latest"] + + name: "Verify dev env" + runs-on: "${{ matrix.os }}" + + steps: + - uses: "actions/checkout@v2" + - uses: "actions/setup-python@v1" + with: + python-version: "3.8" + - name: "Install in dev mode" + run: "python -m pip install -e .[dev]" + - name: "Import package" + run: "python -c 'import structlog; print(structlog.__version__)'" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a3ff8744..2514c0a0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,7 +5,7 @@ repos: rev: 19.10b0 hooks: - id: black - language_version: python3.7 + language_version: python3.8 # override until resolved: https://github.com/psf/black/issues/402 files: \.pyi?$ types: [] @@ -14,7 +14,7 @@ repos: rev: 3.7.9 hooks: - id: flake8 - language_version: python3.7 + language_version: python3.8 exclude: docs/code_examples - repo: https://github.com/asottile/seed-isort-config @@ -27,7 +27,7 @@ repos: hooks: - id: isort additional_dependencies: [toml] - language_version: python3.7 + language_version: python3.8 - repo: https://github.com/pre-commit/pre-commit-hooks rev: v2.4.0 diff --git a/.readthedocs.yml b/.readthedocs.yml index a4b6f431..511ae165 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -1,6 +1,11 @@ --- +version: 2 python: - version: 3 - pip_install: true - extra_requirements: - - docs + # Keep version in sync with tox.ini (docs and gh-actions). + version: 3.7 + + install: + - method: pip + path: . + extra_requirements: + - docs diff --git a/README.rst b/README.rst index a304f8d6..30c5618e 100644 --- a/README.rst +++ b/README.rst @@ -15,8 +15,8 @@ :target: https://www.structlog.org/en/stable/?badge=stable :alt: Documentation Status -.. image:: https://dev.azure.com/the-hynek/structlog/_apis/build/status/hynek.structlog?branchName=master - :target: https://dev.azure.com/the-hynek/structlog/_build?definitionId=1 +.. image:: https://github.com/hynek/structlog/workflows/CI/badge.svg?branch=master + :target: https://github.com/hynek/structlog/actions?workflow=CI :alt: CI Status .. image:: https://codecov.io/github/hynek/structlog/branch/master/graph/badge.svg diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index c16af9b5..00000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,129 +0,0 @@ ---- -# Don't have two build jobs for each pull request. -trigger: -- master - -jobs: - - job: 'Test' - pool: - vmImage: 'ubuntu-latest' - strategy: - matrix: - Lint: - tox.env: lint - python.version: '3.7' - Manifest: - tox.env: manifest - python.version: '3.7' - - py36-threads: - tox.env: py36-threads - python.version: '3.6' - py37-threads: - tox.env: py37-threads - python.version: '3.7' - py38-threads: - tox.env: py38-threads - python.version: '3.8' - pypy3-threads: - tox.env: pypy3-threads - python.version: pypy3 - py38-greenlets: - tox.env: py38-greenlets - python.version: '3.8' - pypy3-greenlets: - tox.env: pypy3-greenlets - python.version: pypy3 - py38-colorama: - tox.env: py38-colorama - python.version: '3.8' - - Docs: - python.version: '3.7' - tox.env: docs - PyPI-Description: - python.version: '3.7' - tox.env: pypi-description - - steps: - - task: UsePythonVersion@0 - displayName: Get Python for Python tools. - inputs: - versionSpec: '3.7' - addToPath: false - name: pyTools - - - script: $(pyTools.pythonLocation)/bin/pip install --upgrade tox - displayName: Install Python-based tools. - - - task: UsePythonVersion@0 - inputs: - versionSpec: '$(python.version)' - architecture: 'x64' - # condition: not(in(variables['python.version'], '3.8')) - displayName: Use cached Python $(python.version) for tests. - - # - script: | - # sudo add-apt-repository ppa:deadsnakes - # sudo apt-get update - # sudo apt-get install -y --no-install-recommends python$(python.version)-dev python$(python.version)-distutils - # condition: in(variables['python.version'], '3.8') - # displayName: Install Python $(python.version) from the deadsnakes PPA for tests. - - - script: $(pyTools.pythonLocation)/bin/tox -e $(tox.env) - env: - TOX_AP_TEST_EXTRAS: azure-pipelines - displayName: run tox -e $(tox.env) - - - script: | - if [ ! -f .coverage.* ]; then - echo No coverage data found. - exit 0 - fi - - # codecov shells out to "coverage" and avoiding 'sudo pip' allows for - # package caching. - PATH=$HOME/.local/bin:$PATH - - case "$(python.version)" in - "pypy3") PY=pypy3 ;; - *) PY=python$(python.version) ;; - esac - - # Python 3.8 needs an up-to-date pip. - if [ "$(python.version)" = "3.8" ]; then - curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py - $PY get-pip.py --user - fi - - $PY -m pip install --user 'coverage[toml]' codecov - - coverage combine - codecov - env: - CODECOV_TOKEN: $(codecov.token) - displayName: Report Coverage - condition: succeeded() - - - # Make sure contributors can use Windows. - - job: 'Windows' - pool: - vmImage: 'windows-latest' - strategy: - matrix: - py38: - python.version: '3.8' - - steps: - - task: UsePythonVersion@0 - inputs: - versionSpec: '$(python.version)' - architecture: 'x64' - displayName: Use cached Python $(python.version) for tests. - - - script: python -m pip install -e .[dev] - displayName: Install package in dev mode. - - - script: python -m pytest - displayName: Run tests. diff --git a/setup.py b/setup.py index 5a60d6be..af851dab 100644 --- a/setup.py +++ b/setup.py @@ -47,9 +47,6 @@ EXTRAS_REQUIRE["dev"] = ( EXTRAS_REQUIRE["tests"] + EXTRAS_REQUIRE["docs"] + ["pre-commit"] ) -EXTRAS_REQUIRE["azure-pipelines"] = EXTRAS_REQUIRE["tests"] + [ - "pytest-azurepipelines" -] ############################################################################### diff --git a/tox.ini b/tox.ini index da37992c..0edc4c9e 100644 --- a/tox.ini +++ b/tox.ini @@ -6,13 +6,22 @@ filterwarnings = once::Warning +# Keep docs in sync with docs env and .readthedocs.yml. +[gh-actions] +python = + 3.6: py36 + 3.7: py37, docs + 3.8: py38, lint, manifest + pypy3: pypy3 + + [tox] envlist = lint,{py36,py37,py38,pypy3}-threads,{py38,pypy3}-greenlets,py38-colorama,docs,pypi-description,manifest,coverage-report isolated_build = True [testenv:lint] -basepython = python3.7 +basepython = python3.8 skip_install = true deps = pre-commit passenv = HOMEPATH # needed on Windows @@ -20,7 +29,7 @@ commands = pre-commit run --all-files [testenv] -extras = {env:TOX_AP_TEST_EXTRAS:tests} +extras = tests deps = greenlets: greenlet threads,greenlets,colorama: twisted @@ -29,6 +38,7 @@ setenv = commands = python -m pytest {posargs} +# For missing contextvars. [testenv:py36-threads] deps = twisted setenv = @@ -36,16 +46,8 @@ setenv = commands = coverage run -m pytest {posargs} -[testenv:py37-threads] -deps = twisted -setenv = - PYTHONHASHSEED = 0 -commands = coverage run -m pytest {posargs} - - [testenv:py38-colorama] -deps = - colorama +deps = colorama setenv = PYTHONHASHSEED = 0 commands = coverage run -m pytest {posargs} @@ -61,6 +63,7 @@ commands = coverage run -m pytest {posargs} [testenv:docs] +# Keep basepython in sync with gh-actions and .readthedocs.yml. basepython = python3.7 extras = docs @@ -73,7 +76,7 @@ commands = [testenv:pypi-description] -basepython = python3.7 +basepython = python3.8 skip_install = true deps = twine @@ -84,14 +87,14 @@ commands = [testenv:manifest] -basepython = python3.7 +basepython = python3.8 skip_install = true deps = check-manifest commands = check-manifest [testenv:coverage-report] -basepython = python3.7 +basepython = python3.8 deps = coverage[toml] skip_install = true commands = From a1c5d9e599ec34e02bed35a156fe8a609c33227a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 22 Mar 2020 09:21:23 +0100 Subject: [PATCH 0352/1520] Fix type --- .github/CONTRIBUTING.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst index 395dcb2d..28aa0f36 100644 --- a/.github/CONTRIBUTING.rst +++ b/.github/CONTRIBUTING.rst @@ -14,7 +14,7 @@ Support In case you'd like to help out but don't want to deal with GitHub, there's a great opportunity: help your fellow developers on `StackOverflow `_! -The offical tag is ``structlog`` and helping out in support frees us up to improve ``structlog`` instead! +The official tag is ``structlog`` and helping out in support frees us up to improve ``structlog`` instead! Workflow From b8fce1caaa05430467e9a9890d8c1cc6da880ed5 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 22 Mar 2020 09:25:40 +0100 Subject: [PATCH 0353/1520] We don't do square brackets anymore --- .github/CONTRIBUTING.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst index 28aa0f36..af252dcd 100644 --- a/.github/CONTRIBUTING.rst +++ b/.github/CONTRIBUTING.rst @@ -102,10 +102,10 @@ Documentation - Added ``structlog.func()`` that does foo. It's pretty cool. - [`#1 `_] + `#1 `_ - ``structlog.func()`` now doesn't crash the Large Hadron Collider anymore. That was a nasty bug! - [`#2 `_] + `#2 `_ Local Development Environment From b7397af76a89c3ce34c8aab19f0f0b4985dceb4a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 23 Mar 2020 11:07:52 +0100 Subject: [PATCH 0354/1520] PyPI shields is just too flaky --- README.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.rst b/README.rst index 30c5618e..58d51c55 100644 --- a/README.rst +++ b/README.rst @@ -7,10 +7,6 @@ ``structlog``: Structured Logging for Python ============================================ -.. image:: https://img.shields.io/pypi/v/structlog.svg - :target: https://pypi.org/project/structlog/ - :alt: PyPI - .. image:: https://readthedocs.org/projects/structlog/badge/?version=stable :target: https://www.structlog.org/en/stable/?badge=stable :alt: Documentation Status From 9aa02f2bdacf57b9ea943ff7f3e82d0840032bf4 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Sat, 18 Apr 2020 18:26:28 +0200 Subject: [PATCH 0355/1520] Fix a tiny typo s/threadn-locals/thread-locals (#256) On the thread-local docs page --- docs/thread-local.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/thread-local.rst b/docs/thread-local.rst index d93b8015..49b09f84 100644 --- a/docs/thread-local.rst +++ b/docs/thread-local.rst @@ -179,7 +179,7 @@ The convenience of having a thread-local context comes at a price though: See `configuration` for more details. -The general sentiment against threadn-locals is that they're hard to test. +The general sentiment against thread-locals is that they're hard to test. In this case we feel like this is an acceptable trade-off. You can easily write deterministic tests using a call-capturing processor if you use the API properly (cf. warning above). From 0e24a574f2a0f402c45c33f68e5abe87f93d1459 Mon Sep 17 00:00:00 2001 From: fbjorn Date: Fri, 24 Apr 2020 09:13:57 +0300 Subject: [PATCH 0356/1520] Fix several typos (#257) --- CHANGELOG.rst | 2 +- docs/standard-library.rst | 2 +- docs/twisted.rst | 2 +- src/structlog/_config.py | 4 ++-- src/structlog/threadlocal.py | 2 +- tests/test_config.py | 2 +- tests/test_loggers.py | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index df887578..29b1edd0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -211,7 +211,7 @@ Deprecations: - The meaning of the ``structlog[dev]`` installation target will change from "colorful output" to "dependencies to develop ``structlog``" in 19.1.0. - The main reason behind this decision is that it's impossible to have a ``structlog`` in your normal dependencies and additionally a ``structlog[dev]`` for developement (``pip`` will report an error). + The main reason behind this decision is that it's impossible to have a ``structlog`` in your normal dependencies and additionally a ``structlog[dev]`` for development (``pip`` will report an error). Changes: diff --git a/docs/standard-library.rst b/docs/standard-library.rst index 0155737e..bad34e79 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -337,7 +337,7 @@ A basic configuration to output structured logs in JSON format looks like this: cache_logger_on_first_use=True, ) -(If you're still runnning Python 2, replace `UnicodeDecoder` through `UnicodeEncoder`.) +(If you're still running Python 2, replace `UnicodeDecoder` through `UnicodeEncoder`.) To make your program behave like a proper `12 factor app`_ that outputs only JSON to ``stdout``, configure the `logging` module like this:: diff --git a/docs/twisted.rst b/docs/twisted.rst index f3dc25df..1174cde3 100644 --- a/docs/twisted.rst +++ b/docs/twisted.rst @@ -36,7 +36,7 @@ Processors def onError(fail): failure = fail.trap(MoonExploded) - log.err(failure, _why="event-that-happend") + log.err(failure, _why="event-that-happened") will still work as expected. diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 5557d9b3..123bf6be 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -218,9 +218,9 @@ def configure( def configure_once(*args, **kw): """ - Configures iff structlog isn't configured yet. + Configures if structlog isn't configured yet. - It does *not* matter whether is was configured using `configure` or + It does *not* matter whether it was configured using `configure` or `configure_once` before. Raises a `RuntimeWarning` if repeated configuration is attempted. diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index b667416d..7a479d25 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -180,7 +180,7 @@ def merge_threadlocal(logger, method_name, event_dict): .. versionchanged:: 20.1.0 This function used to be called ``merge_threalocal_context`` and that - name is still kept around for backward compatability. + name is still kept around for backward compatibility. """ context = _get_context().copy() context.update(event_dict) diff --git a/tests/test_config.py b/tests/test_config.py index 3e4ac500..e33238e7 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -35,7 +35,7 @@ @pytest.fixture def proxy(): """ - Returns a BoundLoggerLazyProxy constructed w/o paramaters & None as logger. + Returns a BoundLoggerLazyProxy constructed w/o parameters & None as logger. """ return BoundLoggerLazyProxy(None) diff --git a/tests/test_loggers.py b/tests/test_loggers.py index 8743d044..38f1065d 100644 --- a/tests/test_loggers.py +++ b/tests/test_loggers.py @@ -87,7 +87,7 @@ def test_pickle(self, file, proto): @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL)) def test_pickle_not_stdout_stderr(self, tmpdir, proto): """ - PrintLoggers with differnt files than stdout/stderr raise a + PrintLoggers with different files than stdout/stderr raise a PickingError. """ f = tmpdir.join("file.log") From 49ab899c711ebb5c4245e6870b5055a2a52a87a2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 6 May 2020 05:46:30 +0200 Subject: [PATCH 0357/1520] pre-commit update, fix ambiguous var name --- .pre-commit-config.yaml | 6 +++--- src/structlog/dev.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2514c0a0..f3244b6a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,14 +11,14 @@ repos: types: [] - repo: https://gitlab.com/pycqa/flake8 - rev: 3.7.9 + rev: 3.8.0a2 hooks: - id: flake8 language_version: python3.8 exclude: docs/code_examples - repo: https://github.com/asottile/seed-isort-config - rev: v1.9.4 + rev: v2.1.1 hooks: - id: seed-isort-config @@ -30,7 +30,7 @@ repos: language_version: python3.8 - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v2.4.0 + rev: v2.5.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer diff --git a/src/structlog/dev.py b/src/structlog/dev.py index dd95a324..4907aa66 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -25,11 +25,11 @@ _EVENT_WIDTH = 30 # pad the event name to so many characters -def _pad(s, l): +def _pad(s, length): """ - Pads *s* to length *l*. + Pads *s* to length *lenght*. """ - missing = l - len(s) + missing = length - len(s) return s + " " * (missing if missing > 0 else 0) From 41257aa5708c5d12b013eb04f60d9a95c60392e2 Mon Sep 17 00:00:00 2001 From: Quentin Pradet Date: Fri, 8 May 2020 13:13:27 +0400 Subject: [PATCH 0358/1520] Document that capture_logs disables configured processors (#259) Co-authored-by: Hynek Schlawack --- docs/testing.rst | 2 ++ src/structlog/testing.py | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/testing.rst b/docs/testing.rst index c4e49910..e69791d7 100644 --- a/docs/testing.rst +++ b/docs/testing.rst @@ -14,6 +14,8 @@ If you need functionality similar to `unittest.TestCase.assertLogs`, or you want >>> cap_logs [{'x': 'y', 'event': 'hello', 'log_level': 'info'}] +Note that inside the context manager all configured processors are disabled. + You can build your own helpers using `structlog.testing.LogCapture`. For example a `pytest `_ fixture to capture log output could look like this:: diff --git a/src/structlog/testing.py b/src/structlog/testing.py index 205a9c7a..e8a5dcf1 100644 --- a/src/structlog/testing.py +++ b/src/structlog/testing.py @@ -41,7 +41,8 @@ def __call__(self, _, method_name, event_dict): def capture_logs(): """ Context manager that appends all logging statements to its yielded list - while it is active. + while it is active. Disables all configured processors for the duration + of the context manager. Attention: this is **not** thread-safe! From db1e52979cedcd11c967307a65d8e2839f199c39 Mon Sep 17 00:00:00 2001 From: Christine Banek Date: Mon, 15 Jun 2020 21:21:05 -0700 Subject: [PATCH 0359/1520] Fix spelling in contextvars docs (#262) --- docs/contextvars.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contextvars.rst b/docs/contextvars.rst index 9ae15a78..70e1a3a1 100644 --- a/docs/contextvars.rst +++ b/docs/contextvars.rst @@ -22,7 +22,7 @@ The general flow is: - Use `structlog.configure` with `structlog.contextvars.merge_contextvars` as your first processor. - Call `structlog.contextvars.clear_contextvars` at the beginning of your request handler (or whenever you want to reset the context-local context). -- Call `structlog.contextvars.bind_contextvars` and `structlog.contextvars.unbind_contextvars` instead of you bound logger's ``bind()`` and ``unbind()`` when you want to bind and unbind key-value pairs to the context-local context. +- Call `structlog.contextvars.bind_contextvars` and `structlog.contextvars.unbind_contextvars` instead of your bound logger's ``bind()`` and ``unbind()`` when you want to bind and unbind key-value pairs to the context-local context. - Use ``structlog`` as normal. Loggers act as the always do, but the `structlog.contextvars.merge_contextvars` processor ensures that any context-local binds get included in all of your log messages. From c0d01bdc4d631603a4a784df5f154ef96aab21d2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 18 Jun 2020 09:59:15 +0200 Subject: [PATCH 0360/1520] Add test for _get_context being called before clear_threadlocal --- tests/test_threadlocal.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py index 6a70330f..bc5bb730 100644 --- a/tests/test_threadlocal.py +++ b/tests/test_threadlocal.py @@ -13,6 +13,8 @@ from structlog._config import wrap_logger from structlog.testing import ReturnLogger from structlog.threadlocal import ( + _CONTEXT, + _get_context, as_immutable, bind_threadlocal, clear_threadlocal, @@ -339,3 +341,16 @@ def test_unbind_threadlocal(self): unbind_threadlocal("non-existing-key") assert {"b": 34} == merge_threadlocal_context(None, None, {}) + + def test_get_context_no_context(self): + """ + If there is no context yet, _get_context will add it. + """ + # Don't rely on test order. + if hasattr(_CONTEXT, "context"): + del _CONTEXT.context + + with pytest.raises(AttributeError): + _CONTEXT.context + + assert {} == _get_context() From ce3c8a669abd528e18333796b5491d0a7e6c59ef Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 18 Jun 2020 09:53:42 +0200 Subject: [PATCH 0361/1520] Stop integration-testing with rapidjson It broke on pypy3. The test isn't very interesting anyways. --- setup.py | 1 - tests/test_processors.py | 22 ---------------------- 2 files changed, 23 deletions(-) diff --git a/setup.py b/setup.py index af851dab..35dc17f6 100644 --- a/setup.py +++ b/setup.py @@ -39,7 +39,6 @@ "pytest-asyncio; python_version>='3.7'", "pytest-randomly", "pytest>=3.3.0", - "python-rapidjson", "simplejson", ], "docs": ["sphinx", "twisted"], diff --git a/tests/test_processors.py b/tests/test_processors.py index a1e6f00d..f8a8f648 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -34,11 +34,6 @@ except ImportError: simplejson = None -try: - import rapidjson -except ImportError: - rapidjson = None - class TestKeyValueRenderer: def test_sort_keys(self, event_dict): @@ -197,23 +192,6 @@ def test_simplejson(self, event_dict): "z": [1, 2], } == json.loads(jr(None, None, event_dict)) - @pytest.mark.skipif( - rapidjson is None, reason="python-rapidjson is missing." - ) - def test_rapidjson(self, event_dict): - """ - Integration test with python-rapidjson. - """ - jr = JSONRenderer(serializer=rapidjson.dumps) - - assert { - "a": "", - "b": [3, 4], - "x": 7, - "y": "test", - "z": [1, 2], - } == json.loads(jr(None, None, event_dict)) - class TestTimeStamper: def test_disallows_non_utc_unix_timestamps(self): From 8b7223324d670d64b7924255ed5903711d88f6f5 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 18 Jun 2020 09:52:22 +0200 Subject: [PATCH 0362/1520] Detect TTY ourselves for dev log colors Sadly delayed initialization wreaks havoc with colorama's logic it seems. Fixes #264 --- .pre-commit-config.yaml | 18 +++++++++--------- src/structlog/_config.py | 3 ++- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f3244b6a..b0bd2b19 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,15 +10,8 @@ repos: files: \.pyi?$ types: [] - - repo: https://gitlab.com/pycqa/flake8 - rev: 3.8.0a2 - hooks: - - id: flake8 - language_version: python3.8 - exclude: docs/code_examples - - repo: https://github.com/asottile/seed-isort-config - rev: v2.1.1 + rev: v2.2.0 hooks: - id: seed-isort-config @@ -29,8 +22,15 @@ repos: additional_dependencies: [toml] language_version: python3.8 + - repo: https://gitlab.com/pycqa/flake8 + rev: 3.8.3 + hooks: + - id: flake8 + language_version: python3.8 + exclude: docs/code_examples + - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v2.5.0 + rev: v3.1.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 123bf6be..44248b76 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -7,6 +7,7 @@ """ +import sys import warnings from ._generic import BoundLogger @@ -25,7 +26,7 @@ set_exc_info, format_exc_info, TimeStamper(fmt="%Y-%m-%d %H:%M.%S", utc=False), - ConsoleRenderer(colors=_has_colorama), + ConsoleRenderer(colors=_has_colorama and sys.stdout.isatty()), ] _BUILTIN_DEFAULT_CONTEXT_CLASS = dict _BUILTIN_DEFAULT_WRAPPER_CLASS = BoundLogger From 33008b053d7d1e69b0ce3952fc5c75c6cdc4fc05 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 29 Jun 2020 10:38:06 +0200 Subject: [PATCH 0363/1520] Add structlog.get_context An official way to access the context of a bound logger. Fixes #266 --- CHANGELOG.rst | 6 ++++-- docs/api.rst | 2 ++ src/structlog/__init__.py | 3 ++- src/structlog/_base.py | 18 ++++++++++++++++++ tests/test_base.py | 11 ++++++++--- 5 files changed, 34 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 29b1edd0..830fa9c1 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -20,13 +20,15 @@ Backward-incompatible changes: Deprecations: ^^^^^^^^^^^^^ -*none* +- Accessing the ``_context`` attribute of a bound logger is now deprecated. + Please use the new ``structlog.get_context()``. Changes: ^^^^^^^^ -*none* +- ``structlog.get_context()`` allows you to retrieve the original context of a bound logger. + `#266 `_, ---- diff --git a/docs/api.rst b/docs/api.rst index f0dae729..dba69930 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -42,6 +42,8 @@ API Reference .. autofunction:: get_config +.. autofunction:: get_context + .. autoclass:: BoundLogger :members: new, bind, unbind diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 4994037b..bc374d4a 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -8,7 +8,7 @@ from structlog import dev, processors, stdlib, testing, threadlocal -from structlog._base import BoundLoggerBase +from structlog._base import BoundLoggerBase, get_context from structlog._config import ( configure, configure_once, @@ -63,6 +63,7 @@ "dev", "getLogger", "get_config", + "get_context", "get_logger", "is_configured", "processors", diff --git a/src/structlog/_base.py b/src/structlog/_base.py index f455a226..4987b6fb 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -10,6 +10,24 @@ from structlog.exceptions import DropEvent +def get_context(bound_logger): + """ + Return *bound_logger*'s context. + + The type of *bound_logger* and the typed returned depend on your + configuration. + + :param bound_logger: The bound logger whose context you want. + + :returns: The *actual* context from *bound_logger*. It is *not* copied + first. + + .. versionadded:: 20.2 + """ + # This probably will get more complicated in the future. + return bound_logger._context + + class BoundLoggerBase: """ Immutable context carrier. diff --git a/tests/test_base.py b/tests/test_base.py index 008a9f69..d673bbd1 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -7,6 +7,7 @@ from pretend import raiser, stub +from structlog import get_context from structlog._base import BoundLoggerBase from structlog._config import _CONFIG from structlog.exceptions import DropEvent @@ -45,18 +46,22 @@ def test_binds_independently(self): assert b._context != b1._context != b2._context def test_new_clears_state(self): + """ + Calling clear() on a logger clears the context. + """ b = build_bl() b = b.bind(x=42) - assert 42 == b._context["x"] + assert 42 == get_context(b)["x"] b = b.bind() - assert 42 == b._context["x"] + assert 42 == get_context(b)["x"] b = b.new() - assert "x" not in b._context + assert "x" not in get_context(b) + assert {} == dict(get_context(b)) def test_comparison(self): b = build_bl() From aea950310ed4e714056f847b56cb1dabcef85a9e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 29 Jun 2020 10:43:38 +0200 Subject: [PATCH 0364/1520] Add test docstrings --- tests/test_base.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/test_base.py b/tests/test_base.py index d673bbd1..5110d7e8 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -47,7 +47,7 @@ def test_binds_independently(self): def test_new_clears_state(self): """ - Calling clear() on a logger clears the context. + Calling new() on a logger clears the context. """ b = build_bl() b = b.bind(x=42) @@ -60,10 +60,12 @@ def test_new_clears_state(self): b = b.new() - assert "x" not in get_context(b) assert {} == dict(get_context(b)) def test_comparison(self): + """ + Two bound loggers are equal if their context is equal. + """ b = build_bl() assert b == b.bind() @@ -72,6 +74,10 @@ def test_comparison(self): assert b != "test" def test_bind_keeps_class(self): + """ + Binding values does not change the type of the bound logger. + """ + class Wrapper(BoundLoggerBase): pass @@ -80,6 +86,10 @@ class Wrapper(BoundLoggerBase): assert isinstance(b.bind(), Wrapper) def test_new_keeps_class(self): + """ + Clearing context does not change the type of the bound logger. + """ + class Wrapper(BoundLoggerBase): pass From 85ce14261fa80c4e019551851ee99f1d4d230045 Mon Sep 17 00:00:00 2001 From: Colton Myers Date: Mon, 29 Jun 2020 23:49:37 -0600 Subject: [PATCH 0365/1520] Add docs clarification for processors example (#269) --- docs/processors.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/processors.rst b/docs/processors.rst index ff21ae2b..e7179ce3 100644 --- a/docs/processors.rst +++ b/docs/processors.rst @@ -54,6 +54,7 @@ and call ``log.msg("some_event", y=23)``, it results in the following call chain ) In this case, ``f4`` has to make sure it returns something ``wrapped_logger.msg`` can handle (see :ref:`adapting`). +For the example with ``PrintLogger`` above, this means ``f4`` must return a string. The simplest modification a processor can make is adding new values to the ``event_dict``. Parsing human-readable timestamps is tedious, not so `UNIX timestamps `_ -- let's add one to each log entry! From a861d2c8b2509a27e2c60c9f55c960c5ead76b5e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 30 Jun 2020 07:51:24 +0200 Subject: [PATCH 0366/1520] Doc fixes --- docs/api.rst | 4 ++-- src/structlog/_base.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index dba69930..ca084580 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -42,11 +42,11 @@ API Reference .. autofunction:: get_config -.. autofunction:: get_context - .. autoclass:: BoundLogger :members: new, bind, unbind +.. autofunction:: get_context + .. autoclass:: PrintLogger :members: msg, err, debug, info, warning, error, critical, log, failure, fatal diff --git a/src/structlog/_base.py b/src/structlog/_base.py index 4987b6fb..4e5e068a 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -14,7 +14,7 @@ def get_context(bound_logger): """ Return *bound_logger*'s context. - The type of *bound_logger* and the typed returned depend on your + The type of *bound_logger* and the type returned depend on your configuration. :param bound_logger: The bound logger whose context you want. From d3fd52f29f10f4d080968d042bfce689b9bab381 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 1 Jul 2020 07:07:02 +0200 Subject: [PATCH 0367/1520] Add FUNDING.yml --- .github/FUNDING.yml | 4 ++++ README.rst | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..5bd7861e --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,4 @@ +--- + +github: hynek +ko_fi: the_hynek diff --git a/README.rst b/README.rst index 58d51c55..04bd3c77 100644 --- a/README.rst +++ b/README.rst @@ -23,10 +23,6 @@ :target: https://github.com/psf/black :alt: Code style: black -.. image:: https://www.ko-fi.com/img/githubbutton_sm.svg - :target: https://ko-fi.com/the_hynek - :alt: Support this project by buying me a coffee! - .. -begin-short- ``structlog`` makes logging in Python less painful and more powerful by adding structure to your log entries. From 0a754642b9ac6a35a3026564a584adacbb69fb46 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 20 Jul 2020 10:37:32 +0200 Subject: [PATCH 0368/1520] Add workflow_dispatch: --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fcbb2d0c..42852ec1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -6,6 +6,7 @@ on: branches: ["master"] pull_request: branches: ["master"] + workflow_dispatch: jobs: tests: From 40ad1357e8b06e5debd58c9d03f082267d96872f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 20 Jul 2020 10:38:22 +0200 Subject: [PATCH 0369/1520] pre-commit autoupdate --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b0bd2b19..9b89a13c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,7 +16,7 @@ repos: - id: seed-isort-config - repo: https://github.com/pre-commit/mirrors-isort - rev: v4.3.21 + rev: v5.1.4 hooks: - id: isort additional_dependencies: [toml] From 827f0e91db906067163667f4950e1a0411db1bba Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 21 Jul 2020 16:00:20 +0200 Subject: [PATCH 0370/1520] Add tidelift --- .github/FUNDING.yml | 1 + README.rst | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 5bd7861e..3fbd7100 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -2,3 +2,4 @@ github: hynek ko_fi: the_hynek +tidelift: pypi/structlog diff --git a/README.rst b/README.rst index 04bd3c77..07535e74 100644 --- a/README.rst +++ b/README.rst @@ -139,3 +139,10 @@ We collect useful third party extension in `our wiki `_. The package meta data should ensure that you get the correct version. + +``structlog`` for Enterprise +---------------------------- + +Available as part of the Tidelift Subscription. + +The maintainers of structlog and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. `Learn more. `_ From 610700003964cd5b71644cb8576681c07edd6104 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 21 Jul 2020 17:07:39 +0200 Subject: [PATCH 0371/1520] Add SECURITY.yml --- .github/SECURITY.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .github/SECURITY.yml diff --git a/.github/SECURITY.yml b/.github/SECURITY.yml new file mode 100644 index 00000000..33747b92 --- /dev/null +++ b/.github/SECURITY.yml @@ -0,0 +1,3 @@ +To report a security vulnerability, please use the [Tidelift security +contact](https://tidelift.com/security). Tidelift will coordinate the fix and +disclosure. From 3c22651edde9e99e1b1cd29fb753d84ea1243957 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 21 Jul 2020 17:11:28 +0200 Subject: [PATCH 0372/1520] Add project_urls --- setup.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/setup.py b/setup.py index 35dc17f6..739079b5 100644 --- a/setup.py +++ b/setup.py @@ -13,6 +13,11 @@ NAME = "structlog" KEYWORDS = ["logging", "structured", "structure", "log"] +PROJECT_URLS = { + "Documentation": "https://www.structlog.org/", + "Bug Tracker": "https://github.com/hynek/structlog/issues", + "Source Code": "https://github.com/hynek/structlog", +} CLASSIFIERS = [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", @@ -108,6 +113,7 @@ def find_meta(meta): description=find_meta("description"), license=find_meta("license"), url=find_meta("uri"), + project_urls=PROJECT_URLS, version=VERSION, author=find_meta("author"), author_email=find_meta("email"), From 93cc56b1972fbbc06c145caeb69ebde6c1bbd64c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 29 Jul 2020 10:55:06 +0200 Subject: [PATCH 0373/1520] Update, move pytest config to pyproject.toml --- .pre-commit-config.yaml | 2 +- pyproject.toml | 9 ++++++++- setup.py | 2 +- tox.ini | 8 -------- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9b89a13c..3aa5a6ba 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,7 +16,7 @@ repos: - id: seed-isort-config - repo: https://github.com/pre-commit/mirrors-isort - rev: v5.1.4 + rev: v5.2.1 hooks: - id: isort additional_dependencies: [toml] diff --git a/pyproject.toml b/pyproject.toml index 8449db9f..e3d7377f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,6 +3,14 @@ requires = ["setuptools>=40.6.0", "wheel"] build-backend = "setuptools.build_meta" +[tool.pytest.ini_options] +addopts = "-ra" +testpaths = "tests" +filterwarnings = [ + "once::Warning", +] + + [tool.coverage.run] parallel = true branch = true @@ -25,7 +33,6 @@ include_trailing_comma=true lines_after_imports=2 lines_between_types=1 multi_line_output=3 -not_skip="__init__.py" known_first_party="structlog" known_third_party=["flask", "freezegun", "pretend", "pytest", "setuptools", "some_module", "structlog", "twisted", "zope"] diff --git a/setup.py b/setup.py index 739079b5..b4da9e9a 100644 --- a/setup.py +++ b/setup.py @@ -43,7 +43,7 @@ "pretend", "pytest-asyncio; python_version>='3.7'", "pytest-randomly", - "pytest>=3.3.0", + "pytest>=6.0", "simplejson", ], "docs": ["sphinx", "twisted"], diff --git a/tox.ini b/tox.ini index 0edc4c9e..429ad795 100644 --- a/tox.ini +++ b/tox.ini @@ -1,11 +1,3 @@ -[pytest] -strict = true -addopts = -ra -testpaths = tests -filterwarnings = - once::Warning - - # Keep docs in sync with docs env and .readthedocs.yml. [gh-actions] python = From 7a8a59697fcb28756afbd8e8b6e4ca6e866d359c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 13 Aug 2020 13:57:47 +0200 Subject: [PATCH 0374/1520] Test on 3.9 too --- .github/workflows/main.yml | 4 ++-- tox.ini | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 42852ec1..81df7ebd 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,11 +13,11 @@ jobs: name: "Python ${{ matrix.python-version }}" runs-on: "ubuntu-latest" env: - USING_COVERAGE: '3.6,3.8' + USING_COVERAGE: "3.6,3.8" strategy: matrix: - python-version: ["3.6", "3.7", "3.8", "pypy3"] + python-version: ["3.6", "3.7", "3.8", "3.9.0-alpha - 3.9.0", "pypy3"] steps: - uses: "actions/checkout@v2" diff --git a/tox.ini b/tox.ini index 429ad795..318831d6 100644 --- a/tox.ini +++ b/tox.ini @@ -4,11 +4,12 @@ python = 3.6: py36 3.7: py37, docs 3.8: py38, lint, manifest + 3.9: py39 pypy3: pypy3 [tox] -envlist = lint,{py36,py37,py38,pypy3}-threads,{py38,pypy3}-greenlets,py38-colorama,docs,pypi-description,manifest,coverage-report +envlist = lint,{py36,py37,py38,py39,pypy3}-threads,{py38,py39,pypy3}-greenlets,py38-colorama,docs,pypi-description,manifest,coverage-report isolated_build = True From d549ee6c78f675919d8a4730525e53b1ffedbe3d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 24 Aug 2020 09:27:02 +0200 Subject: [PATCH 0375/1520] Add 3.9 --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index b4da9e9a..72e9321b 100644 --- a/setup.py +++ b/setup.py @@ -29,6 +29,7 @@ "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Programming Language :: Python", From f43213924efb8960b256a7fabdc6ed9432998780 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 4 Sep 2020 09:56:39 +0200 Subject: [PATCH 0376/1520] CI: Use v2 of setup-python So we get pre-releases. --- .github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 81df7ebd..11107535 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -21,7 +21,7 @@ jobs: steps: - uses: "actions/checkout@v2" - - uses: "actions/setup-python@v1" + - uses: "actions/setup-python@v2" with: python-version: "${{ matrix.python-version }}" - name: "Install dependencies" @@ -53,7 +53,7 @@ jobs: steps: - uses: "actions/checkout@v2" - - uses: "actions/setup-python@v1" + - uses: "actions/setup-python@v2" with: python-version: "3.8" @@ -76,7 +76,7 @@ jobs: steps: - uses: "actions/checkout@v2" - - uses: "actions/setup-python@v1" + - uses: "actions/setup-python@v2" with: python-version: "3.8" - name: "Install in dev mode" From f274330e6fb4f33062325edf3a7a2c23aa1af91e Mon Sep 17 00:00:00 2001 From: Andrii Yurchuk Date: Thu, 10 Sep 2020 12:38:39 +0200 Subject: [PATCH 0377/1520] Fix typo in thread-local doc (#274) --- docs/thread-local.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/thread-local.rst b/docs/thread-local.rst index 49b09f84..26683545 100644 --- a/docs/thread-local.rst +++ b/docs/thread-local.rst @@ -28,7 +28,7 @@ If you are willing to do that, you should stick to it because `immutable state < Sooner or later, global state and mutable data lead to unpleasant surprises. However, in the case of conventional web development, we realize that passing loggers around seems rather cumbersome, intrusive, and generally against the mainstream culture. -And since it's more important that people actually *use* ``structlog`` than to be pure and snobby, ``structlog`` contains ships with the `structlog.threadlocal` module and a couple of mechanisms to help here. +And since it's more important that people actually *use* ``structlog`` than to be pure and snobby, ``structlog`` ships with the `structlog.threadlocal` module and a couple of mechanisms to help here. The ``merge_threadlocal`` Processor From 0b601fe83822e4530dd9b0b4698bb676899d74cb Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Thu, 1 Oct 2020 06:41:48 +0100 Subject: [PATCH 0378/1520] Remove exception control flow from ProcessorFormatter (#276) * Remove exception control flow from ProcessorFormatter I encountered this issue when combining structlog, stdlib logging, and structlog-sentry. structlog-sentry always attaches the current stack trace to events: https://github.com/kiwicom/structlog-sentry/blob/c15fdb076900e87e577bd0f2d7ef0d847706b366/structlog_sentry/__init__.py#L45 . Unfortunately because `ProcessorFormatter.format` was using an `AttributeError` for control flow, that would mean the current exception fetched by `sys.exc_info()` would always be that `AttributeError`. This PR adds a test for that case, and changes `ProcessorFormatter.format` to use `hasattr` to check for wrapped event dicts. * Update changelog, remove hasattr() usage, use 'is' in test * Black * Add test covering ProcessorFormatter with logger processing a structlog-originated record * Remove unnecessary configuration of structlog in TestProcessFormatter * isort --- CHANGELOG.rst | 1 + src/structlog/stdlib.py | 14 +++++++-- tests/test_stdlib.py | 65 +++++++++++++++++++++++++---------------- 3 files changed, 52 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 830fa9c1..65d808b0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -30,6 +30,7 @@ Changes: - ``structlog.get_context()`` allows you to retrieve the original context of a bound logger. `#266 `_, +- ``structlog.stdlib.ProcessorFormatter`` no longer uses exceptions for control flow, allowing ``foreign_pre_chain`` processors to use ``sys.exc_info()`` to access the real exception. ---- diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index edaeccdd..df147171 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -16,6 +16,9 @@ from structlog.exceptions import DropEvent +_SENTINEL = object() + + class _FixedFindCallerLogger(logging.Logger): """ Change the behavior of `logging.Logger.findCaller` to cope with @@ -499,16 +502,21 @@ def format(self, record): # Make a shallow copy of the record to let other handlers/formatters # process the original one record = logging.makeLogRecord(record.__dict__) - try: + + logger = getattr(record, "_logger", _SENTINEL) + meth_name = getattr(record, "_name", _SENTINEL) + + if logger is not _SENTINEL and meth_name is not _SENTINEL: # Both attached by wrap_for_formatter - logger = self.logger if self.logger is not None else record._logger + if self.logger is not None: + logger = self.logger meth_name = record._name # We need to copy because it's possible that the same record gets # processed by multiple logging formatters. LogRecord.getMessage # would transform our dict into a str. ed = record.msg.copy() - except AttributeError: + else: logger = self.logger meth_name = record.levelname.lower() ed = {"event": record.getMessage(), "_record": record} diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index bcaef7b8..c3327bf2 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -7,6 +7,7 @@ import logging import logging.config import os +import sys import pytest @@ -502,11 +503,6 @@ def test_foreign_delegate(self, configure_for_pf, capsys): to logging. """ configure_logging(None) - configure( - processors=[ProcessorFormatter.wrap_for_formatter], - logger_factory=LoggerFactory(), - wrapper_class=BoundLogger, - ) logging.getLogger().warning("foo") @@ -537,11 +533,6 @@ def test_pass_foreign_args_true_sets_positional_args_key( """ test_processor = call_recorder(lambda l, m, event_dict: event_dict) configure_logging((test_processor,), pass_foreign_args=True) - configure( - processors=[ProcessorFormatter.wrap_for_formatter], - logger_factory=LoggerFactory(), - wrapper_class=BoundLogger, - ) positional_args = {"foo": "bar"} logging.getLogger().info("okay %(foo)s", positional_args) @@ -570,11 +561,6 @@ def test_foreign_pre_chain(self, configure_for_pf, capsys): non-structlog log entries. """ configure_logging((add_log_level,)) - configure( - processors=[ProcessorFormatter.wrap_for_formatter], - logger_factory=LoggerFactory(), - wrapper_class=BoundLogger, - ) logging.getLogger().warning("foo") @@ -588,11 +574,6 @@ def test_foreign_pre_chain_add_logger_name(self, configure_for_pf, capsys): foreign_pre_chain works with add_logger_name processor. """ configure_logging((add_logger_name,)) - configure( - processors=[ProcessorFormatter.wrap_for_formatter], - logger_factory=LoggerFactory(), - wrapper_class=BoundLogger, - ) logging.getLogger("sample-name").warning("foo") @@ -631,11 +612,6 @@ def test_foreign_pre_chain_gets_exc_info(self, configure_for_pf, capsys): """ test_processor = call_recorder(lambda l, m, event_dict: event_dict) configure_logging((test_processor,)) - configure( - processors=[ProcessorFormatter.wrap_for_formatter], - logger_factory=LoggerFactory(), - wrapper_class=BoundLogger, - ) try: raise RuntimeError("oh noo") @@ -647,6 +623,31 @@ def test_foreign_pre_chain_gets_exc_info(self, configure_for_pf, capsys): assert "exc_info" in event_dict assert isinstance(event_dict["exc_info"], tuple) + def test_foreign_pre_chain_sys_exc_info(self, configure_for_pf, capsys): + """ + If a foreign_pre_chain function accesses sys.exc_info(), + ProcessorFormatter should not have changed it. + """ + + class MyException(Exception): + pass + + def add_excinfo(logger, log_method, event_dict): + event_dict["exc_info"] = sys.exc_info() + return event_dict + + test_processor = call_recorder(lambda l, m, event_dict: event_dict) + configure_logging((add_excinfo, test_processor)) + + try: + raise MyException("oh noo") + except Exception: + logging.getLogger().error("okay") + + event_dict = test_processor.calls[0].args[2] + + assert MyException is event_dict["exc_info"][0] + def test_other_handlers_get_original_record( self, configure_for_pf, capsys ): @@ -753,6 +754,20 @@ def test_native(self, configure_for_pf, capsys): "[warning ] foo [in test_native]\n", ) == capsys.readouterr() + def test_native_logger(self, configure_for_pf, capsys): + """ + If the log entry comes from structlog, it's unpackaged and processed. + """ + logger = logging.getLogger() + configure_logging(None, logger=logger) + + get_logger().warning("foo") + + assert ( + "", + "[warning ] foo [in test_native_logger]\n", + ) == capsys.readouterr() + def test_foreign_pre_chain_filter_by_level(self, configure_for_pf, capsys): """ foreign_pre_chain works with filter_by_level processor. From 451873df5d6136137132c6c2737989fdd4c0ab8a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 2 Oct 2020 10:01:00 +0100 Subject: [PATCH 0379/1520] Add missing word and line --- README.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 07535e74..b91b20be 100644 --- a/README.rst +++ b/README.rst @@ -125,7 +125,7 @@ Getting Help Please use the ``structlog`` tag on `StackOverflow `_ to get help. -Answering questions of your fellow developers is also great way to help the project! +Answering questions of your fellow developers is also a great way to help the project! Project Information @@ -140,9 +140,11 @@ We collect useful third party extension in `our wiki `_. The package meta data should ensure that you get the correct version. + ``structlog`` for Enterprise ---------------------------- Available as part of the Tidelift Subscription. -The maintainers of structlog and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. `Learn more. `_ +The maintainers of structlog and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. +`Learn more. `_ From fc70e950406b8820a043d9accfb046210c75f0b9 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Mon, 5 Oct 2020 07:42:12 +0100 Subject: [PATCH 0380/1520] Document that capture_logs() relies on un-cached loggers (#278) --- docs/performance.rst | 2 +- docs/testing.rst | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/performance.rst b/docs/performance.rst index b98e591d..2a53313e 100644 --- a/docs/performance.rst +++ b/docs/performance.rst @@ -34,7 +34,7 @@ Here are a few hints how to get most out of ``structlog`` in production: configure(cache_logger_on_first_use=True) - This has the only drawback is that later calls on :func:`~structlog.configure` don't have any effect on already cached loggers -- that shouldn't matter outside of testing though. + This has the only drawback is that later calls on :func:`~structlog.configure` don't have any effect on already cached loggers -- that shouldn't matter outside of :doc:`testing ` though. #. Use a faster JSON serializer than the standard library. Possible alternatives are among others simplejson_, orjson_, or RapidJSON_:: diff --git a/docs/testing.rst b/docs/testing.rst index e69791d7..c3258ed8 100644 --- a/docs/testing.rst +++ b/docs/testing.rst @@ -16,6 +16,11 @@ If you need functionality similar to `unittest.TestCase.assertLogs`, or you want Note that inside the context manager all configured processors are disabled. +.. note:: + + ``capture_logs()`` relies on changing the configuration. + If you have *cache_logger_on_first_use* enabled for :doc:`performance `, any cached loggers will not be affected, so it’s recommended you do not enable it during tests. + You can build your own helpers using `structlog.testing.LogCapture`. For example a `pytest `_ fixture to capture log output could look like this:: From bf760f8229d050fec7860c2a4a67bb041f709e94 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 5 Oct 2020 08:39:23 +0100 Subject: [PATCH 0381/1520] Switch docs to furo --- docs/conf.py | 8 ++------ setup.py | 4 ++-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 9d6ecc45..87bccb51 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -128,13 +128,9 @@ def find_version(*file_paths): # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = "alabaster" +html_theme = "furo" html_theme_options = { - "font_family": '"Avenir Next", Calibri, "PT Sans", sans-serif', - "head_font_family": '"Avenir Next", Calibri, "PT Sans", sans-serif', - "font_size": "18px", - "page_width": "980px", - "show_relbars": True, + "sidebar_hide_name": True, } html_logo = "_static/structlog_logo_small.png" diff --git a/setup.py b/setup.py index 72e9321b..0d8994fa 100644 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ "pytest>=6.0", "simplejson", ], - "docs": ["sphinx", "twisted"], + "docs": ["furo", "sphinx", "twisted"], } EXTRAS_REQUIRE["dev"] = ( EXTRAS_REQUIRE["tests"] + EXTRAS_REQUIRE["docs"] + ["pre-commit"] @@ -89,7 +89,7 @@ def find_meta(meta): ) if meta_match: return meta_match.group(1) - raise RuntimeError(f"Unable to find __{meta}__ string.") + raise RuntimeError(f"Unable to find __{ meta }__ string.") VERSION = find_meta("version") From 69d9e9328d86cdc5e395eadd119c9775ee7343f7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 5 Oct 2020 10:16:29 +0100 Subject: [PATCH 0382/1520] Use a transparent logo and use proper text --- .../structlog_logo_small_transparent.png | Bin 0 -> 26266 bytes docs/conf.py | 6 ++---- 2 files changed, 2 insertions(+), 4 deletions(-) create mode 100644 docs/_static/structlog_logo_small_transparent.png diff --git a/docs/_static/structlog_logo_small_transparent.png b/docs/_static/structlog_logo_small_transparent.png new file mode 100644 index 0000000000000000000000000000000000000000..2da2a22df5830cd499bb699d392f2122b3ad4798 GIT binary patch literal 26266 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 VIqE)P!2 Date: Fri, 23 Oct 2020 18:44:07 +0400 Subject: [PATCH 0383/1520] Stop using OrderedDict altogether (#280) --- docs/getting-started.rst | 2 +- docs/loggers.rst | 3 +-- tests/test_config.py | 17 ++--------------- tests/test_stdlib.py | 2 -- tests/test_threadlocal.py | 6 ++---- tests/test_twisted.py | 3 +-- 6 files changed, 7 insertions(+), 26 deletions(-) diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 08d9cb59..9171f146 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -100,7 +100,7 @@ For ``structlog``, a log entry is just a dictionary called *event dict[ionary]*: - As soon as an *event* happens -- which is a dictionary too -- it is merged together with the *context* to an *event dict* and logged out. - If you don't like the concept of pre-building a context: just don't! Convenient key-value-based logging is great to have on its own. -- To keep as much order of the keys as possible, an `collections.OrderedDict` is used for the context by default for Pythons that do not have ordered dictionaries by default (notably all versions of CPython before 3.6). +- Python keeps dictionaries ordered by keys by default. - The recommended way of binding values is the one in these examples: creating new loggers with a new context. If you're okay with giving up immutable local state for convenience, you can also use `thread/greenlet local storage ` or :doc:`context variables ` for the context. diff --git a/docs/loggers.rst b/docs/loggers.rst index 6c990754..8902014e 100644 --- a/docs/loggers.rst +++ b/docs/loggers.rst @@ -91,8 +91,7 @@ As you can see, it accepts one mandatory and a few optional arguments: The class to save your context in. Particularly useful for `thread local context storage `. - On Python versions that have ordered dictionaries (Python 3.6+, PyPy) the default is a plain `dict`. - For everything else it's `collections.OrderedDict`. + Since Python 3.6+ and PyPy have ordered dictionaries, the default is a plain `dict`. Additionally, the following arguments are allowed too: diff --git a/tests/test_config.py b/tests/test_config.py index e33238e7..4bcb1e3b 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -5,12 +5,8 @@ import abc import pickle -import platform -import sys import warnings -from collections import OrderedDict - import pytest from pretend import call, call_recorder, stub @@ -62,18 +58,9 @@ class Foo(metaclass=abc.ABCMeta): def test_default_context_class(): """ - Default context class is dict on Python 3.6+ and PyPy, OrderedDict - otherwise. + Default context class is dict on Python 3.6+ and PyPy """ - if platform.python_implementation() == "PyPy" or sys.version_info[:2] >= ( - 3, - 6, - ): - cls = dict - else: - cls = OrderedDict - - assert cls is _BUILTIN_DEFAULT_CONTEXT_CLASS + assert dict is _BUILTIN_DEFAULT_CONTEXT_CLASS class TestConfigure: diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index c3327bf2..89f7eac1 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -3,7 +3,6 @@ # repository for complete details. -import collections import logging import logging.config import os @@ -684,7 +683,6 @@ def test_formatter_unsets_exc_info(self, configure_for_pf, capsys, keep): logger = logging.getLogger() def format_exc_info_fake(logger, name, event_dict): - event_dict = collections.OrderedDict(event_dict) del event_dict["exc_info"] event_dict["exception"] = "Exception!" return event_dict diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py index bc5bb730..1675078f 100644 --- a/tests/test_threadlocal.py +++ b/tests/test_threadlocal.py @@ -5,8 +5,6 @@ import threading -from collections import OrderedDict - import pytest from structlog._base import BoundLoggerBase @@ -43,9 +41,9 @@ def D(): @pytest.fixture def log(logger): """ - Returns a ReturnLogger with a freshly wrapped OrderedDict. + Returns a ReturnLogger with a freshly wrapped dict. """ - return wrap_logger(logger, context_class=wrap_dict(OrderedDict)) + return wrap_logger(logger, context_class=wrap_dict(dict)) @pytest.fixture diff --git a/tests/test_twisted.py b/tests/test_twisted.py index a3a71e42..fee74979 100644 --- a/tests/test_twisted.py +++ b/tests/test_twisted.py @@ -5,7 +5,6 @@ import json -from collections import OrderedDict from io import StringIO import pytest @@ -230,7 +229,7 @@ def test_dumpsKWsAreHandedThrough(self, jr): JSONRenderer allows for setting arguments that are passed to json.dumps(). Make sure they are passed. """ - d = OrderedDict(x="foo") + d = {"x": "foo"} d.update(a="bar") jr_sorted = JSONRenderer(sort_keys=True) From 43474354e810cbd1a6893e107b1c7a780fde0073 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 23 Oct 2020 16:45:07 +0200 Subject: [PATCH 0384/1520] Use proper 3.9 in CI --- .github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 11107535..c86d1718 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -17,7 +17,7 @@ jobs: strategy: matrix: - python-version: ["3.6", "3.7", "3.8", "3.9.0-alpha - 3.9.0", "pypy3"] + python-version: ["3.6", "3.7", "3.8", "3.9", "pypy3"] steps: - uses: "actions/checkout@v2" @@ -55,7 +55,7 @@ jobs: - uses: "actions/checkout@v2" - uses: "actions/setup-python@v2" with: - python-version: "3.8" + python-version: "3.9" - name: "Install pep517 and twine" run: "python -m pip install pep517 twine" @@ -78,7 +78,7 @@ jobs: - uses: "actions/checkout@v2" - uses: "actions/setup-python@v2" with: - python-version: "3.8" + python-version: "3.9" - name: "Install in dev mode" run: "python -m pip install -e .[dev]" - name: "Import package" From 87a68c6cb0ada8f95e697a984d61160b53f9e778 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 2 Nov 2020 14:24:50 +0100 Subject: [PATCH 0385/1520] pre-commit autoupdate and drop isort seed --- .pre-commit-config.yaml | 13 ++++--------- pyproject.toml | 9 +-------- tests/test_twisted.py | 19 +++++++++++-------- tox.ini | 5 ++--- 4 files changed, 18 insertions(+), 28 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3aa5a6ba..c9d7ed71 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ repos: - repo: https://github.com/psf/black - rev: 19.10b0 + rev: 20.8b1 hooks: - id: black language_version: python3.8 @@ -10,27 +10,22 @@ repos: files: \.pyi?$ types: [] - - repo: https://github.com/asottile/seed-isort-config - rev: v2.2.0 - hooks: - - id: seed-isort-config - - repo: https://github.com/pre-commit/mirrors-isort - rev: v5.2.1 + rev: v5.6.4 hooks: - id: isort additional_dependencies: [toml] language_version: python3.8 - repo: https://gitlab.com/pycqa/flake8 - rev: 3.8.3 + rev: 3.8.4 hooks: - id: flake8 language_version: python3.8 exclude: docs/code_examples - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.1.0 + rev: v3.3.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer diff --git a/pyproject.toml b/pyproject.toml index e3d7377f..85418117 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,11 +28,4 @@ line-length = 79 [tool.isort] -atomic=true -include_trailing_comma=true -lines_after_imports=2 -lines_between_types=1 -multi_line_output=3 - -known_first_party="structlog" -known_third_party=["flask", "freezegun", "pretend", "pytest", "setuptools", "some_module", "structlog", "twisted", "zope"] +profile = "attrs" diff --git a/tests/test_twisted.py b/tests/test_twisted.py index fee74979..edd98762 100644 --- a/tests/test_twisted.py +++ b/tests/test_twisted.py @@ -79,15 +79,18 @@ def test_errWithFailure(self): except ValueError: # Use str() for comparison to avoid tricky # deep-compares of Failures. - assert str( - ( - (), - { - "_stuff": Failure(ValueError()), - "_why": "foo=42 event='event'", - }, + assert ( + str( + ( + (), + { + "_stuff": Failure(ValueError()), + "_why": "foo=42 event='event'", + }, + ) ) - ) == str(bl.err("event", foo=42)) + == str(bl.err("event", foo=42)) + ) class TestExtractStuffAndWhy: diff --git a/tox.ini b/tox.ini index 318831d6..8091afc6 100644 --- a/tox.ini +++ b/tox.ini @@ -3,8 +3,8 @@ python = 3.6: py36 3.7: py37, docs - 3.8: py38, lint, manifest - 3.9: py39 + 3.8: py38, lint + 3.9: py39, manifest pypy3: pypy3 @@ -80,7 +80,6 @@ commands = [testenv:manifest] -basepython = python3.8 skip_install = true deps = check-manifest commands = check-manifest From f0d241211d6752f8da032218044f884437d809cb Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 2 Nov 2020 17:54:53 +0100 Subject: [PATCH 0386/1520] Test dev env under 3.8 Twisted on Windows can't be installed on 3.9 yet. --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c86d1718..fb692f52 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -78,7 +78,7 @@ jobs: - uses: "actions/checkout@v2" - uses: "actions/setup-python@v2" with: - python-version: "3.9" + python-version: "3.8" - name: "Install in dev mode" run: "python -m pip install -e .[dev]" - name: "Import package" From d4e3c9a4c57217afdd245f75969f9cb51542a111 Mon Sep 17 00:00:00 2001 From: AlfieYou <38186427+youtian001@users.noreply.github.com> Date: Wed, 4 Nov 2020 20:05:19 +0800 Subject: [PATCH 0387/1520] Fix the bug that ConsoleRenderer will throw exception when there is no event key in event_dict (#272) Co-authored-by: Alfie You Co-authored-by: Hynek Schlawack --- src/structlog/dev.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 4907aa66..748fa6f9 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -215,7 +215,7 @@ def __call__(self, _, __, event_dict): ) # force event to str for compatibility with standard library - event = event_dict.pop("event") + event = event_dict.pop("event", None) if not isinstance(event, str): event = str(event) From a96d3024cf915b979231d5fbb1f2834e6fa0825c Mon Sep 17 00:00:00 2001 From: Stefan Schneider Date: Wed, 4 Nov 2020 13:13:51 +0100 Subject: [PATCH 0388/1520] Support deepcopy (#270) * add deepcopy to PrintLogger * exception for __deepcopy__ in BoundLogger.__getattr__ * deepcopy test; improved format * added change to changelog * versionadded, versionchanged directives * Revert "versionadded, versionchanged directives" This reverts commit 72e9cebd416b445e287f28d9a2c5bd46a0ea36eb. * added tests to increase coverage * fixed flake error (line too long) * pre-commit hooks Co-authored-by: Hynek Schlawack --- CHANGELOG.rst | 4 +++- src/structlog/_generic.py | 3 +++ src/structlog/_loggers.py | 17 +++++++++++++++++ tests/test_generic.py | 12 ++++++++++++ tests/test_loggers.py | 18 ++++++++++++++++++ 5 files changed, 53 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 65d808b0..c6dab2f8 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -29,9 +29,11 @@ Changes: - ``structlog.get_context()`` allows you to retrieve the original context of a bound logger. `#266 `_, - +- ``PrintLogger`` now supports ``deepcopy``. + `#268 `_ - ``structlog.stdlib.ProcessorFormatter`` no longer uses exceptions for control flow, allowing ``foreign_pre_chain`` processors to use ``sys.exc_info()`` to access the real exception. + ---- diff --git a/src/structlog/_generic.py b/src/structlog/_generic.py index 77f2d7b7..126870e7 100644 --- a/src/structlog/_generic.py +++ b/src/structlog/_generic.py @@ -29,6 +29,9 @@ def __getattr__(self, method_name): """ If not done so yet, wrap the desired logger method & cache the result. """ + if method_name == "__deepcopy__": + return None + wrapped = partial(self._proxy_to_logger, method_name) setattr(self, method_name, wrapped) return wrapped diff --git a/src/structlog/_loggers.py b/src/structlog/_loggers.py index c36dba98..a235b484 100644 --- a/src/structlog/_loggers.py +++ b/src/structlog/_loggers.py @@ -7,6 +7,7 @@ """ +import copy import sys import threading @@ -102,6 +103,22 @@ def __setstate__(self, state): self._flush = self._file.flush self._lock = _get_lock_for_file(self._file) + def __deepcopy__(self, memodict={}): + """ + Create a new PrintLogger with the same attributes. Similar to pickling. + """ + if self._file not in (sys.stdout, sys.stderr): + raise copy.error( + "Only PrintLoggers to sys.stdout and sys.stderr " + "can be deepcopied." + ) + + newself = self.__class__(self._file) + newself._write = newself._file.write + newself._flush = newself._file.flush + newself._lock = _get_lock_for_file(newself._file) + return newself + def __repr__(self): return f"" diff --git a/tests/test_generic.py b/tests/test_generic.py index 2de22982..13181672 100644 --- a/tests/test_generic.py +++ b/tests/test_generic.py @@ -65,3 +65,15 @@ def test_pickle(self, proto): ).bind(x=1) assert b.info("hi") == pickle.loads(pickle.dumps(b, proto)).info("hi") + + def test_deepcopy(self): + """ + __getattr__ returns None for '__deepcopy__' + """ + b = BoundLogger( + ReturnLogger(), + _CONFIG.default_processors, + _CONFIG.default_context_class(), + ) + + assert b.__deepcopy__ is None diff --git a/tests/test_loggers.py b/tests/test_loggers.py index 38f1065d..56514b33 100644 --- a/tests/test_loggers.py +++ b/tests/test_loggers.py @@ -6,6 +6,7 @@ import pickle import sys +from copy import deepcopy, error from io import StringIO import pytest @@ -97,6 +98,23 @@ def test_pickle_not_stdout_stderr(self, tmpdir, proto): with pytest.raises(pickle.PicklingError, match="Only PrintLoggers to"): pickle.dumps(pl, proto) + def test_deepcopy(self, capsys): + """ + Deepcopied PrintLogger works. But only with stdout or stderr. + """ + copied_logger = deepcopy(PrintLogger()) + copied_logger.msg("hello") + + out, err = capsys.readouterr() + assert "hello\n" == out + assert "" == err + + # this should raise an exception because _file is not stdout or stderr + copied_logger._file = "abc" + with pytest.raises(error): + copied_logger2 = deepcopy(copied_logger) + copied_logger2.msg("hello") + class TestPrintLoggerFactory: def test_does_not_cache(self): From 178f8fd8b4a9fc11759f7291793ed09b8600f454 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 4 Nov 2020 13:15:26 +0100 Subject: [PATCH 0389/1520] Tweak coverage and pytest options --- pyproject.toml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 85418117..c71dea30 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,11 @@ [build-system] -requires = ["setuptools>=40.6.0", "wheel"] +requires = ["setuptools>=40.6.0"] build-backend = "setuptools.build_meta" [tool.pytest.ini_options] -addopts = "-ra" +addopts = "-ra --strict-markers " +xfail_strict = true testpaths = "tests" filterwarnings = [ "once::Warning", @@ -21,6 +22,7 @@ source = ["src", ".tox/*/site-packages"] [tool.coverage.report] show_missing = true +skip_covered = true [tool.black] From f523246e30530028f029a33be8d3de67638f8a0f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 4 Nov 2020 13:30:19 +0100 Subject: [PATCH 0390/1520] Minor polish --- CHANGELOG.rst | 2 +- src/structlog/_loggers.py | 2 ++ tests/test_loggers.py | 24 ++++++++++++++++-------- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c6dab2f8..685f2d20 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -29,7 +29,7 @@ Changes: - ``structlog.get_context()`` allows you to retrieve the original context of a bound logger. `#266 `_, -- ``PrintLogger`` now supports ``deepcopy``. +- ``structlog.PrintLogger`` now supports ``copy.deepcopy()``. `#268 `_ - ``structlog.stdlib.ProcessorFormatter`` no longer uses exceptions for control flow, allowing ``foreign_pre_chain`` processors to use ``sys.exc_info()`` to access the real exception. diff --git a/src/structlog/_loggers.py b/src/structlog/_loggers.py index a235b484..e5fa8e36 100644 --- a/src/structlog/_loggers.py +++ b/src/structlog/_loggers.py @@ -114,9 +114,11 @@ def __deepcopy__(self, memodict={}): ) newself = self.__class__(self._file) + newself._write = newself._file.write newself._flush = newself._file.flush newself._lock = _get_lock_for_file(newself._file) + return newself def __repr__(self): diff --git a/tests/test_loggers.py b/tests/test_loggers.py index 56514b33..bc1e0b3e 100644 --- a/tests/test_loggers.py +++ b/tests/test_loggers.py @@ -3,10 +3,10 @@ # repository for complete details. +import copy import pickle import sys -from copy import deepcopy, error from io import StringIO import pytest @@ -100,20 +100,28 @@ def test_pickle_not_stdout_stderr(self, tmpdir, proto): def test_deepcopy(self, capsys): """ - Deepcopied PrintLogger works. But only with stdout or stderr. + Deepcopied PrintLogger works. """ - copied_logger = deepcopy(PrintLogger()) + copied_logger = copy.deepcopy(PrintLogger()) copied_logger.msg("hello") out, err = capsys.readouterr() assert "hello\n" == out assert "" == err - # this should raise an exception because _file is not stdout or stderr - copied_logger._file = "abc" - with pytest.raises(error): - copied_logger2 = deepcopy(copied_logger) - copied_logger2.msg("hello") + def test_deepcopy_no_stdout(self, tmp_path): + """ + Only PrintLoggers that log to stdout or stderr can be deepcopy-ed. + """ + p = tmp_path / "log.txt" + with p.open(mode="w") as f: + logger = PrintLogger(f) + logger.msg("hello") + + with pytest.raises(copy.error): + copy.deepcopy(logger) + + assert "hello\n" == p.read_text() class TestPrintLoggerFactory: From a88bd7bc3255fd0a8b03c070cef113c04878d787 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 4 Nov 2020 13:39:55 +0100 Subject: [PATCH 0391/1520] Check toml --- .pre-commit-config.yaml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c9d7ed71..6a0d1619 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,14 +1,10 @@ --- - repos: - repo: https://github.com/psf/black rev: 20.8b1 hooks: - id: black language_version: python3.8 - # override until resolved: https://github.com/psf/black/issues/402 - files: \.pyi?$ - types: [] - repo: https://github.com/pre-commit/mirrors-isort rev: v5.6.4 @@ -30,3 +26,4 @@ repos: - id: trailing-whitespace - id: end-of-file-fixer - id: debug-statements + - id: check-toml From 45ce4e0e7a05c5786ca8baa63b162ebe9eafb808 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 8 Nov 2020 13:17:38 +0100 Subject: [PATCH 0392/1520] Add BytesLogger Fixes #271 --- .readthedocs.yml | 2 +- CHANGELOG.rst | 3 + docs/api.rst | 5 ++ docs/performance.rst | 5 ++ src/structlog/__init__.py | 9 ++- src/structlog/_base.py | 6 +- src/structlog/_loggers.py | 110 ++++++++++++++++++++++++++++- tests/test_loggers.py | 145 +++++++++++++++++++++++++++++++++++++- tox.ini | 6 +- 9 files changed, 278 insertions(+), 13 deletions(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index 511ae165..009da9ff 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -2,7 +2,7 @@ version: 2 python: # Keep version in sync with tox.ini (docs and gh-actions). - version: 3.7 + version: 3.8 install: - method: pip diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 685f2d20..c3e7edff 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -32,6 +32,9 @@ Changes: - ``structlog.PrintLogger`` now supports ``copy.deepcopy()``. `#268 `_ - ``structlog.stdlib.ProcessorFormatter`` no longer uses exceptions for control flow, allowing ``foreign_pre_chain`` processors to use ``sys.exc_info()`` to access the real exception. +- Added ``structlog.BytesLogger`` to avoid unnecessary encoding round trips. + Concretely this is useful with *orjson* which returns bytes. + `#271 `_ ---- diff --git a/docs/api.rst b/docs/api.rst index ca084580..5c37f01b 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -52,6 +52,11 @@ API Reference .. autoclass:: PrintLoggerFactory +.. autoclass:: BytesLogger + :members: msg, err, debug, info, warning, error, critical, log, failure, fatal + +.. autoclass:: BytesLoggerFactory + .. autoexception:: DropEvent .. autoclass:: BoundLoggerBase diff --git a/docs/performance.rst b/docs/performance.rst index 2a53313e..601cb62e 100644 --- a/docs/performance.rst +++ b/docs/performance.rst @@ -40,6 +40,11 @@ Here are a few hints how to get most out of ``structlog`` in production: structlog.processors.JSONRenderer(serializer=rapidjson.dumps) +#. Avoid sending your log entries through the standard library if you can: it's a major bottleneck. + Instead use `structlog.PrintLoggerFactory` or -- if your serializer returns bytes (e.g. orjson_) -- `structlog.BytesLoggerFactory`. + + You can still configure `logging` for packages that you don't control, but avoid it for your *own* log entries. + .. _simplejson: https://simplejson.readthedocs.io/ .. _orjson: https://github.com/ijl/orjson diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index bc374d4a..90c962d6 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -20,7 +20,12 @@ wrap_logger, ) from structlog._generic import BoundLogger -from structlog._loggers import PrintLogger, PrintLoggerFactory +from structlog._loggers import ( + BytesLogger, + BytesLoggerFactory, + PrintLogger, + PrintLoggerFactory, +) from structlog.exceptions import DropEvent from structlog.testing import ReturnLogger, ReturnLoggerFactory @@ -52,6 +57,8 @@ __all__ = [ "BoundLogger", "BoundLoggerBase", + "BytesLogger", + "BytesLoggerFactory", "DropEvent", "PrintLogger", "PrintLoggerFactory", diff --git a/src/structlog/_base.py b/src/structlog/_base.py index 4e5e068a..c255cd26 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -34,9 +34,9 @@ class BoundLoggerBase: Doesn't do any actual logging; examples for useful subclasses are: - - the generic :class:`BoundLogger` that can wrap anything, - - :class:`structlog.twisted.BoundLogger`, - - and :class:`structlog.stdlib.BoundLogger`. + - the generic `BoundLogger` that can wrap anything, + - `structlog.stdlib.BoundLogger`. + - `structlog.twisted.BoundLogger`, See also `custom-wrappers`. """ diff --git a/src/structlog/_loggers.py b/src/structlog/_loggers.py index e5fa8e36..ce6c5235 100644 --- a/src/structlog/_loggers.py +++ b/src/structlog/_loggers.py @@ -6,7 +6,6 @@ Logger wrapper and helper class. """ - import copy import sys import threading @@ -22,7 +21,7 @@ class PrintLoggerFactory: To be used with `structlog.configure`\ 's ``logger_factory``. - :param file: File to print to. (default: stdout) + :param file: File to print to. (default: `sys.stdout`) :type file: file object Positional arguments are silently ignored. @@ -55,7 +54,7 @@ class PrintLogger: """ Print events into a file. - :param file: File to print to. (default: stdout) + :param file: File to print to. (default: `sys.stdout`) :type file: file object >>> from structlog import PrintLogger @@ -134,3 +133,108 @@ def msg(self, message): log = debug = info = warn = warning = msg fatal = failure = err = error = critical = exception = msg + + +class BytesLogger: + r""" + Writes bytes into a file. + + :param typing.BinaryIO file: File to print to. (default: + `sys.stdout`\ ``.buffer``) + + Useful if you follow + `current logging best practices ` together with + a formatter that returns bytes (e.g. `orjson + `_). + + .. versionadded:: 20.2.0 + """ + __slots__ = ("_file", "_write", "_flush", "_lock") + + def __init__(self, file=None): + self._file = file or sys.stdout.buffer + self._write = self._file.write + self._flush = self._file.flush + + self._lock = _get_lock_for_file(self._file) + + def __getstate__(self) -> str: + """ + Our __getattr__ magic makes this necessary. + """ + if self._file is sys.stdout.buffer: + return "stdout" + + elif self._file is sys.stderr.buffer: + return "stderr" + + raise PicklingError( + "Only BytesLoggers to sys.stdout and sys.stderr can be pickled." + ) + + def __setstate__(self, state) -> None: + """ + Our __getattr__ magic makes this necessary. + """ + if state == "stdout": + self._file = sys.stdout.buffer + else: + self._file = sys.stderr.buffer + + self._write = self._file.write + self._flush = self._file.flush + self._lock = _get_lock_for_file(self._file) + + def __deepcopy__(self, memodict={}) -> "BytesLogger": + """ + Create a new BytesLogger with the same attributes. Similar to pickling. + """ + if self._file not in (sys.stdout.buffer, sys.stderr.buffer): + raise copy.error( + "Only BytesLoggers to sys.stdout and sys.stderr " + "can be deepcopied." + ) + + newself = self.__class__(self._file) + + newself._write = newself._file.write + newself._flush = newself._file.flush + newself._lock = _get_lock_for_file(newself._file) + + return newself + + def __repr__(self) -> str: + return f"" + + def msg(self, message: bytes) -> None: + """ + Write *message*. + """ + with self._lock: + until_not_interrupted(self._write, message + b"\n") + until_not_interrupted(self._flush) + + log = debug = info = warn = warning = msg + fatal = failure = err = error = critical = exception = msg + + +class BytesLoggerFactory: + r""" + Produce `BytesLogger`\ s. + + To be used with `structlog.configure`\ 's ``logger_factory``. + + :param typing.BinaryIO file: File to print to. (default: + `sys.stdout`\ ``.buffer``) + + Positional arguments are silently ignored. + + .. versionadded:: 20.2.0 + """ + __slots__ = ("_file",) + + def __init__(self, file=None): + self._file = file + + def __call__(self, *args): + return BytesLogger(self._file) diff --git a/tests/test_loggers.py b/tests/test_loggers.py index bc1e0b3e..8d7f5625 100644 --- a/tests/test_loggers.py +++ b/tests/test_loggers.py @@ -7,11 +7,17 @@ import pickle import sys -from io import StringIO +from io import BytesIO, StringIO import pytest -from structlog._loggers import WRITE_LOCKS, PrintLogger, PrintLoggerFactory +from structlog._loggers import ( + WRITE_LOCKS, + BytesLogger, + BytesLoggerFactory, + PrintLogger, + PrintLoggerFactory, +) from .utils import stdlib_log_methods @@ -147,3 +153,138 @@ def test_ignores_args(self): the factory, they are not passed to the logger. """ PrintLoggerFactory()(1, 2, 3) + + +class TestBytesLogger: + def test_prints_to_stdout_by_default(self, capsys): + """ + Instantiating without arguments gives conveniently a logger to standard + out. + """ + BytesLogger().msg(b"hell\xc3\xb6") + + out, err = capsys.readouterr() + assert "hellö\n" == out + assert "" == err + + def test_prints_to_correct_file(self, tmpdir, capsys): + """ + Supplied files are respected. + """ + f = tmpdir.join("test.log") + fo = f.open("wb") + BytesLogger(fo).msg(b"hello") + out, err = capsys.readouterr() + + assert "" == out == err + fo.close() + assert "hello\n" == f.read() + + def test_repr(self): + """ + __repr__ makes sense. + """ + assert repr(BytesLogger()).startswith(" Date: Thu, 12 Nov 2020 11:23:32 +0100 Subject: [PATCH 0393/1520] Add types (#282) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Phew * Add test doc strings * Add PR # * Add tests for new proxy APIs * Add first types docs, mention compatibility probs * Add a more types docs * more docs * Update docs/types.rst Co-authored-by: Éric Araujo * Update docs/types.rst Co-authored-by: Éric Araujo * Add include_package_data=True just in case It seems to work without but who the hell even knows. * Work around the lack of NoReturn before 3.6.2 * Wait, we depend on typing-extensions! This reverts commit 68561ae894567216344e1979877906a0510f4195. * disallow_any_generics * Switch structlog.get_logger to Any, add typing examples * Improve types.rst prose * Use Sequence instead of Tuple where possible * no_implicit_optional * Use Sequence/Iterable, if possible * Update CHANGELOG.rst Co-authored-by: Zac Hatfield-Dodds * Update docs/api.rst Co-authored-by: Zac Hatfield-Dodds * Use verbose Tuple syntax * Be more clear about type hints vs types *salutes @Zac-HD * * Link Mypy Co-authored-by: Éric Araujo Co-authored-by: Zac Hatfield-Dodds --- CHANGELOG.rst | 12 ++ MANIFEST.in | 1 + docs/api.rst | 27 +++- docs/conf.py | 28 ++--- docs/examples.rst | 2 +- docs/index.rst | 1 + docs/standard-library.rst | 7 ++ docs/types.rst | 43 +++++++ mypy.ini | 28 +++++ pyproject.toml | 10 ++ setup.py | 7 +- src/structlog/__init__.py | 7 +- src/structlog/_base.py | 97 +++++++------- src/structlog/_config.py | 156 ++++++++++++++--------- src/structlog/_frames.py | 21 +++- src/structlog/_generic.py | 18 +-- src/structlog/_greenlets.py | 41 ++++++ src/structlog/_loggers.py | 75 ++++++----- src/structlog/_utils.py | 7 +- src/structlog/contextvars.py | 24 ++-- src/structlog/dev.py | 66 +++++++--- src/structlog/processors.py | 152 ++++++++++++++-------- src/structlog/py.typed | 0 src/structlog/stdlib.py | 236 +++++++++++++++++++++++++---------- src/structlog/testing.py | 51 ++++---- src/structlog/threadlocal.py | 126 ++++++++++--------- src/structlog/twisted.py | 66 ++++++---- src/structlog/types.py | 106 ++++++++++++++++ tests/test_config.py | 107 ++++++++++++++-- tests/test_stdlib.py | 42 ++++++- tox.ini | 12 +- typing_examples.py | 153 +++++++++++++++++++++++ 32 files changed, 1278 insertions(+), 451 deletions(-) create mode 100644 docs/types.rst create mode 100644 mypy.ini create mode 100644 src/structlog/_greenlets.py create mode 100644 src/structlog/py.typed create mode 100644 src/structlog/types.py create mode 100644 typing_examples.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c3e7edff..5f02d54e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -16,6 +16,11 @@ Backward-incompatible changes: The package meta data should ensure that you keep getting 20.1.0 on those versions. `#244 `_ +- ``structlog`` is now fully type-annotated. + This won't break your applications but if you use mypy, it will most likely break your CI. + + Check out the new chapter on typing for details. + Deprecations: ^^^^^^^^^^^^^ @@ -35,6 +40,13 @@ Changes: - Added ``structlog.BytesLogger`` to avoid unnecessary encoding round trips. Concretely this is useful with *orjson* which returns bytes. `#271 `_ +- ``structlog`` has now type hints for all of its APIs! + Since ``structlog`` is highly dynamic and configurable, this led to a few concessions like a specialized ``structlog.stdlib.get_logger()`` whose only difference to ``structlog.get_logger()`` is that it has the correct type hints. + + We consider them provisional for the time being – i.e. the backward compatibility does not apply to them in its full strength until we feel we got it right. + Please feel free to provide feedback! + `#223 `_, + `#282 `_ ---- diff --git a/MANIFEST.in b/MANIFEST.in index b96b424d..a7781d28 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,6 @@ include LICENSE LICENSE.apache2 LICENSE.mit conftest.py include *.rst +include src/structlog/py.typed typing_examples.py include *.ini *.yml *.yaml *.toml graft .github diff --git a/docs/api.rst b/docs/api.rst index 5c37f01b..5c57b9cc 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -195,7 +195,7 @@ API Reference .. autoclass:: ExceptionPrettyPrinter -.. autoclass:: TimeStamper(fmt=None, utc=True, key="timestamp") +.. autoclass:: TimeStamper .. doctest:: @@ -213,6 +213,8 @@ API Reference .. automodule:: structlog.stdlib +.. autofunction:: get_logger + .. autoclass:: BoundLogger :members: bind, unbind, new, debug, info, warning, warn, error, critical, exception, log @@ -235,6 +237,29 @@ API Reference :members: wrap_for_formatter +`structlog.types` Module +------------------------ + +.. automodule:: structlog.types + +.. autoprotocol:: BindableLogger + + Additionally to the methods listed below, bound loggers **must** have a ``__init__`` method with the following signature: + + .. method:: __init__(self, wrapped_logger: WrappedLogger, processors: Iterable[Processor], context: Context) -> None + :noindex: + + Unfortunately it's impossible to define initializers using `PEP 544 `_ Protocols. + + They currently also have to carry a `Context` as a ``_context`` attribute. + +.. autodata:: EventDict +.. autodata:: WrappedLogger +.. autodata:: Processor +.. autodata:: Context +.. autodata:: ExcInfo + + `structlog.twisted` Module -------------------------- diff --git a/docs/conf.py b/docs/conf.py index 9bd4aa13..54619d99 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -2,15 +2,6 @@ # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. - -# This file is execfile()d with the current directory set to its containing dir -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - import codecs import os import re @@ -36,23 +27,15 @@ def find_version(*file_paths): raise RuntimeError("Unable to find version string.") -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# sys.path.insert(0, os.path.abspath('.')) - # -- General configuration ---------------------------------------------------- -# If your documentation needs a minimal Sphinx version, state it here. -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ "sphinx.ext.autodoc", + "sphinx.ext.autodoc.typehints", "sphinx.ext.doctest", "sphinx.ext.intersphinx", "sphinx.ext.viewcode", + "sphinx_toolbox.more_autodoc.autoprotocol", ] # Add any paths that contain templates here, relative to this directory. @@ -100,10 +83,13 @@ def find_version(*file_paths): default_role = "any" nitpick_ignore = [ - ("py:class", "callable"), - ("py:class", "file object"), + ("py:class", "BinaryIO"), ("py:class", "ILogObserver"), ("py:class", "PlainFileObserver"), + ("py:class", "TLLogger"), + ("py:class", "TextIO"), + ("py:class", "structlog._base.BoundLoggerBase"), + ("py:class", "structlog.dev._Styles"), ] # If true, '()' will be appended to :func: etc. cross-reference text. diff --git a/docs/examples.rst b/docs/examples.rst index c31bfa9f..bc4dcbbd 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -23,7 +23,7 @@ While wrapped loggers are *immutable* by default, this example demonstrates how Please note that `structlog.stdlib.LoggerFactory` is a totally magic-free class that just deduces the name of the caller's module and does a `logging.getLogger` with it. It's used by `structlog.get_logger` to rid you of logging boilerplate in application code. -If you prefer to name your standard library loggers explicitly, a positional argument to `get_logger` gets passed to the factory and used as the name. +If you prefer to name your standard library loggers explicitly, a positional argument to `structlog.get_logger` gets passed to the factory and used as the name. .. _twisted-example: diff --git a/docs/index.rst b/docs/index.rst index d0f59fc1..451dce30 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -36,6 +36,7 @@ Basics processors examples development + types Integration with Existing Systems diff --git a/docs/standard-library.rst b/docs/standard-library.rst index bad34e79..b1899bf2 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -38,8 +38,15 @@ It behaves exactly like the generic `structlog.BoundLogger` except: - it's slightly faster due to less overhead, - has an explicit API that mirrors the log methods of standard library's `logging.Logger`, +- it has correct type hints, - hence causing less cryptic error messages if you get method names wrong. +---- + +If you're using static types (e.g. with mypy) you also may want to use `structlog.stdlib.get_logger()` that has the appropriate type hints if you're using `structlog.stdlib.BoundLogger`. +Please note though, that it will neither configure nor verify your configuration. +It will call `structlog.get_logger()` just like if you would've called it -- the only difference are the type hints. + Processors ---------- diff --git a/docs/types.rst b/docs/types.rst new file mode 100644 index 00000000..83b22890 --- /dev/null +++ b/docs/types.rst @@ -0,0 +1,43 @@ +Type Hints +========== + +Static type hints -- together with a type checker like `Mypy `_ -- are an excellent way to make your code more robust, self-documenting, and maintainable in the long run. +And as of 20.2.0, ``structlog`` comes with type hints for all of its APIs. + +Since ``structlog`` is highly configurable and tries to give a clean facade to its users, adding types without breaking compatibility, while remaining useful was a formidable task. + +If you used ``structlog`` and Mypy before 20.2.0, you will probably find that Mypy is failing now. +As a quick fix, add the following lines into your ``mypy.ini`` that should be at the root of your project directory (and must start with a ``[mypy]`` section): + +.. code:: ini + + [mypy-structlog.*] + follow_imports = skip + +It will ignore ``structlog``'s type stubs until you're ready to adapt your code base to them. + + +---- + +The main problem is that `structlog.get_logger()` returns whatever you've configured the bound logger to be. +The only commonality are the binding methods like ``bind()`` and we've extracted them into the `structlog.types.BindableLogger` :class:`~typing.Protocol`. +But using that as a return type is worse than useless, because you'd have to use `typing.cast` on every logger returned by `structlog.get_logger()`, if you wanted to actually call any logging methods. + +The second problem is that said ``bind()`` and its cousins are inherited from a common base class (a `big `_ `mistake `_ in hindsight) and can't know what concrete class subclasses them and therefore what type they are returning. + +The chosen solution is adding `structlog.stdlib.get_logger()` that just calls `structlog.get_logger()` but has the correct type hints and adding `structlog.stdlib.BoundLogger.bind` et al that also only delegate to the base class. + +`structlog.get_logger()` is typed as returning `typing.Any` so you can use your own type annotation and stick to the old APIs, if that's what you prefer: + +.. code:: + + import structlog + + logger: structlog.stdlib.BoundLogger = structlog.get_logger() + logger.info("hi") # <- ok + logger.msg("hi") # <- mypy: 'error: "BoundLogger" has no attribute "msg"' + +---- + +Rather sooner than later, the concept of the base class will be replaced by proper delegation that will put the context-related methods into a proper class (with proxy stubs for backward compatibility). +In the end, we're already delegating anyway. diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 00000000..ea371b92 --- /dev/null +++ b/mypy.ini @@ -0,0 +1,28 @@ +[mypy] +# show error messages from unrelated files +follow_imports = normal + +# suppress errors about unsatisfied imports +ignore_missing_imports = True + +# be strict +check_untyped_defs = True +disallow_any_generics = True +disallow_incomplete_defs = True +disallow_untyped_calls = True +disallow_untyped_defs = True +no_implicit_optional = True +strict_optional = True +warn_no_return = True +warn_redundant_casts = True +warn_unreachable = True +warn_unused_ignores = True + +# sometimes redefinition is just fine +allow_redefinition = True + +[mypy-tests.*] +ignore_errors = True + +[mypy-conftest] +ignore_errors = True diff --git a/pyproject.toml b/pyproject.toml index c71dea30..13a07316 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,16 @@ source = ["src", ".tox/*/site-packages"] [tool.coverage.report] show_missing = true skip_covered = true +exclude_lines = [ + "pragma: no cover", + "if TYPE_CHECKING:", + "raise NotImplementedError", + # typing-related code + "^if (False|TYPE_CHECKING):", + ": \\.\\.\\.$", + "^ +\\.\\.\\.$", + "-> ['\"]?NoReturn['\"]?:", +] [tool.black] diff --git a/setup.py b/setup.py index 0d8994fa..5674ee3a 100644 --- a/setup.py +++ b/setup.py @@ -36,7 +36,9 @@ "Topic :: Software Development :: Libraries :: Python Modules", ] PYTHON_REQUIRES = ">=3.6" -INSTALL_REQUIRES = [] +INSTALL_REQUIRES = [ + "typing-extensions; python_version<'3.8'", +] EXTRAS_REQUIRE = { "tests": [ "coverage[toml]", @@ -47,7 +49,7 @@ "pytest>=6.0", "simplejson", ], - "docs": ["furo", "sphinx", "twisted"], + "docs": ["furo", "sphinx", "sphinx-toolbox", "twisted"], } EXTRAS_REQUIRE["dev"] = ( EXTRAS_REQUIRE["tests"] + EXTRAS_REQUIRE["docs"] + ["pre-commit"] @@ -129,6 +131,7 @@ def find_meta(meta): python_requires=PYTHON_REQUIRES, install_requires=INSTALL_REQUIRES, extras_require=EXTRAS_REQUIRE, + include_package_data=True, zip_safe=False, options={"bdist_wheel": {"universal": "1"}}, ) diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 90c962d6..7830da10 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -7,7 +7,7 @@ """ -from structlog import dev, processors, stdlib, testing, threadlocal +from structlog import dev, processors, stdlib, testing, threadlocal, types from structlog._base import BoundLoggerBase, get_context from structlog._config import ( configure, @@ -33,12 +33,12 @@ try: from structlog import twisted except ImportError: - twisted = None + twisted = None # type: ignore try: from structlog import contextvars except ImportError: - contextvars = None + contextvars = None # type: ignore __version__ = "20.2.0.dev0" @@ -79,5 +79,6 @@ "testing", "threadlocal", "twisted", + "types", "wrap_logger", ] diff --git a/src/structlog/_base.py b/src/structlog/_base.py index c255cd26..3ad0252f 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -5,27 +5,11 @@ """ Logger wrapper and helper class. """ - +from typing import Any, Dict, Iterable, Mapping, Optional, Sequence, Tuple from structlog.exceptions import DropEvent - -def get_context(bound_logger): - """ - Return *bound_logger*'s context. - - The type of *bound_logger* and the type returned depend on your - configuration. - - :param bound_logger: The bound logger whose context you want. - - :returns: The *actual* context from *bound_logger*. It is *not* copied - first. - - .. versionadded:: 20.2 - """ - # This probably will get more complicated in the future. - return bound_logger._context +from .types import BindableLogger, Context, Processor, WrappedLogger class BoundLoggerBase: @@ -41,7 +25,7 @@ class BoundLoggerBase: See also `custom-wrappers`. """ - _logger = None + _logger: WrappedLogger """ Wrapped logger. @@ -52,17 +36,22 @@ class BoundLoggerBase: See also `custom-wrappers`. """ - def __init__(self, logger, processors, context): + def __init__( + self, + logger: WrappedLogger, + processors: Iterable[Processor], + context: Context, + ): self._logger = logger self._processors = processors self._context = context - def __repr__(self): + def __repr__(self) -> str: return "<{}(context={!r}, processors={!r})>".format( self.__class__.__name__, self._context, self._processors ) - def __eq__(self, other): + def __eq__(self, other: Any) -> bool: try: if self._context == other._context: return True @@ -71,14 +60,12 @@ def __eq__(self, other): except AttributeError: return False - def __ne__(self, other): + def __ne__(self, other: Any) -> bool: return not self.__eq__(other) - def bind(self, **new_values): + def bind(self, **new_values: Any) -> "BoundLoggerBase": """ Return a new logger with *new_values* added to the existing ones. - - :rtype: ``self.__class__`` """ return self.__class__( self._logger, @@ -86,25 +73,22 @@ def bind(self, **new_values): self._context.__class__(self._context, **new_values), ) - def unbind(self, *keys): + def unbind(self, *keys: str) -> "BoundLoggerBase": """ Return a new logger with *keys* removed from the context. :raises KeyError: If the key is not part of the context. - - :rtype: ``self.__class__`` """ bl = self.bind() for key in keys: del bl._context[key] + return bl - def try_unbind(self, *keys): + def try_unbind(self, *keys: str) -> "BoundLoggerBase": """ Like :meth:`unbind`, but best effort: missing keys are ignored. - :rtype: ``self.__class__`` - .. versionadded:: 18.2.0 """ bl = self.bind() @@ -113,39 +97,42 @@ def try_unbind(self, *keys): return bl - def new(self, **new_values): + def new(self, **new_values: Any) -> "BoundLoggerBase": """ - Clear context and binds *initial_values* using :func:`bind`. + Clear context and binds *initial_values* using `bind`. Only necessary with dict implementations that keep global state like those wrapped by `structlog.threadlocal.wrap_dict` when threads are re-used. - - :rtype: ``self.__class__`` """ self._context.clear() + return self.bind(**new_values) # Helper methods for sub-classing concrete BoundLoggers. - def _process_event(self, method_name, event, event_kw): + def _process_event( + self, method_name: str, event: Optional[str], event_kw: Dict[str, Any] + ) -> Tuple[Sequence[Any], Mapping[str, Any]]: """ Combines creates an ``event_dict`` and runs the chain. Call it to combine your *event* and *context* into an event_dict and process using the processor chain. - :param str method_name: The name of the logger method. Is passed into + :param method_name: The name of the logger method. Is passed into the processors. :param event: The event -- usually the first positional argument to a logger. :param event_kw: Additional event keywords. For example if someone calls ``log.msg("foo", bar=42)``, *event* would to be ``"foo"`` and *event_kw* ``{"bar": 42}``. + :raises: `structlog.DropEvent` if log entry should be dropped. :raises: `ValueError` if the final processor doesn't return a string, tuple, or a dict. - :rtype: `tuple` of ``(*args, **kw)`` + + :returns: `tuple` of ``(*args, **kw)`` .. note:: @@ -156,18 +143,22 @@ def _process_event(self, method_name, event, event_kw): .. versionchanged:: 14.0.0 Allow final processor to return a `dict`. """ - event_dict = self._context.copy() + # We're typing it as Any, because processors can return more than an + # EventDict. + event_dict: Any = self._context.copy() event_dict.update(**event_kw) + if event is not None: event_dict["event"] = event for proc in self._processors: event_dict = proc(self._logger, method_name, event_dict) + if isinstance(event_dict, str): return (event_dict,), {} elif isinstance(event_dict, tuple): # In this case we assume that the last processor returned a tuple # of ``(args, kwargs)`` and pass it right through. - return event_dict + return event_dict # type: ignore elif isinstance(event_dict, dict): return (), event_dict else: @@ -177,7 +168,9 @@ def _process_event(self, method_name, event, event_kw): "string." ) - def _proxy_to_logger(self, method_name, event=None, **event_kw): + def _proxy_to_logger( + self, method_name: str, event: Optional[str] = None, **event_kw: Any + ) -> Any: """ Run processor chain on event & call *method_name* on wrapped logger. @@ -185,7 +178,7 @@ def _proxy_to_logger(self, method_name, event=None, **event_kw): handling :exc:`structlog.DropEvent`, and finally calls *method_name* on :attr:`_logger` with the result. - :param str method_name: The name of the method that's going to get + :param method_name: The name of the method that's going to get called. Technically it should be identical to the method the user called because it also get passed into processors. :param event: The event -- usually the first positional argument to a @@ -205,3 +198,21 @@ def _proxy_to_logger(self, method_name, event=None, **event_kw): return getattr(self._logger, method_name)(*args, **kw) except DropEvent: return + + +def get_context(bound_logger: BindableLogger) -> Context: + """ + Return *bound_logger*'s context. + + The type of *bound_logger* and the type returned depend on your + configuration. + + :param bound_logger: The bound logger whose context you want. + + :returns: The *actual* context from *bound_logger*. It is *not* copied + first. + + .. versionadded:: 20.2 + """ + # This probably will get more complicated in the future. + return bound_logger._context diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 44248b76..eee8b3e6 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -10,10 +10,22 @@ import sys import warnings +from typing import ( + Any, + Callable, + Dict, + Iterable, + Optional, + Sequence, + Type, + cast, +) + from ._generic import BoundLogger from ._loggers import PrintLoggerFactory from .dev import ConsoleRenderer, _has_colorama, set_exc_info from .processors import StackInfoRenderer, TimeStamper, format_exc_info +from .types import BindableLogger, Context, Processor, WrappedLogger """ @@ -21,14 +33,14 @@ Any changes to these defaults must be reflected in `getting-started`. """ -_BUILTIN_DEFAULT_PROCESSORS = [ +_BUILTIN_DEFAULT_PROCESSORS: Sequence[Processor] = [ StackInfoRenderer(), set_exc_info, format_exc_info, TimeStamper(fmt="%Y-%m-%d %H:%M.%S", utc=False), ConsoleRenderer(colors=_has_colorama and sys.stdout.isatty()), ] -_BUILTIN_DEFAULT_CONTEXT_CLASS = dict +_BUILTIN_DEFAULT_CONTEXT_CLASS = cast(Type[Context], dict) _BUILTIN_DEFAULT_WRAPPER_CLASS = BoundLogger _BUILTIN_DEFAULT_LOGGER_FACTORY = PrintLoggerFactory() _BUILTIN_CACHE_LOGGER_ON_FIRST_USE = False @@ -39,12 +51,14 @@ class _Configuration: Global defaults. """ - is_configured = False - default_processors = _BUILTIN_DEFAULT_PROCESSORS[:] - default_context_class = _BUILTIN_DEFAULT_CONTEXT_CLASS - default_wrapper_class = _BUILTIN_DEFAULT_WRAPPER_CLASS - logger_factory = _BUILTIN_DEFAULT_LOGGER_FACTORY - cache_logger_on_first_use = _BUILTIN_CACHE_LOGGER_ON_FIRST_USE + is_configured: bool = False + default_processors: Iterable[Processor] = _BUILTIN_DEFAULT_PROCESSORS[:] + default_context_class: Type[Context] = _BUILTIN_DEFAULT_CONTEXT_CLASS + default_wrapper_class: Any = _BUILTIN_DEFAULT_WRAPPER_CLASS + logger_factory: Callable[ + ..., WrappedLogger + ] = _BUILTIN_DEFAULT_LOGGER_FACTORY + cache_logger_on_first_use: bool = _BUILTIN_CACHE_LOGGER_ON_FIRST_USE _CONFIG = _Configuration() @@ -53,20 +67,18 @@ class _Configuration: """ -def is_configured(): +def is_configured() -> bool: """ Return whether ``structlog`` has been configured. If `False`, ``structlog`` is running with builtin defaults. - :rtype: bool - .. versionadded: 18.1 """ return _CONFIG.is_configured -def get_config(): +def get_config() -> Dict[str, Any]: """ Get a dictionary with the current configuration. @@ -74,8 +86,6 @@ def get_config(): Changes to the returned dictionary do *not* affect ``structlog``. - :rtype: dict - .. versionadded: 18.1 """ return { @@ -87,7 +97,7 @@ def get_config(): } -def get_logger(*args, **initial_values): +def get_logger(*args: Any, **initial_values: Any) -> Any: """ Convenience function that returns a logger according to configuration. @@ -102,7 +112,8 @@ def get_logger(*args, **initial_values): :param initial_values: Values that are used to pre-populate your contexts. :returns: A proxy that creates a correctly configured bound logger when - necessary. + necessary. The type of that bound logger depends on your configuration + and is `structlog.BoundLogger` by default. See `configuration` for details. @@ -125,14 +136,14 @@ def get_logger(*args, **initial_values): def wrap_logger( - logger, - processors=None, - wrapper_class=None, - context_class=None, - cache_logger_on_first_use=None, - logger_factory_args=None, - **initial_values -): + logger: WrappedLogger, + processors: Optional[Iterable[Processor]] = None, + wrapper_class: Optional[Type[BindableLogger]] = None, + context_class: Optional[Type[Context]] = None, + cache_logger_on_first_use: Optional[bool] = None, + logger_factory_args: Optional[Iterable[Any]] = None, + **initial_values: Any +) -> Any: """ Create a new bound logger for an arbitrary *logger*. @@ -146,7 +157,7 @@ def wrap_logger( *is* possible. :param initial_values: Values that are used to pre-populate your contexts. - :param tuple logger_factory_args: Values that are passed unmodified as + :param logger_factory_args: Values that are passed unmodified as ``*logger_factory_args`` to the logger factory if not `None`. :returns: A proxy that creates a correctly configured bound logger when @@ -169,12 +180,12 @@ def wrap_logger( def configure( - processors=None, - wrapper_class=None, - context_class=None, - logger_factory=None, - cache_logger_on_first_use=None, -): + processors: Optional[Iterable[Processor]] = None, + wrapper_class: Optional[Type[BindableLogger]] = None, + context_class: Optional[Type[Context]] = None, + logger_factory: Optional[Callable[..., WrappedLogger]] = None, + cache_logger_on_first_use: Optional[bool] = None, +) -> None: """ Configures the **global** defaults. @@ -189,14 +200,14 @@ def configure( Use `reset_defaults` to undo your changes. - :param list processors: List of processors. - :param type wrapper_class: Class to use for wrapping loggers instead of + :param processors: The processor chain. + :param wrapper_class: Class to use for wrapping loggers instead of `structlog.BoundLogger`. See `standard-library`, :doc:`twisted`, and `custom-wrappers`. - :param type context_class: Class to be used for internal context keeping. - :param callable logger_factory: Factory to be called to create a new + :param context_class: Class to be used for internal context keeping. + :param logger_factory: Factory to be called to create a new logger that shall be wrapped. - :param bool cache_logger_on_first_use: `wrap_logger` doesn't return an + :param cache_logger_on_first_use: `wrap_logger` doesn't return an actual wrapped logger but a proxy that assembles one when it's first used. If this option is set to `True`, this assembled logger is cached. See `performance`. @@ -205,6 +216,7 @@ def configure( *cache_logger_on_first_use* """ _CONFIG.is_configured = True + if processors is not None: _CONFIG.default_processors = processors if wrapper_class is not None: @@ -212,12 +224,18 @@ def configure( if context_class is not None: _CONFIG.default_context_class = context_class if logger_factory is not None: - _CONFIG.logger_factory = logger_factory + _CONFIG.logger_factory = logger_factory # type: ignore if cache_logger_on_first_use is not None: _CONFIG.cache_logger_on_first_use = cache_logger_on_first_use -def configure_once(*args, **kw): +def configure_once( + processors: Optional[Iterable[Processor]] = None, + wrapper_class: Optional[Type[BindableLogger]] = None, + context_class: Optional[Type[Context]] = None, + logger_factory: Optional[Callable[..., WrappedLogger]] = None, + cache_logger_on_first_use: Optional[bool] = None, +) -> None: """ Configures if structlog isn't configured yet. @@ -227,12 +245,18 @@ def configure_once(*args, **kw): Raises a `RuntimeWarning` if repeated configuration is attempted. """ if not _CONFIG.is_configured: - configure(*args, **kw) + configure( + processors=processors, + wrapper_class=wrapper_class, + context_class=context_class, + logger_factory=logger_factory, + cache_logger_on_first_use=cache_logger_on_first_use, + ) else: warnings.warn("Repeated configuration attempted.", RuntimeWarning) -def reset_defaults(): +def reset_defaults() -> None: """ Resets global default values to builtin defaults. @@ -242,7 +266,7 @@ def reset_defaults(): _CONFIG.default_processors = _BUILTIN_DEFAULT_PROCESSORS[:] _CONFIG.default_wrapper_class = _BUILTIN_DEFAULT_WRAPPER_CLASS _CONFIG.default_context_class = _BUILTIN_DEFAULT_CONTEXT_CLASS - _CONFIG.logger_factory = _BUILTIN_DEFAULT_LOGGER_FACTORY + _CONFIG.logger_factory = _BUILTIN_DEFAULT_LOGGER_FACTORY # type: ignore _CONFIG.cache_logger_on_first_use = _BUILTIN_CACHE_LOGGER_ON_FIRST_USE @@ -264,14 +288,14 @@ class BoundLoggerLazyProxy: def __init__( self, - logger, - wrapper_class=None, - processors=None, - context_class=None, - cache_logger_on_first_use=None, - initial_values=None, - logger_factory_args=None, - ): + logger: WrappedLogger, + wrapper_class: Optional[Type[BindableLogger]] = None, + processors: Optional[Iterable[Processor]] = None, + context_class: Optional[Type[Context]] = None, + cache_logger_on_first_use: Optional[bool] = None, + initial_values: Optional[Dict[str, Any]] = None, + logger_factory_args: Any = None, + ) -> None: self._logger = logger self._wrapper_class = wrapper_class self._processors = processors @@ -280,7 +304,7 @@ def __init__( self._initial_values = initial_values or {} self._logger_factory_args = logger_factory_args or () - def __repr__(self): + def __repr__(self) -> str: return ( "".format(self) ) - def bind(self, **new_values): + def bind(self, **new_values: Any) -> BindableLogger: """ Assemble a new BoundLogger from arguments and configuration. """ @@ -297,7 +321,7 @@ def bind(self, **new_values): ctx = self._context_class(self._initial_values) else: ctx = _CONFIG.default_context_class(self._initial_values) - cls = self._wrapper_class or _CONFIG.default_wrapper_class + _logger = self._logger if not _logger: _logger = _CONFIG.logger_factory(*self._logger_factory_args) @@ -306,9 +330,13 @@ def bind(self, **new_values): procs = _CONFIG.default_processors else: procs = self._processors - logger = cls(_logger, processors=procs, context=ctx) - def finalized_bind(**new_values): + cls = self._wrapper_class or _CONFIG.default_wrapper_class + # Looks like Protocols ignore definitions of __init__ so we have to + # silence mypy here. + logger = cls(_logger, processors=procs, context=ctx) # type: ignore + + def finalized_bind(**new_values: Any) -> BindableLogger: """ Use cached assembled logger to bind potentially new values. """ @@ -321,10 +349,11 @@ def finalized_bind(**new_values): self._cache_logger_on_first_use is None and _CONFIG.cache_logger_on_first_use is True ): - self.bind = finalized_bind + self.bind = finalized_bind # type: ignore + return finalized_bind(**new_values) - def unbind(self, *keys): + def unbind(self, *keys: str) -> BindableLogger: """ Same as bind, except unbind *keys* first. @@ -332,7 +361,10 @@ def unbind(self, *keys): """ return self.bind().unbind(*keys) - def new(self, **new_values): + def try_unbind(self, *keys: str) -> BindableLogger: + return self.bind().try_unbind(*keys) + + def new(self, **new_values: Any) -> BindableLogger: """ Clear context, then bind. """ @@ -340,26 +372,30 @@ def new(self, **new_values): self._context_class().clear() else: _CONFIG.default_context_class().clear() + bl = self.bind(**new_values) + return bl - def __getattr__(self, name): + def __getattr__(self, name: str) -> Any: """ If a logging method if called on a lazy proxy, we have to create an ephemeral BoundLogger first. """ if name == "__isabstractmethod__": raise AttributeError + bl = self.bind() + return getattr(bl, name) - def __getstate__(self): + def __getstate__(self) -> Dict[str, Any]: """ Our __getattr__ magic makes this necessary. """ return self.__dict__ - def __setstate__(self, state): + def __setstate__(self, state: Dict[str, Any]) -> None: """ Our __getattr__ magic makes this necessary. """ diff --git a/src/structlog/_frames.py b/src/structlog/_frames.py index a4899d08..827cef84 100644 --- a/src/structlog/_frames.py +++ b/src/structlog/_frames.py @@ -6,32 +6,39 @@ import traceback from io import StringIO +from types import FrameType +from typing import List, Optional, Tuple +from .types import ExcInfo -def _format_exception(exc_info): + +def _format_exception(exc_info: ExcInfo) -> str: """ Prettyprint an `exc_info` tuple. Shamelessly stolen from stdlib's logging module. """ sio = StringIO() + traceback.print_exception(exc_info[0], exc_info[1], exc_info[2], None, sio) s = sio.getvalue() sio.close() if s[-1:] == "\n": s = s[:-1] + return s -def _find_first_app_frame_and_name(additional_ignores=None): +def _find_first_app_frame_and_name( + additional_ignores: Optional[List[str]] = None, +) -> Tuple[FrameType, str]: """ Remove all intra-structlog calls and return the relevant app frame. :param additional_ignores: Additional names with which the first frame must not start. - :type additional_ignores: `list` of `str` or `None` - :rtype: tuple of (frame, name) + :returns: tuple of (frame, name) """ ignores = ["structlog"] + (additional_ignores or []) f = sys._getframe() @@ -45,15 +52,17 @@ def _find_first_app_frame_and_name(additional_ignores=None): return f, name -def _format_stack(frame): +def _format_stack(frame: FrameType) -> str: """ - Pretty-print the stack of `frame` like logging would. + Pretty-print the stack of *frame* like logging would. """ sio = StringIO() + sio.write("Stack (most recent call last):\n") traceback.print_stack(frame, file=sio) sinfo = sio.getvalue() if sinfo[-1] == "\n": sinfo = sinfo[:-1] sio.close() + return sinfo diff --git a/src/structlog/_generic.py b/src/structlog/_generic.py index 126870e7..3f1ca421 100644 --- a/src/structlog/_generic.py +++ b/src/structlog/_generic.py @@ -5,9 +5,8 @@ """ Generic bound logger that can wrap anything. """ - - from functools import partial +from typing import Any, Dict from structlog._base import BoundLoggerBase @@ -16,16 +15,16 @@ class BoundLogger(BoundLoggerBase): """ A generic BoundLogger that can wrap anything. - Every unknown method will be passed to the wrapped logger. If that's too - much magic for you, try :class:`structlog.stdlib.BoundLogger` or - :class:`structlog.twisted.BoundLogger` which also take advantage of - knowing the wrapped class which generally results in better performance. + Every unknown method will be passed to the wrapped *logger*. If that's too + much magic for you, try `structlog.stdlib.BoundLogger` or + `structlog.twisted.BoundLogger` which also take advantage of knowing the + wrapped class which generally results in better performance. Not intended to be instantiated by yourself. See :func:`~structlog.wrap_logger` and :func:`~structlog.get_logger`. """ - def __getattr__(self, method_name): + def __getattr__(self, method_name: str) -> Any: """ If not done so yet, wrap the desired logger method & cache the result. """ @@ -34,15 +33,16 @@ def __getattr__(self, method_name): wrapped = partial(self._proxy_to_logger, method_name) setattr(self, method_name, wrapped) + return wrapped - def __getstate__(self): + def __getstate__(self) -> Dict[str, Any]: """ Our __getattr__ magic makes this necessary. """ return self.__dict__ - def __setstate__(self, state): + def __setstate__(self, state: Dict[str, Any]) -> None: """ Our __getattr__ magic makes this necessary. """ diff --git a/src/structlog/_greenlets.py b/src/structlog/_greenlets.py new file mode 100644 index 00000000..e539d4da --- /dev/null +++ b/src/structlog/_greenlets.py @@ -0,0 +1,41 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the MIT License. See the LICENSE file in the root of this +# repository for complete details. + +""" +greenlet-specific code that pretends to be a `threading.local`. + +Fails to import if not running under greenlet. +""" + +from typing import Any +from weakref import WeakKeyDictionary + +from greenlet import getcurrent + + +class GreenThreadLocal: + """ + threading.local() replacement for greenlets. + """ + + def __init__(self) -> None: + self.__dict__["_weakdict"] = WeakKeyDictionary() + + def __getattr__(self, name: str) -> Any: + key = getcurrent() + try: + return self._weakdict[key][name] + except KeyError: + raise AttributeError(name) + + def __setattr__(self, name: str, val: Any) -> None: + key = getcurrent() + self._weakdict.setdefault(key, {})[name] = val + + def __delattr__(self, name: str) -> None: + key = getcurrent() + try: + del self._weakdict[key][name] + except KeyError: + raise AttributeError(name) diff --git a/src/structlog/_loggers.py b/src/structlog/_loggers.py index ce6c5235..4fe0efce 100644 --- a/src/structlog/_loggers.py +++ b/src/structlog/_loggers.py @@ -11,35 +11,15 @@ import threading from pickle import PicklingError +from typing import IO, Any, BinaryIO, Dict, Optional, TextIO from structlog._utils import until_not_interrupted -class PrintLoggerFactory: - r""" - Produce `PrintLogger`\ s. - - To be used with `structlog.configure`\ 's ``logger_factory``. +WRITE_LOCKS: Dict[IO[Any], threading.Lock] = {} - :param file: File to print to. (default: `sys.stdout`) - :type file: file object - - Positional arguments are silently ignored. - .. versionadded:: 0.4.0 - """ - - def __init__(self, file=None): - self._file = file - - def __call__(self, *args): - return PrintLogger(self._file) - - -WRITE_LOCKS = {} - - -def _get_lock_for_file(file): +def _get_lock_for_file(file: IO[Any]) -> threading.Lock: global WRITE_LOCKS lock = WRITE_LOCKS.get(file) @@ -55,7 +35,6 @@ class PrintLogger: Print events into a file. :param file: File to print to. (default: `sys.stdout`) - :type file: file object >>> from structlog import PrintLogger >>> PrintLogger().msg("hello") @@ -68,14 +47,14 @@ class PrintLogger: doctests. """ - def __init__(self, file=None): + def __init__(self, file: Optional[TextIO] = None): self._file = file or sys.stdout self._write = self._file.write self._flush = self._file.flush self._lock = _get_lock_for_file(self._file) - def __getstate__(self): + def __getstate__(self) -> str: """ Our __getattr__ magic makes this necessary. """ @@ -89,7 +68,7 @@ def __getstate__(self): "Only PrintLoggers to sys.stdout and sys.stderr can be pickled." ) - def __setstate__(self, state): + def __setstate__(self, state: Any) -> None: """ Our __getattr__ magic makes this necessary. """ @@ -102,7 +81,7 @@ def __setstate__(self, state): self._flush = self._file.flush self._lock = _get_lock_for_file(self._file) - def __deepcopy__(self, memodict={}): + def __deepcopy__(self, memodict: Dict[Any, Any] = {}) -> "PrintLogger": """ Create a new PrintLogger with the same attributes. Similar to pickling. """ @@ -120,10 +99,10 @@ def __deepcopy__(self, memodict={}): return newself - def __repr__(self): + def __repr__(self) -> str: return f"" - def msg(self, message): + def msg(self, message: str) -> None: """ Print *message*. """ @@ -135,12 +114,31 @@ def msg(self, message): fatal = failure = err = error = critical = exception = msg +class PrintLoggerFactory: + r""" + Produce `PrintLogger`\ s. + + To be used with `structlog.configure`\ 's ``logger_factory``. + + :param file: File to print to. (default: `sys.stdout`) + + Positional arguments are silently ignored. + + .. versionadded:: 0.4.0 + """ + + def __init__(self, file: Optional[TextIO] = None): + self._file = file + + def __call__(self, *args: Any) -> PrintLogger: + return PrintLogger(self._file) + + class BytesLogger: r""" Writes bytes into a file. - :param typing.BinaryIO file: File to print to. (default: - `sys.stdout`\ ``.buffer``) + :param file: File to print to. (default: `sys.stdout`\ ``.buffer``) Useful if you follow `current logging best practices ` together with @@ -151,7 +149,7 @@ class BytesLogger: """ __slots__ = ("_file", "_write", "_flush", "_lock") - def __init__(self, file=None): + def __init__(self, file: Optional[BinaryIO] = None): self._file = file or sys.stdout.buffer self._write = self._file.write self._flush = self._file.flush @@ -172,7 +170,7 @@ def __getstate__(self) -> str: "Only BytesLoggers to sys.stdout and sys.stderr can be pickled." ) - def __setstate__(self, state) -> None: + def __setstate__(self, state: Any) -> None: """ Our __getattr__ magic makes this necessary. """ @@ -185,7 +183,7 @@ def __setstate__(self, state) -> None: self._flush = self._file.flush self._lock = _get_lock_for_file(self._file) - def __deepcopy__(self, memodict={}) -> "BytesLogger": + def __deepcopy__(self, memodict: Dict[Any, Any] = {}) -> "BytesLogger": """ Create a new BytesLogger with the same attributes. Similar to pickling. """ @@ -224,8 +222,7 @@ class BytesLoggerFactory: To be used with `structlog.configure`\ 's ``logger_factory``. - :param typing.BinaryIO file: File to print to. (default: - `sys.stdout`\ ``.buffer``) + :param file: File to print to. (default: `sys.stdout`\ ``.buffer``) Positional arguments are silently ignored. @@ -233,8 +230,8 @@ class BytesLoggerFactory: """ __slots__ = ("_file",) - def __init__(self, file=None): + def __init__(self, file: Optional[BinaryIO] = None): self._file = file - def __call__(self, *args): + def __call__(self, *args: Any) -> BytesLogger: return BytesLogger(self._file) diff --git a/src/structlog/_utils.py b/src/structlog/_utils.py index 77f5a44c..dc803963 100644 --- a/src/structlog/_utils.py +++ b/src/structlog/_utils.py @@ -6,15 +6,16 @@ Generic utilities. """ - import errno +from typing import Any, Callable + -def until_not_interrupted(f, *args, **kw): +def until_not_interrupted(f: Callable[..., Any], *args: Any, **kw: Any) -> Any: """ Retry until *f* succeeds or an exception that isn't caused by EINTR occurs. - :param callable f: A callable like a function. + :param f: A callable like a function. :param *args: Positional arguments for *f*. :param **kw: Keyword arguments for *f*. """ diff --git a/src/structlog/contextvars.py b/src/structlog/contextvars.py index 77d6bb61..54398c78 100644 --- a/src/structlog/contextvars.py +++ b/src/structlog/contextvars.py @@ -11,14 +11,21 @@ See :doc:`contextvars`. """ - import contextvars +from typing import Any, Dict + +from .types import Context, WrappedLogger -_CONTEXT = contextvars.ContextVar("structlog_context") +_CONTEXT: contextvars.ContextVar[Dict[str, Any]] = contextvars.ContextVar( + "structlog_context" +) -def merge_contextvars(logger, method_name, event_dict): + +def merge_contextvars( + logger: WrappedLogger, method_name: str, event_dict: Dict[str, Any] +) -> Context: """ A processor that merges in a global (context-local) context. @@ -29,10 +36,11 @@ def merge_contextvars(logger, method_name, event_dict): """ ctx = _get_context().copy() ctx.update(event_dict) + return ctx -def clear_contextvars(): +def clear_contextvars() -> None: """ Clear the context-local context. @@ -45,7 +53,7 @@ def clear_contextvars(): ctx.clear() -def bind_contextvars(**kwargs): +def bind_contextvars(**kw: Any) -> None: """ Put keys and values into the context-local context. @@ -54,10 +62,10 @@ def bind_contextvars(**kwargs): .. versionadded:: 20.1.0 """ - _get_context().update(kwargs) + _get_context().update(kw) -def unbind_contextvars(*keys): +def unbind_contextvars(*keys: str) -> None: """ Remove *keys* from the context-local context if they are present. @@ -71,7 +79,7 @@ def unbind_contextvars(*keys): ctx.pop(key, None) -def _get_context(): +def _get_context() -> Context: try: return _CONTEXT.get() except LookupError: diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 748fa6f9..42e1ca09 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -9,6 +9,9 @@ import sys from io import StringIO +from typing import Any, Optional, Type, Union + +from .types import EventDict, Protocol, WrappedLogger try: @@ -25,11 +28,12 @@ _EVENT_WIDTH = 30 # pad the event name to so many characters -def _pad(s, length): +def _pad(s: str, length: int) -> str: """ Pads *s* to length *lenght*. """ missing = length - len(s) + return s + " " * (missing if missing > 0 else 0) @@ -54,6 +58,26 @@ def _pad(s, length): ) = DIM = RED = BLUE = CYAN = MAGENTA = YELLOW = GREEN = RED_BACK = "" +class _Styles(Protocol): + reset: str + bright: str + level_critical: str + level_exception: str + level_error: str + level_warn: str + level_info: str + level_debug: str + level_notset: str + + timestamp: str + logger_name: str + kv_key: str + kv_value: str + + +Styles = Union[_Styles, Type[_Styles]] + + class _ColorfulStyles: reset = RESET_ALL bright = BRIGHT @@ -98,17 +122,17 @@ class ConsoleRenderer: :func:`~structlog.processors.format_exc_info`), it will be rendered *after* the log line. - :param int pad_event: Pad the event to this many characters. - :param bool colors: Use colors for a nicer output. - :param bool force_colors: Force colors even for non-tty destinations. + :param pad_event: Pad the event to this many characters. + :param colors: Use colors for a nicer output. + :param force_colors: Force colors even for non-tty destinations. Use this option if your logs are stored in a file that is meant to be streamed to the console. - :param bool repr_native_str: When `True`, `repr` is also applied + :param repr_native_str: When `True`, `repr` is also applied to native strings (i.e. unicode on Python 3 and bytes on Python 2). Setting this to `False` is useful if you want to have human-readable non-ASCII output on Python 2. The ``event`` key is *never* `repr` -ed. - :param dict level_styles: When present, use these styles for colors. This + :param level_styles: When present, use these styles for colors. This must be a dict from level names (strings) to colorama styles. The default can be obtained by calling `ConsoleRenderer.get_default_level_styles` @@ -132,13 +156,14 @@ class ConsoleRenderer: def __init__( self, - pad_event=_EVENT_WIDTH, - colors=_has_colorama, - force_colors=False, - repr_native_str=False, - level_styles=None, + pad_event: int = _EVENT_WIDTH, + colors: bool = _has_colorama, + force_colors: bool = False, + repr_native_str: bool = False, + level_styles: Optional[Styles] = None, ): self._force_colors = self._init_colorama = False + styles: Styles if colors is True: if colorama is None: raise SystemError( @@ -175,7 +200,7 @@ def __init__( self._repr_native_str = repr_native_str - def _repr(self, val): + def _repr(self, val: Any) -> str: """ Determine representation of *val* depending on its type & self._repr_native_str. @@ -188,7 +213,10 @@ def _repr(self, val): else: return repr(val) - def __call__(self, _, __, event_dict): + def __call__( + self, logger: WrappedLogger, name: str, event_dict: EventDict + ) -> str: + # Initialize lazily to prevent import side-effects. if self._init_colorama: _init_colorama(self._force_colors) @@ -261,7 +289,7 @@ def __call__(self, _, __, event_dict): return sio.getvalue() @staticmethod - def get_default_level_styles(colors=True): + def get_default_level_styles(colors: bool = True) -> Any: """ Get the default styles for log levels @@ -273,9 +301,10 @@ def get_default_level_styles(colors=True): my_styles["EVERYTHING_IS_ON_FIRE"] = my_styles["critical"] renderer = ConsoleRenderer(level_styles=my_styles) - :param bool colors: Whether to use colorful styles. This must match the + :param colors: Whether to use colorful styles. This must match the *colors* parameter to `ConsoleRenderer`. Default: `True`. """ + styles: Styles if colors: styles = _ColorfulStyles else: @@ -292,7 +321,7 @@ def get_default_level_styles(colors=True): } -def _init_colorama(force): +def _init_colorama(force: bool) -> None: if force: colorama.deinit() colorama.init(strip=False) @@ -303,7 +332,10 @@ def _init_colorama(force): _SENTINEL = object() -def set_exc_info(_, method_name, event_dict): +def set_exc_info( + logger: WrappedLogger, method_name: str, event_dict: EventDict +) -> EventDict: + """ Set ``event_dict["exc_info"] = True`` if *method_name* is ``"exception"``. diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 95071132..d17c9900 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -5,31 +5,33 @@ """ Processors useful regardless of the logging framework. """ - import datetime import json import operator import sys import time -from structlog._frames import ( +from typing import Any, Callable, Dict, List, Optional, Sequence, TextIO, Tuple + +from ._frames import ( _find_first_app_frame_and_name, _format_exception, _format_stack, ) +from .types import EventDict, ExcInfo, WrappedLogger class KeyValueRenderer: """ Render ``event_dict`` as a list of ``Key=repr(Value)`` pairs. - :param bool sort_keys: Whether to sort keys when formatting. - :param list key_order: List of keys that should be rendered in this exact + :param sort_keys: Whether to sort keys when formatting. + :param key_order: List of keys that should be rendered in this exact order. Missing keys will be rendered as ``None``, extra keys depending on *sort_keys* and the dict class. - :param bool drop_missing: When ``True``, extra keys in *key_order* will be + :param drop_missing: When ``True``, extra keys in *key_order* will be dropped rather than rendered as ``None``. - :param bool repr_native_str: When ``True``, :func:`repr()` is also applied + :param repr_native_str: When ``True``, :func:`repr()` is also applied to native strings (i.e. unicode on Python 3 and bytes on Python 2). Setting this to ``False`` is useful if you want to have human-readable non-ASCII output on Python 2. @@ -41,37 +43,41 @@ class KeyValueRenderer: def __init__( self, - sort_keys=False, - key_order=None, - drop_missing=False, - repr_native_str=True, + sort_keys: bool = False, + key_order: Optional[Sequence[str]] = None, + drop_missing: bool = False, + repr_native_str: bool = True, ): # Use an optimized version for each case. - if key_order and sort_keys: + if key_order and sort_keys is True: - def ordered_items(event_dict): + def ordered_items(event_dict: EventDict) -> List[Tuple[str, Any]]: items = [] - for key in key_order: + for key in key_order: # type: ignore value = event_dict.pop(key, None) if value is not None or not drop_missing: items.append((key, value)) + items += sorted(event_dict.items()) + return items elif key_order: - def ordered_items(event_dict): + def ordered_items(event_dict: EventDict) -> List[Tuple[str, Any]]: items = [] - for key in key_order: + for key in key_order: # type: ignore value = event_dict.pop(key, None) if value is not None or not drop_missing: items.append((key, value)) + items += event_dict.items() + return items elif sort_keys: - def ordered_items(event_dict): + def ordered_items(event_dict: EventDict) -> List[Tuple[str, Any]]: return sorted(event_dict.items()) else: @@ -83,7 +89,7 @@ def ordered_items(event_dict): self._repr = repr else: - def _repr(inst): + def _repr(inst: Any) -> str: if isinstance(inst, str): return inst else: @@ -91,7 +97,9 @@ def _repr(inst): self._repr = _repr - def __call__(self, _, __, event_dict): + def __call__( + self, _: WrappedLogger, __: str, event_dict: EventDict + ) -> str: return " ".join( k + "=" + self._repr(v) for k, v in self._ordered_items(event_dict) ) @@ -101,8 +109,8 @@ class UnicodeEncoder: """ Encode unicode values in ``event_dict``. - :param str encoding: Encoding to encode to (default: ``"utf-8"``). - :param str errors: How to cope with encoding errors (default + :param encoding: Encoding to encode to (default: ``"utf-8"``). + :param errors: How to cope with encoding errors (default ``"backslashreplace"``). Useful if you're running Python 2 as otherwise ``u"abc"`` will be rendered @@ -111,14 +119,22 @@ class UnicodeEncoder: Just put it in the processor chain before the renderer. """ - def __init__(self, encoding="utf-8", errors="backslashreplace"): + _encoding: str + _errors: str + + def __init__( + self, encoding: str = "utf-8", errors: str = "backslashreplace" + ) -> None: self._encoding = encoding self._errors = errors - def __call__(self, logger, name, event_dict): + def __call__( + self, logger: WrappedLogger, name: str, event_dict: EventDict + ) -> EventDict: for key, value in event_dict.items(): if isinstance(value, str): event_dict[key] = value.encode(self._encoding, self._errors) + return event_dict @@ -126,8 +142,8 @@ class UnicodeDecoder: """ Decode byte string values in ``event_dict``. - :param str encoding: Encoding to decode from (default: ``"utf-8"``). - :param str errors: How to cope with encoding errors (default: + :param encoding: Encoding to decode from (default: ``"utf-8"``). + :param errors: How to cope with encoding errors (default: ``"replace"``). Useful if you're running Python 3 as otherwise ``b"abc"`` will be rendered @@ -138,14 +154,22 @@ class UnicodeDecoder: .. versionadded:: 15.4.0 """ - def __init__(self, encoding="utf-8", errors="replace"): + _encoding: str + _errors: str + + def __init__( + self, encoding: str = "utf-8", errors: str = "replace" + ) -> None: self._encoding = encoding self._errors = errors - def __call__(self, logger, name, event_dict): + def __call__( + self, logger: WrappedLogger, name: str, event_dict: EventDict + ) -> EventDict: for key, value in event_dict.items(): if isinstance(value, bytes): event_dict[key] = value.decode(self._encoding, self._errors) + return event_dict @@ -153,10 +177,10 @@ class JSONRenderer: """ Render the ``event_dict`` using ``serializer(event_dict, **json_kw)``. - :param dict json_kw: Are passed unmodified to *serializer*. If *default* + :param json_kw: Are passed unmodified to *serializer*. If *default* is passed, it will disable support for ``__structlog__``-based serialization. - :param callable serializer: A :func:`json.dumps`-compatible callable that + :param serializer: A :func:`json.dumps`-compatible callable that will be used to format the string. This can be used to use alternative JSON encoders like `simplejson `_ or `RapidJSON @@ -174,16 +198,20 @@ class JSONRenderer: """ - def __init__(self, serializer=json.dumps, **dumps_kw): + def __init__( + self, serializer: Callable[..., str] = json.dumps, **dumps_kw: Any + ) -> None: dumps_kw.setdefault("default", _json_fallback_handler) self._dumps_kw = dumps_kw self._dumps = serializer - def __call__(self, logger, name, event_dict): + def __call__( + self, logger: WrappedLogger, name: str, event_dict: EventDict + ) -> str: return self._dumps(event_dict, **self._dumps_kw) -def _json_fallback_handler(obj): +def _json_fallback_handler(obj: Any) -> Any: """ Serialize custom datatypes and pass the rest to __structlog__ & repr(). """ @@ -199,7 +227,9 @@ def _json_fallback_handler(obj): return repr(obj) -def format_exc_info(logger, name, event_dict): +def format_exc_info( + logger: WrappedLogger, name: str, event_dict: EventDict +) -> EventDict: """ Replace an ``exc_info`` field by an ``exception`` string field: @@ -220,6 +250,7 @@ def format_exc_info(logger, name, event_dict): event_dict["exception"] = _format_exception( _figure_out_exc_info(exc_info) ) + return event_dict @@ -232,29 +263,36 @@ class TimeStamper: You should let OS tools take care of timestamping. See also `logging-best-practices`. - :param str fmt: strftime format string, or ``"iso"`` for `ISO 8601 + :param fmt: strftime format string, or ``"iso"`` for `ISO 8601 `_, or `None` for a `UNIX timestamp `_. - :param bool utc: Whether timestamp should be in UTC or local time. - :param str key: Target key in *event_dict* for added timestamps. + :param utc: Whether timestamp should be in UTC or local time. + :param key: Target key in *event_dict* for added timestamps. .. versionchanged:: 19.2 Can be pickled now. """ __slots__ = ("_stamper", "fmt", "utc", "key") - def __init__(self, fmt=None, utc=True, key="timestamp"): + def __init__( + self, + fmt: Optional[str] = None, + utc: bool = True, + key: str = "timestamp", + ) -> None: self.fmt, self.utc, self.key = fmt, utc, key self._stamper = _make_stamper(fmt, utc, key) - def __call__(self, _, __, event_dict): + def __call__( + self, logger: WrappedLogger, name: str, event_dict: EventDict + ) -> EventDict: return self._stamper(event_dict) - def __getstate__(self): + def __getstate__(self) -> Dict[str, Any]: return {"fmt": self.fmt, "utc": self.utc, "key": self.key} - def __setstate__(self, state): + def __setstate__(self, state: Dict[str, Any]) -> None: self.fmt = state["fmt"] self.utc = state["utc"] self.key = state["key"] @@ -262,7 +300,9 @@ def __setstate__(self, state): self._stamper = _make_stamper(**state) -def _make_stamper(fmt, utc, key): +def _make_stamper( + fmt: Optional[str], utc: bool, key: str +) -> Callable[[EventDict], EventDict]: """ Create a stamper function. """ @@ -273,18 +313,19 @@ def _make_stamper(fmt, utc, key): if fmt is None: - def stamper_unix(event_dict): + def stamper_unix(event_dict: EventDict) -> EventDict: event_dict[key] = time.time() + return event_dict return stamper_unix elif fmt.upper() == "ISO": - def stamper_iso_local(event_dict): + def stamper_iso_local(event_dict: EventDict) -> EventDict: event_dict[key] = now().isoformat() return event_dict - def stamper_iso_utc(event_dict): + def stamper_iso_utc(event_dict: EventDict) -> EventDict: event_dict[key] = now().isoformat() + "Z" return event_dict @@ -293,26 +334,25 @@ def stamper_iso_utc(event_dict): else: return stamper_iso_local - def stamper_fmt(event_dict): + def stamper_fmt(event_dict: EventDict) -> EventDict: event_dict[key] = now().strftime(fmt) + return event_dict return stamper_fmt -def _figure_out_exc_info(v): +def _figure_out_exc_info(v: Any) -> ExcInfo: """ Depending on the Python version will try to do the smartest thing possible to transform *v* into an ``exc_info`` tuple. - - :rtype: tuple """ if isinstance(v, BaseException): return (v.__class__, v, v.__traceback__) elif isinstance(v, tuple): - return v + return v # type: ignore elif v: - return sys.exc_info() + return sys.exc_info() # type: ignore return v @@ -322,7 +362,6 @@ class ExceptionPrettyPrinter: Pretty print exceptions and remove them from the ``event_dict``. :param file: Target file for output (default: ``sys.stdout``). - :type file: file object This processor is mostly for development and testing so you can read exceptions properly formatted. @@ -340,20 +379,24 @@ class ExceptionPrettyPrinter: Added support for passing exceptions as ``exc_info`` on Python 3. """ - def __init__(self, file=None): + def __init__(self, file: Optional[TextIO] = None) -> None: if file is not None: self._file = file else: self._file = sys.stdout - def __call__(self, logger, name, event_dict): + def __call__( + self, logger: WrappedLogger, name: str, event_dict: EventDict + ) -> EventDict: exc = event_dict.pop("exception", None) if exc is None: exc_info = _figure_out_exc_info(event_dict.pop("exc_info", None)) if exc_info: exc = _format_exception(exc_info) + if exc: print(exc, file=self._file) + return event_dict @@ -370,9 +413,12 @@ class StackInfoRenderer: .. versionadded:: 0.4.0 """ - def __call__(self, logger, name, event_dict): + def __call__( + self, logger: WrappedLogger, name: str, event_dict: EventDict + ) -> EventDict: if event_dict.pop("stack_info", None): event_dict["stack"] = _format_stack( _find_first_app_frame_and_name()[0] ) + return event_dict diff --git a/src/structlog/py.typed b/src/structlog/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index df147171..069c3248 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -8,12 +8,15 @@ See also :doc:`structlog's standard library support `. """ - import logging -from structlog._base import BoundLoggerBase -from structlog._frames import _find_first_app_frame_and_name, _format_stack -from structlog.exceptions import DropEvent +from typing import Any, Dict, List, Optional, Sequence, Tuple + +from ._base import BoundLoggerBase +from ._config import get_logger as _generic_get_logger +from ._frames import _find_first_app_frame_and_name, _format_stack +from .exceptions import DropEvent +from .types import EventDict, ExcInfo, Processor, WrappedLogger _SENTINEL = object() @@ -25,18 +28,22 @@ class _FixedFindCallerLogger(logging.Logger): ``structlog``'s extra frames. """ - def findCaller(self, stack_info=False, stacklevel=1): + def findCaller( + self, stack_info: bool = False, stacklevel: int = 1 + ) -> Tuple[str, int, str, Optional[str]]: """ Finds the first caller frame outside of structlog so that the caller info is populated for wrapping stdlib. This logger gets set as the default one when using LoggerFactory. """ + sinfo: Optional[str] f, name = _find_first_app_frame_and_name(["logging"]) if stack_info: sinfo = _format_stack(f) else: sinfo = None + return f.f_code.co_filename, f.f_lineno, f.f_code.co_name, sinfo @@ -57,19 +64,55 @@ class BoundLogger(BoundLoggerBase): `logging.Logger` which should make it work as a drop-in replacement. """ - def debug(self, event=None, *args, **kw): + _logger: logging.Logger + + def bind(self, **new_values: Any) -> "BoundLogger": + """ + Return a new logger with *new_values* added to the existing ones. + """ + return super().bind(**new_values) # type: ignore + + def unbind(self, *keys: str) -> "BoundLogger": + """ + Return a new logger with *keys* removed from the context. + + :raises KeyError: If the key is not part of the context. + """ + return super().unbind(*keys) # type: ignore + + def try_unbind(self, *keys: str) -> "BoundLogger": + """ + Like :meth:`unbind`, but best effort: missing keys are ignored. + + .. versionadded:: 18.2.0 + """ + return super().try_unbind(*keys) # type: ignore + + def new(self, **new_values: Any) -> "BoundLogger": + """ + Clear context and binds *initial_values* using `bind`. + + Only necessary with dict implementations that keep global state like + those wrapped by `structlog.threadlocal.wrap_dict` when threads + are re-used. + """ + return super().new(**new_values) # type: ignore + + def debug(self, event: Optional[str] = None, *args: Any, **kw: Any) -> Any: """ Process event and call `logging.Logger.debug` with the result. """ return self._proxy_to_logger("debug", event, *args, **kw) - def info(self, event=None, *args, **kw): + def info(self, event: Optional[str] = None, *args: Any, **kw: Any) -> Any: """ Process event and call `logging.Logger.info` with the result. """ return self._proxy_to_logger("info", event, *args, **kw) - def warning(self, event=None, *args, **kw): + def warning( + self, event: Optional[str] = None, *args: Any, **kw: Any + ) -> Any: """ Process event and call `logging.Logger.warning` with the result. """ @@ -77,27 +120,34 @@ def warning(self, event=None, *args, **kw): warn = warning - def error(self, event=None, *args, **kw): + def error(self, event: Optional[str] = None, *args: Any, **kw: Any) -> Any: """ Process event and call `logging.Logger.error` with the result. """ return self._proxy_to_logger("error", event, *args, **kw) - def critical(self, event=None, *args, **kw): + def critical( + self, event: Optional[str] = None, *args: Any, **kw: Any + ) -> Any: """ Process event and call `logging.Logger.critical` with the result. """ return self._proxy_to_logger("critical", event, *args, **kw) - def exception(self, event=None, *args, **kw): + def exception( + self, event: Optional[str] = None, *args: Any, **kw: Any + ) -> Any: """ Process event and call `logging.Logger.error` with the result, after setting ``exc_info`` to `True`. """ kw.setdefault("exc_info", True) + return self.error(event, *args, **kw) - def log(self, level, event, *args, **kw): + def log( + self, level: int, event: Optional[str] = None, *args: Any, **kw: Any + ) -> Any: """ Process *event* and call the appropriate logging method depending on *level*. @@ -106,16 +156,23 @@ def log(self, level, event, *args, **kw): fatal = critical - def _proxy_to_logger(self, method_name, event, *event_args, **event_kw): + def _proxy_to_logger( + self, + method_name: str, + event: Optional[str] = None, + *event_args: str, + **event_kw: Any, + ) -> Any: """ Propagate a method call to the wrapped logger. This is the same as the superclass implementation, except that it also preserves positional arguments in the ``event_dict`` so - that the stdblib's support for format strings can be used. + that the stdlib's support for format strings can be used. """ if event_args: event_kw["positional_args"] = event_args + return super()._proxy_to_logger(method_name, event=event, **event_kw) # @@ -124,62 +181,73 @@ def _proxy_to_logger(self, method_name, event, *event_args, **event_kw): # @property - def name(self): + def name(self) -> str: """ Returns :attr:`logging.Logger.name` """ return self._logger.name @property - def level(self): + def level(self) -> int: """ Returns :attr:`logging.Logger.level` """ return self._logger.level @property - def parent(self): + def parent(self) -> Any: """ Returns :attr:`logging.Logger.parent` """ return self._logger.parent @property - def propagate(self): + def propagate(self) -> bool: """ Returns :attr:`logging.Logger.propagate` """ return self._logger.propagate @property - def handlers(self): + def handlers(self) -> Any: """ Returns :attr:`logging.Logger.handlers` """ return self._logger.handlers @property - def disabled(self): + def disabled(self) -> int: """ Returns :attr:`logging.Logger.disabled` """ return self._logger.disabled - def setLevel(self, level): + def setLevel(self, level: int) -> None: """ Calls :meth:`logging.Logger.setLevel` with unmodified arguments. """ self._logger.setLevel(level) - def findCaller(self, stack_info=False): + def findCaller( + self, stack_info: bool = False + ) -> Tuple[str, int, str, Optional[str]]: """ Calls :meth:`logging.Logger.findCaller` with unmodified arguments. """ return self._logger.findCaller(stack_info=stack_info) def makeRecord( - self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None - ): + self, + name: str, + level: int, + fn: str, + lno: int, + msg: str, + args: Tuple[Any, ...], + exc_info: ExcInfo, + func: Optional[str] = None, + extra: Any = None, + ) -> logging.LogRecord: """ Calls :meth:`logging.Logger.makeRecord` with unmodified arguments. """ @@ -187,25 +255,25 @@ def makeRecord( name, level, fn, lno, msg, args, exc_info, func=func, extra=extra ) - def handle(self, record): + def handle(self, record: logging.LogRecord) -> None: """ Calls :meth:`logging.Logger.handle` with unmodified arguments. """ self._logger.handle(record) - def addHandler(self, hdlr): + def addHandler(self, hdlr: logging.Handler) -> None: """ Calls :meth:`logging.Logger.addHandler` with unmodified arguments. """ self._logger.addHandler(hdlr) - def removeHandler(self, hdlr): + def removeHandler(self, hdlr: logging.Handler) -> None: """ Calls :meth:`logging.Logger.removeHandler` with unmodified arguments. """ self._logger.removeHandler(hdlr) - def hasHandlers(self): + def hasHandlers(self) -> bool: """ Calls :meth:`logging.Logger.hasHandlers` with unmodified arguments. @@ -213,32 +281,47 @@ def hasHandlers(self): """ return self._logger.hasHandlers() - def callHandlers(self, record): + def callHandlers(self, record: logging.LogRecord) -> None: """ Calls :meth:`logging.Logger.callHandlers` with unmodified arguments. """ - self._logger.callHandlers(record) + self._logger.callHandlers(record) # type: ignore - def getEffectiveLevel(self): + def getEffectiveLevel(self) -> int: """ Calls :meth:`logging.Logger.getEffectiveLevel` with unmodified arguments. """ return self._logger.getEffectiveLevel() - def isEnabledFor(self, level): + def isEnabledFor(self, level: int) -> bool: """ Calls :meth:`logging.Logger.isEnabledFor` with unmodified arguments. """ return self._logger.isEnabledFor(level) - def getChild(self, suffix): + def getChild(self, suffix: str) -> logging.Logger: """ Calls :meth:`logging.Logger.getChild` with unmodified arguments. """ return self._logger.getChild(suffix) +def get_logger(*args: Any, **initial_values: Any) -> BoundLogger: + """ + Only calls `structlog.get_logger`, but has the correct type hints. + + .. warning:: + + Does **not** check whether you've configured ``structlog`` correctly! + + See :doc:`standard-library` for details. + + .. versionadded:: 20.2.0 + """ + return _generic_get_logger(*args, **initial_values) + + class LoggerFactory: """ Build a standard library logger when an *instance* is called. @@ -254,14 +337,13 @@ class LoggerFactory: whose names *start* with one of these. For example, in pyramid applications you'll want to set it to ``["venusian", "pyramid.config"]``. - :type ignore_frame_names: ``list`` of ``str`` """ - def __init__(self, ignore_frame_names=None): + def __init__(self, ignore_frame_names: Optional[List[str]] = None): self._ignore = ignore_frame_names logging.setLoggerClass(_FixedFindCallerLogger) - def __call__(self, *args): + def __call__(self, *args: Any) -> logging.Logger: """ Deduce the caller's module name and create a stdlib logger. @@ -271,8 +353,6 @@ def __call__(self, *args): ``structlog.get_logger("foo")`` would cause this method to be called with ``"foo"`` as its first positional argument. - :rtype: logging.Logger - .. versionchanged:: 0.4.0 Added support for optional positional arguments. Using the first one for naming the constructed logger. @@ -283,6 +363,7 @@ def __call__(self, *args): # We skip all frames that originate from within structlog or one of the # configured names. _, name = _find_first_app_frame_and_name(self._ignore) + return logging.getLogger(name) @@ -306,10 +387,12 @@ class PositionalArgumentsFormatter: removed from the event dict after formatting a message. """ - def __init__(self, remove_positional_args=True): + def __init__(self, remove_positional_args: bool = True) -> None: self.remove_positional_args = remove_positional_args - def __call__(self, _, __, event_dict): + def __call__( + self, _: WrappedLogger, __: str, event_dict: EventDict + ) -> EventDict: args = event_dict.get("positional_args") # Mimick the formatting behaviour of the stdlib's logging @@ -319,9 +402,12 @@ def __call__(self, _, __, event_dict): if args: if len(args) == 1 and isinstance(args[0], dict) and args[0]: args = args[0] + event_dict["event"] = event_dict["event"] % args + if self.remove_positional_args and args is not None: del event_dict["positional_args"] + return event_dict @@ -353,7 +439,9 @@ def __call__(self, _, __, event_dict): } -def filter_by_level(logger, name, event_dict): +def filter_by_level( + logger: logging.Logger, method_name: str, event_dict: EventDict +) -> EventDict: """ Check whether logging is configured to accept messages from this log level. @@ -372,13 +460,15 @@ def filter_by_level(logger, name, event_dict): ... DropEvent """ - if logger.isEnabledFor(_NAME_TO_LEVEL[name]): + if logger.isEnabledFor(_NAME_TO_LEVEL[method_name]): return event_dict else: raise DropEvent -def add_log_level(logger, method_name, event_dict): +def add_log_level( + logger: logging.Logger, method_name: str, event_dict: EventDict +) -> EventDict: """ Add the log level to the event dict. """ @@ -387,10 +477,13 @@ def add_log_level(logger, method_name, event_dict): method_name = "warning" event_dict["level"] = method_name + return event_dict -def add_log_level_number(logger, method_name, event_dict): +def add_log_level_number( + logger: logging.Logger, method_name: str, event_dict: EventDict +) -> EventDict: """ Add the log level number to the event dict. @@ -406,10 +499,13 @@ def add_log_level_number(logger, method_name, event_dict): .. versionadded:: 18.2.0 """ event_dict["level_number"] = _NAME_TO_LEVEL[method_name] + return event_dict -def add_logger_name(logger, method_name, event_dict): +def add_logger_name( + logger: logging.Logger, method_name: str, event_dict: EventDict +) -> EventDict: """ Add the logger name to the event dict. """ @@ -421,7 +517,9 @@ def add_logger_name(logger, method_name, event_dict): return event_dict -def render_to_log_kwargs(wrapped_logger, method_name, event_dict): +def render_to_log_kwargs( + _: logging.Logger, __: str, event_dict: EventDict +) -> EventDict: """ Render ``event_dict`` into keyword arguments for `logging.log`. @@ -451,23 +549,22 @@ class ProcessorFormatter(logging.Formatter): Please refer to :doc:`standard-library` for examples. - :param callable processor: A ``structlog`` processor. + :param processor: A ``structlog`` processor. :param foreign_pre_chain: If not `None`, it is used as an iterable of processors that is applied to non-``structlog`` log entries before *processor*. If `None`, formatting is left to :mod:`logging`. (default: `None`) - :param bool keep_exc_info: ``exc_info`` on `logging.LogRecord`\ s is + :param keep_exc_info: ``exc_info`` on `logging.LogRecord`\ s is added to the ``event_dict`` and removed afterwards. Set this to ``True`` to keep it on the `logging.LogRecord`. (default: False) - :param bool keep_stack_info: Same as *keep_exc_info* except for Python 3's + :param keep_stack_info: Same as *keep_exc_info* except for Python 3's ``stack_info``. (default: False) :param logger: Logger which we want to push through the ``structlog`` processor chain. This parameter is necessary for some of the processors like `filter_by_level`. (default: None) - :param bool pass_foreign_args: If True, pass a foreign log record's + :param pass_foreign_args: If True, pass a foreign log record's ``args`` attribute to the ``event_dict`` under ``positional_args`` key. (default: False) - :rtype: str .. versionadded:: 17.1.0 .. versionadded:: 17.2.0 *keep_exc_info* and *keep_stack_info* @@ -477,17 +574,18 @@ class ProcessorFormatter(logging.Formatter): def __init__( self, - processor, - foreign_pre_chain=None, - keep_exc_info=False, - keep_stack_info=False, - logger=None, - pass_foreign_args=False, - *args, - **kwargs - ): + processor: Processor, + foreign_pre_chain: Optional[Sequence[Processor]] = None, + keep_exc_info: bool = False, + keep_stack_info: bool = False, + logger: Optional[logging.Logger] = None, + pass_foreign_args: bool = False, + *args: Any, + **kwargs: Any, + ) -> None: fmt = kwargs.pop("fmt", "%(message)s") - super().__init__(*args, fmt=fmt, **kwargs) + super().__init__(*args, fmt=fmt, **kwargs) # type: ignore + self.processor = processor self.foreign_pre_chain = foreign_pre_chain self.keep_exc_info = keep_exc_info @@ -495,9 +593,12 @@ def __init__( self.logger = logger self.pass_foreign_args = pass_foreign_args - def format(self, record): + def format(self, record: logging.LogRecord) -> str: """ Extract ``structlog``'s `event_dict` from ``record.msg`` and format it. + + *record* has been patched by `wrap_for_formatter` first though, so the + type isn't quite right. """ # Make a shallow copy of the record to let other handlers/formatters # process the original one @@ -510,12 +611,12 @@ def format(self, record): # Both attached by wrap_for_formatter if self.logger is not None: logger = self.logger - meth_name = record._name + meth_name = record._name # type: ignore # We need to copy because it's possible that the same record gets # processed by multiple logging formatters. LogRecord.getMessage # would transform our dict into a str. - ed = record.msg.copy() + ed = record.msg.copy() # type: ignore else: logger = self.logger meth_name = record.levelname.lower() @@ -547,11 +648,14 @@ def format(self, record): del ed["_record"] - record.msg = self.processor(logger, meth_name, ed) + record.msg = self.processor(logger, meth_name, ed) # type: ignore + return super().format(record) @staticmethod - def wrap_for_formatter(logger, name, event_dict): + def wrap_for_formatter( + logger: logging.Logger, name: str, event_dict: EventDict + ) -> Tuple[Tuple[EventDict], Dict[str, Dict[str, Any]]]: """ Wrap *logger*, *name*, and *event_dict*. diff --git a/src/structlog/testing.py b/src/structlog/testing.py index e8a5dcf1..508bd8b8 100644 --- a/src/structlog/testing.py +++ b/src/structlog/testing.py @@ -11,9 +11,11 @@ """ from contextlib import contextmanager +from typing import Any, Generator, List, NoReturn from ._config import configure, get_config from .exceptions import DropEvent +from .types import EventDict, WrappedLogger __all__ = ["LogCapture", "capture_logs"] @@ -28,17 +30,22 @@ class LogCapture: .. versionadded:: 20.1.0 """ - def __init__(self): + entries: List[EventDict] + + def __init__(self) -> None: self.entries = [] - def __call__(self, _, method_name, event_dict): + def __call__( + self, _: WrappedLogger, method_name: str, event_dict: EventDict + ) -> NoReturn: event_dict["log_level"] = method_name self.entries.append(event_dict) + raise DropEvent @contextmanager -def capture_logs(): +def capture_logs() -> Generator[List[EventDict], None, None]: """ Context manager that appends all logging statements to its yielded list while it is active. Disables all configured processors for the duration @@ -57,24 +64,6 @@ def capture_logs(): configure(processors=old_processors) -class ReturnLoggerFactory: - r""" - Produce and cache `ReturnLogger`\ s. - - To be used with `structlog.configure`\ 's *logger_factory*. - - Positional arguments are silently ignored. - - .. versionadded:: 0.4.0 - """ - - def __init__(self): - self._logger = ReturnLogger() - - def __call__(self, *args): - return self._logger - - class ReturnLogger: """ Return the arguments that it's called with. @@ -89,7 +78,7 @@ class ReturnLogger: Allow for arbitrary arguments and keyword arguments to be passed in. """ - def msg(self, *args, **kw): + def msg(self, *args: Any, **kw: Any) -> Any: """ Return tuple of ``args, kw`` or just ``args[0]`` if only one arg passed """ @@ -101,3 +90,21 @@ def msg(self, *args, **kw): log = debug = info = warn = warning = msg fatal = failure = err = error = critical = exception = msg + + +class ReturnLoggerFactory: + r""" + Produce and cache `ReturnLogger`\ s. + + To be used with `structlog.configure`\ 's *logger_factory*. + + Positional arguments are silently ignored. + + .. versionadded:: 0.4.0 + """ + + def __init__(self) -> None: + self._logger = ReturnLogger() + + def __call__(self, *args: Any) -> ReturnLogger: + return self._logger diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index 7a479d25..e9046425 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -7,97 +7,92 @@ See `thread-local`. """ - - import contextlib import threading import uuid -from structlog._config import BoundLoggerLazyProxy +from typing import Any, Dict, Generator, Iterator, Type, TypeVar +from ._config import BoundLoggerLazyProxy +from .types import BindableLogger, Context, EventDict, WrappedLogger -try: - from greenlet import getcurrent -except ImportError: - from threading import local as ThreadLocal -else: - from weakref import WeakKeyDictionary - class ThreadLocal: - """ - threading.local() replacement for greenlets. - """ +def _determine_threadlocal() -> Type[Any]: + """ + Return a dict-like threadlocal storage depending on whether we run with + greenlets or not. + """ + try: + from ._greenlets import GreenThreadLocal + except ImportError: + from threading import local - def __init__(self): - self.__dict__["_weakdict"] = WeakKeyDictionary() + return local - def __getattr__(self, name): - key = getcurrent() - try: - return self._weakdict[key][name] - except KeyError: - raise AttributeError(name) + return GreenThreadLocal - def __setattr__(self, name, val): - key = getcurrent() - self._weakdict.setdefault(key, {})[name] = val - def __delattr__(self, name): - key = getcurrent() - try: - del self._weakdict[key][name] - except KeyError: - raise AttributeError(name) +ThreadLocal = _determine_threadlocal() -def wrap_dict(dict_class): +def wrap_dict(dict_class: Type[EventDict]) -> Type[EventDict]: """ Wrap a dict-like class and return the resulting class. The wrapped class and used to keep global in the current thread. - :param type dict_class: Class used for keeping context. - - :rtype: `type` + :param dict_class: Class used for keeping context. """ Wrapped = type( "WrappedDict-" + str(uuid.uuid4()), (_ThreadLocalDictWrapper,), {} ) - Wrapped._tl = ThreadLocal() - Wrapped._dict_class = dict_class + Wrapped._tl = ThreadLocal() # type: ignore + Wrapped._dict_class = dict_class # type: ignore + return Wrapped -def as_immutable(logger): +TLLogger = TypeVar("TLLogger", bound=BindableLogger) + + +def as_immutable(logger: TLLogger) -> TLLogger: """ Extract the context from a thread local logger into an immutable logger. - :param structlog.BoundLogger logger: A logger with *possibly* thread local - state. - :rtype: :class:`~structlog.BoundLogger` with an immutable context. + :param structlog.types.BindableLogger logger: A logger with *possibly* + thread local state. + + :returns: :class:`~structlog.BoundLogger` with an immutable context. """ if isinstance(logger, BoundLoggerLazyProxy): - logger = logger.bind() + logger = logger.bind() # type: ignore try: - ctx = logger._context._tl.dict_.__class__(logger._context._dict) + ctx = logger._context._tl.dict_.__class__( # type: ignore + logger._context._dict # type: ignore + ) bl = logger.__class__( - logger._logger, processors=logger._processors, context={} + logger._logger, # type: ignore + processors=logger._processors, # type: ignore + context={}, ) bl._context = ctx + return bl except AttributeError: return logger @contextlib.contextmanager -def tmp_bind(logger, **tmp_values): +def tmp_bind( + logger: TLLogger, **tmp_values: Any +) -> Generator[TLLogger, None, None]: """ Bind *tmp_values* to *logger* & memorize current state. Rewind afterwards. """ saved = as_immutable(logger)._context try: - yield logger.bind(**tmp_values) + yield logger.bind(**tmp_values) # type: ignore finally: logger._context.clear() logger._context.update(saved) @@ -115,7 +110,10 @@ class _ThreadLocalDictWrapper: :func:`structlog._loggers.BoundLogger.new` to clear the context. """ - def __init__(self, *args, **kw): + _tl: Any + _dict_class: Type[Dict[str, Any]] + + def __init__(self, *args: Any, **kw: Any) -> None: """ We cheat. A context dict gets never recreated. """ @@ -127,7 +125,7 @@ def __init__(self, *args, **kw): self._dict.update(*args, **kw) @property - def _dict(self): + def _dict(self) -> Context: """ Return or create and return the current context. """ @@ -135,41 +133,45 @@ def _dict(self): return self.__class__._tl.dict_ except AttributeError: self.__class__._tl.dict_ = self.__class__._dict_class() + return self.__class__._tl.dict_ - def __repr__(self): + def __repr__(self) -> str: return f"<{self.__class__.__name__}({self._dict!r})>" - def __eq__(self, other): + def __eq__(self, other: Any) -> bool: # Same class == same dictionary return self.__class__ == other.__class__ - def __ne__(self, other): + def __ne__(self, other: Any) -> bool: return not self.__eq__(other) # Proxy methods necessary for structlog. # Dunder methods don't trigger __getattr__ so we need to proxy by hand. - def __iter__(self): + def __iter__(self) -> Iterator[str]: return self._dict.__iter__() - def __setitem__(self, key, value): + def __setitem__(self, key: str, value: Any) -> None: self._dict[key] = value - def __delitem__(self, key): + def __delitem__(self, key: str) -> None: self._dict.__delitem__(key) - def __len__(self): + def __len__(self) -> int: return self._dict.__len__() - def __getattr__(self, name): + def __getattr__(self, name: str) -> Any: method = getattr(self._dict, name) + return method _CONTEXT = threading.local() -def merge_threadlocal(logger, method_name, event_dict): +def merge_threadlocal( + logger: WrappedLogger, method_name: str, event_dict: EventDict +) -> EventDict: """ A processor that merges in a global (thread-local) context. @@ -184,6 +186,7 @@ def merge_threadlocal(logger, method_name, event_dict): """ context = _get_context().copy() context.update(event_dict) + return context @@ -191,7 +194,7 @@ def merge_threadlocal(logger, method_name, event_dict): merge_threadlocal_context = merge_threadlocal -def clear_threadlocal(): +def clear_threadlocal() -> None: """ Clear the thread-local context. @@ -203,7 +206,7 @@ def clear_threadlocal(): _CONTEXT.context = {} -def bind_threadlocal(**kwargs): +def bind_threadlocal(**kw: Any) -> None: """ Put keys and values into the thread-local context. @@ -212,10 +215,10 @@ def bind_threadlocal(**kwargs): .. versionadded:: 19.2.0 """ - _get_context().update(kwargs) + _get_context().update(kw) -def unbind_threadlocal(*keys): +def unbind_threadlocal(*keys: str) -> None: """ Tries to remove bound *keys* from threadlocal logging context if present. @@ -226,9 +229,10 @@ def unbind_threadlocal(*keys): context.pop(key, None) -def _get_context(): +def _get_context() -> Context: try: return _CONTEXT.context except AttributeError: _CONTEXT.context = {} + return _CONTEXT.context diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index fd2b442c..d43d1e25 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -9,10 +9,11 @@ See also :doc:`structlog's Twisted support `. """ - import json import sys +from typing import Any, Callable, Dict, Optional, Sequence, TextIO, Tuple + from twisted.python import log from twisted.python.failure import Failure from twisted.python.log import ILogObserver, textFromEventDict @@ -22,6 +23,7 @@ from ._config import _BUILTIN_DEFAULT_PROCESSORS from ._utils import until_not_interrupted from .processors import JSONRenderer as GenericJSONRenderer +from .types import EventDict, WrappedLogger class BoundLogger(BoundLoggerBase): @@ -39,13 +41,13 @@ class BoundLogger(BoundLoggerBase): """ - def msg(self, event=None, **kw): + def msg(self, event: Optional[str] = None, **kw: Any) -> Any: """ Process event and call ``log.msg()`` with the result. """ return self._proxy_to_logger("msg", event, **kw) - def err(self, event=None, **kw): + def err(self, event: Optional[str] = None, **kw: Any) -> Any: """ Process event and call ``log.err()`` with the result. """ @@ -61,7 +63,7 @@ class LoggerFactory: >>> configure(logger_factory=LoggerFactory()) """ - def __call__(self, *args): + def __call__(self, *args: Any) -> WrappedLogger: """ Positional arguments are silently ignored. @@ -76,7 +78,7 @@ def __call__(self, *args): _FAIL_TYPES = (BaseException, Failure) -def _extractStuffAndWhy(eventDict): +def _extractStuffAndWhy(eventDict: EventDict) -> Tuple[Any, Any, EventDict]: """ Removes all possible *_why*s and *_stuff*s, analyzes exc_info and returns a tuple of ``(_stuff, _why, eventDict)``. @@ -86,19 +88,27 @@ def _extractStuffAndWhy(eventDict): _stuff = eventDict.pop("_stuff", None) _why = eventDict.pop("_why", None) event = eventDict.pop("event", None) - if isinstance(_stuff, _FAIL_TYPES) and isinstance(event, _FAIL_TYPES): + + if isinstance(_stuff, _FAIL_TYPES) and isinstance( # type: ignore + event, _FAIL_TYPES + ): raise ValueError("Both _stuff and event contain an Exception/Failure.") + # `log.err('event', _why='alsoEvent')` is ambiguous. - if _why and isinstance(event, str): + if _why and isinstance(event, str): # type: ignore raise ValueError("Both `_why` and `event` supplied.") + # Two failures are ambiguous too. if not isinstance(_stuff, _FAIL_TYPES) and isinstance(event, _FAIL_TYPES): _why = _why or "error" _stuff = event + if isinstance(event, str): _why = event + if not _stuff and sys.exc_info() != (None, None, None): _stuff = Failure() + # Either we used the error ourselves or the user supplied one for # formatting. Avoid log.err() to dump another traceback into the log. if isinstance(_stuff, BaseException) and not isinstance(_stuff, Failure): @@ -122,10 +132,10 @@ class ReprWrapper: Note the extra quotes in the unwrapped example. """ - def __init__(self, string): + def __init__(self, string: str) -> None: self.string = string - def __eq__(self, other): + def __eq__(self, other: Any) -> bool: """ Check for equality, just for tests. """ @@ -133,7 +143,7 @@ def __eq__(self, other): isinstance(other, self.__class__) and self.string == other.string ) - def __repr__(self): + def __repr__(self) -> str: return self.string @@ -159,7 +169,12 @@ class JSONRenderer(GenericJSONRenderer): `plainJSONStdOutLogger` for pure-JSON logs. """ - def __call__(self, logger, name, eventDict): + def __call__( # type: ignore + self, + logger: WrappedLogger, + name: str, + eventDict: EventDict, + ) -> Tuple[Sequence[Any], Dict[str, Any]]: _stuff, _why, eventDict = _extractStuffAndWhy(eventDict) if name == "err": eventDict["event"] = _why @@ -187,16 +202,15 @@ class PlainFileLogObserver: runit. :param file: File to print to. - :type file: file object .. versionadded:: 0.2.0 """ - def __init__(self, file): + def __init__(self, file: TextIO) -> None: self._write = file.write self._flush = file.flush - def __call__(self, eventDict): + def __call__(self, eventDict: EventDict) -> None: until_not_interrupted(self._write, textFromEventDict(eventDict) + "\n") until_not_interrupted(self._flush) @@ -214,10 +228,10 @@ class JSONLogObserverWrapper: .. versionadded:: 0.2.0 """ - def __init__(self, observer): + def __init__(self, observer: Any) -> None: self._observer = observer - def __call__(self, eventDict): + def __call__(self, eventDict: EventDict) -> str: if "_structlog" not in eventDict: eventDict["message"] = ( json.dumps( @@ -228,10 +242,11 @@ def __call__(self, eventDict): ), ) eventDict["_structlog"] = True + return self._observer(eventDict) -def plainJSONStdOutLogger(): +def plainJSONStdOutLogger() -> JSONLogObserverWrapper: """ Return a logger that writes only the message to stdout. @@ -264,22 +279,28 @@ class EventAdapter: `_ behave as expected. - :param callable dictRenderer: Renderer that is used for the actual - log message. Please note that structlog comes with a dedicated - :class:`JSONRenderer`. + :param dictRenderer: Renderer that is used for the actual log message. + Please note that structlog comes with a dedicated `JSONRenderer`. **Must** be the last processor in the chain and requires a *dictRenderer* for the actual formatting as an constructor argument in order to be able to fully support the original behaviors of ``log.msg()`` and ``log.err()``. """ - def __init__(self, dictRenderer=None): + def __init__( + self, + dictRenderer: Optional[ + Callable[[WrappedLogger, str, EventDict], str] + ] = None, + ) -> None: """ :param dictRenderer: A processor used to format the log message. """ self._dictRenderer = dictRenderer or _BUILTIN_DEFAULT_PROCESSORS[-1] - def __call__(self, logger, name, eventDict): + def __call__( + self, logger: WrappedLogger, name: str, eventDict: EventDict + ) -> Any: if name == "err": # This aspires to handle the following cases correctly: # - log.err(failure, _why='event', **kw) @@ -287,6 +308,7 @@ def __call__(self, logger, name, eventDict): # - log.err(_stuff=failure, _why='event', **kw) _stuff, _why, eventDict = _extractStuffAndWhy(eventDict) eventDict["event"] = _why + return ( (), { diff --git a/src/structlog/types.py b/src/structlog/types.py new file mode 100644 index 00000000..914c129b --- /dev/null +++ b/src/structlog/types.py @@ -0,0 +1,106 @@ +""" +Type information used throughout ``structlog``. + +For now, they are considered provisional. Especially `BindableLogger` will +probably change to something more elegant. + +.. versionadded:: 20.2 +""" + +import sys + +from types import TracebackType +from typing import ( + Any, + Callable, + Dict, + Mapping, + MutableMapping, + Optional, + Tuple, + Type, + Union, +) + + +# This construct works better with mypy. +# Doing the obvious ImportError route leads to an 'Incompatible import of +# "Protocol"' error. +if sys.version_info >= (3, 8): + from typing import Protocol, runtime_checkable +else: + from typing_extensions import Protocol, runtime_checkable + + +WrappedLogger = Any +""" +A logger that is wrapped by a bound logger and is ultimately responsible for +the output of the log entries. + +``structlog`` makes *no* assumptions about it. + +.. versionadded:: 20.2 +""" + + +Context = Union[Dict[str, Any], Dict[Any, Any]] +""" +A dict-like context carrier. + +.. versionadded:: 20.2 +""" + + +EventDict = MutableMapping[str, Any] +""" +An event dictionary as it is passed into processors. + +It's created by copying the configured `Context` but doesn't need to support +copy itself. + +.. versionadded:: 20.2 +""" + +Processor = Callable[ + [WrappedLogger, str, EventDict], + Union[Mapping[str, Any], str, Tuple[Any, ...]], +] +""" +A callable that is part of the processor chain. + +See :doc:`processors`. + +.. versionadded:: 20.2 +""" + +ExcInfo = Tuple[Type[BaseException], BaseException, Optional[TracebackType]] +""" +An exception info tuple as returned by `sys.exc_info`. + +.. versionadded:: 20.2 +""" + + +@runtime_checkable +class BindableLogger(Protocol): + """ + Methods shared among all bound loggers and that are relied on by + ``structlog``. + + + .. versionadded:: 20.2 + """ + + _context: Context + + def bind(self, **new_values: Any) -> "BindableLogger": + ... + + def unbind(self, *keys: str) -> "BindableLogger": + ... + + def try_unbind(self, *keys: str) -> "BindableLogger": + ... + + def new(self, **new_values: Any) -> "BindableLogger": + ... diff --git a/tests/test_config.py b/tests/test_config.py index 4bcb1e3b..14c15049 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -107,6 +107,7 @@ def test_just_processors(self, proxy): x = stub() configure(processors=[x]) b = proxy.bind() + assert [x] == b._processors assert _BUILTIN_DEFAULT_PROCESSORS != b._processors assert _BUILTIN_DEFAULT_CONTEXT_CLASS == b._context.__class__ @@ -114,12 +115,15 @@ def test_just_processors(self, proxy): def test_just_context_class(self, proxy): configure(context_class=dict) b = proxy.bind() + assert dict is b._context.__class__ assert _BUILTIN_DEFAULT_PROCESSORS == b._processors def test_configure_sets_is_configured(self): assert False is _CONFIG.is_configured + configure() + assert True is _CONFIG.is_configured def test_configures_logger_factory(self): @@ -127,6 +131,7 @@ def f(): pass configure(logger_factory=f) + assert f is _CONFIG.logger_factory @@ -135,6 +140,9 @@ def teardown_method(self, method): structlog.reset_defaults() def test_repr(self): + """ + repr reflects all attributes. + """ p = BoundLoggerLazyProxy( None, processors=[1, 2, 3], @@ -151,12 +159,27 @@ def test_repr(self): ) == repr(p) def test_returns_bound_logger_on_bind(self, proxy): + """ + bind gets proxied to the wrapped bound logger. + """ assert isinstance(proxy.bind(), BoundLoggerBase) def test_returns_bound_logger_on_new(self, proxy): + """ + new gets proxied to the wrapped bound logger. + """ assert isinstance(proxy.new(), BoundLoggerBase) + def test_returns_bound_logger_on_try_unbind(self, proxy): + """ + try_unbind gets proxied to the wrapped bound logger. + """ + assert isinstance(proxy.try_unbind(), BoundLoggerBase) + def test_prefers_args_over_config(self): + """ + Configuration can be overridden by passing arguments. + """ p = BoundLoggerLazyProxy( None, processors=[1, 2, 3], context_class=dict ) @@ -173,46 +196,83 @@ def update(self, *args, **kw): configure(processors=[4, 5, 6], context_class=Class) b = p.bind() + assert not isinstance(b._context, Class) assert [1, 2, 3] == b._processors def test_falls_back_to_config(self, proxy): + """ + Configuration is used if no arguments are passed. + """ b = proxy.bind() + assert isinstance(b._context, _CONFIG.default_context_class) assert _CONFIG.default_processors == b._processors def test_bind_honors_initial_values(self): + """ + Passed initia_values are merged on binds. + """ p = BoundLoggerLazyProxy(None, initial_values={"a": 1, "b": 2}) b = p.bind() + assert {"a": 1, "b": 2} == b._context + b = p.bind(c=3) + assert {"a": 1, "b": 2, "c": 3} == b._context def test_bind_binds_new_values(self, proxy): + """ + Values passed to bind arrive in the context. + """ b = proxy.bind(c=3) + assert {"c": 3} == b._context def test_unbind_unbinds_from_initial_values(self): + """ + It's possible to unbind a value that came from initial_values. + """ p = BoundLoggerLazyProxy(None, initial_values={"a": 1, "b": 2}) b = p.unbind("a") + assert {"b": 2} == b._context def test_honors_wrapper_class(self): + """ + Passed wrapper_class is used. + """ p = BoundLoggerLazyProxy(None, wrapper_class=Wrapper) b = p.bind() + assert isinstance(b, Wrapper) def test_honors_wrapper_from_config(self, proxy): + """ + Configured wrapper_class is used if not overridden. + """ configure(wrapper_class=Wrapper) + b = proxy.bind() + assert isinstance(b, Wrapper) - def test_new_binds_only_initial_values_impolicit_ctx_class(self, proxy): + def test_new_binds_only_initial_values_implicit_ctx_class(self, proxy): + """ + new() doesn't clear initial_values if context_class comes from config. + """ proxy = BoundLoggerLazyProxy(None, initial_values={"a": 1, "b": 2}) + b = proxy.new(foo=42) + assert {"a": 1, "b": 2, "foo": 42} == b._context def test_new_binds_only_initial_values_explicit_ctx_class(self, proxy): + """ + new() doesn't clear initial_values if context_class is passed + explicitly.. + """ proxy = BoundLoggerLazyProxy( None, initial_values={"a": 1, "b": 2}, context_class=dict ) @@ -225,8 +285,10 @@ def test_rebinds_bind_method(self, proxy): cached. """ configure(cache_logger_on_first_use=True) + bind = proxy.bind proxy.bind() + assert bind != proxy.bind def test_does_not_cache_by_default(self, proxy): @@ -234,22 +296,26 @@ def test_does_not_cache_by_default(self, proxy): Proxy's bind method doesn't change by default. """ bind = proxy.bind - proxy.bind() - assert bind == proxy.bind - def test_argument_takes_precedence_over_configuration(self): - configure(cache_logger_on_first_use=True) - proxy = BoundLoggerLazyProxy(None, cache_logger_on_first_use=False) - bind = proxy.bind proxy.bind() + assert bind == proxy.bind - def test_argument_takes_precedence_over_configuration2(self): - configure(cache_logger_on_first_use=False) - proxy = BoundLoggerLazyProxy(None, cache_logger_on_first_use=True) + @pytest.mark.parametrize("cache", [True, False]) + def test_argument_takes_precedence_over_configuration(self, cache): + """ + Passing cache_logger_on_first_use as an argument overrides config. + """ + configure(cache_logger_on_first_use=cache) + + proxy = BoundLoggerLazyProxy(None, cache_logger_on_first_use=not cache) bind = proxy.bind proxy.bind() - assert bind != proxy.bind + + if cache: + assert bind == proxy.bind + else: + assert bind != proxy.bind def test_bind_doesnt_cache_logger(self): """ @@ -300,8 +366,12 @@ def teardown_method(self, method): structlog.reset_defaults() def test_wrap_passes_args(self): + """ + wrap_logger propagates all arguments to the wrapped bound logger. + """ logger = object() p = wrap_logger(logger, processors=[1, 2, 3], context_class=dict) + assert logger is p._logger assert [1, 2, 3] == p._processors assert dict is p._context_class @@ -317,20 +387,33 @@ def test_empty_processors(self): assert [] == logger._processors def test_wrap_returns_proxy(self): + """ + wrap_logger always returns a lazy proxy. + """ assert isinstance(wrap_logger(None), BoundLoggerLazyProxy) def test_configure_once_issues_warning_on_repeated_call(self): + """ + configure_once raises a warning when it's after configuration. + """ with warnings.catch_warnings(record=True) as warns: configure_once() + assert 0 == len(warns) + with warnings.catch_warnings(record=True) as warns: configure_once() + assert 1 == len(warns) assert RuntimeWarning == warns[0].category assert "Repeated configuration attempted." == warns[0].message.args[0] def test_get_logger_configures_according_to_config(self): + """ + get_logger returns a correctly configured bound logger. + """ b = get_logger().bind() + assert isinstance( b._logger, _BUILTIN_DEFAULT_LOGGER_FACTORY().__class__ ) @@ -345,5 +428,7 @@ def test_get_logger_passes_positional_arguments_to_logger_factory(self): """ factory = call_recorder(lambda *args: object()) configure(logger_factory=factory) + get_logger("test").bind(x=42) + assert [call("test")] == factory.calls diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 89f7eac1..ad2f5e05 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -12,7 +12,7 @@ from pretend import call_recorder -from structlog import ReturnLogger, configure, get_logger, reset_defaults +from structlog import ReturnLogger, configure, get_context, reset_defaults from structlog.dev import ConsoleRenderer from structlog.exceptions import DropEvent from structlog.processors import JSONRenderer @@ -29,6 +29,7 @@ add_log_level_number, add_logger_name, filter_by_level, + get_logger, render_to_log_kwargs, ) @@ -137,12 +138,19 @@ def test_positional_argument_avoids_guessing(self): class TestFilterByLevel: def test_filters_lower_levels(self): + """ + Log entries below the current level raise a DropEvent. + """ logger = logging.Logger(__name__) logger.setLevel(CRITICAL) + with pytest.raises(DropEvent): filter_by_level(logger, "warn", {}) def test_passes_higher_levels(self): + """ + Log entries with higher levels are passed through unchanged. + """ logger = logging.Logger(__name__) logger.setLevel(WARN) event_dict = {"event": "test"} @@ -278,6 +286,38 @@ def test_exception_exc_info_override(self): "event", exc_info=42 ) + def test_proxies_bind(self): + """ + Bind calls the correct bind. + """ + bl = build_bl().bind(a=42) + + assert {"a": 42} == get_context(bl) + + def test_proxies_new(self): + """ + Newcalls the correct new. + """ + bl = build_bl().bind(a=42).new(b=23) + + assert {"b": 23} == get_context(bl) + + def test_proxies_unbind(self): + """ + Unbind calls the correct unbind. + """ + bl = build_bl().bind(a=42).unbind("a") + + assert {} == get_context(bl) + + def test_proxies_try_unbind(self): + """ + try_unbind calls the correct try_unbind. + """ + bl = build_bl().bind(a=42).try_unbind("a", "b") + + assert {} == get_context(bl) + class TestPositionalArgumentsFormatter: def test_formats_tuple(self): diff --git a/tox.ini b/tox.ini index 847ad026..bdcee204 100644 --- a/tox.ini +++ b/tox.ini @@ -4,12 +4,12 @@ python = 3.6: py36 3.7: py37 3.8: py38, lint, docs - 3.9: py39, manifest + 3.9: py39, manifest, mypy pypy3: pypy3 [tox] -envlist = lint,{py36,py37,py38,py39,pypy3}-threads,{py38,py39,pypy3}-greenlets,py38-colorama,docs,pypi-description,manifest,coverage-report +envlist = lint,mypy,{py36,py37,py38,py39,pypy3}-threads,{py38,py39,pypy3}-greenlets,py38-colorama,docs,pypi-description,manifest,coverage-report isolated_build = True @@ -21,6 +21,14 @@ passenv = HOMEPATH # needed on Windows commands = pre-commit run --all-files +[testenv:mypy] +description = Check types +basepython = python3.9 +extras = tests +deps = mypy +commands = mypy src typing_examples.py + + [testenv] extras = tests deps = diff --git a/typing_examples.py b/typing_examples.py new file mode 100644 index 00000000..5bdd9d97 --- /dev/null +++ b/typing_examples.py @@ -0,0 +1,153 @@ +""" +Make sure our configuration examples actually pass the type checker. +""" + +import logging +import logging.config + +from typing import List + +import structlog + + +bl = structlog.get_logger() +bl.msg("hello", whom="world", x=42, y={}) + +bls: structlog.stdlib.BoundLogger = structlog.get_logger() +bls.info("hello", whom="world", x=42, y={}) + +structlog.configure( + processors=[ + structlog.stdlib.filter_by_level, + structlog.stdlib.add_logger_name, + structlog.stdlib.add_log_level, + structlog.stdlib.PositionalArgumentsFormatter(), + structlog.processors.StackInfoRenderer(), + structlog.processors.format_exc_info, + structlog.processors.UnicodeDecoder(), + structlog.stdlib.render_to_log_kwargs, + ], + context_class=dict, + logger_factory=structlog.stdlib.LoggerFactory(), + wrapper_class=structlog.stdlib.BoundLogger, + cache_logger_on_first_use=True, +) + +structlog.configure( + processors=[ + structlog.stdlib.ProcessorFormatter.wrap_for_formatter, + ], + logger_factory=structlog.stdlib.LoggerFactory(), +) + +formatter = structlog.stdlib.ProcessorFormatter( + processor=structlog.dev.ConsoleRenderer(), +) + +handler = logging.StreamHandler() +handler.setFormatter(formatter) +root_logger = logging.getLogger() +root_logger.addHandler(handler) +root_logger.setLevel(logging.INFO) + + +timestamper = structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S") +shared_processors: List[structlog.types.Processor] = [ + structlog.stdlib.add_log_level, + timestamper, +] + +structlog.configure( + processors=shared_processors + + [ + structlog.stdlib.ProcessorFormatter.wrap_for_formatter, + ], + logger_factory=structlog.stdlib.LoggerFactory(), + cache_logger_on_first_use=True, +) + +formatter = structlog.stdlib.ProcessorFormatter( + processor=structlog.dev.ConsoleRenderer(), + foreign_pre_chain=shared_processors, +) + + +timestamper = structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S") +pre_chain = [ + # Add the log level and a timestamp to the event_dict if the log entry + # is not from structlog. + structlog.stdlib.add_log_level, + timestamper, +] + +logging.config.dictConfig( + { + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "plain": { + "()": structlog.stdlib.ProcessorFormatter, + "processor": structlog.dev.ConsoleRenderer(colors=False), + "foreign_pre_chain": pre_chain, + }, + "colored": { + "()": structlog.stdlib.ProcessorFormatter, + "processor": structlog.dev.ConsoleRenderer(colors=True), + "foreign_pre_chain": pre_chain, + }, + }, + "handlers": { + "default": { + "level": "DEBUG", + "class": "logging.StreamHandler", + "formatter": "colored", + }, + "file": { + "level": "DEBUG", + "class": "logging.handlers.WatchedFileHandler", + "filename": "test.log", + "formatter": "plain", + }, + }, + "loggers": { + "": { + "handlers": ["default", "file"], + "level": "DEBUG", + "propagate": True, + }, + }, + } +) +structlog.configure( + processors=[ + structlog.stdlib.add_log_level, + structlog.stdlib.PositionalArgumentsFormatter(), + timestamper, + structlog.processors.StackInfoRenderer(), + structlog.processors.format_exc_info, + structlog.stdlib.ProcessorFormatter.wrap_for_formatter, + ], + context_class=dict, + logger_factory=structlog.stdlib.LoggerFactory(), + wrapper_class=structlog.stdlib.BoundLogger, + cache_logger_on_first_use=True, +) + + +structlog.configure( + processors=[ + structlog.stdlib.filter_by_level, + structlog.stdlib.add_logger_name, + structlog.stdlib.add_log_level, + structlog.stdlib.PositionalArgumentsFormatter(), + structlog.processors.TimeStamper(fmt="iso"), + structlog.processors.StackInfoRenderer(), + structlog.processors.format_exc_info, + structlog.processors.UnicodeDecoder(), + structlog.processors.JSONRenderer(), + ], + context_class=dict, + logger_factory=structlog.stdlib.LoggerFactory(), + wrapper_class=structlog.stdlib.BoundLogger, + cache_logger_on_first_use=True, +) From 1baf23f2d1232a8a997dbbf958983de80717f776 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 12 Nov 2020 12:22:46 +0100 Subject: [PATCH 0394/1520] Allow the final processor to return bytes too Necessary for #271. --- CHANGELOG.rst | 1 + src/structlog/_base.py | 8 ++++---- src/structlog/processors.py | 21 ++++++++++++++++++--- src/structlog/twisted.py | 4 +++- src/structlog/types.py | 2 +- tests/test_base.py | 15 +++++++++++++++ typing_examples.py | 20 +++++++++++++++++++- 7 files changed, 61 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5f02d54e..0f07f0fe 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -40,6 +40,7 @@ Changes: - Added ``structlog.BytesLogger`` to avoid unnecessary encoding round trips. Concretely this is useful with *orjson* which returns bytes. `#271 `_ +- The final processor now also may return bytes that are passed untouched to the wrapped logger. - ``structlog`` has now type hints for all of its APIs! Since ``structlog`` is highly dynamic and configurable, this led to a few concessions like a specialized ``structlog.stdlib.get_logger()`` whose only difference to ``structlog.get_logger()`` is that it has the correct type hints. diff --git a/src/structlog/_base.py b/src/structlog/_base.py index 3ad0252f..e59078a9 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -153,7 +153,7 @@ def _process_event( for proc in self._processors: event_dict = proc(self._logger, method_name, event_dict) - if isinstance(event_dict, str): + if isinstance(event_dict, (str, bytes)): return (event_dict,), {} elif isinstance(event_dict, tuple): # In this case we assume that the last processor returned a tuple @@ -163,9 +163,9 @@ def _process_event( return (), event_dict else: raise ValueError( - "Last processor didn't return an appropriate value. Allowed " - "return values are a dict, a tuple of (args, kwargs), or a " - "string." + "Last processor didn't return an appropriate value. Valid " + "return values are a dict, a tuple of (args, kwargs), bytes, " + "or a str." ) def _proxy_to_logger( diff --git a/src/structlog/processors.py b/src/structlog/processors.py index d17c9900..228c05cc 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -11,7 +11,17 @@ import sys import time -from typing import Any, Callable, Dict, List, Optional, Sequence, TextIO, Tuple +from typing import ( + Any, + Callable, + Dict, + List, + Optional, + Sequence, + TextIO, + Tuple, + Union, +) from ._frames import ( _find_first_app_frame_and_name, @@ -199,7 +209,9 @@ class JSONRenderer: """ def __init__( - self, serializer: Callable[..., str] = json.dumps, **dumps_kw: Any + self, + serializer: Callable[..., Union[str, bytes]] = json.dumps, + **dumps_kw: Any ) -> None: dumps_kw.setdefault("default", _json_fallback_handler) self._dumps_kw = dumps_kw @@ -207,7 +219,10 @@ def __init__( def __call__( self, logger: WrappedLogger, name: str, event_dict: EventDict - ) -> str: + ) -> Union[str, bytes]: + """ + The return type of this depends on the return type of self._dumps. + """ return self._dumps(event_dict, **self._dumps_kw) diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index d43d1e25..9edfea54 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -186,7 +186,9 @@ def __call__( # type: ignore return ( ( ReprWrapper( - GenericJSONRenderer.__call__(self, logger, name, eventDict) + GenericJSONRenderer.__call__( # type: ignore + self, logger, name, eventDict + ) ), ), {"_structlog": True}, diff --git a/src/structlog/types.py b/src/structlog/types.py index 914c129b..a53d78ac 100644 --- a/src/structlog/types.py +++ b/src/structlog/types.py @@ -63,7 +63,7 @@ Processor = Callable[ [WrappedLogger, str, EventDict], - Union[Mapping[str, Any], str, Tuple[Any, ...]], + Union[Mapping[str, Any], str, bytes, Tuple[Any, ...]], ] """ A callable that is part of the processor chain. diff --git a/tests/test_base.py b/tests/test_base.py index 5110d7e8..4021a3e7 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -157,7 +157,12 @@ def chk(_, __, event_dict): assert "event" not in b._context def test_chain_does_not_swallow_all_exceptions(self): + """ + If the chain raises anything else than DropEvent, the error is not + swallowed. + """ b = build_bl(processors=[raiser(ValueError)]) + with pytest.raises(ValueError): b._process_event("", "boom", {}) @@ -171,6 +176,16 @@ def test_last_processor_returns_string(self): assert (("foo",), {}) == b._process_event("", "foo", {}) + def test_last_processor_returns_bytes(self): + """ + If the final processor returns bytes, ``(the_bytes,), {}`` is + returned. + """ + logger = stub(msg=lambda *args, **kw: (args, kw)) + b = build_bl(logger, processors=[lambda *_: b"foo"]) + + assert ((b"foo",), {}) == b._process_event(None, "name", {}) + def test_last_processor_returns_tuple(self): """ If the final processor returns a tuple, it is just passed through. diff --git a/typing_examples.py b/typing_examples.py index 5bdd9d97..27f0f51e 100644 --- a/typing_examples.py +++ b/typing_examples.py @@ -5,7 +5,7 @@ import logging import logging.config -from typing import List +from typing import Any, Callable, List, Optional import structlog @@ -16,6 +16,24 @@ bls: structlog.stdlib.BoundLogger = structlog.get_logger() bls.info("hello", whom="world", x=42, y={}) + +def bytes_dumps( + __obj: Any, + default: Optional[Callable[[Any], Any]] = None, + option: Optional[int] = None, +) -> bytes: + """ + Test with orjson's signature taken from + . + """ + return b"{}" + + +structlog.configure( + processors=[structlog.processors.JSONRenderer(serializer=bytes_dumps)] +) + + structlog.configure( processors=[ structlog.stdlib.filter_by_level, From cdda888c002099fee8a360d059f43d1e4b080022 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 12 Nov 2020 12:23:25 +0100 Subject: [PATCH 0395/1520] Rely on pre-commit.ci for linting --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index bdcee204..efaba620 100644 --- a/tox.ini +++ b/tox.ini @@ -3,7 +3,7 @@ python = 3.6: py36 3.7: py37 - 3.8: py38, lint, docs + 3.8: py38, docs 3.9: py39, manifest, mypy pypy3: pypy3 From 4c1e77ddc88dd737ae024f1e3256cde93cb02404 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 12 Nov 2020 13:07:06 +0100 Subject: [PATCH 0396/1520] Add bytes string to docs --- docs/processors.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/processors.rst b/docs/processors.rst index e7179ce3..db738bf6 100644 --- a/docs/processors.rst +++ b/docs/processors.rst @@ -95,7 +95,7 @@ With that, it's also the *only* processor that needs to know anything about the It can return one of three types: -- A string that is passed as the first (and only) positional argument to the underlying logger. +- An Unicode string or a bytes string (i.e. `str` or `bytes`) that is passed as the first (and only) positional argument to the underlying logger. - A tuple of ``(args, kwargs)`` that are passed as ``log_method(*args, **kwargs)``. - A dictionary which is passed as ``log_method(**kwargs)``. From 6d47225126b8c9c1b7495cd0d107498523051bcb Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 12 Nov 2020 14:46:21 +0100 Subject: [PATCH 0397/1520] Properly capitalize Mypy As they do in their project docs. --- CHANGELOG.rst | 2 +- docs/standard-library.rst | 2 +- docs/types.rst | 2 +- src/structlog/_config.py | 2 +- src/structlog/types.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0f07f0fe..1e94ce2e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -17,7 +17,7 @@ Backward-incompatible changes: `#244 `_ - ``structlog`` is now fully type-annotated. - This won't break your applications but if you use mypy, it will most likely break your CI. + This won't break your applications but if you use Mypy, it will most likely break your CI. Check out the new chapter on typing for details. diff --git a/docs/standard-library.rst b/docs/standard-library.rst index b1899bf2..6401ec9e 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -43,7 +43,7 @@ It behaves exactly like the generic `structlog.BoundLogger` except: ---- -If you're using static types (e.g. with mypy) you also may want to use `structlog.stdlib.get_logger()` that has the appropriate type hints if you're using `structlog.stdlib.BoundLogger`. +If you're using static types (e.g. with Mypy) you also may want to use `structlog.stdlib.get_logger()` that has the appropriate type hints if you're using `structlog.stdlib.BoundLogger`. Please note though, that it will neither configure nor verify your configuration. It will call `structlog.get_logger()` just like if you would've called it -- the only difference are the type hints. diff --git a/docs/types.rst b/docs/types.rst index 83b22890..a7db5e41 100644 --- a/docs/types.rst +++ b/docs/types.rst @@ -35,7 +35,7 @@ The chosen solution is adding `structlog.stdlib.get_logger()` that just calls `s logger: structlog.stdlib.BoundLogger = structlog.get_logger() logger.info("hi") # <- ok - logger.msg("hi") # <- mypy: 'error: "BoundLogger" has no attribute "msg"' + logger.msg("hi") # <- Mypy: 'error: "BoundLogger" has no attribute "msg"' ---- diff --git a/src/structlog/_config.py b/src/structlog/_config.py index eee8b3e6..7b99c4b4 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -333,7 +333,7 @@ def bind(self, **new_values: Any) -> BindableLogger: cls = self._wrapper_class or _CONFIG.default_wrapper_class # Looks like Protocols ignore definitions of __init__ so we have to - # silence mypy here. + # silence Mypy here. logger = cls(_logger, processors=procs, context=ctx) # type: ignore def finalized_bind(**new_values: Any) -> BindableLogger: diff --git a/src/structlog/types.py b/src/structlog/types.py index a53d78ac..fc817b2c 100644 --- a/src/structlog/types.py +++ b/src/structlog/types.py @@ -23,7 +23,7 @@ ) -# This construct works better with mypy. +# This construct works better with Mypy. # Doing the obvious ImportError route leads to an 'Incompatible import of # "Protocol"' error. if sys.version_info >= (3, 8): From 58f5e988e9e766a1b7241d37aceebdb65ddb6554 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 12 Nov 2020 17:23:00 +0100 Subject: [PATCH 0398/1520] Fix docstring --- src/structlog/_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/_base.py b/src/structlog/_base.py index e59078a9..319d1121 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -130,7 +130,7 @@ def _process_event( :raises: `structlog.DropEvent` if log entry should be dropped. :raises: `ValueError` if the final processor doesn't return a - string, tuple, or a dict. + str, bytes, tuple, or a dict. :returns: `tuple` of ``(*args, **kw)`` From 30d14a4cd236cc7329a7c311bb7a3882a8eee8fc Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 13 Nov 2020 05:56:08 +0100 Subject: [PATCH 0399/1520] Add narrative link to API docs --- src/structlog/_base.py | 1 + src/structlog/_config.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/structlog/_base.py b/src/structlog/_base.py index 319d1121..ec6a2a8f 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -5,6 +5,7 @@ """ Logger wrapper and helper class. """ + from typing import Any, Dict, Iterable, Mapping, Optional, Sequence, Tuple from structlog.exceptions import DropEvent diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 7b99c4b4..dd97a151 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -200,7 +200,7 @@ def configure( Use `reset_defaults` to undo your changes. - :param processors: The processor chain. + :param processors: The processor chain. See :doc:`processors` for details. :param wrapper_class: Class to use for wrapping loggers instead of `structlog.BoundLogger`. See `standard-library`, :doc:`twisted`, and `custom-wrappers`. From 276ff8ccfe007c10e6cc546af9497723ec294f14 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 13 Nov 2020 10:17:36 +0100 Subject: [PATCH 0400/1520] Add LevelFilter (#283) * Add LevelFilter Fixes #273 * Add PR# --- .gitignore | 13 +++++----- CHANGELOG.rst | 20 ++++++++------- MANIFEST.in | 1 + conftest.py | 2 +- docs/api.rst | 2 ++ docs/processors.rst | 6 +++++ src/structlog/_log_levels.py | 30 ++++++++++++++++++++++ src/structlog/processors.py | 48 ++++++++++++++++++++++++++++++++++++ src/structlog/stdlib.py | 37 ++++++--------------------- tests/test_processors.py | 39 +++++++++++++++++++++++++++++ tests/test_stdlib.py | 4 +-- tests/utils.py | 2 +- 12 files changed, 155 insertions(+), 49 deletions(-) create mode 100644 src/structlog/_log_levels.py diff --git a/.gitignore b/.gitignore index 3389b0b0..e2dfc7bb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,11 @@ +*.egg-info +*.pyc +.cache .coverage* +.mypy_cache +.pytest_cache .tox -structlog.egg-info -htmlcov dist docs/_build -*.pyc -.cache -.pytest_cache/ -pip-wheel-metadata/ +htmlcov +pip-wheel-metadata diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1e94ce2e..618e9039 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -32,15 +32,6 @@ Deprecations: Changes: ^^^^^^^^ -- ``structlog.get_context()`` allows you to retrieve the original context of a bound logger. - `#266 `_, -- ``structlog.PrintLogger`` now supports ``copy.deepcopy()``. - `#268 `_ -- ``structlog.stdlib.ProcessorFormatter`` no longer uses exceptions for control flow, allowing ``foreign_pre_chain`` processors to use ``sys.exc_info()`` to access the real exception. -- Added ``structlog.BytesLogger`` to avoid unnecessary encoding round trips. - Concretely this is useful with *orjson* which returns bytes. - `#271 `_ -- The final processor now also may return bytes that are passed untouched to the wrapped logger. - ``structlog`` has now type hints for all of its APIs! Since ``structlog`` is highly dynamic and configurable, this led to a few concessions like a specialized ``structlog.stdlib.get_logger()`` whose only difference to ``structlog.get_logger()`` is that it has the correct type hints. @@ -48,6 +39,17 @@ Changes: Please feel free to provide feedback! `#223 `_, `#282 `_ +- Added ``structlog.processors.LevelFilter`` that can filter log entries based on the names of the log methods (and uses the same order as standard library's logging). + `#283 `_ +- ``structlog.stdlib.ProcessorFormatter`` no longer uses exceptions for control flow, allowing ``foreign_pre_chain`` processors to use ``sys.exc_info()`` to access the real exception. +- Added ``structlog.BytesLogger`` to avoid unnecessary encoding round trips. + Concretely this is useful with *orjson* which returns bytes. + `#271 `_ +- The final processor now also may return bytes that are passed untouched to the wrapped logger. +- ``structlog.get_context()`` allows you to retrieve the original context of a bound logger. + `#266 `_, +- ``structlog.PrintLogger`` now supports ``copy.deepcopy()``. + `#268 `_ ---- diff --git a/MANIFEST.in b/MANIFEST.in index a7781d28..968608e2 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -9,3 +9,4 @@ recursive-exclude tests *.pyc graft docs prune docs/_build +prune tests/.mypy_cache diff --git a/conftest.py b/conftest.py index e4767b2f..ca862f95 100644 --- a/conftest.py +++ b/conftest.py @@ -9,7 +9,7 @@ import pytest -from structlog.stdlib import _NAME_TO_LEVEL +from structlog._log_levels import _NAME_TO_LEVEL try: diff --git a/docs/api.rst b/docs/api.rst index 5c57b9cc..64553339 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -176,6 +176,8 @@ API Reference 'b=[1, 2, 3] a=42' +.. autoclass:: LevelFilter + .. autoclass:: UnicodeDecoder .. autoclass:: UnicodeEncoder diff --git a/docs/processors.rst b/docs/processors.rst index db738bf6..2315a29c 100644 --- a/docs/processors.rst +++ b/docs/processors.rst @@ -85,6 +85,12 @@ How about dropping only log entries that are marked as coming from a certain pee :language: python +Since it's so common to filter by the log level, ``structlog`` comes with `structlog.processors.LevelFilter`. +It does **not** use the standard library, but it does use its names and order of log levels. +In practice, it only looks up the numeric value of the method name and compares it to the configured minimal level. +That's fast and usually good enough for applications. + + .. _adapting: Adapting and Rendering diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py new file mode 100644 index 00000000..e9392336 --- /dev/null +++ b/src/structlog/_log_levels.py @@ -0,0 +1,30 @@ +""" +Extracted log level data used by both stdlib and native log level filters. +""" + +# Adapted from the stdlib +CRITICAL = 50 +FATAL = CRITICAL +ERROR = 40 +WARNING = 30 +WARN = WARNING +INFO = 20 +DEBUG = 10 +NOTSET = 0 + +_NAME_TO_LEVEL = { + "critical": CRITICAL, + "exception": ERROR, + "error": ERROR, + "warn": WARNING, + "warning": WARNING, + "info": INFO, + "debug": DEBUG, + "notset": NOTSET, +} + +_LEVEL_TO_NAME = { + v: k + for k, v in _NAME_TO_LEVEL.items() + if k not in ("warn", "exception", "notset") +} diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 228c05cc..049fe5ce 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -23,11 +23,13 @@ Union, ) +from ._base import DropEvent from ._frames import ( _find_first_app_frame_and_name, _format_exception, _format_stack, ) +from ._log_levels import _NAME_TO_LEVEL from .types import EventDict, ExcInfo, WrappedLogger @@ -437,3 +439,49 @@ def __call__( ) return event_dict + + +class LevelFilter: + """ + A framework-agnostic level filter. + + Uses standard library's order of levels, but relies solely on the *names* + of the levels. If a log entry doesn't have the minimum log level, + `DropEvent` is raised. + + This means that you can use it along with any `BindableLogger`, as long as + the levels have the same names. + + :param min_level: The minimal level a log entry has to have to be not + dropped. You can pass either an integer or a level string. Check out + the `logging docs + `_ for possible + values. + :param pass_unknown: If True and `LevelFilter` encounters an unknown level + name (i.e. log method name), the log entry is passed through. If False, + it's dropped. + + .. versionadded:: 20.2.0 + """ + + min_level: int + unknown_default: int + + def __init__(self, min_level: Union[str, int], pass_unknown: bool) -> None: + if isinstance(min_level, str): + min_level = _NAME_TO_LEVEL[min_level.lower()] + + self.min_level = min_level + + if pass_unknown: + self.unknown_default = 10000 + else: + self.unknown_default = -1 + + def __call__( + self, logger: WrappedLogger, name: str, event_dict: EventDict + ) -> EventDict: + if _NAME_TO_LEVEL.get(name, self.unknown_default) < self.min_level: + raise DropEvent + + return event_dict diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 069c3248..cc137100 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -15,6 +15,7 @@ from ._base import BoundLoggerBase from ._config import get_logger as _generic_get_logger from ._frames import _find_first_app_frame_and_name, _format_stack +from ._log_levels import _LEVEL_TO_NAME, _NAME_TO_LEVEL from .exceptions import DropEvent from .types import EventDict, ExcInfo, Processor, WrappedLogger @@ -411,34 +412,6 @@ def __call__( return event_dict -# Adapted from the stdlib -CRITICAL = 50 -FATAL = CRITICAL -ERROR = 40 -WARNING = 30 -WARN = WARNING -INFO = 20 -DEBUG = 10 -NOTSET = 0 - -_NAME_TO_LEVEL = { - "critical": CRITICAL, - "exception": ERROR, - "error": ERROR, - "warn": WARNING, - "warning": WARNING, - "info": INFO, - "debug": DEBUG, - "notset": NOTSET, -} - -_LEVEL_TO_NAME = { - v: k - for k, v in _NAME_TO_LEVEL.items() - if k not in ("warn", "exception", "notset") -} - - def filter_by_level( logger: logging.Logger, method_name: str, event_dict: EventDict ) -> EventDict: @@ -471,6 +444,11 @@ def add_log_level( ) -> EventDict: """ Add the log level to the event dict. + + Since that's just the log method name, this processor works with non-stdlib + logging as well. + + .. versionadded:: 15.0.0 """ if method_name == "warn": # The stdlib has an alias @@ -494,7 +472,8 @@ def add_log_level_number( level in ("warning", "error", "critical") level_number >= 30 - The mapping of names to numbers is in ``structlog.stdlib._NAME_TO_LEVEL``. + The mapping of names to numbers is in + ``structlog.stdlib._log_levels._NAME_TO_LEVEL``. .. versionadded:: 18.2.0 """ diff --git a/tests/test_processors.py b/tests/test_processors.py index f8a8f648..4021c3fc 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -18,6 +18,7 @@ ExceptionPrettyPrinter, JSONRenderer, KeyValueRenderer, + LevelFilter, StackInfoRenderer, TimeStamper, UnicodeDecoder, @@ -538,3 +539,41 @@ def test_py3_exception_no_traceback(self): e = ValueError() assert (e.__class__, e, None) == _figure_out_exc_info(e) + + +class TestLevelFilter: + @pytest.mark.parametrize("min_level", ["notset", 0, "nOtSeT"]) + def test_passes(self, min_level): + """ + If the log level is higher than the configured one, pass it through. + """ + lf = LevelFilter(min_level, pass_unknown=False) + + assert {"foo": 42} == lf(None, "debug", {"foo": 42}) + + @pytest.mark.parametrize("min_level", ["info", 20, "iNfO"]) + def test_drop(self, min_level): + """ + If the log level is less than the configured one, raise DropEvent. + """ + lf = LevelFilter(min_level, pass_unknown=False) + + with pytest.raises(structlog.DropEvent): + lf(None, "debug", {"foo": 42}) + + def test_pass_unknown(self): + """ + If pass_unknown is True, unknown log levels always pass. + """ + lf = LevelFilter(0, pass_unknown=True) + + assert {"foo": 42} == lf(None, "unknown", {"foo": 42}) + + def test_drop_unknown(self): + """ + If pass_unknown is False, unknown log levels always raise DropEvent. + """ + lf = LevelFilter(0, pass_unknown=False) + + with pytest.raises(structlog.DropEvent): + lf(None, "unknown", {"foo": 42}) diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index ad2f5e05..ac9c1914 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -13,13 +13,11 @@ from pretend import call_recorder from structlog import ReturnLogger, configure, get_context, reset_defaults +from structlog._log_levels import _NAME_TO_LEVEL, CRITICAL, WARN from structlog.dev import ConsoleRenderer from structlog.exceptions import DropEvent from structlog.processors import JSONRenderer from structlog.stdlib import ( - _NAME_TO_LEVEL, - CRITICAL, - WARN, BoundLogger, LoggerFactory, PositionalArgumentsFormatter, diff --git a/tests/utils.py b/tests/utils.py index 7f3cf50f..a1157f4c 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -6,7 +6,7 @@ Shared test utilities. """ -from structlog.stdlib import _NAME_TO_LEVEL +from structlog._log_levels import _NAME_TO_LEVEL stdlib_log_methods = [m for m in _NAME_TO_LEVEL if m != "notset"] From 181e45745c8cecf45db27d382e7863b6b2753f4c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 13 Nov 2020 10:59:52 +0100 Subject: [PATCH 0401/1520] Make add_log_level importable from processors And add it to default config. Fixes #154 --- CHANGELOG.rst | 2 ++ docs/api.rst | 2 ++ docs/getting-started.rst | 1 + docs/standard-library.rst | 4 ++-- src/structlog/_config.py | 8 +++++++- src/structlog/_log_levels.py | 28 ++++++++++++++++++++++++++++ src/structlog/dev.py | 2 +- src/structlog/processors.py | 16 +++++++++++++++- src/structlog/stdlib.py | 36 +++++++++++++++--------------------- 9 files changed, 73 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 618e9039..a702a435 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -41,6 +41,8 @@ Changes: `#282 `_ - Added ``structlog.processors.LevelFilter`` that can filter log entries based on the names of the log methods (and uses the same order as standard library's logging). `#283 `_ +- As a complement, ``structlog.stdlib.add_log_level()`` can now also be imported as ``structlog.processors.add_log_level`` since it just adds the method name to the event dict. +- ``structlog.processors.add_log_level()`` is now part of the default configuration. - ``structlog.stdlib.ProcessorFormatter`` no longer uses exceptions for control flow, allowing ``foreign_pre_chain`` processors to use ``sys.exc_info()`` to access the real exception. - Added ``structlog.BytesLogger`` to avoid unnecessary encoding round trips. Concretely this is useful with *orjson* which returns bytes. diff --git a/docs/api.rst b/docs/api.rst index 64553339..eb181431 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -178,6 +178,8 @@ API Reference .. autoclass:: LevelFilter +.. autofunction:: add_log_level + .. autoclass:: UnicodeDecoder .. autoclass:: UnicodeEncoder diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 9171f146..9a3896ab 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -42,6 +42,7 @@ Using the defaults, as above, is equivalent to:: import structlog structlog.configure( processors=[ + structlog.processors.add_log_level, structlog.processors.StackInfoRenderer(), structlog.dev.set_exc_info, structlog.processors.format_exc_info, diff --git a/docs/standard-library.rst b/docs/standard-library.rst index 6401ec9e..69f16f33 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -65,7 +65,7 @@ Processors `add_logger_name`: Adds the name of the logger to the event dictionary under the key ``logger``. -`add_log_level`: +:func:`~structlog.stdlib.add_log_level`: Adds the log level to the event dictionary under the key ``level``. `add_log_level_number`: @@ -297,7 +297,7 @@ For example, to use the standard library's `logging.config.dictConfig` to log co This defines two formatters: one plain and one colored. Both are run for each log entry. -Log entries that do not originate from ``structlog``, are additionally pre-processed using a cached ``timestamper`` and `add_log_level`. +Log entries that do not originate from ``structlog``, are additionally pre-processed using a cached ``timestamper`` and :func:`~structlog.stdlib.add_log_level`. .. code-block:: pycon diff --git a/src/structlog/_config.py b/src/structlog/_config.py index dd97a151..1962d331 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -24,7 +24,12 @@ from ._generic import BoundLogger from ._loggers import PrintLoggerFactory from .dev import ConsoleRenderer, _has_colorama, set_exc_info -from .processors import StackInfoRenderer, TimeStamper, format_exc_info +from .processors import ( + StackInfoRenderer, + TimeStamper, + add_log_level, + format_exc_info, +) from .types import BindableLogger, Context, Processor, WrappedLogger @@ -34,6 +39,7 @@ Any changes to these defaults must be reflected in `getting-started`. """ _BUILTIN_DEFAULT_PROCESSORS: Sequence[Processor] = [ + add_log_level, StackInfoRenderer(), set_exc_info, format_exc_info, diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index e9392336..a6d5376b 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -1,6 +1,10 @@ """ Extracted log level data used by both stdlib and native log level filters. """ +import logging + +from .types import EventDict + # Adapted from the stdlib CRITICAL = 50 @@ -28,3 +32,27 @@ for k, v in _NAME_TO_LEVEL.items() if k not in ("warn", "exception", "notset") } + + +def add_log_level( + logger: logging.Logger, method_name: str, event_dict: EventDict +) -> EventDict: + """ + Add the log level to the event dict under the ``level`` key. + + Since that's just the log method name, this processor works with non-stdlib + logging as well. Therefore it's importable both from `structlog.processors` + as well as from `structlog.stdlib`. + + .. versionadded:: 15.0.0 + .. versionchanged:: 20.2.0 + Importable from `structlog.processors` (additionally to + `structlog.stdlib`). + """ + if method_name == "warn": + # The stdlib has an alias + method_name = "warning" + + event_dict["level"] = method_name + + return event_dict diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 42e1ca09..8011fd34 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -236,7 +236,7 @@ def __call__( if level is not None: sio.write( "[" - + self._level_to_color[level] + + self._level_to_color.get(level, "") + _pad(level, self._longest_level) + self._styles.reset + "] " diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 049fe5ce..220a60a0 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -29,10 +29,24 @@ _format_exception, _format_stack, ) -from ._log_levels import _NAME_TO_LEVEL +from ._log_levels import _NAME_TO_LEVEL, add_log_level from .types import EventDict, ExcInfo, WrappedLogger +__all__ = [ + "KeyValueRenderer", + "TimeStamper", + "add_log_level", + "UnicodeEncoder", + "UnicodeDecoder", + "JSONRenderer", + "format_exc_info", + "ExceptionPrettyPrinter", + "StackInfoRenderer", + "LevelFilter", +] + + class KeyValueRenderer: """ Render ``event_dict`` as a list of ``Key=repr(Value)`` pairs. diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index cc137100..7bb1f027 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -15,11 +15,25 @@ from ._base import BoundLoggerBase from ._config import get_logger as _generic_get_logger from ._frames import _find_first_app_frame_and_name, _format_stack -from ._log_levels import _LEVEL_TO_NAME, _NAME_TO_LEVEL +from ._log_levels import _LEVEL_TO_NAME, _NAME_TO_LEVEL, add_log_level from .exceptions import DropEvent from .types import EventDict, ExcInfo, Processor, WrappedLogger +__all__ = [ + "BoundLogger", + "get_logger", + "LoggerFactory", + "PositionalArgumentsFormatter", + "filter_by_level", + "add_log_level_number", + "add_log_level", + "add_logger_name", + "render_to_log_kwargs", + "ProcessorFormatter", +] + + _SENTINEL = object() @@ -439,26 +453,6 @@ def filter_by_level( raise DropEvent -def add_log_level( - logger: logging.Logger, method_name: str, event_dict: EventDict -) -> EventDict: - """ - Add the log level to the event dict. - - Since that's just the log method name, this processor works with non-stdlib - logging as well. - - .. versionadded:: 15.0.0 - """ - if method_name == "warn": - # The stdlib has an alias - method_name = "warning" - - event_dict["level"] = method_name - - return event_dict - - def add_log_level_number( logger: logging.Logger, method_name: str, event_dict: EventDict ) -> EventDict: From 44e0b2a0c5d88a76f31e94609c2aa7543a18ec9a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 13 Nov 2020 11:12:42 +0100 Subject: [PATCH 0402/1520] Add more clarifications for LevelFilter --- src/structlog/processors.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 220a60a0..8c037bd8 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -466,6 +466,17 @@ class LevelFilter: This means that you can use it along with any `BindableLogger`, as long as the levels have the same names. + Since ``logging.INFO`` et al are just (undocumented) int constants, you can + use them too, regardless whether you use stdlib logging or not: + + .. code:: + + LevelFilter(logging.INFO, False) + + will leave through log entries with log level INFO or higher (i.e. the log + method's name is ``info``, or ``warn``, ...) and works both with standard + library's `logging` as well as without. + :param min_level: The minimal level a log entry has to have to be not dropped. You can pass either an integer or a level string. Check out the `logging docs From 924f21fcc5dbfd68252e4901ab7125b4af581656 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 16 Nov 2020 08:25:13 +0100 Subject: [PATCH 0403/1520] Simplify docs/conf.py --- docs/conf.py | 177 +-------------------------------------------------- 1 file changed, 1 insertion(+), 176 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 54619d99..2d8483c4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -44,9 +44,6 @@ def find_version(*file_paths): # The suffix of source filenames. source_suffix = ".rst" -# The encoding of source files. -# source_encoding = 'utf-8-sig' - # The master toctree document. master_doc = "index" @@ -63,19 +60,6 @@ def find_version(*file_paths): version = find_version("..", "src", "structlog", "__init__.py") # The full version, including alpha/beta/rc tags. release = "" - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -# today = '' -# Else, today_fmt is used as the format for a strftime call. -# today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. exclude_patterns = ["_build"] # The reST default role (used for this markup: `text`) to use for all @@ -93,22 +77,15 @@ def find_version(*file_paths): ] # If true, '()' will be appended to :func: etc. cross-reference text. -# add_function_parentheses = True +add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). # add_module_names = True -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -# show_authors = False - # The name of the Pygments (syntax highlighting) style to use. pygments_style = "sphinx" -# A list of ignored prefixes for module index sorting. -# modindex_common_prefix = [] - # -- Options for HTML output -------------------------------------------------- @@ -117,129 +94,19 @@ def find_version(*file_paths): html_theme = "furo" html_theme_options = {} html_logo = "_static/structlog_logo_small_transparent.png" - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -# html_theme_path = ['_themes'] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -# html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -# html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -# html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -# html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ["_static"] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -# html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -# html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -# html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -# html_additional_pages = {} - -# If false, no module index is generated. -# html_domain_indices = True - -# If false, no index is generated. -# html_use_index = True - -# If true, the index is split into individual pages for each letter. -# html_split_index = False - -# If true, links to the reST sources are added to the pages. -# html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -# html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -# html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -# html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -# html_file_suffix = None - -# Output file base name for HTML help builder. htmlhelp_basename = "structlogdoc" - -# -- Options for LaTeX output ------------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). - # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. - # 'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass -# [howto/manual]). latex_documents = [ ("index", "structlog.tex", "structlog Documentation", "Author", "manual") ] -# The name of an image file (relative to this directory) to place at the top of -# the title page. -# latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -# latex_use_parts = False - -# If true, show page references after internal links. -# latex_show_pagerefs = False - -# If true, show URL addresses after external links. -# latex_show_urls = False - -# Documents to append as an appendix to all manuals. -# latex_appendices = [] - -# If false, no module index is generated. -# latex_domain_indices = True - - # -- Options for manual page output ------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [("index", "structlog", "structlog Documentation", ["Author"], 1)] -# If true, show URL addresses after external links. -# man_show_urls = False - # -- Options for Texinfo output ----------------------------------------------- @@ -258,15 +125,6 @@ def find_version(*file_paths): ) ] -# Documents to append as an appendix to all manuals. -# texinfo_appendices = [] - -# If false, no module index is generated. -# texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -# texinfo_show_urls = 'footnote' - # -- Options for Epub output -------------------------------------------------- @@ -276,39 +134,6 @@ def find_version(*file_paths): epub_publisher = author epub_copyright = copyright -# The language of the text. It defaults to the language option -# or en if the language is not set. -# epub_language = '' - -# The scheme of the identifier. Typical schemes are ISBN or URL. -# epub_scheme = '' - -# The unique identifier of the text. This can be a ISBN number -# or the project homepage. -# epub_identifier = '' - -# A unique identification for the text. -# epub_uid = '' - -# A tuple containing the cover image and cover page html template filenames. -# epub_cover = () - -# HTML files that should be inserted before the pages created by sphinx. -# The format is a list of tuples containing the path and title. -# epub_pre_files = [] - -# HTML files shat should be inserted after the pages created by sphinx. -# The format is a list of tuples containing the path and title. -# epub_post_files = [] - -# A list of files that should not be packed into the epub file. -# epub_exclude_files = [] - -# The depth of the table of contents in toc.ncx. -# epub_tocdepth = 3 - -# Allow duplicate toc entries. -# epub_tocdup = True linkcheck_ignore = [] From 4e9c647f41d45efa263189c50503798846c20e43 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 18 Nov 2020 09:06:50 +0100 Subject: [PATCH 0404/1520] Add basic opengraph metadata --- docs/conf.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/conf.py b/docs/conf.py index 2d8483c4..87e58575 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -97,6 +97,17 @@ def find_version(*file_paths): html_static_path = ["_static"] htmlhelp_basename = "structlogdoc" +_logo = "https://www.structlog.org/en/latest/_static/structlog_logo_small.png" +rst_epilog = f"""\ +.. meta:: + :property=og:type: website + :property=og:site_name: structlog – Structured Logging for Python + :property=og:author: Hynek Schlawack + :property=og:image: { _logo } + :twitter:image: { _logo } + :twitter:creator: @hynek +""" # pragma: noqa + latex_documents = [ ("index", "structlog.tex", "structlog Documentation", "Author", "manual") ] From 8b50f9eee9bbc36e3800ec9828b2b03eb6aeae49 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 18 Nov 2020 09:14:07 +0100 Subject: [PATCH 0405/1520] Update description, add og:description --- README.rst | 2 +- docs/conf.py | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index b91b20be..1c2355d0 100644 --- a/README.rst +++ b/README.rst @@ -25,7 +25,7 @@ .. -begin-short- -``structlog`` makes logging in Python less painful and more powerful by adding structure to your log entries. +``structlog`` makes logging in Python faster, less painful, and more powerful by adding structure to your log entries. It's up to you whether you want ``structlog`` to take care about the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's ``logging`` module. diff --git a/docs/conf.py b/docs/conf.py index 87e58575..d39b8f2c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -98,15 +98,20 @@ def find_version(*file_paths): htmlhelp_basename = "structlogdoc" _logo = "https://www.structlog.org/en/latest/_static/structlog_logo_small.png" +_descr = ( + "structlog makes logging in Python faster, less painful, and more " + "powerful by adding structure to your log entries." +) rst_epilog = f"""\ .. meta:: :property=og:type: website :property=og:site_name: structlog – Structured Logging for Python + :property=og:description: { _descr } :property=og:author: Hynek Schlawack :property=og:image: { _logo } :twitter:image: { _logo } :twitter:creator: @hynek -""" # pragma: noqa +""" latex_documents = [ ("index", "structlog.tex", "structlog Documentation", "Author", "manual") From c480e04b416b3e3c9e9be9803e09643de25e6baa Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 18 Nov 2020 09:19:55 +0100 Subject: [PATCH 0406/1520] update examples --- README.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 1c2355d0..78464550 100644 --- a/README.rst +++ b/README.rst @@ -48,7 +48,7 @@ You can stop writing prose and start thinking in terms of an event that happens >>> from structlog import get_logger >>> log = get_logger() >>> log.info("key_value_logging", out_of_the_box=True, effort=0) - 2016-04-20 16:20.13 key_value_logging effort=0 out_of_the_box=True + 2020-11-18 09:17.09 [info ] key_value_logging effort=0 out_of_the_box=True Each log entry is a meaningful dictionary instead of an opaque string now! @@ -63,8 +63,7 @@ Since log entries are dictionaries, you can start binding and re-binding key/val >>> log = log.bind(user="anonymous", some_key=23) >>> log = log.bind(user="hynek", another_key=42) >>> log.info("user.logged_in", happy=True) - 2016-04-20 16:20.13 user.logged_in another_key=42 happy=True some_key=23 user='hynek' - + 2020-11-18 09:18.28 [info ] user.logged_in another_key=42 happy=True some_key=23 user=hynek Powerful Pipelines ================== From 052e92a438fda6952f6ee8bb48d6622a3ce68a39 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 18 Nov 2020 09:24:49 +0100 Subject: [PATCH 0407/1520] Add a dummy twitter:title for now --- docs/conf.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index d39b8f2c..297d1161 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -102,13 +102,15 @@ def find_version(*file_paths): "structlog makes logging in Python faster, less painful, and more " "powerful by adding structure to your log entries." ) +_title = "structlog – Structured Logging for Python" rst_epilog = f"""\ .. meta:: :property=og:type: website - :property=og:site_name: structlog – Structured Logging for Python + :property=og:site_name: { _title } :property=og:description: { _descr } :property=og:author: Hynek Schlawack :property=og:image: { _logo } + :twitter:title: { _title } :twitter:image: { _logo } :twitter:creator: @hynek """ From 011f637d7b4a52552957fbf4a3cfc50823ef690d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 18 Nov 2020 09:28:02 +0100 Subject: [PATCH 0408/1520] A colon is better here --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 297d1161..e4d4d2e3 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -102,7 +102,7 @@ def find_version(*file_paths): "structlog makes logging in Python faster, less painful, and more " "powerful by adding structure to your log entries." ) -_title = "structlog – Structured Logging for Python" +_title = "structlog: Structured Logging for Python" rst_epilog = f"""\ .. meta:: :property=og:type: website From 1d135b5516e8878619501d8d93f2a208dd3f9101 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 18 Nov 2020 09:36:00 +0100 Subject: [PATCH 0409/1520] Try our transparent/non-text logo for og --- docs/conf.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index e4d4d2e3..74281a47 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -50,7 +50,7 @@ def find_version(*file_paths): # General information about the project. project = "structlog" author = "Hynek Schlawack" -copyright = f"2013, {author}" +copyright = f"2013, { author }" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -97,7 +97,10 @@ def find_version(*file_paths): html_static_path = ["_static"] htmlhelp_basename = "structlogdoc" -_logo = "https://www.structlog.org/en/latest/_static/structlog_logo_small.png" +_logo = ( + "https://www.structlog.org/en/latest/_static/" + "structlog_logo_small_transparent.png" +) _descr = ( "structlog makes logging in Python faster, less painful, and more " "powerful by adding structure to your log entries." From 151d074fa29776cbbb5d00ee074dedab496eca6f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 20 Nov 2020 10:00:00 +0100 Subject: [PATCH 0410/1520] Steal shamelessly from urllib3 --- README.rst | 45 +++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/README.rst b/README.rst index 78464550..34152965 100644 --- a/README.rst +++ b/README.rst @@ -1,27 +1,24 @@ -.. image:: https://www.structlog.org/en/latest/_static/structlog_logo_small.png - :alt: structlog Logo - :width: 256px - :target: https://www.structlog.org/ - -============================================ -``structlog``: Structured Logging for Python -============================================ - -.. image:: https://readthedocs.org/projects/structlog/badge/?version=stable - :target: https://www.structlog.org/en/stable/?badge=stable - :alt: Documentation Status - -.. image:: https://github.com/hynek/structlog/workflows/CI/badge.svg?branch=master - :target: https://github.com/hynek/structlog/actions?workflow=CI - :alt: CI Status - -.. image:: https://codecov.io/github/hynek/structlog/branch/master/graph/badge.svg - :target: https://codecov.io/github/hynek/structlog - :alt: Test Coverage - -.. image:: https://img.shields.io/badge/code%20style-black-000000.svg - :target: https://github.com/psf/black - :alt: Code style: black +.. raw:: html + +

    + + structlog + +

    +

    + + Documentation Status + + + CI Status + + + Test Coverage + + + Code style: black + +

    .. -begin-short- From 30f24840f15962425c6b621109615891aea0eb27 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 20 Nov 2020 10:00:30 +0100 Subject: [PATCH 0411/1520] Tiny adjustment --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 34152965..c8890139 100644 --- a/README.rst +++ b/README.rst @@ -2,7 +2,7 @@

    - structlog + structlog

    From 12210ce3fe4c8506591e887153cae488ecb78421 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 20 Nov 2020 10:18:29 +0100 Subject: [PATCH 0412/1520] Fix long description --- setup.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 5674ee3a..9b3d46bb 100644 --- a/setup.py +++ b/setup.py @@ -96,7 +96,10 @@ def find_meta(meta): VERSION = find_meta("version") LONG = ( - read("README.rst") + "==============================================\n" + "``structlog``: : Structured Logging for Python\n" + "==============================================\n" + + read("README.rst").split(".. -begin-short-")[1] + "\n\n" + "Release Information\n" + "===================\n\n" From 4aef11eab3efe351d317a5461778d10b5cad6078 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 20 Nov 2020 10:19:54 +0100 Subject: [PATCH 0413/1520] Add funding URLs --- setup.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setup.py b/setup.py index 9b3d46bb..d644162f 100644 --- a/setup.py +++ b/setup.py @@ -17,6 +17,9 @@ "Documentation": "https://www.structlog.org/", "Bug Tracker": "https://github.com/hynek/structlog/issues", "Source Code": "https://github.com/hynek/structlog", + "Funding": "https://github.com/sponsors/hynek", + "Tidelift": "https://tidelift.com/subscription/pkg/pypi-structlog?" + "utm_source=pypi-structlog&utm_medium=pypi", } CLASSIFIERS = [ "Development Status :: 5 - Production/Stable", From 0faeacafb27d000e07806e9586b90d93530d7f5a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 24 Nov 2020 09:01:12 +0100 Subject: [PATCH 0414/1520] [pre-commit.ci] pre-commit autoupdate (#286) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6a0d1619..1ce19f5c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,8 +6,8 @@ repos: - id: black language_version: python3.8 - - repo: https://github.com/pre-commit/mirrors-isort - rev: v5.6.4 + - repo: https://github.com/PyCQA/isort + rev: 5.6.4 hooks: - id: isort additional_dependencies: [toml] From bad0116427286c59e7d85a0ef16e0db663f8ea1d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 6 Dec 2020 17:49:52 +0100 Subject: [PATCH 0415/1520] Implement native log levels though an optimized bound logger (#285) Remove LevelFilter, this is much faster. Since we needed a better way for testing, I've also added CapturingLogger. --- CHANGELOG.rst | 10 +++-- docs/api.rst | 21 +++++++++- docs/getting-started.rst | 7 +++- docs/loggers.rst | 10 +++-- docs/logging-best-practices.rst | 7 ++-- docs/performance.rst | 68 ++++++++++++++++++++++++------ docs/processors.rst | 2 +- docs/testing.rst | 19 +++++++++ docs/thread-local.rst | 2 +- src/structlog/__init__.py | 2 + src/structlog/_config.py | 4 +- src/structlog/_log_levels.py | 70 ++++++++++++++++++++++++++++++- src/structlog/processors.py | 65 +---------------------------- src/structlog/testing.py | 74 ++++++++++++++++++++++++++++++++- src/structlog/types.py | 62 +++++++++++++++++++++++++++ tests/test_config.py | 4 +- tests/test_log_levels.py | 55 ++++++++++++++++++++++++ tests/test_processors.py | 39 ----------------- tests/test_testing.py | 52 ++++++++++++++++++++++- 19 files changed, 436 insertions(+), 137 deletions(-) create mode 100644 tests/test_log_levels.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a702a435..aae565a8 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -39,9 +39,10 @@ Changes: Please feel free to provide feedback! `#223 `_, `#282 `_ -- Added ``structlog.processors.LevelFilter`` that can filter log entries based on the names of the log methods (and uses the same order as standard library's logging). - `#283 `_ -- As a complement, ``structlog.stdlib.add_log_level()`` can now also be imported as ``structlog.processors.add_log_level`` since it just adds the method name to the event dict. +- Added ``structlog.make_filtering_logger`` that can be used like ``configure(wrapper_class=make_filtering_bound_logger(logging.INFO))``. + It creates a highly optimized bound logger whose inactive methods only consist of a ``return None``. + This is now also the default logger. +- As a complement, ``structlog.stdlib.add_log_level()`` can now additionally be imported as ``structlog.processors.add_log_level`` since it just adds the method name to the event dict. - ``structlog.processors.add_log_level()`` is now part of the default configuration. - ``structlog.stdlib.ProcessorFormatter`` no longer uses exceptions for control flow, allowing ``foreign_pre_chain`` processors to use ``sys.exc_info()`` to access the real exception. - Added ``structlog.BytesLogger`` to avoid unnecessary encoding round trips. @@ -52,6 +53,7 @@ Changes: `#266 `_, - ``structlog.PrintLogger`` now supports ``copy.deepcopy()``. `#268 `_ +- Added ``structlog.testing.CapturingLogger`` for more unittesting goodness. ---- @@ -129,7 +131,7 @@ Changes: `#215 `_ - ``structlog.dev.ConsoleRenderer`` now initializes ``colorama`` lazily, to prevent accidental side-effects just by importing ``structlog``. `#210 `_ -- Added new processor ``structlog.dev.set_exc_info()`` that will set ``exc_info=True`` if the method's name is `exception` and ``exc_info`` isn't set at all. +- Added new processor ``structlog.dev.set_exc_info()`` that will set ``exc_info=True`` if the method's name is ``exception`` and ``exc_info`` isn't set at all. *This is only necessary when the standard library integration is not used*. It fixes the problem that in the default configuration, ``structlog.get_logger().exception("hi")`` in an ``except`` block would not print the exception without passing ``exc_info=True`` to it explicitly. `#130 `_, diff --git a/docs/api.rst b/docs/api.rst index eb181431..9220eb46 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -45,6 +45,8 @@ API Reference .. autoclass:: BoundLogger :members: new, bind, unbind +.. autofunction:: make_filtering_bound_logger + .. autofunction:: get_context .. autoclass:: PrintLogger @@ -81,12 +83,27 @@ API Reference .. autofunction:: capture_logs .. autoclass:: LogCapture + +.. autoclass:: CapturingLogger + + >>> from pprint import pprint + >>> cl = structlog.testing.CapturingLogger() + >>> cl.msg("hello") + >>> cl.msg("hello", when="again") + >>> pprint(cl.calls) + [CapturedCall(method_name='msg', args=('hello',), kwargs={}), + CapturedCall(method_name='msg', args=('hello',), kwargs={'when': 'again'})] + +.. autoclass:: CapturingLoggerFactory +.. autoclass:: CapturedCall + .. autoclass:: ReturnLogger :members: msg, err, debug, info, warning, error, critical, log, failure, fatal .. autoclass:: ReturnLoggerFactory + `structlog.threadlocal` Module ------------------------------ @@ -176,8 +193,6 @@ API Reference 'b=[1, 2, 3] a=42' -.. autoclass:: LevelFilter - .. autofunction:: add_log_level .. autoclass:: UnicodeDecoder @@ -257,6 +272,8 @@ API Reference They currently also have to carry a `Context` as a ``_context`` attribute. +.. autoprotocol:: FilteringBoundLogger + .. autodata:: EventDict .. autodata:: WrappedLogger .. autodata:: Processor diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 9a3896ab..f1a9d35a 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -39,7 +39,9 @@ Here, ``structlog`` takes full advantage of its hopefully useful default setting It should be noted that even in most complex logging setups the example would still look just like that thanks to `configuration`. Using the defaults, as above, is equivalent to:: + import loggging import structlog + structlog.configure( processors=[ structlog.processors.add_log_level, @@ -49,7 +51,7 @@ Using the defaults, as above, is equivalent to:: structlog.processors.TimeStamper(), structlog.dev.ConsoleRenderer() ], - wrapper_class=structlog.BoundLogger, + wrapper_class=structlog.make_filtering_bound_logger(logging.NOTSET), context_class=dict, logger_factory=structlog.PrintLoggerFactory(), cache_logger_on_first_use=False @@ -59,6 +61,9 @@ Using the defaults, as above, is equivalent to:: .. note:: For brevity and to enable doctests, all further examples in ``structlog``'s documentation use the more simplistic `structlog.processors.KeyValueRenderer()` without timestamps. + `structlog.make_filtering_bound_logger()` (re-)uses `logging`'s log levels, but doesn't use it at all. + The exposed API is `FilteringBoundLogger`. + There you go, structured logging! However, this alone wouldn't warrant its own package. After all, there's even a recipe_ on structured logging for the standard library. diff --git a/docs/loggers.rst b/docs/loggers.rst index 8902014e..b7843402 100644 --- a/docs/loggers.rst +++ b/docs/loggers.rst @@ -52,14 +52,18 @@ For that times there is the `structlog.wrap_logger` function that can be used to .. doctest:: - >>> from structlog import wrap_logger - >>> class PrintLogger: + >>> import structlog + >>> class CustomPrintLogger: ... def msg(self, message): ... print(message) >>> def proc(logger, method_name, event_dict): ... print("I got called with", event_dict) ... return repr(event_dict) - >>> log = wrap_logger(PrintLogger(), processors=[proc], context_class=dict) + >>> log = structlog.wrap_logger( + ... CustomPrintLogger(), + ... wrapper_class=structlog.BoundLogger, + ... processors=[proc], + ... ) >>> log2 = log.bind(x=42) >>> log == log2 False diff --git a/docs/logging-best-practices.rst b/docs/logging-best-practices.rst index 82e7d7ba..374df737 100644 --- a/docs/logging-best-practices.rst +++ b/docs/logging-best-practices.rst @@ -24,7 +24,8 @@ Centralized Logging ------------------- Nowadays you usually don't want your logfiles in compressed archives distributed over dozens -- if not thousands -- of servers or cluster nodes. -You want them in a single location; parsed, indexed, and easy to search. +You want them in a single location. +Parsed, indexed, and easy to search. ELK @@ -33,11 +34,11 @@ ELK The ELK stack (Elasticsearch_, Logstash_, Kibana_) from Elastic is a great way to store, parse, and search your logs. The way it works is that you have local log shippers like Filebeat_ that parse your log files and forward the log entries to your Logstash_ server. -Logstash parses the log entries and stores them in in Elasticsearch_. +Logstash parses the log entries and stores them in Elasticsearch_. Finally, you can view and search them in Kibana_. If your log entries consist of a JSON dictionary, this is fairly easy and efficient. -All you have to do is to tell Logstash_ the name of your timestamp field. +All you have to do is to tell Logstash_ either that your log entries are prepended with a timestamp from `TimeStamper` or the name of your timestamp field. Graylog diff --git a/docs/performance.rst b/docs/performance.rst index 601cb62e..42cb4550 100644 --- a/docs/performance.rst +++ b/docs/performance.rst @@ -1,23 +1,22 @@ Performance =========== -``structlog``'s default configuration tries to be as unsurprising and not confusing to new developers as possible. +``structlog``'s default configuration tries to be as unsurprising to new developers as possible. Some of the choices made come with an avoidable performance price tag -- although its impact is debatable. Here are a few hints how to get most out of ``structlog`` in production: -#. Use plain `dict`\ s as context classes. - Python is full of them and they are highly optimized:: - - configure(context_class=dict) - - If you don't use automated parsing (you should!) and need predictable order of your keys for some reason, use the *key_order* argument of :class:`~structlog.processors.KeyValueRenderer`. #. Use a specific wrapper class instead of the generic one. ``structlog`` comes with ones for the :doc:`standard-library` and for :doc:`twisted`:: configure(wrapper_class=structlog.stdlib.BoundLogger) + ``structlog`` also comes with native log levels that are based on the ones from the standard library (read: we've copy and pasted them), but don't involve `logging`'s dynamic machinery. + That makes them *much* faster. + You can use `structlog.make_filtering_bound_logger()` to create one. + :doc:`Writing own wrapper classes ` is straightforward too. + #. Avoid (frequently) calling log methods on loggers you get back from :func:`structlog.wrap_logger` and :func:`structlog.get_logger`. Since those functions are usually called in module scope and thus before you are able to configure them, they return a proxy that assembles the correct logger on demand. @@ -35,16 +34,61 @@ Here are a few hints how to get most out of ``structlog`` in production: configure(cache_logger_on_first_use=True) This has the only drawback is that later calls on :func:`~structlog.configure` don't have any effect on already cached loggers -- that shouldn't matter outside of :doc:`testing ` though. -#. Use a faster JSON serializer than the standard library. - Possible alternatives are among others simplejson_, orjson_, or RapidJSON_:: - - structlog.processors.JSONRenderer(serializer=rapidjson.dumps) -#. Avoid sending your log entries through the standard library if you can: it's a major bottleneck. +#. Avoid sending your log entries through the standard library if you can: its dynamic nature and flexibiliy make it a major bottleneck. Instead use `structlog.PrintLoggerFactory` or -- if your serializer returns bytes (e.g. orjson_) -- `structlog.BytesLoggerFactory`. You can still configure `logging` for packages that you don't control, but avoid it for your *own* log entries. +#. Use a faster JSON serializer than the standard library. + Possible alternatives are among others are orjson_ or RapidJSON_. + + +Example +------- + + +Here's an example for a production-ready non-asyncio ``structlog`` configuration that's as fast as it gets:: + + import logging + import structlog + + structlog.configure( + cache_logger_on_first_use=True, + wrapper_class=structlog.make_filtering_bound_logger(logging.INFO), + processors=[ + structlog.threadlocal.merge_threadlocal_context, + structlog.processors.add_log_level, + structlog.processors.format_exc_info, + structlog.processors.TimeStamper(fmt="iso", utc=False), + structlog.processors.JSONRenderer(serializer=orjson.dumps), + ], + logger_factory=structlog.BytesLoggerFactory(), + ) + +It has the following properties: + +- Caches all loggers on first use. +- Filters all log entries below the ``info`` log level **very** efficiently. + The ``debug`` method literally consists of ``return None``. +- Supports `thread-local`. +- Adds the log level name. +- Renders exceptions. +- Adds an `ISO 8601 `_ timestamp under the ``timestamp`` key in the UTC timezone. +- Renders the log entries as JSON using orjson_ which is faster than plain logging in `logging`. +- Uses `BytesLoggerFactory` because orjson returns bytes. + That saves encoding ping-pong. + +Therefore a log entry might look like this: + +.. code:: json + + {"event":"hello","timestamp":"2020-11-17T09:54:11.900066Z"} + +---- + +If you need standard library support for external projects, you can either just use a JSON formatter like `python-json-logger `_, or pipe them through ``structlog`` as documented in `standard-library`. + .. _simplejson: https://simplejson.readthedocs.io/ .. _orjson: https://github.com/ijl/orjson diff --git a/docs/processors.rst b/docs/processors.rst index 2315a29c..485faab3 100644 --- a/docs/processors.rst +++ b/docs/processors.rst @@ -85,7 +85,7 @@ How about dropping only log entries that are marked as coming from a certain pee :language: python -Since it's so common to filter by the log level, ``structlog`` comes with `structlog.processors.LevelFilter`. +Since it's so common to filter by the log level, ``structlog`` comes with `structlog.make_filtering_bound_logger` that filters log entries before they even enter the processor chain.. It does **not** use the standard library, but it does use its names and order of log levels. In practice, it only looks up the numeric value of the method name and compares it to the configured minimal level. That's fast and usually good enough for applications. diff --git a/docs/testing.rst b/docs/testing.rst index c3258ed8..61ef820a 100644 --- a/docs/testing.rst +++ b/docs/testing.rst @@ -40,6 +40,25 @@ For example a `pytest `_ fixture to capture log output ---- +You can also use `structlog.testing.CapturingLogger` (directly, or via `CapturingLoggerFactory` that always returns the same logger) that is more low-level and great for unit tests: + +.. doctest:: + + >>> import structlog + >>> cf = structlog.testing.CapturingLoggerFactory() + >>> structlog.configure(logger_factory=cf, processors=[structlog.processors.JSONRenderer()]) + >>> log = get_logger() + >>> log.info("test!") + >>> cf.logger.calls + [CapturedCall(method_name='info', args=('{"event": "test!"}',), kwargs={})] + +.. testcleanup:: * + + import structlog + structlog.reset_defaults() + +---- + Additionally ``structlog`` also ships with a logger that just returns whatever it gets passed into it: `structlog.testing.ReturnLogger`. .. doctest:: diff --git a/docs/thread-local.rst b/docs/thread-local.rst index 26683545..5613dd21 100644 --- a/docs/thread-local.rst +++ b/docs/thread-local.rst @@ -140,7 +140,7 @@ In order to be able to bind values temporarily to a logger, `structlog.threadloc .. doctest:: ctx >>> log.bind(x=42) # doctest: +ELLIPSIS - , ...)> + , ...)> >>> log.msg("event!") x=42 event='event!' >>> with tmp_bind(log, x=23, y="foo") as tmp_log: diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 7830da10..ff66d90b 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -20,6 +20,7 @@ wrap_logger, ) from structlog._generic import BoundLogger +from structlog._log_levels import make_filtering_bound_logger from structlog._loggers import ( BytesLogger, BytesLoggerFactory, @@ -73,6 +74,7 @@ "get_context", "get_logger", "is_configured", + "make_filtering_bound_logger", "processors", "reset_defaults", "stdlib", diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 1962d331..582132df 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -21,7 +21,7 @@ cast, ) -from ._generic import BoundLogger +from ._log_levels import make_filtering_bound_logger from ._loggers import PrintLoggerFactory from .dev import ConsoleRenderer, _has_colorama, set_exc_info from .processors import ( @@ -47,7 +47,7 @@ ConsoleRenderer(colors=_has_colorama and sys.stdout.isatty()), ] _BUILTIN_DEFAULT_CONTEXT_CLASS = cast(Type[Context], dict) -_BUILTIN_DEFAULT_WRAPPER_CLASS = BoundLogger +_BUILTIN_DEFAULT_WRAPPER_CLASS = make_filtering_bound_logger(0) _BUILTIN_DEFAULT_LOGGER_FACTORY = PrintLoggerFactory() _BUILTIN_CACHE_LOGGER_ON_FIRST_USE = False diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index a6d5376b..5b7dae18 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -3,7 +3,10 @@ """ import logging -from .types import EventDict +from typing import Any, Callable, Type + +from ._base import BoundLoggerBase +from .types import EventDict, FilteringBoundLogger # Adapted from the stdlib @@ -56,3 +59,68 @@ def add_log_level( event_dict["level"] = method_name return event_dict + + +def _nop(*args: Any, **kw: Any) -> Any: + return None + + +def exception(self: FilteringBoundLogger, event: str, **kw: Any) -> Any: + kw.setdefault("exc_info", True) + + return self.error(event, **kw) + + +def make_filtering_bound_logger(min_level: int) -> Type[FilteringBoundLogger]: + """ + Create a new `FilteringBoundLogger` that only logs *min_level* or higher. + + The logger is optimized such that log levels below *min_level* only consist + of a ``return None``. + + Compared to using ``structlog``'s standard library integration and the + `structlog.stdlib.filter_by_level` processor: + + - It's faster because once the logger is built at program start, it's a + static class. + - For the same reason you can't change the log level once configured. + Use the dynamic approach of `standard-library` instead, if you need this + feature. + + :param min_level: The log level as an integer. You can use the constants + from `logging` like ``logging.INFO`` or pass the values directly. See + `this table from the logging docs + `_ for possible + values. + + .. versionadded:: 20.2.0 + """ + + def make_method(level: int) -> Callable[..., Any]: + if level < min_level: + return _nop + + name = _LEVEL_TO_NAME[level] + + def meth(self: Any, event: str, **kw: Any) -> Any: + return self._proxy_to_logger(name, event, **kw) + + meth.__name__ = name + + return meth + + meths = {} + for lvl, name in _LEVEL_TO_NAME.items(): + meths[name] = make_method(lvl) + + meths["exception"] = exception + meths["fatal"] = meths["error"] + meths["warn"] = meths["warning"] + meths["msg"] = meths["info"] + + return type( + "BoundLoggerFilteringAt%s" + % (_LEVEL_TO_NAME.get(min_level, "Notset").capitalize()), + (BoundLoggerBase,), + meths, + ) diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 8c037bd8..8dfe5cb9 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -23,7 +23,6 @@ Union, ) -from ._base import DropEvent from ._frames import ( _find_first_app_frame_and_name, _format_exception, @@ -34,6 +33,7 @@ __all__ = [ + "_NAME_TO_LEVEL", # some people rely on it being here "KeyValueRenderer", "TimeStamper", "add_log_level", @@ -43,7 +43,6 @@ "format_exc_info", "ExceptionPrettyPrinter", "StackInfoRenderer", - "LevelFilter", ] @@ -289,11 +288,6 @@ class TimeStamper: """ Add a timestamp to ``event_dict``. - .. note:: - - You should let OS tools take care of timestamping. See also - `logging-best-practices`. - :param fmt: strftime format string, or ``"iso"`` for `ISO 8601 `_, or `None` for a `UNIX timestamp `_. @@ -453,60 +447,3 @@ def __call__( ) return event_dict - - -class LevelFilter: - """ - A framework-agnostic level filter. - - Uses standard library's order of levels, but relies solely on the *names* - of the levels. If a log entry doesn't have the minimum log level, - `DropEvent` is raised. - - This means that you can use it along with any `BindableLogger`, as long as - the levels have the same names. - - Since ``logging.INFO`` et al are just (undocumented) int constants, you can - use them too, regardless whether you use stdlib logging or not: - - .. code:: - - LevelFilter(logging.INFO, False) - - will leave through log entries with log level INFO or higher (i.e. the log - method's name is ``info``, or ``warn``, ...) and works both with standard - library's `logging` as well as without. - - :param min_level: The minimal level a log entry has to have to be not - dropped. You can pass either an integer or a level string. Check out - the `logging docs - `_ for possible - values. - :param pass_unknown: If True and `LevelFilter` encounters an unknown level - name (i.e. log method name), the log entry is passed through. If False, - it's dropped. - - .. versionadded:: 20.2.0 - """ - - min_level: int - unknown_default: int - - def __init__(self, min_level: Union[str, int], pass_unknown: bool) -> None: - if isinstance(min_level, str): - min_level = _NAME_TO_LEVEL[min_level.lower()] - - self.min_level = min_level - - if pass_unknown: - self.unknown_default = 10000 - else: - self.unknown_default = -1 - - def __call__( - self, logger: WrappedLogger, name: str, event_dict: EventDict - ) -> EventDict: - if _NAME_TO_LEVEL.get(name, self.unknown_default) < self.min_level: - raise DropEvent - - return event_dict diff --git a/src/structlog/testing.py b/src/structlog/testing.py index 508bd8b8..9f5dfbb6 100644 --- a/src/structlog/testing.py +++ b/src/structlog/testing.py @@ -11,7 +11,7 @@ """ from contextlib import contextmanager -from typing import Any, Generator, List, NoReturn +from typing import Any, Dict, Generator, List, NamedTuple, NoReturn, Tuple from ._config import configure, get_config from .exceptions import DropEvent @@ -108,3 +108,75 @@ def __init__(self) -> None: def __call__(self, *args: Any) -> ReturnLogger: return self._logger + + +class CapturedCall(NamedTuple): + """ + A call as captured by `CapturingLogger`. + + Can also be unpacked like a tuple. + + :param method_name: The method name that got called. + :param args: A tuple of the positional arguments. + :param kwargs: A dict of the keyword arguments. + + .. versionadded:: 20.2.0 + """ + + method_name: str + args: Tuple[Any, ...] + kwargs: Dict[str, Any] + + +class CapturingLogger: + """ + Store the method calls that it's been called with. + + This is nicer than `ReturnLogger` for unit tests because the bound logger + doesn't have to cooperate. + + **Any** method name is supported. + + .. versionadded:: 20.2.0 + """ + + calls: List[CapturedCall] + + def __init__(self) -> None: + self.calls = [] + + def __repr__(self) -> str: + return f"" + + def __getattr__(self, name: str) -> Any: + """ + Capture call to `calls` + """ + + def log(*args: Any, **kw: Any) -> None: + self.calls.append(CapturedCall(name, args, kw)) + + return log + + +class CapturingLoggerFactory: + r""" + Produce and cache `CapturingLogger`\ s. + + Each factory produces and re-uses only **one** logger. + + You can access it via the ``logger`` attribute. + + To be used with `structlog.configure`\ 's *logger_factory*. + + Positional arguments are silently ignored. + + .. versionadded:: 20.2.0 + """ + logger: CapturingLogger + + def __init__(self) -> None: + self.logger = CapturingLogger() + + def __call__(self, *args: Any) -> CapturingLogger: + return self.logger diff --git a/src/structlog/types.py b/src/structlog/types.py index fc817b2c..b90f83ac 100644 --- a/src/structlog/types.py +++ b/src/structlog/types.py @@ -104,3 +104,65 @@ def try_unbind(self, *keys: str) -> "BindableLogger": def new(self, **new_values: Any) -> "BindableLogger": ... + + +class FilteringBoundLogger(BindableLogger, Protocol): + """ + A `BindableLogger` that filters by a level. + + Currently, the only way to instantiate one is using + `make_filtering_bound_logger`. + + .. versionadded:: 20.2.0 + """ + + def debug(self, event: str, **kw: Any) -> Any: + """ + Log *event* with **kw** at **debug** level. + """ + + def info(self, event: str, **kw: Any) -> Any: + """ + Log *event* with **kw** at **info** level. + """ + + def warning(self, event: str, **kw: Any) -> Any: + """ + Log *event* with **kw** at **warn** level. + """ + + def warn(self, event: str, **kw: Any) -> Any: + """ + Log *event* with **kw** at **warn** level. + """ + + def error(self, event: str, **kw: Any) -> Any: + """ + Log *event* with **kw** at **error** level. + """ + + def err(self, event: str, **kw: Any) -> Any: + """ + Log *event* with **kw** at **error** level. + """ + + def fatal(self, event: str, **kw: Any) -> Any: + """ + Log *event* with **kw** at **critical** level. + """ + + def exception(self, event: str, **kw: Any) -> Any: + """ + Log *event* with **kw** at **error** level and ensure that ``exc_info`` + is set in the event dictionary. + """ + + def critical(self, event: str, **kw: Any) -> Any: + """ + Log *event* with **kw** at **critical** level. + """ + + def msg(self, event: str, **kw: Any) -> Any: + """ + Log *event* with **kw** at **info** level. + """ diff --git a/tests/test_config.py b/tests/test_config.py index 14c15049..3b46f46f 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -326,7 +326,7 @@ def test_bind_doesnt_cache_logger(self): class F: "New logger factory with a new attribute" - def a(self, *args): + def info(self, *args): return 5 proxy = BoundLoggerLazyProxy(None) @@ -334,7 +334,7 @@ def a(self, *args): configure(logger_factory=F) new_b = proxy.bind() - assert new_b.a("test") == 5 + assert new_b.info("test") == 5 def test_emphemeral(self): """ diff --git a/tests/test_log_levels.py b/tests/test_log_levels.py new file mode 100644 index 00000000..edc288d9 --- /dev/null +++ b/tests/test_log_levels.py @@ -0,0 +1,55 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the MIT License. See the LICENSE file in the root of this +# repository for complete details. + +import logging + +import pytest + +from structlog import make_filtering_bound_logger +from structlog.testing import CapturingLogger + + +@pytest.fixture(name="cl") +def fixture_cl(): + return CapturingLogger() + + +@pytest.fixture(name="bl") +def fixture_bl(cl): + return make_filtering_bound_logger(logging.INFO)(cl, [], {}) + + +class TestFilteringLogger: + def test_exact_level(self, bl, cl): + """ + if log level is exactly the min_level, log. + """ + bl.info("yep") + + assert [("info", (), {"event": "yep"})] == cl.calls + + def test_one_below(self, bl, cl): + """ + if log level is exactly the min_level, log. + """ + bl.debug("nope") + + assert [] == cl.calls + + def test_exception(self, bl, cl): + """ + exception ensures that exc_info is set to True, unless it's already + set. + """ + bl.exception("boom") + + assert [("error", (), {"event": "boom", "exc_info": True})] + + def test_exception_passed(self, bl, cl): + """ + exception if exc_info has a value, exception doesn't tamper with it. + """ + bl.exception("boom", exc_info=42) + + assert [("error", (), {"event": "boom", "exc_info": 42})] diff --git a/tests/test_processors.py b/tests/test_processors.py index 4021c3fc..f8a8f648 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -18,7 +18,6 @@ ExceptionPrettyPrinter, JSONRenderer, KeyValueRenderer, - LevelFilter, StackInfoRenderer, TimeStamper, UnicodeDecoder, @@ -539,41 +538,3 @@ def test_py3_exception_no_traceback(self): e = ValueError() assert (e.__class__, e, None) == _figure_out_exc_info(e) - - -class TestLevelFilter: - @pytest.mark.parametrize("min_level", ["notset", 0, "nOtSeT"]) - def test_passes(self, min_level): - """ - If the log level is higher than the configured one, pass it through. - """ - lf = LevelFilter(min_level, pass_unknown=False) - - assert {"foo": 42} == lf(None, "debug", {"foo": 42}) - - @pytest.mark.parametrize("min_level", ["info", 20, "iNfO"]) - def test_drop(self, min_level): - """ - If the log level is less than the configured one, raise DropEvent. - """ - lf = LevelFilter(min_level, pass_unknown=False) - - with pytest.raises(structlog.DropEvent): - lf(None, "debug", {"foo": 42}) - - def test_pass_unknown(self): - """ - If pass_unknown is True, unknown log levels always pass. - """ - lf = LevelFilter(0, pass_unknown=True) - - assert {"foo": 42} == lf(None, "unknown", {"foo": 42}) - - def test_drop_unknown(self): - """ - If pass_unknown is False, unknown log levels always raise DropEvent. - """ - lf = LevelFilter(0, pass_unknown=False) - - with pytest.raises(structlog.DropEvent): - lf(None, "unknown", {"foo": 42}) diff --git a/tests/test_testing.py b/tests/test_testing.py index 8237ad88..adbc5c2b 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -6,7 +6,13 @@ import pytest from structlog import get_config, get_logger, reset_defaults, testing -from structlog.testing import ReturnLogger, ReturnLoggerFactory +from structlog.testing import ( + CapturedCall, + CapturingLogger, + CapturingLoggerFactory, + ReturnLogger, + ReturnLoggerFactory, +) class TestCaptureLogs: @@ -80,6 +86,9 @@ def test_return_logger(self): class TestReturnLoggerFactory: def test_builds_returnloggers(self): + """ + Factory returns ReturnLoggers. + """ f = ReturnLoggerFactory() assert isinstance(f(), ReturnLogger) @@ -99,3 +108,44 @@ def test_ignores_args(self): the factory, they are not passed to the logger. """ ReturnLoggerFactory()(1, 2, 3) + + +class TestCapturingLogger: + def test_factory_caches(self): + """ + CapturingLoggerFactory returns one CapturingLogger over and over again. + """ + clf = CapturingLoggerFactory() + cl1 = clf() + cl2 = clf() + + assert cl1 is cl2 + + def test_repr(self): + """ + repr says how many calls there were. + """ + cl = CapturingLogger() + + cl.info("hi") + cl.error("yolo") + + assert "" == repr(cl) + + def test_captures(self): + """ + All calls to all names are captured. + """ + cl = CapturingLogger() + + cl.info("hi", val=42) + cl.trololo("yolo", foo={"bar": "baz"}) + + assert [ + CapturedCall(method_name="info", args=("hi",), kwargs={"val": 42}), + CapturedCall( + method_name="trololo", + args=("yolo",), + kwargs={"foo": {"bar": "baz"}}, + ), + ] == cl.calls From 7f7b1e4cc263278ce0396a4ee4b96adf343e5c62 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 21 Dec 2020 06:54:13 +0100 Subject: [PATCH 0416/1520] Implement async bound loggers for stdlib (#245) * Start the async revolution * Keep stuff private for now * Point out that running async means more overhead * Add types * Update from prod * Fix tests * Refactor fixture * More helpful phrasing * braaand --- .pre-commit-config.yaml | 2 +- CHANGELOG.rst | 4 +- conftest.py | 29 +++++- docs/api.rst | 4 +- docs/conf.py | 1 + docs/standard-library.rst | 11 +++ setup.py | 2 +- src/structlog/stdlib.py | 188 ++++++++++++++++++++++++++++++++++++-- tests/test_loggers.py | 14 +-- tests/test_stdlib.py | 145 ++++++++++++++++++++++++++++- tests/test_twisted.py | 9 +- 11 files changed, 375 insertions(+), 34 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1ce19f5c..6d407190 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,7 +21,7 @@ repos: exclude: docs/code_examples - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.3.0 + rev: v3.4.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer diff --git a/CHANGELOG.rst b/CHANGELOG.rst index aae565a8..e25957e9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -53,7 +53,9 @@ Changes: `#266 `_, - ``structlog.PrintLogger`` now supports ``copy.deepcopy()``. `#268 `_ -- Added ``structlog.testing.CapturingLogger`` for more unittesting goodness. +- Added ``structlog.testing.CapturingLogger`` for more unit testing goodness. +- Added ``structlog.stdlib.AsyncBoundLogger`` that executes logging calls in a thread executor and therefore doesn't block. + `#245 `_ ---- diff --git a/conftest.py b/conftest.py index ca862f95..31dbb9d8 100644 --- a/conftest.py +++ b/conftest.py @@ -3,6 +3,7 @@ # repository for complete details. +import logging import sys from io import StringIO @@ -10,6 +11,7 @@ import pytest from structlog._log_levels import _NAME_TO_LEVEL +from structlog.testing import CapturingLogger try: @@ -17,11 +19,25 @@ except ImportError: twisted = None +LOGGER = logging.getLogger() -@pytest.fixture -def sio(): + +@pytest.fixture(autouse=True) +def _ensure_logging_framework_not_altered(): + """ + Prevents 'ValueError: I/O operation on closed file.' errors. + """ + before_handlers = list(LOGGER.handlers) + + yield + + LOGGER.handlers = before_handlers + + +@pytest.fixture(name="sio") +def _sio(): """ - A StringIO instance. + A new StringIO instance. """ return StringIO() @@ -43,10 +59,15 @@ def __repr__(self): name="stdlib_log_method", params=[m for m in _NAME_TO_LEVEL if m != "notset"], ) -def fixture_stdlib_log_methods(request): +def _stdlib_log_methods(request): return request.param +@pytest.fixture(name="cl") +def _cl(): + return CapturingLogger() + + collect_ignore = [] if sys.version_info[:2] < (3, 7): collect_ignore.append("tests/test_contextvars.py") diff --git a/docs/api.rst b/docs/api.rst index 9220eb46..08ca999a 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -235,7 +235,9 @@ API Reference .. autofunction:: get_logger .. autoclass:: BoundLogger - :members: bind, unbind, new, debug, info, warning, warn, error, critical, exception, log + :members: bind, unbind, try_unbind, new, debug, info, warning, warn, error, critical, exception, log + +.. autoclass:: AsyncBoundLogger .. autoclass:: LoggerFactory :members: __call__ diff --git a/docs/conf.py b/docs/conf.py index 74281a47..63a0dbf6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -74,6 +74,7 @@ def find_version(*file_paths): ("py:class", "TextIO"), ("py:class", "structlog._base.BoundLoggerBase"), ("py:class", "structlog.dev._Styles"), + ("py:obj", "sync_bl"), ] # If true, '()' will be appended to :func: etc. cross-reference text. diff --git a/docs/standard-library.rst b/docs/standard-library.rst index 69f16f33..596a1ca2 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -48,6 +48,17 @@ Please note though, that it will neither configure nor verify your configuration It will call `structlog.get_logger()` just like if you would've called it -- the only difference are the type hints. +``asyncio`` +^^^^^^^^^^^ + +For ``asyncio`` applications, you may not want your whole application to block while your processor chain is formatting your log entries. +For that use case ``structlog`` comes with `structlog.stdlib.AsyncBoundLogger` that will do all processing in a thread pool executor. + +This means an increased computational cost per log entry but your application will never block because of logging. + +To use it, :doc:`configure ` ``structlog`` to use `AsyncBoundLogger` as ``wrapper_class``. + + Processors ---------- diff --git a/setup.py b/setup.py index d644162f..18a5d453 100644 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ "coverage[toml]", "freezegun>=0.2.8", "pretend", - "pytest-asyncio; python_version>='3.7'", + "pytest-asyncio", "pytest-randomly", "pytest>=6.0", "simplejson", diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 7bb1f027..0a69e27c 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -8,29 +8,48 @@ See also :doc:`structlog's standard library support `. """ -import logging -from typing import Any, Dict, List, Optional, Sequence, Tuple +import asyncio +import logging +import sys + +from functools import partial +from typing import ( + Any, + Callable, + Dict, + Iterable, + List, + Optional, + Sequence, + Tuple, +) from ._base import BoundLoggerBase from ._config import get_logger as _generic_get_logger from ._frames import _find_first_app_frame_and_name, _format_stack from ._log_levels import _LEVEL_TO_NAME, _NAME_TO_LEVEL, add_log_level from .exceptions import DropEvent -from .types import EventDict, ExcInfo, Processor, WrappedLogger +from .types import Context, EventDict, ExcInfo, Processor, WrappedLogger + + +try: + from . import contextvars +except ImportError: + contextvars = None # type: ignore __all__ = [ + "add_log_level_number", + "add_log_level", + "add_logger_name", "BoundLogger", + "filter_by_level", "get_logger", "LoggerFactory", "PositionalArgumentsFormatter", - "filter_by_level", - "add_log_level_number", - "add_log_level", - "add_logger_name", - "render_to_log_kwargs", "ProcessorFormatter", + "render_to_log_kwargs", ] @@ -337,6 +356,159 @@ def get_logger(*args: Any, **initial_values: Any) -> BoundLogger: return _generic_get_logger(*args, **initial_values) +class AsyncBoundLogger: + """ + Wraps a `BoundLogger` & exposes its logging methods as ``async`` versions. + + Instead of blocking the program, they are run asynchronously in a thread + pool executor. + + This means more computational overhead per log call. But it also means that + the processor chain (e.g. JSON serialization) and I/O won't block your + whole application. + + .. warning: Since the processor pipeline runs in a separate thread, + `structlog.contextvars.merge_contextvars` does **nothing** and should + be removed from you processor chain. + + Instead it's merged within **this logger** before handing off log + processing to the thread. + + Only available for Python 3.7 and later. + + :ivar structlog.stdlib.BoundLogger sync_bl: The wrapped synchronous logger. + It is useful to be able to log synchronously occasionally. + + .. versionadded:: 20.2.0 + """ + + __slots__ = ["sync_bl", "_loop"] + + sync_bl: BoundLogger + + _executor = None + _bound_logger_factory = BoundLogger + + def __init__( + self, + logger: logging.Logger, + processors: Iterable[Processor], + context: Context, + *, + # Only as an optimization for binding! + _sync_bl: Any = None, # *vroom vroom* over purity. + _loop: Any = None, + ): + if _sync_bl: + self.sync_bl = _sync_bl + self._loop = _loop + + return + + self.sync_bl = self._bound_logger_factory( + logger=logger, processors=processors, context=context + ) + self._loop = asyncio.get_running_loop() + + @property + def _context(self) -> Context: + return self.sync_bl._context + + def bind(self, **new_values: Any) -> "AsyncBoundLogger": + return AsyncBoundLogger( + # logger, processors and context are within sync_bl. These + # arguments are ignored if _sync_bl is passsed. *vroom vroom* over + # purity. + logger=None, # type: ignore + processors=(), + context={}, + _sync_bl=self.sync_bl.bind(**new_values), + _loop=self._loop, + ) + + def new(self, **new_values: Any) -> "AsyncBoundLogger": + return AsyncBoundLogger( + # c.f. comment in bind + logger=None, # type: ignore + processors=(), + context={}, + _sync_bl=self.sync_bl.new(**new_values), + _loop=self._loop, + ) + + def unbind(self, *keys: str) -> "AsyncBoundLogger": + return AsyncBoundLogger( + # c.f. comment in bind + logger=None, # type: ignore + processors=(), + context={}, + _sync_bl=self.sync_bl.unbind(*keys), + _loop=self._loop, + ) + + def try_unbind(self, *keys: str) -> "AsyncBoundLogger": + return AsyncBoundLogger( + # c.f. comment in bind + logger=None, # type: ignore + processors=(), + context={}, + _sync_bl=self.sync_bl.try_unbind(*keys), + _loop=self._loop, + ) + + async def _dispatch_to_sync( + self, + meth: Callable[..., Any], + event: str, + args: Tuple[Any, ...], + kw: Dict[str, Any], + ) -> None: + """ + Merge contextvars and log using the sync logger in a thread pool. + """ + ctx = contextvars._get_context().copy() + ctx.update(kw) + + await self._loop.run_in_executor( + self._executor, partial(meth, event, *args, **ctx) + ) + + async def debug(self, event: str, *args: Any, **kw: Any) -> None: + await self._dispatch_to_sync(self.sync_bl.debug, event, args, kw) + + async def info(self, event: str, *args: Any, **kw: Any) -> None: + await self._dispatch_to_sync(self.sync_bl.info, event, args, kw) + + async def warning(self, event: str, *args: Any, **kw: Any) -> None: + await self._dispatch_to_sync(self.sync_bl.warning, event, args, kw) + + warn = warning + + async def error(self, event: str, *args: Any, **kw: Any) -> None: + await self._dispatch_to_sync(self.sync_bl.error, event, args, kw) + + async def critical(self, event: str, *args: Any, **kw: Any) -> None: + await self._dispatch_to_sync(self.sync_bl.critical, event, args, kw) + + fatal = critical + + async def exception(self, event: str, *args: Any, **kw: Any) -> None: + # To make `log.exception("foo") work, we have to check if the user + # passed an explicit exc_info and if not, supply our own. + ei = kw.pop("exc_info", None) + if ei is None and kw.get("exception") is None: + ei = sys.exc_info() + + kw["exc_info"] = ei + + await self._dispatch_to_sync(self.sync_bl.exception, event, args, kw) + + async def log(self, level: Any, event: str, *args: Any, **kw: Any) -> None: + await self._dispatch_to_sync( + partial(self.sync_bl.log, level), event, args, kw + ) + + class LoggerFactory: """ Build a standard library logger when an *instance* is called. diff --git a/tests/test_loggers.py b/tests/test_loggers.py index 8d7f5625..7d9ed09e 100644 --- a/tests/test_loggers.py +++ b/tests/test_loggers.py @@ -7,7 +7,7 @@ import pickle import sys -from io import BytesIO, StringIO +from io import BytesIO import pytest @@ -53,12 +53,10 @@ def test_repr(self): """ assert repr(PrintLogger()).startswith(" Date: Thu, 31 Dec 2020 10:32:44 +0100 Subject: [PATCH 0417/1520] Make & ensure that stdlib.AsyncLogger is an BindableLogger --- src/structlog/stdlib.py | 10 +++++++++- src/structlog/types.py | 1 - typing_examples.py | 18 ++++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 0a69e27c..6aa7d17f 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -386,6 +386,10 @@ class AsyncBoundLogger: sync_bl: BoundLogger + # Blantant lie, we use a property for _context. Need this for Protocol + # though. + _context: Context + _executor = None _bound_logger_factory = BoundLogger @@ -410,7 +414,11 @@ def __init__( ) self._loop = asyncio.get_running_loop() - @property + # We have to ignore the type because we've already declared it to ensure + # we're a BindableLogger. + # Instances would've been correctly recognized as such, however the class + # not and we need the class in `structlog.configure()`. + @property # type: ignore def _context(self) -> Context: return self.sync_bl._context diff --git a/src/structlog/types.py b/src/structlog/types.py index b90f83ac..ce5da351 100644 --- a/src/structlog/types.py +++ b/src/structlog/types.py @@ -87,7 +87,6 @@ class BindableLogger(Protocol): Methods shared among all bound loggers and that are relied on by ``structlog``. - .. versionadded:: 20.2 """ diff --git a/typing_examples.py b/typing_examples.py index 27f0f51e..900a72ad 100644 --- a/typing_examples.py +++ b/typing_examples.py @@ -169,3 +169,21 @@ def bytes_dumps( wrapper_class=structlog.stdlib.BoundLogger, cache_logger_on_first_use=True, ) + +structlog.configure( + processors=[ + structlog.stdlib.filter_by_level, + structlog.stdlib.add_logger_name, + structlog.stdlib.add_log_level, + structlog.stdlib.PositionalArgumentsFormatter(), + structlog.processors.TimeStamper(fmt="iso"), + structlog.processors.StackInfoRenderer(), + structlog.processors.format_exc_info, + structlog.processors.UnicodeDecoder(), + structlog.processors.JSONRenderer(), + ], + context_class=dict, + logger_factory=structlog.stdlib.LoggerFactory(), + wrapper_class=structlog.stdlib.AsyncBoundLogger, + cache_logger_on_first_use=True, +) From c47662c504f688bf0b15329b9d9bd8548b114f17 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 31 Dec 2020 10:43:49 +0100 Subject: [PATCH 0418/1520] Stop setting a pygments style --- docs/conf.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 63a0dbf6..f7144703 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -84,10 +84,6 @@ def find_version(*file_paths): # unit titles (such as .. function::). # add_module_names = True -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = "sphinx" - - # -- Options for HTML output -------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for From ec77e16a89840259d6b5208eca4c43c7d20b6db8 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 31 Dec 2020 11:23:17 +0100 Subject: [PATCH 0419/1520] Update flask example --- docs/code_examples/flask_/some_module.py | 5 ++--- docs/code_examples/flask_/webapp.py | 19 ++++++++++++++----- docs/examples.rst | 22 ++++++++++++++++++++-- 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/docs/code_examples/flask_/some_module.py b/docs/code_examples/flask_/some_module.py index e7c158a6..1a032b81 100644 --- a/docs/code_examples/flask_/some_module.py +++ b/docs/code_examples/flask_/some_module.py @@ -5,7 +5,6 @@ def some_function(): - # later then: + # ... logger.error("user did something", something="shot_in_foot") - # gives you: - # event='user did something' request_id='ffcdc44f-b952-4b5f-95e6-0f1f3a9ee5fd' something='shot_in_foot' + # ... diff --git a/docs/code_examples/flask_/webapp.py b/docs/code_examples/flask_/webapp.py index 1253600b..e08e063d 100644 --- a/docs/code_examples/flask_/webapp.py +++ b/docs/code_examples/flask_/webapp.py @@ -15,12 +15,20 @@ @app.route("/login", methods=["POST", "GET"]) def some_route(): - log = logger.new(request_id=str(uuid.uuid4())) + # You would put this into some kind of middleware or processor so it's set + # automatically for all requests in all views. + structlog.threadlocal.clear_threadlocal() + structlog.threadlocal.bind_threadlocal( + view=flask.request.path, + request_id=str(uuid.uuid4()), + peer=flask.request.access_route[0], + ) + # End of belongs-to-middleware. + + log = logger.bind() # do something # ... log.info("user logged in", user="test-user") - # gives you: - # event='user logged in' request_id='ffcdc44f-b952-4b5f-95e6-0f1f3a9ee5fd' user='test-user' # ... some_function() # ... @@ -33,9 +41,10 @@ def some_route(): ) structlog.configure( processors=[ + structlog.threadlocal.merge_threadlocal, # <--!!! structlog.processors.KeyValueRenderer( - key_order=["event", "request_id"] - ) + key_order=["event", "view", "peer"] + ), ], context_class=structlog.threadlocal.wrap_dict(dict), logger_factory=structlog.stdlib.LoggerFactory(), diff --git a/docs/examples.rst b/docs/examples.rst index bc4dcbbd..33c11637 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -19,9 +19,27 @@ In the simplest case, you bind a unique request ID to every incoming request so .. literalinclude:: code_examples/flask_/some_module.py :language: python -While wrapped loggers are *immutable* by default, this example demonstrates how to circumvent that using a thread local dict implementation for context data for convenience (hence the requirement for using ``new()`` for re-initializing the logger). +This would result among other the following lines to be printed: -Please note that `structlog.stdlib.LoggerFactory` is a totally magic-free class that just deduces the name of the caller's module and does a `logging.getLogger` with it. +.. code:: text + + event='user logged in' view='/login' peer='127.0.0.1' user='test-user' request_id='e08ddf0d-23a5-47ce-b20e-73ab8877d736' + event='user did something' view='/login' peer='127.0.0.1' something='shot_in_foot' request_id='e08ddf0d-23a5-47ce-b20e-73ab8877d736' + +As you can see, ``view``, ``peer``, and ``request_id`` are present in **both** log entries. + +While wrapped loggers are *immutable* by default, this example demonstrates how to circumvent that using a thread-local storage for request-wide context: + +1. `structlog.threadlocal.clear_threadlocal()` ensures the thread-local storage is empty for each request. +2. `structlog.threadlocal.bind_threadlocal()` puts your key-value pairs into thread-local storage. +3. The `structlog.threadlocal.merge_threadlocal()` processor merges the thread-local context into the event dict. + +Please note that the ``user`` field is only present in the view because it wasn't bound into the thread-local storage. +See `thread-local` for more details. + +---- + +`structlog.stdlib.LoggerFactory` is a totally magic-free class that just deduces the name of the caller's module and does a `logging.getLogger` with it. It's used by `structlog.get_logger` to rid you of logging boilerplate in application code. If you prefer to name your standard library loggers explicitly, a positional argument to `structlog.get_logger` gets passed to the factory and used as the name. From 741506debbff61d27ea5426504a28ecb83c84d86 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 31 Dec 2020 11:53:46 +0100 Subject: [PATCH 0420/1520] Move simplest example to the top --- docs/examples.rst | 91 ++++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/docs/examples.rst b/docs/examples.rst index 33c11637..76db486e 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -3,6 +3,52 @@ Examples This chapter is intended to give you a taste of realistic usage of ``structlog``. +.. _processors-examples: + +Processors +---------- + +:doc:`processors` are a both simple and powerful feature of ``structlog``. + +So you want timestamps as part of the structure of the log entry, censor passwords, filter out log entries below your log level before they even get rendered, and get your output as JSON for convenient parsing? +Here you go: + +.. doctest:: + + >>> import datetime, logging, sys + >>> from structlog import wrap_logger + >>> from structlog.processors import JSONRenderer + >>> from structlog.stdlib import filter_by_level + >>> logging.basicConfig(stream=sys.stdout, format="%(message)s") + >>> def add_timestamp(_, __, event_dict): + ... event_dict["timestamp"] = datetime.datetime.utcnow() + ... return event_dict + >>> def censor_password(_, __, event_dict): + ... pw = event_dict.get("password") + ... if pw: + ... event_dict["password"] = "*CENSORED*" + ... return event_dict + >>> log = wrap_logger( + ... logging.getLogger(__name__), + ... processors=[ + ... filter_by_level, + ... add_timestamp, + ... censor_password, + ... JSONRenderer(indent=1, sort_keys=True) + ... ] + ... ) + >>> log.info("something.filtered") + >>> log.warning("something.not_filtered", password="secret") # doctest: +ELLIPSIS + { + "event": "something.not_filtered", + "password": "*CENSORED*", + "timestamp": "datetime.datetime(..., ..., ..., ..., ...)" + } + +``structlog`` comes with many handy processors build right in. +For a list of shipped processors, check out the :ref:`API documentation `. + + .. _flask-example: @@ -69,48 +115,3 @@ Since Twisted's logging system is a bit peculiar, ``structlog`` ships with an :c I'd also like to point out the Counter class that doesn't do anything spectacular but gets bound *once* per connection to the logger and since its repr is the number itself, it's logged out correctly for each event. This shows off the strength of keeping a dict of objects for context instead of passing around serialized strings. - - -.. _processors-examples: - -Processors ----------- - -:doc:`processors` are a both simple and powerful feature of ``structlog``. - -So you want timestamps as part of the structure of the log entry, censor passwords, filter out log entries below your log level before they even get rendered, and get your output as JSON for convenient parsing? -Here you go: - -.. doctest:: - - >>> import datetime, logging, sys - >>> from structlog import wrap_logger - >>> from structlog.processors import JSONRenderer - >>> from structlog.stdlib import filter_by_level - >>> logging.basicConfig(stream=sys.stdout, format="%(message)s") - >>> def add_timestamp(_, __, event_dict): - ... event_dict["timestamp"] = datetime.datetime.utcnow() - ... return event_dict - >>> def censor_password(_, __, event_dict): - ... pw = event_dict.get("password") - ... if pw: - ... event_dict["password"] = "*CENSORED*" - ... return event_dict - >>> log = wrap_logger( - ... logging.getLogger(__name__), - ... processors=[ - ... filter_by_level, - ... add_timestamp, - ... censor_password, - ... JSONRenderer(indent=1, sort_keys=True) - ... ] - ... ) - >>> log.info("something.filtered") - >>> log.warning("something.not_filtered", password="secret") # doctest: +ELLIPSIS - { - "event": "something.not_filtered", - "password": "*CENSORED*", - "timestamp": "datetime.datetime(..., ..., ..., ..., ...)" - } - -``structlog`` comes with many handy processors build right in -- for a list of shipped processors, check out the :ref:`API documentation `. From e2a2b1b834cb377c0dfbd51044e886bf491c4d2e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 31 Dec 2020 12:01:09 +0100 Subject: [PATCH 0421/1520] We do need the wheel dep for build --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 13a07316..a6ce0f78 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools>=40.6.0"] +requires = ["setuptools>=40.6.0", "wheel"] build-backend = "setuptools.build_meta" From 88111e2390e3b1de2b4c633d823f3d1e56a98a56 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 31 Dec 2020 12:02:24 +0100 Subject: [PATCH 0422/1520] Check build more strictly --- .github/workflows/main.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fb692f52..0b8666df 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -57,12 +57,14 @@ jobs: with: python-version: "3.9" - - name: "Install pep517 and twine" - run: "python -m pip install pep517 twine" + - name: "Install build, check-wheel-content, and twine" + run: "python -m pip install build twine check-wheel-contents" - name: "Build package" - run: "python -m pep517.build --source --binary ." + run: "python -m build --sdist --wheel ." - name: "List result" run: "ls -l dist" + - name: "Check wheel contents" + run: "check-wheel-contents dist/*.whl" - name: "Check long_description" run: "python -m twine check dist/*" From 33dd1f48c9cdce13ae70b1ff92e1d3fa8e4dd8cb Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 31 Dec 2020 12:08:52 +0100 Subject: [PATCH 0423/1520] Add comma --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e25957e9..a0b113cb 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -17,7 +17,7 @@ Backward-incompatible changes: `#244 `_ - ``structlog`` is now fully type-annotated. - This won't break your applications but if you use Mypy, it will most likely break your CI. + This won't break your applications, but if you use Mypy, it will most likely break your CI. Check out the new chapter on typing for details. From 7181d7b15a39cbde596a92e22563039c606de5aa Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 31 Dec 2020 12:13:31 +0100 Subject: [PATCH 0424/1520] Ignore github and twitter in linkcheck They have rate limits. --- docs/conf.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index f7144703..baf67c25 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -152,8 +152,11 @@ def find_version(*file_paths): epub_publisher = author epub_copyright = copyright - -linkcheck_ignore = [] +# GitHub has rate limits +linkcheck_ignore = [ + r"https://github.com/.*/(issues|pull)/\d+", + r"https://twitter.com/.*", +] # Twisted's trac tends to be slow linkcheck_timeout = 300 From aa9ea5bc669841184dbf6ea4d82953a6f47ddee6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 31 Dec 2020 12:19:45 +0100 Subject: [PATCH 0425/1520] Remove dead BitBucket link --- docs/configuration.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.rst b/docs/configuration.rst index 8f3b1ba7..0cd8347c 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -164,6 +164,6 @@ If you use standard library's logging, it makes sense to configure them next to **Twisted** The `plugin definition `_ is the best place. - If your app is not a plugin, put it into your `tac file `_ (and then `learn `_ about plugins). + If your app is not a plugin, put it into your `tac file `_. If you have no choice but *have* to configure on import time in module-global scope, or can't rule out for other reasons that that your `structlog.configure` gets called more than once, ``structlog`` offers `structlog.configure_once` that raises a warning if ``structlog`` has been configured before (no matter whether using `structlog.configure` or :func:`~structlog.configure_once`) but doesn't change anything. From f3a2d1019546df9af7ae52912f32dc04c1a53916 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 31 Dec 2020 12:22:45 +0100 Subject: [PATCH 0426/1520] Prepare 20.2.0 --- CHANGELOG.rst | 2 +- src/structlog/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a0b113cb..7afd3cce 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,7 +5,7 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. -20.2.0 (UNRELEASED) +20.2.0 (2020-12-31) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index ff66d90b..b15460b8 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -42,7 +42,7 @@ contextvars = None # type: ignore -__version__ = "20.2.0.dev0" +__version__ = "20.2.0" __title__ = "structlog" __description__ = "Structured Logging for Python" From b28d63d628ca203b441c5654f9a19f4031a11e8c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 31 Dec 2020 12:28:07 +0100 Subject: [PATCH 0427/1520] Start new development cycle --- CHANGELOG.rst | 25 +++++++++++++++++++++++++ src/structlog/__init__.py | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7afd3cce..f8fa6067 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,31 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. +20.3.0 (UNRELEASED) +------------------- + + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +*none* + + +Deprecations: +^^^^^^^^^^^^^ + +*none* + + +Changes: +^^^^^^^^ + +*none* + + +---- + + 20.2.0 (2020-12-31) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index b15460b8..d6f7f08a 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -42,7 +42,7 @@ contextvars = None # type: ignore -__version__ = "20.2.0" +__version__ = "20.3.0.dev0" __title__ = "structlog" __description__ = "Structured Logging for Python" From de68a2229a69b6bc27d00532d8c26b863740d095 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 31 Dec 2020 12:35:16 +0100 Subject: [PATCH 0428/1520] nope --- src/structlog/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index d6f7f08a..262d92ec 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -42,7 +42,7 @@ contextvars = None # type: ignore -__version__ = "20.3.0.dev0" +__version__ = "21.1.0.dev0" __title__ = "structlog" __description__ = "Structured Logging for Python" From 28614e661bf1bcaae9f22ea53e03eb9f6e765f56 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 31 Dec 2020 12:52:58 +0100 Subject: [PATCH 0429/1520] Also nope --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f8fa6067..6cd4aad3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,7 +5,7 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. -20.3.0 (UNRELEASED) +21.1.0 (UNRELEASED) ------------------- From ec6077a55942f207b3eb810d1e3b852bcfc5dc59 Mon Sep 17 00:00:00 2001 From: Jan Margeta Date: Thu, 31 Dec 2020 17:22:06 +0100 Subject: [PATCH 0430/1520] Fix a typo in Getting started (#289) --- docs/getting-started.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started.rst b/docs/getting-started.rst index f1a9d35a..a4da048c 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -39,7 +39,7 @@ Here, ``structlog`` takes full advantage of its hopefully useful default setting It should be noted that even in most complex logging setups the example would still look just like that thanks to `configuration`. Using the defaults, as above, is equivalent to:: - import loggging + import logging import structlog structlog.configure( From e9e1f68ab8f0f3e2dc2f4b6b5ba7b7e2dc3988bd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 4 Jan 2021 12:52:58 +0100 Subject: [PATCH 0431/1520] Clarify default of ConsoleRenderer's colors param --- docs/api.rst | 2 +- src/structlog/dev.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 08ca999a..b1307da5 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -71,7 +71,7 @@ API Reference .. automodule:: structlog.dev .. autoclass:: ConsoleRenderer - :members: get_default_level_styles + :members: get_default_level_styles .. autofunction:: set_exc_info diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 8011fd34..54b98631 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -123,7 +123,8 @@ class ConsoleRenderer: the log line. :param pad_event: Pad the event to this many characters. - :param colors: Use colors for a nicer output. + :param colors: Use colors for a nicer output. The default is True if + colorama is present, otherwise False. :param force_colors: Force colors even for non-tty destinations. Use this option if your logs are stored in a file that is meant to be streamed to the console. From a2d97164ec21d09a8a09ccb9215eb25223400964 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 4 Jan 2021 13:02:15 +0100 Subject: [PATCH 0432/1520] Update isort URL --- .github/CONTRIBUTING.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst index af252dcd..6f3363a5 100644 --- a/.github/CONTRIBUTING.rst +++ b/.github/CONTRIBUTING.rst @@ -192,4 +192,4 @@ Thank you for considering contributing to ``structlog``! .. _CI: https://github.com/hynek/structlog/actions?query=workflow%3ACI .. _black: https://github.com/psf/black .. _pre-commit: https://pre-commit.com/ -.. _isort: https://github.com/timothycrosley/isort +.. _isort: https://github.com/PyCQA/isort From 81e40f752352519bbf1dc0f240ef274d8f33cfbd Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 4 Jan 2021 18:02:23 +0100 Subject: [PATCH 0433/1520] [pre-commit.ci] pre-commit autoupdate (#291) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6d407190..cb5b82da 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,7 +7,7 @@ repos: language_version: python3.8 - repo: https://github.com/PyCQA/isort - rev: 5.6.4 + rev: 5.7.0 hooks: - id: isort additional_dependencies: [toml] From b9c8aa20f4f5c0443b4b2cd6a9345f07758df8e8 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 5 Jan 2021 08:07:33 +0100 Subject: [PATCH 0434/1520] typing: wrap_dict now wraps Context types fixes #290 --- CHANGELOG.rst | 3 ++- src/structlog/threadlocal.py | 2 +- typing_examples.py | 21 +++++++++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 6cd4aad3..90a51d05 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,7 +24,8 @@ Deprecations: Changes: ^^^^^^^^ -*none* +- ``structlog.threadlocal.wrap_dict()`` now has a correct type annotation. + `#290 `_ ---- diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index e9046425..ea221ace 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -35,7 +35,7 @@ def _determine_threadlocal() -> Type[Any]: ThreadLocal = _determine_threadlocal() -def wrap_dict(dict_class: Type[EventDict]) -> Type[EventDict]: +def wrap_dict(dict_class: Type[Context]) -> Type[Context]: """ Wrap a dict-like class and return the resulting class. diff --git a/typing_examples.py b/typing_examples.py index 900a72ad..33e061bc 100644 --- a/typing_examples.py +++ b/typing_examples.py @@ -187,3 +187,24 @@ def bytes_dumps( wrapper_class=structlog.stdlib.AsyncBoundLogger, cache_logger_on_first_use=True, ) + +# Regression test for +# https://github.com/wemake-services/wemake-django-template/ +structlog.configure( + processors=[ + structlog.stdlib.filter_by_level, + structlog.processors.TimeStamper(fmt="iso"), + structlog.stdlib.add_logger_name, + structlog.stdlib.add_log_level, + structlog.stdlib.PositionalArgumentsFormatter(), + structlog.processors.StackInfoRenderer(), + structlog.processors.format_exc_info, + structlog.processors.UnicodeDecoder(), + structlog.processors.ExceptionPrettyPrinter(), + structlog.stdlib.ProcessorFormatter.wrap_for_formatter, + ], + context_class=structlog.threadlocal.wrap_dict(dict), + logger_factory=structlog.stdlib.LoggerFactory(), + wrapper_class=structlog.stdlib.BoundLogger, + cache_logger_on_first_use=True, +) From bf39fb4c85ed962ab4083857f1c5edd9982eaaf9 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 8 Jan 2021 08:32:56 +0100 Subject: [PATCH 0435/1520] Call out change to default wrapper class Fixes #292 --- CHANGELOG.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 90a51d05..c37aa4d4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -47,6 +47,11 @@ Backward-incompatible changes: Check out the new chapter on typing for details. +- The default bound logger (``wrapper_class``) if you don't configure ``structlog`` has changed. + It's mostly compatible with the old one but a few uncommon methods like ``log``, ``failure``, or ``err`` don't exist anymore. + + You can regain the old behavior by using ``structlog.configure(wrapper_class=structlog.BoundLogger)``. + Deprecations: ^^^^^^^^^^^^^ From 7a6e5a05c096ce4ed6c53ec633e3350a5c51dd73 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 8 Jan 2021 08:50:03 +0100 Subject: [PATCH 0436/1520] Remove PyPy from envlist, make tox -p-friendly --- tox.ini | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index efaba620..d12dd1a9 100644 --- a/tox.ini +++ b/tox.ini @@ -9,7 +9,8 @@ python = [tox] -envlist = lint,mypy,{py36,py37,py38,py39,pypy3}-threads,{py38,py39,pypy3}-greenlets,py38-colorama,docs,pypi-description,manifest,coverage-report +# Currently, pypy3 is broken on macOS. Since we don't need it for coverage, we only test it in CI. +envlist = lint,mypy,{py36,py37,py38,py39}-threads,{py38,py39}-greenlets,py38-colorama,docs,pypi-description,manifest,coverage-report isolated_build = True @@ -97,6 +98,8 @@ commands = check-manifest basepython = python3.8 deps = coverage[toml] skip_install = true +parallel_show_output = true +depends = {py36,py37,py38,py39}-threads,{py38,py39}-greenlets,py38-colorama commands = coverage combine coverage report From fa120c28a4fd512d2177a868c6c72b94b8f555be Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 25 Jan 2021 09:59:57 +0100 Subject: [PATCH 0437/1520] Minor updates --- .github/CONTRIBUTING.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst index 6f3363a5..e7d2b3fd 100644 --- a/.github/CONTRIBUTING.rst +++ b/.github/CONTRIBUTING.rst @@ -23,6 +23,8 @@ Workflow - No contribution is too small! Please submit as many fixes for typos and grammar bloopers as you can! - Try to limit each pull request to *one* change only. +- Since we squash on merge, it's up to you how you handle updates to the master branch. + Whether you prefer to rebase on master or merge master into your branch, do whatever is more comfortable for you. - *Always* add tests and docs for your code. This is a hard rule; patches with missing tests or documentation can't be merged. - Make sure your changes pass our CI_. @@ -67,7 +69,7 @@ Tests - To run the test suite, all you need is a recent tox_. It will ensure the test suite runs with all dependencies against all Python versions just as it will in our CI. - If you lack some Python versions, you can can make it a non-failure using ``tox --skip-missing-interpreters`` (in that case you may want to look into pyenv_ that makes it very easy to install many different Python versions in parallel). + If you lack some Python versions, you can can make it a non-failure using ``tox --skip-missing-interpreters`` (in that case you may want to look into asdf_ or pyenv_ that make it very easy to install many different Python versions in parallel). - Write `good test docstrings`_. @@ -187,6 +189,7 @@ Thank you for considering contributing to ``structlog``! .. _`backward compatibility`: https://www.structlog.org/en/latest/backward-compatibility.html .. _tox: https://tox.readthedocs.io/ .. _pyenv: https://github.com/pyenv/pyenv +.. _asdf: https://asdf-vm.com/ .. _reStructuredText: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html .. _semantic newlines: https://rhodesmill.org/brandon/2012/one-sentence-per-line/ .. _CI: https://github.com/hynek/structlog/actions?query=workflow%3ACI From 24aa1a7c3283075bde88f25c45b31ab063fa22af Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 29 Jan 2021 08:36:59 +0100 Subject: [PATCH 0438/1520] Remove unused # type: ignore Probably caused by mypy 0.800 --- src/structlog/twisted.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index 9edfea54..e37dcab8 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -89,9 +89,7 @@ def _extractStuffAndWhy(eventDict: EventDict) -> Tuple[Any, Any, EventDict]: _why = eventDict.pop("_why", None) event = eventDict.pop("event", None) - if isinstance(_stuff, _FAIL_TYPES) and isinstance( # type: ignore - event, _FAIL_TYPES - ): + if isinstance(_stuff, _FAIL_TYPES) and isinstance(event, _FAIL_TYPES): raise ValueError("Both _stuff and event contain an Exception/Failure.") # `log.err('event', _why='alsoEvent')` is ambiguous. From b7a480306c64e90def6c28cb0b6385560fd4dbe0 Mon Sep 17 00:00:00 2001 From: Kamal Marhubi Date: Fri, 29 Jan 2021 05:33:11 -0500 Subject: [PATCH 0439/1520] Fix type of contextvars.merge_contextvars (#300) With the current type, using it in a processor chain requires a cast to `types.Processor`; replace use of `types.Context` with `types.EventDict` to fix that. Co-authored-by: Hynek Schlawack --- src/structlog/contextvars.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/structlog/contextvars.py b/src/structlog/contextvars.py index 54398c78..af58cd4d 100644 --- a/src/structlog/contextvars.py +++ b/src/structlog/contextvars.py @@ -15,7 +15,7 @@ from typing import Any, Dict -from .types import Context, WrappedLogger +from .types import Context, EventDict, WrappedLogger _CONTEXT: contextvars.ContextVar[Dict[str, Any]] = contextvars.ContextVar( @@ -24,8 +24,8 @@ def merge_contextvars( - logger: WrappedLogger, method_name: str, event_dict: Dict[str, Any] -) -> Context: + logger: WrappedLogger, method_name: str, event_dict: EventDict +) -> EventDict: """ A processor that merges in a global (context-local) context. From e191df70375c804b606c0507047c061fd2bd6fff Mon Sep 17 00:00:00 2001 From: Elad Namdar Date: Thu, 4 Feb 2021 16:28:26 +0200 Subject: [PATCH 0440/1520] contextvars: add test_parallel_binds to expose the bug in the contextvars impl --- tests/test_contextvars.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/test_contextvars.py b/tests/test_contextvars.py index 538507f7..54257fca 100644 --- a/tests/test_contextvars.py +++ b/tests/test_contextvars.py @@ -2,6 +2,8 @@ # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. +import asyncio + import pytest from structlog.contextvars import ( @@ -133,3 +135,36 @@ async def coro(): return merge_contextvars(None, None, {"b": 2}) assert {"b": 2} == await event_loop.create_task(coro()) + + async def test_parallel_binds(self, event_loop): + """ + Binding a variable causes it to be included in the result of + merge_contextvars. + """ + + coro1_bind = asyncio.Event() + coro2_bind = asyncio.Event() + + bind_contextvars(c=3) + + async def coro1(): + bind_contextvars(a=1) + + coro1_bind.set() + await coro2_bind.wait() + + return merge_contextvars(None, None, {"b": 2}) + + async def coro2(): + bind_contextvars(a=2) + + await coro1_bind.wait() + coro2_bind.set() + + return merge_contextvars(None, None, {"b": 2}) + + coro1_task = event_loop.create_task(coro1()) + coro2_task = event_loop.create_task(coro2()) + + assert {"a": 1, "b": 2, "c": 3} == await coro1_task + assert {"a": 2, "b": 2, "c": 3} == await coro2_task From fe3176fa5c9c6a72d645b373fbf655ca1b440826 Mon Sep 17 00:00:00 2001 From: Elad Namdar Date: Thu, 4 Feb 2021 16:28:40 +0200 Subject: [PATCH 0441/1520] Reimpl contextvars code The old impl was broken, since python contextvars impl use shallow copy to copy its context, and using a dict as a contextvar type ends up sharing the same dict among different contexts --- CHANGELOG.rst | 2 ++ src/structlog/contextvars.py | 53 ++++++++++++++++++++++-------------- src/structlog/stdlib.py | 8 +++--- 3 files changed, 38 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c37aa4d4..a6d82a5f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -27,6 +27,8 @@ Changes: - ``structlog.threadlocal.wrap_dict()`` now has a correct type annotation. `#290 `_ +- Fixed bug with ``structlog.contextvars`` impl + ---- diff --git a/src/structlog/contextvars.py b/src/structlog/contextvars.py index af58cd4d..bd3f6576 100644 --- a/src/structlog/contextvars.py +++ b/src/structlog/contextvars.py @@ -7,6 +7,8 @@ Python 3.7 as :mod:`contextvars`. .. versionadded:: 20.1.0 +.. versionchanged:: 14.0.0 + Reimplement code without dict See :doc:`contextvars`. """ @@ -15,12 +17,11 @@ from typing import Any, Dict -from .types import Context, EventDict, WrappedLogger +from .types import EventDict, WrappedLogger -_CONTEXT: contextvars.ContextVar[Dict[str, Any]] = contextvars.ContextVar( - "structlog_context" -) +STRUCTLOG_KEY_PREFIX = "structlog_" +_CONTEXT_VARS: Dict[str, contextvars.ContextVar[Any]] = {} def merge_contextvars( @@ -33,11 +34,15 @@ def merge_contextvars( context-local context is included in all log calls. .. versionadded:: 20.1.0 + .. versionchanged:: 20.2.0 See toplevel note """ - ctx = _get_context().copy() - ctx.update(event_dict) + ctx = contextvars.copy_context() - return ctx + for k in ctx: + if k.name.startswith(STRUCTLOG_KEY_PREFIX) and ctx[k] is not Ellipsis: + event_dict.setdefault(k.name[len(STRUCTLOG_KEY_PREFIX):], ctx[k]) # noqa + + return event_dict def clear_contextvars() -> None: @@ -48,9 +53,12 @@ def clear_contextvars() -> None: handling code. .. versionadded:: 20.1.0 + .. versionchanged:: 20.2.0 See toplevel note """ - ctx = _get_context() - ctx.clear() + ctx = contextvars.copy_context() + for k in ctx: + if k.name.startswith(STRUCTLOG_KEY_PREFIX): + k.set(Ellipsis) def bind_contextvars(**kw: Any) -> None: @@ -61,8 +69,17 @@ def bind_contextvars(**kw: Any) -> None: context to be global (context-local). .. versionadded:: 20.1.0 + .. versionchanged:: 20.2.0 See toplevel note """ - _get_context().update(kw) + for k, v in kw.items(): + structlog_k = f"{STRUCTLOG_KEY_PREFIX}{k}" + try: + var = _CONTEXT_VARS[structlog_k] + except KeyError: + var = contextvars.ContextVar(structlog_k, default=Ellipsis) + _CONTEXT_VARS[structlog_k] = var + + var.set(v) def unbind_contextvars(*keys: str) -> None: @@ -73,15 +90,9 @@ def unbind_contextvars(*keys: str) -> None: remove keys from a global (context-local) context. .. versionadded:: 20.1.0 + .. versionchanged:: 20.2.0 See toplevel note """ - ctx = _get_context() - for key in keys: - ctx.pop(key, None) - - -def _get_context() -> Context: - try: - return _CONTEXT.get() - except LookupError: - _CONTEXT.set({}) - return _CONTEXT.get() + for k in keys: + structlog_k = f"{STRUCTLOG_KEY_PREFIX}{k}" + if structlog_k in _CONTEXT_VARS: + _CONTEXT_VARS[structlog_k].set(Ellipsis) diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 6aa7d17f..dbd5d83b 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -34,7 +34,7 @@ try: - from . import contextvars + import contextvars except ImportError: contextvars = None # type: ignore @@ -380,6 +380,7 @@ class AsyncBoundLogger: It is useful to be able to log synchronously occasionally. .. versionadded:: 20.2.0 + .. versionchanged:: 20.2.0 fix _dispatch_to_sync contextvars usage """ __slots__ = ["sync_bl", "_loop"] @@ -474,11 +475,10 @@ async def _dispatch_to_sync( """ Merge contextvars and log using the sync logger in a thread pool. """ - ctx = contextvars._get_context().copy() - ctx.update(kw) + ctx = contextvars.copy_context() await self._loop.run_in_executor( - self._executor, partial(meth, event, *args, **ctx) + self._executor, partial(ctx.run, partial(meth, event, *args, **kw)) ) async def debug(self, event: str, *args: Any, **kw: Any) -> None: From 827d96b086c474a4f79ba876f4acac2a6cfb4702 Mon Sep 17 00:00:00 2001 From: Elad Namdar Date: Thu, 4 Feb 2021 16:31:18 +0200 Subject: [PATCH 0442/1520] contextvars: fix broken test_nested_async_bind test --- tests/test_contextvars.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_contextvars.py b/tests/test_contextvars.py index 54257fca..892f7056 100644 --- a/tests/test_contextvars.py +++ b/tests/test_contextvars.py @@ -56,11 +56,11 @@ async def test_nested_async_bind(self, event_loop): async def coro(): bind_contextvars(a=1) - await event_loop.create_task(nested_coro()) - return merge_contextvars(None, None, {"b": 2}) + return await event_loop.create_task(nested_coro()) async def nested_coro(): bind_contextvars(c=3) + return merge_contextvars(None, None, {"b": 2}) assert {"a": 1, "b": 2, "c": 3} == await event_loop.create_task(coro()) From 00bf80d6e2886e12f4223cfc869231b444c16364 Mon Sep 17 00:00:00 2001 From: Elad Namdar Date: Thu, 4 Feb 2021 17:17:08 +0200 Subject: [PATCH 0443/1520] Fix contextvars docs --- docs/contextvars.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/contextvars.rst b/docs/contextvars.rst index 70e1a3a1..6ed9e28b 100644 --- a/docs/contextvars.rst +++ b/docs/contextvars.rst @@ -50,11 +50,11 @@ The general flow is: >>> # Then use loggers as per normal >>> # (perhaps by using structlog.get_logger() to create them). >>> log.msg("hello") - a=1 b=2 event='hello' + event='hello' a=1 b=2 >>> # Use unbind_contextvars to remove a variable from the context >>> unbind_contextvars("b") >>> log.msg("world") - a=1 event='world' + event='world' a=1 >>> # And when we clear the threadlocal state again, it goes away. >>> clear_contextvars() >>> log.msg("hi there") From e9eed3bb5f4e2e28b1e3352a2ea3effffc781eaa Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 4 Feb 2021 15:21:00 +0000 Subject: [PATCH 0444/1520] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/structlog/contextvars.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/structlog/contextvars.py b/src/structlog/contextvars.py index bd3f6576..6133560c 100644 --- a/src/structlog/contextvars.py +++ b/src/structlog/contextvars.py @@ -40,7 +40,9 @@ def merge_contextvars( for k in ctx: if k.name.startswith(STRUCTLOG_KEY_PREFIX) and ctx[k] is not Ellipsis: - event_dict.setdefault(k.name[len(STRUCTLOG_KEY_PREFIX):], ctx[k]) # noqa + event_dict.setdefault( + k.name[len(STRUCTLOG_KEY_PREFIX) :], ctx[k] + ) # noqa return event_dict From 12f580451d0206cb31f118ab8b37d79a6bcb3fde Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 18 Feb 2021 06:59:15 +0100 Subject: [PATCH 0445/1520] whitespace --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index a6ce0f78..beda7562 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,7 +27,7 @@ exclude_lines = [ "pragma: no cover", "if TYPE_CHECKING:", "raise NotImplementedError", - # typing-related code + # typing-related code "^if (False|TYPE_CHECKING):", ": \\.\\.\\.$", "^ +\\.\\.\\.$", From bca6527fadc61bc9586d21b316e6d29217d341fd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 18 Feb 2021 07:02:00 +0100 Subject: [PATCH 0446/1520] Fix example It doesn't need wrap_dict anymore. ref https://github.com/hynek/structlog/issues/294#issuecomment-781073763 --- docs/code_examples/flask_/webapp.py | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/code_examples/flask_/webapp.py b/docs/code_examples/flask_/webapp.py index e08e063d..3940e9bd 100644 --- a/docs/code_examples/flask_/webapp.py +++ b/docs/code_examples/flask_/webapp.py @@ -46,7 +46,6 @@ def some_route(): key_order=["event", "view", "peer"] ), ], - context_class=structlog.threadlocal.wrap_dict(dict), logger_factory=structlog.stdlib.LoggerFactory(), ) app.run() From 20c206ec46de9b79830bb0fafc5a77502a57bbe5 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 18 Feb 2021 07:18:17 +0100 Subject: [PATCH 0447/1520] flake8: mute stray errors --- tox.ini | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tox.ini b/tox.ini index d12dd1a9..72bb910a 100644 --- a/tox.ini +++ b/tox.ini @@ -1,3 +1,6 @@ +[flake8] +ignore = E203,W503,W504 + # Keep docs in sync with docs env and .readthedocs.yml. [gh-actions] python = From 95e657bc2f992bacc65073eaa2e93fba7967ac56 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 18 Feb 2021 07:24:27 +0100 Subject: [PATCH 0448/1520] Somewhat improve changelog --- CHANGELOG.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a6d82a5f..bd257e76 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -26,8 +26,8 @@ Changes: - ``structlog.threadlocal.wrap_dict()`` now has a correct type annotation. `#290 `_ - -- Fixed bug with ``structlog.contextvars`` impl +- Fix isolation in ``structlog.contextvars``. + `#302 `_ ---- From a2c2553f1a9e1884d7d43e003af56fcd74a2ea34 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 18 Feb 2021 07:27:24 +0100 Subject: [PATCH 0449/1520] Fix version tags --- src/structlog/contextvars.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/structlog/contextvars.py b/src/structlog/contextvars.py index 6133560c..e6f86a0a 100644 --- a/src/structlog/contextvars.py +++ b/src/structlog/contextvars.py @@ -7,7 +7,7 @@ Python 3.7 as :mod:`contextvars`. .. versionadded:: 20.1.0 -.. versionchanged:: 14.0.0 +.. versionchanged:: 21.1.0 Reimplement code without dict See :doc:`contextvars`. @@ -34,7 +34,7 @@ def merge_contextvars( context-local context is included in all log calls. .. versionadded:: 20.1.0 - .. versionchanged:: 20.2.0 See toplevel note + .. versionchanged:: 21.1.0 See toplevel note. """ ctx = contextvars.copy_context() @@ -55,7 +55,7 @@ def clear_contextvars() -> None: handling code. .. versionadded:: 20.1.0 - .. versionchanged:: 20.2.0 See toplevel note + .. versionchanged:: 21.1.0 See toplevel note. """ ctx = contextvars.copy_context() for k in ctx: @@ -71,7 +71,7 @@ def bind_contextvars(**kw: Any) -> None: context to be global (context-local). .. versionadded:: 20.1.0 - .. versionchanged:: 20.2.0 See toplevel note + .. versionchanged:: 21.1.0 See toplevel note. """ for k, v in kw.items(): structlog_k = f"{STRUCTLOG_KEY_PREFIX}{k}" @@ -92,7 +92,7 @@ def unbind_contextvars(*keys: str) -> None: remove keys from a global (context-local) context. .. versionadded:: 20.1.0 - .. versionchanged:: 20.2.0 See toplevel note + .. versionchanged:: 21.1.0 See toplevel note. """ for k in keys: structlog_k = f"{STRUCTLOG_KEY_PREFIX}{k}" From 6bdaec56a6d43d65337c70d8103b30e20abe0bf0 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 18 Feb 2021 07:44:19 +0100 Subject: [PATCH 0450/1520] Improve test coverage --- docs/contextvars.rst | 3 ++- src/structlog/contextvars.py | 3 ++- tests/test_contextvars.py | 10 +++++++--- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/docs/contextvars.rst b/docs/contextvars.rst index 6ed9e28b..f581900f 100644 --- a/docs/contextvars.rst +++ b/docs/contextvars.rst @@ -46,7 +46,8 @@ The general flow is: >>> # middleware), clear the threadlocal context and bind some common >>> # values: >>> clear_contextvars() - >>> bind_contextvars(a=1, b=2) + >>> bind_contextvars(a=1) + >>> bind_contextvars(b=2) >>> # Then use loggers as per normal >>> # (perhaps by using structlog.get_logger() to create them). >>> log.msg("hello") diff --git a/src/structlog/contextvars.py b/src/structlog/contextvars.py index e6f86a0a..7c8a5a1f 100644 --- a/src/structlog/contextvars.py +++ b/src/structlog/contextvars.py @@ -8,7 +8,8 @@ .. versionadded:: 20.1.0 .. versionchanged:: 21.1.0 - Reimplement code without dict + Reimplemented without using a single dict as context carrier for improved + isolation. Every key-value pair is a separate `contextvars.ContextVar` now. See :doc:`contextvars`. """ diff --git a/tests/test_contextvars.py b/tests/test_contextvars.py index 892f7056..df016612 100644 --- a/tests/test_contextvars.py +++ b/tests/test_contextvars.py @@ -3,6 +3,7 @@ # repository for complete details. import asyncio +import secrets import pytest @@ -112,7 +113,7 @@ async def coro(): assert {} == await event_loop.create_task(coro()) - async def test_undbind(self, event_loop): + async def test_unbind(self, event_loop): """ Unbinding a previously bound variable causes it to be removed from the result of merge_contextvars. @@ -125,13 +126,16 @@ async def coro(): assert {"b": 2} == await event_loop.create_task(coro()) - async def test_undbind_not_bound(self, event_loop): + async def test_unbind_not_bound(self, event_loop): """ Unbinding a not bound variable causes doesn't raise an exception. """ async def coro(): - unbind_contextvars("a") + # Since unbinding means "setting to Ellipsis", we have to make + # some effort to ensure that the ContextVar never existed. + unbind_contextvars("a" + secrets.token_hex()) + return merge_contextvars(None, None, {"b": 2}) assert {"b": 2} == await event_loop.create_task(coro()) From 765d7f0947785a5ab81bc6e9e328147466dacc01 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 18 Feb 2021 07:56:03 +0100 Subject: [PATCH 0451/1520] Simplify --- src/structlog/contextvars.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/structlog/contextvars.py b/src/structlog/contextvars.py index 7c8a5a1f..17796151 100644 --- a/src/structlog/contextvars.py +++ b/src/structlog/contextvars.py @@ -41,9 +41,7 @@ def merge_contextvars( for k in ctx: if k.name.startswith(STRUCTLOG_KEY_PREFIX) and ctx[k] is not Ellipsis: - event_dict.setdefault( - k.name[len(STRUCTLOG_KEY_PREFIX) :], ctx[k] - ) # noqa + event_dict.setdefault(k.name[len(STRUCTLOG_KEY_PREFIX) :], ctx[k]) return event_dict From 71727c9123144e6ece2c385fca7b3df0f6ef2d0a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 18 Feb 2021 08:01:37 +0100 Subject: [PATCH 0452/1520] Fix key order in contextvar docs once and for all --- docs/contextvars.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/contextvars.rst b/docs/contextvars.rst index f581900f..33bd079e 100644 --- a/docs/contextvars.rst +++ b/docs/contextvars.rst @@ -38,7 +38,7 @@ The general flow is: >>> configure( ... processors=[ ... merge_contextvars, - ... structlog.processors.KeyValueRenderer(), + ... structlog.processors.KeyValueRenderer(key_order=["event", "a"]), ... ] ... ) >>> log = structlog.get_logger() @@ -46,8 +46,7 @@ The general flow is: >>> # middleware), clear the threadlocal context and bind some common >>> # values: >>> clear_contextvars() - >>> bind_contextvars(a=1) - >>> bind_contextvars(b=2) + >>> bind_contextvars(a=1, b=2) >>> # Then use loggers as per normal >>> # (perhaps by using structlog.get_logger() to create them). >>> log.msg("hello") @@ -57,6 +56,8 @@ The general flow is: >>> log.msg("world") event='world' a=1 >>> # And when we clear the threadlocal state again, it goes away. + >>> # a=None is printed due to the key_order argument passed to + >>> # KeyValueRenderer, but it is NOT present anymore. >>> clear_contextvars() >>> log.msg("hi there") - event='hi there' + event='hi there' a=None From a9bed6fe875958d53f1fded1a7e18b0206c61300 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 18 Feb 2021 08:12:59 +0100 Subject: [PATCH 0453/1520] Anarchy! --- .github/CONTRIBUTING.rst | 8 ++++---- .github/PULL_REQUEST_TEMPLATE.md | 4 ++-- .github/workflows/main.yml | 4 ++-- docs/license.rst | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst index e7d2b3fd..78eb2ae1 100644 --- a/.github/CONTRIBUTING.rst +++ b/.github/CONTRIBUTING.rst @@ -23,8 +23,8 @@ Workflow - No contribution is too small! Please submit as many fixes for typos and grammar bloopers as you can! - Try to limit each pull request to *one* change only. -- Since we squash on merge, it's up to you how you handle updates to the master branch. - Whether you prefer to rebase on master or merge master into your branch, do whatever is more comfortable for you. +- Since we squash on merge, it's up to you how you handle updates to the main branch. + Whether you prefer to rebase on main or merge main into your branch, do whatever is more comfortable for you. - *Always* add tests and docs for your code. This is a hard rule; patches with missing tests or documentation can't be merged. - Make sure your changes pass our CI_. @@ -184,8 +184,8 @@ Thank you for considering contributing to ``structlog``! .. _`PEP 8`: https://www.python.org/dev/peps/pep-0008/ .. _`PEP 257`: https://www.python.org/dev/peps/pep-0257/ .. _`good test docstrings`: https://jml.io/pages/test-docstrings.html -.. _`Code of Conduct`: https://github.com/hynek/structlog/blob/master/.github/CODE_OF_CONDUCT.rst -.. _changelog: https://github.com/hynek/structlog/blob/master/CHANGELOG.rst +.. _`Code of Conduct`: https://github.com/hynek/structlog/blob/main/.github/CODE_OF_CONDUCT.rst +.. _changelog: https://github.com/hynek/structlog/blob/main/CHANGELOG.rst .. _`backward compatibility`: https://www.structlog.org/en/latest/backward-compatibility.html .. _tox: https://tox.readthedocs.io/ .. _pyenv: https://github.com/pyenv/pyenv diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 2648a078..7755e4c2 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -7,8 +7,8 @@ If an item doesn't apply to your pull request, **check it anyway** to make it ap - [ ] Added **tests** for changed code. - [ ] Updated **documentation** for changed code. - [ ] New functions/classes have to be added to `docs/api.rst` by hand. - - [ ] Changed/added classes/methods/functions have appropriate `versionadded`, `versionchanged`, or `deprecated` [directives](http://www.sphinx-doc.org/en/stable/markup/para.html#directive-versionadded). Find the appropriate next version in our [``__init__.py``](https://github.com/hynek/structlog/blob/master/src/structlog/__init__.py) file. + - [ ] Changed/added classes/methods/functions have appropriate `versionadded`, `versionchanged`, or `deprecated` [directives](http://www.sphinx-doc.org/en/stable/markup/para.html#directive-versionadded). Find the appropriate next version in our [``__init__.py``](https://github.com/hynek/structlog/blob/main/src/structlog/__init__.py) file. - [ ] Documentation in `.rst` files is written using [semantic newlines](https://rhodesmill.org/brandon/2012/one-sentence-per-line/). -- [ ] Changes (and possible deprecations) are documented in the [changelog](https://github.com/hynek/structlog/blob/master/CHANGELOG.rst). +- [ ] Changes (and possible deprecations) are documented in the [changelog](https://github.com/hynek/structlog/blob/main/CHANGELOG.rst). If you have *any* questions to *any* of the points above, just **submit and ask**! This checklist is here to *help* you, not to deter you from contributing! diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0b8666df..e6914470 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -3,9 +3,9 @@ name: CI on: push: - branches: ["master"] + branches: ["main"] pull_request: - branches: ["master"] + branches: ["main"] workflow_dispatch: jobs: diff --git a/docs/license.rst b/docs/license.rst index ce16c9d7..d9bd3d9a 100644 --- a/docs/license.rst +++ b/docs/license.rst @@ -8,8 +8,8 @@ For more legal details, see `this issue `_ -- `MIT `_ +- `Apache License 2.0 `_ +- `MIT `_ .. _authors: From 334f0297549e3464204d2407e8b8eb4ebd732411 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 18 Feb 2021 09:30:30 +0100 Subject: [PATCH 0454/1520] Make filtering loggers pickleable --- CHANGELOG.rst | 2 ++ src/structlog/_log_levels.py | 30 ++++++++++++++++++++++++++++++ tests/test_log_levels.py | 11 +++++++++++ 3 files changed, 43 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index bd257e76..4c1adb3d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -28,6 +28,8 @@ Changes: `#290 `_ - Fix isolation in ``structlog.contextvars``. `#302 `_ +- The default configuration and loggers are pickleable again. + `#301 `_ ---- diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index 5b7dae18..58942b9b 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -94,6 +94,18 @@ def make_filtering_bound_logger(min_level: int) -> Type[FilteringBoundLogger]: values. .. versionadded:: 20.2.0 + .. versionchanged:: 21.1.0 The returned loggers are now pickleable. + """ + + return _LEVEL_TO_FILTERING_LOGGER[min_level] + + +def _make_filtering_bound_logger(min_level: int) -> Type[FilteringBoundLogger]: + """ + Create a new `FilteringBoundLogger` that only logs *min_level* or higher. + + The logger is optimized such that log levels below *min_level* only consist + of a ``return None``. """ def make_method(level: int) -> Callable[..., Any]: @@ -124,3 +136,21 @@ def meth(self: Any, event: str, **kw: Any) -> Any: (BoundLoggerBase,), meths, ) + + +# Pre-create all possible filters to make them pickleable. +BoundLoggerFilteringAtNotset = _make_filtering_bound_logger(NOTSET) +BoundLoggerFilteringAtDebug = _make_filtering_bound_logger(DEBUG) +BoundLoggerFilteringAtInfo = _make_filtering_bound_logger(INFO) +BoundLoggerFilteringAtWarning = _make_filtering_bound_logger(WARNING) +BoundLoggerFilteringAtError = _make_filtering_bound_logger(ERROR) +BoundLoggerFilteringAtCritical = _make_filtering_bound_logger(CRITICAL) + +_LEVEL_TO_FILTERING_LOGGER = { + CRITICAL: BoundLoggerFilteringAtCritical, + ERROR: BoundLoggerFilteringAtError, + WARNING: BoundLoggerFilteringAtWarning, + INFO: BoundLoggerFilteringAtInfo, + DEBUG: BoundLoggerFilteringAtDebug, + NOTSET: BoundLoggerFilteringAtNotset, +} diff --git a/tests/test_log_levels.py b/tests/test_log_levels.py index edc288d9..1253475a 100644 --- a/tests/test_log_levels.py +++ b/tests/test_log_levels.py @@ -3,10 +3,12 @@ # repository for complete details. import logging +import pickle import pytest from structlog import make_filtering_bound_logger +from structlog._log_levels import _LEVEL_TO_NAME from structlog.testing import CapturingLogger @@ -53,3 +55,12 @@ def test_exception_passed(self, bl, cl): bl.exception("boom", exc_info=42) assert [("error", (), {"event": "boom", "exc_info": 42})] + + @pytest.mark.parametrize("level", tuple(_LEVEL_TO_NAME.keys())) + def test_pickle(self, level): + """ + FilteringBoundLogger are pickleable. + """ + bl = make_filtering_bound_logger(level) + + assert bl == pickle.loads(pickle.dumps(bl)) From 716970990694aec75db2ba8535cc5d838538fbb1 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 18 Feb 2021 15:49:36 +0100 Subject: [PATCH 0455/1520] Strengthen point of bw compat & default settings --- CHANGELOG.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4c1adb3d..f099ada6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -56,6 +56,9 @@ Backward-incompatible changes: You can regain the old behavior by using ``structlog.configure(wrapper_class=structlog.BoundLogger)``. + Please note that due to the various interactions between settings, it's possible that you encounter even more errors. + We **strongly** urge you to always configure all possible settings since the default configuration is *not* covered by our `backward compatibility policy `_. + Deprecations: ^^^^^^^^^^^^^ From b0be0441d0a6ad92059f16d662f8d67de7925619 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 18 Feb 2021 16:13:04 +0100 Subject: [PATCH 0456/1520] Allow look for `logger_name` in ConsoleRenderer Fixes #295 --- CHANGELOG.rst | 3 +++ src/structlog/dev.py | 5 +++++ tests/test_config.py | 4 ++-- tests/test_dev.py | 43 +++++++++++++++++++++++++++++-------------- 4 files changed, 39 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f099ada6..fad181bf 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -30,6 +30,9 @@ Changes: `#302 `_ - The default configuration and loggers are pickleable again. `#301 `_ +- ``structlog.dev.ConsoleRenderer`` will now look for a ``logger_name`` key if no + ``logger`` key is set. + `#295 `_ ---- diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 54b98631..4565d5b2 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -153,6 +153,8 @@ class ConsoleRenderer: .. versionchanged:: 19.2 Can be pickled now. .. versionchanged:: 20.1 ``colorama`` does not initialize lazily on Windows anymore because it breaks rendering. + .. versionchanged: 21.1 It is additionally possible to set the logger name + using the ``logger_name`` key in the ``event_dict``. """ def __init__( @@ -255,6 +257,9 @@ def __call__( sio.write(self._styles.bright + event) logger_name = event_dict.pop("logger", None) + if logger_name is None: + logger_name = event_dict.pop("logger_name", None) + if logger_name is not None: sio.write( "[" diff --git a/tests/test_config.py b/tests/test_config.py index 3b46f46f..1f9edb41 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -28,8 +28,8 @@ ) -@pytest.fixture -def proxy(): +@pytest.fixture(name="proxy") +def _proxy(): """ Returns a BoundLoggerLazyProxy constructed w/o parameters & None as logger. """ diff --git a/tests/test_dev.py b/tests/test_dev.py index e20f4d9b..b94da4b8 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -23,25 +23,25 @@ def test_negative(self): assert len("test") == len(dev._pad("test", 2)) -@pytest.fixture -def cr(): +@pytest.fixture(name="cr") +def _cr(): return dev.ConsoleRenderer(colors=dev._has_colorama) -@pytest.fixture -def styles(cr): +@pytest.fixture(name="styles") +def _styles(cr): return cr._styles -@pytest.fixture -def padded(styles): +@pytest.fixture(name="padded") +def _padded(styles): return ( styles.bright + dev._pad("test", dev._EVENT_WIDTH) + styles.reset + " " ) -@pytest.fixture -def unpadded(styles): +@pytest.fixture(name="unpadded") +def _unpadded(styles): return styles.bright + "test" + styles.reset @@ -139,14 +139,29 @@ def test_logger_name(self, cr, styles, padded): """ rv = cr(None, None, {"event": "test", "logger": "some_module"}) - # fmt: off assert ( - padded + - "[" + dev.BLUE + styles.bright + - "some_module" + - styles.reset + "] " + padded + + "[" + + dev.BLUE + + styles.bright + + "some_module" + + styles.reset + + "] " ) == rv - # fmt: on + + def test_logger_name_name(self, cr, padded, styles): + """ + It's possible to set the logger name using a "logger_name" key. + """ + assert ( + padded + + "[" + + dev.BLUE + + styles.bright + + "yolo" + + styles.reset + + "] " + ) == cr(None, None, {"event": "test", "logger_name": "yolo"}) def test_key_values(self, cr, styles, padded): """ From 0b14ec046dfcf50337da9c46e99cffddccaef36d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 18 Feb 2021 16:18:44 +0100 Subject: [PATCH 0457/1520] Let Black go brrrr We're ignoring the warning/errors anyways. --- tests/test_dev.py | 165 ++++++++++++++++++++++++++++++---------------- 1 file changed, 107 insertions(+), 58 deletions(-) diff --git a/tests/test_dev.py b/tests/test_dev.py index b94da4b8..da2117ae 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -94,16 +94,22 @@ def test_level(self, cr, styles, padded): None, None, {"event": "test", "level": "critical", "foo": "bar"} ) - # fmt: off assert ( - "[" + dev.RED + styles.bright + - dev._pad("critical", cr._longest_level) + - styles.reset + "] " + - padded + - styles.kv_key + "foo" + styles.reset + "=" + - styles.kv_value + "bar" + styles.reset + "[" + + dev.RED + + styles.bright + + dev._pad("critical", cr._longest_level) + + styles.reset + + "] " + + padded + + styles.kv_key + + "foo" + + styles.reset + + "=" + + styles.kv_value + + "bar" + + styles.reset ) == rv - # fmt: on def test_init_accepts_overriding_levels(self, styles, padded): """ @@ -122,16 +128,22 @@ def test_init_accepts_overriding_levels(self, styles, padded): None, None, {"event": "test", "level": "MY_OH_MY", "foo": "bar"} ) - # fmt: off assert ( - "[" + dev.RED + styles.bright + - dev._pad("MY_OH_MY", cr._longest_level) + - styles.reset + "] " + - padded + - styles.kv_key + "foo" + styles.reset + "=" + - styles.kv_value + "bar" + styles.reset + "[" + + dev.RED + + styles.bright + + dev._pad("MY_OH_MY", cr._longest_level) + + styles.reset + + "] " + + padded + + styles.kv_key + + "foo" + + styles.reset + + "=" + + styles.kv_value + + "bar" + + styles.reset ) == rv - # fmt: on def test_logger_name(self, cr, styles, padded): """ @@ -169,17 +181,24 @@ def test_key_values(self, cr, styles, padded): """ rv = cr(None, None, {"event": "test", "key": "value", "foo": "bar"}) - # fmt: off assert ( - padded + - styles.kv_key + "foo" + styles.reset + "=" + - styles.kv_value + "bar" + - styles.reset + " " + - styles.kv_key + "key" + styles.reset + "=" + - styles.kv_value + "value" + - styles.reset + padded + + styles.kv_key + + "foo" + + styles.reset + + "=" + + styles.kv_value + + "bar" + + styles.reset + + " " + + styles.kv_key + + "key" + + styles.reset + + "=" + + styles.kv_value + + "value" + + styles.reset ) == rv - # fmt: on def test_exception(self, cr, padded): """ @@ -208,15 +227,19 @@ def test_pad_event_param(self, styles): None, None, {"event": "test", "foo": "bar"} ) - # fmt: off assert ( - styles.bright + - dev._pad("test", 42) + - styles.reset + " " + - styles.kv_key + "foo" + styles.reset + "=" + - styles.kv_value + "bar" + styles.reset + styles.bright + + dev._pad("test", 42) + + styles.reset + + " " + + styles.kv_key + + "foo" + + styles.reset + + "=" + + styles.kv_value + + "bar" + + styles.reset ) == rv - # fmt: on def test_everything(self, cr, styles, padded): """ @@ -240,26 +263,46 @@ def test_everything(self, cr, styles, padded): }, ) - # fmt: off assert ( - styles.timestamp + "13:13" + styles.reset + - " [" + styles.level_error + styles.bright + - dev._pad("error", cr._longest_level) + - styles.reset + "] " + - padded + - "[" + dev.BLUE + styles.bright + - "some_module" + - styles.reset + "] " + - styles.kv_key + "foo" + styles.reset + "=" + - styles.kv_value + "bar" + - styles.reset + " " + - styles.kv_key + "key" + styles.reset + "=" + - styles.kv_value + "value" + - styles.reset + - "\n" + stack + "\n\n" + "=" * 79 + "\n" + - "\n" + exc + styles.timestamp + + "13:13" + + styles.reset + + " [" + + styles.level_error + + styles.bright + + dev._pad("error", cr._longest_level) + + styles.reset + + "] " + + padded + + "[" + + dev.BLUE + + styles.bright + + "some_module" + + styles.reset + + "] " + + styles.kv_key + + "foo" + + styles.reset + + "=" + + styles.kv_value + + "bar" + + styles.reset + + " " + + styles.kv_key + + "key" + + styles.reset + + "=" + + styles.kv_value + + "value" + + styles.reset + + "\n" + + stack + + "\n\n" + + "=" * 79 + + "\n" + + "\n" + + exc ) == rv - # fmt: on def test_colorama_colors_false(self): """ @@ -286,16 +329,22 @@ def test_colorama_force_colors(self, styles, padded): None, None, {"event": "test", "level": "critical", "foo": "bar"} ) - # fmt: off assert ( - "[" + dev.RED + styles.bright + - dev._pad("critical", cr._longest_level) + - styles.reset + "] " + - padded + - styles.kv_key + "foo" + styles.reset + "=" + - styles.kv_value + "bar" + styles.reset + "[" + + dev.RED + + styles.bright + + dev._pad("critical", cr._longest_level) + + styles.reset + + "] " + + padded + + styles.kv_key + + "foo" + + styles.reset + + "=" + + styles.kv_value + + "bar" + + styles.reset ) == rv - # fmt: on assert not dev._has_colorama or dev._ColorfulStyles is cr._styles From 5b5a6c947decb7ccefa76646ca6c28cefd5697bb Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 18 Feb 2021 17:02:08 +0100 Subject: [PATCH 0458/1520] Prepare 21.1.0 --- CHANGELOG.rst | 2 +- src/structlog/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index fad181bf..4d012c42 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,7 +5,7 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. -21.1.0 (UNRELEASED) +21.1.0 (2021-02-18) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 262d92ec..e0d445d1 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -42,7 +42,7 @@ contextvars = None # type: ignore -__version__ = "21.1.0.dev0" +__version__ = "21.1.0" __title__ = "structlog" __description__ = "Structured Logging for Python" From 5d84526e43ee34a2addf4673cbca3abdf408fda2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 18 Feb 2021 17:06:32 +0100 Subject: [PATCH 0459/1520] Start new development cycle --- CHANGELOG.rst | 25 +++++++++++++++++++++++++ src/structlog/__init__.py | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4d012c42..aeeb356e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,31 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. +21.2.0 (UNRELEASED) +------------------- + + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +*none* + + +Deprecations: +^^^^^^^^^^^^^ + +*none* + + +Changes: +^^^^^^^^ + +*none* + + +---- + + 21.1.0 (2021-02-18) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index e0d445d1..980ccd0a 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -42,7 +42,7 @@ contextvars = None # type: ignore -__version__ = "21.1.0" +__version__ = "21.2.0.dev0" __title__ = "structlog" __description__ = "Structured Logging for Python" From 4dd01ecafe29f33e9f8f20ee7dbeabc35901d6da Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 5 Mar 2021 10:18:18 +0100 Subject: [PATCH 0460/1520] Document entries attribute --- docs/conf.py | 2 ++ src/structlog/testing.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/docs/conf.py b/docs/conf.py index baf67c25..20ee2da1 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -74,7 +74,9 @@ def find_version(*file_paths): ("py:class", "TextIO"), ("py:class", "structlog._base.BoundLoggerBase"), ("py:class", "structlog.dev._Styles"), + ("py:class", "structlog.types.EventDict"), ("py:obj", "sync_bl"), + ("py:obj", "entries"), ] # If true, '()' will be appended to :func: etc. cross-reference text. diff --git a/src/structlog/testing.py b/src/structlog/testing.py index 9f5dfbb6..bfae4219 100644 --- a/src/structlog/testing.py +++ b/src/structlog/testing.py @@ -27,6 +27,8 @@ class LogCapture: Generally you should use `structlog.testing.capture_logs`, but you can use this class if you want to capture logs with other patterns. + :ivar List[structlog.types.EventDict] entries: The captured log entries. + .. versionadded:: 20.1.0 """ From 32b5dc7c9a8f14dc293b400ef74856c78d2668c4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 15 Mar 2021 19:38:54 +0100 Subject: [PATCH 0461/1520] [pre-commit.ci] pre-commit autoupdate (#306) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cb5b82da..956d2bdd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,7 +14,7 @@ repos: language_version: python3.8 - repo: https://gitlab.com/pycqa/flake8 - rev: 3.8.4 + rev: 3.9.0 hooks: - id: flake8 language_version: python3.8 From 592abda0b6bf1b83a34a78b59c3b8575b6a0275e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 22 Mar 2021 18:08:01 +0100 Subject: [PATCH 0462/1520] [pre-commit.ci] pre-commit autoupdate (#307) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 956d2bdd..d30b55bb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,7 +7,7 @@ repos: language_version: python3.8 - repo: https://github.com/PyCQA/isort - rev: 5.7.0 + rev: 5.8.0 hooks: - id: isort additional_dependencies: [toml] From ce0986cc74cf4aadd2985fa17854e6103ec48dbd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 1 Apr 2021 16:36:11 +0200 Subject: [PATCH 0463/1520] Fix typo Use dashes to signify inserted sentence. --- docs/loggers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/loggers.rst b/docs/loggers.rst index b7843402..0ac91fa0 100644 --- a/docs/loggers.rst +++ b/docs/loggers.rst @@ -30,7 +30,7 @@ Finally, if you call *any other* method on :class:`~structlog.BoundLogger`, it w #. Add a new key ``event`` with the value of the first positional argument of the method call to the event dict. #. Run the processors on the event dict. Each processor receives the result of its predecessor. -#. Finally it takes the result of the final processor and calls the method with the same name that got called on the bound logger on ther wrapped logger\ [1]_. +#. Finally it takes the result of the final processor and calls the method with the same name – that got called on the bound logger – on the wrapped logger\ [1]_. For flexibility, the final processor can return either a string that is passed directly as a positional parameter, or a tuple ``(args, kwargs)`` that are passed as ``wrapped_logger.log_method(*args, **kwargs)``. From 98c9dbeaadef5828b73aad4b37e681273ea938c7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 5 Apr 2021 18:54:13 +0200 Subject: [PATCH 0464/1520] [pre-commit.ci] pre-commit autoupdate (#310) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d30b55bb..4b93997c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,7 +13,7 @@ repos: additional_dependencies: [toml] language_version: python3.8 - - repo: https://gitlab.com/pycqa/flake8 + - repo: https://github.com/PyCQA/flake8 rev: 3.9.0 hooks: - id: flake8 From 4f559c0230b0a14c08a279b9acc16e6a69fbe81e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 9 Apr 2021 09:53:16 +0200 Subject: [PATCH 0465/1520] Fix off-by-one error in pickle parametrization --- tests/test_config.py | 2 +- tests/test_dev.py | 2 +- tests/test_generic.py | 2 +- tests/test_loggers.py | 8 ++++---- tests/test_processors.py | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/test_config.py b/tests/test_config.py index 1f9edb41..f99a9fb9 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -351,7 +351,7 @@ def foo(self): ) assert 42 == proxy.foo() - @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL)) + @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL + 1)) def test_pickle(self, proto): """ Can be pickled and unpickled. diff --git a/tests/test_dev.py b/tests/test_dev.py index da2117ae..1781ed80 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -364,7 +364,7 @@ def test_repr_native_str(self, rns): @pytest.mark.parametrize("repr_native_str", [True, False]) @pytest.mark.parametrize("force_colors", [True, False]) - @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL)) + @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL + 1)) def test_pickle(self, repr_native_str, force_colors, proto): """ ConsoleRenderer can be pickled and unpickled. diff --git a/tests/test_generic.py b/tests/test_generic.py index 13181672..30138286 100644 --- a/tests/test_generic.py +++ b/tests/test_generic.py @@ -51,7 +51,7 @@ def test_proxies_anything(self): assert "log", "foo" == b.log("foo") assert "gol", "bar" == b.gol("bar") - @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL)) + @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL + 1)) def test_pickle(self, proto): """ Can be pickled and unpickled. diff --git a/tests/test_loggers.py b/tests/test_loggers.py index 7d9ed09e..fe533964 100644 --- a/tests/test_loggers.py +++ b/tests/test_loggers.py @@ -73,7 +73,7 @@ def test_stdlib_methods_support(self, method, sio): assert "hello" in sio.getvalue() @pytest.mark.parametrize("file", [None, sys.stdout, sys.stderr]) - @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL)) + @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL + 1)) def test_pickle(self, file, proto): """ Can be pickled and unpickled for stdout and stderr. @@ -87,7 +87,7 @@ def test_pickle(self, file, proto): assert pl._file is rv._file assert pl._lock is rv._lock - @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL)) + @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL + 1)) def test_pickle_not_stdout_stderr(self, tmpdir, proto): """ PrintLoggers with different files than stdout/stderr raise a @@ -206,7 +206,7 @@ def test_stdlib_methods_support(self, method): @pytest.mark.parametrize( "file", [None, sys.stdout.buffer, sys.stderr.buffer] ) - @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL)) + @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL + 1)) def test_pickle(self, file, proto): """ Can be pickled and unpickled for stdout and stderr. @@ -220,7 +220,7 @@ def test_pickle(self, file, proto): assert pl._file is rv._file assert pl._lock is rv._lock - @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL)) + @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL + 1)) def test_pickle_not_stdout_stderr(self, tmpdir, proto): """ BytesLoggers with different files than stdout/stderr raise a diff --git a/tests/test_processors.py b/tests/test_processors.py index f8a8f648..bf788016 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -259,7 +259,7 @@ def test_key_can_be_specified(self): @pytest.mark.parametrize("fmt", [None, "%Y"]) @pytest.mark.parametrize("utc", [True, False]) @pytest.mark.parametrize("key", [None, "other-key"]) - @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL)) + @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL + 1)) def test_pickle(self, fmt, utc, key, proto): """ TimeStamper is serializable. From 2ed01b025cf67ab6a35ebd74dea966e5959c1801 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 19 Apr 2021 19:20:00 +0200 Subject: [PATCH 0466/1520] [pre-commit.ci] pre-commit autoupdate (#311) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/PyCQA/flake8: 3.9.0 → 3.9.1](https://github.com/PyCQA/flake8/compare/3.9.0...3.9.1) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4b93997c..d3d69411 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,7 +14,7 @@ repos: language_version: python3.8 - repo: https://github.com/PyCQA/flake8 - rev: 3.9.0 + rev: 3.9.1 hooks: - id: flake8 language_version: python3.8 From 36d7e12edb5ddae52b5018f79c401b1b5292d43b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 26 Apr 2021 18:51:13 +0200 Subject: [PATCH 0467/1520] [pre-commit.ci] pre-commit autoupdate (#312) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d3d69411..509614e9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ --- repos: - repo: https://github.com/psf/black - rev: 20.8b1 + rev: 21.4b0 hooks: - id: black language_version: python3.8 From b7e9636d699a9358a77a0f602b8b227ff0874f8c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 30 Apr 2021 14:52:21 +0200 Subject: [PATCH 0468/1520] Be shameless --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 18a5d453..2ab820ea 100644 --- a/setup.py +++ b/setup.py @@ -20,6 +20,7 @@ "Funding": "https://github.com/sponsors/hynek", "Tidelift": "https://tidelift.com/subscription/pkg/pypi-structlog?" "utm_source=pypi-structlog&utm_medium=pypi", + "Ko-fi": "https://ko-fi.com/the_hynek", } CLASSIFIERS = [ "Development Status :: 5 - Production/Stable", From 272cbe62a8f66f286ba200d6bf689de71b2c92fd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 30 Apr 2021 14:52:46 +0200 Subject: [PATCH 0469/1520] Handle sys.stdout being None Fixes #313 --- CHANGELOG.rst | 2 +- src/structlog/_config.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index aeeb356e..ca5b0536 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,7 +24,7 @@ Deprecations: Changes: ^^^^^^^^ -*none* +- ``structlog`` is now importable if ``sys.stdout`` is ``None`` (e.g. when running using ``pythonw``). ---- diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 582132df..c800f52f 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -44,7 +44,9 @@ set_exc_info, format_exc_info, TimeStamper(fmt="%Y-%m-%d %H:%M.%S", utc=False), - ConsoleRenderer(colors=_has_colorama and sys.stdout.isatty()), + ConsoleRenderer( + colors=_has_colorama and sys.stdout is not None and sys.stdout.isatty() + ), ] _BUILTIN_DEFAULT_CONTEXT_CLASS = cast(Type[Context], dict) _BUILTIN_DEFAULT_WRAPPER_CLASS = make_filtering_bound_logger(0) From dd30465d76586cdbe8ba7895d21dd4acd42d551e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 3 May 2021 18:50:51 +0200 Subject: [PATCH 0470/1520] [pre-commit.ci] pre-commit autoupdate (#314) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 509614e9..af7ac77d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ --- repos: - repo: https://github.com/psf/black - rev: 21.4b0 + rev: 21.4b2 hooks: - id: black language_version: python3.8 From 4e529508da3dbe8407e51bba19c71e36c2c27b13 Mon Sep 17 00:00:00 2001 From: Ben Nuttall Date: Thu, 6 May 2021 06:04:11 +0100 Subject: [PATCH 0471/1520] Add missing backtick to ExceptionPrettyPrinter docstring (#315) --- src/structlog/processors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 8dfe5cb9..c08cfc66 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -391,7 +391,7 @@ class ExceptionPrettyPrinter: This processor is mostly for development and testing so you can read exceptions properly formatted. - It behaves like format_exc_info` except it removes the exception + It behaves like `format_exc_info` except it removes the exception data from the event dictionary after printing it. It's tolerant to having `format_exc_info` in front of itself in the From 32427879dcf57433b4a8c1aeaae0d77434ff51df Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 6 May 2021 07:10:53 +0200 Subject: [PATCH 0472/1520] Document that cached loggers can't be pickled ref #301 --- docs/performance.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/performance.rst b/docs/performance.rst index 42cb4550..5bb2e439 100644 --- a/docs/performance.rst +++ b/docs/performance.rst @@ -33,7 +33,11 @@ Here are a few hints how to get most out of ``structlog`` in production: configure(cache_logger_on_first_use=True) - This has the only drawback is that later calls on :func:`~structlog.configure` don't have any effect on already cached loggers -- that shouldn't matter outside of :doc:`testing ` though. + This has two drawbacks: + + 1. Later calls of :func:`~structlog.configure` don't have any effect on already cached loggers -- that shouldn't matter outside of :doc:`testing ` though. + 2. The resulting bound logger is not pickleable. + Therefore, you can't set this option if you e.g. plan on passing loggers around using `multiprocessing`. #. Avoid sending your log entries through the standard library if you can: its dynamic nature and flexibiliy make it a major bottleneck. Instead use `structlog.PrintLoggerFactory` or -- if your serializer returns bytes (e.g. orjson_) -- `structlog.BytesLoggerFactory`. From 5d5222f51548807bc9a943d67c6ccda803856f85 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 7 May 2021 12:09:44 +0200 Subject: [PATCH 0473/1520] Add Python 3.10 to CI (#316) Have to drop pytest-randomly since it doesn't seem to support Python 3.10. --- .github/workflows/main.yml | 2 +- setup.py | 2 +- tox.ini | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e6914470..6ec1a381 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -17,7 +17,7 @@ jobs: strategy: matrix: - python-version: ["3.6", "3.7", "3.8", "3.9", "pypy3"] + python-version: ["3.6", "3.7", "3.8", "3.9", "3.10.0-alpha - 3.10", "pypy3"] steps: - uses: "actions/checkout@v2" diff --git a/setup.py b/setup.py index 2ab820ea..f514100a 100644 --- a/setup.py +++ b/setup.py @@ -34,6 +34,7 @@ "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Programming Language :: Python", @@ -49,7 +50,6 @@ "freezegun>=0.2.8", "pretend", "pytest-asyncio", - "pytest-randomly", "pytest>=6.0", "simplejson", ], diff --git a/tox.ini b/tox.ini index 72bb910a..1ea29309 100644 --- a/tox.ini +++ b/tox.ini @@ -8,12 +8,13 @@ python = 3.7: py37 3.8: py38, docs 3.9: py39, manifest, mypy + 3.10: py310 pypy3: pypy3 [tox] # Currently, pypy3 is broken on macOS. Since we don't need it for coverage, we only test it in CI. -envlist = lint,mypy,{py36,py37,py38,py39}-threads,{py38,py39}-greenlets,py38-colorama,docs,pypi-description,manifest,coverage-report +envlist = lint,mypy,{py36,py37,py38,py39,py310}-threads,{py38,py39,py310}-greenlets,py38-colorama,docs,pypi-description,manifest,coverage-report isolated_build = True From 6bdd71060937ffac30255434f5ce9b2cb800ebe2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 11 May 2021 07:15:07 +0200 Subject: [PATCH 0474/1520] [pre-commit.ci] pre-commit autoupdate (#317) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index af7ac77d..3a0d450b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ --- repos: - repo: https://github.com/psf/black - rev: 21.4b2 + rev: 21.5b1 hooks: - id: black language_version: python3.8 @@ -14,7 +14,7 @@ repos: language_version: python3.8 - repo: https://github.com/PyCQA/flake8 - rev: 3.9.1 + rev: 3.9.2 hooks: - id: flake8 language_version: python3.8 From 1cfd15a647088c71832f48637766438e123300c3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 17 May 2021 19:10:15 +0200 Subject: [PATCH 0475/1520] [pre-commit.ci] pre-commit autoupdate (#318) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/pre-commit-hooks: v3.4.0 → v4.0.1](https://github.com/pre-commit/pre-commit-hooks/compare/v3.4.0...v4.0.1) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3a0d450b..25afd61d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,7 +21,7 @@ repos: exclude: docs/code_examples - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.4.0 + rev: v4.0.1 hooks: - id: trailing-whitespace - id: end-of-file-fixer From b05397e85dccce9b7a3201a035c1496bea48fcf8 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 19 May 2021 11:43:09 +0200 Subject: [PATCH 0476/1520] docs: fix a few simple typos (#321) * docs: fix a few simple typos There are small typos in: - docs/performance.rst - docs/thread-local.rst - src/structlog/dev.py - src/structlog/stdlib.py - tests/test_config.py - tests/test_stdlib.py - tests/test_testing.py Fixes: - Should read `passed` rather than `passsed`. - Should read `length` rather than `lenght`. - Should read `initial` rather than `initia`. - Should read `flexibility` rather than `flexibiliy`. - Should read `contextmanager` rather than `contextmanger`. - Should read `appropriate` rather than `apropriate`. - Should read `recommend` rather than `recomment`. Closes #319 * List sphinx-toolbox dependencies explicitly They are missing and breaking the build. Co-authored-by: Tim Gates --- docs/performance.rst | 2 +- docs/thread-local.rst | 2 +- setup.py | 10 +++++++++- src/structlog/dev.py | 2 +- src/structlog/stdlib.py | 2 +- tests/test_config.py | 2 +- tests/test_stdlib.py | 2 +- tests/test_testing.py | 2 +- 8 files changed, 16 insertions(+), 8 deletions(-) diff --git a/docs/performance.rst b/docs/performance.rst index 5bb2e439..6df4b45f 100644 --- a/docs/performance.rst +++ b/docs/performance.rst @@ -39,7 +39,7 @@ Here are a few hints how to get most out of ``structlog`` in production: 2. The resulting bound logger is not pickleable. Therefore, you can't set this option if you e.g. plan on passing loggers around using `multiprocessing`. -#. Avoid sending your log entries through the standard library if you can: its dynamic nature and flexibiliy make it a major bottleneck. +#. Avoid sending your log entries through the standard library if you can: its dynamic nature and flexibility make it a major bottleneck. Instead use `structlog.PrintLoggerFactory` or -- if your serializer returns bytes (e.g. orjson_) -- `structlog.BytesLoggerFactory`. You can still configure `logging` for packages that you don't control, but avoid it for your *own* log entries. diff --git a/docs/thread-local.rst b/docs/thread-local.rst index 5613dd21..b1ac3cf2 100644 --- a/docs/thread-local.rst +++ b/docs/thread-local.rst @@ -79,7 +79,7 @@ Thread-local Contexts ``structlog`` also provides thread-local context storage in a form that you may already know from `Flask `_ and that makes the *entire context* global to your thread or greenlet. -This makes its behavior more difficult to reason about which is why we generally recomment to use the `merge_threadlocal` route. +This makes its behavior more difficult to reason about which is why we generally recommend to use the `merge_threadlocal` route. Wrapped Dicts diff --git a/setup.py b/setup.py index f514100a..4134a0a7 100644 --- a/setup.py +++ b/setup.py @@ -53,7 +53,15 @@ "pytest>=6.0", "simplejson", ], - "docs": ["furo", "sphinx", "sphinx-toolbox", "twisted"], + "docs": [ + "furo", + "sphinx", + "twisted", + # explicitly list sphinx-toolbox dependencies + "sphinx-toolbox", + "cachecontrol", + "lockfile", + ], } EXTRAS_REQUIRE["dev"] = ( EXTRAS_REQUIRE["tests"] + EXTRAS_REQUIRE["docs"] + ["pre-commit"] diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 4565d5b2..d96cf0b4 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -30,7 +30,7 @@ def _pad(s: str, length: int) -> str: """ - Pads *s* to length *lenght*. + Pads *s* to length *length*. """ missing = length - len(s) diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index dbd5d83b..b45d1a9f 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -426,7 +426,7 @@ def _context(self) -> Context: def bind(self, **new_values: Any) -> "AsyncBoundLogger": return AsyncBoundLogger( # logger, processors and context are within sync_bl. These - # arguments are ignored if _sync_bl is passsed. *vroom vroom* over + # arguments are ignored if _sync_bl is passed. *vroom vroom* over # purity. logger=None, # type: ignore processors=(), diff --git a/tests/test_config.py b/tests/test_config.py index f99a9fb9..89c700fe 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -211,7 +211,7 @@ def test_falls_back_to_config(self, proxy): def test_bind_honors_initial_values(self): """ - Passed initia_values are merged on binds. + Passed initial_values are merged on binds. """ p = BoundLoggerLazyProxy(None, initial_values={"a": 1, "b": 2}) b = p.bind() diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 81393992..b8745ce2 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -188,7 +188,7 @@ def test_proxies_exception(self): def test_proxies_log(self): """ - BoundLogger.exception.log() is proxied to the apropriate method. + BoundLogger.exception.log() is proxied to the appropriate method. """ bl = BoundLogger(ReturnLogger(), [return_method_name], {}) diff --git a/tests/test_testing.py b/tests/test_testing.py index adbc5c2b..13d4ea50 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -42,7 +42,7 @@ def get_active_procs(self): def test_restores_processors_on_success(self): """ - Processors are patched within the contextmanger and restored on + Processors are patched within the contextmanager and restored on exit. """ orig_procs = self.get_active_procs() From 3d5eaae26a15d1a81e0f51584facacebfe0c7551 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 31 May 2021 18:45:54 +0200 Subject: [PATCH 0477/1520] [pre-commit.ci] pre-commit autoupdate (#323) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 25afd61d..595b52fe 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ --- repos: - repo: https://github.com/psf/black - rev: 21.5b1 + rev: 21.5b2 hooks: - id: black language_version: python3.8 From 91a952c395b857ebdd5923b0ac0fd231af55b735 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 1 Jun 2021 11:22:22 +0200 Subject: [PATCH 0478/1520] Add Canonical Log Lines to best practices --- docs/getting-started.rst | 2 ++ docs/logging-best-practices.rst | 22 +++++++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/docs/getting-started.rst b/docs/getting-started.rst index a4da048c..493a5406 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -70,6 +70,8 @@ After all, there's even a recipe_ on structured logging for the standard library So let's go a step further. +.. _building-ctx: + Building a Context ------------------ diff --git a/docs/logging-best-practices.rst b/docs/logging-best-practices.rst index 374df737..e1aac291 100644 --- a/docs/logging-best-practices.rst +++ b/docs/logging-best-practices.rst @@ -2,10 +2,6 @@ Logging Best Practices ====================== - -Servers -======= - Logging is not a new concept and in no way special to Python. Logfiles have existed for decades and there's little reason to reinvent the wheel in our little world. @@ -20,8 +16,20 @@ This is why the popular `twelve-factor app methodology`_ suggests just that. .. [*] This is obviously a privileged UNIX-centric view but even Windows has tools and means for log management although we won't be able to discuss them here. +Canonical Log Lines +=================== + +Generally speaking, having as few log entries per request as possible is a good thing. +The less noise, the more insights. + +``structlog``'s ability to :ref:`bind data to loggers incrementally ` -- plus :doc:`thread-local context storage ` -- can help you to minimize the output to a *single log entry*. + +At Stripe, this concept is called `Canonical Log Lines `_. + + + Centralized Logging -------------------- +=================== Nowadays you usually don't want your logfiles in compressed archives distributed over dozens -- if not thousands -- of servers or cluster nodes. You want them in a single location. @@ -29,7 +37,7 @@ Parsed, indexed, and easy to search. ELK -^^^ +--- The ELK stack (Elasticsearch_, Logstash_, Kibana_) from Elastic is a great way to store, parse, and search your logs. @@ -42,7 +50,7 @@ All you have to do is to tell Logstash_ either that your log entries are prepend Graylog -^^^^^^^ +------- Graylog_ goes one step further. It not only supports everything those above do (and then some); you can also directly log JSON entries towards it -- optionally even through an AMQP server (like RabbitMQ_) for better reliability. From d88875d54e188724b881220691c4c8565c147891 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 1 Jun 2021 11:40:14 +0200 Subject: [PATCH 0479/1520] Re-do badges There's really no point in build status badges. It's just confusing. --- README.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.rst b/README.rst index c8890139..0035b327 100644 --- a/README.rst +++ b/README.rst @@ -7,16 +7,16 @@

    - Documentation Status + Documentation - - CI Status + + - - Test Coverage + + Downloads per month - - Code style: black + + Contributors

    From 5e7c7a9ecb8aefd493edde1a66784bb09d982b56 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 1 Jun 2021 11:49:33 +0200 Subject: [PATCH 0480/1520] Simplify further --- README.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.rst b/README.rst index 0035b327..c410bea2 100644 --- a/README.rst +++ b/README.rst @@ -15,9 +15,6 @@ Downloads per month - - Contributors -

    .. -begin-short- From ab5acc6934a4ca81625e103dfbef087a89320323 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 1 Jun 2021 11:52:43 +0200 Subject: [PATCH 0481/1520] Compound adjectives are hyphenated in English --- docs/examples.rst | 2 +- docs/loggers.rst | 2 +- docs/thread-local.rst | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/examples.rst b/docs/examples.rst index 76db486e..9baa10e3 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -52,7 +52,7 @@ For a list of shipped processors, check out the :ref:`API documentation ` .. _flask-example: -Flask and Thread Local Data +Flask and Thread-Local Data --------------------------- In the simplest case, you bind a unique request ID to every incoming request so you can easily see which log entries belong to which request. diff --git a/docs/loggers.rst b/docs/loggers.rst index 0ac91fa0..e313691c 100644 --- a/docs/loggers.rst +++ b/docs/loggers.rst @@ -93,7 +93,7 @@ As you can see, it accepts one mandatory and a few optional arguments: **context_class** The class to save your context in. - Particularly useful for `thread local context storage `. + Particularly useful for `thread-local context storage `. Since Python 3.6+ and PyPy have ordered dictionaries, the default is a plain `dict`. diff --git a/docs/thread-local.rst b/docs/thread-local.rst index b1ac3cf2..495a5791 100644 --- a/docs/thread-local.rst +++ b/docs/thread-local.rst @@ -1,4 +1,4 @@ -Thread Local Context +Thread Local-Context ==================== .. testsetup:: * @@ -105,7 +105,7 @@ Within one thread, every instance of the returned class will have a *common* ins -To enable thread local context use the generated class as the context class:: +To enable thread-local context use the generated class as the context class:: configure(context_class=WrappedDictClass) @@ -151,7 +151,7 @@ In order to be able to bind values temporarily to a logger, `structlog.threadloc The state before the ``with`` statement is saved and restored once it's left. -If you want to detach a logger from thread local data, there's `structlog.threadlocal.as_immutable`. +If you want to detach a logger from thread-local data, there's `structlog.threadlocal.as_immutable`. Downsides & Caveats @@ -160,7 +160,7 @@ Downsides & Caveats The convenience of having a thread-local context comes at a price though: .. warning:: - - If you can't rule out that your application re-uses threads, you *must* remember to **initialize your thread local context** at the start of each request using :func:`~structlog.BoundLogger.new` (instead of :func:`~structlog.BoundLogger.bind`). + - If you can't rule out that your application re-uses threads, you *must* remember to **initialize your thread-local context** at the start of each request using :func:`~structlog.BoundLogger.new` (instead of :func:`~structlog.BoundLogger.bind`). Otherwise you may start a new request with the context still filled with data from the request before. - **Don't** stop assigning the results of your ``bind()``\ s and ``new()``\ s! From 2047dd1a552061929d2715276e93d1e32aa58468 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 1 Jun 2021 12:12:22 +0200 Subject: [PATCH 0482/1520] Add licence badge Color is complementary color of the blue. --- README.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index c410bea2..1d9dae96 100644 --- a/README.rst +++ b/README.rst @@ -9,8 +9,11 @@ Documentation + + License: MIT/ Apache 2.0 + - + PyPI release Downloads per month From 09fd63bedb874ddc2d970525b19d125d69d03c9b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 1 Jun 2021 12:13:42 +0200 Subject: [PATCH 0483/1520] Add missing space --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 1d9dae96..3ddf5b16 100644 --- a/README.rst +++ b/README.rst @@ -10,7 +10,7 @@ Documentation - License: MIT/ Apache 2.0 + License: MIT / Apache 2.0 PyPI release From 4abc083070c0209dbb712288b410939acfd1e4e4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 2 Jun 2021 14:40:58 +0200 Subject: [PATCH 0484/1520] Harmonize colors --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 3ddf5b16..703f06be 100644 --- a/README.rst +++ b/README.rst @@ -16,7 +16,7 @@ PyPI release - Downloads per month + Downloads per month

    From db4a7eb7b9e8f76acbec3ebbe77407231baaeaac Mon Sep 17 00:00:00 2001 From: James Estevez Date: Wed, 2 Jun 2021 22:50:15 -0700 Subject: [PATCH 0485/1520] Fix typo in performance.rst (#324) `TimeStamper(utc=True)` Co-authored-by: Hynek Schlawack --- docs/performance.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/performance.rst b/docs/performance.rst index 6df4b45f..d1b203ca 100644 --- a/docs/performance.rst +++ b/docs/performance.rst @@ -64,7 +64,7 @@ Here's an example for a production-ready non-asyncio ``structlog`` configuration structlog.threadlocal.merge_threadlocal_context, structlog.processors.add_log_level, structlog.processors.format_exc_info, - structlog.processors.TimeStamper(fmt="iso", utc=False), + structlog.processors.TimeStamper(fmt="iso", utc=True), structlog.processors.JSONRenderer(serializer=orjson.dumps), ], logger_factory=structlog.BytesLoggerFactory(), From 154652912ce088fb5686dbd9273aefcc50dd1bad Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 15 Jun 2021 09:47:24 +0200 Subject: [PATCH 0486/1520] Pin apeye that is breaking with sphinx-toolbox --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 4134a0a7..27aa2fb6 100644 --- a/setup.py +++ b/setup.py @@ -59,6 +59,7 @@ "twisted", # explicitly list sphinx-toolbox dependencies "sphinx-toolbox", + "apeye<1.0", "cachecontrol", "lockfile", ], From 13262cbb26322a10f4130f81b241f0e959c06e99 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 30 Jun 2021 11:04:42 +0200 Subject: [PATCH 0487/1520] Fix types --- src/structlog/processors.py | 2 +- src/structlog/stdlib.py | 2 +- src/structlog/twisted.py | 14 ++++++++------ tox.ini | 5 ++++- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/structlog/processors.py b/src/structlog/processors.py index c08cfc66..a0a3d097 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -106,7 +106,7 @@ def ordered_items(event_dict: EventDict) -> List[Tuple[str, Any]]: return sorted(event_dict.items()) else: - ordered_items = operator.methodcaller("items") + ordered_items = operator.methodcaller("items") # type: ignore self._ordered_items = ordered_items diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index b45d1a9f..df86e5ba 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -319,7 +319,7 @@ def callHandlers(self, record: logging.LogRecord) -> None: """ Calls :meth:`logging.Logger.callHandlers` with unmodified arguments. """ - self._logger.callHandlers(record) # type: ignore + self._logger.callHandlers(record) def getEffectiveLevel(self) -> int: """ diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index e37dcab8..f791e38f 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -93,7 +93,7 @@ def _extractStuffAndWhy(eventDict: EventDict) -> Tuple[Any, Any, EventDict]: raise ValueError("Both _stuff and event contain an Exception/Failure.") # `log.err('event', _why='alsoEvent')` is ambiguous. - if _why and isinstance(event, str): # type: ignore + if _why and isinstance(event, str): raise ValueError("Both `_why` and `event` supplied.") # Two failures are ambiguous too. @@ -105,12 +105,12 @@ def _extractStuffAndWhy(eventDict: EventDict) -> Tuple[Any, Any, EventDict]: _why = event if not _stuff and sys.exc_info() != (None, None, None): - _stuff = Failure() + _stuff = Failure() # type: ignore # Either we used the error ourselves or the user supplied one for # formatting. Avoid log.err() to dump another traceback into the log. if isinstance(_stuff, BaseException) and not isinstance(_stuff, Failure): - _stuff = Failure(_stuff) + _stuff = Failure(_stuff) # type: ignore return _stuff, _why, eventDict @@ -178,7 +178,7 @@ def __call__( # type: ignore eventDict["event"] = _why if isinstance(_stuff, Failure): eventDict["exception"] = _stuff.getTraceback(detail="verbose") - _stuff.cleanFailure() + _stuff.cleanFailure() # type: ignore else: eventDict["event"] = _why return ( @@ -211,7 +211,9 @@ def __init__(self, file: TextIO) -> None: self._flush = file.flush def __call__(self, eventDict: EventDict) -> None: - until_not_interrupted(self._write, textFromEventDict(eventDict) + "\n") + until_not_interrupted( + self._write, textFromEventDict(eventDict) + "\n" # type: ignore + ) until_not_interrupted(self._flush) @@ -236,7 +238,7 @@ def __call__(self, eventDict: EventDict) -> str: eventDict["message"] = ( json.dumps( { - "event": textFromEventDict(eventDict), + "event": textFromEventDict(eventDict), # type: ignore "system": eventDict.get("system"), } ), diff --git a/tox.ini b/tox.ini index 1ea29309..ae9a2b1d 100644 --- a/tox.ini +++ b/tox.ini @@ -30,7 +30,10 @@ commands = pre-commit run --all-files description = Check types basepython = python3.9 extras = tests -deps = mypy +# Need twisted for stubs +deps = + mypy + twisted commands = mypy src typing_examples.py From fcdcd66bd5b1c8d143e3917e74cefd7c50745a60 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 30 Jun 2021 11:12:51 +0200 Subject: [PATCH 0488/1520] Pin sphinx-toolbox Broke again. This time `ImportError: cannot import name 'deprecated' from 'domdf_python_tools.utils'` --- setup.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 27aa2fb6..9719690b 100644 --- a/setup.py +++ b/setup.py @@ -57,8 +57,9 @@ "furo", "sphinx", "twisted", - # explicitly list sphinx-toolbox dependencies - "sphinx-toolbox", + # Explicitly list sphinx-toolbox dependencies. + # Unfortunately they break very frequently. + "sphinx-toolbox<2.12", "apeye<1.0", "cachecontrol", "lockfile", From 855268212d72aa7a75fe952b1fe176089ea93a9e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 30 Jun 2021 09:17:29 +0000 Subject: [PATCH 0489/1520] [pre-commit.ci] pre-commit autoupdate (#326) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/psf/black: 21.5b2 → 21.6b0](https://github.com/psf/black/compare/21.5b2...21.6b0) - [github.com/PyCQA/isort: 5.8.0 → 5.9.1](https://github.com/PyCQA/isort/compare/5.8.0...5.9.1) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Hynek Schlawack --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 595b52fe..94690045 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,13 +1,13 @@ --- repos: - repo: https://github.com/psf/black - rev: 21.5b2 + rev: 21.6b0 hooks: - id: black language_version: python3.8 - repo: https://github.com/PyCQA/isort - rev: 5.8.0 + rev: 5.9.1 hooks: - id: isort additional_dependencies: [toml] From c90e05ed62955d132b9bbc9288901a2f7c663caf Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 10 Jul 2021 16:14:10 +0200 Subject: [PATCH 0490/1520] Embellish --- README.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 703f06be..7ff18e78 100644 --- a/README.rst +++ b/README.rst @@ -23,8 +23,11 @@ .. -begin-short- ``structlog`` makes logging in Python faster, less painful, and more powerful by adding structure to your log entries. +It has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio* or type hints along the way. -It's up to you whether you want ``structlog`` to take care about the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's ``logging`` module. +Thanks to its highly flexible design, it's up to you whether you want ``structlog`` to take care about the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's ``logging`` module. + +.. image:: https://github.com/hynek/structlog/blob/main/docs/_static/console_renderer.png?raw=true .. -end-short- From 3e36c7e7d9f96b57f962b2966f75dd45937d3568 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 10 Jul 2021 16:24:41 +0200 Subject: [PATCH 0491/1520] Mention testability --- README.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 7ff18e78..09748a32 100644 --- a/README.rst +++ b/README.rst @@ -65,6 +65,7 @@ Since log entries are dictionaries, you can start binding and re-binding key/val >>> log.info("user.logged_in", happy=True) 2020-11-18 09:18.28 [info ] user.logged_in another_key=42 happy=True some_key=23 user=hynek + Powerful Pipelines ================== @@ -86,7 +87,6 @@ There are `plenty of processors `_. - Formatting ========== @@ -115,6 +115,13 @@ Output ``structlog`` passes you a dictionary and you can do with it whatever you want. Reported uses cases are sending them out via network or saving them in a database. + +Highly Testable +=============== + +``structlog`` is thouroughly tested and we see it as our duty to help you to achieve the same in *your* applications. +That's why it ships with a `bunch of helpers `_ to introspect your application's logging behavior with little-to-no boilerplate. + .. -end-spiel- .. -begin-meta- From 01f48d85d13fa4cd72c248f2662fe94cae31b288 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 10 Jul 2021 16:38:25 +0200 Subject: [PATCH 0492/1520] Add some warnings and clarifications --- docs/standard-library.rst | 117 ++++++++++++++++++++++---------------- 1 file changed, 67 insertions(+), 50 deletions(-) diff --git a/docs/standard-library.rst b/docs/standard-library.rst index 596a1ca2..65c891b0 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -103,9 +103,68 @@ Processors Suggested Configurations ------------------------ +.. note:: + + We do appreciate that fully integrating ``structlog`` with standard library's ``logging`` is fiddly when done for the first time. + + This is the price of flexibility and unfortunately -- given the different needs of our users -- we can't make it any simpler without compromising someone's use-cases. + However, once it is set up, you can rely on not having to ever touch it again. + Depending *where* you'd like to do your formatting, you can take one of three approaches: +Rendering Within ``structlog`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This is the simplest approach where ``structlog`` does all the heavy lifting and passes a fully-formatted string to ``logging``. +Chances are, this is all you need. + +A basic configuration to output structured logs in JSON format looks like this: + +.. code-block:: python + + import structlog + + structlog.configure( + processors=[ + structlog.stdlib.filter_by_level, + structlog.stdlib.add_logger_name, + structlog.stdlib.add_log_level, + structlog.stdlib.PositionalArgumentsFormatter(), + structlog.processors.TimeStamper(fmt="iso"), + structlog.processors.StackInfoRenderer(), + structlog.processors.format_exc_info, + structlog.processors.UnicodeDecoder(), + structlog.processors.JSONRenderer() + ], + context_class=dict, + logger_factory=structlog.stdlib.LoggerFactory(), + wrapper_class=structlog.stdlib.BoundLogger, + cache_logger_on_first_use=True, + ) + +To make your program behave like a proper `12 factor app`_ that outputs only JSON to ``stdout``, configure the `logging` module like this:: + + import logging + import sys + + logging.basicConfig( + format="%(message)s", + stream=sys.stdout, + level=logging.INFO, + ) + +In this case *only* your own logs are formatted as JSON: + +.. code-block:: pycon + + >>> structlog.get_logger("test").warning("hello") + {"event": "hello", "logger": "test", "level": "warning", "timestamp": "2017-03-06T07:39:09.518720Z"} + + >>> logging.getLogger("test").warning("hello") + hello + + Rendering Using `logging`-based Formatters ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -156,6 +215,14 @@ Now both ``structlog`` and ``logging`` will emit JSON logs: {"message": "hello"} +.. warning:: + + With this approach, it's the standard library ``logging`` formatter's duty to do something useful with the event dict. + In the above example that's ``jsonlogger.JsonFormatter``. + + Keep this in mind if you only get the event name without any context, and exceptions are ostensibly swallowed. + + Rendering Using ``structlog``-based Formatters Within `logging` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -328,54 +395,4 @@ If you leave ``foreign_pre_chain`` as `None`, formatting will be left to `loggin Meaning: you can define a ``format`` for `ProcessorFormatter` too! -Rendering Within ``structlog`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -A basic configuration to output structured logs in JSON format looks like this: - -.. code-block:: python - - import structlog - - structlog.configure( - processors=[ - structlog.stdlib.filter_by_level, - structlog.stdlib.add_logger_name, - structlog.stdlib.add_log_level, - structlog.stdlib.PositionalArgumentsFormatter(), - structlog.processors.TimeStamper(fmt="iso"), - structlog.processors.StackInfoRenderer(), - structlog.processors.format_exc_info, - structlog.processors.UnicodeDecoder(), - structlog.processors.JSONRenderer() - ], - context_class=dict, - logger_factory=structlog.stdlib.LoggerFactory(), - wrapper_class=structlog.stdlib.BoundLogger, - cache_logger_on_first_use=True, - ) - -(If you're still running Python 2, replace `UnicodeDecoder` through `UnicodeEncoder`.) - -To make your program behave like a proper `12 factor app`_ that outputs only JSON to ``stdout``, configure the `logging` module like this:: - - import logging - import sys - - logging.basicConfig( - format="%(message)s", - stream=sys.stdout, - level=logging.INFO, - ) - -In this case *only* your own logs are formatted as JSON: - -.. code-block:: pycon - - >>> structlog.get_logger("test").warning("hello") - {"event": "hello", "logger": "test", "level": "warning", "timestamp": "2017-03-06T07:39:09.518720Z"} - - >>> logging.getLogger("test").warning("hello") - hello - .. _`12 factor app`: https://12factor.net/logs From cf117973c170d99694370b51936b6ca68fb3c12d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 11 Jul 2021 08:46:32 +0200 Subject: [PATCH 0493/1520] Annotate stdlib config examples --- docs/standard-library.rst | 32 ++++++++++++++++++++++++++++---- src/structlog/processors.py | 4 ++-- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/docs/standard-library.rst b/docs/standard-library.rst index 65c891b0..fe56571f 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -127,19 +127,38 @@ A basic configuration to output structured logs in JSON format looks like this: structlog.configure( processors=[ + # If log level is too low, abort pipeline and throw away log entry. structlog.stdlib.filter_by_level, + # Add the name of the logger to event dict. structlog.stdlib.add_logger_name, + # Add log level to event dict. structlog.stdlib.add_log_level, + # Perform %-style formatting. structlog.stdlib.PositionalArgumentsFormatter(), + # Add a timestamp in ISO 8601 format. structlog.processors.TimeStamper(fmt="iso"), + # If the "stack_info" key in the event dict is true, remove it and + # render the current stack trace in the "stack" key. structlog.processors.StackInfoRenderer(), + # If the "exc_info" key in the event dict is either true or a + # sys.exc_info() tuple, remove "exc_info" and render the exception + # with traceback into the "exception" key. structlog.processors.format_exc_info, + # If some value is in bytes, decode it to a unicode str. structlog.processors.UnicodeDecoder(), + # Render the final event dict as JSON. structlog.processors.JSONRenderer() ], - context_class=dict, - logger_factory=structlog.stdlib.LoggerFactory(), + # `wrapper_class` is the bound logger that you get back from + # get_logger(). This one imitates the API of `logging.Logger`. wrapper_class=structlog.stdlib.BoundLogger, + # `logger_factory` is used to create wrapped loggers that are used for + # OUTPUT. This one returns a `logging.Logger`. The final value (a JSON + # string) from the final processor (`JSONRenderer`) will be passed to + # the method of the same name as that you've called on the bound logger. + logger_factory=structlog.stdlib.LoggerFactory(), + # Effectively freeze configuration after creating the first bound + # logger. cache_logger_on_first_use=True, ) @@ -181,9 +200,11 @@ Rendering Using `logging`-based Formatters structlog.processors.StackInfoRenderer(), structlog.processors.format_exc_info, structlog.processors.UnicodeDecoder(), + # Transform event dict into `logging.Logger` method arguments. + # "event" becomes "msg" and the rest is passed as a dict in + # "extra". structlog.stdlib.render_to_log_kwargs, ], - context_class=dict, logger_factory=structlog.stdlib.LoggerFactory(), wrapper_class=structlog.stdlib.BoundLogger, cache_logger_on_first_use=True, @@ -244,6 +265,7 @@ Thus, the simplest possible configuration looks like the following: structlog.configure( processors=[ + # Prepare event dict for `ProcessorFormatter`. structlog.stdlib.ProcessorFormatter.wrap_for_formatter, ], logger_factory=structlog.stdlib.LoggerFactory(), @@ -254,6 +276,7 @@ Thus, the simplest possible configuration looks like the following: ) handler = logging.StreamHandler() + # Use OUR `ProcessorFormatter` to format all `logging` entries. handler.setFormatter(formatter) root_logger = logging.getLogger() root_logger.addHandler(handler) @@ -294,6 +317,8 @@ For example, to add timestamps, log levels, and traceback handling to your logs formatter = structlog.stdlib.ProcessorFormatter( processor=structlog.dev.ConsoleRenderer(), + # These run ONLY on `logging` entries that do NOT originate within + # structlog. foreign_pre_chain=shared_processors, ) @@ -367,7 +392,6 @@ For example, to use the standard library's `logging.config.dictConfig` to log co structlog.processors.format_exc_info, structlog.stdlib.ProcessorFormatter.wrap_for_formatter, ], - context_class=dict, logger_factory=structlog.stdlib.LoggerFactory(), wrapper_class=structlog.stdlib.BoundLogger, cache_logger_on_first_use=True, diff --git a/src/structlog/processors.py b/src/structlog/processors.py index a0a3d097..1e27ae1b 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -57,7 +57,7 @@ class KeyValueRenderer: :param drop_missing: When ``True``, extra keys in *key_order* will be dropped rather than rendered as ``None``. :param repr_native_str: When ``True``, :func:`repr()` is also applied - to native strings (i.e. unicode on Python 3 and bytes on Python 2). + to native strings. Setting this to ``False`` is useful if you want to have human-readable non-ASCII output on Python 2. @@ -433,7 +433,7 @@ class StackInfoRenderer: involving an exception. It works analogously to the *stack_info* argument of the Python 3 standard - library logging but works on both 2 and 3. + library logging. .. versionadded:: 0.4.0 """ From b12a54c01650bf858505ea0de655614eee4d81a9 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 11 Jul 2021 08:48:31 +0200 Subject: [PATCH 0494/1520] Emphasize --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 09748a32..fdb725ff 100644 --- a/README.rst +++ b/README.rst @@ -22,7 +22,7 @@ .. -begin-short- -``structlog`` makes logging in Python faster, less painful, and more powerful by adding structure to your log entries. +``structlog`` makes logging in Python **faster**, **less painful**, and **more powerful** by adding **structure** to your log entries. It has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio* or type hints along the way. Thanks to its highly flexible design, it's up to you whether you want ``structlog`` to take care about the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's ``logging`` module. From 48677379a762a0ad4420f7e7b8f6a66cbcd79f4e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 11 Jul 2021 08:55:39 +0200 Subject: [PATCH 0495/1520] Add support for better-exceptions (#330) --- .github/workflows/main.yml | 6 +-- CHANGELOG.rst | 9 +++- MANIFEST.in | 1 + docs/_static/console_renderer.png | Bin 79966 -> 104240 bytes docs/development.rst | 14 +++++-- docs/getting-started.rst | 8 ++-- show_off.py | 40 ++++++++++++++++++ src/structlog/_config.py | 8 +--- src/structlog/dev.py | 57 ++++++++++++++++++++++---- src/structlog/processors.py | 3 +- tests/test_dev.py | 66 +++++++++++++++++++++--------- tests/test_processors.py | 15 ++++++- tests/test_stdlib.py | 17 +++++--- tox.ini | 20 ++++++--- 14 files changed, 204 insertions(+), 60 deletions(-) create mode 100644 show_off.py diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6ec1a381..a7e00818 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,11 +13,11 @@ jobs: name: "Python ${{ matrix.python-version }}" runs-on: "ubuntu-latest" env: - USING_COVERAGE: "3.6,3.8" + USING_COVERAGE: "3.6,3.9" strategy: matrix: - python-version: ["3.6", "3.7", "3.8", "3.9", "3.10.0-alpha - 3.10", "pypy3"] + python-version: ["3.6", "3.7", "3.8", "3.9", "3.10.0-beta - 3.10", "pypy3"] steps: - uses: "actions/checkout@v2" @@ -80,7 +80,7 @@ jobs: - uses: "actions/checkout@v2" - uses: "actions/setup-python@v2" with: - python-version: "3.8" + python-version: "3.9" - name: "Install in dev mode" run: "python -m pip install -e .[dev]" - name: "Import package" diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ca5b0536..fa6b7c34 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,7 +12,11 @@ The third digit is only for regressions. Backward-incompatible changes: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -*none* +- To implement pretty exceptions (see Changes below), ``structlog.dev.ConsoleRenderer`` now formats exceptions itself. + + Make sure to remove ``format_exc_info`` from your processor chain if you configure ``structlog`` manually. + This change is not really breaking, because the old use-case will keep working as before. + However if you pass ``pretty_exceptions=True`` (which is the default if the ``better-exceptions`` package is present), a warning will be raised and the exception will be renderered without prettyfication. Deprecations: @@ -25,6 +29,9 @@ Changes: ^^^^^^^^ - ``structlog`` is now importable if ``sys.stdout`` is ``None`` (e.g. when running using ``pythonw``). +- If the `better-exceptions `_ package is present, ``structlog.dev.ConsoleRenderer`` will now pretty-print exceptions using it. + Pass ``pretty_exceptions=False`` to disable. + This only works if ``format_exc_info`` is **absent** in the processor chain. ---- diff --git a/MANIFEST.in b/MANIFEST.in index 968608e2..3d03bf62 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2,6 +2,7 @@ include LICENSE LICENSE.apache2 LICENSE.mit conftest.py include *.rst include src/structlog/py.typed typing_examples.py +exclude show_off.py include *.ini *.yml *.yaml *.toml graft .github graft tests diff --git a/docs/_static/console_renderer.png b/docs/_static/console_renderer.png index cfff817c9a4b1adcb4c82fe18931d086edad8160..8207dcb6563d76e2a5f7283f40ce8c3aabe1adfa 100644 GIT binary patch literal 104240 zcmZU)1ym%xwy=#2Fu1$J0E0E|&^Uv;yTc%jyAJLygS)%CJA)7I?(Y6`-h1x3XMKOK zRjX3T-aDxzRoRvObf~Lxq6QLJu~EpHxm}cF`UTma7}76ftH241 z_*av3B}yEbjLXodThT=vFy7xo@de-ljiRUJ+TM6*!30s&6(S@_B<*+xa-AVm0yrb^ zrluzJcn5+3!kOrtbHFT)j~s> z;P17=WE%1mxxa@W+Ole>MMmNhS`3uvu%sX5s(+wjunc&%fVMHCO$$e$Cl4b+Opj%t@M>rG(X7|*(4;xb9L{TNmmoJ1ELlCi7gbUw!zW62dN z^zuw}{!ON+(It;|$dbV!u;h{SD)$!FGTOnFdq`q((SGzCh&JIU?bcq)?l(2*vrHv+ z1Q@?k*pD*}qJ0be?I+pB%OTmq0mGF(>(Q6E!I*(fz(3H9{OB*gYv6~YkF4!WXbbkE zfvfi$*UtDOLmWe5=&T4A9g_V{09|DOh$Y?xWC?=letgT|MY}kcTa^k4&1yWWhw1Ku zV1g^OKBWR95Il#da9B274N8AO1)J#Hp*3!aXTNshKcaysunwTfIjcW zFX6-q@H3AA!vf<+@uMSw4DYe8hQ|11SdD81v!@SOL`L$<+vGHdD(Z2w#npys>gKzI zb@b=IghTK{*2nloLLlOI7(R1~;FfDMfi|fP)j8}r!8v;+@&l?|@5#>D75Jk_J5*LQV1RfqYhYurt2-L47z+It zK4}CA3EejJ7FP$`n)S7oJAK%%&gL`8OHuCqe$+~H5> zp9ViQe&YW{D$`LpDcUkGWc5k)RTWr~YZEvr$U78s)Z@Ovi+^$pI!Bm5*owGgIW}F*WXjE{ z*s37?OFdJ(&|Gw-5npgr^*g6Uv`*nB6iahVkygmEW}c`*O4ENC!P>>T(>eCu?kt$Q zI;uc6e}XyVjhn+U$mz}z(y5@8#|dzVbj)p(vP@j#b&)(5LqfUGBqlej2yyRlHD5J5}$P7%fGCU^%*t| z&`T}Oj3^pw7`V;CHQG0#X`MA5r-c4K;#Oj=`)QiYwv=j=VX0%eX4F^zwPB>mqTY>f z%vE)}oW5?^)T_>^cD$ZX|7AGJ6x%8pv|#lxzdn-*(lhW`@Y_b&tRBr7*^10d%$u@{ z-tnSpoh2x8lC6-{%g{+TnQ)qbWEf-^VQABCT|{u^^niQ`qaB9 zT6?!`a-OsWo~{E|tQu|a{gyh2f{1vdC8KTRlFVuk_$O@ukbq3J#03@*ImpkY;Q>DC z3sr_gz|Hc|y!gJuj9LG}xJw`?oOl#4RW)3-mbFj3qj&zn+RaEppUtjMJ@wsILthGo zlA6L?N*-G+dF)``Hu#s$FEuDV1kzxUz=U94_y&Z;K=w($1E|R*?t?4s_?EbqNCT1x z{6@A@iDnH~=SKkQV#sAkSja)FbL<%TO75Wod>)dxSIB+nI>sCIAg>teEM6I28ip1+ z5845?8rlLOkk(uD^$w~6%1%g$jDd;0hTG0H^P~Oj<~c4s4lbViAZ=Wa`QsR(;>&ON z2|8t+VJ%lO+<1ayPtGTJK!n-=zU)@vsU+_9%eBj;-q-doD^QR^$OfU8qNU;i+YC9?&yg&2E?fxkw?I@EY1vLH!n z0pJyj9rLime9Qb^JHH1#wm^5G(W9Zzf~NVqw$>?ey7ZTdR~e)lv8J$ge9iuX=gMo` z>x1RaJUjLwRyo7r8^dMWvQVOshQR{&gOf*>xDVjH)2pNJIpd@Y^J`co<_cCamd{f6 zhV2f>WC^FFFU9JQ8+Sp z@VqdfFiNSXNHc9MP43XH{h(V`?!1hT9zvyfgGn%%js#S;2DblOrs`chB2w#>%_Wk(wWW@R4J}8ZW zBh98|{pWegn%#Zl!r6_>>$!I4Sck{k`l<(E22;jETU=}F1^oE~aM<&5-{8D&TD*+d zhzOf6hyS}*=}rAHNBG8ZTSnXD?c?35E7skq0-)<*?&5l*>lTx@h!^0M^O0M)(fM&J z(A`~;e4~5c5!Z=FNcS4N40P^b_j$V^UiVqW2_ruCAopOockbgEcY)d9=>!oX5qm$A zp7b65m=+(84(6``Hh4w7yc#-QVXr3FR$=L-bp?8Q@FuabQ|^tpqUV9ZY1sax0RthE zIS4_3-D-iM9LP*8phL*KQ>BnxX1Ur!XQ7yZ9iw3GBl;@AgHfSa|1yWG?M02chpzVb zw||q`EkU}EulW%d;9(bR}r&}Bs1P1eYM*BQOvLXJr6tX@W@_*CdLH`mIR1%hu_&h5a*_)WyIGBSR z87Dn@K26PAD62cF%Sdw@fvgz}j6sGb46fF;|55?tb>;p{TAMf;khoe~**I{!@{#=` z!Tp*3S2lo*<6ki7{BI|CyFBN;y&2?+_Wy|F2`qKMeP)jzNJ$jlub zZMgve7Z(=>7ZwJPy%~Usi;D}u$P8d+rvH?ncW|?DG;pQ2aUlO6BmZkh#KghK-on<= z0%Sw-FS`bYASXvYGO~YF^q=4Vw9~}Z;{R&0arpObecmA8UnKx021dYtY=5fq{wtST z-on+yN<+lL`m=jJ>)>bMV&wft{{L6MJ>ruzSBaM&$^GnSemGvhf5wa-Znx%e5e!TKOhQCZ*%kb> z1I80;=!&18gyOHq1tFUN1f~E9qrO11(W=qT;-a0zcE3dWBR)^45s&OP=g3BsQo3F` zr}K8|Vhsi80+4qzbqpl7oQxn}%5xFVv6fwE>3i;Zc0eL^LB=Cm1{cH6H4q84@v zB%ADp0f$2+@lht)iL%VhogmHy4pzKU z7ba!*%Z08koK`!DyR8B7P6vrQH7C{oG~?g8wmBq>#YD^SU!V$#{;QGyu`Ca(?Fx%f z8hqdDFKki%PrVF$P?WONWO_j2>s7MK?>Luy#(voNz2Pi37H9Aw5C?TC_FbHCL!WyPxzD6Y_6H}CYHCRbTg~h4f zX{pp%B1v3KOi@y@cK#txJX%phqs95`IJBw?fVmru4ZW@=mCQ9z={h5FeR-K}z0#zl zq*SM5J?XUf1>PpF{x1gU=V;pGI_oNV^G~<@1pola5Ree&59e#j9+y)wy_=&q9Qk3i zTiD+qhB;7C)AZ+?$mdl4de;w>|GCcHU4CM9pD`}2;u8P?KhpQkNIRmUBXUSSz+{4n zCZ1|7KZwpWGZw{2C`dvK$#d)B&W56=!e zxMl#{+^J$w1QtpnDk_QN9``mlXTjuerz6$Qld-EgrvS(Bu&`V(BI-;ohtw#0wCdJY zZUbudlW-OjZ*Ol5JUmGq9i465daLjQE=I-}G26J}`+H~7g+#jLf`S5NZC(jgYfccq>rm%b`FE$#^gkI|k`DWSrrlTm{uO!H z`0)K43<*I&e!hDjAc|Ewn|aq;#miF*LQXXBDZ=|EU6beHcw<|;LCywPe& zY~!UT??AF#g{zX+M-{hJD9{%kwx6PC`WD}YeW%)N#q{~MLG90|m5!^s+fu7ZGcPN5 z5O0T9v9nyk7W+L7)&bVkqQa79;&Y)`8ML*bBSB&WZSGdzn)yv7VSPibv?U7;Ri`dL zD}yC#K|iIUZ&eq{^x}+2n!58-XIKx)ch~)>(Hw0;B6mUj(Z-pmj<)*T5w}2AJF8CT zwdHBC$=9k8&-=MiW)u)1Y_yaAH8*4CZiZ| z$jI@c+ly=C28pz)@>1b%8YXpOstieV8bY5fvm#m0YO&NczDi{7vbg;DXnS)}&|?}@ zM(>&((C)>1C^zYC(>yM(rrqY8k&L{3O8&i3MhH&7`^Out!4Pnv zYaXh^@wl6>*!aQ52IHz&oYo4%xzfbf;*2@JMj-v>X!u9=uFKk#V`6JSfY;|hUgz5} znRxbjx3^}^q0aPJ_oeOVZ+Ypy#cl_Yy9PGp78CM@>bzbRnwEQaxX7r2WFn7#6;;!- zg|kIzr}4MD|$G*A;{`leI8 zF@a`|3zcy9*@WL*J5eT*V`2m}G=2y4ki#0ti;AN63)r8`SM++MrKd~({*9}R%(9{- z!k71IXk-Khe0A+}Fq<64h#-75QwHK}%tOaq~~<40Y$BKBgS3}o4NW{4Oi zEPd~d85H>f{m0|s98>qTzaPrGQIVRQ+`rM`hpCUnpA@Fvl!ketN%{y45uAj?#IJq0 zlNRpocm;)pGtYM?6>KcpjW%oUZJ8R;vF8{lhoX^)XGm`D?jE*4-jafn_`CY9ag^ij zmb24C=ivq2FPq65^l-fqZG#2}ct0q-b5#VrS2Q-?g*l2jOGC_o!PO32`kg6NN1D zbhtMeOi|+ z%Uq(BG@W^rW;dN=a=LmcYb#3Q*M0hOR=O;uOTfnka{oRcKA@-|yPl0(|Dkiu)X{ay zQqd%uH#A-EsU)HqKEPwEXU(?75|=#Rovo6Of+Gp_2VprV2)b7st@lCm30w@v*3~tD zuCTtIl^@s#eXco<-)1y~gj$-OkWh?UFZN`R?Xul(XTV4f)m&UGA3v9cp7-qJ?0j#K zm6Gy9P*AYmZl{p{fdKRKO|9@oFcSX|IqKBdby+@j5$w+px1i~CgAB&~VhPo-v0Q(4yWP8$S#{-UEm zGc0&q8}gvpJ+=L*#aF2PS$qS(v`x1XG@+TUmkiK!`B+i-SIB@OHC0VLsX(Ws4YxzV zu*gs>+l>9Lm7qKPBMl^a8yofyt)iQo`{go#5@VNIHOIp};ofZ>Rpvax%E!Y3P!UBu z?Db}D;m9YPALX?$Nt!Z%j`*OX1=MmUs}OXt^Y*YNT;RZfZRsGowe-=g6gTZI@ml#Z zUMDwZy4`H;fy;MwqnDESwiURcsB8@NwiWGDAb}2VVSgo3L-0lHH5~9B*l4vzd5oWE zIk-9zsPNXk-KYgB)UwG0P_o-1=GB&aVs~5(uGH_JiqMT_ke2&+@4_I@-i}H3zm&BW z2I;zP$ticvV%P^ijOplg`G---Oy$Z|OYcW=eDq~CvGv_owqZ?S7Syp$%K>ljQ{|Nf zZYtX}+lli9PyXB#F)2~Ofy2Od3(%$VCC@kv#RC8x;DlyI7IWg^#a81qFcmL8`1TjC zSLmh)H0;*diNx(@szLCs?o<;UVZ4jxkUc3CYi((&?H@!9e+f}H;w=_7L=2c}cFzs~ z$E$boMg6EBXKS5_Nu4i^&U`UceOrlp4=-^}v`hGW5rxb-?(Grz)-o` zGJKsxpV!f15iue35I@wFmnUgAysX!C+r#uKm6B6Oz$Xmh^_31V&C`qFQ)jjN$&DZ0 zF5IvAz5&JNSo90(#SB3BU)4^V?IzeBrj1Rm9PBMKX62(o{Dax_C6f;W|>)TC3a^jlL_|{8Gu&AJ7NXbyHcr**^q-+ql;7b}o;dKA64r)dezP~+EGDJMCcjHimk)u;nL&%JsnVtK-3mx>^`(u^wWuNYA zcw}D5!Z`L;`&3m$iv&)^)e$ZR8tQih&G*>+!~ETKhHFsEZln+(3J;1@5^_4gh5*7c z+!!jS;w5QsE*M#n3x9!e-&7|3r<=!AC6feAq{jDM^R_c;R1LH2s2#3;_w|UD?ThPy z=fvB+=bp4z9O?|rEGc~Om5t}R=FjbQmN_1m`_5aG^@ZhS%7}Da7HNQ_>qa&EG^)nV z!s6m#@o%Mvm$Hpwg`?h^hP(2ip6@x@OaC+Jy#77uQii+n6j0C@G~yIm_z2i{E-t9h zY)6cxacrSsV6G!!)St9HOVm@ghu*QFNlBL`&FO?Pn!~f!Rgx(|Jr$>^C&_B|+Eyj3oEK)}Y!3V^r=AM4(k$Bw#yjM!mo8{oLas zylbq%N}%`0^lWb%HmngAI>pEHLmHVsQ@gb~Hqg|uv9r|qy(c*9GG7u>$74Lva0Z!( z+pHv}Pf0L^!2R(hdPV|C#%DM7LeX@PnpEqWMe~ADoSpaT#!RFx5FT3|fojA-gjTh( zFq;24!N#=D=1&U2=%z~{MV`Hhm$-P|^WF(1q3+W`7Z=YJ(IBV1v@BVbKW)9u8uYW( zh??U~yg@kc?(rXN2L%9{zS!wa^#t_`~{e3=&-!<#8Bc0ccOv3+uCmL8_z2ZD2 z=W|_bHHvOG6qw`nXnT?BlQ)?)DDvrUBaqmJp}RA@U933n3b3&ea#OEc{y0tettWDY z``iE1ksEuiGV>v2mBvpKud~t8S6L|*VOM@~sm}DN+VJ*cA-VCuT(}%`Zfpo;hmB5Z zCwiQ_cwBQ4YMW<~k(A6GBKFbN`+M*@hz~keGOf}dZ;ZUR$*S{6VNJCBX}LH|WJN=y zMKVYg!x9(|6b%fR_0aQP9s11X!|)08Re<^RcXz!v78tum{H9-Dl%F5QCQpc^rHT_v>tyTb z_ys85p3wrT>WV{V)*|OhE(;LUvbT>LM$lF=(ljz1HMM@Ys{4*LiP~O?(|jB+puygK z^S!Tpi%?cl661H2L2=#(WW%5=z$L$kCm1TNx3CdZT2RGLkKLq!naYZo^GqqEZjXQ; zL((ZaVI*dwS>X{xXsjzy`CEOr>l=oqSx_3@Mqs_~wQ-7v3Ehy+xG@^8V#Py3I zE&e;g@)YdsLvvf(LioAwxTq7pnB|WU3$(4e$*%ma3>~E~!G3y%am2x(&!X69MVswL z54Ep%UDjZA&5-a$EVqJFmzT)l;kLes45(=fdo)@b>@)`9{Y2)hz$2@9zfMk0w{hv@ z!0916z&FzoHJYh=e0Zh^CIa9(CT{3G<9@r&7qS&#G_i9&k$x8m7M)@Nqwtd~ zAl;;ZP^E`MP_(yqz0WXv-wM@fbu7WsMIeWP#6vjM$01S13Frwfpb}o){5ZXecZwjm z^QY3fd&whq9T*&hyC`q?GbpyZJTp|=-u0|;ZFje<>!Y)0y+pJwuSXO>E{HDlT@YuL z6g;KEY%ngkUCc|mR^R%e(R#(WW^RXK9R|a)E16!4A+BFP7xImWgCV+5E=%^J;~{g- zxe`Ot2#a@lX@{nyVF1JZTNNaP*PjT#qXLcVr172ULfyQAoXRy*K5>ps#LR~V2=Dda z@JmyT4~nX~w_CoKl+jk~6@@Nkp^Le`XDdF@OO|pu3YUxCsuPeFA29!>_iRJYs39u0 zcR|l5-23`5y5CqDHJC%HcP9Ga5h3$1UV!w#?;B#0wiH*=0?%C)}ZInx0+)6K<+JWbj%|!oNi^gZ4gAfzCcoL(nt}I2Yl+^ac=Uiv+}p(MRqsB zG7-xH{{3|JZK1)f>{wnb;i=gJsg&KUf<^2@M!EEg3+=JbmYXxhBFBnW<1DuQr*`<- z8JzcCF2e3Q#hgT;a60R7vUKSJ=snJx?fC~Ty{m?vI$lO|n=C#^4psqQ3dki**>8Y!u$L+Akp$g!<~612qPH&@yta z6T1ivbdLRU^DOov>UHG5YR)3O5^81_0vnTEE*&u(!7wLBP{HBH7DwAU&r)Rv z&w@V$V$Oa$QFz7e9<8~Y-JI))7yp#wE3j*}7kx4)U0M)1tI$zyXo_uhdX^$e?ybpa zqKv2DYiLF?j!w;_OIB%rjaIvBs>qbegXK7@z;$uC@FIM%3+en;p<9>4ZnG?ePKALc zIoXVY-gM@OM(Gq3Yyt;HRqt3s4a!%@)_co?8fu z=w~E|jVbxrK+%4R1CGWMm9+8n-V%25oQ~ zlMO^?y74bD2n70%cLjKgn4i(YbeS+NU+a~D+<|D5A?&_P=!!B zsMmgTbI3@zg;hAcxENsO>;LrO{zM}YneU$wObp6svbTp+)qI2Rb@uY|GT)D|a140B z;-5fgTF^Gh3@8b$Gugov>7_RkB1kTnzg1HA^uLeLz#Xn_76w z&O4&6f*ix?G-Wyb&mF2O07}u?Ojprz15|~dkIDmzipv~taw~oia#vc2y)gevCX0^{} zhWQ<8LhWChA0zSMfd}w8s*8EdR70!b4PI^EV`W7}znGCn<;BIJ{mSt#cblGO;?+7M zy{}HpU>gO{(MjVIJl>3fCB&crpxro=?d@y=B95ut43Y@N63Q%TBJcY&-tsdWqdu4L zd$AXIX%uIq-bN0b;gb>EmPNR)xaC^~1MK{;J7UzeY{(USEmPo`C{n%Njp{FS7o-U2 zD`GviSzHcUZ~!?+V#o2HZ6${8ITBoT;yltDGGMx9Dn+uq-w1 zlpBf!eZEhKn~0C)Ywmgej>2=B5&B@)&*+Sd^%hnT~-94dcq^PDW)UiB7BmgC4%HVVl;>s(G>QaWR8n zJOXoZx$$6Sv?q2awU-Z4k_sCbiW{1@UZD?%-o=y1xK}wV z`rQ1{9Yhh91KugIbTS$X4x`XtC1A#&NK=04<6djSS_jzRdc9K+J1N8B2xf<7AdseG z*wL7=WjYSbEjMzQ<2%nUvh@zt%F;GE8IxlTo?55pSDvWDT-cpR`Mgf|<GL252r*LK5=pfm=dDqZ+u7>d9n_lnlC?%zdoFMR)lmHBL*#G=Jsw#vPucJUKw zpVCj>g&24xkB%%1XR@O@^cYPGT=b6FriKz})vn!_?0S7=q*&Zo4gQdd*fG`-01mwL z-ynFudsvmH;2a-wPiREA%p$Pc+?~{@0a(Tvuw^Asal=hMPTagsqhw%qzd6-WElh6Q zM&zQbX9qnaY2F{nqB7Ib+Gs0@8lZZ&i^`{5J`-^*O6qwj$~LW9+ekar@qfJDz)i#u zkn)cFFvd*ApqroV?ei#^0e*%ffkmY47l+DBJ%KLEU2bbM2()ile4x&|DBr_pw}q4n zuK>R~;}L8;&oka02=BN}!L>=~KeSctltMu!Pq`1k&5&eQJRpPGt2Hgx5^kL0+jFwq z2+elL*RO zq2&I1sl_~O$HOTD&D)+KM`9pAOrnc0^>ekR2C2xAf)HFk?+0XG*x!} zM759Un_tZ&7@MP&FN#7Qq2LY(ut|)6Fz7XI8NcBl8{0J-qAw z#DqEQk4HBb4N7%}j-g{}Y@myOfZlPHH3%x=^^ksoX7#q(zR`evT9r&fq2A!d>{JT{WXf}n{-ip)QgECu1MZjy}#nnd}Ic4O! zl@m;RJ0*-98ZqAHaWSAuvAoc>|u3#m^ z7)gXp#p?bn{t=&=@i5feE5uX+E&RE+tt^7J>XJ3GGpDz=Re-Qp%}a4n^H2^pHXLG$ zH#mt&dA-?CN5Si&-s@Kk8IZK>@m^D9!EsY9jRTb#6NsYC3j;fSVbsp0p)f+y_Vmcv+lHhevx3?OTJQL~sT_%C8!ihPQ)Yx@bFG zM<64XkaQs+gy)Fd>=$dOf;pRR@SG`Hj{$4U2by?1G-*hes+=n6Rwa4ibzLCsSv}|6 zweh;DoYe>d_ouaml3LR&srGaWUKIPS!~v8eoE_g{e2;_-<}kEe!+{Gerr;k56M{5on+#xl=2`B49!=1QQ@9ZcA2vLJ3nq zs9$}aON{nAOPBH6vuj?fHn0vK`NgV`kzjGi246+7%}~#dPjitb?k(s8mdrbHW&BA06@% zEUipX{RjQ{f5rTyaKRgb?iJrp$~uv`AuMoXcaP3wsW{u4a#y|QR|VC?zA{F1i&#bO z9Q0{X-d$qxlucM1rWkyi+zEs0x_OMwQ&#$4!`-4mzRc!;T43?<#3p%6W+p?UbZi{A z8{f|Uc-mgUQjM`Hw5S+NNbN!9V+vw^r&e1Eo2{*1h3|}5ppty?#gesmtHsJ79!v$p z`bunUY(iXIxf6<3Q9|M!WyzEcr(3Olk99&)Dw(E^$C^w4pNS5s)c|u&aZIi&$okY` zWpz~~%X8T!T2#$AUCtT?uj{4+B#He=zHF|Nqu>w;8l(p{$3BQ!m+;u1W6Gmth>>uT z#B7u0jxVbaSAH{N{+`CBiVX+O1AEJ4UX!dRA_DdF=o;Qpyv!B&fV!UAt9gw|T!U?x zQoPdZ;YY}2FJde|H|7vTe9s&a8oJeiwdOWC=*~STA*W3${w#X4iS{D0oLgG@UZBmf zj4b}VG&82!Lf#_0q<4sgi75&Wz6gK8da<-Py7K!kV#vW*^g|{5UgTCR9n56*w=Fj$ z1OyCR!hDL)Y%Z&*tCU*r|ePX*{Z@I@%gFD<+T|2qECDDg1BD zsZ3s_oAXOc5^^8g3y}R9H42{t8iePU|Hmrz(~qmapN%&6XEqOho;3L3Eonuj1H6H& zYhB@_z3u{fFO*B`P(wjOfV22xiS^W5C@tNv{E2YU(rR18gB#l>RNW zwPj#x)z-!p;Wz;I)53y@*5%%CB<`ECmX@VU)^rEv-CyO6iH%UDRk?*m$Q0ew65KlL z3Z2t4KEZYVMk?d%El4dZBq4W#zueh)#PVHsH z`Laq6QGFiNBzEr;8X6ikEp0rbE7a5Tv!cQ@6jRJm@$FXUgU35)1PeBbd*ROyt2PZ=mdmGelL^&4Y_~w?#d%*j@ZHCpTUqkMdg} zX=ErI4($JrAmG6vSULGfVKNF}vaCSL)WWF?Vf<_ZdJs$I?CmY9q>N0#-N}NMrD?O( zTI(GWU!9)UPu|zLzP=1z-nHVq431==Lt!)#(H%>;Q;?Y62@38OA>lUlGE+N#AXr5?1Z38)PQ%({c?)57E=e@^BdvT2(#$tyHWrE z(f8=JiH#xM=Z4l?Q4-tqv+k{JbHIq#QxhNmC?V2IV~wkId~7Ir+4Ttu_O6YKc{?KU zVd#f9@VWK|>{a&qed!=9NQfaR0qPkh4u5BDby=vWe3SI$;$%;lKSD;yk_B{Q^meh; z6W>rgJL9a(Dx5Zv$xwD-Q5Bnsv3UY`Y-!D^{5w57y^!{@btHo*p7!Uq)Y68;Q=r67 zqBonZchWo~=eSDYO}WD%-1oQO%G8v=;}4-nB4`0vNTh>1__&#wna5iM{ASAr!G$P7 z9+6^uMa5jxDZIVlp3zYBp}?L9lua^S%YC@d>0w}zl<*&ffO1R=sp|7Hy4V}(OJ;?> za%J6HpqbNP#F5Zwp-kF4QTp#xm-Tz z+N7=YDJ5A+WmVPd)B)2R?ue{U$FD8Z&5QWOfe7nJu4!!+KMsKirZn{sSoIr!O3%lZ z<_na^v{|^byrwEttJzY^geO_8M!Y;afTk~71z4p2`|9$_b$nM$nIs)d|G zK6>=)B^gCgVcA>@k#oE)jHWJDl?4NIeJaQ`l)Gen65AK=piHmja+j6HW=*$JSKbnpEww+XdaTGnGs~Df1d=+!0IM8uv zU}XOc3!L8fykO6Cmi~l8hW{q*Y`xn2yVuo_ii|fMiHKL^!E;Bj2XZ62O+9N{0=@q5 zE8UIj&iKdWfi)B3)%|_p%SBu8_4VLSd!P4yBge1@b*QuL%N=6iJ&T@_Z>uvt`&!|wr1@A4%z+lR}LB{@9f5cNhpZk`L z8<%C?-fdWbK}>%1-x!nQVw7fO)ZtHl3jIKL0KKqq0|lq9!NX-X>|ujND;h5&U6RG7 z`S+`^&==+6CWjqv&8w~tIAKp->Lz%;BXTym(~@0u9*F%;eOd!{=++*686r?9h#b6@fxf(unGTF zjB2p_hj)N}`Cs0FbQBDu&)-0VNPx0k`4HO}8H;qLdx#8!lajwVniD{r>9*&-u+F@G zs_Pm+ECU!X?CNS(PB@U0oIy~=*yQJr%NI;bK@;Qf_JTl+=Xm5a48Y&RqOdJAL4KYr zD};q#vvw*K?jE;pR=2F6&83UtuE_^uhuV_xI{on0cc%Ss2;s?TLEGZqbLStU@OfuP zMczO6!9_zZwAppvUOkV@9e0D#le6bkR8&6? z7+wDX69&J|-)(p;5JExT5LdNJcBV^#yB~h#mYCTwg6dlHxc}*eGxV19wY{4v;%@pA z!p=KdSQU5WrPyk(X3Qe;IaPQ*?~5KbwEOE}j!b;cW;0Gx0w37@EeI^4?GsL*^6r5p zM!@$6jUHariwwes5+jc)8>&t$u zKj{^2u0yh!G>_X4Y%wQN*T`RUPKY1bo9wW4S9bW;tiU{!mKS*q2z;*QyG-W1342^7 z2wlGJv{e>r?ih&J%*OWd5^>6S_w--@Y5Yq^rKPAhO=SNJW8wIcCb5!oPmhn^%WH^H z4Av^Rt(iDLO)#FOy1i~qzRsY>eJA6TW-;&c7d~1)0qp>XY=54aqwgG6XQR;k89_Iq z2sn(=Pxo3x=gBj#WpvJwveP96_#9#Fq%dak#y~+nyyIVFqn48o9`jMTFM{3YG976+ zrbq6$@O$W~I=Plt0HrgD$iK62MYi*H6qmJ0S+cP6X&q9)ui}1KJQap|++x>uw2V8= zN-b^L6oegj)RyMtVaqjUPckNa+wvkFRrvCF7S9^2dSqWhLm4f?lLC$<-Z?u{8Vmb1Z&K^tL7|=|DWgK8Ry^6 z!>``|Lor^_2JzHza+tMIwqkl-jb`-lfZn_w^x`wud$j!`A#D6pgu40x?Bdr5Oq4Vz z#|TDPs9*d=#nX7$K&K`J8W;rIJMzk(0jcHM##BmKsiMbx{jjhTwjcZ-`Y?gwPqPWQ zc~DuOv2P2I=mz+Ui9>Aw(`S6mV!1tvDui23URMDE1l*CpT`I)24-V7r#YCzr`UuSe zlB1|M+ky|+&Txv?8}9vlKFpIl+E3e`O=03n=(#|V@OdBGpbkYG=IL|}r(SL-i<`Gz zqy|}v4@~KSc2^JFiWie_z>kFO;e1BA0ZnTDZyQPZ$X}vX~(<;Ul7^$EK#e-EKTeF`gn~fILP^yE39XFX`Q-7Sq&3<#p5Z(*NRpy&Kw_ z%{O}SMErWmgj(n`xdsna<BRcFujofSk>0!<}V92|wEZGWJClXp zZ0kY=$D@yXX_o4{&oiCDaAJjysNUOywE}?Ng<$;C8@^R1Xe1DvD ztNk0i{;{G5yFR1QbSIX*JDEZsv6O*7KO=b$^-$eM#zY=o+3Y}S5-~=lhPYgEW0P&m zKF_mg`+AtzB{4S~qU{<++hkR^`dul|j~;P3A-x8||9Khmm!6^`8sGcl4j#yoieue1 zo?12}3X_w#6et8}f9Hs5*p_DC63RDVUYRj>r^{Re#ATn~AE$(M+ zy*b7=_cV=Cf~Ie8Nt}CG%$6ylWB%g= ziJWQCNVG>?CqDnUR0eYU{L6w|`9=d>^1@g$09(x2=hlBZGcJy1KE_GiYT7`g@^8=d zH0CS8mGk~*U|5oW*eY^YyAln0Wn@HxjHOyT&+NZplFyCCn$$UU_Wu8)Nm#NN|4#de zKp{ZiIc8<+@F0DiKhlUrLR?->#k$X|#D;Y7nb1e@Z(N`nFv$1=pY`=y$*X6Zg0&M1 z{fkxd@8iBT&TvO7UuxQwUnoYi5jWFGvaQEKy2u$C*r-iHCa4LMiw!=g<-T0;fRFic$JPjosTY za%Z?wUNCDO=rXZ;qRhquBQHx)tR=v}SbD2a=#CDVExVwS5S)KIeuZyi_ zyB4AI_cyj}SZ!t&8FbEVk3Z-?b=P%sFBr`$rWJIFAayt079|@UEUlG)3vC*TXTP1| zEuiS;DtQjD)tjwgl~z^c1l5V9odP3-r}hi|?_Lu7lf^ zbK+fgVvLn-_Vy8bvt@QqM=tNlPB~4=kNA{ZmRPSshAaO+!rnS6j&~-A~d34dqD)T0ZP zhDHI4aOO?`b${ww`Yg_HgsV)a9ecSE;_zqI)Fb$K&cv$$7|VKqmuD1@gm+EK5b%L5kA+9y0HO~z15MW z+Pcmg)l-wZRb^+zb%Q0mO)+ioIzGPwAeg|Hj%;9_yCD-p0{0s8j(*6mer=^8#Tb5% zdt@hH45@GV!e}Hh4AeOJkgszfVq~X2Xy&N>VZGLp;oAbvSs~Cv!t2)ao*zvO2DG-+ z@e7Mf63-W?%se*NtV7)Dl2utuD1^%{b`9&E06Z}E$hIWT8rd0#^6pW^GN`I*igHf0_hFrGlQQUw0gU7Ioq)ve|LL2`7!{9U0xh9@DJom<*Ig8C2Kv{Ez3PT7{|6F!fRQjbgs0!t+DRikkAPux|^;@>uraHl(+N zzp^slVg+^VE6Hd_k8*-{!a&sU?DE-Kbpj?l&TNI9z9J3GGpe>rl<}BajGeNipfYb<`Mt9>q{n7b&zs}5$wK^Om^hBfiV>) zTTxg6KP9E^s8!gv&ZW4*rIKyMr*W@Vp~wK3e!>t^hAI8G&Hf4Did-p3(;4@=6gg9wXUiz zG_T$uSap|8_S)BV_U$5O7F)k6W03&b4#sCO??c+Jhxmwz#27IaOa1dsK6kai>CWE$ z^NLPp!}6BM=Qu)F<7h*0T%S!@b&g=z6;zF}vP1(|s!Ve1gR!)txvdBCN|o^Jr<((Z zh6R@Z2-Jl|60nywKf3J7iV9=yHprADT9Ro}&+EO@{#Z}PgBnSk2|Uo-5vJQGh}#4I zg0tR@r$jnq`sUkJo2&!6R|fY)q?UZUTxO4ey)PA$;L=UOcMq556Df>ox$H;yfQtYb zG#{GryQb{TJ)bs;;j=f0%Ig!GHe$k%ZKUn`yXO1lVhU$iK>yCF_BQmL9u~0w%7WjRz5?`6{p!9B~upT5=S`<_=4`#5=R{T0sn z%K+n~{8@3_B7b;fqz}Kh#skpXrT+aJSxl<|5N-?WLYVG4V3`p2^V0oJHRA(O#EF z$aj@X4tSP3kxt+FAyFSGNW_|e!?%|QXu(+&?*D6op$ob@X)fTwz(~Q?_6!&7mm&xw z8+buV(cJnx^P%PCrG*tOkV^ZH77h$~F5}Uc`gMo~((C zjLYy)SV1JqC{M%X2eaM%+5J6S z%&S@dt(kttq22wxHoZ&3<~O8^t+&(!vunvsY|uQFW9I;*YrSirGZzM9=!ox8TEEI} zCt|^(zl=5b;rJK-0e#06xa7AC#8CN3=^!(#K6oUF3+m_SDiRk*>BL9AdG~Q`&rQB^ z1dE;mtxb50$M^F^Icaa~Be^cIoH8k{@vU7Ymo>Lm(@wh?RQKIrUep7iL#3-AybBN+ z00{l5Cu3X=U=<#`f@D#Teq#GZq3&N;P@S3U8B11V`V}~H{UR4>tEnT+0ZLn5J1egv z5(62EJeo7UccN^ua;Gar3$ykv|K^J+AWFwojkK@H@6h2)+TLg3zcS82lpX`kgJe8L ze5>H@Ov!r3VTMrsup1|{ECogUvNe9OS3C*en6(XPui@+~I(USvR+3T_wW%o+hQkte zrC}iSskxSz;__c;BXoRFO=@0HzHV>{$ibM<8xZBH_Z~2gA;!2v%G+V8~q6y83(l++@6jZXV2DY zd>w|CMbugYxjQ8lo*}6FGe4nQV$-h|8@lIGgGy;y-T(2%KxRe%V*cOWm_XGiC3$%P zI>%^xuGE=qgXlU76`SyOId8pm{O@oTuM-t>qMI1b?8Wi+5!;rEyhHFqKXt!1w-ipB z@}|$p9Gm^|e^}bob#{U39pGDfd@+!h86WIZ79G@urKN7T;zwr{h$(k7JsS#yyZom1 z^}e=m*~AS#=u<<4-xiOary3^|m4e`Oy7w5(Lu!`D!qh+&S^l|sk zyX$zL&tmUKgePqpaOO3<*tOPKdvVdEx36ipla!_4C|@(_bdCdk6tVFp&g3F&%^76@ zceXL$$!7NrYvc0#oHOkTeU$FW*zr}ZOYLW6CWl1bFAMWc`Z}!2B4#Olyv_Q$SY=CX z8AwY@Lcz;oPz5H*@1n^~Z%@m6HK|)W(-9Vj_ml^=}AnWB8oM&In!2f)uO z-U?q?gD~uc(AV}}D3(UJe#Y?&$#as{`)!qwe)H>L;lDACpGHwAjH_&{bjA`cCDxN! z?@u(2segQN@f7@)?5Fo}cry`FlED1(UD#AtwJXTc@;frl0eu=VtgsKYQSk{h5^yl2 zTu1^BxHRc)xPS=*1{>Grrwc}0SK>Vd3N;bHS;%H4(y{h}Ei>svZv&!LJ^AD--aFbI z@}9+TMF~M-*AdjtPpAHr>_iN%@SZr&K}%;e7A7VILxKMECkrsWQSpn8S&Qr_N|lP; zyPBPV&uNK?6pIGDnlPgfj3ah3DjP{v?Hx`o_Z6L|=R9V$=BzhD@?;uy$0Op>ZoJ`8 zB&5(X)W=RvcBrcb9%gs)2jQzXy#HbW_{>@kHLH$fWbFPhQIZ!CvAGvfBZ=Ci>~yG+ z^m%A2d))5-l4$*C@) zImY2|Oh)y(q+c5dYG;0aC;Aw;>lA!yyGI4BB%i+$w+H8K`@;M33f*%3lRcLm#{M*^ zw1{=XT|`rx_X4x_Y*ROcR_!{l!#vBu#PMiG6$RMG5rU?&nV*Z^dH)QN*(~d-&NW%o zLDim-vP2g5JD3ma^$#;n_j-^Na9Al&yYQYHwSufMGZt$P^s-RewgB*-`%- zCYGxW8ueSephJ=TtXePpl7CW}hIDD8HS%5lLQQFrgr-a8oxZuGBdO@@?YIfvWo8v| z4u~i0v)#Aq@S{-8tHRxi{_YwL4jawrQYElOL8_Gbb3=UDVKWz1@RV2)}^ZzjN3Pm_@xLO~$!Nx$OnQzqVL0&idBbxkh0JvV-WTW}G=#4tt$_rU)8H82gQF4V3 zxbjZ<;#(duh7)x}+BImuDeEjDkxT(&R?8??+e91H9vkaY8uoWq+id<9N-i6e>$D$l zJ2#HW+zl0zqPR#e*WM*X=o<|NXWL%ZVR*-SnttwI_!p-kd>UEcE)odZHi5qTQ+SIg z@7oV|S4Yx5KKrzF>2Agd5A` z*3j0T6nR~XraIF63J$l(JC7l-*tvK8#blXN1FeazG_RIH(JQd4FS5%{`Z*v9@pvLt z&BJrWDU;2sy?v$O>wO&#RShxP^|i_P{+mHMEga_%sEW6s<9{6j9O|>tBph<=&k16GK6iJHz`#KB zx3kmJ+_AK=hsjy%%mY%LR*tyX9gu*;MxIwhr^EZ-+!IP@$3lNYH3}&jGRY|!&)SPn z;4a0qwQ0b>K@l3PO1NE3e>ATcvntwKS>&Jp$6?Xk|KVB$jOP5oTG;$@mj2=$(CAdv z;8PqG1rLAP`+Y4jF;DYCG>f}2eJl74Jcb|DBXNFVVTOKvb_K;gU&qmrNzX@KLs3b| z=p=E?KJU#oKTC^1*_tDkGyW~mTCVNM?GqM=$$0ucH?796iVAB!F26-I#&}lKi*2cm zD;V{!nFn26d_9?Ii`Jm_T1)*9FBzz4GSk0xS2CgJvgbJLd^7)rs;C>_Dfo+2!HrG| zecluyd|)`0NWF6C!RzWs_g!`GsBHCUhBgmlrU*(qBO~MXme$)Up^`%JU#6Nr+!kAc zKNF!IvSb!3itfir1q}_(a`pOQ%Zu*6?G?yr0wXOE5mI&bd*ZPko&SI!IvT(Rj^`{i z8B8M%lQJ^Kf+B}FiC?mL@Bg7d968xJT7N&6y+cDnCMG6c-cY_TsHn(PuGE&QIF&o; zPpg+nWfHT@`y!}hGpXNuO|DQV>*|_}Odh$m#$BiX-{y)DaQpUJsfn~_ESK3S-(D+h zd(WQ_3r51wul{C41t^6BZ03fz#NLMT(39fkIhj z0Vc5IKTs~fAg~B92pmWNJ#ko}g>uTzDSqimkWNcL;9FC}0O>Ch{Rhi}B8Bi}s9d8F z>cYz2p25i2*p}Os<}W)0FtG&i?hS@V%H;GAF4R5U9Mml3eJy~UC z5*QP%BA|&kJ~dVRWTA3F#pT%(=!*EVp8{n3eB;#~QP)@)f7ETYA3#Ri6WOUDJoJ$$ zyJ$UTpU!CGUMnsrA1EY!o%_ImpK$s;5z*P1)4jgC#gi_b$svd_)E&vWr4RdWmqgg< z^W5slNSv^Hcz#}a`J4I1hH&KWc5{;BE=Z&01-q3sWCXw#}CrU^M_VT$kHLR+2B$C@dV2riyB#HZJpGP*hf&9F_e^_$xb7{5I+mJVeDyT8F|Y8M)S<=P9SRs1Wi-ut+fw`qbC=WEQ6B*{@O?U9)zsP{ z2yOu{ud}T=!da083Kw$f{dU%c)Z*1vzM&|_`w49(AfZh!KI;X*+G61ir=^{aAFj59 zJ8;b{^*nO({QB{B7lr&A5$nVA&gpq07e1guL4stavD1kchu6-}8psl0eBy1Jnu?mnRi1dB)Hg%h8ZC4aV)q zUxE&+8KCa1YZDztTGSryQ!*GbUt_Zi?1bLSco!vCWa=>(*Nb~@Uz`vedwraHQjmwB z^cMuTViEs-obfxUsV@l$_=NXnq9`Bjtdohp*SOh2)uOL1k7t1D3G!-LDVJnFo<#JO zTd$m%MC@B&KtM>1?Kq0A7zV}>lgB*F)fzgGYBlYayIYvHuc7SV%B^aDhr8Sx>=B_6 z4D}1@Pp1UDqyGI}N`nu~)vhWdi` zF~}Qo*ex!fdU>0(nJso?saiEXnYR)aN||F^{1?h8$IZUFmn9vvkq zPG{EXyp6*MO}>@8l_*&)!40x6bUL+n2wp91sr$8!Y@E~q(?}k$^DTwa?)zn|_v3DA z$SC_3g-P|$9PCCkQ@EKN-?n{==61UoVO8ZK89WRlvf7^$AFi*je?M!D*t@lRKH2LTK8Wz5 zpOKUQ($6pv5eYUVj}+cbWv+7Ag7S7=SoW!Tqn`A)7baKwfo=cNj8AG-+ts(NCN9?>e7yz@ev59ke+C5T0 zo;dN~A5fj|6Bn(!eU!;UW(WPcZ4k&0EmNNF)BemL!n(+EXrk#ISav)+6{9%>W8r=k zPBinXN4eAqY(xJ~yD*pggCH6>`hfHhhLky-E|93d)JJCrpamX$4&nz=GNybitG`4A zFxL!B{0T>I?u0x8L%sd~6YAxdmRP^2^sag1!#TTi$u<<_xeR)?C#3&oDgYn_Xv?9bXjd$k?WBM+@o0O2*39mcRNUkxFaSIloUM zb~f@<opi?WZ`e7v^2b;jH*r}I)H6!={*0xT@4hvMRdV8PjAOOxDo zMY)Md`s3C$N;@mZ|7p1YzUVa%|G0bgiV4Y)?x_MzU_-O07I>VUoS+3k{hML2SWMBo z9Qqq7Fxavqi<6b8>;z(r>zv`*QA~q*lS!w~zHX5(b8rGGaZ+m8? zI6dL?-H;J;=8A?c1e!nuIN5!t6*i~~ zciC1n#D*FUX6(KM^VqB@(SB7TU~&@?LShEamC8|IXYJ-aJa~>yMA2Lx))#WKI)`RX zizDh^Sl2v*>-E!&z7VTG0k)#w7dBiazR&(9{q4YVXzwP0^Pell1h|b{ZIYm4`56`_ z1ipBEouR0$UE$__%iTZEqZ$?hO2Kdi7Y-8;gUe$HW%S)E@Ab9~VtcjN+g&G-f3K?KkB>Z%)a8xo16O7GZuZp2*1+QXxD$=&)F z5Vl7WjE1)peYO6^Lf`BsIiOlu`qBFQe7_+Yb8U$ubCt-M@S6t@) zYH-*GD7c>(h+m@&u7LSg86nIs`wcrkWXvM6TD}G|_w3Y2WiCbY(e9rStYg{5bm&`E zO<9FlR`Htj4X~ZK0l_d4IE<+^uFy3w@1AG#Y0uOfhnP#giIgar3LIhQEjP|~&Hsqr ziH-kx8|)JD2O2dw-R!G@{cApKimZeEXuIl4W7^jvMMXtfPfzTG_;`Te0aIm4SY#wY z8D1}LLu~jp^bSn!;4Ad?1FKun*TuXa-Nd59C}`mCj3rryfrdhKxtdxEKtJ#JG3i~M z6BC6>1M9Mmu3wb{LPNVR{V!6JU46=Ypi}I>Q;&KBkqqsa+t@El`e(ImF0YSv)nF(v z55PX)Cv`A_*^f8dEug~7HXl5|hZ64qLW*98?`nai!9mV4ZTLOu!U}nBKqfu^*x!oq z3;kEpx7{?P@6E3^0ck_7cP70zDHl>PecK__9+#hS*jAMy1p?whF_EMFqfDJ$I5QvxpADy2j0dPyG%qzly@lPzz+SHV+ zpr|NR?2DmhAU$RKi+rUoPlaZ4?7~PS61b(hdWkN)jh@vRKY>s7o|yNZhm^{)bts|JC~-gZTgKs#<;h zg<7he5f}Wou62-)Sy_I|7&)gq|J~W7EG7P{8yFcQG`Klm zYh@?YOA<|QFrCWvt_~n&31CEYc}UM!)(YD7rpNLVzN{M%x#8)7)3kwgu*EwL9nQw98U_%ETBz~@Y zFLw1G!4Zq?7qx$ zrwD(v_tRqdiuDJ*s8i@DnZ_aTlt_p;;i&PPrCJmC;*e)>1=YtN49s1Y#k-iYQc8ca z5C1MI+x0(bBaiiaN%BGj^lzZiLT*>vGR)`Pr(>;(kYZK3@gvNgU0c70X6i2ZD3z4! zCtq~VaTHB?9ybNm>&+8Lc0enol=J^nZ?QeX-?SgRD)^Fc{0rEL>caXS+Ul(P&quVd zS+=ykx5UIrcyGQ-!WOS<#WpS6gg;lRq0Ghi1?Co|JV0il9XZm+P8wB#XzOq*~ zyTXv-zhCE-##`|_^tfDeU~^>l3l=lRLqW5%!42BD+q&#o-X&ZFL5Xh+9ref1; z%p)NU%Hd)lU<7f6pnYQ?8;ID=4+#NWUtR4dA<21oU;#Z7CQcu+czAfYi@~8S)YKx) z>oGjF%Hx;4nThoD^gu(($;rvlBK<-Gquu|%up}pkjDUdeeH)2uRRF}K(yy2mP)egb zJw3?*Z!k_yPN61~HS~XLOWFlzXJ-Nxlq-+Aoip3pVyWnsD|s;Lu#pb#3@+B>V=0Ux zaZCTApq5Mjt4uBtn_d$ur+z6Em0{M&w-hBMah*NT|3R28W&c`JShB%QgzfYm8;eK4 zDMjh5Iiy}ztJi4l7gLdma<(!%HD^s{!!Y%h4nb8aip&xfqraM+niIS5yziJ_T^I@O zH;O=AKm4TQBe(tsX}Z`&v7wSPhgF6o(j+-fnLlNga{KZALYwKjcp(cb@`}xHXabgJ zPoH8x(Y8WHLO3irt&3F`dFzjJKc;a$?U*X3D%ttC0-b(at3b)QA^j)q0tRFe5~Jg} zn_F0*X&7{&MG}w$!O9eaw@91?vS>k&q57ZJl-Cr3ZV8T}{^u94+t+=$bXs%Qxj?!bcrMY=3 zUo38LV?zeLBv~;gz{FuVo*Wq$mn7_Wb!%&|a+xYWHFd=p3$W78&C%1wM-YfV$YCVd1G-JV`CnI|FEq06^D<`1YE6v# zqTCim0?=0#SabC>Z4lKoEME6;e+|sV|56}5+ELPx!}chMWMaPETAP_EPjEUKuNNSd z0Z+|h+>SH&`p4X%*t?fCb1h{tb`E2h`%h`)N*3P9Tt5zFz z%{U;hY6~D19+1QE=$}wwU^LYm>|t!NPyr)wgwLc6xFP=b?T^5vcL}(@yDP}eh1ADy zb~;hsYL}9hE*u?&sYnviXs|@Q3%?GFh(LS|g2(H(*EqvW@vHX#2tS6{(Xfe@Xh0%C zuJ$!dO^G!Uj{HkFB4UsmDEn+xfDfA? z$vG37(DL^;m4D<9w5X%D#|J>r9tPUN54eK|bzN1q`bMT1$c%?+by8<5Rgp)w+?ZF~ z2S|Y78=Lz`koRANQS2*5`;Cm3&*s}3!zj+-^)p;u7wqeTL`!-5WIfOX)jXN&v$l1= zWM*?`hcLWr#`v&vJ|b!>zxJ0gduy$&&5nV;3{ZAvYbkjQh2^mvNYNI!!rf614`De1 zN8Xyc29K8kzr}DhoNhMyG1+@3)L-5cF%qzFE$y2;tF6Jx*Q|YxFxw6eZ4@kO*X%N4 z+=1oMo&28AzL~B2fv-0ixoLZNlQLQdOdjBSek1UN|H2gTIXGBkP+wd^V&{g@afWy(bLEHEoLtQ6~vj` zzcNO`DE~`6%<2Engi(R_|3|_IWV&d_2z8Ib!Dp;O= z-qHLoByz4UCVIcix9e2@+X-3~*_EY(^VHlc#q@-Vde5g?qxd*<2}WU)t0-7A@bW2l z-S{{Jk;Zt*d|h6=?uXw)3U$^GJnj}xm}A+_L0N^X#P;%vs(kQXFQ3ocj*r--B|08| zzF%%<_2C2Q(IbcdBz^Sq^%=}|`p1y_kw_7@wj3`v30e-Y;Gya+-+=<5%yOx&iqFUVwmb-KcvKcn$_usUAKzIp$D70PhW6eeMW-@-}{e zSCg}_V5b|f!MAf-jQ23s>A&iRp?SG?!7~I=wQk@X}yw`705_`!>NfLhmEmxj{ zJW+CGf2rEzD)RIf=Zm|>D;3=)QPe=<41gGop$&Wg>;>(MBon>5 z%)~~f_p>|NaI>I4YEH@}&FSjW%e0`Yj)g@UoxSlWT|3$TNXQ0xdB)OfKt(N2xZp-` zPZ%hqI*4bMy?)d_;9ROH9ehNMA_)8l-~&L4{rIF8#kc6;{{yCUyZFm@tFZYio0rmM z^Q3xZjr#KGmU4MS6pR|9fOdlLfP_y=dI1P5?^zda4%X)$H<33L-@4o$13WI8C)74P z);%U1G7q?-%z4|avdRYB70VY=C$xO71p0C15U^>~#Ok#dj}4+I17yug{O4Ays^~0Y zh8NaaU5fDE*($VJrKtkghC>=FepE zZeBf3H!5J~Dm8*z8ba=xxQKeG?XNEdRlz!?sAj1(>jHkdA{wtI%K_Ul;kTCr_Rn#) zqaV(Q5uIM)O~0Rhyn6*yQC>WpPD!Qf(;pm6yv9~&H;YejKOhq~SoQ8q7luZ+Jr^TR z0!%?ce7l(EH_I{~!1k~wvU|$ndKgcmf4Ru%%QGnn?PK~x>$-|VJUeGsU z3Dll`VQS3kc!sb`nQW$vNWTBkX5@0ZYLks%%m{ayCxrJdV(N)iLp0!#`A%GKy1;+g z^QxM7_efcJ(|Y^U&WeVLhbJ@B=iSXgzWIjp;x$G~T{6yi`in>r{esiT*Z8tD zA?(Oi8r2AGw+3+so++i?TG|(r1F*0Yp}k`2@{$f zrS~aMRkEMV*XuCO#3h(FO5_h{z|`BYTO5z5>MYF6SfXquXZ28EQkB!dCmI-n9BZ3H z^RziACJ?h~>wu;6^R0FKyi%)G8L+fo2QT0;l34zmXJUJsK@Y^~*X&7|)V!n4Wo_c# zNPX%1u>IASUJ}WP3>LxlPZ#i5WyF|Y~~p;mZJe3IY{W&Zhpt; zz?CHlzF(n@eFZyo->FSp@MC_sf( zQ4bedQ!uKm*LqvA`zqJ3lF*NVomA9Y1kiHz}904%!r-Ektfpc2pSLp&U|Sdp*g*R@6o zcmeLxhO(kB1C|UqMMhw;8#&)U^JfbN!<|+YMNIy#06u4ejy5Rz%Z!xdCj#^?AY>GQ z6Ck(~qM2|IvZ01KY$pP&7$f1Eby!mq95)u_Ukh5TyIwXcq&F`ohb5iwC4z}xtV{ti z$6MLtT&pCG{1Q+Qy5s%fqZZtLcwtnFEA1YQ7EM1$4E!?zY3rI!b6)?bsk;&uFzeubmwGEiFR@cvZxX*Ukvq{L&UoE0_s%1sItc^?%iFr;0gEtZ-bB{H! zUO(ULGRUBgGWo<=R5}@J>x_@x1=WOBe{WVO-} z=l*akb|TL*S+VBvD_StkYNJ}=75udMF5$21^^zCltzYKbsmGWkCq6bqhW?pJlpfKq zgG)JWCFjr#Oo3Wx{^q7x8L<0KcZno7?@uMYaYjmC!=fG!HAvDI^>2S8MYU3aZ{72$ zJ+a?TbNUp-c!5KYDfrCujcHU*8fmMr0xurv^3(wZ^?pS4CS&%!jNu}Jp|?QPMWv3P zO{5u+ITdCGBl}WKaFB30YBRVwI?T95v5-Rd5rK)Iya!?^tZ) zq(mE_cjIjxDzVZKYN_p+Db>$t6#F>eJwwmqy?=n2t7~q6yuCG~_P&_aIY^t0&vLZg zhr_1IHfmhzwD`MO(2}VWApSj+4ly#Sj(xben=(K9x!cJ#$||3Y){y$djKxc3Pq3Z% zGzM)vD;7z8dg%r&K;yx?Ks&y=5;b2vQ@11VozjqY@nG>g`gm3l9L8^GjUqtlw820) zGTGqbawgyO4>T?J`zo_T#5m4)oH9KE(nP7ahcjMXRuXP#0l3{l)1=~5Ck<2EY-6dcJPiDCD&JmVWtk(EmBC&6q$WBkR z8V%yKIB#I?-)aq0bkDQU@FzE9b;=qO=L{c|;i?=(U@bRHS((7ECl8bniWPxmY*(xu5C{rCKRHbp4zDdhCnWrcOW9n4X0_PLI+rT+yS8r~ zm{R}&^a%6Y;;~pJU)sY+d@)_kZid~(?JwZGkEUbZ2ipy8x5Q&w+I$;$3T%x~5pt_P zI||J+s$mn@?875FxK(>TGr5U>iZ)pqS4@pwP3VQ1&0g_v=8xs4bUs5mD7nMLu*r#| z-S-xP=XS-@K%C9Ncog1*CJ$b-=mF;4uTM zDB?#a0+}JPARDI;_MmpeOE`{AKs)~vVnI&@sngk>EbrLLx3B5!%n?@IsGdp17|=<| ze#%V)mobED<~ln_D+;{>-W1av&j)GSO%7uZvx#8aY#lBeA0C-t`&_81C!s8YUG-3P zA`eCKt++!>cKti?6Nuz~ZiqEMGPI~YeHyBIt{pqbdfRlX7tn@{VU53e7-cd!GDV#6 zemCVYa+51~iQKCv6#?|pTkb=e_dr9g1L}fhu!&w%AV~&nRRbrfp;hx>K)?YfM3C!_ zhzx_0Hl7?Sp5&mEIx8kB+1q`<-jXboo26H?g?`7cZ(GQsePibYJ{=|P9C4)uM}v%o zLfCcE8p+}%gBdak!HA00%~5&prubUkxEbdJinF0?*pPHmT;<@7JsN6L;qay(q*c~i!A;Tn? zPpg=^AZAhYe2wN6CTf@k7y_$OJl3LHW<${+J+8ggRU1vGfx8zb5MN>4k)H(uY%n&M zLd;9@#l=-WSg5o`y==1hoFsa?W)CiEIjK+f3&MmHq6*J*BEryQA99F_>C+y2jue+G z&U!%E%fuA&IOV9-p{Pq@x=2F^!a6D2HmQyjrCGcfU$U5Vw+#_1M9d=y^3TQ8D3`)_ z_KCv+dce+vR@Ghk##_Btn=Z~E(J_iw&hP8w@F3lbBq=F>fps1iHtw?3Q!jGvt%|@uX9kX&VZUqO&Vc4+05zpA` zvi2*rd(=&}`6#r|*(Y+!fl(F-Eaz(H{CLHuZ=IwfKF^5P`PwpWHYc%6lXqpKQlXcq z(AP@njtUVAjZQCZLF1JeTWc5~pYF9(!1*a7lt=)x=b(r#XKBn9iI~vL{6BCc(GR%EQ@~^2og2ZizsX<8=H#HXl0g$bW-J!T$(d<5Pxtu=9m8?5XO6a&m#?ypz z)jAe#Y59|QN!Gv{{)84n^k%_Y&5nZ{1$t|MO*;9P4yF1U};qABC z)Ia?KuoklA5xdr>?x|Ox6!wwa*cAsOUGdY+?W4LFA13mJ+ZIsOt&+7YTHFu-J6`jE z8GisB1S1@@NQzRki+XnXu#8Bf6mb98q=y(1X-(22qSa*UOB1h|t-tP~p+@q+N)^(w z_1AIuh-8fre>~AbtnU>=sd%lAD;aVA!g3bG->eI{ha;h zKTrnfdR2)N&ZfZ6-WRW@s8ej@2OjT_X!6eo__KZe`&Sasx}bT`Af7pZq7x`bKl4E} zSN+k~i-A=qrd|^yJf9?$xvQD8ng9K#2%@0ob7ex*c{{(csi|+OLQ*#+yxwUhk{T4} z+JK+0L`Jx=beM3m#mNHEPl%-|;6dbkv06|Y{MOYYssb4ak>uF*nfIgME8Nd>=%-dL z6RTeXH1`^;VRfxu$C~swd&$2$WDO0!)mtw0kbzW3C@4H&EGX^eJD;h~QZ|z^?=3FR zu?6)1QV6_Vi``QyaBIN!@ocm~G42*yZ3uPg&<7x3&W4X(D)$s>e2_=3 zfcu^hRB|L)b$G`{*_ppWYvnG`0aU=x|H$`B0j&36!%L78{@iK2%vPj;E1WvKI^EB6 zm^-0T_IRvMUOF2V3X0Gbu3Upv_4hQ#Kt;8Ky*&;G<1b2mN@2kI3^p_sDQVFvMF8m@ zfin@;Afd6Dwl;2t2`NQKbnCs))$Z3Tv5cvyJdunw`;>}hc$YH=wNU@G^W*Z-_gpKf zG?s$rJ4EOUj*Klf2O#c=#{&JcAa~^5a>$q7-Y2;J>;$?@EGAQYuJOzrI*#InBs!iD zm*qwqygbZ+vtMMs^To4$VkgFOitWo*@i8i!wOuET#h+x0p+PL>}M-&Q*mW9ZUkfycAB?H!PA=8zg8`~s_7tz z?+T0&rHbJulpNTE_per|mR;B)u9q0?j1-*UoTfW1Y5<>+`|W(D3eO4{1!{}QY5Dh;{F6i&aykzRCq&XDf{+{6!s> z-pzTeAm!$~ipwe${4`$`kIT#6^?mibethn)O;{T=I$I5b#TraPuYddjeDJDBz?5&c zIjSildW+A;`)re4K$$!?t#;dY;Bz7KW{PB13OwAafoTg4yKPYD!45MF?q96TH=ui$ z+fzc?{GF$|DDB1($G5Ytkt4&rTMHf9lEF2@(2x7is|hCicYCkTcX*4E%MHg-kH!d1 zIlpcbfT%tyR5J4#H=tCys&&4$XYn+CEx7ZX#QUK=`!GA4XAfc9N^Y(0{}q_bmS{`s@e#pf+urf(h^E+=d41^@;zM?cKp zlnhtCEMJaUZ@Sb!C+u#N-nDY^*0>=CIkppVJk{|VwcPBgC85rJ1$=mvM{J`)jpST} z2~eb+(Xup_6A`Yon=hscN?d>PeW5}t?_$0Z%Cz)SQ{(|loVy9QxBS^srD~T4w6&r| z6zb4rV1?pl7RNW5O*kK~G(!jl1S(9xX_@VuTj9>z8`Q2q)*%??VEjLny>(brYuh)x zK@e~R1`&{M5J{!GM5IGHrHAfjK)OMtySuw<=W;5_N{6Ev7aOZw&Y{wDwArQo&Sh+dXf(@#}_Q#V-N9Qx#?>iovO zTGdkDE+c|*$BV%M9%+B{`O8-wot@=*5DAm{YWf3f(w7{26_Q62c@dhDDsf@tUGzSx zDsO-gq!(?t>p&8BVSHY=&_;q@;gNKx^oR*D>FW;~^ z2GO$SnHdO4@bS@{DboVKblhQn7zIA=@FaPYmLtv|DqL*_nm7SI} z-tdiX)Mz-Z!bUm&!bfn>N4QlVxuzrvE}yTbGePRzXBE4ja=F=#h_ z-oqKpnF!tMWc5iEjPUq~F_=yhJLn^b-gL}u-QnSXW#!sjZW(Sp-YYh4m5_x+wPTFy zk2pQ#ZA23_80vk4ub+KwIB48gYW;dCHSKe=`vac&VogG`W>X|dfCFSU`tS``5UUDz zE;^_WtnkIbEL*8ivy-TUSw!S~uKVdjkl9o%jTE6fw+LH#72JIGWhQYdqcYtqA<&yU zJMmZdXD!-7NMVGpwo*KZR@DZ+r_4L` zbR>yvKB{qy?Cd#-s(Fpn;bDFK!;GmwUp6Y@PQzxoq*3kyJ+Fp>vw>76AyrjXyI(yR z;d{yl{xt`-QzVlvMK_BVIK-65MI^{IO7cbQvC23)#TIPzT~4rOQ&F$nDk9Noh-)|z zug?mc)LyN%UVm9z-yahpSCO#OKkQ*F_zyyhp6T2BUrdhvnFVlc3m-1M z`>`yveP<9+LS(YabTZS$zK^e?qAT2LhN5wM(CuqbcqMyAaXY;E@<%$BC^@EtPVpck zPsyL+&MS%sqQY8f#3Rk2bXo*^R?Af9yPsH{PtOjp@4`z6^|0z%DUj|81;J{AwE1Ae zjVACVJ(FSOgKfStW5>1#ceVTvyKWzAhxG;#H-c4}pV$z}SAVjc0Le*9_s678aJ@^G zS5jSAJzyG0j=GhJrT7_ibElfH>?;-DEuUZ^R_VN>`va}Wyhc#ClM_J|S!RZu8#0!p zFaVmwMRIO=>rs)urXGnkxV$7$s2WAF*BMQ!@+27G@M&yKMvcRFs)#z|d*%cBC3P}= zv#!1+!Bl{uWOA2OZr6^8ZZck5b_-Km2LS?A3+oI|ErY3U8mGveAhh99-*YuRmbz8{ z%PWM1?!(3u6D$1pIL&sx?~643xvDIvs~-k5FX;vQ=VMt%W0w!P<*Sw7sI69pkWW;Z zBdI2ymKlb|H)_|0ulSP$*Xu;Pc7GqGvr5VG&Ju#MfaV=v5>YZCEz`JLq}^+%cUP0d zzLWrXOc^$&aydQg`0gP3NYkt+b@}aP>o2*)>wXVaGmJbsBgme6L(lTO2!%MYaY~7& zaC}4O76N14SH|r=YyXGUupUKc!^eTd2%*%_mo>b?XH5w=3peVS zmD5avg`E)_4|g||isDR1+^*H1kvWC^=d{d5nsqGGxos4*1O+`C%!n4Rs-fm{m76%4 z_H$LHHKG?{hLi42^L(n|7rAOBtSJqTYluO-=_DK)L{##0258mvjo9 z&!g)dkE8_!tBip>b6wI7IZg<7Wh)afP1Nii_PejUFLki75k1Kuw4^Mj?1}Q1Ic3z# zZo2>}-^ptHG4TChh{>1BtS`5{1o7|l2lQXWFD!P4eSvfRBU+&+81BfuMqFcQlsk}Y zcODz}7nET5bS|+zLSEI0?mbH1SAv0fUSzTnNobSJ4~X{G)WOc- zDCTTOO+%SKR%5qn!0mJl@%R((2MOfhBM)Z(6{p?9QOA|)R8rnMkdA}tE`wTY{O19q zxem&a@L6y3s}3{-Pd1j0ODP7!Gc(BDfZZ>Bzqj*=**5M`h{+{N4B6|Ps%%Fvp0wBj zwJi#VkqN5eEYgv#@>y1FaB7t6S;bSpW4R}eV1Y&ld=!NuUvIcC+;^5A(L1NHF4rV* zn3YCjBky6H%E(8yL-YeVoix=q;tC%rOa*d!>CnOfih3g0(M4T1mgD0+PY^#sOeavTDN!7gy zQsPB;16LNCwlVPZT5QL^P!818)aqN|;<*a*btwC?+bW8VNePXMd*qypuZyng9S+`I z9;uCQTmUP=_xpj=9Z6-4*{t~f8C|s#onoGHb=%@7&iz8vK`&JKA!`vHGdZccQESgZHok6Y8%zT>ezFTN*0{H6rPD|IkZM zls22%`;Ckp11`1`P3E_uS4CVlFS6u`UdRDGY=3i=6^*^YYLS7yUcR!4L&%5SX?oig z&%Jzc`GoMxNu$Be^>C@2&umf4KujxRN2GE6>M`2pm0_ae!QA=?%>t9k%Ql0vBd`jhR7iUk`6DIa6{$=Dyf|eWi7*lf_2BUut{1#@$m?g z&*8DEr$&K4SPG?qEz}xxGraD==9;kt<(sSBN8A^Ol_t7uB{^!Ay}7C`>$Ng}v_Rh( z4PP0=@`!MMBbB$$>%5fT>Gu^RMFAPS3>B(v=j7Q4!)J=zEpwQbG>#MPY`kDOLifGI zRQq(sj@M`{rTSI>-7jb!V9lux&93SkqoTf7f z9~#V~aZTzX*8j#ykp3LTvHki;BDvdeRxxfx3|DQ_!AuL49?*dWO635V0m26e^~6ri zBaOnK4~{oN-1IH%GlB(ZWAOCefBX+31#iHv%|`OSixfmfK?jB8!(Hz#>P=%BkIe7% z-8~33FQ&Eadu&osQFSoia6n!d*=m3*Gp+vEG#lt?oFcz2>+xy=L{<$`nO8gG343Nj zrc;GjXal7qp6-r&Q&D~|afP%!9;&LGQc6tEkf?oFyHkb6VLeMB>puL-3bJ;^iA;Mz z{NJy5c91HEW=cSz`=R27nCE;@momd;w!k>M?rZ!iiTcIAu&zIRh9%6Jo^?wyotZDy z)9av{>7Q|!$ePHT_->n}nFe#l;)FL|!3A0Ls%tn&JA_KP1F{_p`cFG}*y^#EI(&IT zdyW=ap$*k#xTbXW68mo-xhRg=(3A1p%a0}GKEAP}g%?ye$=1D$)5U^pKnuXMh$-~hKidw+)KbuMUlg7jslj#PqbKvgYMIqKZLjs(?(B`4 zsN#V3A-xw4DDeZSAq|VE)xG}Wos;K5GpWjo2+)WtWoVzAoTz*)C3oDIecw>`O|^m> z7TgaTVK)Xx?YDxP)U8r?@&Wp8L;*qW#n@u#LCHwgK4sj4~i68en!u@&h+ zdZ>AXi|iW@;=wyL#rY-6`;S2ulkp$M(PaC)N_Jj*XuH0|7vuGx_rVk02!Oo0{;WG6B=S8K@(x>69Sl3c0f6O1FOI2clM-@oumhv{?cr z$O!+u0}b~Yy1Ny$sNB+nO8WB@?Fg#YeV;?#U~pe*h`p!Rd}{ityb)orRWbVxq0x^( zW*S%L$f|{bH+0^L%oo})CW*UcmAw(fcC@&<>)^ZKO@$4@wlYyHu|NjJ5NIb`Be|yv zTx2-wGuIzo(!h4@5xJMV^geii6YV`oa+k#c3Q}lhd%mXR_>YG0D<1&elR+j@68K8x z)f8YANhWpirz|3YcTG&5Ugq>}FL#d57CJ%%8^x*|@}#ny+d5*)JD=VxO-stXohj3E zunuT4Mz6fSZYNsPYH}(2sy3b$J*n6P_8YvbGvJ;(T}pbT^ElvOaVVf6E(tO7IX=QBJw3K{i- zCjwA5IB#VgSsl6eNeq+6Fj{M??}M4NmFF2DBOE`c&6M1BHD>eA1BM7Y5a7{JWlLDp zm1tzDh{59R5=mrjk+>HxkH$v9hO5w7@f<1h!~w&ZJ7yVqz02nh7hUC@?@f~hwDrpL zo;zruhlgqJWEVKGK(zeG-BjEB10k%&e?m$5-voxrGK5kO#ynCX zXiIVj5#~dF(gfw^lxLYq0W=`-`Q|9;jbE~F)irxhGpF@zopDYEjSj37+$8$AY6OEQt-v<43l0o6k%Tb3LX8o>OI`yuPLbF$L z(R+un!&+Vm6|?Vs;_2z!daZZ?RQR<*e>Eh8BSY1>Za*Lg1@y^#2ehOd%!#x~L^zxH z`UIkEre>;)MWE!FKBK_iDEJ1e+?et9*+D-2A{)*(F*<~g967t4Q1~>)pWr9#C6|g* zTOVOc4#oNox#!^Z>bzc>@9$FR*c(V>5lI5zKh6<`Jm@ZqmObZImlfV#H^w);nHlA>`5-&dTe?_}r z=^#e&*PY>SG;23eO&S*68KL!0(pvoej$ZCfD?^%Bj#2Qk(FpgeR9r7-h>qL5k!JC& zU!uNY`bM(dDxvYZp{7f#;u#N3WTu)HFxZOwz?iJuH@f(FXBXSnF=urYt!fF~^rBo9 zw4A_cz!$u+mn;tS8FPHI(ng|_E(Y$CkMNkWN#5Yg=djE;o;;ki?<;M1YHB_wo-_!O zKM0K>nv=n7`-=%C7JeL}JnH+<=&RCc44n*;T6BCiNheOfEV#8*AzO8g{Tu%xjV$R` z*yi(6;URB&pcHr$WkuH!g>lYopl@I;UUwI=qc|ox{}~AEUqXzIn_qllWDG^MZy(UT zG6$Y!`1=UZzw(*X3}_0}@eFnPuC6Z%P*mL>9d@6(qE)g_Zk~&2 z9DBrdhgY;$Mwr2tLaH7D&*v{&uxo;5%rroiuPC7tK(+M_-_s1}z>~f*mLr;ljv2I) z{D@4FbC5Z$_$39m8Vt$e}kkQzC=cBDh?3Q0Ht#a|Y@u*IO>8ho6inlbM+zYsgm9of8k zETZy;-|jy4ZTF%Fxr*={L-OEE-0lev21}+WaT&?CGj_hDP;Wu-Zdo{<&qMo|a9P_* zTd(mY9+YLT_PA#uu^$lN4&+cekD=as`8;^*k zk|UEq3-?zKG|NvLBa)cjxtMLBMnKq0LC6l!vn$eS@{{_(h{>}-MMd=j4$;^!LUZyI z*4`dcpPp`pf2;F~b}!~4pGa|@y5BpF6j|syW9A&X%=}idRQ^Su&Aa-R+#0!zPcUY> zIUt{?dr43Ec&!_5HuD?77kT-a4vsHQ%F>@9l(1)CW#|zwIKZIS=G=BZd@5yOFI4(X zviH9jK{_qwlV94_XPoV3si`k;d-PUV-*mA{Afx3`w0)#~GMm-)F>%g+h^?@w7aQ?0N7TdZ58Z8BdPDv4SyP$XD)I64pgv{Vt` z9~@D@gfFmLK%nYy9~>ISv=@p+T+RvJ3_M*WkdQ|^(>F}{Dp(y)uK)tI&0HerxL#DF z{tQ*P(SN@0%j!)Q*P43>~u0NU-BQaUa3* zCeUJUQroAJQ6M&)}6ES1sRDoVL#7>f(b5q&91XV(Wh9VIv-zV3@Yh(EUq z8jNR^a59sYk--t-q{9Q`C`Y9|&l`!K%}rF8IoQ{E-4P8y{iv>An--UObm7=cqsOx9 z@zdP~fQ8=qgzG-j+WACOU}O|^zp^u1k)xvEO*6MWn&C^?HV_w{XLto7)@9Yh0N+&= z?7EIH5>ER5Mc|XP!i*UQ|o{g6WBG2E zS-hWT?aLPuWWElnRuzrwX&mCw_fs=V5Cv~Qd7Q{540&i-`>u$rX;1qjske-suw)mL zW0B7?IsfS_mN59H#qNr-@4DuYbCMI7g@^1xJ?qmSC*a!k8cDiI|H&%4l$qiF#(Ux7 z8L?bP&4mvW#*aH6-d>~4gPF2tp#+>`i3+P*Ox`u|>&i~#cD{d!G}6IeQ9yXAGTUT~ zg=@pgu$t$a_3sq+JCjwFH}W}Lh1?7L4U`SmmN==;5ZuUzqq|-?C_iV(9Gfqv)dGko zxItPUvi)wteo{}qSpIIsQ7o4d)`SS*SYJ-Z+mj5fY2HXe^NY<#v53Paf3$_~FuFgs zdtD35ayYs9V_46*o4S5|8r-fBaLsVgs8J_hp@%RD z<^}yxKD~i@Xui0%;=Jc~epP2qm~}j3Z0?lu)2rR zkp$ct|5Stv4XnOTGMI5%9FSD|vJD;;yY-9fYik=CtJZ<33 z!QDk>W0@$EMfh~O+DYpiYMh*PXzTt{8?_M_7#LnxEZx}sy}dLzcYP737V9&H!0ILM zpd0M(&p0D!7zdVTb8hZiAvbv=yYpPf;#S4G)ne$-+y>pEW>eIxc4d+Acs4-^X4zix zIFO`5!_GcUePs6vsRPb@A{Rq*Y|AVMG6yTL^|!m%7BFUDFWL?-ZY*hH&0=fD{Mn`cOL-*FN&Xe+z`pw$p0|2>7YcF< zkGQoZGP1En&s9lKND>K>l9EOyE=WjH0H_#cWevSrWok!9^}uwP!(k=jxgtFySAE>u z61A#%pUt7D?|JY)OzueBgtyD&OSF3FNPN{I7PSg4g{zoC1IL*&C=`C0*+RWfazR}~p2nyOhRjhiGCxy?J=`ffu8l>r}S>1`H-Na@8 zmW3nM=El+OVvaRtqbH%bFM>z$AYdz~g=;|@x$-g7lT0Mw}#%>j)TPp<=A)K-QBo= zn8i6(QnSuR6?uROPFniVcw%EP(Bw{><1#X8ZEY==6!aR9;npnKxEB2uL(~3n?tPIP}YAImJOGhWkR5YNoY z`ki9&5zi;Z$47~Q^=#wCDOsA7-Rni>Qg+s2OZ7K5t4Qh4IO?4Y#l75Iy9KGwhtkmb zDmHNs%UQf#FpiWkceSt+t8l8~hOi)^uHN<`ToX;9mZsccRKYaF_7>xIc`npX;6Tjz z)4GLc#MQE^ztEoVNO#ImTHt#3DR;?xOR?Nekel)Onx%(mslboOg$ks>+u8N5T7Yx> zP^5Ch+jMc+vX3By)eHnaf9nb(A`Q-7emY?UlxIj%^?HrqkGvQV|ChLuGCY^S^p$wQ zQ0EkO?1pOdc|nZE(s7?V+f#jPDUWlMjAFnqHxf~ioVsl&M|Qx4K2fAzJz7xG)YgK# zO!p>4{5bu89yv8c%>#-05r>5yq$HV~7L@MWk_VJSjXbYo)+ zXJj;^dwZ=jc%sqSws-epbpBE>_HZlBR(mc7RhU6X5Is4<_9 zcfaU2+S!tM63P@tzJEBd>%u{%5Mruv>7_c)ECzXp%Y(I28aun0G3}q-o0S@HW`@ zt+v?9Kg}o-bopkVP5+89RNhbf7AW#K%p4(!RtK*9o`BJ9S#h4({un*}6Bk=8& zoFB^bRC2%NF#~F$*9bv}pQX!DDhi`C8_n61__T$Dxoa}0P=)do72>jl`UHO>Xq5fP?qmPK+B~wK9%6qtzRmMQbXQ|4e6cr`R!px8_``dwf|I_k zuFoR|(}Wi(b}jSyu_j?m)O`_s=Ic*fuZ>)xGNN7!LBT4^D6`i4B=zEO;$jUiJVXWY{P*{FNzs++(QpM%#KIXXXykLvl= z_|s4t4E9BcHss+UiL2W2OMP?Ef9g$BO-NScQvo-=QK*4Ynx=$=1P;AlHd>fds&SR^ zu~3LzW*wR6M%`M?(jGAHZl=XlDrOqEVOT=d><8W>OXUW%Wy2Mf9(L`_%t0Y^D(Z_4Re19KCIzOYYrb>Kt#MwrlDm%<7WEB$&+tN( z$^GkRe%q>a=_r?j4~s%LfY2_h<>A46R8NKU{uGE$KPO5qpFbut`?vRW|4;8}9*H6! z6EUBS!o5yfmQMTgMgu+ehszCqd5oimOW()GO@7F)03Dc_%WOH8*~2SgO>x#Xh_PPiq6IS+dhF4G1e4$1KUzpMumx7EmNA`8rVCTG!YA|t&| zn^i<@;Ud`k2TM)!Ra8wf#7pgct}WArssYr zzbtaj3dg+#9#>jmduf14FqS*P^(gBoMVo5rv!o=E^SrIt&iLDoivI$r3F#3O zIShmb0F;eI&80&{XuWuR_nk7Ouk35kY7EpL{_6|H=on z4ZH~^1Ap?KJ!63J!}$Y}-m*_U%-ziYVQ(y(@^q^Bk}auIQflk_9DCZ?`3C57$*In9 zad8*IzIttK2#jnL7~J{DJ>E-k!^=t4efSS^BQAU>9#A@c@87jvY%CJ;d-E*ihG071 zZKdethZ^*YmaDezsL_|2Isf@%;ZpuA8O_cQ=9MMafP?s-jz4UUnKrGD93OuCuZ}-0 z-n9R4{Ea}!USe(o(6$ixB8zZjZ5`b;!1ZFc)5}=OUrkB*Lg)?K(N^?<@jTm)!QkPF zUZ-rySHZN$b}vKYZ|eL?u~}v9qIut>v^d4>KA-d=xAK~vX*UZ~^Os8G?)Wr5tD9hC z9*f*9I>*C2oofLiR7{cLTa|sG(4#grZgyMT=kFrnv`m@EPf1;wS+T_!V8#0&-t<;a zoBneZPn%ot<8~>zgifuAZX?OI$$jjV z(A|jlRauoF;qA$@@esSjfrs*e5KZ3_KE~R{$7%lAD9`V_*Ut>}^~Z$6c?=zwwQ*90 zZ+>R;pX!~cyZInGF#|T;aksqTzbteAc!L#G5%v-0b|=kaE;t>i0B;zg#Qu?5lMAZ9 zlo**)A0pPtBY$R`@+F|mbd*J=F!U0mdlV?wI)f^20q#Nrgfc6*pL1AohdXk=@9MB7 zx58f3h5}#I>4|E1Mh&kB`GoReq{PWM;@5C^> zK~nT%Cyxndojmc(TcF-g`EH+{BT0s{|u6#|KlqP++YE1{8>xg+T|}X%zer1 z@KS9bELt*|J~u>Iws zLLJuwJXBP-hjZ+vQ*^6koV>hAXapQ21UZ8#{4E-6N+a@bx=(!BZs`()B`TI}LfoYV zpckB%jJJUCWFhNnZPLX9me(NhgahcYttvAiu%r&VtkDCaW; z!If3G?)5?h83Pu9Pfg0j*A{THE3M;oa-M&$AX71N<&m$=Y&5c5GVnA0EOQz^rn0#P zP}NJBrF@%`|BIUachfs5DqspJcw`=<|C3($1Fp!p$O*y)0CUJ` zXwU(R(xz}6Gg)78O(ccO4#K#WYpAdPc4Jf$55SbA;#tywia0)Ed!>!#-P_Wuse(Qu zMZbz_;A9hp@D&E#^Z<9vvd3pJ6JJS z1$~2Mdfl>sgm-%*Mmw9=^-@Wt;(qzaNwN+*|`vH&HkOeM5r`>PtC#A%o$hPf&;Z^Va zzLAc=eC#&|x^q9Fs*haJG6lctluOcn9e56y)V~o6I%t z8la!r+_~zul8trCbWYYfBNGz#N+(iNNk*p|8+ojWq3;+N90F?gEv2Q4Tf5{uRel8o z1c3G6Ik?A_fSE2_eTOwH%Io6x1lO(_X|~tUKhA!G5&NbjR&odaZp~B6_ydqE8gn2e zz*k@|_axsf?37FVteVH@foXbm*g6O?Lx%4rvZ{hV2beZ863=S71M>xK?w;5Et$+y? zz!GW&Lq@X!dknsmH;E4lx6kbTy&E|pH89^JgZrrQOQzuV{mpPnHZF7a7eKHt68{=f zpj;yDxOhRnJ6)0j=Cj6(Xa}z41Hgq0P8%L00*}9_`7z@8GLyI+!<33OL{dB+>yk(& z0Y8Y#T3|N{)fmY{i}m`a-^!?dDITPk+cLnbE8{aFS79h6E+&@d@pz`~_XkeEW#Ff{ zM^gahYr0+orK67L3^Ogt@%w(A0LDR$9x}Eh8pXWlHXLVQr%@uyzLHBeGK%_R1Glk=uQG@JKIDSmX!UU?VA8OSO7Sp)h1nld}Q&h;glS} z>?98$XWKwf=4-FlrwLWK-~ejLSdt(Su1eyI-N}rd@tg|Gc%iv6J^xyqSFd20?J*y5 zbEK1A8HkFC+Af_S=p0r}Yhk*9VOs7tlwMXZ1or_*gG?rc59-5o84k=@KJIu!+TN{XxXP7E`vO@^*xcwnb*#DKTl{+xV)T_#%A6w|N-$>Bb z^H8Q_d%zy#`xVh&`7QbTvLZUQ3E%gmDDkW^V)hz&Vb46m3+nB?Q9!RfuG^0~onS&T zR#r@_Hz9=FO30O-ts;OQWPNsgOMdh|{{i_IhZH~x!JC^E9@K0hKMS$u9MYjr7yB2w z|K|ppx`uHqp6dGv-J`;A@b}|D)_ETGJ(^Kl$H*Opd3mBe}~b-Sqixs+^psCP%@Dr`qQ%y@bCICHJD6ZosWtVqpTLI*A$;G z*ba|=gL~HVZbYd6bk5X+GIm7>;(9)c%c9@&RXFv+@h-$KI$1L1F<^v3sQ+P$zs01f z$PIOsh(bz)(4Yh1z7xlzJ$~0CP{f=6@dRDy8piyS#dwT@G(adJcDIi0s`!NOze4Y1-NfxJwkk3`S`c_^us>1MrO^(jSw z8!r@V>zGYBh`7i|LgzgvLDi*}9`S;4p94g|FZ1wlaH;?&=dASE;Zl?OSEN-!H7iKE zs#X;_q*7qny+HsukHa7L^5JTk8qkM5@8zupXC5^iY0Z`DkQ4H`#Xg12ym`0nVf1^G zMKI9-Ml0O;InxY;rge5{%?bSYeJ^ZN=XOeL{=641Yd%t`zIipwu%lIK{+qmtc`nWW zdavNY$H4-w5A`B8@60(63aC@u{31YFA_O+%NLYQbAHEb@-D@-s|buys)9D?05Nvp{6XhX`9K}UYDEOBb~ZfWs38g zfv;M6FkYy&UPGrENMJM9r$6*}Fx)6F79dCprJb~1DQsyDqcsiD!TjaA);!@b2 z2PyN1JDoxmu_r;!DK8?X&HtyAz=3N)t{kerYJGO~1vpcXF=b+rh4gUbgIh?a}>QC0EyGtQHkKG4SF z$aFK{yaJd8s@cHfnX7VF*ReK$eGLR`?Go>1XwVPvp($F^~ z!Z8LMF>J8sq;NO>XoO^ktNe8(sD|GFUP2e0fj~mD(aH15FPfb*8kZCzRx%(O78y5q z+W;-+i`_~ew%xp!*;j?`=24@Tz@{T> zC2i+`%WJbUP!a=#Gt+$9NBdJ`Czq@E_Z{qtk~fO&)vnF`y$bp-^%z|o9I63D-Z#|j zt$hdDPnpMS9S)KKU9!8|J*myr|>$(B@!AuHp6wC1=Kp^a+TB7k%8EqEQB(=mGR^L*8 zc=cAt>1!J#oz4xA52u+!pB}D6R5E8~RA9ugKS&2dYz+PXF41N_EJ)4``@OduS#RVM2h5vMdaR}c{L~5Ee4tU# zN#HW2WX1`8RafHk5kt(@TSZRc#{CRr&_uNl&GJcs^QIWGQjrJ6zPS$`uk zVk#*UFDeLx8L>8=V@|5Aq4-P(S?zO22J4Yy)n*$JJF><~yA~I%;I+3EYO55?-O;BzbjD0%IybVG|Pyz$noZ>eXIHpx0xt*;W6? z{$fQ-p4viOb2>f^{l~uR86=R}hf;~oe-8$fB0quL522RpPDa$1@hrwdz{o|GVr!e@ zukpwjdNFTOgN;(4eoXIyQ#~wT^cEQc46DdAi z0k(}@)?_((dB=R!ifF5uDj?RvUsdsjzz|I~y=EERGGYC|$>H+hqMEQqtr;JeU%S~` zaf7oU%vG^De~i(ia^29W`LVT45tse+Xj-wwt;sQC<&~_b!|_TRK%I}%M0?zh(@Gza zCg;Tg0TD7l;EjoNIzaJ{?3J|W#9#*m6T4q~ii?YX44IUOVF+?L`oU{t`)&6bB0z4{y@L=905$iJ~iTuWvIZsh#>o>R5EN0Yff z|EUfSkb*a@BUhjVl>sUh8z)N`!n|u$Zf?NiNw^2sFBAn`MVL%gc(WUl;vOI2N17_s;bU9 z+>DKnZv)5LYhyV%IWi(s0BtyMf_ElGoIBeZ2E;&Zxi5Bxauo}de4<(bMC1*O&I#CG zKW?`JFP=q={Y+_^LW?`Jp%Q-wrs`opoUhnWS8c|Q=tR+#zC*^C!VzkgPx2E_ny0a(ZV$#U3DCQ z6H4Noc-`=(30NOO$Q1y(aK7lcJPIs=&Z7=4r{CxM zyS2H5BY(z&QwJXIyT{uxZ0)nl-O2tP9^K{U2ee?zd5l>igSvr`ANSc$Alc43IoE$rg1-X2rGCDGmI#I%g^0!D@rnE>shHSQp zOIJ6j9_Y_WZ>3C8YrPNy#iFE z$#EI#$Ob+3G=GnO@P^OrjZ`9s919IUe~HF8SmO4in-~XByClF#AG5o^8|*JEKE z_Cs|4(%ISh3zAIYVJZ8DqrOBwC9ZpUSuyI0W7lyCebTz5&*-pV*O{a_X6V+`JmQ`E zlv}fgEAyiUl(ER%nw9_f>iWyggUgsU@P(Q$mF@5IPFJ0CS9GBk#l;T~3;LQ^WFyI( zwp~M&N=gjjtSYj1Tl`NzxIMKFp`a?PjDW9aB_^hLUtw^94&u5Kk%oRbfIh!_W)iNv2b3t21~WF3AQ;33s{;X=#a+CYdh5>LzM{p%*UKcfT+V45U+z2R z0m$GQ-c#@UM#Dk8_Sd-CyE73l&-BFd-F^~_IzCvjqm6{)G8-}toghekKt71^DSHBn zX;F>*uok0a=XjFRmiyDAnM$rNzeIQe;FPP)?f7O(`+Fxd+vs^j%Kb-(-w)(8kBvUX z^P8=dV3Y*v1LhZs9BuI6t`Brf0@s>rS-?ma;u-oxDZsX5(E=sV`DvbQ*&Jut%rXRp z5`7YMTid;&x&ic-S1B&LVsnko%>2_H{bp+%F6WSVmL0TpM`OqFLEi?K9}ihE?zGs= z6kY4x%hIK~KPaGdxu?BuhhYGu@#+x|n@*+Ys6P*(tq6djE8QQSKT1D*;n9{^QqCP7 zKk{#2yFF{(y{aKwY6!bE(8?tMl6-ag(YArIeBE3Wzu&-lI}NE5-l`5CP8=D*{V+a0 zF_EqrsDv zab7MMLYGbE?@sAEnvQtPcjF)N7dW3@ycTXE!Q#WxDCOWcof@7=85O+k*Vd}Q(z@lZ zb_>C0AF^;?8QwBfR^1VaDueU=9>8Dtadnsr&ThiV$T;?oru$O~A#m$Q%#As!An0}* zlE*$>Lcg7x!s=vg?R8^pqb}maeOi@a7ZIxDvE%-XPR-U--_~wDfL5(#AnITfr|NZw z1x8H+%~Eh+<3PdOGOcp)3%XKEO!#qi%O+#w3d1&yDlJw1uy+rLmowTg_Df4%Ca0J2 zzp%T%w*K*4$}WaM^Z$_b)nQe4+tyN23MeIwgmjBYhtl2MAl=;!0!nW}TIud?q*GEF zr5iS}X};yT_ng;zzUSG0!rs4FYpyxR7<0_`g!kPV+smz~ZwJ2vV5=wW0@Lr3f9r@P zn3#{K#QHP9wW?4JyHg$f2N;6sS1p&;eBH4d&+-SS5g-Dd7y7Hf08=d<%3 zrw0Cln%ye;&x5a$^gJa|s{a6l#wZr#=T1&#nR-f@ZKm(E%Ueg^&;!eu6(hf<4v zC`JM<-$TjW>TnFXRY$_sq>twU=yHbpxTCR|kVkfRS;mLXc=}T;|xz|0q01 zh>uINj!*4lXr0BR#7u!pqDus&z%kai5a2vEPz!80pUpSZWTsJ1wBFf4*Cmah2w~4a ze2&GUZFbrFW5Z7jx{o>-ke`A2xk=ZF)N|Xg*=jF@w_2E?{o5Wep^Aux0YOAapP5YP z%W)wh*WD=#%1BGUY~e04wHQ|JcOIA9Ec$I-a&Og3XU!jF7F@spD3;$7+5U}`KMv)K zdU7-fboyAYd+F%*G|5RQUoVUc1hNWuia*jTFAc`0e%&&z)0OrI0w+T6HeHj!#kXpl z%on6kd-Spda0BI9c9B+)`zAsdmYgscbNuz_51vs>Kte3o*+}?$M?*2hm}%9Rb53o8 zV;0np^lOjM#h~@PW}{o7p-VbpeCi~AaVwxH1*vNk;Hy2mLsHF0S zvPEi&8SHTBtWWS>^3zKc5y zL@cP0tsQ?xqx7a(0a~sr33*vj!`bcqXj{;-uR6(ez-y2OT(%q_L)8$kZoCTT^;K_6 zUcB{cQxj01rC*aj_bKQ3lK`Bq!-^;L!;^}Sklk;W^dToRvyyMtE|Glto(NDhzUts zRY0?@+1H&1!=$lD9Ati+?Ps2mNY7img~#&@(+t}!vrrh)vh3P*4a{|b>|h&kKGht! zVVuY)7?!LAeG!a!aY9kAAMSlg4}I|`8P%a73 zyY#v(JX3}ioT)>bZhR#KJkG$Mt;s{=>xPz|EeIS7gmNg;jf>pF85YOoM7Z06Y|sd4 z+)@k`j!GeT8V>8?v&v&(q9<^OnD{KzcBl+wfY&oDb@Vfg#PD+7?*Z%>rC)_04m|PT zMP2)B`NA++>49>o`lj+hd9xV?6C>ht^G60~NX_2C)s+@@$|f$oKM0Nbu3y4%@Cy~+ zA^p4w509l(Iw&u8U`Y?>e%?ZyD{QV^Wm5PvlHGpwk)efwm&Kx3d8=BTn=l0P4z%gW z_XSXv=;U$}`ISMFk2?8COmv+uFW2OUt$hXE)L4QAPnWlPBJm>|3Rxe#z~2At+VQDR zk?8J@Z}DzfJd4g{;Apv z`4#o55~929BUl+d=?(12Y{>sEkffbMV_hP<*6m2oNGT*0jA6vq#?Apo`s({0t``F8 zr7Qa0hsURRq>T_bkCCm0(5y(N7bHA2_~_S{vO`Ehi}i8MM_KtRs#aGsR%S;Cd%P2q zz8ZU|;H|VL72T=!$X~21okF}bh)0Y^y`$LEYR9fyYi72r{~RY~rRp2=i{ht^+~v(j zVJY}q|C`TiE^O@+O7XTRvzql)hfcp_oEAFfeOXA6p&f!!!z!;0(AoW@F>!8xLasVl z^HL;{=EtAmiEA2Cr!-Hm*R*qOWc8G&l@g}D-e;z%DM;9)V`iNbwO#}D zg2?`eZuN&!ltzDoW}w(l7^3L2I{u7Bj~#;@T{9EM6y!wfDL>h0QDbvaWtq(N_w z+ugA_dm@T=EP+_L497VsnC_c`)ZW}(3Aul#r``z66c!*7>v;euL|xs4KJ z6lSi+s@&*{RU{A>@6~{to?AFjn!5D=cQSv-C@LIlOZPj)g6?=J(!Q8~}PjC&om;=91X;XZ5DP*Y#3 zEjiq6YKrv1e@JxEU8*hXkN8OkKhbPd7R`3kUb zIBhLnqv!KY@7x8;&m(ETB$W{gXUd4IvePad z?u9zJvjriJMby+dm+q%p<;&~bVt?NIRkkwQcJQ{&dafkWnCH>+woD*Fnw*^{QPjz- zxdg5#qN;}Bt4z=a2fyh|keA$)BAnn2-=P;jW_-1b=1t{SE+cMzW40b-6SOqe2}G0v zQ!7gfyM1oR8Fa}E5l4K!?_ya6aikHN1nsZhbxG5#d*w?wU6cvd6R*LrP#+dRGfeSA z(&|kl4!*ju-I8D69oeU|^V&NSOc&xhSZiroYHazP#6x=xNja0?@_(ay?^ z#EM@mVZIyxn+L&`p-Y}RlJbK)Gls2VmU}2`E9w~1xN$`l!UWff$z}?B-5M+Omo*DN zQm8VIh$+?!6uT#}tjLd1(MGDr?lq4DzXg&uVBd!u7UI)ZqdY>GMM@yz+!bSb+yG2V zKl*Nq;OJ;bt$sz!HJB;U6xjOQv^O>?5cuL(Hff%##-KNK!!x3gr%vxr>gM>?0iJ}D zkMcEdxop#>lOIKq^8}Olut5U!v$(BW_jv)i$L^J#*sm8Ho3Cm!Rupu{fJQpKAhzz{ zYu1Q+dX(0_&<{X@#H&SoVn4d*t}p0%R=M#Tr=j6=T3vsqzt#Pt&wi!2>i4xi;#i5# z_^{sf0ewpb2KY4cRcz9X>;#HNN_Rb{k!g05eyjrmv1Xb`toE`fNgvSk@{_h(KW&ZuqHiwlOR}k5UONG zTjhS@zk)}l!!;}lgJ{*;<}!J?KZD1&$|3Vj{`Hb@V1+@s(&pilcZE&G4foVTd*?hl z%xzY`_407lEA$~2B_b^8v&4(p)3Np}*ypVXfrd+D=Dt=h*aRLTqtjM8MGyDHZOcu{ zlJV{1H7IS=~tQL~Ae zZtZuv`gV=`qzm`U3j$>CukRygU|c^Rq9vkdFYc=$=ppDCtp-5ysn*#Y`4yKl=JvA7hcH{dTF?j2b1Y~dpB+h6ZqFYR}?jD4IuVSkkM*# zPSIjH&h&gLd^_1?V$#Cjkv1$EiAPXbV9g>*r@LD3TM~8yu(UmL!AqK_NG}rKAf`C9 zOUlVCmd>j5bSHUeBX78ZO$7y>LA>V+QTT%#B~M=c%1o1V?|3s%r`x~qX?77g&lfg> zIO?$VOSVd}>7-((PNZqW`=EJ?>8B%`8vZ2yB11#_A9W0-^xJuK)0WOdFCB4>4ZDV4 zp0$f2AEu0Hh4j7IG(|JoY6Mo>d?YW%)V9nrWv4Jx z-8sT1$F3nGdB~bWjqoMu@?aP)@q?{Zcvr zTmEwTVb4ck${6uc00p`{oD6nKu@S{8p;!L?t)9m$?&mcFm{Y-npU*j4+KR6J`Q>2u z1KsHZW(LN`*AWkEmx8;lS1{E#G*F6>vAnTOUfX-K6k~l;w)__Xi^tj_xdz82XFK`W zRfv@wD@4lq?GHh39@O7m@mJiD)RTl6V(qup$D*4O*R_x3Eg3vSTlZNFjcs0oCAVm| zsmIp$!TPZD;HdTBR5<5IF!iXMAalfh_O#CtPirVs=t_4eSN4 zjJ6RMr&;__-vG4(&+DisIC3^g*`H9me!EV)xFOg%XTK(|5%li+mX2ldEWUY!og`qs z8{w;>$++Mx!U<$G>f;r)dqH4YO3)rBlK8>vmZzyUhG5_f>hi5pJ zzGL>fXoU3Z-bja4QG`R~qetS0Y`^(>1CsdcZO+}=fA)v4W2D}6EXiwpIQjbcG`RXS zz1xjw8GVzivia$ePk)yW*$SpUOXngq`wW~{=xs?AFRpIx9O@%|G^~I|MS!1Xnm?cA z%WQWuW?R%dk}x+C`}W?Z#DF-j7BS}LgD;*Gjd$H-8BOk>hi|QqyzCn7d!G$FBxOf&y=XU>eVumlxOmb>V4@us+xD>N z^VCgn>VYh~X3ehUkjMH+P@CIrDR#b|K>V%EhDXSoG~sHQL#jtBH*oYkgp7w0?%&p; zR#SPsM)YF+?chOnfWWhgUs4Tb#M?c`riIr-u3vO4J___;#b+@Y9^&>}8e>xYaCbho z-b^L|->4$K2SZaP8Aop5F!rGGV=0sIYkV60h&!xrBu~Znioc&_t)lTm%mB+;YuZ}H z-GiZ*EUlS5c@cBp#Znd(>PJV0$XUSxd%7T1cqf?@3G(vi=0CoMh_B0OM6n4H!?<)D zp~`_noB~(WozIiwp1bp*qW-vQ6n(X0}&yGnN{HVdQkMN`$gx7p~kx%amvVuQz z^r2DY!6~uAX3X#OI=^D7ziW7V>KndnO0%_HX*xn>pZgqKy+bZEe6yi&Tr8e>?-ks0 z^8fq!NEk4D2~#Z2z>R-|8uMQtA!ihOj04fK&%gJi!+-Zs={9=UEXFpk`BL1lc^gRWj6DOJn78}2fm8I0x|G+{COS+3BmY#VJPbKv4PmCmao>c9nAa-c~ zcIT{AKAugkY0#@G`)PJ=w|ku^Lt$DVOqk!@5M&K|El54g0fd0LddQeozkUTZ1{W5l zSmA8-R)%`=18S2|1K9`YR?8=@&Z*C=TfPv2 z;-N9-G+i|9iApH`(}*VFx?))e=r7XRAk4Z_;;OagudHJguD5IvVL;@}Kdr1$C|gl;DcP7Y)BG;Su5-K}{MPmD$8(;0&AR+2;wsSF~!}T9w~rhVdn2S(TH#0y<>Rf#~nw`Kv&se+5zp6VO^t zT9vexrI0P+IKnw=Zu(6rH=;@Ybc-bhRHu7~La2?fWiP&_P^Y!N_RZL&R1A1sO#Qp> zP(}?R_klQS(tJQZG6MY30czh0qr z-cRRqwyjtzuv?zKX1*UhAy^ZgYYXP3(iMW@PTcK}|Ahl_VUWT#z!QCh6Q*)fOw@~yHM2h_xA^n{;e}O z9TUHYo4#C+(@nX_ZGFH3A`TwR>id05q@AMx?02?+eyJAc&PscG)%(7;&_)}Y@pF{= zazI#2%q#>UW11Fr(bj-D#A;{<1Y6z>c-9No6}?A5rk-p6ivk{rbY>t;qVDdU{$mW{ zEQluU0ubfKudibVdeMFvsPp6aFpSlLBjg9DKZeQtht+EBI!6I?j`)AScJThmX#)a< zsU0hYPQLa~)xDS8BUPi<7jCNE*;c*}6Lngz-q9aQ5|mRs?A`JiOdh6?LZww@SMx4> zgge-4VLH?Qcp-|^CtmGUo?Lnn?vwi4)y|+A_DIg!48MD%#)o_4_4C=47)tS|h916) zU(D#a!@(G^w;m^tq{CH;R0g<1*xA_HATk=5e|E{18xIom;o0GmG{YbGJr0O^6t#=8 zXkUJQ!6sq{+n-}t@e>sFOJvk6I<>w}cDUTb-=)>4$m$@e1sJ054Os-S34$(Wnz%@& zaE*c)rRM7MUfW`ZIwh}VSdlP8EM#7oXswZ8rkOl?N&6z6?=N5$>1 zn?ri+&)k}0T&*^`N+WZpMMymrZ(BNVW$M&9DAQBqs3Y3w6JlGU3p3F%5cid&wEozAI=GP&*7q9k*RwK_DA_N=bFcUb(D?vRVx3`qI{9~l5zv+ z+ppcn0`8!lT-fPOKRfw)0XDZyF63?wlT-K-1E^^l0C3IRgkh3_S*b~08a57JCF5TW znx5&EuKs$#T;a4i91D!nh04u9C!ToYUKy_`KxXHsaUyoX)WlrT$W5)rkht69?sied z^xdh#Z#difRy|J%ULfmOu6S(edtxv`KMm~y?z3%83P`@nhXfz4>JsQx(I{S0(?)y~ zTguu@aE)(xdu}8|JzReWh%%GjPbs7>ofBS@vRriaQ!=9PYr5^etyPcx*4dJ#)i5B) z&7?7n*Sp0Vy+q;`NMwV9;4W(eBQLrod+E`KvJ~?=2-n1lberq=&Zo%EIlrGflz+bZ zX&fyX^!VI#|7UZ0UeNRwie4T`>OGiIQT>HQPmTO30hGZ8iBs42cR0<6?fA_y%Htc~ z7u>1$1arC4NrQmiqJH^OxG~XfdWFepw6zxEl=MsBucOAFB!JH}o2js*k~%Ue;Uzz^ zR1efaE2W3kN~Q1>*AwF1PYuacSt6s}hlB!JO|^$HJ&uIRSy`0ECRVDYhf~I`QaCKx z8@9xJGFqJ0^dUxQJ9Wh>1yn)J7c)jZ2_g$^77TRiO(k@%dLr@Mc44Y4jF}S2+NdGD zyy=3Og-?KFcDb7x=ak`BsKs-}1R%Vb)JhQ**bO?b0*Z*i-*2@dap{yawDS$PLqhOS znd3Kb#fM3pn;k`BFNgFqCI=aDIBB&C%7G5YbD4bbD@F}^E(Thiq(XyQxt=k`yLmh& zEfqj_6@e(@Tp`m9<#gTGuvluURaReWa;b5|FvW8O(e1fLIIyWGES(e^R~zjI@5#Qj z?R-YNrV6PS<@nG1t7t3Z-Kr%Dlo!cBv#-@2-0^lXp!1IbM!9@X1g@%msWgj)fyMVB zEbApY4IkUNp-Q{S_IMikof~u(-53Lxp1ThMc`I*V{3bRVmRTKQmj#QGR>+7M$&H%QA98Yz8m>+ z{!NWEd%JNGxPa7lq3-Q9AGPJo|1T+7>t`uqyn za#;eLKnx`ZkhPb-AI{(x7r5T0EVZt;nA9TmyLG?~s1LhcBeP==eH)L9^XTZ27!jAP zf=eII`P`vU<-3PxXJ}IN6F|*f4FBPLVlWN0UUw*5LTY;0uqGF6tYL-Etdqmo ztzL+amY$x3Ov2+lKI;vX(xlMN-BYZ#C&+K^yfz@}&SSo?<`pRr(-V3gNHT|B%q_#} z9L=Zl{A{h=D+5dxzb$Po-qblBvMWno#EaK6B`<4HJMN~V$>;&^=m(>F&#lX{J# zl`FXe)z~y!$VexhX(I7*MSg;YH1uo&ZX;@+!EltkB*vY*?>gsl(FdkcI(56Je`JaN zYOwQp_}M}I%1)ahSy=_h#;X$;)G@;3w3=N@>xxKuoFy1)BqeWD3ASpMEr4KZnZg{a zB;%E^#p})>tO_(bCMGK!Guq|L;4fL@6dy4bKWFzF(4~A8joh|0GG-Zph^@qC`7e8) zzQ9%V2)ABo)Aiwl@M?4Grd(t1drlR^dbEBRO*4(yHV~atG*6F!-zP6(!O<$wM7N@T zE8Hk5@_vVb^Iy;Mm;GWhmvT0+Miv@SV^$#H6aRO*3i8$%h){-#`G}6@6B_P~_cMwf z8y(O0N{2neHApgK_%~=j#cJfgdGls6!Xn|lemZCr`Vy5D!R-$;VdHp8!(pmlYHkng z{3beDm6+f5uwX5O;~azuv2Zu-{??S#CW^)o zFbhh6cG13dxy7Se3!%0$WA+n1zPe>q>ygby*Dv$KvA{uUL4_&^x(f1G>|d$A33Ut& z?mT;C591;swK1McW;OUlZpd(E(`k648(PO&uv$o^vWVxqu z567x(%L;ni7>4(thk^qIHThkDR`my)#H1H(gPXH_3pdMZ%*1jHu-J>kC8COkQk@Pd z_qe}f8G1m+hY-f!jg*wxo=n12Yp$|dQV*m2d^{l%ji}R>JMuCzo5xa+k1o(bdUeBi ztc{=jB999j&;*R3pLA#!*5i{Hd->;`<6gNCN}YOs&edEJ(=3_;#{Z+ITV*IcJsQ%o zpgA2Ga|e*5)H_S}cQ+}FB&;Z9&B<$omh7i@<1CCvfsMtNIdn+}fk+&>CC_NlPIU}* z+fI6k(oLN@+O1}prBF#yay7pp_V)GdojboY=nc9<#AU)m9VFVsHQv9wHjScVW>$9S z@F?*^hgl6Tg*2Z49I=p+XDtnN9|xpxv4OhLcQ+im-Jsb&cjE-vDZ+`O^WX&w;;QQt zY5wO>M~coaZreru^L)S+aR10rCHfaGtolt)!eMUslBr;Of3A_xiL39%LzGHPA?ocVy2~NXo9Hp>j1RX zav<*IycC)#7M?oeT40U)iBW4$CTKYCK|w{S#g>SFeS0cNT52fA zoX}OIT3ocs>o?2%BX@d28YEN&8(9iQg2(m@xIX;!@xi@Y1R&u2kGi zVj9vpN?vmtUtC<*17g6Iqj7K4D?(L7l#Zr^1<+`V=TW^e?{JjC#iU zl;t(6x=&{yl5daA#;sZh_CG*`5WFucj`?)iR_?ZtZ;xYNxZu($uT6k%QR4m;w672z z_REB9(YFMreJk0SA$ar04#AnZGqFu9-yW^g0uxqgYNNT-7-Q!I} z6d_sOYT5e^MzP^rZG83nc`a4vNNeT9-+@14S>tiBucpS~AjihaZ-X%J#hP69 z@)n~qVU592D}mh3T^DWj5cCl`69Ri&< zvywuJ!y~8>uB@g+YQlU^U`H$ZEY+u7=qw)yp5t(8FxV))b^3rXZH2v$y7A6tHnR%N zbZNNu=@d&^Q0+Vk;!tKwDe>Tf4kqoweW2;pF2bVAN$29aJrm*S(bM}FW^^*uKKhN}=? zfdfnnR>dC>mc%vc3mx#Q9r`_2P2lmZ`>G`=wuuyYyvLFG_B&rat~zsmm{}B(z<&PQ z#l%#@^Vc$;2Q(?*d+8|9Rl`UR*9ZtSlf>C^4N2K2q6J4Wwn?%=%3=gTF{j8P=sF16 zP7&BEA$HyXe;U9?u<`SQLBh+w!u0>(di^Vi1>>99dtMJiaVE7i5(GE7cK#&j!^ub6++_6qG7P9R-I@O=kDC6eumL%NcT(*BhM^D&?x#&}p>0D_ty`_h@&cGk9@HjTk4RugtK!kvLk=abDnd$YNav`g?FUqp8ICrnrM?VH2sbr z`nyO4(lnwy*mcyFI1Shjr;iOSZZ~Rk)gJM$ZC4Zr)k>(QfA952oi{p_>O{kx{DpQ% zkW+wnC5A}J@G{^S_51cl!F#1BQq{qE;&$9S$6tYIvhqn3mdpopD6}=PWn*@It#Tc$ zO-E0^)w1uoNRj2`=M|mg4tzaok6lXTvUK~c*Ik}OU%QrT(Ki|;;>Aq)uFZFgNjJ|~ zCr!=#skHt%d-UH4(ZjPWk<^DWI`M>P)HGGwJ_U0hP4jZ)!}{F8#L2Qo^!6Jm<$~F- zwP!Ehh)gKS59OD)#e~RYU4ODqLBln@^ugS%HCJTO@vDw+!X#nN9fZKNkv6*y7b;cd zifi3s4LU;{d2eSiEpw;MgqdXyu+jfQddS3sPUOBcmd*YqN@Sc+4ClpYp*MG6RGixQ@>1)t<4{*%BR-mV;>uon z84UlDC;0I9K3*4uS1~_b;oSHLMF~K&97u^mcr1Mo`WZ=WKz1nUL-Q7TTL$Aa_O4`z z<@EVh*VQTeT6J`-D%av5=Ft)*S^H&@eI)OOXEbqcX^Z$&)%(--DGJDNNN z!yPWmnhqC2;p$b-eTJ75&c&oYIijjF(&-X7a$<64dZ{B_0TkvbAym31?#+&TRS62G2VNpC2F*^izg=6yS z@1Jg?5JIePGyr#ERL4tsj@4-y&3aMkh8oZ)WFk*Z8KHV z_tJy`pQs}q6Q*x-D~X^n`sW~pH6QZP!_M=5U&x}mTs;`uz1=6-)7JIL7dqBdeY z8V!VAU+-~Ln<~C8n^)fcVg>WMCB~~m5GuCZ6Bx8w8ZwU1i=n-yk?Bqfhs}4E$#pt* z+Vx@|`~-wq*49uif6}QJMvN}C7;!^1$-I+A|B0hlkVm-lx1OflWqj`*?G;ksGQNl} z73k)~hs$OqgNf%N<`MH#)DpfJ8W17^hF^W4-O`4xfSo2W^N3DyEQc z|4%qSLbb=RX>0#ZY>@FXrqNU0eThjysOc#|-cVT@hjjB+7nIu!`rxd0%DmKF3}a6U zWIwz+nad5F3)rd_`@b6k4jxIXcJE4>bepER0L7p!&nx3)_BtlKsB}V1a|QuTdjWT& z72a@s(FtlGrxwh5DNXS4i(EzW_1n;ag%BcbXe={5yVeq0(sm>tdBcTo(M% z%=o2LKMdYuRScJuk-y2c_sQVxp&*#LP+?&Npl^*0&2ScX(Rqp{39mAEC;vk)`6HIe zz&}BAG1YU6`tn!!{?{=A<%6TI@wk8P_~@TZEageNcO zSvQT1_|;!M?>|CxU)h2&44?dOwkLG|N+{%wpZ-e0=Q40wsFW!#e7i?zb{ia6UnBMK z*vb0eBfn|r-$%am5^UQl+K@8WBgxj${D}1G_PpIAZB6(Lbv^e;+_&lIo1f_%{J%H2 zkS!(n{(9Y5zKP6TmtE=1Ju#0n*M)gi_PcmYekgQ8_&S9{&TTAx#Qx$GDp&ct=hOry z4Pm0Oxju`Jn6{KqzTRMzAv0`?Cy@1 z{PCPRtu3ikLz2Zxr9k4D=0&#(&4c4U4!w>>S({JERKaYA1?io%`Gky=JRJ+e)^J?Q z*&T}W3cgwkQQZN#AdCJWb!=Mk$bSM(z~Xywm9|ZUN!ctQ8%aETR|Ww`x(|I#MHGZl zS&dE%nSV2Zl-FM9Shy>QA4e-yrA38~P7h=;HMb**ObQiQ2})`#8l4qX=!rEa5bF(Z z$T=kJ{y(V%v5GlcSf%@bh9tMEiW@p}mPKJ9X^X6%&84vGr2NoXUjlj!lS;!!9A-6@ z(KJ2+3C6zB+U~mLtC=mkVELcJRR2k61BfZWq6rh)s{3FBiJQMF(w7WUvw4q(gQXY{vsma2p`UqSEH3v}@)sUX02f7h4d~uJ@46rPZO?OJYpG)Acg1 zpXWs1lp48yn(KV^mOD2g=b;VSa#+VC*uQkqXT~4eY`bsRbxbZS`5_zLoWm?u&t5N5` z%+-oa;ybVBvWkBtNUK%PSF8AwaQ#NPFsyWL?t@IujQwIBmoDsLSgT|1XSQBMOcFGB zVzeK0a*F_28x@7f`uHuIA6h060q1nRX#U-0LL zwE6m?S#&-zlW6D3Yz`$x^1n@TP?JlSaJ^P8b2KGzg_YN`M|!(I!%>;J%Om08omo_P zOBplyQD3kC5HwW=s4V{1Oxn`*FS}iuE1+L>Tg>Mg9nvT9HA1lKtsSG@%~iIx{R=f~ zj=n#|?nXRU1qFhO6!Fr~~V;%Uvm8yVi4=?ezI4k7ytUnvPcDDHie6LHJn( zx{CD24^sRe=|zR-G9c3z@!hnq<<0^$)({SXihttnt=Y!UODT zy0nG}woTJ2znmhic$6E5yCSsnM34whFO`*s&I3EmvWfc_YYkgnS4u%~V5F$`hEcZ! zBHlpWtlTVsP}9|DxI>Zh?T}@WHni%;&gN=jeD8axVuqzCE&SoLB;Luq>^R< zAN<6$G~`lDcHI*9swr0K*6(&DU#Y6*`mi9OXtA1OG-LW^b4*}Ea@9uo%@(|kO?mkr zxNPfCIqOD1wRJrJ;}Fkc!-%xwNNBB1jjdzixTkZu!`$f{EI%6tHfhU*T2K-zRO@0A+WZ0@c$y3Xe} z+(*|R!WFF@X!dcQh44w%REQ-a zfedACfzkp3*{>G%{1(p%a`^sp8dHJ# z`!m&ujt+hxaf-h<#A<3HF+aX9S~670s0ACI{bf4$0Ra_?l>J-O#J&JyTL_`co>k=D zl@o#E{cQ-Ns_@Rw8ly(nppZQV0ek*XYL8#_`aDiAY&NQ1$3$`fsUrjCq^`EF*s`nF zFei;>(uq=z&0cuuVpGVe$=z=xC8q4M*Os$-OV|hJ-WnSF`95c4OF2%N8PFE_Ft~q19A*C$IT00E*G)Acwfsf8%iu!9E+dGzCQMWo*_Tj@?<8)x6)!1K~_^b*o&-jWm9P|6W3@@`JL!q#4#GWp6T9N{pR+WV|-%>sFpDPI=3XRGc z|165CcVJPtZg2dka{n2Y>pa~;cFx!H>LVKOwj~=H6UCP|O3WDw7`FF!lW`?DVZSSL zozK*18?0DI3hMaeo5h*}AmL^|yx)AqGTvRU!VBCV_}qbab`IBZ+l zZedyRrBomP$fT<_7Aa~rSiC*GjK-uh^2{6M)Kfm=EpyKlpA~J4#KLUpjP|W2uV0x~ z<{RO$t=F9;!;ZW|suk4=*qa|Q+cq%ns&a+*Tpdjw1n3GAtQf!52-7tHSS_nqr>rC{ z$gcIBI4ZJ}cjj^2SdIsn1Cm;B2Kl$xoDsS|+wPt_K{ZG7jg!=w7 zC{_xxNA7Sb9a-TKN>zmQu-Im(H1yhhVK%j5J1C|0FBs?HoKrl+wd0|M`bGux%i-fu>9!SLZm4KzuJY1BN@v;ZvW#0!EL=u7z_bqWGjd>4` z$^WC4Crx~D_0tZIuqwXM>lMV>4^RV}jgYEO{R1~{M+r8?>O0rRW__Wx&~87$1ZMh6 zoJ39f?8WF45{dan-H{vJ?f#VXmfO1ytu_Ud?C+F9MA-ihvX4;L-~6kX-62rotUr&r zYb-&ON?>LZotjV0kCUgxml-pa@^*OwrGHhDCdd8DLu;fnQdK&`K)^83DI>0_^|zFy zKYOH$eKyvm)OOP6wDPL#P0oWU(ehNHf<^6ULB=}AfZY=hW<+0sp|E5NaQ}^1sk6V4 zjEz)G_8lGNMr>sHbKwOGz54XKnwpW&dl6gfZy~VJzT2PhMR${yKH9@`7fJRHo&47- zj#Vo+Q@U^3eFYbd*Z)%HtW$ydl3Oy>WHEiU=yj!O?L3aspwq>A!*QtL zC+0s%4tc=sAF$-UDTDawKM&%6%3d8dL^M4%$_=4^;?}>RP$(|=nX6q#N7jGN?f)%f zH~wI?8#-1|3IA;3|0#~aKQS-FBQu+U2{t*vz=ytn4@tAt^E1j&Q|-UK0MgWd0C*CB z)2`QDRsa3nSj+**^wYl|h;0oMhX~*u930pIGn%ViZ(F5bI{hU%x%HeJC|O4p3>g0V zUsokNx<$P1&Sxco5@-E%OfczS!OeUCSYHkyU@o$-S<3d}>w6DWI|oM*KTAxI@_6)tDl$*Do5HwxtR-h_VN8<_~yT#*n5b7n20veq*_cDL4dDg z(Bw9d&gB5+_P1JKTKuzl3m|i-0U}b7+KqNgC1vGwVbR|_@0$ejofiL_7YHDxTFoB! ztVbW(QB~K?trom<4uo0w=v0|V2B7Z&&SianZeJ4<_zArF(Y9a69FR^V-X{J>2U{1HFTbKtc|+bYeg6(XBLtK4|Vu z%+I*~rsfEQp7o?szm22$Up*z9N&>{}MF9sBlPu_p-;doA*j{PR)B$v%oLBqJ5~U+- z$v79N4|&FDYXFgkD0r za4MJlk=Yg|j;21E&D*pen11J``O%Eh|A1}(vjVs!JIX~Cnp~^^cludK@eg0561=3J z<|}-41C(I#Kufpxv0350Vd23U96r2JZvqNl7NdKTCd_Cp(_}7Yf!d} zOy-?cTvIw$6V3KJ2yxGaO3Bf&s){^m^!GIhvzgzy=-2X+p#R=0j)DI2A$V|KDr(Rt zrV1xbfZ3Mk$}It#QG?nCFo)`!Zm{8j)nr~R-~Hv<1Q;R{Ac8LH{;NyW5%7a_qV?4; zLh9ayVQ2*`R#I|oClq2Ykn%T4XNzR$0&C3>MvV%g$WF(Iv3HpKR6vCM1MT#CI5yFC$fh0s_faBN+L=2-V!fK&!2DG}Mz$4ad>{?e z>}EaQ?^u(Oc(kBj-$#JR@Nba#UliE72z)BVG3PmIZxB57TX76(Wpse4l}%fc&w$j3W3yk5q99t za{$*q-{Us&rB*XRV#?vdIy7w0KFgER0b|X7E99?7nql*r+m_Z5bVw3LBr}Kg647OVH1i2M>_Ujc0ZW@RQfeQ{` z7o2ggZ-fH*Q%-XLZSSj>2DtFtja%zqoa(eSeEUA%6yF;>T}hK@OmUL?lxg!{&sfI; z(Ob*>X{gKI%$~mtcvbOUhmG1ylc)Xy=RjmONEyvX0lF>YfvwzLmZJTS5C&+8W;Net ztr0;6Fc-2=Ujst!;_c3zDq!n98QfO~6t2+S;&S)(U#q}kchbXc*(2XEq^xjHq&Jz3 zYoNmL-FYL}g+odDzPNFVK(32;8W8rBC{OpRVuRRc!lo$Dm^ZF{TWK?k<1g~5k|J9G z8*3;ny7vvv=nwNum%nMAe=QL?>|+IU;1V)2aUVwJn*-tJSiyk@iqZJ`mHT`x>7 zkzgeh2FA^PW~~}pX%hReo<&V6S~vUib4bM*rojDkc(9gK2f1x#Iz&TxEvrfwfA>fy z5S`t4+Gv+-MK}Yaj}+i(@kf(Qwia#UBNs4KV?1=l?h-xn|6R=ce~BORbxo)RN7M=w zgpG`hz=%&{o`^~ow)Y}{J*PRlodXs{V!rnt@hp`?U&36BE8iTRto5;2306(I>#e4x zpHwpb_kq=b>JAED8f#cIG52qE=k@+rPkwd8Adx^*E-w1&ZEe@h;jgzFG9KZl8|&Ze z{woiF;s;nW)CAa5QGK_<{{?2$4T5d~=k;|VC?7s)Kro^sMl`YXf35m;Q}{VoZj9HL zAjDe@<+pQJ2Mj{f_~9Ju%tR&sN=pEy7;yXl*n7*cD!VRfR0&Z)P$_98lt$?;rMsI= zN_V$_v~+iOhjcfaQo6glJHEy9=JS5%{5ikRA1`oU?7i=M-D|En#~gEvFYod(r@>sn zI-yLh1IcP)AT3J0z~3YMD@GW%iL@Yw(gDBqPM{{5XF-#qanfGRiQ zD)|5Jm!5+R2KT97q38bwWubQ)k9}~*b(66F`z4siitY(f!T-$afM0tYLDSGWnN{^a zNa?>IQ@|8v*DtN;IH{pTio{C{07ME+D11zs4E zMPHsf0r^ZN|F-ZjHwh+lj(0%gE09q5+kf|wKtT8*0-mMZ4l?&nG=tx%9&&|BtxKWt zP6B^T@6_8nAsdj$=STffc6YYR&rD+7;le+5OKbDabZZxpDdsCgCwpf_M=CyEEQDN} zd@GX*LW4}T8NNPCZ*On8R=dCk%P{*IzAv$aHz6|@bRM5*=d%PR$=V;*2$8rqpB~A){v+=#2B$qAD zoOO{@B$utK5j0gS=W`yD_tN{F%8L>Lk}0U`#oaV(@TtV!^slu%ZmxZ4>iv3SpP#2a z6#&RXUtMfnn9bQgVTofi^=Y`Sp70c!NihQhHXR-4k<oSPas=~^Z*6A+?={ZJ3| z;)c_{Ado8^4l~Sx5ue8?jJ4e9asSj{$kW&bvO*A(r8ekqoWg3=$Qc)j$0rR zjRb>kl=%*M+Hdv;zyT?mC4wOyJ)fPG)dzf1RxgiM2(Hoy`hf>B;La9IbFNlzo)7r0 zZl*OWSVF|%6% z2Jb}!=0Ji-PVnB@C;NjYt47k}8{75Ef5tA_$2%E7MU??GKNT=5bv@RQ_FYPufOx&q z;h`ToE-od|9vMarHy$tiGd=^%8iYV{6{&^>%E4dJ6-6ZiLECjr;8G3x)ZdZHD&nn% zm_DSs)MHr5n&wF0M|sLk^|}TIrku)6F101vaRzg%ya=nRKr_IE=s0TG*QaihL+FzLuMZqPsA+JHCdd8tnIeE};11Dl^xIhY?|x3Y7g8PxmLw zyhapQ*sJcmoMY_+LPD_m-Bp1y|3zMEchySi9_05kTExjJ+-(OfkL{W25Hmd>e0Z(r zTQ6C)2cjZBIec>u2ub+HRD~IU6E7E_H&=?G(x39xkwXfYg7nTYHkxaQJn~3`@%s|3 zpReV(-8ns_K2fGX{G6d3HEcC9DN55z)}+57eYK1x34eWl<17+)+^N^ayp!b?0Ua(i zWF)-`#AA=A;C5+LusdK$SKS}YXhNq{5E6-^$qpGA84@jd8g#~W-+#5FuivcE4yD_i zjt(Zpg6>|+JFg*(3D{A0NDyDyAYAm}S1%B$*V|Y%y!f=YRN)WF9oirW*jxMhn`f>$ z#pRZeyu>X>Q%k+tE#vlT%90=e^z({VmwfkQaK9mMcNrpiH>ENt_oh(2XU?*_$m(qIX|~@_=Oua5B|Nvi zS4C>R`M;a4x)!pGqM*m?-1AX1N$f(^#Yty3@5qioF& zWC&VFxY3hfekV(LI}wCOlVSEYZA~zwwta=PMb*6NgFJ;|ob%5~LyihyFIv*JX1=yKa;*GdH#@XR_U!oNilK=t^2cG&xFwd_FIm732`RaD5 zU5gps()kd?*JS35hR~#;be6}k69HOe zUv66c)jxb%eQr&8Wxhg7~+L#Oze(a+Fg**+Z>oaEC)frpi&|+5{mU%dq5S^3H zo=3Kn(6efLt4QV5j3$LW}$4rmI-dB0t+U2yECw(1*57WtV% zVMW5u)fBC;nA%UoXg>axz;*R~&K?MCeSNfdW76L&(^Km<*li3xN^+lNMhD7&ep4(X zLW<5CArciZW<8+QXp-Jw8fx-5oJF%LLT1c1{V7FJ4kCz5xa}hN9!-QIL*r{|anAi= z?CI8=EW#j60^5rts|odLR(YT&EYfv%hAkM^`J%@I$ewcKuhGdBJ|CeayW5A;!`x_y znBl8;e;{2OR}Jp|H=gz9{VTbI@5Ud9i~(nxl=9W=jYOi*9}x*Kk!(Ap>DoTqq1mhG zDj2M*lI|Jxi<8jo0f)&X72`W&G4pkmDc_*oUrPk}=Mq``>cEpGfonRFsM^cU$uX?f zBunesdtE%g)~7Fj+%R)!KU-z0s`rbE0*p3GU8u)Pem=!l(5zun%#)FC&i!6MAF1qs z{*{uHP}H`ttPz1Z?AVgji|Lo+ikotyO|{Mb7>^NYWK2FIEho#+ty!a7zKTlSg=y}N z@N@#z470wg#Xe`QzvlT(tu>bJSh;$5bo~1w_VMURna)hmXwhsNuRM@{+TR$symoUaS6+~SU6c+py4O8y|$#I^gQ%-e1hsd#jX zW<0pDNeh1UIYT=+|Ga=ku6*aleSVWud2^>k8gkm|`w;aKm)?D22!ae_KdI+>=PPUctjKJcI z^|y-?@z8%ZqV5ZTx1qgx6WLjwRaI;{RW4tREQ$|=bcW*%TLW#6!?4J%@@YdGE^0ws z*}1Bpzgl;=zr9lFMaglOng-!0XQMyqIN;Q9qOF z?Tb+o8x)#L1e?I>ANQvacHYe`q0<$v0Q~KYivS}Nyrnx1v$2vdAX<+h1@cX=JXyKO zd7f~*WHvHFr#o^@qTaw8LBWeL-RR%F78nw&Hr~0WQu&}7aZ0XKymUy-NW#M6)U+(Bl=b0!T zS>*@bymkhdGYre&c*dP_IPdbP3RA2g(}glw_e1SGwc2u{0H})NIW4V_h)BRljD_7H z9Zd0r)M{BFCc4Te9=->h{Mr*C?!n|7^`B+#QsRmZw`B|3iXT_TJYbdF++7!x^3t=# zz-Wqysx^HU$HRvLL)J@b-medL#i=&Q|21^u2cRn)cmkMsMp^S}T*lGpNsxN8?RQF9 z9kzT&fKxiO+n>$4@u~f0F?13IGqxc*4@q`pIkG3XS~^8tGaCKgr~ea2ay-k)WSSqJ ziG22cY7{>}EcM7oCM1Xocra0fzJ*}`TG3lX4zZoXocH_K?q_@iw922Vok3oF-(lm1 z^~>zzy4z3!Go-#^g&(17E?eCA5$$mSkl@q4jnQ7&k0Yn{hMf3j z6rmZ_vX9_+n#+c~_xbNQVQfwBBp)DA*rbRDFhOGY` zzru(^`P01915(A5D$t`D;oOdsZyeUe;uXH8CITH3NeOdJR(i~r5!i)X#QGK9s@A1& zdhC(+ao3+T;C}PIqdL$XDYnOU?|wXJT$k1naLj9LuPG6jbsEq;=mH!Km5?y;o&nL{sm|IJ3tB=PhngKVRO}%mPHwYzucaN-k#53iLA^#gd^m&b0wwtU&ZfpWQNa>;uY|XcCtT}ME7z(g+t&gWg?l)a9FasJ0r%^ ztNLLzb0*=StPQ4if6ANXQJ$JFIzQaE=b4Et$(Cyg*~Ak3A6k*ml$m{lvL_?rh#&N4XznE$ z3}=-T16@hTqMnm^+wj0++MEo>y}pc?YL*QUEj-;D5gnrBDk!W`gfL1?n8DyJXH5(l zP1TJETk#prIHtDN!uGQDyVXK zzlcWki^+K1uv4X)hCXxqOcRH#;9nayg5Zpwc@Gs1HHzShsK#i`ow%CvF#JwPubwdMlI_tUb% zNy2h)v|Bj?q2L1wBD>j({A`(Oj}1CL3;pJ+WV5;;OGy{}vZ`4O>bPok>WvX0Wn?7b zko&lafkX(Kd;QefIKopn(&@Bp$x&fHurtPN8Puv{rJH6Q`(hq43-9f>7lP*->yWsF z<`Kaf*6;J&C`CUbw7;IHKVbJ&`ev}JUcGfNscz(tXYbjzCgJaVp4(!6a~caGKh+SE zt4NB3Fe|y4_qf1dwtBxP{=)^SXFe;)Gh^&%1i>(!ay zm`O*GPs}ynOBNk_z+k`6@ykSn-O%B4013hO(2c4mljFW*5mG|4FKEgx-^JO@ZNTn< z?KSG5Ng%XN-Pnt2Ys?-jb%Rw%SOtWctehGQs`cK z7>F^=z?cN(*A_(?0S&=o2KE}uotS{ooTO+Y!vZb!UO0Q6J*i>72AubC4CcT*(Pwbl z-I&={W?@?C59V%`Sy%Th*T(VA-A3s(^{75v#%SDkQRziQRzjMt%<^ZQFYvjJ7P*|R z#wJ!hAPX7P?yo%g*8i&K9SKw9XiX^OdMb}s@Cr-n<(xsQ&i`Fqi7?s&v+#j7IbO9W zHTt=7g&TwR;Q62Kht#gS(n?utzc8s1=j7to$RDtb>a#U2#wU(7_fI^|C6hVU61i+C zc5qfwBx1=vZ+8wKYJExE@qSQ6<4&PM8)Iw#5ErA((uMS-!#~$`gv=FZe4mFro)!x8 ztM6YYf(0oW+3$RH$+cK)x3=5QnY$ETOBe4fgwJU|r6jTiBFNY9)NMSh$;}ubC>Yid zd`T1FE{_1}0q^n496{PrZaDG*pJfktL-a~Sy{1Omu{YV$HcCua3!#Pg3oszA%`8X3 zXWNW1DosTp;81dYGwW=AiODr8D@`7xKl(PqxcD~Ooz;&b+o zmcXaQwH{591|=eEA~HO47Y={??%_o&WV-^zMsYVUIAYau_nvLbG7P4FXb2@yH(IJDs^+1E9YAuiH3YVSW)=QGW zb3SaO*{h=$(Vo5D(`KdTM6LvP>@Jh^b(Wbkny&voa9IW4&0tO^?og-_dCc-YX&ssk z(>S~B!)Lb=+$b*9(B!I|DZ>1dTx~jI=PkWx@$a1>vyi|Vb$6KOGI9X34Dm3VZ{QEcJNlV#M7bd?{oPAw z0xLDoB&p4*1vFj4J378jReU^NSTeB<_Wtj0a*XFeg=p%Hh_O0t>`UJHSp(SKj(Kem z;4_})q__?DMbro?)!Uik@7d1Po$c@D?tvSl(Dk!c_=7}ZZscGOH*yGpYX*?*QN^TI zAt`A*cbCQ$%*EJX*pRxhuU)k!jsYXYP@p}r;-L#XU+LU#jR_p9tO&ee@V?eHJrTd+ z)U)OUs+Y8n%Go5Oq`jaIMgg2XFH{L7|JFg{`2<6N2#Nr`HDKa998gHE^vg(o3qUde z-jE{?f1saodeqYt;^XrK-AihME61bMN072Wk+zjB677Rabb(K33X9+y6SLKF+a1g+ zpl)&YsX)Hq!`;nAj3>NKIr5AGjVLcSHW*Zsq<>mrTHFof@>lZ_y)E=`4IPm=dAk!>@jdR)3uCYz);AO>D+xb*Or7Oq9Z0Y z?(1y71dMnoYU4#-9B#&|l2F`a2riJoBcg}q$>uW{VpZEhJXck zJg2G?I%v9~1>^3IsyWUFcdCRdTJEE{xS4>H@&*el=L9eqG6)Q~!+@#Cw$2Fx>KH1= z;rFUbB2@QKpIdENQl8e;H7rC;1m$r zf&v2sa(ey2Q4vD)WKe;M1Y!>SvI?vX0|r~FIbvX1b`?-3#sVnlmSkA<2k{&q?oa_m zq#_uP%AR@7CL)q7?1~4q7Ko!!?#v5LC$XUqN@Vfc0jt-KK%%QLx(<*+Zujj&a*bIP zfLdGO33!gzN2LJVdd9ahalHmerp>y&ZyYz0++P%@30F-FWH*71uAoYlNt(KJYXhJg zT$8px@=_oVPKrQMH$BAkfO|wRq3BU}HN|wgL5(i$Co#?ixf?O4h4Pwr0P_II3qhzB z@sEMw*S72}nsyJ+sav-JMkE*_=*uGqbV`C!oN=g2GLI%?p+5cRFZ%{}G{!RIu>i zuTiVD5{Wa;E1HZY#6#2{aVs?iJdy!S(^k6k^#pT+b+Qcw87;It!J# zjdrLCvp(>)e#Y$eN8=tr3}$7b`-T*_@u=G4B?9V9QT+ulq)u@tL;J{Z%J{9}dM2-; zrBZ8^)o{JNP`Qk>W^sGj{OBAmW~*GK(>)oBX{T>+wT;cE@1&m#3Rd88GOp4|7- zyDMNq-HoztfyKzgqa4utoH($>jQP>W)qdhaxu~Ro1W+pS+usY)2DnTnnUJ?FB4-_F zl18j#)um2gLSJnH3sFA@me)>`ybHl~fBILT8P?M(pddr~Q6kYoB;@U9HOdNLm>m|v zbuC1B1$?8Ty9wRZoK8323#9#OG^;v`Ls^_|zFJqECPLV`+9`QRse`C&kNjEGW=EO1 znfggwZ3YtVfg5z%kWi!1o>Ro5P730cLOh^@lOiJCcskr4Lv`}seOoa0MS!?BTWkFb zi3+^}qyV7x`onj9K66l6?sw;ngaxIpo-L#hzd2IYMT71EU9xjAoNP_6IAI3oJ4+G92jB|J2w)pV@!ZU))4hiv>iu^uiiKr<#ZK zd4nt@tOkbTz?WJ{QY8KED3P~86E}|+HGQlR-h0#O5f(T)ZU+>$tuwDNikwUymwEIS zrNukZ|8I@`Hc|jq@bf=^^5Y5rrOE7N1&Wof8doE38!S0GulX8^72qQU0-H~o<2@DmT^n_WEZY8Q3aHWzk(kC?yk!oIr&4(m#T&z> z<5?@7>%t@DHS0Rhne3cQNTl8hS(M@X?%kPO8#kdvQRp?5e!iMlRb@S}x)1gm(`OGh zn9qqF{=Ry5+_n%K`}d@+>A6F!;HzJgN+Ul%c|Ls~=j#>`Lai2>)&l&UCVTBvS<3{d zhi|WtPH*K#=Sm>lNmy7hS3H4UKo6769GD-<$W8y1T#fmG@m+~%XM1Sc~} zXzUaDY>ui{mU=znGV^t2&u-AGJ5|$%I}{OR&v1ZPu~t29UGM1&A^KTEEFerMWKyYIQFv2@ARY3WbcVsc+EG?oi;PPb^pN^SSqCsxK(J|E4UWNaG66_uJkRGDzV(X_(s8r+`?^GcGnjqP4QcHlh*?ANL^h(53Tif4DvgjsSH8ce2yx8< zEH(J6vTg$T*CB+~DOK~#G<~rn0k!c>k@gADY_T|^SXwrd$xnJmrbU6V-(@2{xGu?g zD34H+Inc%V=Q-LYL4o8hbTiuJb znHaqh^0&GOh%?~B;4sN+zSfUyjl}g`#xf0*sdnwQPhSJ~mz^xjL!u{yRIoodE?C~6 z+3%1VloF8D@LKvNFh_O*qoHZJ4HGX*J2H>;@aTxgGmInNgZ}pIORv8N%~z2;kHXd8{E^}Kk*sGI-ykU}(|;U- zm`eF9ia4(JyvD!mrAENgEi?}F-CgOXkIA%5xtRBrL8c@h2Tj%mr@pT%Z!uSZtC#cz zTC~Q>2V67NSX5-v55Hr}FsW8c(O-52nx>-rS*Kb}vHIRTxq!X)WsSNIe|#W@AnZ-Y z#J!}GEPRbA;_lM4GO0IDHy)J-BW}mApe#g=DcS*Tz#}@nXxuL`n6&tBL(f9*)L^(U zrY$J@cGebg=9=BzIrUGyu{8R3+O-~p-%Y%3;c%>(X}?)M>UJkQ)l)9UeZv0VA|Igz zK$q559Yra9dBwO72*Eh1D@~B^118+p@87S2f!dx@eWhTk$RlUxA5?SjuLV4)DV^aV zE+|QV3*6vXKBjvbk}Bos_->c|f6Ld(4xH`My7JANNJAviy_xKH{v%I44F7qtEV22zR#X zbvxlb8Av}*W{dzVaEem`&gN6fh!lxS9NO^};QL-j1!>|~9OjM*guV9B)C54-_OH+{ zTfQZrO~6&%vmRslqwmD(p~>NboqdA1+I^v++sOH+@hFI7%h zHK1)ABAtL-C3pu(=KHk3Z8X-eD~~(CM1ZgedIJ)iY<_U*VXOUATr3@iQcJ1>uUSsW}$O z0oE#*`_|a|gIc)Yy!Wd;av7httgH-ZbqO{LJ!&^|jEhx8o#d+FU*h;yii^~#bS8x7>XK<08ZlHJK^XoOHM@KF zA2TVt^F#9w?(KVm3{Y@MU+*4FsL095k3-xW_Wr<)*AmdJDh_7~j|4X7)SszLu-+v^ zCR{l_30!P7cRTr>$nCDdCv8ySoFY(qQy2gQibK%+^7&L7ofrXMU0lcy<6L3zc5%0)c?C@u#4M2HPRC2EC6b{K-V5sr$;W#siR$`*L%TzrCRZKTfNQQxQm)|({bpiA2%_s!H0`+uzOxEqz(ysXQ*~x_Yqwd4AQn~sEYWEo4+;#70N*(GOmFD=O&QdS z2uak~Xxp&0N!SB@+H9`QunZmv6X&S3%Hb3L3;>gcS6Wo1+{qJ<9!D@5|Cpr{V$PlU z4AVfTg0UWKG~*aBjqMYbb~Bo^I|D#z_3;)H)i-bfN|XGYX9QsY5>_dLLp$nB3GnIEFir{&-mxo=zFQM~g@eNN=*Ur$z0 z{=AqsLsRO{MFK>9=ac?^B0cBEVC}5)mQ%9zw}P$xYkNt1MMYct?2GpO2zxLsQQC_3 zQ8n4Sai=*(^k&JOd*88mjaBvr7t`HxqJCG)71*@|(BVcCpkqfWHzemuVmoj>+@9!4 zC0$ptpigHWAw|&7G{(=P=LFK!2~9_(@`>UKE8p){43RuZAYX(Xu6;SEWJvZj5(ACK^5gnw>PMwod2OsLy&na^t+r!xliOD5+S#$c@FcDJQ4_e9zC1qP9xzRdCC6yx(|1JMjJK9j98nXwD;tU!!})>;yQY;Lh@bY(|o9 z^OM72lp(Ygz#)y#>auH0(H2N!)U>xJO7wk@Yp2y*ED5na^xf#aFi|-^Nw2dQ*O^#I zYdip+&{DhkD}HSIqjyt12}QFJ8pp70re>W17ppF_HQWjQXoR19@vQvRPIB~sBzPye zqAuI(e&Mb=rQT@CD^`Kt*YYT#8IWeTY`_qGCQA49I*RNDM1RHFN@{mS2xmuXX$YQU z#fD0w^gL-Y`~F*6GoN;!xztwYNjW;O<+F-u=#C#A62=G%-eXVPNicD{h+iPYox z^sY&itpea&61XfofFpTzcfkIZZN<&$dMoa}Z`4uxgcu{#K77wvwuy|@!EG(diyu3d z<%ri+JQ(Es%t>rX5!W;$1OjSbJNtHs1!hTLApxI@Gabsvws4TDT&^`nEdk}UT%&z= zYRKVCPtj}HhZ1~FiNoG#V|cUWHsx~QjN8|&&%GN}d*+s-^;4_cbM-OEyWf@{*`FMB zVEG1a4oV`evq?BF7dxZ^-Lfr~=Z6s7EJs?tV@K}*Ep_2(h1uCOG)WHW=^hY3-aeC( zhQl@}QYmP{#V;9FE zj#Q@D27qCo-(xB)CpmduD0TnrQl89?FkH-OpEq1gr74h^R zxS3BBMsAnw{pXFX`osv)SWUc8qfivqOqXeUY?tJ%=?@z7ck2nJbg5rI;w{&AKr^{( zx9+Bn$=yf8uD#6(v22?@A7ixzRe)J4D}tP+W$&6j->))1-LD6}8M~jTAACc@s$LqA zU>670<)4Kr4UspcH5QypG%a2c91pqUyU^zCkQ@a@eArfpl6bjJN7MN^3@|=OdQR!5 zK%mUiwbuGqW;Kpo*n6Dj(TFlwS39yZ2X9bo18KI&y~JH`kx3$$@2mVBOm-|COnb69 zKXSq%XqbH)N~R8=9&r>1s+;=M%v^|4;XiT20*42a1?!<*_L~53{gU~M+;E5(4#^B& z5xcO7_??-7!^nzzq8Z5f3UBBywPA5m9<--RC0p=)DG6`xN_5)J^TrG>_16co*@h;- zcuKe)MdNGj%V$^Z#UY$k(F|`MT_6fC#q?tZV2vloiy+w=Wl>m2Z@2|$wh~_xBzeIj zB}>W8)*@M*S+y1P+c*KXGm(hwi-Q9!_zDmC>!`OfePe*ys+3R#-FPXOd z3EuRlU2TDDZ|sM`G-6;5@&Sc@RSjJG-pqwI>WWc1RWLR^)1^|e>FR*OzO+OdZPO*6 zZcJdx1J^@C3#r&a*&$kBftIlTYMl44mXDj|rhPd}R{bA*#aT65gqr6-E++DkujKB? z!c6tv^FXgIyD)XP;r@DO{d}fdn3FH=E%*J9Op^nx#5G+fTEhact|yOB;w)7;#!s>t z7M{1a^#&oLNdI*#Rmo;c|LxVGc%(D(rsk9$is@SnMs827Z`bpS6=7cx_T=)u8nOU5 ztpmmf$(BYJjdm#*U-fWL-F7T08+?steX5g8hE*<>BLL^U>!%L=Z`iTXkuR|3z!_TE6d3xl$7TJS7r}AuIyw?V z_R6GL^w$sWi&<;(1Kft5w?h3Nr>Zt0p8|VRPp!`)+q$Lcw4bflsZK)NZ;4ZSZM4|I zb5;MsLtENltK;Yd4ga`I$NXYJWEan#e{)2VTU<8N5Y98h&!2xA>A5IOF_+SehVvfd zLWDyO+eDU3mdHE|9cP1lQcN7k(;b^_)@T$RLAW)eb@i@BD-Tl40*?wXr%UfYCMY=N zQ&NqzpcfR@8q;d)*bbOsIvo}T?pe0CGYcR5>H1y@__xjwYN)9#9)R$jb^;aRE)XAK zdDg2iZ?dK_XI=IV&OfU1u0u_w@YIH-)aYbq!}jpf$D&N3b39tIJvf}$jPlF};V)KFE`AO>SvfuswU_yy3880@x)HF-2%KA8s|L z{-^ygL4u>m$+&Et?ut(50w8ZKkv1k~E$GXG{UuciU1iqH%Pf-Y-4)Tg56?zY3|Bxx z$))F#_RH)QFHaAdXiBXhrAmV`eR-}^66VP7|rv{eT+Lf%)UWL*mP z=#rfE5qJcA0!Q5d(^srVOPHweEBsd{L$1l}_Qksi0jiJ^jYb*ErR2BKU707u+s+kX zUe|%A%lp2=fU#G+SaXbT*|9_(x12cHf%~z+<%o`v&!5fj_Ds^-Uln4glyw(t)0prw zkY1}-{y4>Y=)8WkRS92cZBA3Yr!kY<%vs|0?I$HNv6=JKe&L)y-W#th zp6_zO1@Ncoc|2QZAmLXbmoHTMU54x?Hzmn>VPj#b*-gz{miN)1VP$m&Lc*zIJjtu0m{n`L$KLWu^LWU^$2hae4A!P> z%2m93+YH7_A!>?uG~-a?J}gqfSu38~RV+Q_W@&L*=@2ai?7fCO+pZ5N38#kB6=SqY zvR4|vh{b1H4`RqMsHD8tU?`uS7;tyQpm6+43*g}v$ui+(MgImdcexgfo1K-(D@toX zuIG;<6?-Osh?k~=A7io-gljf@+j@(PYamkIB*J!wqao+0(3BZ$xie>Sbbs)$uflo< zrL?Ek=wPoz)#(mC!rW(LUOVF9Y<0N?V#e8?deT+p0#unjYSNe@I%PTgbF`t>*UHF7 zMssfk&1Me5JqWH9m7Hu}`j(m#Q|*^Jsa>T*4HK>Salg6-B+$XG{s<}nUVS5sZ1y(K zS>T{=Vb(-4I8^*WC!8NMfcKfL{|X)@q1=?}(`Pxs-#`e=N8rvlPGzEq`s&jvVmoK-2*vBqH2rj7xho(^Ifj z$-3MnxB}~A6aRjHjnC4uH7Nmw;-)VAW8r>4+g48IsvZM=i~~C2Y-;4&QqB9~LG@KG zd}jP41up7?``|!oLaoW3*Ex8vJ`kVx$O5_pjrXQfM^+L$QUgxq&j%p23iNkaEke?zUH&G3hnOTgRfH) z4G{?34{OBSw@bcBGte@pGYZF~ttYP*^g&fmQUWH`&;{V;hh>0aac1^I)e z{am}(-*(NRIKEJwWMd~D``IdBy zd6Z@D&-=w!WbDs(x8e5%;*{RzipC6v!<-9y8TgsiZ3(avay2ZHVa*c;Jc*(xNCr^_ zvFj0+Zz}y{Z_*R`et1j!^Ajr48klr+4p6M7od_`QrV}VTe3#%<<+3iEcoC<+o~fZVHmcEh|IQksBp)Hco)PqW`qz$(OVx2XH}1)T+|uTsjQW1+_o)Cf z7~!~Dm3@MEl5?#SB03xCgVLyi^JPs~ zL<8FO6I(JMDk>^Y`OtrmUW7c;vDMKRMIXA1>45utQ-`%}45cl-P`3}EIS9`Z`c#V! zf_LDd)m|LqEqwW5qGUl+AcSB*XNvH5_N`W!{%h7*8`WP%Tgrt6zAAX70*k>RbgWu! zN%IY*)SiS$SYzcI!ENb(GE;6vjLH(;-SKmmVTqrIEag_c)V=|2tH7CI4L2cgNybsYn82rCP9M zPtsWywO;~zqg#e5k{!yIlT5BqLffAdLzXiOxtCT&_U&!*A?OeEYJR}5=e-8C2_)x- zDBT_x($lSRi#jE_!}`^vObZDd?x^nbo_9Eb?>^@c>LoiR+}WqN91G99`vC&9t`^NR z2PNu9Yo#!cIyPIom)b^|RcAHFf>E*wR-KETfS5qTE3;6sNCJx=j0c0_Q69phfib-| zgH%;8)#N&%mib924_Ur4NrCKMHC40Gb`wsuwbI2<4V`d@*IjJ+Cqs}NbFQ< zHNRC`4-9M9hZHm-^$U?jY;L1AH7TdMkeY)UR8SaP9;C4bj~3cR^4B~DvlkGzHjvma zhMX%p`HN`cF`45KZU1BuP$YCjT|ktI5tF)QbVA4-2ucF^{zK0bw^@n$lg zCvrxi|DJKuS}IXW)(vDnvQ6eUEARMtSBL|1qJJl~`T3NjH!mXnLYE`cX@Tnbj1Kkgax^ z0ksC{GS$o4(R!^V^fiLBJN5be3*^yq9FC4r6b`eVdKc;8%e8okhI%E7fHBuCRUQ>A zgPH6JEz3!_n9ANt_KsFfVp-W-tWDL+8+7noWRvD6PFHT6VoB>_x3sK4!vKm@y7BHX z@L7=LP4h5SF-_aD{n%OGmv*1wmIfS(c^5QFy7I{&vym`rE;c_lPqFJw2A|jae*I{f zvhXQ`tuI%^Wi%2TR(f!w=S!WHHi{e1L(=hH5^||kJ%6zhXiZD5cKn{!>Nj?3;x|<_ zuZ|^bAEJ08yFAgD5RUnW4j-!GycUK2pcm{dG(C**35Ndg8)@IY@yDims z3{cD7t%Sr_7yg2Mh8)V8*MBDq)ps+%n+mpEd+y_XV++QNysAfv?~b><(z^x?^L7(vGp)CwxS^iT}F&p(f)Axkv9?+{>_v{W&?v)b3enOyaP7)4U%%q)>*DT`~Z z9$Dh)bDs!cH*geLWt?#E#wBm4+!eP6KZiguF&(%-0?=f7gUrsb`yqd&+uI6^dqkM?8Llv04D4ve=a>@30#Rh*pv9hB- z8ayAu1|5H>;n<09<9UsQ>Rj$gffS-jGFE|ultjDrhJ&#m?1B9@T$r$l&RNeikIW9wS^or&& z{=_sBw@}0-<-@ayskJ;6M(#6=oew;Pp?i_a9z?Y6C>sqe+c35uMF6D`{8Rn3IqK4S zq4rlTp5B2n)12SYg|`-YmVbT1KQ00sSr-5NRTK`Ye9X%9cxnIj zzyJO17r;lh>0OSl(=)ova7x0}U}KS4vfC6baY5! z#wxzOoTAVHG_HBB2Er@CTI+v*rN8<*I_eM~0C zyrPC<=TAa+!D&v_rplN%O)S@&83U~dgu0*uH}~TU3TiRcs(FoW?}FZflA!nNN&Ff$ zi`J`by}sygV90tsnEgIHIv0#M;3(+NmFop!)2(h7I?LoVZqk70{nu0Q*S(08hC4U# zuA*Aqif1esc+|{E$FuBsoedz`d7oovj5h<(CBFk-%(raIgTQ3HK7Xe|6=J6usJZ;sepT9z()UK>Iz#L@ z+ZtOZ5OUab&h5sTAaAA*E3&bZy}KoS6O9V+3n&~zu$FqSV*AER!UN0u^s3wnP2 zAY<*nyWoCzBbxn|T2iVU^h3xnMK!Jf`K}*{mWl!J3B+q(WAdZ)>7vKI4731r%t7jyQU1xM}6T?1|b00^ZA?~cLm`~0JX%R7t%a4!acWs7|AN{_J@gyPMD zaQ5w4*^lHda(B2#_9VR~kGu3~?K7-M;0*tv?>>Cic%~|7YrF_IM1!`QhXNYbOwzXi8mguM;7^vDOl$z)#rl#jq3~QF@d0QP=@I~E&>@Fo8^)Xc`Vw9b zNZlz0ZL;$Tg}L07tcS^^i3KZAgc?ZYRg4894skQ)ggLE!N8p|5Km+|#?Km#-C4-TT z=dSy82O9lw+d1TLz~yquSH?aO097&{uT$#(X9K>0$r4DL13+WIuU|l?i`*M^qTamu zuEc~Z1S$Cq{&vL>mnx04ZkZ9D&2L@}!HSY+h4YSJqI4O3o;sHDL}D?X~FfPF%IxgzMlPs zYkz7_cbrg1%M?3&#Ss-w6Ziw&W$O$4zr`C{IFTT}0&HGEpu>gB*|+JMo;mNdL;b7(SAi%CAgHYs zFkA*wA`>ML+UlE&g9GZy;Wh@qjn3eksXpk`e(~i6pc@xH(+4zO66kK5H?5OGp>I}& zW7~_DfGnq`Bf)tlho+du2|(1ZmX1IauM_Ik7W9U}?Kb5RX_Y-%rx2w0&XI!WY(i}r z(xK9USW8wwR;{E{ZFVQ4t^b4v%mZbMM?HPgi1Gm>o2s{-OZw1-cMx!pA5Q@AQ~KM{ zhg3XIBq&OBBjB%PqpMI=-ICRlxgVDCOnJf&B|O}2aOdfgsNa*B$0Hy^kqH`hW`y~# zPyB-#t_Nq#n@!Cc&zP_+jFtvq0nhR&U5+ZobmrPGa`()E=%Hs=&u|`Z$4HH(j>lcAS1EvUx{K(BlsQ=Cv5Q z3TDO8>30Uc&)P@mvq7LdrJ&r|uRq{wvtIP@RryO3>(1mQcIJ`{drrb0uVmU$qlG2R&`oNV!3X+m+r(#fGpI)deE@BqOdFSA zIYruBQKIuk<1!s@?;u}(`u>y}NQEe@$Sc~c9T5gnl$c&stexag&#ZpaoG> z));&#X}UJr9{cNNoc4bFgJe^dh5BQsk@)XND;-Q0fcN^_;jP~5>vzlfe5Z5Tv z&*I`=N1=0ng>?vwbsZIYe1~VhnTG2;UN4Tm+&u*(F{8QvYUl;A>~#}B&I=LuB)Rt} zM(!)YQ*f&_lYFChnsT!Mj5F!F@f^L1``zx-p~nBGva^nha_zgl$QBe33_==3q#NlF z5RoqFp-ZJCq(fR-xe`@Zh$TI;*k zPy5mWdH$x);SziqQYj;#;;YvjQdkBR?Fcb`PcgQj8kG8C~ujs!%4H0DlrmF;%YYOGaUs7 zT?MK6D(?niY>EU^GBHgCc@ zhdgV0+XO79S2z#{FhnWkB33J08Un^x%fs0KHkCT%M7?WGLqj4lzn&`5*X2_m2}>i7vWJ$lOP9s45fp$ z(`4joVwy&0S?%^C8Jjln-Jy0Bol?}J=ntY%usM&$HwoPozKX?Ee=@U74YTUo8X2^puUeWITY60Y8O!L=79#9daN zUf9y78x6FMn8&4axOP$%UsuAf#3?e*K?P$l({qUpRRk+=j>2nz5p39rkFghycAG|o zMJleD|NYzC=+~j)o&tl?5BNb$-<$~pv{s9*h4f2H!DQmA*M?AUrx?E# zAaF^fuO$nWz1L-&_$1dv@Q(1DQ?c51O&W}0WhQkqtno*}w2+NPdCzxI0Z)M+z4AZWz*=rO(F?lkbm)+}WzR0;jRzO!L9Nt>}4 zE7D$)$S(b982V69^~t%xDg)+{m{K_=(l)}!&odq`%{Ya4>?iHV!C?s7|HUJsw z5yWVX?{Qh$K4=%g!;~zGXz_DyS3-XJezACw)u+dH4k<2a*ws3C`+(ab9@O;~Ik70> zg7Vihh_{R@Z4}hw3F;Qwz!S)~Bjx*ujTiYf(>lrp8}IIW?Qiyr<(_9dMxEFzUYJi@ zv;~=mC3iRfI*WoQRX_as=P`}fE9N#bI|S6Ku=)U%whC z%$hfOu`PRHcyS~F&+^4v=*zQN`XJu_-X9YG23r-bGesj_|wAf zE=jbQ(1tXJUz^wz-^iMqtRvHsW?r} zcJW!1CU6wGG(fkP!DP;Q)r9U)k4h|sZ*QM&p(KTK7IH)6O7qc%W@I&kYS^(_*xYL{ z-8)lb>h2Tk!fVnu?KC5()p;EqFYd`YD#0_eJgr4FElYYc0pXdTcWFzh*?I}kdo1_y zSk|9wf?#OnMbA^dy4Vfb9qZ!nlcV#D11AL8e?T7~Z`oLjzNvTm@n?=t(LvX#3MCNTJO&ol5U))|cQ?mszj%$n=# zzMf-^FloWbb?jKC$lL9B$}DNR$~>X@^2mA} zI1UPBX&@n&^LCu!2`LNx`aPF>Pxk0@lPw1Mx0&p&E)cHTp-{zT<*=hh$?#ncjl1gU zx1)IE>$<1$xWSu(n}C6gLHY>v%nbmxGQt1;S$wLUyrjZGu_3PD{xdMv`3dn$iXlkB0em=;b^*|2?8+G-Y4aGPmYaHDXe=Dp7fEPtdnPV2H=JCc#iDG zXg#xDU--#XaCPd6zSx=oF!Cm;2tUD~JQgTwWU z2M?sE2FEtB!5naoKYwl&^L^_-q}VV@-o9X-fxXX3}%Qd z@*cobi=Zfhpm|%)k##ELn=1Q8#G_Y^IlTbT~DxK59E-Mya0p2 z;jr-aKN#BNNz#$!%^%a8eQQC@L%4%aCF(v#5KHziV<>w5FZq| z=jnJm=*In|S01lxxfhZ`$w+h~C6k;ORlhJP2_JOe02RqQOXxw4cG2-7h$drnRF>1&lA;Q@Vtd%>E_+3t-<(C|e4}z>#<_x9(a^1n{Rk-(cWu?k$Z#)~T&0OIuY| zcez1mx2*MI{dD{4u@9~frd~o084fxBn9BKEK;9ha*!I%ofL1@#o=*h>okR$BkP5S= z5sY@{7b#FL`DRQ^3Q_KFx({&-z-t!8H<|79F{TDy&XAi0piW5|3_D$Ig{@}O208-q z9`GAVYxxtg>H_P%OErbBx0aF-Fm@u{bbJ{wG+U5ZA8N1r(i({q;XwntL@9DCmVFE3 z>UivQKd2?=f7Gd2M>_^?gb8#dq2fMvB8{Rxh^9Sh)5R7qL*n%((pP^7fibw+$v?BN zSMeHL`&b@=iP7OGl`ZmSWVO<(f<>o3e&MRgXUe+Sdr#d5+^Y#Li4IHv4n*%eZlu?X zCKGIi!&=wJ)%A|xNB>vy^gz?>Vt%nRBg>p=68_y)saw78FXk`fh!2hc!AJ*dQmS3?;*JFutrrxx25&w&`}v`t*ZQL`Xi zOtqhOg$liof}zZnm!gr#Si-3xBAPBte3}SKYNc~;@|MyLvwBI)*C6YZ(LeI_@vL{4 zpI&Gv$!x^jRrC}mbqnVsvEN^CS_!S>s}XIom;n9XQ7^DfVliF= zot6Wx)$HN^y=NN~hhOfu%eQ(vC(+3|&OLny+BXR7W}KdSgmJ^Yg$`v}!<3(6LJquk@ zVRF%P;omksgB8}RGs01EIJ%U?U{1AsO~oT@YPFOe(@njq5xHo8`Vg+#Y;uvh=7liR zzQpBSeAa7CV*iU>Rd@dnb~W=6xnOOJ)_q!c605O@&Zkzj2Jz8&`wLL#iZNE8XC4=> z6J_bLzAmko*6}wX#Kt;#rce4pVgS!GeyWM*!~)eB91-j42FWKkL1;X|PkQ(G(EzVR~PS`^CgP{U%;i$Iuhv zvmb{t$YUT)GA*F*CEL7k9g@lR9%H|BiL6f$z1CzfO@wi=sduz9Gr z7hNCF@hrA%bbD39p4mG$WXYR-5YqN!mUsQ7sEM|6u33L#{lPDftSCa=j#6?15AZOYL!Z8%?Y5faU)23K@!HfyFG=Er&-EG< z@9Sb#>T})QM)AU{9>t!Z3^{TT5Br56kU@T@UhROM8V~3SRVG85b_x*>w`s=zLcPwT zsMl5!QL_hr82_eTKWzf)wSb#dW8W>&){4}c0c}382#UgC>^6kW!7LApQs}ZUQ1q|Z zG(z+|obz)(r9O!GVZkxXw(-DxpGN~<)vpU!*(-p z)Xf0Hf(>q$G_z#-j8R7i9;{q3tpy`ivRD~}-RFO2UL{e?tCBOP@)U@iaXQ0|4aU8Q z3#snY%Kz`cYX|mX3pyU#UURcDNx8lo_XPLBy}`+{8w>Mb?#Y{YNoSzZ2Uta!_L)U- ziwym#4%3U%sW9<(^c;hj21!Fx(2U2)XvE%O?T&TR)*KyQf^s^#3l4GqBtC=n{TE{?ysA#nRlTi z6dI&neT<&^OSkSY?=$nkK4Q?0<9PQ`xnR3#kp@t$F_pq^N09zZqTp2@D^DgO^7SF5 zz_G(sQOBT-y00*(!{d@j>{2A{=y-&E>th5f1i$A82(2*tw(rIc2IjxY2kf3Ko=u72 zbKhIj9x&B;(91mIQNd2)mf3yNHbLiqUNI5vTilMsNjl?0E%%;!F z-`utT)uqM4gsL?$RXW_SG)HMLz9f;=(Dy!=2~bT}kqp$Oz8te5>`_SP!TN_Vf#R@q z&cTmN=u(RDYa-vzKc3E8thRKLD*F*)|5TDxJ)VWKB6hRGd$2M))8wFpt*a@1Xi6B* zsQ?&zbn4?4Kw>j{D!stC)19@gqb(ROsa^1`jKe9PoQ_`(9Rs38cN1ecpAwuBlvkfJ zVcpQ}AXPf)yp<}?`JVFqQ!HjXBTt9xQa8i}_(34DY?yW4Rno9RxqSJYT7)>3H)GCt{} zwGd!6yH!`vm(COFYA~X(*@xjMZ1z)dU0VOaZE9`jiWpZNSti*7tcHLQU_RM#5Uo{? z$`dH~cuTJkna*No@U}TW=yikdI&A*di9Jk9-y?uFqq3;#tZ`(b!wkIoeVTV~WGAN~41qY=x zFOyxE40_5xNEjiqVD&jL*`fqCgZIHSH7{(C^_5+b2xHyK(ZKpd_#42eI! z2F+IeqAcpg$r~g44iB?CpH$Y?E|&MrcLC=*p?^RJdO|a0OaB1C(o--YN+I8j57!H@ zSP=HlqwGY!=9`MLc>rRpskZnOO!J(GWkp@Y4=25>uyT*g#GDL@cK+g3*44D!y9D8K zr(8QzTSSHVZYBJA&!Me*L1a+`{QYS_&Cy2dp1f z&R>!sN+2ky=&%xL3AJgLOB9JuGeDOEaHdqQUVAXZ5G-zt-KsH32KqzevkCi&@B*){ z@ST(zp%j+-yxgCZE#CAR0Q8swiF&@Ll!6}>UJ1n8U*4m@R|U^id-d!L{DuvdF72G| zG|W6WEr;h1r=;SInZ=4sJqi(x8_KyTy)~-#>q3F`-)Xa9L>-)VWBOM-!H3V%3$_Vr z`hs#u()!9EEUY`bj`k19W$1Wi>&X>isyQP|Iaf>J{7dwKWp-(%d0$uh6utgaiz)8~p^o#1*(1D>1$$IJS(V8Ek**r z)%lcV%D97OghF8ByL^a`aZ*#>=?$J2A0^VFHEMCPXVR<%jsBm3+Y82^KJj3Y87F3M zSfHQMs#2yE7>^3J82+ulh}*aN?6>|G;#U5|O~5IKO+DH=m7nY7&s#l=O^DA=$A*%) z1}{rxM)-~%KA!=$qvS~J{)HF;!?{-2Wiwbkzn@nXb+5n-Py*cf1HY8Nt}x%PD{M4! z-O3&xBG+9a6>eyBc)>dZEYBz&7z4qbX<$huh8%<83ftHiS)FzbIvtc_sj@`eu z<2!F)K=lIW;jxO3;_Kh3+g)atMOqT}YM1mSL$n7FA}0_QA0*;#A?GmuXkV{!gGlBU zi!|L0aEH5XLX|vEB>2qkQu80hPnSje-L>lYQpzqF{nd15Rrs(!d5p0zak?+5#?SRm z!P}7!D`D70It?tHW{lQp!tTbGNepB{F7}AyLjmnJ=feRWm4X-3U46ma@SJ;ZZM-vT zfV!^~^eO>ywxs=Agkf1H%~9JBt%A@|bm6QFt-~KyQ;tStWL!DBQCF0qiHX;JLbr^= zLOb&dMkj~OcR769g%uq$AG+cqM5=FlmC}LpZL2l4WU}qE_}Wx9Yp2Q5ZIcG_rrx7% zo_LU?KAhBk`mGp6-{O*4)fZ`1Mc2La=+wD>c)5StLQZL7+vY1^(nNMr_U`TsRhd(4 zTE<8&ROzS>xJ$;`51C@?rRly&zXrY%*8{%De*m~_>(nA6_wLymFm}UYZeTHsvMo!y z!+v7E9{)0K8**qyYMsosvd^*qZ0>r5b^SFRwh++K;eRm5_TGu-W4m>wyLWdHs2b!n;dkg(s2(|yaAZw!9LhNgc_H`RHjrI?PNZU9@6{^=LXx(zqs7y7$*?0 z&pGg;*dEJIF&*~`l#bJjH>ZGI`zEbM(CLCs8521IUn_AryD?AedUND8J8{BS^mSt( z1H77o+s;-=e~%1Vs-WBj9e$63&xc=TUK=$qivR+h^OK`_AXpnKsPgOaYX#Ugyjv1G z1RVmoCl+fG&ZetcfiL6(ajU_yx({&vwP)=J%J)lTS3)l$Rlny{5a;xtATKs9ow2KH z^Ts7c#Wd61LWw!~2kyxW+JK`qVwGAAX*aa9Zds#Py2Xw)d|#n|UoCaMN@Q_;K)Yk4 zD0l=t&tpV0Iv}#VF;YN{2gR{mdm={5;wKp0O{E1FFv!Vli91e>ywHjxD#mac; z&$F@2c|3}vItrhm72S$!H-nf`ugl)oTrCQGMuC}6ccjWz=mwFD*#O&m4HCP2fN|ey zkQB(?p-jas-X$Cmd z%P_r2*aAvwvQZH^oBoG>shw|@6B+N3{o(o~ZN)3FyEy0w^W&=i7aqtv}xD!ft+9%3t@iIeFzrmhaLsl%~l(~nve9L|H2J<(IzrBT|uhw+{~RYM|Q zp>4H?XwblBXV7(e;#qG+QGvw>P><}2@G`azAZw+}2+=0U>dW%R5R@CK$hW=eOZ^VHhHlczT3EqE=gSkwg6}mUI+RM}*Q|lH$3d0pW0w$__9qnF zEFL+K&98SvphErdAln&hQ zHUo6OPS{S=5-<7nE<478N3qfnSgABy_gIAZ=gLQlAY4`%BTz=hDUu8im66wc1Sv+w z5VYNUuvQKLc8@K_Z*m_r9?sBLT$j+jBpY=0QoYX1cqFPB(axRQ7X)q4#!WhI=T;y~ z6S_VqW*#21($9Haqx4;ND5n|skd$q!z;CuMt_9Or4M&@K^ds!BqzB&-&II#ga>5#) zf=@!|4!Lb(Vje znXToudd!qQsGEk`PyVJ(Mb7{8Z9?}`%W1ADY(%2Dzx4iu4uZDAVMl8_&*BhJV*G~T z5kj&N5semekV@X39gq1e*urky<2rmY=hX;*cPAc;NxHLpv_$3X+38Kv%Ja*(1t9EN zelY~r?Z%5J5r*AO9k;(eFp3-_@jI?v3FEvt(~FEHE`h>>h(#{LDqU%Iyf1izr7e)` z7L!LgE=Tr$O?g;5H;9t0K{Y0Q(%6Dcx1MtEbL1IF?3%EC1-Vt-!6Sn)iZocRUOGu02Jt$E9uQ2CU-;;3J! z^Z4JWbKqVvSH06;-m;?BU2tJ`{)C))DgS_+b0Bq%aPPA}e6QHL{kBxTfM%;XOjFQF zsf)S3lH5K_q#)9mLRX<-lIDJ_c{r|q#jdZ2{{>PP35I0&P1V`uI{zrk_w!ap@gh5^ zVrL6ucDvmVQ6E3}ehqjv$d{U`f|04^Zj4?EwAJyolE_-t@Xe=b)7%*Bp0&@Xt30PAmDvPyBfr-zQLt)T_#RBpyB>5B z-4-F828OSRD_(WstxPbnt#5}mHQs=bN#jmeWW54BrwL*z*Tmr}Hl|wIQl3U+XPnEk8$!x5Li#~X<9G|2xyj#R1G*5tC zXFL;9s*fk|qqKC!Z+8lQkRb^8yPXE8WwZ#>v zPTbE^hNwl^n9T*x532-%o|lKb;?7M={!1Lp)T6GKXHssGN(-#$0V+9yTbgDi96I&( z?7>9MuU5IcSbYQ>|9qHRQbV5QE4^MZy+?k5hJH%AZYpLk{k;;2?Qa3yy5S zHP_R^R}c~6+?ihY#@$D8ZCydypo>@}(qS)BhJ_vUOWdER2xi?i@;IAW2(k^lchrJ@ z-(--1HROR!RISMu9J7=o*Y?e(NKdQcA}CZw5(-j>&+EjcaH*?c8Rz+8GMGt?TrtPf z=B#!A{7(cu8=BG2b`Raa_+!({^B+Mq{z_!sK&0(Nr9_Ci^utTRrJm}`JsZK`{nJA8 z!KU^t1oOW*L5%uCkFVG)C^}Rr(o$7va&ulv;5|U&gV(qrZNY`}jB%@68YRkH_A3E{ zoO3|YFC6Q8{nnR<%jGjDj5}al73v$^_}CDDH7CiZ46*~ZPNtz5 z_!whH;6g_6Bhn_LMMON6H=I1|_vYtFXBqPF@_6Rm5jsNxs|GfQRm_-Kw1Wt*?v55O z^iKFtg9Xl28#ea9SiZ_A#z&|1T)nH)2~)rdXIWs{93T3n#KnRoVCT{mM~p$KTJiOP zDf0Yq=%|{^vN^M$gyPZRo@5wwifx17(ZXJ>5!8Uqbh4Cml>)etB^)Y}C>}hrn>NK> zd37GxV4!KQx3nl`Zb9-W zy&-`f6Q{lI7xj`@@;V#^RisMX;^&Nhb4;?*=5%V8KITlEH`yzG?;pstg8g!WGAJ}L zO+uXCESuh^fK8To95Kp|_NeK)2Rcy|K1(Q!(FkrenyKCyNzcjbsY=`AO?5w>vc;Al zWb6>dBwwXx0|$osOUrqumD?g`Rste`<}_BKTfM=E|BeY&=o81quFqz>db5@2hCkf9 zGaGDaIZkYbgb>o2UvwJOq%qc=-|E`k$0mE8P_g7Q@kI9o^k3w5yzhA!(9_bV<0$ts z=GN6UbSSqmU{YZO8V?23cBsgKg@Vs=X%lY!1#C9#AL!7J=>o1>SstXde zK!I2~|4fnwJSM9pJBZfgWl%-(G8IS|s_=SLu|duISRCO{QXZC9Ok3#DtT3fyzv*+Y zH^eM&jtG3vfFpm5af5?L$+`)dqZi#{H?z0-0UbBmR)!?H2LT?U*-z@y)e9wXJ4l6T zC|#u_rH&%zS=zr+G`8YYcGeGT_N6&3qO` zmty?}#z51;_<|oBpsFb#V(FwHdEtE9cdom7A1kXzM)f5 z5xsgE#J2_BPuNmN#oBZADGl3g%S_+*dXCSIXhTJxzRZm{`Oiy)dag9IJ_F27CO6t{ zR@U_xs>s9w5!awhUkNKPny$G@(P&eA@cDB?;;ih+p0#JvV;EEGvQ>!cM|lrOd5n5{ zb_I?*TP)2p{tbW;Q0`%QCGP8Jw3v$rBPbrC7{6?B8 zN=FO65p?yMx(o*MS|U6!_~E#mhKYY)!(E!hpjEl8?f3$*kb9d9)ksLeNm^2XUv^6wke_u-%+2%cQHw`sF9cnn%GutI z4ZzJuvI4KZS_y?yv)+!yo|cFR5RxI}$TRlvKS zp~lK9COmJ&Y?yudUYFFV5VQlYUzUF!4BMEx1mEKrE**Btp{HQeB$^Fz|K*>^?e!k2!6a*V>Jh(%uZgx7~tUnTz|RRwE|hA zhpf!TD#h{Lg0`zKt(TzMoR@H#y}^_ly6A};`mQUX?bs4=eTaf!(eGQme%Igg{QbDy z`55{vzjByk;^23r-B0D6s!{k?5W3U57SCxGX3_AWGtZ#i-&TQ0EK&F(kn59Ts$z%t zZVsK`rKOG2Ex&kN*5^*BXwMqtYLb!&o94O8XHWr|kYrV_G#G%#$_tb5_Ow~0(R#1+ z9HTJi?Zcp?$M{A}^zMy(`9N7!urw3r#o_*qo?#(+0d&b_hHWI34hfsyerMLQYqZ!F)%EEF=b@)B`Cc4M zbzl69iSX>&8Kb)#NTBS=Agpsebpi(-Mu>~=V*!Wt@Cc&ip?IuK^udY;#^oYDS znEf&mEBr<~%4n>ux0CNmJfzfr#>;0c+d~Z3zK9FgPgRW+c zgH&}4Jvw|Io>Z4DdQBx#qSbWql4CVN3KCe{cT=h2l6aDRfZCW!yT~KJJ`5}%+Up~n zx3g6XV&{Vp#q7g%YXHHD)|2PtpY+$7x@i5 znwPh>rIGNc4iZODt=wl>NN+L9VLdNs616hG6MnCc@f&gU12ry7P)%1zk=XUxrj`5t z7kfH^H!B;CHsfXnl2;Tdr;s`BqddgX14-R^(IpMg;$OHLa$VR2mPzuea0PG!&%a(b zs-}C0_q%x3ljj zeFSP6`)$$#%jVG~I#@d_COmOJ@izp(B625~!$<9{PN$ChQk&m8$aJzqN9UbaT?i|t zf5T8wAUR3S7zjyJ`9$L(@{;Mub>qO4~UMRS4^ zl4sqH@!g`C8pej64$f!EI3db-YytJ4n_&K#j;N~`6l|(;B5rK7B%@8z$i!}1{>q~N z@vwaU_&c1B^(2ds{qx*WJqx@;xZI!v%C%l+;zHquSupzn4c%B?f7bG$x4}-BxwdoJ z=P(NQBswDvhcR~+t3)M3T%n(ex4H?9mOsLHy8ddyqGH`tYb$#kV^DfoVgNMq-FEA8SSMxj=t03!B&^Yk)2 z?+8H9v8bQ8@#xzOEb_H{tk6v~h}AE>@NMvpcPV5yzXJxtVKbplvHcXgVo zgII`5E>e+Z(qJ*5AwRjH)*>oVibjF%e5Q_E%wdw1ge#CD7)EAF(kU!TyO6`w;in5{KNefv9Ig%;34 zVVQ1{nuto#eYU6m@Myc|pFahWhN0)5XH)5`qo)7;@BfTwNef(;PiNlY+Z@^Z`y2lA z0q6bgSP>-f8v;zB_ht0wx}E1wr$(CZB%SKsn|)ywpFq5$Ek{KqhcF>a%%6p_F4O^y-vIL<+lDX zTbpf;@zlqhvyboVBU(jC8W9c;4g>@QQC3Dm4Fm+71Ox=s3I^)$9it}3w7(ZnH#KQ7 zke|~8ryw9AAhHso8s4B6hR_BYW6NLH^M0xrHdrDUkeK$BFsqn;7i4q8*(b5(()Y=k zPrcU3RE(E+FUS<$@0i!V!S|&j`W?dkfN6GLRwwTPG>p zA&doNL*&STy5JY`u_G8e@~ImqUxVe|5B0?9zff`%3H3V0{QU4Z%IOdIH8!#5IEZ5l z*F10C12FR%s^cPvx}K>MQ(5no|}qN zwS9Z3uzI3Ny0eTE@YN22%}ldro{Y0C*}L2MX0`cKb>O}ynf5wyLm@<$^F5G}9)9f0 zqCo4{)Q&0BCj95%*SH$yd~2^wZBMyBUX5|u$7b8a9>eq|L`2%kt?F_?w!+>?yoAUA zXyfT2^4HVU05%*b`PqlX)^JiKML2`Ml%fdqkZtOHe1DKXx*s!*=jSF6YZ{4&_os&g%wj2H;hp|$SYGY7AVT>0JfL1O>I6B`VGeYj% zavR9?>c-&itNRw%eeZ{g`6zI=*ah?@%HlSlRwfZC+a;Bg ztlK+0iK&i6Lezc=p(wC515v4=|$&t`c5l?oSiHSjZuL-yECG7!qqN@r+hQA0Ids$(Mw==F3Z6*Byp zuP)9ydccH4N!L`}tzHrIqQaeewHaQrR2$)VP+_7_@y=6v5?ZC6h+SS#+qA?iahKnq z=f61?K~|{^_t{Zv9`J*ltGJGq&bm}VNXN@P%teZ)P4c8t*$8$dJPy2yRRfJ&X*Gf_ZJS6HJd_*r184u0)w`V&W3*2f=1i3%3Kgkj5Smq0}*C7itLe zS_&%AH&WYx4pIP{k$b&%;RkH|Rck8^s(Q#`rQ*&S+}aT(MB1PwQo~noD)o*-=e)?f z5qvF|Yi;}3eYtCfr<|8xP0*aAtOizl+2u1n3IeGyX*OcX(ulTKO@dv?U2CULibiX`X4SQK6$1fRbgzRIV+YF!~Hp!h>KC zox^cia5LrnwEd02Q;1GlwZonw!HSnynvLRB8uwxP{;2isP)aRQ$vE|XeKKD9WSWtxY>vO zMKEgA>FZ9rNJX-#ftSlr)e*3h93R%3`?&$#AQPDT=RKBYLMU`Q!th4FI7}HOR=Lz% zGW*OpT-Kl|9j1dx`X*Ok(wGeGYbwW&5ZoWkVsO-a)=LUYKByh82z|LE?LlzmTEKE9 ze(>gp0E0I(vN&+re7~EF!Ji&Zu*`t~DAb+M9m=Z)WLNH2mrFS+<{CY~7b}b6dzYb~ zaV3hFW->o1t|A}}E*bH$Ef!A!h7D}KTFuGLz<;vq66^$08)*f$QZ9s? zutVwqAh7^Hp}8(aYNm|O;|kUdgn+PAIo#j?$KYFH;pLS}cJ$Rg@F%+!FgvaRvjsSJ z8|pb3Li-OdaF#9T=Wb;(!kq6@`nx@Wv<8$jFwGDSudc5Er`xrQ0b4~iDFqs3N!t;1 z3yRzs-ozmZ^lE<@5RW^#w6n}g4dE#f2L+&RQIKaN1@_xV+hYrTTK(7v1_SN#=fSQbz$j;twyYD{2VhH z37`-ooRYHIO|{&3TruxK%aL&JK$u`40@>v?*%2x9`oxGOPAD2eFGRaNUA`*t(pRy6 zm{y%7;LTkD#@YlZ=a2?SJ_t?eWvxj=dDE{qmF!`a;*V8fOzkU*=CxujN?<8ukBbuzW=8?y9 zd>+#GR95A=LE*Zp`QFG$jMeQ(#utM7=CnWHOv3f~2tK;HvOE6OH}uRMzk59x8AX*{ zx)&b><1aW2d3&B=J~toVamfm{;dqsrtU7{F+jNHU2$i9>T?-1aG zt~Y?7Dan(jG?*G^k(p&AI*euIWviP@A>5R>)QuhUb)JXH=%GK?eZx(8NtIVTSa#FD z2n29)21+H334Zk@aMvc^9{=g(kqlLWoh*&PdNkf4W0J&%=mBOFx9SpIh0hGF#nS&U za!5?qN~nc9^M8g}gJ9K*^B7_Nh$%qR8f;fTMKzum&xRNw3mcsI;9W*`HS%FH)|-wSYN^t!OK0$YH-jd> z86=Z1M0%xe?gD*_|Ax-t#g`PK*%H*vvREJyT6cmvDU%;YyghRFmMlB?ZN(m=UO3Y1 z^gLd7zxA7t$aUMY>W0jiy~(n|H>MXX+T^>6(NQw3y=%Ik)a8{N(wL$oGQ)LEI-1{R z->8;2img+%>Fcs8>plZHM6&g!h5YXHTGKKz_V#C>L6>@u9m)4p^Wq)k-mZ!A9d8)u zhHmjWAnL?_%_t1?=2mpzv+Qv?{QZFISm!MI8Oi~gcoR#+u!o8isLXSgnrl683Urh zQSemc4{}xtIXwsfnev(U1t!|2EVkX+qQN-p(#Unl1w+{Il<|&s z(%&W>6G$IY3x1NOxqEcu##@v)Mm&H|QaRCCD!um&nPi>u*Q^RR~4of$vj4@zgoz85qU*JH*Y z^~4i7)uCrxRCoeOd>8Zu#{1G=5Hg?VI$lVs%Y-VU>%EORyDOx%c(P8E+;zW?Ng0zadOildpE$xDP!sRfF%5AXdwqeu7SN ztNd6gCojuQDi>O?yX=;%ehj2-k_rHs0cbVlEYug2=HYmVu?O5BRt~74G3D`9QfNMx z{+j$EQ}b%niyj?cp;JShlMku9`4?-s5T!EZf9pE{YNOL0ZOjwcdkVuJ(0s z_q4v5AN{Eh?NwY$?GWO$05!O;aItoeazNc?om=NRKcf%esd-^pZyvH-H(hj}gsC2Q zYVdQ_s*Li5UYM8$fo=4>xo;LPtKxiklsMU_1Lq~UkowBz*Ty{KJ~N=(jPUs(R=qPC zQRKOgN)F0cVhYZ$uDTJWKd+xI_I5JR(qqdqLH4-=LL~kRl=nB4Cc9A-he4Tc=@k`= zCDc(BxHg@lwr8Cz2-^F8bT_|L!uZIXY=UzkrB&ij8gs`G8}hD&QHR0n-{8yM>tPIm zQ?k;#4DrLK=?8)3loG-dm<=#PZ=iO}GRfXe83zgUHmlpcf(%(jLU-B|N2O;{l9U_H zdslo2H#pHwp4Yy4wZvXn_>PKV!@_oKWMFcsiQX$}z z4N`Ad+4XDU*C2 zS{nq(EgjB-Ly^5%OY5pSK*=Viur!qMU+Aw;C6OcPsHjuVvy(=KQ5!K)J~76vJ*m`R z(&>Snv{{Td5&P zxW2Ber1NGxGw^Cs%YgvWmk$SzkBZQQmZV*l=;~Ik`H?f|b?KMuM2ZT|}|Xws_b2)%Tj$F0=8Q&pWzX4|h*w!?(ZKv$dlpQZ1< zEZAA{4kqvKG?P?`;Q%%S{4zo(7e~bx0LLHRr?AeXC`JeeF)VV@PD*1D0y)oK#Mr9y z*)n;ZehaG9(nQfR3}KQ|ZTvG@*qf-N)(Yf>xw2}5VwviK`O>{u@Rgg-CL^7u zX9Neq-%>AMQ)3#u(8}nB)fGi6$92Rm_$*VQpVplVgV#F)e(+;vBO@#n>(F~F%{|qq z!C9p1_u@4E2V4U)UJ2fw<`V9(2_6=N3_eRo$vYwbcz+WQjNNO21j02)bQSB39YL%@ z=(;#|hUP^vT4bOLq||b3VG@AMA4{XU-IT@tiUXE99;imwTo%~L6P1j0kWo@Ix0ygl zFnP2E;jUjv;z%dC#KA+3?X92L&M3Cpp_vWUF!|ddO}~ z-I^FNn-##?^n}|lJ zix|5UC}6W^%jQzHij&`~FRQ-0d+?o3&r_Wlrdm~T2VEP6adUTLO_dZ@Fwa!i=olR` zhG6`9yqXkad2Yseespj5lu*^%S^I!UNb~KeuBaCSoIh*NMW@BT+VfWG?3suYHwB!p za#}ts(3Ro+p_Y7Mgs6P~I+(s%t=#wrLFmnmvqY|7B;W+khZ#BT$cG1$QkO{jabv3{ z5U3~1pBtll68H=Rx2K|=3lqgzjwUPc7*IK5SP?2mb>Vr8TK4bz6HDu~PRcEW+}X=# z#=*PL8tk7)edWOFLZRq030u5|tk;y56j7Hn?D9bSv>?f`3=P`C0R8^K8vC%)McNXE zOx!9l6M(vE`AW~F`j~I{Rrc6wFVv`B{f~@hoE)E+l+iefL`;$V5>c^b6Q_AN<>3X2pQgywQt^(m$IX!#@Jw zZ(|z@%~8@X^dntL0Z#$4d3S>H;3f^{f|;2(A~VCVqVitLXO>Sim1Pq=_*j3J?CD6y zk(K~bkWiY?mM4}l(2m2ibWW$a3bz(Re-CPn`D_hcNJCrlnSEq>?0fz5o|Q3PZ`ytP z6790i*I5{Ewk3o$xR;5wKnSp09k`GIGbFv|82rPMZPIl3W3-7WHUmS~`}2FClKXWp zD9}bWO?1E|H|>15X1tQhPcZqH)oyzbHh3>sQjQzCMV%PRs%0DD7SvDKDk5d3AH{r>PB3m@x3VfuFq+%p_=OJO~@AI;+X z{w(_egf>`hPl$z~VsFE}SW4!C;o|QT$+pSXTz^Q488EbUZpheON|drSXoU6!rVF$` z__0&yD22Q2BryXh(yALy^UagS&Dd1 z%>}K4@T7kuof5_=sj}+77(h9qKCnI{boqp&W+wAfBN@%HB%N6$QYv=8h)Qow`1vWm zCyDPykLX~7UWphIDrnszfDA2*)S1Ro>XF7SAa}#kjv_$s$CHggV%ENiQW2rn^+b&1 zgfF=M;y}LrjnDO)G*0p-klGq2n;@h=D|F8wH+=CsE6&)7+0&0h>OB!2e#BZ)!NoIb z(?8AKd0~*=DjMMUW9hp)LXiQVatCtxE&qWat_8A;ZE;@aQgvp&{C_iq*oN<3BU!H4= z25sS6qHnh+bo90$>ix|S{*iDVa=(WY(<#t(Ni#QF=1ILTJYXZ7UM^k#9_HkU5F}gY zpFYxNp2NCX;SP$_6e%coR1iL>Ia2$&fcUTq_%~;)F z-y$n1d{S5Xqz6|^Q5|TU`b91k#Et-4fHWGzPgYAKH?$AMQoNXVi|&2NT4!7O-aU%B#uyt%n7Nq2LFuGf&1!5)$#I!uyrIJ zTh>SN&U10i6v?|IPOvf?#L(N944PNT!V1@9f1B+?QFO0@@LRe9s#Bg9+D#g(0?PR< zUa`}3P0z4{L?nXtNhXJm(uB>r-KWB+${tT#p9=J&l!v6vfgMLJ5{|s4LHO^3Y_n27 zm4{+d;*tv+Khu6W%XX2f=vqKNZ}YPhd}j8eACbSWCtmn|6&pKWI8!U&G{WRj$INCG zVHXS?O_7=zJqhb>-BKh_zQWlT?i`O8-kb7SU~WQ(&k^SsWc3m3X(P*aau{WmsjZ-A z^j8hhAQ*AL`7W_W^_<7@C_W{rW9DTCKV8Mh_pA8hwky4n-UU;2wLML+%f5?Q=_?Hg~mV? zCwU)+u*qFI0KRUA@9fw*c0+~#Njx`m`L>#nmA}C~gnT#^lVw3>d z5~)~u9mn->&3_;|TOqXTXVdhgS3-1V?9Orx=LGK-=ifspU7+cayzRu#7-~0%h{0Re zZ(F|pfT*HMkbq2V_w`}dQef^~4s#=;e@Q}dkv%m3qfdeScZf2fcc2Z`eA&bm<*B1# z_fYi*>d&1t_lr`hHQu4M%uZ9Ga2ql5EPDZVcI|Od@mj|l8^`GE5QI&cH2Dmd$^@Hv zW#Xt|_?wevO`GG*3Ax z!0<&`OIcqwb6af`Dd>)gH@EByRYt&UX_Q@hQ}1; z-0iyvXQeB1Qt%`O^Y;$RUlAlbES8u3z9Nd#R~Js*d^H@UrlemWEuw8sT)9A3$i2n2 z{i!e-PL0*TK_{BDWFL1Wh}IK!`ts;&*ZL4&L8-)>5}Dmo_NS_ss~mVw2&K+Vu4BX> zHYSJVRXL@de?kPJPHeaJI6F@tcNa$cSfY0+RJ!hh%LQ4k1-A9Lpm1TE!Q~wZmF$k> z4pPLtU|#yz5w4kTB8;LNb}sq5tExCFrhq?gWIK#9UcX9>TN|Fc<4kw3Ynh&!x{nNM z#hq}Ml^|xxp&Lbt{_IcxmasX5wSo@Q;bBaM@5-s~Z`OvnL;RJqvS@TywxVKr`hyu6 zDFj3+ZW`;qDTMvQ>`%R@Xv*K;wZaTBh0xTL+2(m=-}%(F!tg)=(htr$SgkT+-F%M) zJas@EQ}%jY<7t#K7PDx45-AxZ$-K9WC}8LO>m($R3^~; zA~hkw$umS@dRUx%aL89E%w;tdJwEg;#WN3DK5r%Bn-*_Mse)1vo{>c~$kNYAZgU^h zj}N|Z9tyLmfP}NfMrp$JU>XmE_`@jm8Ku`ePo63y zgkDwBdz4n?nBdnKO@Qe=$=1H6{1N6s(XJOkpK;EhRO-nOSDMzD%D+S1Ez4zO{y7CtZ0Vr7)?gl#7AyqIAWl;|#rgsTAqz@BBiY@{=XafqJfWPA9?2 z1lS9A!s4k~!=?^Tw2E4d5BoSM98I(RnmXdS)ct3tOIGLpELxb<+|`#k`*)~Q=Nhxc z{Lrg0ErhM<0|O)O(jqQU5?($^A>zAh^LWXNT9mT~s6z4qscNd7s)*sh02!u}1 z{P08$l|Rc<2#NRSpsk!0nqtm7k7~-yxL2+oMriRq_b^HR_*SQ@F(Yr>v_{_U+yZw^ zij)b<=)O@GjFnR!+>}8WD?W^-ANrg-)duAHql@lZH~{k5{S$(vcX#@jClOE88(Us0 zdq~i{2Bku$>9L^yKAyd@xB(bVH@5T9`*~>RNNdTAG5@Y<#VmE6d&a)bJd9k9>CODO z^45Z#yKlL_aHE@tZSSW(mG35!Z9C=S>GnVHIEN_2i{h;1^tXQl#)GM1K#sq2%*7l` z{z2LOm#~h3aYm9+ujQP!{2xRA-v-hIMzqtWe{X(W5)%RNV+C=-a-~gjeW#j-z203R^c3xU0HWzKI91EFH3Muw6*&oyE``+hvWoF5h~ z8fA(z)j;*EfmkYr4-CPSzEMp^K=ymjL_NE4Qy z#ELeLWisXV=DR8kYYYiJT%IBvAXU%%0>Ktnd7t5dE?s=mz34h%wFu$PQY*!~1M@M) z-S{jPLV)S~4FBCvpE|Ql+H7XT9TLyrgS7|%ZaZE*eCq2vS&>t}`^`QN91*h&<7)jG zHcXn|Dsv}scse$QnAz!HD0-esowr^`2pc8$*~8E@G&yujq;4w;=i6JQ0w6?OHHM2u zwd%(M*(3YQ!@0F|#lk{`-s{^ez2EoyF|u=Fu`-j!82sxZ7zg7J2S4U<9D_G=HISwH z@4OMIf>C`uv~bk!mBu(cC3Oy<+gZ zOQU`~=O(cOnB&uRT4e9Z)R!+a$F68|NCNs^e)NC% zEe<9l9ArGtK*q)gp=f-S$R<4Zm%T~TpYnr;?AbM#OQg~O`E7i#?kKC{j2o;kPgHzy zE=q)CUK@v~v*kcvSoq)QFe!EDlcG+ zC{|lLq!_(PZ!@kUVJkN~5>Fr9q>eQxg|lvfZJc+?gW6E!GpG(1VKRK~AYPS0<6&3m z6(p;SuwxX*EINqU5Hs^S7d(S}ltu>?rafL*Ph%4apEV4>B+SY&eY5689X!OEkrG&b zNA*A5C!VRa0P23t^j{*_y<}z6!Ofj6U;g^!_wynbH4B=lD#AH%!FF%UT^7yz+!NnY z>2kwPm`6oXIN=I}8+GqW6psTSFF) zRYSdDeAaO{yxLSnd|wwyf|$C{{hbWKrzWW)rRI0VK&jUD$zq*aowxaTy;frw&9tFT z5hDHA0tBk{q|>z|ruKt7=JZD=oWMJ0Ca=R>EZafW(FVr3h}+&;u;7&cOh!pd6T(vQ zan9I8?N%lilZN2f-B-#@8t>lrybnjpA-|2Q`Obl%ro0_6ElqwFN6ky_G2?C@1dcC(XEUvfM=2 zLvs>l05HkNcsZbw!>mGPC?VQkxQ>FK2Y)RjDk7F?8}309zpR{~b)#QjWNw7e_eEZu z;3-lTxUUeSD)5uDrW&f(8cVK18igfgqhYYtOZLf11x|xr4+JSR&W@|WlFC*!L03Uz(C1W=TFKZ{G5#D@CqViBP z*^O3WIg#|F!(RGOYaYPW^V(ox@rk&Ku|B zUI-j^Kv8%DkC4P>U7$qS$ok~Et&KH`gv`^Mi$}q=3K}^ib=qSK6-4g?L^a`B;Ou?~ z{ng$Lqt`Z14_86{I;#}?ZXXf)4!rp#W)miUC{;Y?%(QiVf z$5xgw#{R>tTS$HDhD|#lvd-j7M<;!LA5^FL&Z_g@Zm*h%~9pBz$ zc-!sk%MHcZFku%ocGupKoT<5z14?#fd#E$h84LV?^@QJruqS)r0$e$&DNd26*$I?i zeCsb!_roKpnFM#xQ+xL~Rn~c%lAgGm=;#_i*3Q~N5ezbvz7|X5A{=(erTL;@vd2%@ znBT$9iCzEl@fYWl_z?&g?^s-u{t%e(!C|wZT-Ve2PE98z8IB@=4zDrX6G6Ba$vMxt zu8cEzX%J2hV2ap?gK=+a3^tlll&F8SoT#6)G@SRh1e1pv=p!Lcl%#54nG)}I5|%Ki zmWVb5X>dd$kbM2MzgE~xg4d2!XBqtoKWDE)FVI?+kf@3J!2Cyibqn*SJ5|6M{)9yh zLf|O&}2a{bBD-@gv*DvX2=un(_9!K zK@4=<`%eR^g-O6T+oh5{H$lu-hx_o@Z+oBNaNAA@`WM)jn>m|X#`^-Ur<&n*t%(|R z)o$3Wm4w8e2QXP1n>l%lzL&9mG!_DK|4Q_vM~D&52eEqm2TcBQHCIZ;bL%-b0V<{Z zIGcs?IadZ(BRn*Xllq$R_Hd%Rh0>>$vg%Ila^V^jFd$zZ)LA7gVrr^!ye(@L>zgFl zA$DqULzu5YbqE_!%}6g~alDS)|09xo^@fzmcz(+ChHwi$VvagVME>S%*_C#w-mo4v zlg9$CT)7|t78J48xT@|>Tb1uX2QVILJ z3&i?ZTi=6O@7QxE^s|6B&HUkT#k*T%;)F`z?toXiZ^O;rjIZ}P&)BoF^h(Rl^N!YAfTWlF&CL#;^!BV@pU(3 zMld{z=M!|5uO62TR0>vr3&}g*c7xn#LC*8OhBpQp&T+Uk7E<7eF+uo^fxf~U2M)6G z$b3sau_eP3`uPc~1A*`2u<5;*vDwhU>Em(v?nl)^hk+O}IAWUw5pPV% z-IEQC@ZW9JZ+C>OZN4^k2keMI{qFOL(A)~8aNPdLF2++NFf z^5ltd@}vrisoSnAK`>z3pYn6-49L%e$9oqem@@Tk((?4bWe9;nzF`;P8F`RR2im*q zz22F8Gh?gK$sERai_#=n-UpLSWUqXj62|unz2A)Elb?BdF29=TB+yl zTe^_mVZ5i%IIn;65}!Sc)sAeX_nk0*&0q1sT`gk85&S?{NX9ZX+DEupJdfE@V%I_P z{qk&V8JLM?zqLrCl)@1lz#n#7A4Xi5)J>N?^nYMjjkkHm+RgK8X6+UEKFdWsepJXu zN4FY9z)sv_!*H;-)*I1g@oYz!=@^kNGx>(bE+cHdv!bcRVM1Fckd-^1nGdUgfcZ`? zAn0p#t7yCSmjz??wZ<3~MV)QCwI|(FPLFa?0=u1#6#8L= z3eDPaACSp}e8X6TG9nU=SKRJta5J8@<63DiT%o(zWvRqy|+#2D` z(kJiQ-x}f!qh6=|5ACyIzS=WUixQJOO2E#+rS{P8pNH9T7@A?@MTou^oO`cL%G6MRT)+2L&e{L5Q9!78AhhrCyq%%D$QH=!m= zkmgJADPdXyqgofJm#fqtkFbxvqS96X!%w0IEJG)L7cAL{+`WjZ4FU8uR{hF4b1QI? z(A!dp?aR@OpH+s!QQHrrWZ5d{GlNm;HrpeUAQp)WlwO-h1tH)2@`WV)!EtVylH5JW zfvVJMXx??${Tph;n(boFyBDS|wtMcNP`uD3)L(?Q@iaH%Nu5?aOo~{$Q%#pVL?dI9 zoFe$!2P^Z#2^uxlA8xzJn3c0dckO6QpV;YWboJZKGeOhL!z zJ3!$@{ z=g#H0ArHU;Lg1C(IVbSoGT)Lc%_U;ru|(txl-^qydr6^U#Tw`D{V~9(9uq!uA`c(c_6Xu*d~3vW_7c2*LFP zXJ6?IO(B#S_nVk2lC>Wr%w-JN9DC5S2ty(VX0?+^Q&dq+!eftEcC2}CKmdD*5#C_^ z2<6MBD@-80mB(b8L+Ih;wQZRhu~S$}#i{v5K`uLL?UZ0N(?oN+uCBzoi>B1VK%nLe zo%+V&Lghp`1;=$bY`%cRb)1?Q#54ha)Z(OqD_&3Pye8%HX7s2eZBn{|AyPMTd(kCr zIFVde;(wPdPXGUqExbm=IK6(-EjlfBYIGpplVsPG-iAy%nGTx?3= z*QeU)kpC7ws?aM~dnBPEzrLzO{>(e++)E*W9U5UV>&vo5oI&*o{?k*6BSSI;Z#+hC zL_xYCc+)9Hqe!H0FKryJohmyQoUJmlV|u;-r98QTln?j3yG0Tpl&Z2Z3h(Tn&vqP& z$woEAkY)c{jA%z^K&ggO-{tB4^rm%Q+$NA~yiy$`X;IYdNH@nO4dULq5^kPtvFQ4R z5n*E`ahSk2(&?H7e9Ok)X#&vRV301gUvtz^K#B%rpw>xBQSGx6a_mRE*k%SsqAJ_{MB0fZL-A3&eI+Z)cT-=S z?KCqIS#1yAJT_vBX=2mrcgx8tRI=7X8leF1C=2eUa!Q|Cbya#}A2_d?$f4j|WS1Y) zT&GDXOg=DKK&+S@HzHpj^g-=Li}sc zZL?9lvf%WnfJIBV%%b+lwCG=j$d5R9l@~TLW$qnZ(}9F+wrsWY1#y!mZxW}KMG3#Q zTLGTzeDVwuWkvY>*~v-K7*t7pB;N)yu5W%XT4PT9!}b`dM?_b|Oe8)H8Qbt$a%@|c zQqa#|tl4W)Ma{No#1Pm>7`|U-HlFULR@>$8B&6I*QP#raru7T+qfMV}XT=VZl%I)0 z?lX$_rcG4?rAj($?}@q0tUC13g_%>fvB6?w=Sa4j8uk;VQ=vFV?_pTx66F6mT6A~G z#FFvuy5_B{7bqqVN4zx9Zm?HYVyK#>{B`w8iqYqivwO@hE#SvS)&()vMaL&YsR?#g zrdtAjuOqk9vTgxt4@894N|d;N4cObZbu&}7D8^V_DLlZ9Gq3!`o`aVZtFk^wY~O_8M#C(J11(}dRrrWTPs zXL4_)%=iuQ&-jYTyE@*T=Hm5}`nbY?9|tDbVq}t^CrLiIb7Z>HtX7E)>^w~rCmD+_ zc!$>G#Yr3`D8EsxgGLBelpDJh;T7cG)7IC)qH50(meB(1Y;*|`E$omEowebeOqP3{ zIPREg3HD%D2EhdsRO(>GYTwo-#u%b%jl&i1?8Q?Ve~O+J3x?j^EP7;@v3D z<>xD&24bFVvK@T0_r`jnpJ<7$pzS+*y<~B3f{sbN8iVW%%|L%LY#=9r|A@G4=-d+ zMll7ZyQ#4z8+srv3FlfFYX-L1aLU(NR(4d&C3c-c?sgvUH$M*L_Q^Gy9b@0QwB__p z)C{oJ+F?_5vTxJ7SyIq%FcR;p_&v+)*t~z`{id0@*XArP@ghp5WIL5#Do9AThuPvK zZf@O53ICUN?(eX@DC8SmZuV~kKm39vKf=TlLGS-n0ja7iNVhfQ@lxrjP1VgF3IAKb zv;_0Ba1adyF4)*6^-16e!Fj=laio|ck^4F(dFb|({u;c8esC-HyGA@wmaj&DOE{=C zpfM(L`mhZIstCV@ zP`&@E!khI2LAVZxQ?x^DFpVciGI+^Lv-n&Q3DSC+V6zvow+_luQAE3W6qV4G;hVZW zR<%5e55D}y;2keD0q?kcRrI4|F;Q&;)Ce0PN28$BBSw_fAm|mlTj1hQTgGP<6)1c$ z5o1?X(EbER))gp%@0mUDl1L7xJ0_hw_Ie)^bZn-E>Akr1(4I2Jj0+IriSkFs5?1{U zd6?z1XYA@gRDbl1CzZ;?sf@1<4KIy3K7Wk3u60*)sEMB+l+gkE0I@{QfG+955GODj zcv8sRA1$VgN0rxIjFsr7JwB!*+Q z6Pik0ou|^mhk*8*we}%GN+xinH$5T#j!Q)8ov9C#pC%YkR1JdKeUxrv{e7|Z%h`M5 zWNy?6|CVYkiJX7%$HTR-OK{+(CrmCc&h&$3$^YSeyf7kW>o(~DhX?&V+fy1qkYj93 z4pz}VHjW#VBR?Pi#rH^+uM3<**Wj7WkCP?*kz)8=4xXP!M|1aW8U~Uu4!uGS09Jx3 z$midg9$K~Y84Q!Q$XsyNj=ALYQn0>K9}7cr4KK2HRr&^WL+ML74& za0w)V^u)D^dh9FJRI0~I!3zDU@y#~(-2DcZAoX`l4427nm{Qb68w#-z%AR-x>m@V8 zqfcJ+Z%7NozElS36an8>pS*v{5*OciFA2Nj159zP$)A-l>|UR-S6Ku3#kRK~=ekqH za#*+xc;X;!<^@*m>WoId8GPQd%uDqkKA%zecYl<|$<55zCqi1Mcfi$udFFrWsQp6( z!8LZ|rOQ;6wg9JLV`BQ7V=A&adRuGs-nIPyaG@wehax)7pt?+ZX5pXNr_=TSe6x*5So=(Sq{X7vW=Nz zQ7e#b$YjBqLT7W{`2odjU2oUlxr72BJtctg$Bby+aflp?&ynG93C=RdwcR#Q7p`~B zXHeWWSjYFgYd5sM_Cv2qtR``HNF++M;hp8~w)i+R(-iX*j!w0D4RZbrl1JSQLPcGK z48eMnwBWb#Jyw2jazUM3-mt=5*HIoO$Z?Tjl9g@@<~5iyP<_z}LEdYpc_e7-avVc` z%0-vTvdKIA!4CSNGDvEEouh43eYd zG?IiAChdC!MfkNAQh(URT)0*QltgD~zl3|hIvgC2vm}OGlbOq?7tsPH4cdqC)Q?$7 zBAeJ4gl|>RJEt9LAIA?@INHs2KEUc_ag}5N{eG3y2g?pMHyBr+Yj&~$F#dS_g6jU$ zz`+p`ewh9b>Epf>;bN)I&Pyjvc+lgIU-I3+H171MLI?;LXaJ^2TrWsgRwo-1Hunoh zMLjphw_T}fgRVGn4~3M#rk!lI)*opwz99;wHaYQBz;9X6IoN!9F)A2-@)d}i`(lFh zz|x9%8QIR3*_la=7arYt*d^Ym?h>;*^|ZhxPVy3t@<3ch_o!`Tdc<!6ml5AU6f4 zIOtqEqB%Hx!k!7hnpErBT*UA{W> z-Vu)Dv17nPC?S$*^Iaw8+hqR8Z}_b?Hcj2qR%Neg|0!V{sg#S0saq1)uTf|69I!7M zWW~WNGnm+Dgpk#&;cWR)c*8E-oGe}0gvDd*QK&eP5ZF(~Lqn*?2=sHHKG%*kf3St`B>7l%F&0kKi< z@XyjtZDjBeO_18p5iEQ*^(874a($1ty~(84I8`{<6G?1Ypdx zV9Yk}BX;ee>|@iRn^+83B1Wu4L=D4x@9{$^uW&1qw6WHpA8-;|ePL|meye@~P{vm1 zrNj**(XNjV2UYPC1xb$cmj&kvyE~u_mDS~S@AD!HAa5fljh?8*=A}0AJzdi!{?;CY z44uugcvZ>h$0*h`e_PAvRStPNk0U|i#a`Vlj`w0>%zos4d^Gu{addZjMwVet>E6Sk zxB+o{=8P$wJDQwfJ`7<##5b77`pIvccCi0Myghg@k&eTYxlr44ob;Hv%t|=fKRRC) z;6WHx%x26)&cTJ6xqsQC{&cB_<}~>$hQfnRgT8kE_;a`SFVOx!AU;ZvRBmXn`1gMk zyH29th0sSJ{|C_jkGA<>0Q7%M>*xH(_1{fP0>J|v=7+!o@jv5}3xZ;-_d~)>9QMD? z0&sYB!F7SDl>R6FhrNWVoJJVR$eFIpc+II2vZEs1XLJ+L@xmkgdfauIHuUf$C1#H7 zez_o2&rFj#0AlJ9IhW~`#hLM->=fvS7q(p9AnKCJuW*%z`e)3dykKni|2cM6ifa4g z>Q4ZMC{_sDVk|dt^Z*+I9X{C81-InhZ~gypeFNI_iR>4H4M0ZgY_1^zm?947f1~tb ze3na5d_lV0E);aKMczUsRE43Yoa3)jyTX0Zz1V0NCs%=>&Q9kL%?~mcotZyHLSu!g z9=t>pas9eViSn$CbNwNy&Cdy}D{0D{SNfDm1lDysbw z@sohu4PS$XkUon4Wc0XsgSsX4iQ^CSJQ!uxLldtVmv&)UvlNH?v5 zW_L}PjLRg~H_mT35H4sQoi(+t(f06fi#XLS%rUll(OD2RM1)-*&xsrP2Um9$`NKg$ ztrQ`?J3=}OvCeFogBiaC!9q(O-`A zsGKz$u#W-JO}UqONB~tMnzE~l7fUFuQ!#A!!4da7J^1+oruF@^{=cw!_DZ=d`4k_| zAO$(t#*A<>)v5n~!{+06hO-G5fMzdlG>WI^T)Y@oA}<#j)g;ZWJU-x1WLJ^lJqs+jjaV-GKZ@)p?TNh&dm_j4kmxHE+N701UsJ8OT!X&m= zldU<_QQW;%tfCSjA4&{tHl#y&0#~amh@e06_9R(P0xY#AALDc$V?)(r68b*3|BJDA z4wCfg^LA(2wr%&cZQJf?+qP{^+qP|1+qP{@o2P&0*^S+O_I=}=$bagNim0l%BeU+z zyuQ~bcboe|jtjP+V#Ww>yb#^+db*A+83_KAVXGg{H8q)}I{X*zhB3{8C%YxfqBpwON-L83l21Ak$KkiT=!~EXTSr|1Zj&F-Xs(gu+_z zIyr5o^+DAX4EMP9qW3F8&c$F9cun7c;CD^VK&OBG->tp-?nv;R{tq^J;!N^S>JH4X z;5(nQF$oH9b_AY>i<_Qx+X#2zLBku!eQG7Vw+2(f-HJzb=d49Ss_Y0uTM3k~Q%3?C zA7o?FhB)047P+Lkg%b(OD9GN2~Tb5TbYpqCQ|8-IdrPHdUSU$ZuS1G8^q5&m7$0 z0MUu{e-f{aneYO;nd;SFJ5(UDYVoQHuiJc%89Z%JLP8Jp`#jw-&RX!0w^8+Xe=D3& zdPgd~%{g!2PQ;((xC3P?rqiG|G2m^>KMct`KgO$OA9BNFX_GYj_U#dM))BzlDsl({ ziADZh5H?*CYkEWmb3D!wq2{4`o;I@gddqUtcv(!2B6j$$(CV~;D7DV^x_lmyqKjLx z0tJkD4a{ByNcGx9-I#+K@d(&QTOk!S+r38MDw%tbM$P6QyGdtqW6l@L6dbBYOhqQj z?W+WTwmWpw-pA#THTC>bne1Zx&9TRiDY#)qq6Ge$y?p`JQ6JwPdoEiwu;HaBwW#ta> z$&;BwoMxL)*kH-lBBk!(^@6(UV#rN!T6Q?lZAxgnB*f2W{W)VdkaH>I^G z{R_fvD8I%CXYLVi9(5y@Ox#=1dErgzs`)*dcr-OR>Ol*pTw~+9Zt5HOUEZOzI?&;j zj$bgi>{+Ci*#f&YY}r+H`vMiQTOYBa>lZK}qCEgzYPqSymrZu}HtS%Zx4L_R2Ve*4 z@PJ$mPxY6f&ze!*xoyLKu-3Gq-J`3Y>`AF$LdeJ{8yc}4X%~#fGEULoy~b;v7lV-w zOlRmR{!cCZX&U;i@~EDvVdVJeKgE6Az97m^*&WeAV$Q71l&3wOZtZ;yr7**`+_R(o z?-M8+ur#T5Q#D;JJIz&&|;j_fp)Kym+ z?%>#)jD^pkvzizogK%<_7`Wb~LUMZZEwJjCX8O{ZD&U%Wg8w@Wi>nmcx5i+Gvw2y* zF~vIE9lH7(H(m9A0%9c76_(tDZ8$`0`j`3}h&o62LF|qF6vW6*0TA$4JSY{v7d??x z8R~vbVa#g4n}V$yW?E7^5M1q1aZFj!`+4u;-dp(U{EDWyFIAau7?x^50g)?ORBMwGwu`!BwdzM5tT z9-p2jk;O_^$$Xz?G`w0wx~T6qu8P zOC?j4S3@qiZG$_qtH<`bywO%J-=lD>xXU^bh{C${bJe#61;Zw?&$gp?R|hNq!kXbI z+JgC5h44MfZTW{4I(%Q5+f4uBx6Jf$D8CO9j9nh%}p8Put9bqkV z_cJV_7Vw}A+kDkL{s1|{!y=8MVJ#6YljQs4e;yr35Cb^r@D=gjquYf47#vC=-W%wa zTx|bU$)Z@xqt_2CFk*aVRjau7Ke5Q~@rY?AaGH@kgwxr289ccS!EkSALm`F)opqH) z5J_$r;%@Zth}rameJ8Vkq!+66?+k!#|H_i{*)7>FUjMcnO8}9!xBvORZ<7 zUx61FOuC+&ZUI#ud# z<+4sNn4H9A88+3p3OpZPR=Yu=CwwGw1tt1H45-0%+SGLKgw_fk_{hyita4ao$ zSCx9SaD*iyZ^vgB&1{C@;EwKWfZA!55x7|LEe1)uxoIyVWxAp8dw5S!ys)(0|*RcCWjaeY4bH334EwYzpvV1NqmsHwtUy@?2AN z=^P!MoF^ri3nO5^*6c<3axZ$}n#Y2X4BSaRD~0i6LEw76Ax0YAGj(ogzg-~BN5BE5 z9{@nKf5iFBw>;?LR!%t$BU0B)yzjniO7s3nOog>P6t`z}~%GRDZvX z19ydY(1`?X9YgVF9diAiMFc-VfBRlLhs3o@DIqB5+#&5IZxhevkULwk8A4yvO!O>Y zsINy{h>g-$m+upd7O6yAZRcTxtrx>|{Q)ro>h-p`Lx`P;g(_y1Ue;v5KK;Rt;Dh78 z(9@QR9T30Q1kpdNci>>6#cH>mUX@9_!|A3?$HGrr z*fTlF%9toP!y2^d;prC-;zT+A+n?Gn_fWz%Q!J zbggb+b$8#v93>X~*FWhypBPxHSb9TPV%Y6=T{X6_PNv6vG(xnZz8Aqe#$x=e!2SPo z@0SPO1U`g<4^xczI&56Q?vALQ9MquG9PKXZa+gGMIL1ul{N#)eMQ6z?ow6=CsqTO3 ze)sUbFtJG76SN@HV|X!SpkXWCB9>8FZ}6cl(RfuNErcJ<7##J)FcM#%$mnLAYjFNd z;D9!E=(3-N^f9wz7lfm7{r+|?Sn5im77q#Ze^)nU`@c-Dxqjrg*Z24`-LpC+ZGj5V z8vw%wkh0PYY#FjHRoXBgNqvzsWXRN~Usy=zGZdFu#`4rbQ?bhT285x2782uvfu+7o zW%N(M#x`_TQZt$3fSv&fS^6vHC7HsYab^$@dx^lifYclRvVoquxGh<3lY=n zzIwIYd*PnE3|-8AyilFmx)W0gX)=HZcCZmXP{i@ir$~#=os2)=;238{InF-srrEO`sl_N9_8>EbHGz*&|HFot89@ z0JJK7Pcf>X<4Zme859mpF1Wvb^%D*4u6G#iZ*Jd?#} zVOps;(=#*GA)@)4!v7QqB=r(>(WCTE?akw?x_R}rODX$9)dR2<1EP1{fV$5n1DYfN zD>=id{$x(kPXco{9*F(x$5aPV z2g$YoN$o~=R~p-b;}%+b5w&1U!MfQ<$1zHxO6hxR`>d@TABMg4NrPhcL~o`4%iar~ zV+*tfB7`$NN~uruXXh+hj|(s8a8-OvSv+NyMZ4*g{H=;Y3EDk8cX+x_NV{RSILC_V z7EYKh8zL#(b*<6ww^rrUx3{z*LN!(t=rbcOQp*G{^KP&qo#)J59>Dog?)JOb`QU}I z{RE+lZn@3i!Qu3Zj`qQ_?Fr*3oFEbjhj$KaT0U}0mJl4aKkK|pq2cI<>Q-H7i3U%E zm-+9lC!F3dAMnbQS*(;PC{e?kLv(-jE(7fh7ERH~K_i7XIl}AG&XpZR1q>x82y(MW z2<-2>Kndbh+SBei>CbX!M@Ot_Jd4pzd5nfv*zy;AhY^zZ9;rr_gGRShMk&Gj+j1;+ zE|q=B$&?dSEfSJcGR7Z%#Ffr?`WdurvSSbr>L$8a+Nc#4PPlJw7|Zee8ImFTnykcS z%mIvbm&{}y=A8REpPNKl2T=>*#0WG7Cr(anx>yI%i22jQz4DC#s_3>10Shyqmk;s0 zCCj2Ay+l^;nI0wQ072dqp-=2%U2|0q@{^j?HNDM4~BU6$X z;t{QN2k_m(?hw`h(G3mZP2!R+&h(@@LKBE6RFK zwP|+sRSsK_CQD@JRM5|vKfC(4PZL1Y`)}>0M3mnhy^_yaVYUCCoBQwWeHNk?ZUp}W zWaVAsyXXJU_9^(!o4P0Z4I;*fdjHm*3lQ~i`7YhN1v_s0e!< zQ-5*bE&(06IRY~u3h(b%mE;fs=jbRMb$5aB{!1Q0j%8cA^7e=}rZq%-W+J+&T+*Go zCU7|LN@Zio4VTrelG2Vgv}c%JK=wF0>#03FL3P5X+-_Vk%<3jqXMp&`?vBS1d?{2Y z288H3B`NhMY6+>7p@!y7<+80zSfp3kZ zt$%=7G!SYIcS5opN}MZIWDhz{Pr(=RuF)4eHMS+#MY@ z3jpXRrtxrop0cqLy(QS~K>3hyB3p223`AjzUbTBJZxL!W62tMwYYpq6uaY50=k@f4i- zaU5aYBp1-(^&2n!9U%A&htB4Mc{I%WmNkTx+m}!zG)@?6z^l&MiUw!ok4Sz~;+v@N zA;gOhyIxzhXYc=UT&N>2TRsPY@Q` z9%W*n-1!Md{ic_`un#{kr@DHgM&PaM#Kg<1@Rz|#9?V6@djBthm{n#d1_+SM<-s%Qzdu_`1dwv1{{jl z5CH!b#;bFeKUD3IFWG6JDM(Sd0~(_X`uH~z%JrK&Fk2xk-Qaz^;qC@qnGjqUgY)|m zYpDxwYNZ88lNl1F$y&3U*kRM*5JOh@wDd*qG1NijK`Jags-Er|qp;MvsV&%Luh_fN zbE)Li5+*~_VS(3q5vE&)8*x_6-V363m6s_-NuUpWmxWgKDb{fyWkB;CZk1b5or!?o zA7G*}5re3^@91KE+MzU!cu5EP)?W~Hs5_6m;eY##oHArFpm0{OTT#b1B7{_-VAmh+ z_Pje)~8Z$q1g&I2twY zEgL^H2-1aj*Pm_cXnOrCt%V;~uNe#%Dq6=9zaphdGY18v&FQ2e5Dc!p_}3m5*;5dRN9Wy;LZsi&{9Tw|d(DNdA5}9yozskhUSFWqPi*}*G<92D z!5QhUf6_Towl8aoY#hlCF!U&N@w(aU*}&L6Auq?~*CV&KT3cllzu2{gIE4`?y_G?H zPxW2kY#~Kubiv`Fq3wiKN^5LEh6jKiAeCx~kHS>jRo@^32fMKC?%$GbvR(0hE-lR< zZ;8GS5lFnKq;3=!?xgkRGt|x;7epBT1n&y1^*Qw3yk&v`@74w(r}F$IgDoI16dqmf>8|@??gk;tVSO*v5g2j_569qdeULn&5RX!4637H z))`KoIIrireNc3U9CF~H*lLTmc0M#rC**y!yeSAK#tM3^Jx<;qj#8;AHY!U%$KF)% z5)bG6VB%gjZ0yFgddQrazVwWmpAYq?$HkuiB7OOod3s{X3ARH{EQqiK)d9dxj1^uN z(3llSy(}EkDg6xy29|kyZFyGJO)foKo6e4$JDP=+!hjmHORykYzNtIWP72yih>#~O zT&p#nQL{-M8v(*7SnnN8Wu5r}#{4CDbAtAr?@Ua5?xRxBQxxE{c`u(VKBe?Kkm{oi zm035&Je3k8=0`M`C=?{8C|ADjfS86mELC~gV9BrV#qs{(3ZO4icHhM=G({h;TE`{> zFk`z%fH8C}RPRFqCX@#raKAkBw+Wvabsp>#5SMNHQIN6X+l@P|W?~t6PTr7TJ0}|i z&9-MR-V3NF?5Z^#qrX@uwf|9Nu9;R=1}saP4wMmMa3Ndm-{ekvB{jJqPJV2%+^>*o zL(`i!Ktl4nZI>nXM`k!m?~z&N3R3hPt(EtYP1)_8$XSj0kz(|U%$KNi%dDF()B{=8 zA;4(GB7M#b40@OsBi$K?fz*)U<3l_%*ZhZop&)~;F$M420n}$gBjo;NLM^Km>ec&) zrB%jhI5k)IknOC-G!9N>9}Q4eG{5{xhaJ;+e^+Wtyx|ULO>f(Y4drE7!S=Ra+Z*D@ ze!YKWBn{U<->wrP;%+xt)LmYlF3BTs2(B&ncSr4hf z@dqrI^`C(STwTT|N-N=)c7rzeXS(m(afvOv-K6YG0{;>U+8mXxYkxn~1-xaU`}t-q z$$Y3q(%C=0CPhn^zP40rcoh4LNZB9&k=dY4|32Pl{ zTMZ$6SsVWTB@`sD0G_U4(g%ewdZyx@3OSt#QZjLhF3@j*vOiJPY&9M|LFJXG?E3X! zHDtlA(D{angkOP_*XSi#QwoT_Er&%gL&DQwBRW5szS z>Kv~&oE91bbUfTR7`uQeMoOmV*q$`*rsC@eDb;i4A=%+aBrWX6=Xjy*rd&lrr&*o* zCGfgDW54+EjScadtLDkbfW2OG&vQHEMTKFt+Y;nUvyX)FMWFvePZ(ig?rsFB*yO3* zV3y?$Aet=@)!|4my|(FhpmE;KcRObe>Kf~m-x9S^*YGCxJ_#n_QJ_#hvUmB z6BFK=#%Srq7zFj!Uj%^SIO2n}A6!_u$z~^LXagqBTG` z;Q_ra>{IM19%GjvnA`t8`K#LC5VOt*a(h2(XZi~+n}K#L!V^@G#3-89bSrR78d`hxV`NmB=_AFXZPrS6Q)D_n zdn2f;@qMkG2|P-oqAgc$ATZK9XB5r+!4!DG@sRhzLjt9hcT$t%0Ez=Ef(_VK6x~78 zfzyHwafuMa%2}XgZ`4c+T#6i?MOJC50a{GjQXj-T`mRG3kpKr?#$Vk5D)R7aB#-h0(|)`Pet|7V^@WY94clhn=^it3Eypv&P9*fr1~y=D4pa z+kpEc7k|-5R>Z}m*!k2DU8zUbbEKq9A?scsX%>)2>SxKbgTVmYUa{ml(T@Qm5Fv~f zJAMw;3WPZ~_yp9YV4TslVDX+?jN~3%2DJ3kdUM+-*tI)8O($%_OuoTC`Ru_g1dQit z6`KUo561*P%cz43N6)9*aD+^uUbZ%Rj_JP;^(DD~jbfOOEi9gZ-{8pr!Y2?gH;3^i zk`=gIny{lZy8J8FGaS!RK3w501uywEL9VZ2hRSg+)>A@9=i8kpR6$Rxm*}R>RGF(* z3k7QQB+t#{NxCjz;xf%*XXHI0q^ojk$ou2EeGcrz(O#jI_7bzN zlN{4-@b;zJIs1Mx{BfIv`vef=$8t04wFc({&xK`?FL2;TC0e|irP$D;K`Ib!68P_O ztEh)BCLcjC1P1`;Yi95I76V3p(iZ?3p^lP&XU@tE7xUt|`P6nA4c%Yu&qk(&2>0${ z&FgADiQp?duxfQa(T2Rm441^4#xc6WSSf_h*H!-Q%N_h)=?4L%^f^9rZeaO>iV&kq z>9}KllauX%O}Zeq!TI@znOrWYvH~Zm#)Tkmdd~o=IKpwfdjoKw;_;lF9og?r6^9na z@^X*s@TAnLY|#*Aoe0?e^sI(ZsVCLsPx8(N;*NNCLfWYABb>P-1$P^k<|zfgi~T{g zQ;0UHQI+G3(~tHINq^&awf^(`V@s#Z7u$ zqS15&vHKV8GFwE3`T$ZfUWN${2G(gntihy8*@SslTZtH_?4}=SjYOdE8ie>2m!=Lo z`dU(!YShs!@;0)Gm$k^NAaUz~jTY-M;4kyr-eC1~Gm`^-eLiJEY$6M!?4HiNIy<8b zo%MaQR}M%L!mKoooFO?X90c1BWKpg>yC?sn!4sqkDgyfZX;#NoD#e90|NZ{oi*f6Zx@#K3Fzqo2U^7eD70h84q7r;`nqSfYt& z;zf390{KT>!#>k^LjVZ$&(8Od*?u!=#|od;?2OR1vm?IrrIRZ-?dx+RM4_=*&a_h| zvUehd-1&`3&sQs8E2~nR;8N@@{zRanxcLj!fu&`d;RywS-r=YA5OBCrej`dJ07^mq zcgD<-l!{ql+sKc`pnOXpnLMbTchD(YsXr&zZ$B+O&bN5Y^Ucd8^JE?Ax{z#@Fek_7 zz+Y0*g>b<=nyHGr5|sN_3q}&vwhee*7onoZ{s=v1@)nq(=f@jaG{!u%PvjN8I~T`$I7HBBI*~3>;9yIC6c>VRY}bMAf_3lN;RZR3 zMcd_h{bX>C=AI$im}T-(aK8BQYiwN~shu8txjbqYe{W{u8bdnL+H6gxqSsas`I5XE zrQN+i*VbZ&BEh8H0OG2+j|$-*BV%OYtF8*Uy?*f2ZBCa2v71T=zs* zVZ+wGP?O_yKJ&TbX`W;m_izJPhf-%_ue?yM#s5IV+2<>0nRuy%B6y>vy=F6O%lfy( zmbe9}6N-2zdW^?U2M%HjCAx?F(T4Iz&IlxlM1vKf{8)N{ZnYD5ar~9n*3qaD$>2CA z1ua&TR{Bfu`FVEleIM#ryA@4`Up1VfVR@@@ z+gX>77DWcrYG8YJXX=&{N^gruTN!VVOOy>Uk>Q-7;ObtFL9lX=WS%N;VeD?HK5mS^g|0Y^db_EO#5eP`Te8ad%3_xqF|6*NZ1y@zncwM)XL)&MsBPegCZ-I&L_L8etic}Kcx$6h+IL=^qFUdoEs%~n!%q(x z$gr+uc($fhF_5~>1a2lZo#bc* z@+zRU@Q(`!bfFqqwWHp%=?5-fAg^vI-NeuL%wibR@mQAQ)|h9i)vot1lI3PR_t{ZQ zm2+n*$UXid+Z_kI+1vLWo_rsn1eeB`v91^RrSMCN*QmR`qq!lzn zY%9Wyp1OsO&)Xh47Le^HSU;XA3CAheQ_^fu8RsV^aN5bpl)g-s1KtW$Ge)AyS~dXw zyAoE?O$BC)M&b3H?K1t&0iuy==+*bA3SD;ywT@@Vs)4m5J%#%9^9}|VQ5bveqLa=S z{j9LA;bxYS36xCJwvp&Bj?e8{4Bfa*!O9A#fQOfrq%NKQoT!?75v@mJF;xsRIe6n4 z3i|+!ZT#xGzo{8Wx*{E%mPN0lr9<4J0RZUw_!Ut93!m-kP?Dnv{U4l`&~IJ?&buAt zAxL_gi4)AhSiJ?&yf2`h9bG6L>{JF7jc)xq>O(!YAgDuha_e{_ziicbO1>}M2|OD~ zE@-@$#Y($_mQvAhpMd8YAK`GCi_ffxcrhV_+=IcUG!ST6MW|NN!(w`#7{jeAijAB9 zbjYbzsnea;WTO!g3VwtM6`z@0WRlkwRp-47fse1whPtnJ#Kd{8&kUyPgBZ3*z0?Hl zHzU!gha$o5rOr02ohdQn*_!ptYq2cdH&t!CEE{^5?|oSxjB0@B zR*W!{_jz{30=_f?=!!B+5-~g}&iw5bCp%xVhO9-_7pk+jNEvzv-DLiqWMONYv{tV4 zNq(GQUphxvR8}8r_y$)z`SzpVlF6=a1cP8-+8f3VJH18mE_R|xA5+?_Lg|t+NUVYy%5)bn! z1`~2|^1I7-bf+t_$04od_6r7U0mFDNi1}ftT~`-$CvCv2ZrqH|OS0SO6>aBk(Qu$j zgPJU_WLJb&Y5Z5TF3KZ$&Dn}Hrbahyb>C*e4mHhS^&T`W1?QFvDlexAU$Q7~rMY8K z)?xYOvgmR$?65U%^NpM#A}&(dg`Zi1(J2j(cJz-f?xhcm;JIgIh-esvoSd+Sb

    3 zxy46bkyr9xzR+D0XQLmk{Xb%fCVsE+f){FwV12SkPJQCSdh!l;bX4c}=5vYCXap__ z!Px6%(iUf$rKqZgiR`Qj?od|suxDq~5m-Q?B)du29V!!E6Tpk%Il-8ipjU%3sm(a_ zH?=xEFy)H@dY-2VTC5WKGdFUDr(2Ze#V-U6iC}4V?!sQ+w*;po}>mBbg~-wXyY6m*<7a*skX~N zOgMQ%Uuh|^&)8s>;QNr^c^lxyu?mbZ@*#q>@pY?qZ+tOC>?D8i*RBwlAX*rfLb}JVszPUAxSUH7MP!vdvNs3ZzsKz35XBxv zpC`0;Bd$53Xp-w}%rG8_2hmBVj@_)l^&a|0Y}psL=}ThVQv(!`UhLN7NwP12y@C1i zpdLdfb6&^!_ibus=*$clXyR#7Qav0y=?)C{+^_K`e{zzD-~Vd4h7dDU)~x?d7yot5 zjR~R-elWT-an%2Bbn+is$^Xq5A>LU29WVZK?Pl-~e?$&UpA7q7-}wC-9^(yxBYTyC zeq0uG-{s8f)9T5ZvGFU(GV^YEv@5}8G8i!WTv-QpEE~*RmwSnUX)~Rcc8+;%yzL7H zu~~u0lpaIG`~2lL*_eI!fgL{7W?SPQ`~Rv9iv#=7O`a+yi;Lkne_x)D20Bttx1*;r z+@rX9yn3@Ewia_6UUT3;viUz2NkN@`z~hOJ0i9+39OT%}Wfk@`zly(4L!m0t*7@>& z$9wg<2Z8&T2bz(8qga{yIRP$3XSRDmRIkCV!`vW>nFWeO%mp3S{Z!GZ^Ihjgd><7R z|89rbU4EJW?yMm7=ymmmbX8K*8+*x9Bb?%uEtpL|Ja|LN7l?1U-hy1r>CP6~QoBYE z|21;fc^R36gK+Lgza}~jr}c`|7l!5A)?$AznT|Bjhg{r0T?^@~MQjIcWB4^_MA|NA z#_q+Psh^A*>77!aXl4fsSjdY(Sdx^TUYIWcAk2SLNrOmW*rcMwD-XCBznT*03H$+r zWzxgRaqGYk{nQ*D+&GEX=;)D85}Z~yISHNhZ=tIee&~6ZM}KJnBCnelL}S_RIiem` zuE7T^=h$;~{`9_4g<1{Yqbb&Iw`FB1RNkB#L;(-kLZ44Ax4$MGRby? z#&Xb_XyWq1%uy0Ij3a$$(E*B_cF~|07w?yRzg%dZwfc62Og$%4PYbjw8Qb1woI5+w z3nq2soWJSz)(5Cm7PP&`U)Dmdw>}B^ya~Wo9mKl^q8reIni~J`?q9;4<2=y=FjI0m z<^v8F5mxQ;hVk7xHy`$-G6W=P5# zjkxV=8Zja~Ee5HjP){JFJFBAlE|VHGQ^jDES&1Lp3+Dz^1)a;pT4lzoQxlv7kHy=P zcK9Ez96|3DaX=Y*WuxLvlP+xAl9c zceoT0@0R`c0Uh4Nb8z^=P)*;yhwqxSut&)*n>l&i;mGMtjl@7qfw_Ul&cSLbPGTf* z%K^D4^q6B@x?#9L@sR=EAYZeOEd3~N>?QggYQj274c++ArWJKidUGjMYxNDuo6_U8 zNd3a6f5VaCpKBf**+m{`nb+Z%N72dZP4*>{*=5%|X=x}oKfoAo>d?d|{fALfv=8Xq zlL*`XJ~9hF0L)nLc#)MC-eF+KJvBeuV++h@yPY$SrW0K#e2wg&nZfk!8H-g7B%J`fHjQwAK0cRx=m`=_(G zgzg9Z`Hd6^4 z>v_iX#W7uA3gZjpuGeR;lpZQLedCAL=QvA){feKk!hoOquvX6cUqWvGP}Q>^pXmp& zg|xxCGtbk;;W*AxtMuZxEOA3L-4I>_-T2l*J1b7{tjqq}Y@<<}viOf3wZ3g}g zL#G-+4)--3v4b##3*`SVFtlm)t|cD%#+J`?#eQ_$s(g5H-5#RLPK}1u?ioec^A7RR z5a;u{NFppB_;yA<0JY~mqUM|%vB8O?pMa!ALKxPI@Jfp}CT;*oBH2bL4s{iJbMTGP z&d%soQ1UoHDJQmVJ=Q?C0L{H@H~k`Gh7SlI%soG+%|ErHoE@1OK2!Coh+#31v0QOb z+npi2zj|Ub)$UCyHP!{w9yv?Z51Gl?^Fzztbq4ea|W%ke?S3bU0I8@c!qMYPid77tMC9o*2= z`k^2LG*?|S)E0yx;U7h=KhkK6XeL$wpDDUvVmo-Mn<61vn$zPK{0TNv^$_goO7Qm% z??x~s-*Z!Cz#2{jXZ}>QAa+`2Bl_o+&mO0+vI`J;OZ1?&d1xjH@}w_^mXJMcsiJU# zcVRN%cYwnDavz`{2Nz{UI8(*(23R8$^l3KTiiE0_~Y6$6TMkJta2^hEm1 zJy701c*cAKhPcJ@La)xJ;zI_pEOrX@n?IVG7@jL{lpW84_n>#2;0G~0-m@^- zRmX3ujCqocz3J4XjNQktZAZj?(Z7+K_Jv_k!a3uv=9hZ47*@t^7h*!|(SjtgT>2UM z30Ge_&KPfHhXole&m*l z#4}GBgo~ApdMHz~pQM1-NM$*`3KY-JHN!^^F-{>~XDXTtoqCb-ZKH5+7XyP+V zn!!|F9jSYlUFDYs5OZgH#W`eBI$}=HZ_TfazaeeK;&Gv5PgI5>JUAT}J9{f2^60O2 z*9L27-u8e1ebjcS(T6xpNTo>}MNQtZC7&5pF>HPaCC~P&7+c+!7gu)8#1h)F`M${> zxUG~jn(2PVJ(0Tm;{Y@>%`fOB=BkN>g`Xv8GX63`3@+r$y=$FlPnb+1Nv*H+(2IhI z&qGV8XBME;z~RIM$;WCtT1&(r?X3klrC7&ICmmJ8!3^HtFIvh~vem!Y&Fnbxr_u7# zGdFj$%b+Fi*0afk;k#QaY*OpWitHzVFX(^@cmf793gN6Pz3!Mm70nA)_J%O%A&=6t zXV$f_5DQ&4TTsA_geb}Z(eoZ^j3b1;q9?KutUmPb4~dki-rhCn{h@miz@{0F+sqFx z%&r6(lkXBkZc7M|;4Wyk2AYjXcWe$Yog1jk$g5=8KL&As>GiIBK<=I?I@{1V$cSgR zO)2w>A#2UAEf>`33%>g7$~pbTSPXYq%!uk4k!Ma2fpP>8!#a?FuPGTI?7vR{&A{Kc zF=l&)(};+ty9R9H7dzunSwAYk0Tg-gv-?^*RecLa zT1viAnty&U?a~&K<^;yOGvG;KPhb8bk--<-cUXZZgRQ%-V-SrF2NxOniMbc)7ct&C zL2>-jtA9_t(A6owha&0?_Q~}{P_j=Q0@ZrA;~Q4XM|mrLm*NY1?W*(R(^->S1hRr6 zr?zDm%>$U!k}_H_=DFrT?q59j`QRU(n{NBa`wR)}>FpPo>{`cj%;OHw8oMptX2dw` z3|uuv>Lh=CkLsHGOaC$JQl4`;8)_P@W=rRn_cX0;nHXVThHs!T12<7TN+n(3#VJ#R zrQVI+5GfnZ;?Q2xhv(|RKerTMhy|hJ9kZcf)-3rXt}BG6=*Ty;j*8?Jz}-DW^`;Q^ zEAF6W;sG>~FEg@7P11QSN;D|I!`dk%$&fQ>NrAWbE7jE}vi5RT!|S*Ka$hNVmn~sX z-9kCgm)8idm1LtrR+vG|g}iNPxrCaW-qi!@GGuANr6_EyN3?pJtkVGIU7lQ_Z&$|8 zR{Pf{Ep24=g)Yw|(ntiCPHYZwRg&ua4XKD&hFF^6o9`AENk0s1wBUeHp@XvO>9SCo6`;#v8re-TgLsW2E zWinL_V#Q@VJF&7j0riMN?)wc?_Pw)J^I-0;YJC?X|A*4`-}&((PKz!K43ATC&({UH_kD%12Xx}yyLnFVl$@eibq-2_>O362#9p>_o0lgP$oS;Vk- zA`4lpOk%c@k|PooXkl$nU7ScD6ECYv;9N^ih8uvFrJh}0Ku^J^vBZ1PH=;wa?9=T_ zt`4)Qpa6Vn$o0d|QQ9E4dlK>K^5QD0y%{)uQa={3thNsMl8)g|sGOFXC!uE!1QyrX z6<#Yl8fq(d4p0d4F?mM`#$S&H2e_)wkfoC0qWI*2j5_Vh)EBL(uBpSC6Wd;&Fkri-TVd=XoCfL^d;4kn!g~Fyx)(Rj6yW=b+~3^E==@==n&^bJM7q zS%RM*q(=yMM@pnHm8jzbvWGorw3~FsWW1PB$D$8xdCg?!uoTW(;vFm-08TyZDpVD%R zG4DXiMv5_^L%_j$)fz_$X58Llr9idcmnljotb@|*Vf zoaXK5=@oPHj?EA=+M|hj<|LeQxb($y?H8_M-qOFZ?=2{ZQZ@dKj6Yexx4pRquqq)` zK8fv`%BqpCU=o966=ABpSX9~ETd1Jxu55J8OH}hySr5k8o_VL}P@Zq84Txqs#{O&7ec+Zmy42bWIG#R5vV9m;k3t;Qi;4np(h;N3n}SXA-fYj z5aDb=d|5=O{ghqdZf+r&`{tGHSy;{kG|GX!KXI(42$xr8AVMZG)TTIRCOyK-Uffm+ zeAMEUVm+EcH{-fH@699<9^3Hp^Bp2@#WBDWn=&^X1kQnVAS=H?Aqr|q<@rmy*b2>Z(DxUpsH#ExT#nHl1knHdr@GgHjW z%*@Qp%*@P*nHk&6Y`3vL&&-`W_rCYm`j+&oTT-`c&MuqMP%@#qrFh-zXWA`If#YirEW~tK(MJl#vJhuk@2LQ+6r}UwAGOS4 ziSNB5ArUNyW{V*u(^0*A|yLPL8W>kn*#s%jr3h)Spie^bpI+1`3QLpFJJ zB{^Q>^W1$t;YTX^S{2ciukz*X9b96p#6Ez-|}GlYm3ng`p?0 z$|>Y{uP7e3VfkQ1i`%@iphEuCV+^11GnM7$X z;lWlf{~}Y&e9#Ax-QlzTrVdh<=N0hz!Iq*+v}M~jqHTbGD8U4wNCCpoMEX(}tQrNn zZ#ObngAbS98;xMlL~az^N+`V%*m)w`jA#%?L<;`FJIh|m^C!!0+=h@BIQ1VayT9cB zk7b{O+Hs`~NcJMsd<_-@HoS9=^OrH(^c^79CM)Ki{pt*xO8{us)g;$B>Gc|R6|=lp zZbO}G$qic8E7ZW+fXM16Ihg&-o9)jW)F0Rap#bQ)ZU z(hZFRx~)Ely~);3rp{y>DAn#&f-=j8pMKkv2rRXg!YC>UD0(6l8u%^T+1%?>=X}O+U zP3M0LaD9`2o(z!h>(YEgQAnk27DF$$=J%J~E+m&o);@Sx3%JnQZxo$ByLZ@7!gO>; zsZLwnRxb6p4USz{=4DZ{wb;yaq+3oY+?p!YolhCdU50akUfI`d=mm#EG$4c#D7oIvP@AZ9wdENhl)amt?B)9+l0i90Xa>&2!naCqT_<~-^^ zOQ|PIdM^*U_x_UL!*ny%Elw0$I$Xc_y-wuOfDjNru7u;GW+rlUUDn#{>K7_F}R z4B2s)q4uqW-b=K(!*@63danNuO=v6gF$P-hM(l!tjJ^O_$*;P)z5V6_-Uw(t4JW$klE$n#4rn&^$-yO;Z^b2iGm{(H!GN%+;C1KI+ zWm9B{!If*js|zP@k-~U|$NFZFSoL1kN+^?iWatldS^*RkHuW}29k|3%|EH)D*uX^) z@iIy2HP?&Nw+{-#mHZc`U$26D2pqvmmmn{M8OtF*ygkG?4Z3C^N7ewxrqW!)^yh*0O|SF1)W>wXGxer_BnX zhdE@_wzi%-TV9y!LIm-$ABwL`>`g23h@d+N)QF%a*7(?S!Jy(Naez8aR_39R)PqZTobHHTN5& z6%VVCG|J7f;YI&VPCy9Rb;qH8CYHp3CEnAOda%->6 zd!rOCeX!kqJi^Y;r1f^f`5qouwPSzL2sp~pn=V4XKgqFf6VOS(sG9dx;QA7*x=X|A z&UFbJ`I9JdM;<&&Bi_G4-cV>`@-Em=i`QyxREcz{y(cjB13WL#14VQ~eutQ>Sa9Ot zzm&T6CDEqueVjDpiqNl-zei{L2e%pJOYx~0{ow1;=0>7Kxo9x`*xVwU`QDbYWp*w_ zd2i-BpGm>jrBo3zMT{LI@hG#3`6HF_%8ZrRgHe+_f!i+4gRuEgHu4jtj(nlDn+nNT zm5iWzny&OP3%t)c!UDnb6Kduii0mp$A9L~*lqD_Pys zm>!Qpgv!;b#T?P_vI1n|f!T*h@==4L+Dmv-gJE@0FQ)$^vtZEZugrofh1upt_++um z++-KW5nb1dPHh4p@ZM@%f?}Qm6o2!ZUGXSpMsaz#))R7e-}A$EBUX#5!N)8)7D^fn zJ-uHpHt!vIpK+|Pk2Ivu682zCerZe;5Z!+|=4)(yzyVjVCcdm95dI#dPWy9AGDZEm z@upGnJKP$>`g3nvZpH$9rlPtajXs_PF~LFu$At9pxU~#aQ^2GP{eAe{f3|ND~2}OjV zY7Ns^q}Y~^L)Nskn;Hdnv5l%S?r&2c171_mnJDF^d;AMs5(<&UHHerDY~SRTvOCJO zm~2!0aYd3WdeSpJqC%TP*#w2TRVmmrCDqiIClkI){VW7Xm+2Q}6bYL`mZCtSYRK0`w zrp8QvVD>)+%g2nkUI}@0v`tBG?;I~Eq< zL6G6T{UI_2KORBTk(_Pe;}N1qg-tRc|Cb#9LHFJ`Z|zi{dtCNa5+|NL@y^aCe`B$A zoD92fYli`BPYT-F3*6|w#mN67jUcVCf8u|n5vbMO>4+e`#Q&Zpmjn&nj1bdnX$|0y zUKN`1C^uil@EUoJc&`uT;1nZw7lQKbMXWf>$C$5KVua@hg0r0Bq~HJ8H$pWQYOw#k ztswnOx~TL0zj%M4tx&=qPC}VaMyx34AOH9E`QySz-EPSLeNAdG8QAylT=it@vHmYH zv}km`uJ3!=fjD9gijK;gJ!b{P7zOudlabJ&VGS8Rk|CaTqcKl+I1foo94TGpKQzn7 zPCYZTT9gZ%?_dVXx47{wFa8&#kfo2to%HGJ>kSz~$qiQsE(gKB6r4#OINFK4%8sh$ zSbTFnI7i)`Ib@H%klH6j!kk?nRmgy8RyU_D)|sPB;W^-FXJo$0Ou~R4nPgzLF3NF> z@D}>o&|CO#afj?F8=wn&KQ$HlGp!-T^cHqdsQ?~PMWV&mieiyqzapLf&;fKvY)T1= z_4nEiA9Z9fQusm!t0YF!lUF~(_0#jY+k7h6TnagTFK`k5kg(ghZt`y}v4ePttPX)+ zg*m&2&~i|*8sEFI?>s$na9b%$EJx^E5ox*9us9JYX+ZPKg^V0}$(mnk0>x#lI+7O! z&))1wNP8Q?=T(ch`|Vh|bkW=R21{{hYh0IV(&5ZP`{HGLlW*tuPq9{96vo4j4!kFS zOoc+dOy4c~fOLzhp{_vb;jpnkT3fi6xIXulb`<{r#E07fJ)nTDB}lEksT0N~zwABi zQk~_cEnZi|`0LF6a0h$#Bz(cGM(TFeQIOdX#gNc)?_83DUF zFX`h(|F)u`vXpb$Z8Y9lWSUmHZG~7~?!|6u3hL#D;6zV)spG5QBeHUfTdJ5Yx;89= z?2`9fDsphH>ZU8#7-H6me$>0U_(IGIH;!I*uFtCz&2rg!$YE@Z@ZWGa13rZ725;#H zs(o6C>>+qsW%}ah=qxlTpbcBJDK=N&Lfx3LFwZc(bI0Ck%)`!e$ltf@@N=69|82_n zB|?8VZSpIj0DsqK!G!RE6sqwF$o?2b)h|3uRM2#Pami7!>;#ekOHSQiOU2Crw6E!j zaiI}$*vzFR;Ba!mGZ|4V(j-siLl>K%U3cMWs-;Jf&Iv{nzajTF2Mb&kT4d6|ZWfKMbIb~piBGvtct zV0(OD^Kj~{RC>oG)s`Z%tks-`v#NzP*qwkE32G)U!^k0r3LNItMOY&wpW(Cp(gJr7 z#~S;4lXZ}8LXxC+MU*=Gm3g3#lpQ1G-PjQIY5?zAEMiYN^ zZ}>bau=Rd_!rx`D8XVj6poYE8-xMJXs?Gt1eWuoO`uJAIEvk?|1utM+IxW+keV{Gb zn`iVKMfDr-uFLJXrN+GlLu%rekLvDr`T~x2I~u8kw_^i0f8mjz>k+~Fhw_%L0yWut zc|`mr^3pBPCIyE+v`brrp44By zkcUJq}op2t1~{I}O{U++|?zt9Vu7J2W)>s<6W z4loL4zsj?5_8VG!j<*u9sk!|8W|SJm!*@0;c6=+kP^ge(K!Yp5&~OZ+CvHLiE+gH| zlq}HglpWK+qHNl>KA7Bzm#b=NG=)>{Xoqn29M)Yu(?Wh;>V8kprw3#8ir@C(YVm&6 z*KBu2ieyEhcPR4U3CitaaRFb_Svriu_Gt!O-PhWjx z*aYiO*(pBYeq)5UqD$0#93-mA=GU16ey?k_0G&2EbeSf{9x(#0m&lhsf^?kP ze=}qJ6Lu##LFYIjU3O3@0H%L`+knL~IeU{1Db382z$gHwI}B2bB();FK3q(X<*}RP%y^#mS~%ueN;JO< z6Xzbi9Nq1$GV?$axmqQ7qTyTX>(i=<{+`d*^seg7P0K~T?d5mj^<8LE=1$*)fl?{{ zuKfW^_%xClrpmLWczDB2J6oW7DtwnEq%wFoANMfgmi-;@KdTP zA0P{^eC|_{WDEqM`s%M~M&K>t>$!unw$$Wj{!l7PD9b4^dD?q$vff?w-1s}@F!6@7 zUtT@O-Ln%Qo9Z)053`FiuMGVmTIBCpyZ-gXke1F%V79soX_&;Dl40M~jz8^2g|Jrc zy*5#ZkJqJ43MwPUz3`Js8J#eAr)OZpeVi>lCS(9~-_U**YFTuM?<}FVDVZJK2k>L+ zva-qq`kBoJKjw(TbANm*2jWV-K}H92LC)_lH2$2g^hsle^Eaw83K%34y}@{^+jBb<`@T+^s1S#`6MaGjx5?) zsP}$d`~+{MP$E#)NE4RP@Q8V&Z|7j-oO5qw{s}Fz!})VVNfBQUHyPGt@xISk=AzCVe#D@_B=OG!me zaZdWl`vTman4=~BHFMzBqe!YCa-#yR!9S}{%2=rItnPT-J9x0ddb(JKpmsk!Bb~Wy zRxP#0P4&}C@P}CeKC>k-c63m{Yx)~0K2J@mR$%Hn349Q1Wk#O{GZP`^XT1ZBzV-D5 z2wZpqmg{Wl%B!3^4NVDp&(D_7yDB06VP*W_(2*qU(oFJrGuBp3XLSd7c>vh|uB#Rn-!n z7P7J*rmdhDp|3 z(tR^N4|G4MviA)KdmEa(%i43zy2-e3-Dfo3AA@Bayy=Q;68AEBYGD5;EE9H<+tC*_PR%P}Z=>4MuCk9*x^;@c^&?&|ZUyVuVKzU|LR6%?)w z7;hTWMWgJTZ1#9~j22){EMYarjjjcvu*Vz+l)=5!c36?TTu(|R+`HnAmObsx#GqYm zR`0N37&E&R;e8zib4+jOjiIcHL7pT!Z9>b`Q?7`0F6I2FdOZ?mchVT*X3EJYa}w!r4qy9D`Udl< z&!M0Ue))OA2G=oOPhx#m#+mNTExIc%`4zTLj?8cY-peZW^G{?O`ZGl>)%Pai z4j)FG6K2A6NHW*r4q*(=nO|<9&=tJ9U}^ypcTQEV#7e&ptb18nFJ`pbxz40cDA&fC z=)M>ZZe{Os3h`w4U3R1b*J%B#xX?i&+wRG5w(FKnzC6^O(Tz9C`>idqK^{%6Qj*eZ z#eq;n>%p?WD>g?}_=E8o07I*myQ^~bC;vT=GyJNOa_FI)=03VQ)^j!@Aw)&lI}%(# zeQO+EYfyyD=FI_F7`MG5hBYHs1(h;R`MBOoD1Uv=_K8nM_sK^$g_d~+)a4_`B?(kj zU(Bh|-i;^mM0)vcjY;9WyN^We(i+_)F_WpRiII^ehe|kyhAFc!HeJ>ig)Le51`!>-Dg{~1?L%D2$ei%)4kt#vXd@n z*OP7W53yPVO7SzP5s5-CPL9vK(awDm#9X~3H^v?}A_^~g3*8NLw!l-NxpMOkL0D(+ zp6YDgXlvT?dA^jl(#?P5O3Bm$)hUu+VC-v-~v-1)f+ex!Ffh}8-g6%nK<|VEFx``?LnZwlFVL z#?*imL6 zcoS!)&`djG_~w6R9R7~j9{8zKHa~0=A1rTrUO}y|1NJZByQzI8ftfwf?** zY|q8IQZvU#b`g3w&4;WO?6$qNSvWwW^I%gf38iiRMw#Jt671|SZ&xRd?m0Ulo*jjuxBk7s1Sk&*DEcXn@cf+)^?)16*=ma9LRdT6vDRzbJF%w(pnKQGJ=Pv#0eZ z95(yKDtS(w?rL!X$@mY@CeSuuef;DepE6GJ#Pru4TezIPhEkaVCkOiuV|DPnuLdY< zdsdEEz1}F2y=@1v#!R`AwgX2AwhFf;zUV(3qClgrp`wV)%W(j#9GG}Xidf`m0-ducPmG(p?5BkLZks`={gf{jA^!si7Yv5N>|2g{oH2!JA9%#{NOfokyu=h9M-}|872QtDzJozOZycAF+{WI6$w^)Ds)?*pMTcR6f}$GIG@J_U3V& z(5{sEVctUL+LX#*Uf5La;a!VeoRv&M!15;la6icnbfS5bM>Gt~@m3EAFb|^dZv8A7OaY66>*^Kx>7)75KE8182X^^!_b5I6Be};lV06#zG*YuW`h@Z z$7pQGPc7Dk>l-Q;sD&)57*%66d3vKeEsxOpx7nMQQP_2TCte*~)KGZnDudptP;km< zVr(+!*Qrf16-o#qi%@H;mD;k4oHw;b>)?1aO_GA&?Wu`Ul^bDcUF_XYZURZjlrPd_ zm_d`T+QSV8G!*p_pG1BBwTJP3%qLL=ZHx-09?OJjzgAr=Pv;*vm?o2AV)H;rbx`H2 z|8`TY{h?WAV=wf3cUG0jjkXKvg3sTZP7?ct@r9Y91(Hs2Mzg0)H+CsMMTMIH-Cu5e zWb6J+(WI}_#@m{DBMPLvnI)IEidx~l4gWcaj+L@06^YIl`#~N8*F!(OR<#Fe%vuLd zZLd7nsFjNycxTCMwI3eF9x2v4dzF6Lt?}WjGQ1G@(Pyh%Zc0)-;b^(ArdLS)jTEO6 zmmAXaK9oWp>ULjA|Bs)L_q7 zG(=sf_CDMsVs;MoEGBu$-Wn8mT(Pa(ntx;nxWvzn=-lqFRnHpc$n)-tkOHOMeK!zw zpR*O~^_;#5OS@6UVZ>@jyV5^A5)dtYJjeltY`USRyL|%R98PzZj}VyKFg&z5_XI-H zF;p8v|NZuTfJXfY79_!1MJKv_vXRV67n;BTY zpQb{Z0ld}KUqa&U&$Nkn_NWbrSw){!g3Js#D>ul;t&3+7qBg${ettZ3#1XDab`pX- zx~V&jYYJ+bqLwwgDE~F;^+_^8Z@6*xwBb(OD@ZF8hDQ(cJIU+0>d5F>i zQdo>&D3Yat#V)nsMoUQh5|6p2zDrxm+vWw{bk%Q~Q@E~sJ+Cm+HvjfXz58aC4-I7I zfJYhFrMWtl6|;$(8P&KvirDD_Z`t%^Up0A`yHPOh&(SRyrE z{lh^Wq8#D%Zzd=~civs=(lOd#PO@1E(GuFI>qXk95*1j5IClJ&%>{O+CIJt}oy z;sfMZlH)Ccs3;O|5fi`dsJk6|)@_S3VTgUGyg2oDlAHW?vQWbuKeEhEUvv$C>87be$|*%xFm*aSaexjQz0KaBpOc%ag-;I-8faKxO(NmHdU1PXPnbUD zdY3;s?`HS|i0>3KI#T`8@<2u!3#Jv=mz11RqV(l@AOB-ULVyWN)Y#$j*2_`HuRzUV zwIbFhMGZAuQzQ{V6AgxCf4@NTs1KdsWgz5M=%?y zl+fBeI~)77gh_4j_DNphA}=nyWW4_xhm49-UfP;RGuGaMtomWm3T@=a)35>S`v^sA zBh2AJ!K5!5AqWMepmw&J;rV4S*=#3AGuXyneG+dn%nxsCs(8IP^)0v&L8OxDqqb0^ zWkKxvs@%JYW|@4uE~4%f>D5p2P1rJ$2CRbZI1Jt4}(W}>avt2X%~7LJC^CW zuR9~aT;;8&6jnvxC1u4O(-jSbi%y_dw|{i*dvaaJZ}o4R_DyySY8N+7<8&dLYNH>- z3M(KAO(?yFlCvJ?Q@2N@nsCu*LVxVpj_A*Zzc|m988IQ#b~KaPe5q1KMY)uss3}0g zd~p~A(HZpfK_Ygk$%1+TPA+4*d8tfnJ9V@rQGKOgD#`+2S&&?2MokX?$+O&Ty8^&} zdAni~p++?@&`G*(Bt0|%fi}g#y^)iA8c?@^2KV@0)6zn_$W71A&pY}nyF-#`B<+O< zig#hFdUiwUkw%l5cG}{bVHuE2{kYzO{MeHR5*)=2K!&W9RoBQcJyKMns+upkI!+DSr#H5+bIa-@^u_izhTthqgR*cS?q)2xt8F46QT#zdH$ zw#2dY(WN&vf5eHUdPbFtl2{Kz7YnPduZLx9J-;gTIu|g|@#wI4QW;5w->mVmfCOKF zD&j*~<6%J4ZE%FaJA8jS>~(n_0beok$_>FaYV+@#@P9mT7PH>HQ-=KDFXURM=$$a- zBFzfu3{w9%G(tf>+c2X0avt98I735~1M{=qfFcD`;6izTz4?!;R6Ve->oPqLVi$mQ zj(D5f3rV1h1UsW8JTEe23PZ5=uwROriNiknn)y@D>kv!E)959zm}gtza;Xdp`12|o z__&7G^1L9BSwM_wvt>?GGjJ=p{))K_l$H)3iUmSliOvwvpSg3ThCSo&zi~i)d1f0} zUC@7)3I-mJ8fXfy2C5z?KV*cAeAoXt~p=As=J6zo2&SWBw#FQwneT2icPw?5x=(Ywx}BX5$lvQB z6@6tGnWNFt&Vp*R3OSg}Mt2>2hR6gApMa z{JxU$@U*j*gINBcuw+(dnY?i+*5(J7O~8zSB2m5KA0tvBz}-QujPZd3lM2>VQuRF5A6xMmp#0nM_05yc z0ZQ}l#v&QlrW@mLr2_Ks3!}q8<6u+A2jI%pWjvIaOEUjH8X%S9BEui{uvF{(&sz8H z%ggRUk!QOq?Pe7B|JUdIU_#;V-o21{$05x>hT$!K9HACzY)mU6BIDQrb{?SHnKBlV5F*VAeGz4Nc|H z8O=Xnn+}8@jJR)&9B+rbNm~ywKwm`#EpAwVCxhHER#|+Ztn3i3G`egfEJai)L_r2! z^^keCted0dKPqp~>cB;Kg1wWd*&?EepHvhrP?O&vBlzbOynl{_c^>cDqYxY~kbnPY zk|{&8-@}NWh%McF%RwD)fO|gQ&wKjm2uZ{%XRI9q2H`)N+y?Z~UFkKp*yhtSQp46u z7voIcgh8MF zCR$Okws-M&C;m#vm1zZTc1KgXN~e`VjqQ;Q@mZQyKfSXObrP*sm{6@bB9}RP7Go$4 zaUi!5zA9)h8J+cNJU`i~#5Gx9-VWah3MN)_AehCU224YvT#w_Q$8z|`t%L+qF)w-x zstQJQeUyNvFh%*?-SJyKv8f`iJiuY+p(f@|{zgkQDltlQ zVoO-{hI&ai<*d`2Z~)vBy7d47TimGizVGd(H$8fU2Rz6sCGz#raY?beiXiLh2G*;c zsETx7S0Nn1oRn_<)Cah9zrqM(bdRwRYs#qHH!_ z_T(6j=-ndJEllKfyj3JOm|NW0z@=5Z=jYoY0h!MD!@ITNu-Cr2sz4wel*Vmft|W<} zxd&ZkR>)6Ry}NTx=FMiP?F&4G+99)luM;APJ|3SAQe;j{XNJ>@BqryrzBZc8i$9y5 zn=d#$UtbLdAV&^KlFF7}Wg^|#apb>O`oV)67z;f{Z*Wn2QSXbl$dSf>O4h+?J!t zyjw5HhUsQ6KF5YrUn`Bksp1m{rbSF{0r6&HC&F#_wXlIF^X@z$z2!ko@I;{jMxwK3Jw#Bjf2@TJ{`_~f^PL-kiDgoL3g zbuvJCylc0h_rsZXu0Brf_myr&MXFiTJ7H5VE-eE8oo3P6@4Rm7L9r)=TGQX3JP3%) zH3{e}qkdV9=9e>DC;sl5u?$0H`@M!?eifU3b;ji#dApIZ9i(czwWPW?%6ePNFAQ)BI5pu-Ix*cQSaDp>?Ilz=bW9+VjWvV5KnXWm%V0T?%iQBvU z`*pl$i*h}~=hl-jW!#QPgvrxR;zQJ(#cV1B~V1c7h2-z=zHzfH?vhR+pt z@{5!58aTjV&pqO)`pljGdPOp+=yRXSK%WinURd44Vr}n8t(o@f?|P2kXjx(4yajkY zlNfDzf)mWvJNOwI%W}B%=Y3WOA3iC)U=W;7lqVx-%fu&roNb3;oPlkq)4XQjUC+Dp zrdhxIz5j&CSb!flsuJApj=phv$Ea-axHh#MjjlH)(snvJeG*G3eGECSASn(P2QO24 zr_=5hBFiwm$!nN^PLBto zM6MohJZT446rMZIr_XILngrz$b)}{)dldL4Ill!1<@YMwTAlY*4%-_FOT6h(5X+-> z^8f=g(}#{8p8y*Y{P_W5DIF(%o-3ivvD#&2wG|3BL;B;1iF@o@11t$nQp z#rLJUE6-xPersz5RtLZ&JO+aDG%o!~AHr8pDLaL=e+Q>T34{43S|2k!a)A@bY*U`c-@>V1IOp2d+-ySp7zjUhGk0)D>QCs%F$NFr18pi%w`EHs1L`HWL3BfoQUmR zyNHZ0!=Z%~8|;k>ee$@0ZH)%QSmiZd>M@OGTq87>jRK=ZA(+`H(vjEPyw30zKO`k# zlg3j0m&5fCp9fvPy}F|_0h$ie&?J0<;5?RpK^!#}%hK*7$)#re<|AN=kD_6(fhBrH zC#rpxq=u{O5S*^))rYjHvJjAzoA@s1!Q;8pLfdtJ(SHG8nBW+FHFzzH^xRJL{0NcC zwhhqwB10+7;c&K$x>t9e&O)L+qHhaQz|padhEjfd3)Kc}LvSD{)%?s5`u9|iX8$<2 zExJu)3%KMf!LI|0eN)+1>`;hSV z+HLLVkQY_MK`Ex}c0Ay`8_4i7S*9*CNg5wsG}s1i4rIbvBPTn^j1%}ff2mTxoKVwp zDfxR>DptUUvRq4f4V=6rAk@^pu$kD;myC2pxY#A>MnWH~sIg59ktwSB_AEk=mQ9KHD2^pM+L=Ex3`gzw8N+dFut3`q zEx%%@EDl+lMoQr<=ACcz#i$KJ?lIH0cr%C@i_b-`%tC7bl6xKoHZQBrB5@9+cL;v( zmW9SNp%a+xxH}zC-%^x_Fdcl@X8YSg;;$tn%qFJs$Zq>6f3czUO+secY^p81sj4%P z%z`72?{4*>c7^x&QR9}%;Zd_R7^mRLSF6BFOI_Vi-4UQ?YUMFLtsil2 zs_lx$h2vp=79ENJ!O5%M?JfZ@j8%T@L-LS(O3)#VnzLRlY-ZltQ%-uWzDnl2JECzk z(=*JrLNAFlpDzwx4v7ZC+x#)M9;+{^p$v%Mv3Bhy#jw+THxXevu$KtF`S72AB&YJV zEsQm7(jTomD%{+;%#@)dixG@5b9>EKL;^4hTA#Lw2+n8M$S}bpKK?5NP2RyEOP>5Q z)Q2K&H8a7WWpB;KY6bkt>EaOjY+C^U-xY;v=#o%bnxWp+4;7Hi8J2|vZ59`8#Pi6V zwlksqPE!08_D976y9Tp=JY{72+b#GzR6uS67I;me3bA3%`X4;NA5-{J_TB%#maVCm z`>%6cnBQrSYm+E0_y2&|@5dtqzJm({2re9wzc2j<58*2k&%d4OWAcK;=nS1is~J*w zqOA8LT*RLL^tkaS3;ijL1NATClu*{93iU8KUYO_si8pN=hEH1N;dO1kQ0MdVa*t5o z!d*e55gC40Aln}HeKy`fjSDjBaG|w6Olr+GR3s9S9T4X;TZ{P046{7wQqSN^LaR-d!F<%uOwAhL?aK1AFeeBluckgaH;zAcb^Y7m_ zv|2EwBCPsjBcA(yLalxYC=XsMA=P=nQeI?+ zl#IeKRXI+zg7^(y?rEEh|G*IOh~0ZQf&2_I=s|C*NCd8UfoXe`{q2IALuBc-$0Um$Kj8bJ@Bt*(;=2M zFzLir`41IZPUNxyf8P_CZy(b~xy#C3N}~1K?H)i+xza1D2k%$Zb|#0u-YXmi&>Zi} z!G!M=8o`%7lA1{YOvsS`4JN6s5eCKf!_^3o3$Bey2;lQw2b=q6#WVoXa}Yj z8{P7wjzQfy@LMtOTeILmLN!I*KI8}oW6|ciQT6wSvZEHSNi?Mn(5oTEXJiR|waQdWrIqZJI43bq3TU+=(?l5;f-TiZ+`Q)cp5kN23;SYNMX&Uk_$ zruy&~F#vmQ#Z)8$%&g2%1AGevq28V>bBxs%`bfUsjP5OFqw0mmf3Oab?9V4Wyjbr2 z!8qBkXc9_8or)hJHy zwE`~H0+rb8%6!+pnPO?`8vb(tmfo+Djc@tr*=AP{?_lO|?;x~pzWn1T;L@+$_N9DK zWGdjO-$)>vqC zBoUUzF$fWHyb(C&zuX-X(XG`e?rcz4UxUO>7Nioh?39-XS|wK=tA1$j(7|CZsa01S zdG`e2%>*Oy++H7|lUQmouEZn{6aCCX<&xgcPprkN;TDFulLeCQ`uz(PxWf@IO0?(s z-#+$UaTQp85yp9%qfuYMVtX%JJM61a+B*~00+r8b=-~iMKpg5W^C_Emrh%a|Vt4MT zct2a6XAQj26$ho@L9bY>QZwSY>ULU>lTdu6**&o80tu(!l}ezo%UQisE^SlVSik#7$5>4H-cU?Ks5=cp{LB;0bvY>#STgNcg8F1<*`E^PvW`2wKyFRtg(FDI zcS`GE@w9L9!fkn0{kA%cChS7kFy$`>vIZ=tnT?7&~IMN@?}i_H8`Qm z1%Caj+ln8;-z37;rQJ!s7BBq^WPAdT`4`5xV=Her(Ci~a3coXcuKg3-?5R$9NzeiN zh9x$NY5oFIC4T{_hyaUwnQ^|xr_-d45mBJi81o$!zHnA(1m@0eda{Ej-xHU#c2`~^ zyB#f(+BI;M!K==%^35D>f2W)H;QUX1=c;d8=4x3D#h(?hGjl&5^7@jYoU6-k?tq9< z@=nDpV9ADWo*HEgDv>lm_XqjzUB2a9wH{l#ljbBV075D~!r&E-edVHMDQ$zn(q>bP9o2*09 zPl}^wIDs|u3DtEvWwo-j3A<9?OSD>gT#=T%iW^4@*^QCQw@;^sZ+OBWbl(LPG*T_| zoG{fDJ5h@AlBD>udy;tY@&<6=;}4Yt`qa-WCVd4$LQQ|bmlRx!Q1HzBMQ}$*PQB$M zQX250@)xF=F%5f0Grz36$pfN-^Oy5_Qgnd42F#y~|G>|H<@B4;xjcMyoc3XnYW!cu$3~L$1<#1TSXP+&J(7%h$shw6^t~^(E_tCU6LZ zTkbM-okkHbVBI=A^xRR0YuCj5Z3B6HGX(1LX62%*RJrT1yl`;!8k)2k!2w%fAbcU4 zL+aH$|NN_C5O2@K@hd~sib_g46ZG$n(C!({N`i!CbDiZjcEr+)oxu1J@K}TQ=u}ln zLLFVE3(iqt8TKg5bC*)5jk4*cY9F`rKBHA(5-Z)LL}=ZggLKe9*Sc4L`<$74WnTfQ zZeF}7tUsn6i~0a?Naw)f!cgQtxO5SaU*U(P zB~Am-*v3vM?kkhOUTt63s$%4|0E{mIy~Xcik=?x%SReFQuplzd(~tJOJ);RpXM%)> zD9Hf3if}`AY{CwOj}}d~+>h&x`D&gPL@xNRfasu)&+pcUzUlXVU^!YaddE@h{m&C= zDmI3aPx9SZSK$z-KqWy@nBFA4)k38U1 z5}(V*-VjGG%nttRDc?J|iuF`7Kk)9$PQylg=-qXzUw$Wg=8o;pq-fDjG5OqSoHA-* zPKqIxsj8CAky7v^?8FvKJ(%?&t5OF1=7EUMLEeQ1r^^{Uk1>`Fmq=8Tb=420gVl)E zTW*kiGz69DOYi(th`9`*ZiQ{fs1d=4k%$K_-z7`e+X}EAbWk5i|XmmVu66EQ9+7IWM40I0K^O9xV=i zM&AeIC}LQ5^FhCP6QDhO7#q~Hy_eP2BTA*MjX@Yt{|lbMQ=C5_wgRWnF16YruEwKw z1{z@#N{KfhZC;rI#$NbWAKCO)w)bb)93X#+Bz-+RWVA?|!SgISdFN2bERfBHJN+vq zCbkajowv?45FF#8a=O_sW7$}qe`Arz(lMfc0das)2zU#Xt1o7u`#rC`dZbKkz{c znzNGWb{fq^YYRF^XnfMHM3s<83HxM95+vCBdVY?NdDMO{748IwJ!47dg-zzj#Z;}32^QtCB}YP>(zeQg z%dX+{fb#~VN$91qx_Y45{fTq;rEaRNR^3??M8g6=Z`QOL53K-av#4$kr&j9A3f>!7 zzD+;N7AanRYP*^39kXciUTY4cb8;Dsv{f%KS5$Xhbe@a@bX>_%`Xx)TO#v$RlheGQ z6^NWWsjW{*WhE6Am|Q@Sld--9PHRl~NLLVFYR&pC*HCOe{6vt_>w7$19~ED9`%i!n z-m9a5gyKf+CFSFLhWHad3x0GLGe5>men~~*4V#gRJWQL>*lx=_?ABL0z5#KT5b1BL z=+x=3q(u{h& zh54zG_tz!;GZkGY02ouu?+HhKW7pn6<|D6z@}(dW{Ubm9;Wgm!c_Je~cxC^KB>Mw} zvj;@UXUGKoB_8~l6npvr(%Vgf@1Os(({u?y6nlZ_e^YdT&sGRP65KeTKMek}(`i69 zoH-hZ^tb5q=Lfit?T~>!+>*(oa^$~305_g`)OSFrZ407}mqK`8OVzjJ2*tW5%l z!um<%Kj+UJ2uQWzfQ1?Uv(rOB6lp`g-`PC^APB^D(C)7U#{cpsf9{t%1rX&h^xp>B z&v^fzZuE5N#RC?DkB8Ckl9Q9|dVWw;mg4bUKfWxwo}CYzU(p&dvow6Tx&#_ldGf0* zUz-=2mYxRTd7D)HM$*)Jc3+TRR84cpKyxZ6*DS$h)cN^7$hnL7n#RKq)7qtm-^NWn z!fdUY2(Uq1@Z&+|YC2WjnDZrFH~f~*6NCpo4Cwt+e;fSs(|P{08}0F(SS0rbf!1dr z7LQHP(DmsysUyuFAw?1BVd9l55N)4eUf3IT zYSx3k<#W+-KmLX{1evv_d5XWxRquha@Y2<9Z6K76fbcyJnV5^rubratKjN1ZCFD6> zbB~SE!q0+)fBs05fAX}+TRdgIjRWaQNb8{4N^lfx{J#xheo=sX%+FSBAN99!07dkt z<36OVpZ9wdtDjM#!6b|H_vC67?j0Mj5rvQ2gyu0}dVF+fxR_ zr2HPG^JkP!7V7KZ-v*yxBEXOoyi;B&`+F4TpHZ0m{4{NhqYO0Od`8rwSSew{cA`QlPmu)^#fmS0LlLai}Eu=Hq4X(WGqAz*}@cVWmGF*w77pa$1r(|JU0WvboF+vH!XQHPtv}nBq@|}%M8L3&XKXgrB-QxgC ze4jxVl8=X9B{{pj%7`(MIp|T;P9O#w;#Qu3&N7Y1=Jx1&FZd?wE*Z%9O-3&C{D0SQQJ+I#q)!2b=LnD zERQCN;Xm>&W`&DForc^}n2hS0_v;-iRIhz>tuShK>JxyIssau(d?`z7pA z{iM3BOGB(_BUcoE?K>wHoV7C4Qtnuxj_)w_G_{j(?1`7X)mIDbLicih8? zD!7RFG2Ml9V;w}8-kZjh_>AghYv#9Dc4djwy?yd*oJ#@WOy}qVGxv*=@WH8}(KN3D zN$ykxJnvVxqAHkN0gJ9*F$-P;L>{)yzK?Yf^7*@I04Vk!S#gzt4o=!7E~BgAZUeu$ zyE&EUpP@|)0_Z`lbYkz|Vq!8Bu2)|Lvo0>jakeyOmNJE~W!+3ev&uH`^EOuvOzr=M zYKOIbwrV$hbREJp&4$%oI=FhD{K4GCv6z!f>&3y?mJi+yZzVIkL{#AD>PsVB43B1M z$(Zgo{f9Cm&22~W;~*auk=;;ca97j?O7=lJe0s2_IW4z2+9^-QCkNFU z(K+d{(Ua78?G$xVmcA|!cJehQLnT3?h)LvX>0t5w|A=}+dHf|GI^lp2i&Si(z=-!M zoJHi=+;JPP_JSU?%p0RUt0ej_Z#e)moqX`^FA?%F^Tqzi5$p2f4&~@$mN*6@3}wI_MA%%~0~1nZWTeKqUqqbi zuvujgC*fLicGINwwPSL#D?f$Rw%W(a?bnBZEZu=M#6+!n(ss{1jc<{iB1oO|FvgIU2xfZU|0LBnnP@SH7BPy^5 zfYfifz-_qZ##y6ZF8;(`DHyl<=0gI0$X=cGvq1C+9_BGSF@SyPdDX4ePw6cLD$AVm z1+5}S`zIst2O!nZTpNJW!QRbXG*2eOYwju=iF)T9LJ32Yb%5}OY=83= zwIX+~&n_f!v6E69)|W~XvWvI$GwIefI?^?3>A9WEejaZ7SzHqa6yMV)LqN$I3*=ns zvzIJpY4ELS;H|8ckmXQ%Y?O$Yq~M{hF2dDwl#qBsh{z@ES@4c3i;c;ego0f*&LUoE zKTB=Y+>>b?V5yZCUHT*h2yekMh(kC~zmfk*FOK#L{1&Ux=v<6v&o#Dg%C zI_nkMtB5^6m?^{!^(KA$iS9SudrI4`S&?q#8-bdkO(_SrG<{y_vm+La`0rEhgpKSm zQ?KIBF}o(VGJlJBnBFTi{F_}nx)s!X);-;c_=A@Wan=;_cg(u_6(+0~jFY1BU(k>t zy#J6CtqHz4n}6;tM%CHWh_YZH(cSZg+Q-4O92a%qQ9cXyceRj}VWg4epkwK16GX%@ z(RWRj2XvsMT0^R|Kk@LzDon1~XD82{+xxxm_f`d-DyYjBd4AAN@a0Wrf6vj<-wHA+V!XRP z37G^hbv&QCoM=p%y&LB4t|9qOJFB!Rv>>zlEO{@hHgKT5!@T+i*^Qgz4hP7~Le z>k~Wbu@~7ZNh}3M~8br@kzckG__#_CWjjLfqvb-yb?!a zN@bw&zvengo;?%pY=Tri=0?PPK?njiiJb>FY#<-2w8qXh&Y+(`}ylOd#vOu3R zbt;}Om7fpfU;)m{X4ZO4<7n{h-oL~#gp)X-X8));n4^qaUvZuj=8KPAM24Y@XK5?$ zI?lPL?xAL`BzdE~ku_1>pM*WytIw*SXIi`6i2kMB=?N8(jBf7zL11Js{Z9mjs12X= ztzW9rS_{SKn*$=#GQ0GVFqht`dVX0P^5jYl^EXEh#%{4L#E$VlwZjrTF)Xqoy-i-l zcE=O6ZYH*HWN*_1)|+)(fPkqN5rOq@e*8Ev4d?Cuf)%$tR(h(Ttlk=wypbYHCxPK{?-2N z)<`*z@-%JLThg5|&Um~LI<*jd`O!MyL41~{*u&nt}qH_sDlV(}#>nzN|N{}P)#w@3)G3qP%MAzkR2 z=#FXixQO)ogF-QQ<#v^m7jxdy89-l=PW;l!NH2e8QvDxLezD=+dSXlApT;TQmAG?i z-4rHnVPz8i>epU^34lZ@;&Q+0?4OwrAj3WPgk(M?Q-YtjW)%D_PbHMP{t0_u_lDyA z&5Znf#BfIv0TQ)HTvk?z-+s>@0f^6UIlNEzdtR#yjHbyKU$)Bplp(w|>5N=jXSp@5 z9EI*}^h~FCBwjHkD*8#?$<1qlRgzedlep z$3dLHJ87Bs84daj$y&^`p-$%e>wv2vJl~dCYn-B=${vLtM7T5D8>O-ZM%waS?!L+I zbhvJ0(!Erjz`wMxa*_55MQ#A$wo07dj0=QH>h9bF7SU@yv`_L56Aef*Zu<;)uVjfNx7z-d zfqgjnH?5aAO|1FuIcbZer3>nS!X5VEA*z_|kDQbRL;C+WpzyxdH1#!wKauc$@SnJb zx@M_l^E9HDc(~4zq2LWaJblJt8c1>h!F}$+I>m|yzK^E!nt|xd^NZC@KV}lWQ|a}Q zk7J_C7N^Xx*mB!FGN)sa|N15B@F9-;Irrlk7Y4KdXMhLOaId={OR8?(|B(c*%~g*2 zhiY%nl4!3$M)=AwG&4g!TuRDXG~`~2a&ObT;`$7D}ov1b+)sko{JOsNXEWL;f28n zRjKfAx}#nmFYP{^HtPcNpUfj2(H7+FVqhMd6Q_s7Vc zs!6g9oVA);3Yj-4T!ba_?e_li|78R?^)g-B>{NCHlXzTe(F&i*OkvFJ)bd>A$?FiB zNEbWh+?U|c$lX>GjX9fMEHZ5~HlH#t>B#_VU05f!#|b*u&}r#UW=}VfxnT$TrP#F6 z!MJ%wU2sV(&){bBAKWk|y0ofPqpR%)jND#F?v;$ig!$W^yK-RZx^8YNapm7^HYCF} zbJqanp~~Au(bzxfi!YdIe~}iVk}QUI8LHLQ3>ML=Z?V!B4|r*@HO#ED#q6;w1{C699JffD==@mVGO zCqTDO`FhS`B`TPEhrEBMpxONTc(gycXAjC~ZZzR8j3^*{sjTk8WDQ>D(y|oa!fjo9 zJ4H4hC6Bzxy>M!N=Z&$VyvLA4OJxw!kXi?hHTPq8$00hp*##`8;sSlcPNGza3+qx8u#Lh+OHCjTBj0;^+OLv`TBPZYu| z;x#-fuFOb3JXw@47H92sV_)gg(U(|l_6RSn3ewP&3z{xtcD7C9G1~fNL$-b|8$H0* zJ(hpR#&r!JJ#6iH@#DTS?~~X+(w?VSyK9)Jdwrk_cXFv~g!EgD8@!N4Qvc*M_kFMu zMtGK*^y~vGBlEq|m$6+!#c$+r_un1facS-cBe6_1hq+i;=nGo6*F!g@fFQ_SXu8(3 zm3_u*PW{OzIHKxhV;boaS+Cp!8zVhHZL6M7tdcl_?#8{ zq0Ky6e(k9@`bygyp%zL7XRJlH(o>;2@-B z(a>%r?q2Ci(H(Fa7C2e~1zJ1x3iTDIZSkaQmOa0`F@Ri)0%`;2gu?$Iy4VOos2Q8m zW4yl9hk(OMp=lr&6V>xVwu&m>bBu&=$1r_&(K(Pz!J)&0cFU=!j*U436?H>23wG?=+k37rF1k1uH7y`?PUOGdrAz+0epw>g@!04Kl z6WIEUC|$afP;Aw{gY)VC3~rNjU$S(e7XMG!cCQ58-_QQ@eB^!>Ce3_iy&!0Y(E(y= zKwV~;1Z+iPlW>Di)z4YCOaeJ$i9?8n-%Qq0!a#NmWf;~DYEO&vRuF|?C|q|b4T~?# zo3)N{Fq1?{O*x8Sh6UAvbuW2w8k%0oVz>>o>&bW}*~i{JU)e17h_MuqBm`t+A0pdb zt=mkDZg*=u;kVSD(0Z!fkzkO$&}+i0%i|x<$R5eBTf8b zcl>TN#ypU0kR>p%EYA{Wu4nGm?OvU|m&LFltyr_Bf~L8WCY|7l_%Dk;;4h26Dt8+? zEB2PF<^uIDP%GywZJ!8FdsWR z8-#6*BGhI;neW*mRiLE<4oRtgx>yQ;(0s+@F>qg}-OFh*wLU*}HVaJf|1`(2zD2ch zzMbGtV%`AO-e%9s?(te}Bx}tT+)woXB&@CL3f?vnh`FyK>+?ip+L0$FKAbp%M>IM1 z$?OoyhYN09msY`(>|!;HAEZR=V~>1&G8G*M8`U-mzgv)F95KP}ytUeSv6o>H@ds+X zAPG4&b?mmBFO24DA&miV+yiTU{dgE#+UKpt6pM8!2f>}(;WYCJC; zZzLJSckS=FXOFk1Yk2j!+ab76i;H6aJ4v~-c#>O$mGeIFaIWMr141+ao7C@5#f4wo!X~+K9?0lq#i9G{S;3GqjqFP%R3rL++La+^r$LASwnFJplI zRYUTpOC`1br(@ncXZEYe?k^u{Jp*AKbUQ=KFzfHO|M}tE2w*I2PvAJ-CjKL112(~f z0=PDKP!5d$s?-JiK7!aQlLH8o9Vkk(=*B1<=Rc%3|99>T7Z}Smr;7L2Vm<0}ljF~g zxLs%-W~fI?G>;n+-C$XdtyhW}KE-Fm*AX7R8I0FqC<*_uwtsTxCcvAB4d5vj=6q=t zPc^t_wUj_Zjrd&vv3}(1eL$A+B;<9QS^i~UXrCz)^7vER!s8H=${bTZ-S4guAgy_i zl1ik6+*5)iR_L=129#--wjlCxxA6PW3~=Uo3b65!98!BslS;hI0K`NS~z+*jH9 zHS%|FkH8CpKmA;cTg^>scU0d@97M%;q_g-n%nP|~Bh8M<7EPyeqRD`~^`6`Mp{oX5 zWUV2(giE#Tt&YgeHiYs&=lAU$DAX7z-^2oAS#1Y}*PC>7JfY@cAW7*->0Kb~pX6yzS3R?*&YfPIiuVIo@7uon>{tkJvtPd07yPYqD`Uim5;~hQkJ| zxinr^*bnvJ?TDnlm3n4t_O|7?jq_?)+i$;zGYCG*bCsTuFCLJwIQ80BAx30tlR*o% zdn8&WQ|}UM`%%yugjMxhZvn9U;Xk2$J)Dk4Q~h%hD-gG{q-zt;>MqU0t3|%HxAesZ zOFLu~{jl+fHjCo5dPm;u7o*IwY3<*8m(aQw5~-YMIkkkc|62)Wz|Jby2G2p>ME?WA zV-G$P@MNA7OR`eqP(CGzt?{JHGa?rrMN7oG*#fxH<}=7+{Qh45Wzui`RcO5f*$PQq z1in>yiK_OL;eEu)Js378mkHs%oC)nF+DtdLr5F=A(}>a(Q;crvf44;`WO;8PGg zy%NGwlYKWQCk5|oX*owX&av8(>oe`eqTMsY*|MMZ%EAcji%0w`s?idF1j|e2=K{DQ z)={hp)}-UL_)?TgSeiBNe$*k6fZEF5wXrdF&gpCAxA(_v@TBgTqM<~;X8ipaw2i1!&pkeGznmE3 ziGumYn)21m2&FZ$EWI8~tMig+9HFke?J_^!4ueCGW`fKRO1nb-$JjeVqo{k=#U`Vs zj5wv(N?28XZ1Y^oo^jTk?}UedI!iuRDGUe0q09r?;{6yeroNI1vZ1#SB6V##A8TVX zzS>v%j5B>@&DcBqP$%8RjLngxdT7b$TcPgN{0pIa0>#0TqWzFp{$iY9@JU#=H$ZW5 zu`Jpf1iz%fAi77EcpKVy_Pbxcn&xy!`^?mLM$rZco!RNb!25hcg)k>LYTyKP3EhYC z1Lk%v);S0Nb-JE@qeGVVoM7bjvsDQ(m7YM}~E~8^xA#@zx$a z*PE1@??MB1JT)6r7ZzK8mS+cEh<9i&&ilOyb^k2SCfvGrH{H-$#>e-vFF=DyM8Uid zPU$5BInbDqKDrd#$7ofcS@^>sBtKg#{ppLI@b(=o#t~g&Yd$K(|9uO8n}&=}^KvjJ z5?8JgIy?f;YDAM&5V^3dql>OdBRAKe>;3NNq8zNzCZW>i8ayq-*=251YhkraY|PJv z@AfbyJ1dMocA7WTR5PamG{6FqoW*AKqF`*TYO4wo+b5KP*SoWEQ85|+Be)U{K>F{3 z9xV-3ka?(1o>e<%Rr4(ZW%S#0e8`XyA2<|G(yvW|<{J)qjW!)Rr} zV?p5$r|qrI5l>4RR~_ROEjHX!hquE!uz~=*A|$;x5I0D@_-ju$(oLOq5RpTedL#j3 zD3oL0P)*hSH4Az2T$WW|=h2IMP0~mBM+Lx%C!Jz23u-dYKoijx!G({_huDUbG17X*SReS8Q(+fyq*AFG*|yE zU#?WV&0B4MbmWmkXamcHl_44$dr2mD%!T;QuwO};x$Q;t^ijIpZ&N=s2&^KVliSVn z@!gFVO*%X&9*adxP=7_z>4|N?lxuqU@){M6WNnNQy1b} z!B-WLbug309CP#+>AJ*|f1u%beaDtoLGRKDzpmx$N}a$Z=zd3MG<1lLKwPv2oAZci zz}~gmo>Na$;qnH?XP`0|-H8FdOC*)a{1i}}-vOat;51IW_lq)WJMp7TUaiOed|P&KKQCzDJ46CtKF{~A6`(d29VYZxyd{>}=e7Ab zQk5_#bY=tedhZFd1U?kQYHT?U0Ny*nkS(AgK)a+7-4#;}ez#kpW4HKKE$r6c2Qg%~ z4xzxxyPLV$J&Pxu+~ftZS$PH+&tK5Gw;DY$?whyto;;Bp?w!r37ARc2C;n`4K-yRE zRJAv3WP6Tx8k7DrlE$?^oVn%Npj=-tK547?>p3P&dxloq6|`kbBcWFdNS&)mI(;+;3klsq4N|X@hOB1C11eH5m#K1+Cb>q-ZM6@~Ku|np%EQc-j5* zQ^jXP^7oZba02CY zfxQC4=p&YIlQY~Rf`2y@VBM2oWQ49Vx>iYjHS90!hB*uCJ|S)48K2O$qshASox+WV zU9!=uWQ7LONUSJLg93h_0`Ze+&0@lq=u{kpS8|KT!`{ESPGE9sv>znGYCWE*e1V)1 zu1Ae7wX-vQ9+NFk zGB?9%|3LJ3bzyF1k`d3QOkXJ}RTvt@gct-j{Gcg9g~;-P4c6 zj?)9D8Vc0{0D8xT|1_IDW zZqQa{U?|n{!SG{0z^chQF?y>0?BUTX_mb=0F)2HrY&Y86p&~+>v?`x*vQ-_YgIj{c zpMg|(FE}ISY$!f}C|-L%9N;!!>7^{Z;8UtT`%Z)x)FU{2LI(#9Ye^cItSS-k7@7AY zJ*uo^7H>5rxtPyo%&4axTHj8Fz)MDb-WepL=sroR zq7SAUz|6Hu#Pp3B`*bcO1!o~Ib1}!=!+^IOuvS6418+uc4X#0ha%BorG1I*hmDF`F z!tAb0tLa=S5|0x!!BvK&4-2aV)@Q$jpmGLo(Yjq`X*e&4@7osac(F|?s`)|@pcDMZ zkn~5#3&sL+?`ycmtN!G2(hw69!-EUveOK=+e{n286%n4V5!=-?#tV*E0hvxX6+7O{KPu=WpUkdr#VdHELAU7y4qPe*je z0=M@*xt*6QZJ)_VF#jBN0jDUn4@oM<4drH@56qXIk8FkIy+$0@^TTUOUs9Ih&_4GO z@#p>b$1u$w>}dzB5Lt*S@Bbd<3$O$Sog@|GYk4nc|+r1pG~I1rEQ)i9a7F>D-9vd0MFXy9B!JtH_sA!xp5evBO#zAFdXx zhu^alzc;W(zkf9X>-*AIZuKoYQ!MWLSMhZv^Xp=5U~L79r|&?O{==2L z`F2oY%!&5JHcV}rJk~V8>_We-y(uQVNNR}(xNJEAjw4suo0f8tf-(nQ>yqm;? zKMqvPN6tL=RLQBs9Ifa94Lc(OU+qcT0BU3NF|5!l@gc7i2uk6iFD?8BdQB%D55Ku;-L={a=? z7XIS*`M`2&5fZ=FtY=lM!oSSTC0%x;Z@z>XVk#RiO`NN$(D$4J&w`73M|LKUCXwlz z@7ma2CC5BpvAMo&b|stsb!R~U(HfusiHmEk$Ekoc$v#q5KrNcvX;B}A)! zz8R_jMCRid(hYFf0q7zjimqjag7#kjw2|oa{B91@R%C{~(453$8&te{m(#<)vwk}u9g{V9Tl3twmp37N1k{QG5`nTI{zYWO=#Nuvy3A-OAK+O__=+44@jP<2>RG z&ut4L-PDyUG)-P6R*ew9ebeL}I)oOt$~*VaGrtdA!68%Umx3VUOt+>mT6BmhOAH)7 zv>ywp5=BaZIY(w%Gn+vs!L{$b{H5qDc{ZXVJ5+*j3`V;vMVbtjk*448`PM#p##42;B(AOn+=zp|1f`i(Z zQ>8vcEjav8BPT|e#SRDc9u#g*oW4E&AMi>ubUalo7Gfq<2^(C+xTO4 zL@!N3xjwF7aojNnMogq=Kv~QahW+b9MjN|CRddzIiPu3$LxOo(mT@!XQO~cRIl$gJ z_Qrc@(0Kd0Gwrix_E{6V%JD}tTDR{)Zq`^+&a}SsdAz;ke~26qnb=3hz~D7U6ThV^ z0WSJrbb?P)>9H?)fx-M4ZLP}r-pL*%ra*jD(*x_o5C$9q$1f!Vn*A|^<(2u;zxWl) zRDcI?>q21x)wF$S&afB7B)ARIv-dG~7Iq0ZGPBS2HpH&BuhIqSoD=Ft+AWTfveqIO z{@&|Popbb*X?l0MKU0Lh6rRKE6q!BsSR&A7)7qE=dqFLu(^e_Rs}%E^em4vvEhCjw#*rXP0V6=dBnSC)mSA=H)k-ISHb!$!VD0 z+1^XC`3VTwX1paBE=bMwM}N{}`Wl{~Ad5|5(6qNT^lz@gHJ^s$pKooK7v6Bj!dt(7 z=2G6RGvF}u1Ns81h2aWzezItDy69cXB5T>5OT}Nft zg3qd?)R~?8Mv)9h^ou2f`>NIZvcY=Y;f%IyB6xNuq&8PoASMOLzVmji<{zXWVvXx6f2-?n(DpWM*;J- z77%ciNsM(eP8kk{#tJxJfa5k@I*5u@JP;y@cP0!jK`#h>U|Z2vpOAS?Rn~_Oo$hzW z-lQ^iq;R+fiO~m|tSCC(qrqZ_Oj57bA}=YzfQPDfcEy+%xF$83DmCRqZ|WlCpCASX zqgB*<=)4b4O^F~$(3kFQY_2DreZ6^hXwQ+OYi^{&k2_uSY~X$8+DMH$BMPEMekti7_OER|gfGdVi_4d^(P^|T_c{hgh$p|W|dNn&s~8m{UCaUAWUPN zb62puW(oAT4?U&~S*c?zS5)Y9w%uWyqn$ZvR+2HK#hRf67i5%m?pG+gf6h~0on4FN zzF`nVd~JjA6}7Xo@ham82tIPuTBLQiaYQ`o1ffkg*0=lISp3NDMQDlmprKHP5_@4^ zFom;PBV%1IFMF?GjSA~LW@tI|954SxXO6R!%1^fGEhsoBA2UGQo}(fMXnaZsY?rA* z;CU2Z`Yb^H;{#M*?s{t(l}e7XJI8z8`FHtCHGJO|n%gf|)lrwklA8U{UW9)nCS{l{ zOMEWe3|XchSU+-P168mG4~n*bVntjsi529i&9-}8(tdA6+n)5j^!$DUAxe^ax<;<} z_PAX^sds&r<5u-Z55(}OHD4B>7uAe+5MzBwxa)a&<9pnf>>wuijN;8e>m9j{il+u+ zkai*C1BM!qSsR0J@b;j+H_^s_appp@g&p8<4EH8TKie9UI( z`5JCP%SZ$9wL$;9yzZ+(x8%IL9J_IY{tPJZ(X=nc6Vu=t^KitJfo6RIzKCiCe|Nka zGqydBcPNNZ$tiGEyq22tH9jbs%68-8SVAYc8@z+B-SE;v&og&=GhqI_ALDrlDKr4S zFT?A3PPHe8=5U{;9{BAxR2-{&>75+03}S*k363Grh1t;b!&bz`bfS5}JM8qz^Mn*h zqRD5sIJ3~yVfEOC1aH;Otc$mFpW?JAF z8aj0QxzA)UJ$@eR%-y=%DVEwQSqXosV(2U>${Ej>Cd*D(;x_8f7?{(nfDE`#_n1uy zfjV(HRRT?JE~4{uj`!?OlJ7)7yVQ2#dV2>}u!Vk4A4&K&#>8gnPqt=3lT9|!48t}* zYQfmHVHs!GbPn1+1BI$uan32MH}O)7R|6#IaT?Y*>wkZKiu&XJL{aVboigh?h$W-E z1>-2wVXE)u=TJ=uLE@*Q<(t^O%Y4xzg;yfA{Kh%S!QZ}Bsf!Ig(6QMb$9nEBC0aV8 zN|Y>%FufE9Xsvx;mgLON%^r#s?XJ!K6yCOVDb69C=6;!Y(_n^<@`_NTPLXA-t2Mf^ z$L(TRjkOHEbBf#J#71&&R~9T|Cgps&4kV2BNZk%vdJN}j|CErw+W-xufhpuxgU?Z<9pnbx$T!D9LSki+AM=aZbV$o;AL7S^#$eq#Z$eGTz9pVg4ez!T$an&$w4&vx!VHZ39u$ z^cFNj2mBJGRW0*dobR;V1-v1(ZK337Y_QvsBKLJ}3Dh3$v|)b=;pQeJpHOAFJX+B< zsjv{u8op{ji;vVUU1a%eg{WYXN-;{f2+#=!21*XzIqlD zMm$)>Iyj^0Ey7I&r;nR6untAtu$l7hW?h5xtmP~M^ql?FkTt|r)(!pE@a~<7Euzwu z(f7Mrq3gu$Xk#{8_opNJ#N>L2`&w%=0q7gE`E(|=Y@muArp-|J!5}pHCZ7jvbv^vI z)k4L-JOJ`cQeRM%w-_wuO#3?%q4_6tiJ`DAzMDa3e`v_u{E2Z1l@S|@o$sTyE8A8B z3H^Fw$ck1uDN=O`x9*BT>8&8eGJ1~BgcB-lQS_0K8QE!L-EfF?N9wp|j^^^rl%?`% zHo*3eJ5v=5AXE$PC;MBI;_R0)Bd@N9Wh)tMjV|svtuXSB3*D90ZaM6w`r4@jX@OF9 zh1Vop&ECi)66@O&y3C!eW6KfzDk79{sY9!HeT#D|M21f)rWpC;v5yJ7s+!uSx$g$t z7Q5zr7U=U?#`_Ua@i@Bu8PXPNC8gLE+c=l!xo+?K#`vNl(Au7ZV(b@Kqb6U#I(nw+ z+btqvPiQf4#nmTrBjUX67q_8;Vt{#Gf0W+B#?}-8<$dVDP>rK<v2lWDz};|DY&xDdZ;Ls+vlk@$C9kA zMggM~?qtRf0n~BdfLQd_)sp!LO|5RQWF)qsQHGk(9r)sx!x22xfmFV4nINaV`sFb&qVeY-hxu2TRQx?AlsvL7Xr;Km24#A{8gm|IKXEUI!CuD@m<@aBQ26guiMmC$DHK}ae7HBBGy8<2xD0aY=s0d$$ zKOfBi?;vL(98AFBvN)jorgW^Ya&)gUIP%>DvRR>(H9B?7u|rkl>T8d2d{wGHo~sBJ zG_9Y6A(X>-B-*fqa7`7KLbzhbWkw#~gS4$mjXJpgrG6I^Fp>VPo z)&!kN527uE;e}|t)y*D*;l<;GYXlrOXMLs(6$dF3VPgR@#i`^O^M@mR`IYZCOeNK? zST|L}&$^DL2HhJ@u4ut=G$1}pedl?P*c~jvQz7n*1BL5ya4~C_bv38t(HYWQcUT2G z^9i9Anj0fU%-N_Eem1iO_02ok-f-?nc@k|rJjk>5Fq3-Hu1}0tJZs0dU$jn4`xfuI z8CRARbH$p@d~OLT`O$pIE#eA>hep@a1+AZ3N?8+e^bNU`PGuxNS=ZdQvBt>lBjaNG z50J3x*zX;fg-qEw+#WK%vcIClB$CaBiY^E8dxY|Y;H6ZsC8+C@ZD3p&x>1g;X6A^O z=8MyHr$v5yn+9#UUG22eKykqhX+0s6=w9q=Ta=n#RrPi^m8^(hejI59g-LBv#94on zNbsj!6F%jHe3SGS8lwJ*6*+7ucjI+!&kC7Fd$y3?>L7VjIj%X8=Yf;etJ=;~ z&K$%4-R(w-r%QlhoO_Qsm;8I))nPaiV;9xmW1nBxx^AK$7B>6!(P z$(cJ!vQaBHQ#Vz7)tdQA4^)%f4ccHSs^g0VXvN(9h15ePa?=(JcDKC`6>v7oUgL^D zmNQKbM7gG9gUnm{rD<@leM;o&7gRqmJiwN&Y43fLW3hjf&yf!wl6<;soEN=DqssTB z>xv~eebv+M0<3-W{RS!0#fGlwS#S10>U$6q8kJo~{06k0P;q>=$dyFC{>}R)N7IDr zD#4D&1^tbUGmj$9&=T=drDB~xj+KG3B(ToTSB20xU%T;@{3!g^&H1R&+f*szG=T=V zN1|NUP|MZYNi)raS;l(|zo^k?#PN;0BC(iN($Ueh6*oIIedXq5H7k$^{K^wqCu_JA zshAgJ$>u6m2dN};@lutrwApRDAV|j{wE*mXRzDUOY^1iT=yM?2aY+!$&cfNYo0DIp7PXLasV1FwEk>Roi7fM{Mw$95bwx08sF^fcN$+=iN89A6RtmY zRp@((iUC~A@v?W#i~GR^L=lpKT@%@};c`VbNllgiGD$PZU41)+L`y$~^!fgZSY1XI z3y{73ao9f}5h}pXrcd2zWiHmxJ_@#1c@o>bprh-tzM$4q&W-)suB^OFqj~zcJZ2o;Y38B;=df&HxMW{uBWs>)CudL~gKaM7W-hH&O}^GOv>sTBt0_pdfe3f{ z4%yr$?4&P#hpA2AMdiLhOufq-_E^g9X{>KQDm&^C`UdC_WEvtLUJ9R7&W&3eS|Mb0 zM7!LUw09)lhrcRsljQB)acfe4udGdJPo2?;h6MFT%T=3G2^RXxF}S%9Y+CdYT?d`{ z@H}VfI0~YY#m=P_PDN!-0Udc)TiNi%XXnB+l^0eF<;g%^ERTc&>&0!8O5v=lB+Wvh z7(wW^BnJQW?^BNPvqJI)!Jq!Q7Tg;o>E&QYZaT!pLvva+jZ`HIGer?S?z~JesZ014 zwfa({%a}z96**A4pW;cl+7~0Qto>WwU`|))jN9w1ka7tSV@au8y>EDPb=sDjGbi?Y zFr>$@tgQD5Oxa-D}^O?ew$8m?5$|L2qt!2ay+hU;A zQU??x?MP*OW0yz^=1p-9C-sAf|7^u-adC_7^3m!>tKQ1;0**+Eoa}$Kb=F}~ZfhHt zMv(3j0ZHl30Rai=R%+;mK^kdLknS$&?gr`Z5*X5w6Y_(u2Ez0Wz{{5#h*v)-Ba zUF*Kr{d?9!t|vVZe+YPlE>$O41b*|p176dNgJ0NDxGSUbiw*iX7CK62s|iV5Lt#i% zl;Y|K@g%wx>66NDuog@f5kuG>p+^Uq!!##sj-@0sj{*k`@F@+pqP|bvwmHsbhw2Gt zk|Hy# z+c=OqDYO53j<8&?w0tt8_c>L-d;+Q4;9pO=M|)W@o`DK;$BF;t&Ts z<^0T^mD`;5tC-5oE^nyNKD#k8t# zbPHQch=jy!MeCduPYh;~{ZM$7e9&*Yc#Nk#(AAybC^UDgL}<34a&vLWfYG9;$GqS_ zV+P+~IjuX^tsG9_u*KP@O5tyW(5OM>H&v;=Ef6bI4I1Z^_$7w_`*1oNv<{=s3CrcvQ-AWh?dj>U^Tq6md^0T|~QexU5= zM6Hs)nbRyxh~y4Oj?Ci;s>#XUD&^Cm`2IJa;z0R}Pr>e37{5}ytnRqSK{s*ebG-{( zTCc3XWsW!O<2u05Wisp8nfHNg-_Y|V<1*Y zd4!_)%kK;e1mFzNy%H^bizOQHM7ZgmkB(I(P3*LpTU|vrp}8H|OeW;ZhiBfn`CXXi)n2kchbP%Q-~VsN{zS{Df#&3cAubn8Gw7raA$Y_gtQuY>h-a zC!Bk%N9M$XH<8tC<2bWMnaejQsikj|lBiNv2xb1A_`VABHIXT=){fM)?Me@qSOuYd zsN{m9PDBL9F%)rnUD6_~dP20GfITIcD}+eWt%yVKl8;ZAW>9H)AJ`m&D# zDl2Bx58iMP?xPGYO=`U@R^9C0aZ9wy!!MFxr^Ec-dw`Eu?e{q+otAnN*&l0mw71Zi znMBC?U-XOVbqrEv6$>r;&TK#I)XTAcI(j!B0t5uJ7jiv@0dKy%=28{4oK67N&8Ahk zmjUw$p>JeGw4MZ>7rE~e(R~+HTT@fRh)hfH`a!IBFfI4M&Kw*vzp0 z<+K`Sii`M-)Uf8~PGQGQL}ADFuk=;h=Fdu0O32f9ZeTX@g7R`|5Zta&{=i)yl)U&p za)dC;tt5k4e6T>FJWg0z`IR@t!L-hUeIaW1Cu=k;qA0#e*CSHINE=4VS3mc`|0oGk znAwaPDd8vD39X_kIbH9h=|L-9-PI+HoI_syyomS#iXG@E+rHM|9&3N$Om|=_pqs*r zT>y^g+OIJy4K-s=jJj^M!X3_^R<9wTyZ`H;j|SZjuS|KuG;?&m@UP3~Sc$ zpc=IS$M@v*b6C@}BZbsZxh%hf=-eHS!?XzbZ%skhkvAK2fVwKLvPA<;fKW>)+dGc$ z-@Fq*QzIK!w(i7)z!pDxLd-%?;s@*p)0o^!%P9=9W+$o5vH~}28@~{qv?%v0t)jF` z`^WqCf`$mZtQmoFlO)uDwOI2a3V9}zSzOeAGbkf4UgsBt@=z)&DR3E?@nMLn-2hr0 zgysn~IiE=Y%AHcb^WH0%1kCyn>hFfo4)1hccr%Z@dEf|l5B4a{7&7U98KS*7O*9Q-A%7yD@A!7b{j%WB!-4 zL?egu{!!LA+1-H??zLo)i5vO=q3Awjp5Ya0*hAJzHIdX`4md$=;yzl*PR(J=(7z$u z+1l8OiE{;o=WE!Utab7pv{KVgBqm}^ZQJez^xxghWE4!OtD|Q=tyBu>>XRsNq%+p3 z&~_>go}v@`3eiJD0ABaZXkYfs^^#DZ8rhosHr5pg`0qS2D4_Az~-9oU&i@>}x zzDM5EGdjBm5rH;crAIfanbFT-qV@OGdv%NGpeP1tSGcL_@ZuMj*66#3%ekn&`AnH3 zgN`#H_W20Altd3hx^UdeSCabAz52NlkD(b4yUi4=cMzCN|6TE&;c*@?V*ad0)695Rg4u^NND#* z)I1`8)TK#RH?JOMAg%YlKxRts_4pCG7L~`T?qe=VB&^;=pFFD{8-~XgyH^23Padu@ zgg!14?dYqeH0;$oCRn5x7&PPdz^8f!n*TuDz4u?npI#VS1Poc|$-*@ha~= zqno{ETTlM2v!u}V;t#CDc?P6^-E3cRCyvo%YGlEu&$)=|%Y5R&>mL4@c|BE73`dGu>AL&l#!^BKG<{EZ$Q2bVwl z4Yd>stT*%Lp>A5+PG3+%A#U*cYqEDTTArdU^R-O`xjlgX(R1cRbHSLJDMvHV4B@h! zR@KJpOj@-PcFqhy1gso$sxaM=2t5%(uD#JSmfc!RKUtrW2)8_AcG?RDlFqLqsH&Gt z&}pU1?SPe3eJcNHrZUhh)bwVIX$yW7v-1PR8EGu6JdP_{mx zlm&@`kIcvA3bDF5f>X za*MwmCO#k+251FP1eBWOnsDGDNwIT9)x?*1-d5UUFUlpnbPp{?ef%9!k>P{onHM5f zYT5Mg+U>TYbdi=A#@yL}JWe)u$wq?TH;|Dz$P8;Q?SrqZwW%kV;)K$N!WU};p$ecu zUN#GOTOPT6o>C1TQ1XU4I9%r%^7w+RYy$8vCqR`-298kbTjP+xxm7n)^9;YPkM%=WN~9hM)gQ=+_>%bU=|OUMT0xq{EUe8bolSnDdC1x(@@g3x+5-rcB^ z?|pTYWEAem^_zYddR)_&fvPJ)%(|%aMdESXYc%OO968fhueToCoY6^&iz6el-Qx`_ zd^sIv0~(%zX{&!M=bY|q&2hXRRC$|5n3)gpA{53!xDK8H?N6Qz;D&v3QV8Y6{pZI9 zGQr*JH+lm`^WXV^lE-)o5Bl8Q+&%#?C^YtuYSy*vJ|$Zv?|g>spcGM7q-%tw&)))8*cem3~B-NR^mgO9_2wuu$w~{sw|#s zO+RbFY;$Z{qN2%#@THTa97Dd>83^!|;Y=S3#6msxC5!BWZRa;*oUZT2zS4UbP=G?T8xt0|L4~CiyICt%TXLo{Q244C zXnLOa%R7G0<^D^=DgC(Uv+Ctv&}IkK3S_0Fm|p*QI$To)j*8*;_q5 zJ&Klqg-~+EQkqw`1+EmVq1-*s$WyC`-^mm7g~|1zAuP!@^!Q>P9Vv6 zC7*rKm7OqU`vW{R7fUbW8>rJL2paYltzxI$cwRt1FXRxmNnj-R2`0Y`T5Yl#M3)?CP?FEPT#?kPtW$qrEZnZNus_a zMA15RBx$^i3eO2MFvboKXX-0Ysm~0I zhhJ=upy;%P5StIWhyvPwa_?ra3U)5Sz=oeFG zq;dvOO68l*8JOeJ4AFLqUS3^jAZDNsb+#HY`QHWL+iXytHva>QOEx2cV{6iM_11Lz zp6Hne4IWIfG%(DJp3GHJ)~1|>`{&t`Lgew!M?a#)%Ss?ezW{6Tr@N42(p_Ld8P2;G5UHBZ zop2dEU4Qbu^Wtt+!ubKW*^%NsWL2=Ss40KnJ@lq7D2ucymzDIU-y8%C4*yZsjD=0K zF8-@t>gW93j%7je3I7%iKS`0Wl6oh{+VP2QdZ2xK*@FPAG`%jh(I0A@aBx~8Fm%6CGhJ%OBGs~pb5<8twFnIVWYQq7OX1jR3Y z+7i8iB#@)GJX^;gsXh*vpLXS$e5hFWPZvSF86O+ckC{6~VI#gjCv!n-<(Oc>$yylO%}?CnDxlmmId^ZP z6N`@IZNkiRO6MTC+Da5|T~tQ7cqJ<9J>P&mQS}sn1m|jIv>fe8s)Jpww8d0e?^vQH zk55KP$#zp;T@C*;1Q8GyxafcEn&BJooPDw}o(hQYo_hWF)BD*Mn}Ht>8f;2C;!41JlrJy?vil&r{rdMQK?OHYCiAz_%p6Z?u9b80FEx05Aiw5+b5DEaq@sG zw;ZP3uLYExc2$pM5{TY=C+0#CKkRU6c9}Ewy*P&<^;vYYrna5>8R??^$ccK|W=8#; zCB+vOu_a>~{6^=~Z8ybh(wjP2ZY1E8?Uf0Cd#~-nk4h+4Jg&Zm4uXhV>4uaK#FuK1 zdDc^<3{bL{8m8?pI* zu-{#9sf+s=EmVX~QE~6OaF{LRr~W^J?8U-{KVGC2oDUgSdU<290_%Dxa;h;(PXo-C z<@ABJ|Iauq=KCF=)?ITrY>Ig0kDN9*>2&LqldW!&0QVc~MXo)RQvq9GS z{l@)-N_KOzyk0=>T<3giVR+$O9Je-#!LCSJnFmA>(B zpJ0xYM^@4^H^7p5AjOT=28SF+b_T)vx+)d9bud68+;Cn;C;*>!$^A98D{Twu#m7dRanZpcB%CTuNE%tnDhJg}S;F|H&-WQzC_bPdu=yqkH}Lem9MZdLyv3Of>bTTz3R1iE)qkAMq}< z?8@38WFi^Sdt+_x%CN;KzYcOoO&G-p!)dh8+Fjq8e9CMnS{@cQZy;1*)jk2f49 zsp#rZO&@-ZP30|a5f=;^3uy8My%=7HWeD}i^-&*d76wiCaKk-o2e%HRFE5uGL*wT( zG&7Fn?V#1sQ})xzS-N0w!W8=#a|fTmu=tPeP+@w9mm8Z?CJW3g(gC_9-gqFp&TV!( zwF&OAZgz91%&;;mmr!Zh9Zwx7X!T+-EpVL^%J!|pHY0xN2w~fS3_(bS#KH<_3$cuK zMO_|Yv8K{Ge!r}1E!|W}c&`m5+6T4x#9AxC(!q8hz2y@AjYjHY-8bMb!gUD1@$q+F zymp7(*H;YQ^X~kw_vzOvl$EaAa*H04owo@~qmBD_&eOX-%Ew$_l-=p56236+jhIoM6d1$uNru=nC;eu(c6P=3~6Q02pL?Xq18m958rcA< zG9GF&KWxm|{V_!dduJdvfxI?;JtI{K;wh0N?0=Wl5>#EH>T4DT+|x0KEZrUciX}{3 z9p4$CLCiHCrS1-LN7RK%uu1uwLe^Z%u(mstMp@mr5_^=$d?C4Vu@!A_= zOp%PqUcQ?fcx;3FAwQxQ$4jCf2vmbIEyOOIb;z-HLl6<8(l=d)`IXV15Wq);NA zm&r$_es?s410zN|A+sPb3p!UOoQ|{qoQ2JS7J2(6WoCiPDuH*z{`pEkOQm(<`cCHb z&?EQ#uR;oUibRyE7`Y2DE4f;NCa_&GBbO0aKEP}aVasoUEKlZ@qnhT+9wRh zM&mNmr{q$yWcHvq#zk@bKs+%TcA@r4^`P-zKB9aAI*rT?#x_uq2+v8)GP~D_OJPlYC z<_|xtDDz@_1v?*jii1v;Pt+bHnbsEnU|!NokOB_Q!4m* zM%!;?fR6(Y{EGM-XiJC}^ux#{gb6IxISH$`Jwx~yG=9n&FVe<^RlXC_X%FDRy6dw0 zKm1qNS3tCzK<3DtM=FVpfvipbP(KH_*^jjar}3! z{=~cqa66~*DbuLTM(#T8(C2qT#>~6hkzQr_>*MjpRm(uTUP-gwf=f$lQM1YT91rZQ zT7E|PxH5}9liI+0a|1iL`c}32t{Y7|mwfAo?eO0b$e?EWL5}3_=?)Ff555WM1-kgD zCKk^lubuLjCj$vqxs;4I^RmMAMd6HRj!{P<%KL{HrHPcjQu=)~SqNZ~m_-2>*ZEc_ zP6%i;!}FwxY@u7;uJvWUG8d%_+glpZoC?^tjC4uB)&CFq&A%Y%<&rF#Xx4i zXCbjbVqIyNk{MBCI!Nll7mHN=bhUz{1v{@tn+0fl7h2|$?qT?`zME`l$e_*0=EY}N z8q>RRHWaoc>EFzA%#?~ zas`eJ%?ueAFH1%F?iRABpU{*u3g5mIm5L$!Ei#b;d>7k?{SC1}z5ivK8aROUb7_<^ zJSE{$(O7SWlxi<5@fvKbTQ=gS z!+Gdn!qO306t$Gi=G{cXTu>zDVGCfMa7D|<-|+Tn?S5kP>MlY}Ky~xJ39e3)y@T^d zM-nclbPBqyY&rc@x~0l2IdjS7_aO~^goSUqA14R-Xbco*R6y?QGDRHf9Z)@RwyJ{~ z&-kCxMT`~3I6d|Pcci<*LZE>dp<~D69f8JLJ6sQw19y32EJSFjVi06{rY*^73&B8e z(`4@W(;Y=6ixUYss4dXeROgG=?IRHXH^SF?P}ga1JDFB~wIFfE$G@k$E;(P|E}L6s zafWW>Q-H3-R>AE_yoZMW@UNmM=&>In(M~s*DO(K26ORQD^D14 z&#-?b8Df*q#qgpczm;oMf`_ installed) console output while in development: +The highlight is `structlog.dev.ConsoleRenderer` that offers nicely aligned and colorful (requires the `colorama package `_ installed) console output. +If the `better-exceptions `_ package is installed, it will also pretty-print exceptions with helpful contextual data. .. figure:: _static/console_renderer.png :alt: Colorful console output by ConsoleRenderer. +You can find the code for the output above `in the repo `_. + To use it, just add it as a renderer to your processor chain. -It will recognize logger names, log levels, time stamps, stack infos, and tracebacks as produced by ``structlog``'s processors and render them in special ways. +It will recognize logger names, log levels, time stamps, stack infos, and ``exc_info`` as produced by ``structlog``'s processors and render them in special ways. + +.. warning:: + + For pretty exceptions to work, `format_exc_info` must be **absent** from the processors chain. -``structlog``'s default configuration already uses `ConsoleRenderer`, therefore if you want nice colorful output on the console, you don't have to do anything except installing colorama. +``structlog``'s default configuration already uses `ConsoleRenderer`, therefore if you want nice colorful output on the console, you don't have to do anything except installing *colorama* and *better-exceptions*. If you want to use it along with standard library logging, we suggest the following configuration: .. code-block:: python @@ -25,7 +32,6 @@ If you want to use it along with standard library logging, we suggest the follow structlog.stdlib.PositionalArgumentsFormatter(), structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M.%S"), structlog.processors.StackInfoRenderer(), - structlog.processors.format_exc_info, structlog.dev.ConsoleRenderer() # <=== ], context_class=dict, diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 493a5406..0241f902 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -10,9 +10,9 @@ Installation $ pip install structlog -If you'd like colorful output in development (you know you do!), install using:: +If you'd like colorful output and pretty exceptions in development (you know you do!), install using:: - $ pip install structlog colorama + $ pip install structlog colorama better-exceptions Your First Log Entry @@ -35,6 +35,7 @@ Here, ``structlog`` takes full advantage of its hopefully useful default setting That in turn uses `repr` to serialize all values to strings. Thus, it's easy to add support for logging of your own objects\ [*]_. - If you have `colorama `_ installed, it's rendered in nice `colors `. +- If you have `better-exceptions `_ installed, exceptions will be rendered in colors and with additional helpful information. It should be noted that even in most complex logging setups the example would still look just like that thanks to `configuration`. Using the defaults, as above, is equivalent to:: @@ -47,7 +48,6 @@ Using the defaults, as above, is equivalent to:: structlog.processors.add_log_level, structlog.processors.StackInfoRenderer(), structlog.dev.set_exc_info, - structlog.processors.format_exc_info, structlog.processors.TimeStamper(), structlog.dev.ConsoleRenderer() ], @@ -197,4 +197,4 @@ If you want to see more code, make sure to check out the `examples`! .. _`standard out`: https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29 -.. _recipe: https://docs.python.org/2/howto/logging-cookbook.html +.. _recipe: https://docs.python.org/3/howto/logging-cookbook.html#implementing-structured-logging diff --git a/show_off.py b/show_off.py new file mode 100644 index 00000000..45242ddb --- /dev/null +++ b/show_off.py @@ -0,0 +1,40 @@ +""" +Show how console logging looks like. + +This is used for the screenshot in the readme and +. +""" + +from dataclasses import dataclass + +import structlog + + +@dataclass +class SomeClass: + x: int + y: str + + +log = structlog.get_logger("some_logger") + +log.debug("debugging is hard", a_list=[1, 2, 3]) +log.info("informative!", some_key="some_value") +log.warning("uh-uh!") +log.error("omg", a_dict={"a": 42, "b": "foo"}) +log.critical("wtf", what=SomeClass(x=1, y="z")) + + +log2 = structlog.get_logger("another_logger") + + +def make_call_stack_more_impressive(): + try: + d = {"x": 42} + print(SomeClass(d["y"], "foo")) + except Exception: + log2.exception("poor me") + log.info("all better now!", stack_info=True) + + +make_call_stack_more_impressive() diff --git a/src/structlog/_config.py b/src/structlog/_config.py index c800f52f..a3e61a04 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -24,12 +24,7 @@ from ._log_levels import make_filtering_bound_logger from ._loggers import PrintLoggerFactory from .dev import ConsoleRenderer, _has_colorama, set_exc_info -from .processors import ( - StackInfoRenderer, - TimeStamper, - add_log_level, - format_exc_info, -) +from .processors import StackInfoRenderer, TimeStamper, add_log_level from .types import BindableLogger, Context, Processor, WrappedLogger @@ -42,7 +37,6 @@ add_log_level, StackInfoRenderer(), set_exc_info, - format_exc_info, TimeStamper(fmt="%Y-%m-%d %H:%M.%S", utc=False), ConsoleRenderer( colors=_has_colorama and sys.stdout is not None and sys.stdout.isatty() diff --git a/src/structlog/dev.py b/src/structlog/dev.py index d96cf0b4..46d861f1 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -4,13 +4,17 @@ """ Helpers that make development with ``structlog`` more pleasant. + +See also the narrative documentation in `development`. """ import sys +import warnings from io import StringIO from typing import Any, Optional, Type, Union +from ._frames import _format_exception from .types import EventDict, Protocol, WrappedLogger @@ -19,6 +23,11 @@ except ImportError: colorama = None +try: + import better_exceptions +except ImportError: + better_exceptions = None + __all__ = ["ConsoleRenderer"] @@ -118,13 +127,13 @@ class ConsoleRenderer: """ Render ``event_dict`` nicely aligned, possibly in colors, and ordered. - If ``event_dict`` contains an ``exception`` key (for example from - :func:`~structlog.processors.format_exc_info`), it will be rendered *after* - the log line. + If ``event_dict`` contains a true-ish ``exc_info`` key, it will be + rendered *after* the log line. If better-exceptions_ is present, in + colors and with extra context. :param pad_event: Pad the event to this many characters. - :param colors: Use colors for a nicer output. The default is True if - colorama is present, otherwise False. + :param colors: Use colors for a nicer output. `True` by default if + colorama_ is installed. :param force_colors: Force colors even for non-tty destinations. Use this option if your logs are stored in a file that is meant to be streamed to the console. @@ -137,10 +146,14 @@ class ConsoleRenderer: must be a dict from level names (strings) to colorama styles. The default can be obtained by calling `ConsoleRenderer.get_default_level_styles` + :param pretty_exceptions: Render exceptions with colors and extra + information. `True` by default if better-exceptions_ is installed. - Requires the colorama_ package if *colors* is `True`. + Requires the colorama_ package if *colors* is `True`, and the + better-exceptions_ package if *pretty_exceptions* is `True`. .. _colorama: https://pypi.org/project/colorama/ + .. _better-exceptions: https://pypi.org/project/better-exceptions/ .. versionadded:: 16.0 .. versionadded:: 16.1 *colors* @@ -153,8 +166,14 @@ class ConsoleRenderer: .. versionchanged:: 19.2 Can be pickled now. .. versionchanged:: 20.1 ``colorama`` does not initialize lazily on Windows anymore because it breaks rendering. - .. versionchanged: 21.1 It is additionally possible to set the logger name + .. versionchanged:: 21.1 It is additionally possible to set the logger name using the ``logger_name`` key in the ``event_dict``. + .. versionadded:: 21.2 *pretty_exceptions* + .. versionchanged:: 21.2 `ConsoleRenderer` now handles the ``exc_info`` + event dict key itself. Do **not** use the + `structlog.processors.format_exc_info` processor together with + `ConsoleRenderer` anymore! It will keep working, but you can't have + pretty exceptions and a warning will be raised if you ask for them. """ def __init__( @@ -164,6 +183,7 @@ def __init__( force_colors: bool = False, repr_native_str: bool = False, level_styles: Optional[Styles] = None, + pretty_exceptions: bool = (better_exceptions is not None), ): self._force_colors = self._init_colorama = False styles: Styles @@ -202,6 +222,7 @@ def __init__( ) self._repr_native_str = repr_native_str + self._pretty_exceptions = pretty_exceptions def _repr(self, val: Any) -> str: """ @@ -272,6 +293,7 @@ def __call__( stack = event_dict.pop("stack", None) exc = event_dict.pop("exception", None) + exc_info = event_dict.pop("exc_info", None) sio.write( " ".join( self._styles.kv_key @@ -287,9 +309,26 @@ def __call__( if stack is not None: sio.write("\n" + stack) - if exc is not None: + if exc_info or exc is not None: sio.write("\n\n" + "=" * 79 + "\n") - if exc is not None: + + if exc_info: + if not isinstance(exc_info, tuple): + exc_info = sys.exc_info() + + if self._pretty_exceptions: + sio.write( + "\n" + + "".join(better_exceptions.format_exception(*exc_info)) + ) + else: + sio.write("\n" + _format_exception(exc_info)) + elif exc is not None: + if self._pretty_exceptions: + warnings.warn( + "Remove `render_exc_info` from your processor chain " + "if you want pretty exceptions." + ) sio.write("\n" + exc) return sio.getvalue() diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 1e27ae1b..4fcc074d 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -267,8 +267,7 @@ def format_exc_info( behaviors: - If the value is a tuple, render it into the key ``exception``. - - If the value is an Exception *and* you're running Python 3, render it - into the key ``exception``. + - If the value is an Exception render it into the key ``exception``. - If the value true but no tuple, obtain exc_info ourselves and render that. diff --git a/tests/test_dev.py b/tests/test_dev.py index 1781ed80..837b374b 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -3,6 +3,7 @@ # repository for complete details. import pickle +import sys import pytest @@ -200,9 +201,12 @@ def test_key_values(self, cr, styles, padded): + styles.reset ) == rv - def test_exception(self, cr, padded): + def test_exception_rendered(self, cr, padded, recwarn): """ - Exceptions are rendered after a new line. + Exceptions are rendered after a new line if they are already rendered + in the event dict. + + A warning is emitted if pretty exceptions are active. """ exc = "Traceback:\nFake traceback...\nFakeError: yolo" @@ -210,6 +214,13 @@ def test_exception(self, cr, padded): assert (padded + "\n" + exc) == rv + if cr._pretty_exceptions: + (w,) = recwarn.list + assert ( + "Remove `render_exc_info` from your processor chain " + "if you want pretty exceptions.", + ) == w.message.args + def test_stack_info(self, cr, padded): """ Stack traces are rendered after a new line. @@ -241,27 +252,44 @@ def test_pad_event_param(self, styles): + styles.reset ) == rv - def test_everything(self, cr, styles, padded): + @pytest.mark.parametrize("explicit_ei", [True, False]) + def test_everything(self, cr, styles, padded, explicit_ei): """ Put all cases together. """ - exc = "Traceback:\nFake traceback...\nFakeError: yolo" - stack = "fake stack trace" + if explicit_ei: + try: + 0 / 0 + except ZeroDivisionError: + ei = sys.exc_info() + else: + ei = True - rv = cr( - None, - None, - { - "event": "test", - "exception": exc, - "key": "value", - "foo": "bar", - "timestamp": "13:13", - "logger": "some_module", - "level": "error", - "stack": stack, - }, - ) + stack = "fake stack trace" + ed = { + "event": "test", + "exc_info": ei, + "key": "value", + "foo": "bar", + "timestamp": "13:13", + "logger": "some_module", + "level": "error", + "stack": stack, + } + + if explicit_ei: + rv = cr(None, None, ed) + else: + try: + 0 / 0 + except ZeroDivisionError: + rv = cr(None, None, ed) + ei = sys.exc_info() + + if dev.better_exceptions: + exc = "".join(dev.better_exceptions.format_exception(*ei)) + else: + exc = dev._format_exception(ei) assert ( styles.timestamp diff --git a/tests/test_processors.py b/tests/test_processors.py index bf788016..47f2a6cf 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -276,6 +276,19 @@ def test_pickle(self, fmt, utc, key, proto): class TestFormatExcInfo: + @pytest.mark.parametrize("ei", [False, None, ""]) + def test_nop(self, ei): + """ + If exc_info is falsey, only remove the key. + """ + assert {} == format_exc_info(None, None, {"exc_info": ei}) + + def test_nop_missing(self): + """ + If event dict doesn't contain exc_info, do nothing. + """ + assert {} == format_exc_info(None, None, {}) + def test_formats_tuple(self, monkeypatch): """ If exc_info is a tuple, it is used. @@ -293,7 +306,7 @@ def test_gets_exc_info_on_bool(self): """ If exc_info is True, it is obtained using sys.exc_info(). """ - # monkeypatching sys.exc_info makes currently py.test return 1 on + # monkeypatching sys.exc_info makes currently pytest return 1 on # success. try: raise ValueError("test") diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index b8745ce2..1dfd75f0 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -22,7 +22,7 @@ from structlog._log_levels import _NAME_TO_LEVEL, CRITICAL, WARN from structlog.dev import ConsoleRenderer from structlog.exceptions import DropEvent -from structlog.processors import JSONRenderer +from structlog.processors import JSONRenderer, KeyValueRenderer from structlog.stdlib import ( AsyncBoundLogger, BoundLogger, @@ -501,7 +501,12 @@ def configure_for_pf(): reset_defaults() -def configure_logging(pre_chain, logger=None, pass_foreign_args=False): +def configure_logging( + pre_chain, + logger=None, + pass_foreign_args=False, + renderer=ConsoleRenderer(colors=False), +): """ Configure logging to use ProcessorFormatter. """ @@ -512,7 +517,7 @@ def configure_logging(pre_chain, logger=None, pass_foreign_args=False): "formatters": { "plain": { "()": ProcessorFormatter, - "processor": ConsoleRenderer(colors=False), + "processor": renderer, "foreign_pre_chain": pre_chain, "format": "%(message)s [in %(funcName)s]", "logger": logger, @@ -656,7 +661,7 @@ def test_foreign_pre_chain_gets_exc_info(self, configure_for_pf, capsys): have access to it. """ test_processor = call_recorder(lambda l, m, event_dict: event_dict) - configure_logging((test_processor,)) + configure_logging((test_processor,), renderer=KeyValueRenderer()) try: raise RuntimeError("oh noo") @@ -682,7 +687,9 @@ def add_excinfo(logger, log_method, event_dict): return event_dict test_processor = call_recorder(lambda l, m, event_dict: event_dict) - configure_logging((add_excinfo, test_processor)) + configure_logging( + (add_excinfo, test_processor), renderer=KeyValueRenderer() + ) try: raise MyException("oh noo") diff --git a/tox.ini b/tox.ini index ae9a2b1d..10ed4cce 100644 --- a/tox.ini +++ b/tox.ini @@ -14,7 +14,7 @@ python = [tox] # Currently, pypy3 is broken on macOS. Since we don't need it for coverage, we only test it in CI. -envlist = lint,mypy,{py36,py37,py38,py39,py310}-threads,{py38,py39,py310}-greenlets,py38-colorama,docs,pypi-description,manifest,coverage-report +envlist = lint,mypy,{py36,py37,py38,py39,py310}-threads,{py38,py39,py310}-greenlets,py39-colorama,py39-be,docs,pypi-description,manifest,coverage-report isolated_build = True @@ -55,14 +55,21 @@ setenv = commands = coverage run -m pytest {posargs} -[testenv:py38-colorama] +[testenv:py39-colorama] deps = colorama setenv = PYTHONHASHSEED = 0 commands = coverage run -m pytest {posargs} -[testenv:py38-greenlets] +[testenv:py39-be] +deps = better-exceptions +setenv = + PYTHONHASHSEED = 0 +commands = coverage run -m pytest {posargs} + + +[testenv:py39-greenlets] deps = greenlet twisted @@ -90,6 +97,9 @@ skip_install = true deps = twine pip >= 18.0.0 +# Needs to run last, otherwise we have a race condition about coverage files +# lying around. +depends = coverage-report commands = pip wheel -w {envtmpdir}/build --no-deps . twine check {envtmpdir}/build/* @@ -102,11 +112,11 @@ commands = check-manifest [testenv:coverage-report] -basepython = python3.8 +basepython = python3.9 deps = coverage[toml] skip_install = true parallel_show_output = true -depends = {py36,py37,py38,py39}-threads,{py38,py39}-greenlets,py38-colorama +depends = {py36,py37,py38,py39}-threads,{py38,py39}-greenlets,py39-colorama,py39-be commands = coverage combine coverage report From f50da1d60f8410b4f651fa31eba968c771bf7889 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 11 Jul 2021 10:44:41 +0200 Subject: [PATCH 0496/1520] Package meta data and old pips are unreliable --- README.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.rst b/README.rst index fdb725ff..3ddb435d 100644 --- a/README.rst +++ b/README.rst @@ -143,9 +143,6 @@ We collect useful third party extension in `our wiki `_. -The package meta data should ensure that you get the correct version. - ``structlog`` for Enterprise ---------------------------- From 7e0150d9db146648fa87e37a7918c9f8f0ee2e62 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 13 Jul 2021 06:43:15 +0200 Subject: [PATCH 0497/1520] [pre-commit.ci] pre-commit autoupdate (#333) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/PyCQA/isort: 5.9.1 → 5.9.2](https://github.com/PyCQA/isort/compare/5.9.1...5.9.2) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 94690045..043863fc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,7 +7,7 @@ repos: language_version: python3.8 - repo: https://github.com/PyCQA/isort - rev: 5.9.1 + rev: 5.9.2 hooks: - id: isort additional_dependencies: [toml] From 1f76a041dbeeb4e23a5128c9465a96a0ef789267 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 16 Jul 2021 07:08:25 +0200 Subject: [PATCH 0498/1520] Fix links --- docs/configuration.rst | 2 +- docs/development.rst | 2 +- docs/logging-best-practices.rst | 6 +++--- docs/processors.rst | 2 +- docs/thread-local.rst | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/configuration.rst b/docs/configuration.rst index 0cd8347c..7aaf4778 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -157,7 +157,7 @@ If you use standard library's logging, it makes sense to configure them next to See `Third-Party Extensions `_ in the wiki. **Flask** - See `Logging `_. + See `Logging `_. **Pyramid** `Application constructor `_. diff --git a/docs/development.rst b/docs/development.rst index 4983d819..dcd73da8 100644 --- a/docs/development.rst +++ b/docs/development.rst @@ -9,7 +9,7 @@ If the `better-exceptions `_ package .. figure:: _static/console_renderer.png :alt: Colorful console output by ConsoleRenderer. -You can find the code for the output above `in the repo `_. +You can find the code for the output above `in the repo `_. To use it, just add it as a renderer to your processor chain. It will recognize logger names, log levels, time stamps, stack infos, and ``exc_info`` as produced by ``structlog``'s processors and render them in special ways. diff --git a/docs/logging-best-practices.rst b/docs/logging-best-practices.rst index e1aac291..20fa5ced 100644 --- a/docs/logging-best-practices.rst +++ b/docs/logging-best-practices.rst @@ -59,9 +59,9 @@ Additionally, `Graylog's Extended Log Format`_ (GELF) allows for structured data .. _Graylog: https://www.graylog.org/ .. _Elastic: https://www.elastic.co/ -.. _Logstash: https://www.elastic.co/products/logstash -.. _Kibana: https://www.elastic.co/products/kibana -.. _Elasticsearch: https://www.elastic.co/products/elasticsearch +.. _Logstash: https://www.elastic.co/logstash +.. _Kibana: https://www.elastic.co/kibana +.. _Elasticsearch: https://www.elastic.co/elasticsearch .. _`Graylog's Extended Log Format`: https://docs.graylog.org/en/latest/pages/gelf.html .. _`standard out`: https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29 .. _syslogd: https://en.wikipedia.org/wiki/Syslogd diff --git a/docs/processors.rst b/docs/processors.rst index 485faab3..40cca26e 100644 --- a/docs/processors.rst +++ b/docs/processors.rst @@ -117,7 +117,7 @@ Examples ^^^^^^^^ The probably most useful formatter for string based loggers is `structlog.processors.JSONRenderer`. -Advanced log aggregation and analysis tools like `logstash `_ offer features like telling them "this is JSON, deal with it" instead of fiddling with regular expressions. +Advanced log aggregation and analysis tools like `logstash `_ offer features like telling them "this is JSON, deal with it" instead of fiddling with regular expressions. More examples can be found in the :ref:`examples ` chapter. For a list of shipped processors, check out the :ref:`API documentation `. diff --git a/docs/thread-local.rst b/docs/thread-local.rst index 495a5791..0a082819 100644 --- a/docs/thread-local.rst +++ b/docs/thread-local.rst @@ -77,7 +77,7 @@ The general flow of using these functions is: Thread-local Contexts --------------------- -``structlog`` also provides thread-local context storage in a form that you may already know from `Flask `_ and that makes the *entire context* global to your thread or greenlet. +``structlog`` also provides thread-local context storage in a form that you may already know from `Flask `_ and that makes the *entire context* global to your thread or greenlet. This makes its behavior more difficult to reason about which is why we generally recommend to use the `merge_threadlocal` route. From f55319b9672eb63f299c70f4c033d498c41a8a6f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 16 Jul 2021 07:39:03 +0200 Subject: [PATCH 0499/1520] Add get_threadlocal & get_merged_threadlocal (#331) --- CHANGELOG.rst | 2 ++ docs/api.rst | 30 +++++++++++++++++++++++++++++- docs/thread-local.rst | 21 +++++++++------------ src/structlog/threadlocal.py | 26 +++++++++++++++++++++++++- tests/test_threadlocal.py | 26 ++++++++++++++++++++------ 5 files changed, 85 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index fa6b7c34..edd47b81 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -32,6 +32,8 @@ Changes: - If the `better-exceptions `_ package is present, ``structlog.dev.ConsoleRenderer`` will now pretty-print exceptions using it. Pass ``pretty_exceptions=False`` to disable. This only works if ``format_exc_info`` is **absent** in the processor chain. +- ``structlog.threadlocal.get_threadlocal()`` can now be used to get a copy of the current thread-local context that has been bound using ``structlog.threadlocal.bind_threadlocal()``. +- ``structlog.threadlocal.get_merged_threadlocal(bl)`` does the same, but also merges the context from a bound logger *bl*. ---- diff --git a/docs/api.rst b/docs/api.rst index b1307da5..869ba83f 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -109,11 +109,39 @@ API Reference .. automodule:: structlog.threadlocal + +Modern Approach +~~~~~~~~~~~~~~~ + +.. autofunction:: bind_threadlocal + +.. autofunction:: get_threadlocal + + >>> from structlog.threadlocal import bind_threadlocal, get_threadlocal + >>> bind_threadlocal(x=1) + >>> get_threadlocal() + {'x': 1} + +.. autofunction:: get_merged_threadlocal + + >>> from structlog import get_logger + >>> from structlog.threadlocal import bind_threadlocal, get_merged_threadlocal + >>> bind_threadlocal(x=1) + >>> log = get_logger() + >>> log = log.bind(y=2) + >>> get_merged_threadlocal(log) + {'x': 1, 'y': 2} + .. autofunction:: merge_threadlocal .. autofunction:: clear_threadlocal -.. autofunction:: bind_threadlocal + +Old Approach +~~~~~~~~~~~~ + +The following APIs use a different approach, that we discourage nowadays. +Please see :doc:`thread-local` for details. .. autofunction:: wrap_dict diff --git a/docs/thread-local.rst b/docs/thread-local.rst index 0a082819..efe69934 100644 --- a/docs/thread-local.rst +++ b/docs/thread-local.rst @@ -19,16 +19,16 @@ Immutability You should call some functions with some arguments. - ---David Reid + --- David Reid -The behavior of copying itself, adding new values, and returning the result is useful for applications that keep somehow their own context using classes or closures. -Twisted is a `fine example ` for that. -Another possible approach is passing wrapped loggers around or log only within your view where you gather errors and events using return codes and exceptions. -If you are willing to do that, you should stick to it because `immutable state `_ is a very good thing\ [*]_. -Sooner or later, global state and mutable data lead to unpleasant surprises. +``structlog`` does its best to have as little global state as possible to achieve its goals. +In an ideal world, you would just stick to its immutable\ [*]_ bound loggers and reap all the rewards of having purely `immutable state `_. -However, in the case of conventional web development, we realize that passing loggers around seems rather cumbersome, intrusive, and generally against the mainstream culture. -And since it's more important that people actually *use* ``structlog`` than to be pure and snobby, ``structlog`` ships with the `structlog.threadlocal` module and a couple of mechanisms to help here. +However, we realize that passing loggers around is rather clunky and intrusive in practice. +And since `practicality beats purity `_, ``structlog`` ships with the `structlog.threadlocal` module to help you to safely have global context storage. + +.. [*] In the spirit of Python's 'consenting adults', ``structlog`` doesn't enforce the immutability with technical means. + However, if you don't meddle with undocumented data, the objects can be safely considered immutable. The ``merge_threadlocal`` Processor @@ -43,6 +43,7 @@ The general flow of using these functions is: - Call `structlog.threadlocal.bind_threadlocal` as an alternative to your bound logger's ``bind()`` when you want to bind a particular variable to the thread-local context. - Use ``structlog`` as normal. Loggers act as they always do, but the `structlog.threadlocal.merge_threadlocal` processor ensures that any thread-local binds get included in all of your log messages. +- If you want to access the thread-local storage, you use `structlog.threadlocal.get_threadlocal` and `structlog.threadlocal.get_merged_threadlocal`. .. doctest:: @@ -184,7 +185,3 @@ In this case we feel like this is an acceptable trade-off. You can easily write deterministic tests using a call-capturing processor if you use the API properly (cf. warning above). This big red box is also what separates immutable local from mutable global data. - - -.. [*] In the spirit of Python's 'consenting adults', ``structlog`` doesn't enforce the immutability with technical means. - However, if you don't meddle with undocumented data, the objects can be safely considered immutable. diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index ea221ace..31df92e5 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -13,6 +13,8 @@ from typing import Any, Dict, Generator, Iterator, Type, TypeVar +import structlog + from ._config import BoundLoggerLazyProxy from .types import BindableLogger, Context, EventDict, WrappedLogger @@ -169,6 +171,28 @@ def __getattr__(self, name: str) -> Any: _CONTEXT = threading.local() +def get_threadlocal() -> Context: + """ + Return a copy of the current thread-local context. + + .. versionadded:: 21.2.0 + """ + return _get_context().copy() + + +def get_merged_threadlocal(bound_logger: BindableLogger) -> Context: + """ + Return a copy of the current thread-local context merged with the context + from *bound_logger*. + + .. versionadded:: 21.2.0 + """ + ctx = _get_context().copy() + ctx.update(structlog.get_context(bound_logger)) + + return ctx + + def merge_threadlocal( logger: WrappedLogger, method_name: str, event_dict: EventDict ) -> EventDict: @@ -181,7 +205,7 @@ def merge_threadlocal( .. versionadded:: 19.2.0 .. versionchanged:: 20.1.0 - This function used to be called ``merge_threalocal_context`` and that + This function used to be called ``merge_threadlocal_context`` and that name is still kept around for backward compatibility. """ context = _get_context().copy() diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py index 1675078f..2cac457e 100644 --- a/tests/test_threadlocal.py +++ b/tests/test_threadlocal.py @@ -7,15 +7,18 @@ import pytest +import structlog + from structlog._base import BoundLoggerBase from structlog._config import wrap_logger from structlog.testing import ReturnLogger from structlog.threadlocal import ( _CONTEXT, - _get_context, as_immutable, bind_threadlocal, clear_threadlocal, + get_merged_threadlocal, + get_threadlocal, merge_threadlocal, merge_threadlocal_context, tmp_bind, @@ -326,19 +329,18 @@ def test_unbind_threadlocal(self): Test that unbinding from threadlocal works for keys that exist and does not raise error when they do not exist. """ - clear_threadlocal() bind_threadlocal(a=234, b=34) - assert {"a": 234, "b": 34} == merge_threadlocal_context(None, None, {}) + assert {"a": 234, "b": 34} == get_threadlocal() unbind_threadlocal("a") - assert {"b": 34} == merge_threadlocal_context(None, None, {}) + assert {"b": 34} == get_threadlocal() unbind_threadlocal("non-existing-key") - assert {"b": 34} == merge_threadlocal_context(None, None, {}) + assert {"b": 34} == get_threadlocal() def test_get_context_no_context(self): """ @@ -351,4 +353,16 @@ def test_get_context_no_context(self): with pytest.raises(AttributeError): _CONTEXT.context - assert {} == _get_context() + assert {} == get_threadlocal() + + def test_get_merged(self): + """ + Returns a copy of the threadlocal context merged with the logger's + context. + """ + clear_threadlocal() + bind_threadlocal(x=1) + + log = structlog.get_logger().bind(y=2) + + assert {"x": 1, "y": 2} == get_merged_threadlocal(log) From 30e424fbc11c0c81a1406a818ce4dc5f4ecb2e6d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 20 Jul 2021 07:19:52 +0200 Subject: [PATCH 0500/1520] [pre-commit.ci] pre-commit autoupdate (#338) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/psf/black: 21.6b0 → 21.7b0](https://github.com/psf/black/compare/21.6b0...21.7b0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 043863fc..e9d9959b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ --- repos: - repo: https://github.com/psf/black - rev: 21.6b0 + rev: 21.7b0 hooks: - id: black language_version: python3.8 From f189e55c81f2a116b235c5871264f4b3ef92db19 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 23 Jul 2021 10:05:23 +0200 Subject: [PATCH 0501/1520] Add get_contextvars & get_merged_contextvars (#337) --- CHANGELOG.rst | 4 ++-- docs/api.rst | 4 +++- src/structlog/contextvars.py | 40 ++++++++++++++++++++++++++++++++++-- tests/test_contextvars.py | 36 ++++++++++++++++++++++++++++++-- tests/test_threadlocal.py | 14 +++++++------ 5 files changed, 85 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index edd47b81..bfcd2b18 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -32,8 +32,8 @@ Changes: - If the `better-exceptions `_ package is present, ``structlog.dev.ConsoleRenderer`` will now pretty-print exceptions using it. Pass ``pretty_exceptions=False`` to disable. This only works if ``format_exc_info`` is **absent** in the processor chain. -- ``structlog.threadlocal.get_threadlocal()`` can now be used to get a copy of the current thread-local context that has been bound using ``structlog.threadlocal.bind_threadlocal()``. -- ``structlog.threadlocal.get_merged_threadlocal(bl)`` does the same, but also merges the context from a bound logger *bl*. +- ``structlog.threadlocal.get_threadlocal()`` and ``structlog.contextvars.get_threadlocal()`` can now be used to get a copy of the current thread-local/context-local context that has been bound using ``structlog.threadlocal.bind_threadlocal()`` and ``structlog.contextvars.bind_contextvars()``. +- ``structlog.threadlocal.get_merged_threadlocal(bl)`` and ``structlog.contextvars.get_merged_contextvars(bl)`` do the same, but also merge the context from a bound logger *bl*. ---- diff --git a/docs/api.rst b/docs/api.rst index 869ba83f..a4b4ae9a 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -166,9 +166,11 @@ Please see :doc:`thread-local` for details. .. automodule:: structlog.contextvars +.. autofunction:: bind_contextvars +.. autofunction:: get_contextvars +.. autofunction:: get_merged_contextvars .. autofunction:: merge_contextvars .. autofunction:: clear_contextvars -.. autofunction:: bind_contextvars .. autofunction:: unbind_contextvars diff --git a/src/structlog/contextvars.py b/src/structlog/contextvars.py index 17796151..91ea223d 100644 --- a/src/structlog/contextvars.py +++ b/src/structlog/contextvars.py @@ -18,13 +18,49 @@ from typing import Any, Dict -from .types import EventDict, WrappedLogger +import structlog + +from .types import BindableLogger, EventDict, WrappedLogger STRUCTLOG_KEY_PREFIX = "structlog_" +STRUCTLOG_KEY_PREFIX_LEN = len(STRUCTLOG_KEY_PREFIX) + +# For proper isolation, we have to use a dict of ContextVars instead of a +# single ContextVar with a dict. +# See https://github.com/hynek/structlog/pull/302 for details. _CONTEXT_VARS: Dict[str, contextvars.ContextVar[Any]] = {} +def get_contextvars() -> Dict[str, Any]: + """ + Return a copy of the ``structlog``-specific context-local context. + + .. versionadded:: 21.2.0 + """ + rv = {} + ctx = contextvars.copy_context() + + for k in ctx: + if k.name.startswith(STRUCTLOG_KEY_PREFIX) and ctx[k] is not Ellipsis: + rv[k.name[STRUCTLOG_KEY_PREFIX_LEN:]] = ctx[k] + + return rv + + +def get_merged_contextvars(bound_logger: BindableLogger) -> Dict[str, Any]: + """ + Return a copy of the current context-local context merged with the context + from *bound_logger*. + + .. versionadded:: 21.2.0 + """ + ctx = get_contextvars() + ctx.update(structlog.get_context(bound_logger)) + + return ctx + + def merge_contextvars( logger: WrappedLogger, method_name: str, event_dict: EventDict ) -> EventDict: @@ -41,7 +77,7 @@ def merge_contextvars( for k in ctx: if k.name.startswith(STRUCTLOG_KEY_PREFIX) and ctx[k] is not Ellipsis: - event_dict.setdefault(k.name[len(STRUCTLOG_KEY_PREFIX) :], ctx[k]) + event_dict.setdefault(k.name[STRUCTLOG_KEY_PREFIX_LEN:], ctx[k]) return event_dict diff --git a/tests/test_contextvars.py b/tests/test_contextvars.py index df016612..4cf3b998 100644 --- a/tests/test_contextvars.py +++ b/tests/test_contextvars.py @@ -7,9 +7,14 @@ import pytest +import structlog + from structlog.contextvars import ( + _CONTEXT_VARS, bind_contextvars, clear_contextvars, + get_contextvars, + get_merged_contextvars, merge_contextvars, unbind_contextvars, ) @@ -19,7 +24,15 @@ pytestmark = pytest.mark.asyncio -class TestNewContextvars: +@pytest.fixture(autouse=True) +def _clear_contextvars(): + """ + Make sure all tests start with a clean slate. + """ + clear_contextvars() + + +class TestContextvars: async def test_bind(self, event_loop): """ Binding a variable causes it to be included in the result of @@ -145,7 +158,6 @@ async def test_parallel_binds(self, event_loop): Binding a variable causes it to be included in the result of merge_contextvars. """ - coro1_bind = asyncio.Event() coro2_bind = asyncio.Event() @@ -172,3 +184,23 @@ async def coro2(): assert {"a": 1, "b": 2, "c": 3} == await coro1_task assert {"a": 2, "b": 2, "c": 3} == await coro2_task + + def test_get_only_gets_structlog_without_deleted(self): + """ + get_contextvars returns only the structlog-specific key/values with the + prefix removed. Deleted keys (= Ellipsis) are ignored. + """ + bind_contextvars(a=1, b=2) + unbind_contextvars("b") + _CONTEXT_VARS["foo"] = "bar" + + assert {"a": 1} == get_contextvars() + + def test_get_merged_merges_context(self): + """ + get_merged_contextvars merges a bound context into the copy. + """ + bind_contextvars(x=1) + log = structlog.get_logger().bind(y=2) + + assert {"x": 1, "y": 2} == get_merged_contextvars(log) diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py index 2cac457e..7251a2a1 100644 --- a/tests/test_threadlocal.py +++ b/tests/test_threadlocal.py @@ -33,6 +33,14 @@ greenlet = None +@pytest.fixture(autouse=True) +def _clear_threadlocal(): + """ + Make sure all tests start with a clean slate. + """ + clear_threadlocal() + + @pytest.fixture def D(): """ @@ -287,7 +295,6 @@ def test_bind_and_merge(self): Binding a variable causes it to be included in the result of merge_threadlocal. """ - clear_threadlocal() bind_threadlocal(a=1) assert {"a": 1, "b": 2} == merge_threadlocal(None, None, {"b": 2}) @@ -307,8 +314,6 @@ def test_merge_works_without_bind(self): merge_threadlocal returns values as normal even when there has been no previous calls to bind_threadlocal. """ - clear_threadlocal() - assert {"b": 2} == merge_threadlocal(None, None, {"b": 2}) def test_multiple_binds(self): @@ -316,7 +321,6 @@ def test_multiple_binds(self): Multiple calls to bind_threadlocal accumulate values instead of replacing them. """ - clear_threadlocal() bind_threadlocal(a=1, b=2) bind_threadlocal(c=3) @@ -329,7 +333,6 @@ def test_unbind_threadlocal(self): Test that unbinding from threadlocal works for keys that exist and does not raise error when they do not exist. """ - clear_threadlocal() bind_threadlocal(a=234, b=34) assert {"a": 234, "b": 34} == get_threadlocal() @@ -360,7 +363,6 @@ def test_get_merged(self): Returns a copy of the threadlocal context merged with the logger's context. """ - clear_threadlocal() bind_threadlocal(x=1) log = structlog.get_logger().bind(y=2) From c5fe2e15d10f42939016945faaf28cd7275a89a5 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 26 Jul 2021 13:48:07 +0200 Subject: [PATCH 0502/1520] Reorder examples, add more explanations --- docs/examples.rst | 90 +++++++++++++++++++++++------------------------ 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/docs/examples.rst b/docs/examples.rst index 9baa10e3..996b68b2 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -3,6 +3,47 @@ Examples This chapter is intended to give you a taste of realistic usage of ``structlog``. + +.. _flask-example: + +Flask and Thread-Local Data +--------------------------- + +Let's assume you want to bind a unique request ID, the URL path, and the peer's IP to every log entry: + +.. literalinclude:: code_examples/flask_/webapp.py + :language: python + +``some_module.py`` + +.. literalinclude:: code_examples/flask_/some_module.py + :language: python + +This would result among other the following lines to be printed: + +.. code:: text + + event='user logged in' view='/login' peer='127.0.0.1' user='test-user' request_id='e08ddf0d-23a5-47ce-b20e-73ab8877d736' + event='user did something' view='/login' peer='127.0.0.1' something='shot_in_foot' request_id='e08ddf0d-23a5-47ce-b20e-73ab8877d736' + +As you can see, ``view``, ``peer``, and ``request_id`` are present in **both** log entries. + +While wrapped loggers are *immutable* by default, this example demonstrates how to circumvent that using a thread-local storage for request-wide context: + +1. `structlog.threadlocal.clear_threadlocal()` ensures the thread-local storage is empty for each request. +2. `structlog.threadlocal.bind_threadlocal()` puts your key-value pairs into thread-local storage. +3. The `structlog.threadlocal.merge_threadlocal()` processor merges the thread-local context into the event dict. + +Please note that the ``user`` field is only present in the view because it wasn't bound into the thread-local storage. +See `thread-local` for more details. + +---- + +`structlog.stdlib.LoggerFactory` is a totally magic-free class that just deduces the name of the caller's module and does a `logging.getLogger` with it. +It's used by `structlog.get_logger` to rid you of logging boilerplate in application code. +If you prefer to name your standard library loggers explicitly, a positional argument to `structlog.get_logger` gets passed to the factory and used as the name. + + .. _processors-examples: Processors @@ -10,8 +51,8 @@ Processors :doc:`processors` are a both simple and powerful feature of ``structlog``. -So you want timestamps as part of the structure of the log entry, censor passwords, filter out log entries below your log level before they even get rendered, and get your output as JSON for convenient parsing? -Here you go: +The following example demonstrates how easy it is to add timestamps, censor passwords, filter out log entries below your log level before they even get rendered, and get your output as JSON for convenient parsing. +It also demonstrates how to use `structlog.wrap_logger` that allows you to use ``structlog`` without any global configuration (a rather uncommon pattern, but can be useful): .. doctest:: @@ -45,49 +86,8 @@ Here you go: "timestamp": "datetime.datetime(..., ..., ..., ..., ...)" } -``structlog`` comes with many handy processors build right in. -For a list of shipped processors, check out the :ref:`API documentation `. - - - -.. _flask-example: - -Flask and Thread-Local Data ---------------------------- - -In the simplest case, you bind a unique request ID to every incoming request so you can easily see which log entries belong to which request. - -.. literalinclude:: code_examples/flask_/webapp.py - :language: python - -``some_module.py`` - -.. literalinclude:: code_examples/flask_/some_module.py - :language: python - -This would result among other the following lines to be printed: - -.. code:: text - - event='user logged in' view='/login' peer='127.0.0.1' user='test-user' request_id='e08ddf0d-23a5-47ce-b20e-73ab8877d736' - event='user did something' view='/login' peer='127.0.0.1' something='shot_in_foot' request_id='e08ddf0d-23a5-47ce-b20e-73ab8877d736' - -As you can see, ``view``, ``peer``, and ``request_id`` are present in **both** log entries. - -While wrapped loggers are *immutable* by default, this example demonstrates how to circumvent that using a thread-local storage for request-wide context: - -1. `structlog.threadlocal.clear_threadlocal()` ensures the thread-local storage is empty for each request. -2. `structlog.threadlocal.bind_threadlocal()` puts your key-value pairs into thread-local storage. -3. The `structlog.threadlocal.merge_threadlocal()` processor merges the thread-local context into the event dict. - -Please note that the ``user`` field is only present in the view because it wasn't bound into the thread-local storage. -See `thread-local` for more details. - ----- - -`structlog.stdlib.LoggerFactory` is a totally magic-free class that just deduces the name of the caller's module and does a `logging.getLogger` with it. -It's used by `structlog.get_logger` to rid you of logging boilerplate in application code. -If you prefer to name your standard library loggers explicitly, a positional argument to `structlog.get_logger` gets passed to the factory and used as the name. +``structlog`` comes with many handy processors build right in, so check the :ref:`API documentation ` before you write your own. +For example, you probably don't want to write your own timestamper. .. _twisted-example: From 4c19f0c10077492212b9b6aa0a9e68b6a644675e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 2 Aug 2021 20:05:03 +0200 Subject: [PATCH 0503/1520] [pre-commit.ci] pre-commit autoupdate (#342) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/PyCQA/isort: 5.9.2 → 5.9.3](https://github.com/PyCQA/isort/compare/5.9.2...5.9.3) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e9d9959b..16d8f13e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,7 +7,7 @@ repos: language_version: python3.8 - repo: https://github.com/PyCQA/isort - rev: 5.9.2 + rev: 5.9.3 hooks: - id: isort additional_dependencies: [toml] From f18859ba654cf6194371be272f1c7decbc9b51da Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 9 Aug 2021 08:14:12 +0200 Subject: [PATCH 0504/1520] Remove outdated and incorrect warning (that was invisible due to bad markup) ref #346 --- src/structlog/stdlib.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index df86e5ba..0da98eae 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -367,13 +367,6 @@ class AsyncBoundLogger: the processor chain (e.g. JSON serialization) and I/O won't block your whole application. - .. warning: Since the processor pipeline runs in a separate thread, - `structlog.contextvars.merge_contextvars` does **nothing** and should - be removed from you processor chain. - - Instead it's merged within **this logger** before handing off log - processing to the thread. - Only available for Python 3.7 and later. :ivar structlog.stdlib.BoundLogger sync_bl: The wrapped synchronous logger. From d20fd093432a20833ab52e2391c49504536b8b8d Mon Sep 17 00:00:00 2001 From: Robert Rollins Date: Tue, 10 Aug 2021 21:30:29 -0700 Subject: [PATCH 0505/1520] Cease all use of Colorama on non-Windows systems. (#345) * Color codes are no longer defined as empty if colorama isn't installed. * Removed all use of colorama on non-Windows systems. * Updated the changelog. * Fixes suggested by hynek * Add pragma: no cover to if _IS_WINDOWS: check. Co-authored-by: Hynek Schlawack Co-authored-by: Hynek Schlawack --- CHANGELOG.rst | 3 +- docs/development.rst | 2 +- docs/getting-started.rst | 3 +- src/structlog/_config.py | 4 +-- src/structlog/dev.py | 75 ++++++++++++++++++++++------------------ tests/test_dev.py | 19 +++++----- 6 files changed, 59 insertions(+), 47 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index bfcd2b18..65c4cec9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -34,7 +34,8 @@ Changes: This only works if ``format_exc_info`` is **absent** in the processor chain. - ``structlog.threadlocal.get_threadlocal()`` and ``structlog.contextvars.get_threadlocal()`` can now be used to get a copy of the current thread-local/context-local context that has been bound using ``structlog.threadlocal.bind_threadlocal()`` and ``structlog.contextvars.bind_contextvars()``. - ``structlog.threadlocal.get_merged_threadlocal(bl)`` and ``structlog.contextvars.get_merged_contextvars(bl)`` do the same, but also merge the context from a bound logger *bl*. - +- All use of ``colorama`` on non-Windows systems has been excised. + Colors will now be enabled by default on non-Windows systems even if colorama is not installed, as it's not necessary on such systems. ---- diff --git a/docs/development.rst b/docs/development.rst index dcd73da8..4edfc8a0 100644 --- a/docs/development.rst +++ b/docs/development.rst @@ -3,7 +3,7 @@ Development To make development a more pleasurable experience, ``structlog`` comes with the `structlog.dev` module. -The highlight is `structlog.dev.ConsoleRenderer` that offers nicely aligned and colorful (requires the `colorama package `_ installed) console output. +The highlight is `structlog.dev.ConsoleRenderer` that offers nicely aligned and colorful (requires the `colorama package `_ if on Windows) console output. If the `better-exceptions `_ package is installed, it will also pretty-print exceptions with helpful contextual data. .. figure:: _static/console_renderer.png diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 0241f902..99cb6973 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -34,7 +34,8 @@ Here, ``structlog`` takes full advantage of its hopefully useful default setting - All keywords are formatted using `structlog.dev.ConsoleRenderer`. That in turn uses `repr` to serialize all values to strings. Thus, it's easy to add support for logging of your own objects\ [*]_. -- If you have `colorama `_ installed, it's rendered in nice `colors `. +- On Windows, if you have `colorama `_ installed, it's rendered in nice `colors `. + Other OSes do not need colorama for nice colors. - If you have `better-exceptions `_ installed, exceptions will be rendered in colors and with additional helpful information. It should be noted that even in most complex logging setups the example would still look just like that thanks to `configuration`. diff --git a/src/structlog/_config.py b/src/structlog/_config.py index a3e61a04..af3a1360 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -23,7 +23,7 @@ from ._log_levels import make_filtering_bound_logger from ._loggers import PrintLoggerFactory -from .dev import ConsoleRenderer, _has_colorama, set_exc_info +from .dev import ConsoleRenderer, _use_colors, set_exc_info from .processors import StackInfoRenderer, TimeStamper, add_log_level from .types import BindableLogger, Context, Processor, WrappedLogger @@ -39,7 +39,7 @@ set_exc_info, TimeStamper(fmt="%Y-%m-%d %H:%M.%S", utc=False), ConsoleRenderer( - colors=_has_colorama and sys.stdout is not None and sys.stdout.isatty() + colors=_use_colors and sys.stdout is not None and sys.stdout.isatty() ), ] _BUILTIN_DEFAULT_CONTEXT_CLASS = cast(Type[Context], dict) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 46d861f1..5cb7ca2f 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -47,8 +47,6 @@ def _pad(s: str, length: int) -> str: if colorama is not None: - _has_colorama = True - RESET_ALL = colorama.Style.RESET_ALL BRIGHT = colorama.Style.BRIGHT DIM = colorama.Style.DIM @@ -60,11 +58,27 @@ def _pad(s: str, length: int) -> str: GREEN = colorama.Fore.GREEN RED_BACK = colorama.Back.RED else: - _has_colorama = False - - RESET_ALL = ( - BRIGHT - ) = DIM = RED = BLUE = CYAN = MAGENTA = YELLOW = GREEN = RED_BACK = "" + # These are the same values as the colorama color codes. Redefining them + # here allows users to specify that they want color without having to + # install colorama, which is only supposed to be necessary in Windows. + RESET_ALL = "\033[0m" + BRIGHT = "\033[1m" + DIM = "\033[2m" + RED = "\033[31m" + BLUE = "\033[34m" + CYAN = "\033[36m" + MAGENTA = "\033[35m" + YELLOW = "\033[33m" + GREEN = "\033[32m" + RED_BACK = "\033[41m" + + +if _IS_WINDOWS: # pragma: no cover + # On Windows, use colors by default only if colorama is installed. + _use_colors = colorama is not None +else: + # On other OSes, use colors by default. + _use_colors = True class _Styles(Protocol): @@ -174,34 +188,39 @@ class ConsoleRenderer: `structlog.processors.format_exc_info` processor together with `ConsoleRenderer` anymore! It will keep working, but you can't have pretty exceptions and a warning will be raised if you ask for them. + .. versionchanged:: 21.3 The colors keyword now defaults to True on + non-Windows systems, and either True or False in Windows depending on + whether colorama is installed. """ def __init__( self, pad_event: int = _EVENT_WIDTH, - colors: bool = _has_colorama, + colors: bool = _use_colors, force_colors: bool = False, repr_native_str: bool = False, level_styles: Optional[Styles] = None, pretty_exceptions: bool = (better_exceptions is not None), ): - self._force_colors = self._init_colorama = False styles: Styles - if colors is True: - if colorama is None: - raise SystemError( - _MISSING.format( - who=self.__class__.__name__ + " with `colors=True`", - package="colorama", - ) - ) - + if colors: if _IS_WINDOWS: # pragma: no cover - _init_colorama(self._force_colors) - else: - self._init_colorama = True + # On Windows, we can't do colorful output without colorama. + if colorama is None: + classname = self.__class__.__name__ + raise SystemError( + _MISSING.format( + who=classname + " with `colors=True`", + package="colorama", + ) + ) + # Colorama must be init'd on Windows, but must NOT be + # init'd on other OSes, because it can break colors. if force_colors: - self._force_colors = True + colorama.deinit() + colorama.init(strip=False) + else: + colorama.init() styles = _ColorfulStyles else: @@ -241,10 +260,6 @@ def __call__( self, logger: WrappedLogger, name: str, event_dict: EventDict ) -> str: - # Initialize lazily to prevent import side-effects. - if self._init_colorama: - _init_colorama(self._force_colors) - self._init_colorama = False sio = StringIO() ts = event_dict.pop("timestamp", None) @@ -366,14 +381,6 @@ def get_default_level_styles(colors: bool = True) -> Any: } -def _init_colorama(force: bool) -> None: - if force: - colorama.deinit() - colorama.init(strip=False) - else: - colorama.init() - - _SENTINEL = object() diff --git a/tests/test_dev.py b/tests/test_dev.py index 837b374b..3eca486a 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -26,7 +26,7 @@ def test_negative(self): @pytest.fixture(name="cr") def _cr(): - return dev.ConsoleRenderer(colors=dev._has_colorama) + return dev.ConsoleRenderer(colors=dev._use_colors) @pytest.fixture(name="styles") @@ -47,11 +47,14 @@ def _unpadded(styles): class TestConsoleRenderer: - @pytest.mark.skipif(dev._has_colorama, reason="Colorama must be missing.") + @pytest.mark.skipif(dev.colorama, reason="Colorama must be missing.") + @pytest.mark.skipif( + not dev._IS_WINDOWS, reason="Must be running on Windows." + ) def test_missing_colorama(self): """ ConsoleRenderer(colors=True) raises SystemError on initialization if - colorama is missing. + colorama is missing and _IS_WINDOWS is True. """ with pytest.raises(SystemError) as e: dev.ConsoleRenderer(colors=True) @@ -117,11 +120,11 @@ def test_init_accepts_overriding_levels(self, styles, padded): Stdlib levels are rendered aligned, in brackets, and color coded. """ my_styles = dev.ConsoleRenderer.get_default_level_styles( - colors=dev._has_colorama + colors=dev._use_colors ) my_styles["MY_OH_MY"] = my_styles["critical"] cr = dev.ConsoleRenderer( - colors=dev._has_colorama, level_styles=my_styles + colors=dev._use_colors, level_styles=my_styles ) # this would blow up if the level_styles override failed @@ -234,7 +237,7 @@ def test_pad_event_param(self, styles): """ `pad_event` parameter works. """ - rv = dev.ConsoleRenderer(42, dev._has_colorama)( + rv = dev.ConsoleRenderer(42, dev._use_colors)( None, None, {"event": "test", "foo": "bar"} ) @@ -350,7 +353,7 @@ def test_colorama_force_colors(self, styles, padded): If force_colors is True, use colors even if the destination is non-tty. """ cr = dev.ConsoleRenderer( - colors=dev._has_colorama, force_colors=dev._has_colorama + colors=dev._use_colors, force_colors=dev._use_colors ) rv = cr( @@ -374,7 +377,7 @@ def test_colorama_force_colors(self, styles, padded): + styles.reset ) == rv - assert not dev._has_colorama or dev._ColorfulStyles is cr._styles + assert not dev._use_colors or dev._ColorfulStyles is cr._styles @pytest.mark.parametrize("rns", [True, False]) def test_repr_native_str(self, rns): From f775abafb0b8b38a71becdf908f6ff4a3f1f6603 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 11 Aug 2021 06:36:20 +0200 Subject: [PATCH 0506/1520] Clarify changelog --- CHANGELOG.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 65c4cec9..6f5bd80b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -35,7 +35,9 @@ Changes: - ``structlog.threadlocal.get_threadlocal()`` and ``structlog.contextvars.get_threadlocal()`` can now be used to get a copy of the current thread-local/context-local context that has been bound using ``structlog.threadlocal.bind_threadlocal()`` and ``structlog.contextvars.bind_contextvars()``. - ``structlog.threadlocal.get_merged_threadlocal(bl)`` and ``structlog.contextvars.get_merged_contextvars(bl)`` do the same, but also merge the context from a bound logger *bl*. - All use of ``colorama`` on non-Windows systems has been excised. - Colors will now be enabled by default on non-Windows systems even if colorama is not installed, as it's not necessary on such systems. + Thus, colors are now enabled by default in ``structlog.dev.ConsoleRenderer`` on non-Windows systems. + You can keep using ``colorama`` to customize colors, of course. + ---- From 19491bc7346f7a6847076dce535a8b49335c6b4a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 26 Aug 2021 09:43:28 +0200 Subject: [PATCH 0507/1520] Add get_[merged_]threadlocal to narrative docs --- docs/thread-local.rst | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/docs/thread-local.rst b/docs/thread-local.rst index efe69934..8e9d6c9f 100644 --- a/docs/thread-local.rst +++ b/docs/thread-local.rst @@ -1,4 +1,4 @@ -Thread Local-Context +Thread-Local Context ==================== .. testsetup:: * @@ -50,6 +50,8 @@ The general flow of using these functions is: >>> from structlog.threadlocal import ( ... bind_threadlocal, ... clear_threadlocal, + ... get_threadlocal, + ... get_merged_threadlocal, ... merge_threadlocal, ... ) >>> from structlog import configure @@ -61,7 +63,7 @@ The general flow of using these functions is: ... ) >>> log = structlog.get_logger() >>> # At the top of your request handler (or, ideally, some general - >>> # middleware), clear the threadlocal context and bind some common + >>> # middleware), clear the thread-local context and bind some common >>> # values: >>> clear_threadlocal() >>> bind_threadlocal(a=1) @@ -69,7 +71,13 @@ The general flow of using these functions is: >>> # (perhaps by using structlog.get_logger() to create them). >>> log.msg("hi") a=1 event='hi' - >>> # And when we clear the threadlocal state again, it goes away. + >>> # You can access the current thread-local state. + >>> get_threadlocal() + {'a': 1} + >>> # Or get it merged with a bound logger. + >>> get_merged_threadlocal(log.bind(example=True)) + {'a': 1, 'example': True} + >>> # And when we clear the thread-local state again, it goes away. >>> clear_threadlocal() >>> log.msg("hi there") event='hi there' From 37d0b5a48ba369047705d67b4b3105484c4ddd7f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 26 Aug 2021 10:00:45 +0200 Subject: [PATCH 0508/1520] Proper import order --- docs/thread-local.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/thread-local.rst b/docs/thread-local.rst index 8e9d6c9f..3d97eeb1 100644 --- a/docs/thread-local.rst +++ b/docs/thread-local.rst @@ -50,8 +50,8 @@ The general flow of using these functions is: >>> from structlog.threadlocal import ( ... bind_threadlocal, ... clear_threadlocal, - ... get_threadlocal, ... get_merged_threadlocal, + ... get_threadlocal, ... merge_threadlocal, ... ) >>> from structlog import configure From 1df431ca94bbfedefd599ee0cabfb2de0db75453 Mon Sep 17 00:00:00 2001 From: Ivan Dmitrievsky Date: Fri, 27 Aug 2021 17:47:05 +0300 Subject: [PATCH 0509/1520] Fix typos (#348) --- docs/contextvars.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/contextvars.rst b/docs/contextvars.rst index 33bd079e..58d69605 100644 --- a/docs/contextvars.rst +++ b/docs/contextvars.rst @@ -15,7 +15,7 @@ Context Variables Historically, ``structlog`` only supported thread-local context binding. With the introduction of :mod:`contextvars` in Python 3.7, there is now a way of having a global context that is local to the current context and even works in concurrent code such as code using :mod:`asyncio`. -For that ``structlog`` provides a the `structlog.contextvars` module with a set of functions to bind variables to a context-local context. +For that ``structlog`` provides the `structlog.contextvars` module with a set of functions to bind variables to a context-local context. This context is safe to be used in asynchronous code. The general flow is: @@ -24,7 +24,7 @@ The general flow is: - Call `structlog.contextvars.clear_contextvars` at the beginning of your request handler (or whenever you want to reset the context-local context). - Call `structlog.contextvars.bind_contextvars` and `structlog.contextvars.unbind_contextvars` instead of your bound logger's ``bind()`` and ``unbind()`` when you want to bind and unbind key-value pairs to the context-local context. - Use ``structlog`` as normal. - Loggers act as the always do, but the `structlog.contextvars.merge_contextvars` processor ensures that any context-local binds get included in all of your log messages. + Loggers act as they always do, but the `structlog.contextvars.merge_contextvars` processor ensures that any context-local binds get included in all of your log messages. .. doctest:: From b39a720df2a8b144ecafd9d7eedaba9d0ecdf5dc Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 28 Aug 2021 15:58:50 +0200 Subject: [PATCH 0510/1520] Let's get rich (#349) * Make exception printing customizable, add rich printer * RTD is 3.8-only --- CHANGELOG.rst | 6 +- docs/_static/console_renderer.png | Bin 104240 -> 157406 bytes docs/api.rst | 5 ++ docs/conf.py | 1 + docs/development.rst | 6 +- docs/getting-started.rst | 4 +- src/structlog/dev.py | 114 ++++++++++++++++++++++++------ src/structlog/types.py | 11 +++ tests/test_dev.py | 73 ++++++++++++++++--- tox.ini | 34 +++++---- 10 files changed, 205 insertions(+), 49 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 6f5bd80b..2b4d49b2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -29,8 +29,10 @@ Changes: ^^^^^^^^ - ``structlog`` is now importable if ``sys.stdout`` is ``None`` (e.g. when running using ``pythonw``). -- If the `better-exceptions `_ package is present, ``structlog.dev.ConsoleRenderer`` will now pretty-print exceptions using it. - Pass ``pretty_exceptions=False`` to disable. +- Exception rendering in ``structlog.dev.ConsoleLogger`` is now configurable using the ``exception_formatter`` setting. + If either the `rich `_ or the `better-exceptions `_ package is present, ``structlog`` will use them for pretty-printing tracebacks. + ``rich`` takes precedence over ``better-exceptions`` if both are present. + This only works if ``format_exc_info`` is **absent** in the processor chain. - ``structlog.threadlocal.get_threadlocal()`` and ``structlog.contextvars.get_threadlocal()`` can now be used to get a copy of the current thread-local/context-local context that has been bound using ``structlog.threadlocal.bind_threadlocal()`` and ``structlog.contextvars.bind_contextvars()``. - ``structlog.threadlocal.get_merged_threadlocal(bl)`` and ``structlog.contextvars.get_merged_contextvars(bl)`` do the same, but also merge the context from a bound logger *bl*. diff --git a/docs/_static/console_renderer.png b/docs/_static/console_renderer.png index 8207dcb6563d76e2a5f7283f40ce8c3aabe1adfa..9e8095d080f02f8bc3baac018216a5003525adb0 100644 GIT binary patch literal 157406 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�(vAP?=<7B)Ew?02*S>guN#~en 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 <9X7&XtsLY^Sc*?jr{3G1q}}cqU79*Lb$8s?Rx0 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 if on Windows) console output. -If the `better-exceptions `_ package is installed, it will also pretty-print exceptions with helpful contextual data. + +If one of the `rich `_ or `better-exceptions `_ packages is installed, it will also pretty-print exceptions with helpful contextual data. +``rich`` takes precedence over ``better-exceptions``, but you can configure it by passing `structlog.dev.plain_traceback` or `structlog.dev.better_traceback` for the ``exception_formatter`` parameter of `ConsoleRenderer`. + +The following output is rendered using ``rich``: .. figure:: _static/console_renderer.png :alt: Colorful console output by ConsoleRenderer. diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 99cb6973..45f99772 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -10,9 +10,9 @@ Installation $ pip install structlog -If you'd like colorful output and pretty exceptions in development (you know you do!), install using:: +If you want pretty exceptions in development (you know you do!), additionally install either `rich `_ or `better-exceptions `_. Try both to find out which one you like better -- the screenshot in the README and docs homepage is rendered by ``rich``. - $ pip install structlog colorama better-exceptions +On Windows, you also have to install `colorama`_ if you want colorful output beside exceptions. Your First Log Entry diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 5cb7ca2f..af6ad361 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -12,10 +12,16 @@ import warnings from io import StringIO -from typing import Any, Optional, Type, Union +from typing import Any, Optional, TextIO, Type, Union from ._frames import _format_exception -from .types import EventDict, Protocol, WrappedLogger +from .types import ( + EventDict, + ExceptionFormatter, + ExcInfo, + Protocol, + WrappedLogger, +) try: @@ -28,8 +34,21 @@ except ImportError: better_exceptions = None +try: + import rich + + from rich.console import Console + from rich.traceback import Traceback +except ImportError: + rich = None # type: ignore + -__all__ = ["ConsoleRenderer"] +__all__ = [ + "ConsoleRenderer", + "plain_traceback", + "rich_traceback", + "better_traceback", +] _IS_WINDOWS = sys.platform == "win32" @@ -137,13 +156,64 @@ class _PlainStyles: kv_value = "" +def plain_traceback(sio: TextIO, exc_info: ExcInfo) -> None: + """ + "Pretty"-print *exc_info* to *sio* using our own plain formatter. + + To be passed into `ConsoleRenderer`'s ``exception_formatter`` argument. + + Used by default if neither ``rich`` not ``better-exceptions`` are present. + + .. versionadded:: 21.2 + """ + sio.write("\n" + _format_exception(exc_info)) + + +def rich_traceback(sio: TextIO, exc_info: ExcInfo) -> None: + """ + Pretty-print *exc_info* to *sio* using the ``rich`` package. + + To be passed into `ConsoleRenderer`'s ``exception_formatter`` argument. + + Used by default if ``rich`` is installed. + + .. versionadded:: 21.2 + """ + sio.write("\n") + Console(file=sio, color_system="truecolor").print( + Traceback.from_exception(*exc_info, show_locals=True) + ) + + +def better_traceback(sio: TextIO, exc_info: ExcInfo) -> None: + """ + Pretty-print *exc_info* to *sio* using the ``better-exceptions`` package. + + To be passed into `ConsoleRenderer`'s ``exception_formatter`` argument. + + Used by default if ``better-exceptions`` is installed and ``rich`` is + absent. + + .. versionadded:: 21.2 + """ + sio.write("\n" + "".join(better_exceptions.format_exception(*exc_info))) + + +if rich is not None: + default_exception_formatter = rich_traceback +elif better_exceptions is not None: # type: ignore + default_exception_formatter = better_traceback +else: + default_exception_formatter = plain_traceback + + class ConsoleRenderer: """ Render ``event_dict`` nicely aligned, possibly in colors, and ordered. If ``event_dict`` contains a true-ish ``exc_info`` key, it will be - rendered *after* the log line. If better-exceptions_ is present, in - colors and with extra context. + rendered *after* the log line. If rich_ or better-exceptions_ are present, + in colors and with extra context. :param pad_event: Pad the event to this many characters. :param colors: Use colors for a nicer output. `True` by default if @@ -160,14 +230,17 @@ class ConsoleRenderer: must be a dict from level names (strings) to colorama styles. The default can be obtained by calling `ConsoleRenderer.get_default_level_styles` - :param pretty_exceptions: Render exceptions with colors and extra - information. `True` by default if better-exceptions_ is installed. + :param exception_formatter: A callable to render ``exc_infos``. If rich_ + or better-exceptions_ are installed, they are used for pretty-printing + by default (rich_ taking precendence). You can also manually set it to + `plain_traceback`, `better_traceback`, `rich_traceback`, or implement + your own. - Requires the colorama_ package if *colors* is `True`, and the - better-exceptions_ package if *pretty_exceptions* is `True`. + Requires the colorama_ package if *colors* is `True` **on Windows**. .. _colorama: https://pypi.org/project/colorama/ .. _better-exceptions: https://pypi.org/project/better-exceptions/ + .. _rich: https://pypi.org/project/rich/ .. versionadded:: 16.0 .. versionadded:: 16.1 *colors* @@ -182,13 +255,14 @@ class ConsoleRenderer: anymore because it breaks rendering. .. versionchanged:: 21.1 It is additionally possible to set the logger name using the ``logger_name`` key in the ``event_dict``. - .. versionadded:: 21.2 *pretty_exceptions* + .. versionadded:: 21.2 *exception_formatter* .. versionchanged:: 21.2 `ConsoleRenderer` now handles the ``exc_info`` event dict key itself. Do **not** use the `structlog.processors.format_exc_info` processor together with `ConsoleRenderer` anymore! It will keep working, but you can't have - pretty exceptions and a warning will be raised if you ask for them. - .. versionchanged:: 21.3 The colors keyword now defaults to True on + customize exception formatting and a warning will be raised if you ask + for it. + .. versionchanged:: 21.2 The colors keyword now defaults to True on non-Windows systems, and either True or False in Windows depending on whether colorama is installed. """ @@ -200,7 +274,7 @@ def __init__( force_colors: bool = False, repr_native_str: bool = False, level_styles: Optional[Styles] = None, - pretty_exceptions: bool = (better_exceptions is not None), + exception_formatter: ExceptionFormatter = default_exception_formatter, ): styles: Styles if colors: @@ -241,7 +315,7 @@ def __init__( ) self._repr_native_str = repr_native_str - self._pretty_exceptions = pretty_exceptions + self._exception_formatter = exception_formatter def _repr(self, val: Any) -> str: """ @@ -331,17 +405,11 @@ def __call__( if not isinstance(exc_info, tuple): exc_info = sys.exc_info() - if self._pretty_exceptions: - sio.write( - "\n" - + "".join(better_exceptions.format_exception(*exc_info)) - ) - else: - sio.write("\n" + _format_exception(exc_info)) + self._exception_formatter(sio, exc_info) elif exc is not None: - if self._pretty_exceptions: + if self._exception_formatter is not plain_traceback: warnings.warn( - "Remove `render_exc_info` from your processor chain " + "Remove `format_exc_info` from your processor chain " "if you want pretty exceptions." ) sio.write("\n" + exc) diff --git a/src/structlog/types.py b/src/structlog/types.py index ce5da351..7db8f72c 100644 --- a/src/structlog/types.py +++ b/src/structlog/types.py @@ -17,6 +17,7 @@ Mapping, MutableMapping, Optional, + TextIO, Tuple, Type, Union, @@ -81,6 +82,16 @@ """ +ExceptionFormatter = Callable[[TextIO, ExcInfo], None] +""" +A callable that pretty-prints an `ExcInfo` into a file-like object. + +Used by `structlog.dev.ConsoleRenderer`. + +.. versionadded:: 21.2 +""" + + @runtime_checkable class BindableLogger(Protocol): """ diff --git a/tests/test_dev.py b/tests/test_dev.py index 3eca486a..3bb2b085 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -5,6 +5,8 @@ import pickle import sys +from io import StringIO + import pytest from structlog import dev @@ -26,7 +28,9 @@ def test_negative(self): @pytest.fixture(name="cr") def _cr(): - return dev.ConsoleRenderer(colors=dev._use_colors) + return dev.ConsoleRenderer( + colors=dev._use_colors, exception_formatter=dev.plain_traceback + ) @pytest.fixture(name="styles") @@ -204,23 +208,27 @@ def test_key_values(self, cr, styles, padded): + styles.reset ) == rv - def test_exception_rendered(self, cr, padded, recwarn): + @pytest.mark.parametrize("wrap", [True, False]) + def test_exception_rendered(self, cr, padded, recwarn, wrap): """ Exceptions are rendered after a new line if they are already rendered in the event dict. - A warning is emitted if pretty exceptions are active. + A warning is emitted if exception printing is "customized". """ exc = "Traceback:\nFake traceback...\nFakeError: yolo" + # Wrap the formatter to provoke the warning. + if wrap: + cr._exception_formatter = lambda s, ei: dev.plain_tracebacks(s, ei) rv = cr(None, None, {"event": "test", "exception": exc}) assert (padded + "\n" + exc) == rv - if cr._pretty_exceptions: + if wrap: (w,) = recwarn.list assert ( - "Remove `render_exc_info` from your processor chain " + "Remove `format_exc_info` from your processor chain " "if you want pretty exceptions.", ) == w.message.args @@ -289,10 +297,7 @@ def test_everything(self, cr, styles, padded, explicit_ei): rv = cr(None, None, ed) ei = sys.exc_info() - if dev.better_exceptions: - exc = "".join(dev.better_exceptions.format_exception(*ei)) - else: - exc = dev._format_exception(ei) + exc = dev._format_exception(ei) assert ( styles.timestamp @@ -431,3 +436,53 @@ def test_set_it(self): exception. """ assert {"exc_info": True} == dev.set_exc_info(None, "exception", {}) + + +@pytest.mark.skipif(dev.rich is None, reason="Needs rich.") +class TestRichTraceback: + def test_default(self): + """ + If rich is present, it's the default. + """ + assert dev.default_exception_formatter is dev.rich_traceback + + def test_does_not_blow_up(self): + """ + We trust rich to do the right thing, so we just exercise the function + and check the first new line that we add manually is present. + """ + sio = StringIO() + try: + 0 / 0 + except ZeroDivisionError: + dev.rich_traceback(sio, sys.exc_info()) + + assert sio.getvalue().startswith("\n") + + +@pytest.mark.skipif( + dev.better_exceptions is None, reason="Needs better-exceptions." +) +class TestBetterTraceback: + def test_default(self): + """ + If better-exceptions is present and rich is NOT present, it's the + default. + """ + assert ( + dev.rich is not None + or dev.default_exception_formatter is dev.better_traceback + ) + + def test_does_not_blow_up(self): + """ + We trust better-exceptions to do the right thing, so we just exercise + the function. + """ + sio = StringIO() + try: + 0 / 0 + except ZeroDivisionError: + dev.better_traceback(sio, sys.exc_info()) + + assert sio.getvalue().startswith("\n") diff --git a/tox.ini b/tox.ini index 10ed4cce..b74bc0de 100644 --- a/tox.ini +++ b/tox.ini @@ -7,14 +7,14 @@ python = 3.6: py36 3.7: py37 3.8: py38, docs - 3.9: py39, manifest, mypy + 3.9: py39, manifest, mypy, docs 3.10: py310 pypy3: pypy3 [tox] # Currently, pypy3 is broken on macOS. Since we don't need it for coverage, we only test it in CI. -envlist = lint,mypy,{py36,py37,py38,py39,py310}-threads,{py38,py39,py310}-greenlets,py39-colorama,py39-be,docs,pypi-description,manifest,coverage-report +envlist = lint,mypy,{py36,py37,py38,py39,py310}-threads,py39-greenlets,py39-colorama,py39-be,py39-rich,docs,pypi-description,manifest,coverage-report isolated_build = True @@ -30,9 +30,11 @@ commands = pre-commit run --all-files description = Check types basepython = python3.9 extras = tests -# Need twisted for stubs +# Need twisted & rich for stubs +# Otherwise mypy fails in tox. deps = mypy + rich twisted commands = mypy src typing_examples.py @@ -55,15 +57,8 @@ setenv = commands = coverage run -m pytest {posargs} -[testenv:py39-colorama] -deps = colorama -setenv = - PYTHONHASHSEED = 0 -commands = coverage run -m pytest {posargs} - - -[testenv:py39-be] -deps = better-exceptions +[testenv:py310-threads] +deps = twisted setenv = PYTHONHASHSEED = 0 commands = coverage run -m pytest {posargs} @@ -78,6 +73,21 @@ setenv = commands = coverage run -m pytest {posargs} +[testenv:py39-colorama] +deps = colorama +commands = coverage run -m pytest tests/test_dev.py {posargs} + + +[testenv:py39-be] +deps = better-exceptions +commands = coverage run -m pytest tests/test_dev.py {posargs} + + +[testenv:py39-rich] +deps = rich +commands = coverage run -m pytest tests/test_dev.py {posargs} + + [testenv:docs] # Keep basepython in sync with gh-actions and .readthedocs.yml. basepython = python3.8 From 1daabc25ee1cd958f47e5ab475e4e65940688486 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 28 Aug 2021 16:49:31 +0200 Subject: [PATCH 0511/1520] Drop sphinx-toolbox Unfortunately the frequent breakage is not worth the convenience. :( --- docs/api.rst | 12 ++++++++++-- docs/conf.py | 3 +-- docs/custom-wrappers.rst | 2 +- docs/performance.rst | 2 +- setup.py | 12 +----------- src/structlog/types.py | 9 ++++----- 6 files changed, 18 insertions(+), 22 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 01f7d02a..38af5cda 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -297,7 +297,7 @@ Please see :doc:`thread-local` for details. .. automodule:: structlog.types -.. autoprotocol:: BindableLogger +.. autoclass:: BindableLogger Additionally to the methods listed below, bound loggers **must** have a ``__init__`` method with the following signature: @@ -308,7 +308,15 @@ Please see :doc:`thread-local` for details. They currently also have to carry a `Context` as a ``_context`` attribute. -.. autoprotocol:: FilteringBoundLogger + .. note:: + + Currently Sphinx has no support for Protocols, so please click ``[source]`` for this entry to see the full definition. + +.. autoclass:: FilteringBoundLogger + + .. note:: + + Currently Sphinx has no support for Protocols, so please click ``[source]`` for this entry to see the full definition. .. autodata:: EventDict .. autodata:: WrappedLogger diff --git a/docs/conf.py b/docs/conf.py index c19a4b0a..5a14e6d6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -35,7 +35,6 @@ def find_version(*file_paths): "sphinx.ext.doctest", "sphinx.ext.intersphinx", "sphinx.ext.viewcode", - "sphinx_toolbox.more_autodoc.autoprotocol", ] # Add any paths that contain templates here, relative to this directory. @@ -70,7 +69,7 @@ def find_version(*file_paths): ("py:class", "BinaryIO"), ("py:class", "ILogObserver"), ("py:class", "PlainFileObserver"), - ("py:class", "TLLogger"), + ("py:class", "structlog.threadlocal.TLLogger"), ("py:class", "TextIO"), ("py:class", "traceback"), ("py:class", "structlog._base.BoundLoggerBase"), diff --git a/docs/custom-wrappers.rst b/docs/custom-wrappers.rst index 7133475d..74916dc7 100644 --- a/docs/custom-wrappers.rst +++ b/docs/custom-wrappers.rst @@ -51,7 +51,7 @@ It's much easier to demonstrate with an example: You can observe the following: - The wrapped logger can be found in the instance variable `structlog.BoundLoggerBase._logger`. -- The helper method `structlog.BoundLoggerBase._proxy_to_logger` that is a DRY_ convenience function that runs the processor chain, handles possible `DropEvent`\ s and calls a named function on `_logger`. +- The helper method `structlog.BoundLoggerBase._proxy_to_logger` that is a DRY_ convenience function that runs the processor chain, handles possible `structlog.DropEvent`\ s and calls a named function on `_logger`. - You can run the chain by hand through using `structlog.BoundLoggerBase._process_event` . These two methods and one attribute are all you need to write own wrapper classes. diff --git a/docs/performance.rst b/docs/performance.rst index d1b203ca..e22ec4a7 100644 --- a/docs/performance.rst +++ b/docs/performance.rst @@ -80,7 +80,7 @@ It has the following properties: - Renders exceptions. - Adds an `ISO 8601 `_ timestamp under the ``timestamp`` key in the UTC timezone. - Renders the log entries as JSON using orjson_ which is faster than plain logging in `logging`. -- Uses `BytesLoggerFactory` because orjson returns bytes. +- Uses `structlog.BytesLoggerFactory` because orjson returns bytes. That saves encoding ping-pong. Therefore a log entry might look like this: diff --git a/setup.py b/setup.py index 9719690b..00f52763 100644 --- a/setup.py +++ b/setup.py @@ -53,17 +53,7 @@ "pytest>=6.0", "simplejson", ], - "docs": [ - "furo", - "sphinx", - "twisted", - # Explicitly list sphinx-toolbox dependencies. - # Unfortunately they break very frequently. - "sphinx-toolbox<2.12", - "apeye<1.0", - "cachecontrol", - "lockfile", - ], + "docs": ["furo", "sphinx", "twisted"], } EXTRAS_REQUIRE["dev"] = ( EXTRAS_REQUIRE["tests"] + EXTRAS_REQUIRE["docs"] + ["pre-commit"] diff --git a/src/structlog/types.py b/src/structlog/types.py index 7db8f72c..199a7066 100644 --- a/src/structlog/types.py +++ b/src/structlog/types.py @@ -95,8 +95,8 @@ @runtime_checkable class BindableLogger(Protocol): """ - Methods shared among all bound loggers and that are relied on by - ``structlog``. + **Protocol**: Methods shared among all bound loggers and that are relied on + by ``structlog``. .. versionadded:: 20.2 """ @@ -118,10 +118,9 @@ def new(self, **new_values: Any) -> "BindableLogger": class FilteringBoundLogger(BindableLogger, Protocol): """ - A `BindableLogger` that filters by a level. + **Protocol**: A `BindableLogger` that filters by a level. - Currently, the only way to instantiate one is using - `make_filtering_bound_logger`. + The only way to instantiate one is using `make_filtering_bound_logger`. .. versionadded:: 20.2.0 """ From deda44e736b98d6f974d47e6b0dbf0cb9efc9357 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 28 Aug 2021 17:02:09 +0200 Subject: [PATCH 0512/1520] Shuffle tox envs and ensure lint runs in CI --- tox.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tox.ini b/tox.ini index b74bc0de..8dae0a65 100644 --- a/tox.ini +++ b/tox.ini @@ -6,9 +6,9 @@ ignore = E203,W503,W504 python = 3.6: py36 3.7: py37 - 3.8: py38, docs - 3.9: py39, manifest, mypy, docs - 3.10: py310 + 3.8: py38, docs, lint + 3.9: py39, manifest + 3.10: py310, mypy pypy3: pypy3 @@ -28,7 +28,7 @@ commands = pre-commit run --all-files [testenv:mypy] description = Check types -basepython = python3.9 +basepython = python3.10 extras = tests # Need twisted & rich for stubs # Otherwise mypy fails in tox. From 205f8a768705031776a855e3aa8623f26f2dfd3c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 29 Aug 2021 09:35:27 +0200 Subject: [PATCH 0513/1520] Fix tox -p --- tox.ini | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tox.ini b/tox.ini index 8dae0a65..00501a36 100644 --- a/tox.ini +++ b/tox.ini @@ -42,8 +42,7 @@ commands = mypy src typing_examples.py [testenv] extras = tests deps = - greenlets: greenlet - threads,greenlets,colorama: twisted + threads,colorama: twisted setenv = PYTHONHASHSEED = 0 commands = python -m pytest {posargs} @@ -126,7 +125,7 @@ basepython = python3.9 deps = coverage[toml] skip_install = true parallel_show_output = true -depends = {py36,py37,py38,py39}-threads,{py38,py39}-greenlets,py39-colorama,py39-be +depends = {py36,py37,py38,py39}-threads,py39-greenlets,py39-colorama,py39-be,py39-rich commands = coverage combine coverage report From ddc709cf492d8235b9799ed453e49a540c66a211 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 30 Aug 2021 15:13:57 +0200 Subject: [PATCH 0514/1520] Update exclude_lines --- pyproject.toml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index beda7562..beeb88ae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,12 +24,18 @@ source = ["src", ".tox/*/site-packages"] show_missing = true skip_covered = true exclude_lines = [ - "pragma: no cover", - "if TYPE_CHECKING:", - "raise NotImplementedError", + # a more strict default pragma + "\\# pragma: no cover\\b", + + # allow defensive code + "^\\s*raise AssertionError\\b", + "^\\s*raise NotImplementedError\\b", + "^\\s*return NotImplemented\\b", + "^\\s*raise$", + # typing-related code "^if (False|TYPE_CHECKING):", - ": \\.\\.\\.$", + ": \\.\\.\\.(\\s*#.*)?$", "^ +\\.\\.\\.$", "-> ['\"]?NoReturn['\"]?:", ] From d2349eaebb2d8b1e4f628d76bc2a3eab4f52b2a7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 31 Aug 2021 07:22:27 +0200 Subject: [PATCH 0515/1520] Run mypy on Python 3.9 Looks like 3.10 is broken. --- tox.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tox.ini b/tox.ini index 00501a36..836f966a 100644 --- a/tox.ini +++ b/tox.ini @@ -7,8 +7,8 @@ python = 3.6: py36 3.7: py37 3.8: py38, docs, lint - 3.9: py39, manifest - 3.10: py310, mypy + 3.9: py39, manifest, mypy + 3.10: py310 pypy3: pypy3 @@ -28,7 +28,7 @@ commands = pre-commit run --all-files [testenv:mypy] description = Check types -basepython = python3.10 +basepython = python3.9 extras = tests # Need twisted & rich for stubs # Otherwise mypy fails in tox. From 6bd5b32ea58a9f9a8edfd846284f918b78fe3468 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 31 Aug 2021 05:25:29 +0000 Subject: [PATCH 0516/1520] [pre-commit.ci] pre-commit autoupdate (#351) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/psf/black: 21.7b0 → 21.8b0](https://github.com/psf/black/compare/21.7b0...21.8b0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Hynek Schlawack --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 16d8f13e..411a62d1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ --- repos: - repo: https://github.com/psf/black - rev: 21.7b0 + rev: 21.8b0 hooks: - id: black language_version: python3.8 From 54538731c763950e577896d44b10a1a7e50be137 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 1 Sep 2021 07:19:39 +0200 Subject: [PATCH 0517/1520] Support bytearrays as last return value (#350) --- CHANGELOG.rst | 2 ++ docs/processors.rst | 2 +- src/structlog/_base.py | 8 ++++++-- src/structlog/types.py | 2 +- tests/test_base.py | 10 ++++++++++ 5 files changed, 20 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2b4d49b2..4332c706 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -39,6 +39,8 @@ Changes: - All use of ``colorama`` on non-Windows systems has been excised. Thus, colors are now enabled by default in ``structlog.dev.ConsoleRenderer`` on non-Windows systems. You can keep using ``colorama`` to customize colors, of course. +- The final processor can now return a ``bytearray`` (additionally to ``str`` and ``bytes``). + `#344 `_ ---- diff --git a/docs/processors.rst b/docs/processors.rst index 40cca26e..427c63ca 100644 --- a/docs/processors.rst +++ b/docs/processors.rst @@ -101,7 +101,7 @@ With that, it's also the *only* processor that needs to know anything about the It can return one of three types: -- An Unicode string or a bytes string (i.e. `str` or `bytes`) that is passed as the first (and only) positional argument to the underlying logger. +- An Unicode string (`str`), a bytes string (`bytes`), or a `bytearray` that is passed as the first (and only) positional argument to the underlying logger. - A tuple of ``(args, kwargs)`` that are passed as ``log_method(*args, **kwargs)``. - A dictionary which is passed as ``log_method(**kwargs)``. diff --git a/src/structlog/_base.py b/src/structlog/_base.py index ec6a2a8f..8c97ac93 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -131,7 +131,7 @@ def _process_event( :raises: `structlog.DropEvent` if log entry should be dropped. :raises: `ValueError` if the final processor doesn't return a - str, bytes, tuple, or a dict. + str, bytes, bytearray, tuple, or a dict. :returns: `tuple` of ``(*args, **kw)`` @@ -143,6 +143,10 @@ def _process_event( .. versionchanged:: 14.0.0 Allow final processor to return a `dict`. + .. versionchanged:: 20.2.0 + Allow final processor to return `bytes`. + .. versionchanged:: 21.2.0 + Allow final processor to return a `bytearray`. """ # We're typing it as Any, because processors can return more than an # EventDict. @@ -154,7 +158,7 @@ def _process_event( for proc in self._processors: event_dict = proc(self._logger, method_name, event_dict) - if isinstance(event_dict, (str, bytes)): + if isinstance(event_dict, (str, bytes, bytearray)): return (event_dict,), {} elif isinstance(event_dict, tuple): # In this case we assume that the last processor returned a tuple diff --git a/src/structlog/types.py b/src/structlog/types.py index 199a7066..c4a0dd4d 100644 --- a/src/structlog/types.py +++ b/src/structlog/types.py @@ -64,7 +64,7 @@ Processor = Callable[ [WrappedLogger, str, EventDict], - Union[Mapping[str, Any], str, bytes, Tuple[Any, ...]], + Union[Mapping[str, Any], str, bytes, bytearray, Tuple[Any, ...]], ] """ A callable that is part of the processor chain. diff --git a/tests/test_base.py b/tests/test_base.py index 4021a3e7..62994611 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -186,6 +186,16 @@ def test_last_processor_returns_bytes(self): assert ((b"foo",), {}) == b._process_event(None, "name", {}) + def test_last_processor_returns_bytearray(self): + """ + If the final processor returns a bytearray, ``(the_array,), {}`` is + returned. + """ + logger = stub(msg=lambda *args, **kw: (args, kw)) + b = build_bl(logger, processors=[lambda *_: bytearray(b"foo")]) + + assert ((bytearray(b"foo"),), {}) == b._process_event(None, "name", {}) + def test_last_processor_returns_tuple(self): """ If the final processor returns a tuple, it is just passed through. From 9d0d550c5564bd322639b07b5d9b7f78bc555d1f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 16 Sep 2021 11:09:31 +0200 Subject: [PATCH 0518/1520] Add another warning --- docs/standard-library.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/standard-library.rst b/docs/standard-library.rst index fe56571f..17546637 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -202,7 +202,9 @@ Rendering Using `logging`-based Formatters structlog.processors.UnicodeDecoder(), # Transform event dict into `logging.Logger` method arguments. # "event" becomes "msg" and the rest is passed as a dict in - # "extra". + # "extra". IMPORTANT: This means that the standard library MUST + # render "extra" for the context to appear in log entries! See + # warning below. structlog.stdlib.render_to_log_kwargs, ], logger_factory=structlog.stdlib.LoggerFactory(), From 3a08abda598165e5690e866e2cdb59e45b0ef626 Mon Sep 17 00:00:00 2001 From: Joshua Bronson Date: Sun, 19 Sep 2021 12:45:33 -0400 Subject: [PATCH 0519/1520] Add reset_contextvars and update bind_contextvars (#339) structlog.contextvars.bind_contextvars() now returns a Mapping[str, contextvar.Token] corresponding to the results of setting the requested contextvars. This return value is suitable for use with the newly-added structlog.contextvars.reset_contextvars() function, which resets the requested contextvars to their previous values using the given Tokens. --- CHANGELOG.rst | 1 + docs/api.rst | 1 + docs/conf.py | 5 ++++- docs/contextvars.rst | 16 ++++++++++++++++ src/structlog/contextvars.py | 30 +++++++++++++++++++++++++----- tests/test_contextvars.py | 25 +++++++++++++++++++++++++ 6 files changed, 72 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4332c706..66200c55 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -41,6 +41,7 @@ Changes: You can keep using ``colorama`` to customize colors, of course. - The final processor can now return a ``bytearray`` (additionally to ``str`` and ``bytes``). `#344 `_ +- ``structlog.contextvars.bind_contextvars()`` now returns a mapping of keys to ``contextvars.Token``\s, allowing you to reset values using the new ``structlog.contextvars.reset_contextvars()``. ---- diff --git a/docs/api.rst b/docs/api.rst index 38af5cda..c5f46165 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -176,6 +176,7 @@ Please see :doc:`thread-local` for details. .. autofunction:: merge_contextvars .. autofunction:: clear_contextvars .. autofunction:: unbind_contextvars +.. autofunction:: reset_contextvars .. _procs: diff --git a/docs/conf.py b/docs/conf.py index 5a14e6d6..c07640f3 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -71,7 +71,10 @@ def find_version(*file_paths): ("py:class", "PlainFileObserver"), ("py:class", "structlog.threadlocal.TLLogger"), ("py:class", "TextIO"), + ("py:class", "TLLogger"), + ("py:class", "Token"), ("py:class", "traceback"), + ("py:class", "contextvars.Token"), ("py:class", "structlog._base.BoundLoggerBase"), ("py:class", "structlog.dev._Styles"), ("py:class", "structlog.types.EventDict"), @@ -163,4 +166,4 @@ def find_version(*file_paths): # Twisted's trac tends to be slow linkcheck_timeout = 300 -intersphinx_mapping = {"https://docs.python.org/3": None} +intersphinx_mapping = {"python": ("https://docs.python.org/3", None)} diff --git a/docs/contextvars.rst b/docs/contextvars.rst index 58d69605..d3649400 100644 --- a/docs/contextvars.rst +++ b/docs/contextvars.rst @@ -47,6 +47,7 @@ The general flow is: >>> # values: >>> clear_contextvars() >>> bind_contextvars(a=1, b=2) + {'a': at ...>, 'b': at ...>} >>> # Then use loggers as per normal >>> # (perhaps by using structlog.get_logger() to create them). >>> log.msg("hello") @@ -61,3 +62,18 @@ The general flow is: >>> clear_contextvars() >>> log.msg("hi there") event='hi there' a=None + + +If e.g. your request handler calls a helper function that needs to temporarily override some contextvars before restoring them back to their original values, you can use the :class:`~contextvars.contextvars.Token`\s returned by :func:`~structlog.contextvars.bind_contextvars` along with :func:`~structlog.contextvars.reset_contextvars` to accomplish this (much like how :meth:`contextvars.ContextVar.reset` works): + +.. code-block:: python + + def foo(): + bind_contextvars(a=1) + _helper() + log.msg("a is restored!") # a=1 + + def _helper(): + tokens = bind_contextvars(a=2) + log.msg("a is overridden") # a=2 + reset_contextvars(**tokens) diff --git a/src/structlog/contextvars.py b/src/structlog/contextvars.py index 91ea223d..9a05c47f 100644 --- a/src/structlog/contextvars.py +++ b/src/structlog/contextvars.py @@ -16,7 +16,7 @@ import contextvars -from typing import Any, Dict +from typing import Any, Dict, Mapping import structlog @@ -98,16 +98,22 @@ def clear_contextvars() -> None: k.set(Ellipsis) -def bind_contextvars(**kw: Any) -> None: - """ +def bind_contextvars(**kw: Any) -> "Mapping[str, contextvars.Token[Any]]": + r""" Put keys and values into the context-local context. Use this instead of :func:`~structlog.BoundLogger.bind` when you want some context to be global (context-local). + Return the mapping of ``contextvars.Token``\s resulting + from setting the backing ``ContextVar``\s. + Suitable for passing to :func:`reset_contextvars`. + .. versionadded:: 20.1.0 - .. versionchanged:: 21.1.0 See toplevel note. + .. versionchanged:: 21.1.0 Return the ``contextvars.Token`` mapping + rather than None. See also the toplevel note. """ + rv = {} for k, v in kw.items(): structlog_k = f"{STRUCTLOG_KEY_PREFIX}{k}" try: @@ -116,7 +122,21 @@ def bind_contextvars(**kw: Any) -> None: var = contextvars.ContextVar(structlog_k, default=Ellipsis) _CONTEXT_VARS[structlog_k] = var - var.set(v) + rv[k] = var.set(v) + + return rv + + +def reset_contextvars(**kw: "contextvars.Token[Any]") -> None: + r""" + Reset contextvars corresponding to the given Tokens. + + .. versionadded:: 21.1.0 + """ + for k, v in kw.items(): + structlog_k = f"{STRUCTLOG_KEY_PREFIX}{k}" + var = _CONTEXT_VARS[structlog_k] + var.reset(v) def unbind_contextvars(*keys: str) -> None: diff --git a/tests/test_contextvars.py b/tests/test_contextvars.py index 4cf3b998..01539dcd 100644 --- a/tests/test_contextvars.py +++ b/tests/test_contextvars.py @@ -16,6 +16,7 @@ get_contextvars, get_merged_contextvars, merge_contextvars, + reset_contextvars, unbind_contextvars, ) @@ -63,6 +64,30 @@ async def coro(): "d": 4, } == await event_loop.create_task(coro()) + async def test_reset(self, event_loop): + """ + reset_contextvars allows resetting contexvars to + previously-set values. + """ + + async def coro(): + bind_contextvars(a=1) + + assert {"a": 1} == get_contextvars() + + await event_loop.create_task(nested_coro()) + + async def nested_coro(): + tokens = bind_contextvars(a=2, b=3) + + assert {"a": 2, "b": 3} == get_contextvars() + + reset_contextvars(**tokens) + + assert {"a": 1} == get_contextvars() + + await event_loop.create_task(coro()) + async def test_nested_async_bind(self, event_loop): """ Context is passed correctly between "nested" concurrent operations. From 90751b0c97cad64492e7bc3686997666461e4a68 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 21 Sep 2021 08:45:17 +0200 Subject: [PATCH 0520/1520] [pre-commit.ci] pre-commit autoupdate (#352) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/psf/black: 21.8b0 → 21.9b0](https://github.com/psf/black/compare/21.8b0...21.9b0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 411a62d1..59fe33c4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ --- repos: - repo: https://github.com/psf/black - rev: 21.8b0 + rev: 21.9b0 hooks: - id: black language_version: python3.8 From b4abfa4db9443b4c607edbab2126aa7c44ac8d9e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 6 Oct 2021 10:30:59 +0200 Subject: [PATCH 0521/1520] 3.10 is final --- .github/workflows/main.yml | 8 ++++---- tox.ini | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a7e00818..dd7a903f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,11 +13,11 @@ jobs: name: "Python ${{ matrix.python-version }}" runs-on: "ubuntu-latest" env: - USING_COVERAGE: "3.6,3.9" + USING_COVERAGE: "3.6,3.9,3.10" strategy: matrix: - python-version: ["3.6", "3.7", "3.8", "3.9", "3.10.0-beta - 3.10", "pypy3"] + python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "pypy3"] steps: - uses: "actions/checkout@v2" @@ -55,7 +55,7 @@ jobs: - uses: "actions/checkout@v2" - uses: "actions/setup-python@v2" with: - python-version: "3.9" + python-version: "3.10" - name: "Install build, check-wheel-content, and twine" run: "python -m pip install build twine check-wheel-contents" @@ -80,7 +80,7 @@ jobs: - uses: "actions/checkout@v2" - uses: "actions/setup-python@v2" with: - python-version: "3.9" + python-version: "3.10" - name: "Install in dev mode" run: "python -m pip install -e .[dev]" - name: "Import package" diff --git a/tox.ini b/tox.ini index 836f966a..600c42a4 100644 --- a/tox.ini +++ b/tox.ini @@ -14,7 +14,7 @@ python = [tox] # Currently, pypy3 is broken on macOS. Since we don't need it for coverage, we only test it in CI. -envlist = lint,mypy,{py36,py37,py38,py39,py310}-threads,py39-greenlets,py39-colorama,py39-be,py39-rich,docs,pypi-description,manifest,coverage-report +envlist = lint,mypy,{py36,py37,py38,py39,py310}-threads,py39-greenlets,py39-colorama,py310-be,py310-rich,docs,pypi-description,manifest,coverage-report isolated_build = True @@ -77,12 +77,12 @@ deps = colorama commands = coverage run -m pytest tests/test_dev.py {posargs} -[testenv:py39-be] +[testenv:py310-be] deps = better-exceptions commands = coverage run -m pytest tests/test_dev.py {posargs} -[testenv:py39-rich] +[testenv:py310-rich] deps = rich commands = coverage run -m pytest tests/test_dev.py {posargs} From da7f6f8b17e8516205831bdf936f8ac03bc5900a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 6 Oct 2021 10:33:40 +0200 Subject: [PATCH 0522/1520] Add PR link to changelog --- CHANGELOG.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 66200c55..21e83fe3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -42,6 +42,7 @@ Changes: - The final processor can now return a ``bytearray`` (additionally to ``str`` and ``bytes``). `#344 `_ - ``structlog.contextvars.bind_contextvars()`` now returns a mapping of keys to ``contextvars.Token``\s, allowing you to reset values using the new ``structlog.contextvars.reset_contextvars()``. + `#339 `_ ---- From 2f2c2c1e8835507c76c46d5aa6e3ace6aab579fe Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 6 Oct 2021 10:36:42 +0200 Subject: [PATCH 0523/1520] Update changelog --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 21e83fe3..ba709a0a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -16,7 +16,7 @@ Backward-incompatible changes: Make sure to remove ``format_exc_info`` from your processor chain if you configure ``structlog`` manually. This change is not really breaking, because the old use-case will keep working as before. - However if you pass ``pretty_exceptions=True`` (which is the default if the ``better-exceptions`` package is present), a warning will be raised and the exception will be renderered without prettyfication. + However if you pass ``pretty_exceptions=True`` (which is the default if either ``rich`` or ``better-exceptions`` is installed), a warning will be raised and the exception will be renderered without prettyfication. Deprecations: From 76017c7ec06a918d70c5a3dc360d87143b3b1fab Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 11 Oct 2021 21:35:09 +0200 Subject: [PATCH 0524/1520] [pre-commit.ci] pre-commit autoupdate (#355) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/PyCQA/flake8: 3.9.2 → 4.0.1](https://github.com/PyCQA/flake8/compare/3.9.2...4.0.1) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 59fe33c4..b8fe10e7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,7 +14,7 @@ repos: language_version: python3.8 - repo: https://github.com/PyCQA/flake8 - rev: 3.9.2 + rev: 4.0.1 hooks: - id: flake8 language_version: python3.8 From ed5b70efa485cc81297a1ab51f38807bfa5541c3 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 12 Oct 2021 14:24:38 +0200 Subject: [PATCH 0525/1520] Re-arrange and fix changelog --- CHANGELOG.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ba709a0a..21f271b3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -29,20 +29,21 @@ Changes: ^^^^^^^^ - ``structlog`` is now importable if ``sys.stdout`` is ``None`` (e.g. when running using ``pythonw``). +- ``structlog.threadlocal.get_threadlocal()`` and ``structlog.contextvars.get_contextvars()`` can now be used to get a copy of the current thread-local/context-local context that has been bound using ``structlog.threadlocal.bind_threadlocal()`` and ``structlog.contextvars.bind_contextvars()``. +- ``structlog.threadlocal.get_merged_threadlocal(bl)`` and ``structlog.contextvars.get_merged_contextvars(bl)`` do the same, but also merge the context from a bound logger *bl*. +- ``structlog.contextvars.bind_contextvars()`` now returns a mapping of keys to ``contextvars.Token``\s, allowing you to reset values using the new ``structlog.contextvars.reset_contextvars()``. + `#339 `_ - Exception rendering in ``structlog.dev.ConsoleLogger`` is now configurable using the ``exception_formatter`` setting. If either the `rich `_ or the `better-exceptions `_ package is present, ``structlog`` will use them for pretty-printing tracebacks. ``rich`` takes precedence over ``better-exceptions`` if both are present. This only works if ``format_exc_info`` is **absent** in the processor chain. -- ``structlog.threadlocal.get_threadlocal()`` and ``structlog.contextvars.get_threadlocal()`` can now be used to get a copy of the current thread-local/context-local context that has been bound using ``structlog.threadlocal.bind_threadlocal()`` and ``structlog.contextvars.bind_contextvars()``. -- ``structlog.threadlocal.get_merged_threadlocal(bl)`` and ``structlog.contextvars.get_merged_contextvars(bl)`` do the same, but also merge the context from a bound logger *bl*. - All use of ``colorama`` on non-Windows systems has been excised. Thus, colors are now enabled by default in ``structlog.dev.ConsoleRenderer`` on non-Windows systems. You can keep using ``colorama`` to customize colors, of course. + `#345 `_ - The final processor can now return a ``bytearray`` (additionally to ``str`` and ``bytes``). `#344 `_ -- ``structlog.contextvars.bind_contextvars()`` now returns a mapping of keys to ``contextvars.Token``\s, allowing you to reset values using the new ``structlog.contextvars.reset_contextvars()``. - `#339 `_ ---- From f610c7f1756920223ca030c9e1328d5745a27724 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 12 Oct 2021 14:25:20 +0200 Subject: [PATCH 0526/1520] Fix pypy3 explanation --- tox.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 600c42a4..82124321 100644 --- a/tox.ini +++ b/tox.ini @@ -13,7 +13,8 @@ python = [tox] -# Currently, pypy3 is broken on macOS. Since we don't need it for coverage, we only test it in CI. +# Running tests on pypy3 is very slow, we don't need it for coverage, and it's +# unlikely it'll ever break. Therefore, we only run it in CI -- just in case. envlist = lint,mypy,{py36,py37,py38,py39,py310}-threads,py39-greenlets,py39-colorama,py310-be,py310-rich,docs,pypi-description,manifest,coverage-report isolated_build = True From 7fccad9ef4bc18631e804a41df21568eb0a053aa Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 12 Oct 2021 14:26:52 +0200 Subject: [PATCH 0527/1520] Add rich to default dev env --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 00f52763..5a360636 100644 --- a/setup.py +++ b/setup.py @@ -56,7 +56,7 @@ "docs": ["furo", "sphinx", "twisted"], } EXTRAS_REQUIRE["dev"] = ( - EXTRAS_REQUIRE["tests"] + EXTRAS_REQUIRE["docs"] + ["pre-commit"] + EXTRAS_REQUIRE["tests"] + EXTRAS_REQUIRE["docs"] + ["pre-commit", "rich"] ) ############################################################################### From 175978436327f0888c183bed775bb830a4c1b097 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 12 Oct 2021 15:07:11 +0200 Subject: [PATCH 0528/1520] Stress processor return values --- docs/processors.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/processors.rst b/docs/processors.rst index 427c63ca..1e1699a2 100644 --- a/docs/processors.rst +++ b/docs/processors.rst @@ -26,6 +26,13 @@ Each processors receives three positional arguments: The return value of each processor is passed on to the next one as ``event_dict`` until finally the return value of the last processor gets passed into the wrapped logging method. +.. note:: + + ``structlog`` only looks at the return value of the **last** processor. + That means that as long as you control the next processor in the pipeline (i.e. the processor that will get your return value passed as an argument), you can return whatever you want. + + Returning a modified event dictionary from your processors is just a convention to make processors composable. + Examples ^^^^^^^^ @@ -112,6 +119,12 @@ This should give you enough power to use ``structlog`` with any logging system w .. versionchanged:: 14.0.0 Allow final processor to return a `dict`. +.. versionchanged:: 20.2.0 + Allow final processor to return a `bytes`. + +.. versionchanged:: 21.2.0 + Allow final processor to return a `bytearray`. + Examples ^^^^^^^^ From 8096b0d019c4e73565a9c2abd91940771550b931 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 12 Oct 2021 15:08:49 +0200 Subject: [PATCH 0529/1520] Use "chain" consistently --- docs/processors.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/processors.rst b/docs/processors.rst index 1e1699a2..7686d22d 100644 --- a/docs/processors.rst +++ b/docs/processors.rst @@ -29,7 +29,7 @@ The return value of each processor is passed on to the next one as ``event_dict` .. note:: ``structlog`` only looks at the return value of the **last** processor. - That means that as long as you control the next processor in the pipeline (i.e. the processor that will get your return value passed as an argument), you can return whatever you want. + That means that as long as you control the next processor in the chain (i.e. the processor that will get your return value passed as an argument), you can return whatever you want. Returning a modified event dictionary from your processors is just a convention to make processors composable. From 72872397f14be0344616dda22c90952f43234d1a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 12 Oct 2021 15:18:52 +0200 Subject: [PATCH 0530/1520] Add a bunch of PR links to changelog --- CHANGELOG.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 21f271b3..2d4844a0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -29,8 +29,12 @@ Changes: ^^^^^^^^ - ``structlog`` is now importable if ``sys.stdout`` is ``None`` (e.g. when running using ``pythonw``). + `#313 `_ - ``structlog.threadlocal.get_threadlocal()`` and ``structlog.contextvars.get_contextvars()`` can now be used to get a copy of the current thread-local/context-local context that has been bound using ``structlog.threadlocal.bind_threadlocal()`` and ``structlog.contextvars.bind_contextvars()``. + `#331 `_ + `#337 `_ - ``structlog.threadlocal.get_merged_threadlocal(bl)`` and ``structlog.contextvars.get_merged_contextvars(bl)`` do the same, but also merge the context from a bound logger *bl*. + Same pull requests as previous change. - ``structlog.contextvars.bind_contextvars()`` now returns a mapping of keys to ``contextvars.Token``\s, allowing you to reset values using the new ``structlog.contextvars.reset_contextvars()``. `#339 `_ - Exception rendering in ``structlog.dev.ConsoleLogger`` is now configurable using the ``exception_formatter`` setting. @@ -38,6 +42,8 @@ Changes: ``rich`` takes precedence over ``better-exceptions`` if both are present. This only works if ``format_exc_info`` is **absent** in the processor chain. + `#330 `_ + `#349 `_ - All use of ``colorama`` on non-Windows systems has been excised. Thus, colors are now enabled by default in ``structlog.dev.ConsoleRenderer`` on non-Windows systems. You can keep using ``colorama`` to customize colors, of course. From 429b13f200538d10a9fc5cb9d240c8dca9c5ca31 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 12 Oct 2021 15:20:48 +0200 Subject: [PATCH 0531/1520] Prepare 21.2.0 --- CHANGELOG.rst | 2 +- src/structlog/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2d4844a0..315cbe90 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,7 +5,7 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. -21.2.0 (UNRELEASED) +21.2.0 (2021-10-12) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 980ccd0a..ee4f6178 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -42,7 +42,7 @@ contextvars = None # type: ignore -__version__ = "21.2.0.dev0" +__version__ = "21.2.0" __title__ = "structlog" __description__ = "Structured Logging for Python" From 3142e507a2f32ee7ad16261ae89c8bcd96392c20 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 12 Oct 2021 15:32:07 +0200 Subject: [PATCH 0532/1520] Start new development cycle --- CHANGELOG.rst | 25 +++++++++++++++++++++++++ src/structlog/__init__.py | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 315cbe90..4fed3df0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,31 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. +21.3.0 (UNRELEASED) +------------------- + + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +*none* + + +Deprecations: +^^^^^^^^^^^^^ + +*none* + + +Changes: +^^^^^^^^ + +*none* + + +---- + + 21.2.0 (2021-10-12) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index ee4f6178..197a2e64 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -42,7 +42,7 @@ contextvars = None # type: ignore -__version__ = "21.2.0" +__version__ = "21.3.0.dev0" __title__ = "structlog" __description__ = "Structured Logging for Python" From 470e58c4999520e1a3e13938127a2f756d9f1657 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 14 Oct 2021 12:43:53 +0200 Subject: [PATCH 0533/1520] Update codecov to latest version --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index dd7a903f..0d8794b8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -43,7 +43,7 @@ jobs: if: "contains(env.USING_COVERAGE, matrix.python-version)" - name: Upload coverage to Codecov if: "contains(env.USING_COVERAGE, matrix.python-version)" - uses: "codecov/codecov-action@v1" + uses: "codecov/codecov-action@v2" with: fail_ci_if_error: true From 35e9f481269120aca7798d3d5e18d841feba56d8 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 14 Oct 2021 13:01:56 +0200 Subject: [PATCH 0534/1520] Update main.yml --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0d8794b8..c2582700 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -57,7 +57,7 @@ jobs: with: python-version: "3.10" - - name: "Install build, check-wheel-content, and twine" + - name: "Install build, check-wheel-contents, and twine" run: "python -m pip install build twine check-wheel-contents" - name: "Build package" run: "python -m build --sdist --wheel ." From c20b5f46e50df3f05cb2e97995b3fef1c8310db3 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 23 Oct 2021 13:41:13 +0200 Subject: [PATCH 0535/1520] Clean up links in getting started --- docs/getting-started.rst | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 45f99772..2c254855 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -10,16 +10,17 @@ Installation $ pip install structlog -If you want pretty exceptions in development (you know you do!), additionally install either `rich `_ or `better-exceptions `_. Try both to find out which one you like better -- the screenshot in the README and docs homepage is rendered by ``rich``. +If you want pretty exceptions in development (you know you do!), additionally install either rich_ or `better-exceptions`_. +Try both to find out which one you like better -- the screenshot in the README and docs homepage is rendered by ``rich``. -On Windows, you also have to install `colorama`_ if you want colorful output beside exceptions. +On Windows, you also have to install colorama_ if you want colorful output beside exceptions. Your First Log Entry -------------------- A lot of effort went into making ``structlog`` accessible without reading pages of documentation. -And indeed, the simplest possible usage looks like this: +And indeed, the simplest possible usage looks like this (if you're reading this on a small screen, you): .. doctest:: @@ -34,9 +35,9 @@ Here, ``structlog`` takes full advantage of its hopefully useful default setting - All keywords are formatted using `structlog.dev.ConsoleRenderer`. That in turn uses `repr` to serialize all values to strings. Thus, it's easy to add support for logging of your own objects\ [*]_. -- On Windows, if you have `colorama `_ installed, it's rendered in nice `colors `. +- On Windows, if you have colorama_ installed, it's rendered in nice `colors `. Other OSes do not need colorama for nice colors. -- If you have `better-exceptions `_ installed, exceptions will be rendered in colors and with additional helpful information. +- If you have rich_ or `better-exceptions`_ installed, exceptions will be rendered in colors and with additional helpful information. It should be noted that even in most complex logging setups the example would still look just like that thanks to `configuration`. Using the defaults, as above, is equivalent to:: @@ -199,3 +200,6 @@ If you want to see more code, make sure to check out the `examples`! .. _`standard out`: https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29 .. _recipe: https://docs.python.org/3/howto/logging-cookbook.html#implementing-structured-logging +.. _rich: https://github.com/willmcgugan/rich +.. _`better-exceptions`: https://github.com/qix-/better-exceptions +.. _colorama: https://pypi.org/project/colorama/ From 6bea84a0ab3cd33a63fefc2271d1213a118beafd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 23 Oct 2021 13:45:00 +0200 Subject: [PATCH 0536/1520] Finish sentence lol --- docs/getting-started.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 2c254855..786d5df8 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -20,7 +20,8 @@ Your First Log Entry -------------------- A lot of effort went into making ``structlog`` accessible without reading pages of documentation. -And indeed, the simplest possible usage looks like this (if you're reading this on a small screen, you): +And indeed, the simplest possible usage looks like this +(if you're reading this on a small screen, you may have to scroll the example horizontally to see the full output): .. doctest:: From ac5bb3f9c266da668d0ae9ee7a94379ae919eae4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 23 Oct 2021 14:03:03 +0200 Subject: [PATCH 0537/1520] Minor doc polish --- docs/configuration.rst | 2 +- docs/loggers.rst | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/configuration.rst b/docs/configuration.rst index 7aaf4778..13f928b4 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -38,7 +38,7 @@ Thus the :ref:`example ` from the previous chapter could have been written .. doctest:: config_get_logger - >>> configure(processors=[proc], context_class=dict) + >>> configure(processors=[proc]) >>> log = get_logger() >>> log.msg("hello world") I got called with {'event': 'hello world'} diff --git a/docs/loggers.rst b/docs/loggers.rst index e313691c..b8339ce4 100644 --- a/docs/loggers.rst +++ b/docs/loggers.rst @@ -28,21 +28,22 @@ Finally, if you call *any other* method on :class:`~structlog.BoundLogger`, it w #. Make a copy of the context -- now it becomes the *event dictionary*, #. Add the keyword arguments of the method call to the event dict. #. Add a new key ``event`` with the value of the first positional argument of the method call to the event dict. -#. Run the processors on the event dict. +#. Run the processors successively on the event dict. Each processor receives the result of its predecessor. -#. Finally it takes the result of the final processor and calls the method with the same name – that got called on the bound logger – on the wrapped logger\ [1]_. - For flexibility, the final processor can return either a string that is passed directly as a positional parameter, or a tuple ``(args, kwargs)`` that are passed as ``wrapped_logger.log_method(*args, **kwargs)``. +#. Finally, it takes the result of the final processor and calls the method with the same name – that got called on the bound logger – on the wrapped logger\ [1]_. + For flexibility, the final processor can return either a string\ [2]_ that is passed directly as a positional parameter, or a tuple ``(args, kwargs)`` that are passed as ``wrapped_logger.log_method(*args, **kwargs)``. .. [1] Since this is slightly magicy, ``structlog`` comes with concrete loggers for the `standard-library` and :doc:`twisted` that offer you explicit APIs for the supported logging methods but behave identically like the generic BoundLogger otherwise. Of course, you are free to implement your own bound loggers too. +.. [2] `str`, `bytes`, or `bytearray` to be exact. Creation -------- -You won't be instantiating it yourself though. -In practice you will configure ``structlog`` as explained in the `next chapter ` and then just call `structlog.get_logger`. +You won't be instantiating bound loggers yourself. +In practice you will configure ``structlog`` as explained in the `next chapter ` and then just call `structlog.get_logger`. In some rare cases you may not want to do that. @@ -102,7 +103,7 @@ Additionally, the following arguments are allowed too: **wrapper_class** A class to use instead of :class:`~structlog.BoundLogger` for wrapping. This is useful if you want to sub-class BoundLogger and add custom logging methods. - BoundLogger's bind/new methods are sub-classing friendly so you won't have to re-implement them. + BoundLogger's bind/new methods are sub-classing-friendly so you won't have to re-implement them. Please refer to the :ref:`related example ` for how this may look. **initial_values** From c2bae5c7a98e5d2c0f479960d0d8e65cc97a1904 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 23 Oct 2021 14:09:53 +0200 Subject: [PATCH 0538/1520] Simplify contextvars intro --- docs/contextvars.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/contextvars.rst b/docs/contextvars.rst index d3649400..4dbd1d97 100644 --- a/docs/contextvars.rst +++ b/docs/contextvars.rst @@ -12,13 +12,12 @@ Context Variables import structlog structlog.reset_defaults() -Historically, ``structlog`` only supported thread-local context binding. -With the introduction of :mod:`contextvars` in Python 3.7, there is now a way of having a global context that is local to the current context and even works in concurrent code such as code using :mod:`asyncio`. +With the introduction of :mod:`contextvars` in Python 3.7, there is a way of having a global context that is local to the current context and even works in concurrent code such as code using :mod:`asyncio`. For that ``structlog`` provides the `structlog.contextvars` module with a set of functions to bind variables to a context-local context. This context is safe to be used in asynchronous code. -The general flow is: +The general flow mirrors the one for :doc:`thread-local `: - Use `structlog.configure` with `structlog.contextvars.merge_contextvars` as your first processor. - Call `structlog.contextvars.clear_contextvars` at the beginning of your request handler (or whenever you want to reset the context-local context). From 5bcc9621f037d580685f768dac1785e72f229e1a Mon Sep 17 00:00:00 2001 From: Stefan Scherfke Date: Fri, 29 Oct 2021 13:12:41 +0200 Subject: [PATCH 0539/1520] Rename deprected "merge_threadlocal_context" to "merge_threadlocal" (#359) --- docs/performance.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/performance.rst b/docs/performance.rst index e22ec4a7..5657a57b 100644 --- a/docs/performance.rst +++ b/docs/performance.rst @@ -61,7 +61,7 @@ Here's an example for a production-ready non-asyncio ``structlog`` configuration cache_logger_on_first_use=True, wrapper_class=structlog.make_filtering_bound_logger(logging.INFO), processors=[ - structlog.threadlocal.merge_threadlocal_context, + structlog.threadlocal.merge_threadlocal, structlog.processors.add_log_level, structlog.processors.format_exc_info, structlog.processors.TimeStamper(fmt="iso", utc=True), From 7436c1b51c37449464e237865dcf096605b92515 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 1 Nov 2021 18:49:29 +0100 Subject: [PATCH 0540/1520] [pre-commit.ci] pre-commit autoupdate (#361) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/psf/black: 21.9b0 → 21.10b0](https://github.com/psf/black/compare/21.9b0...21.10b0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b8fe10e7..f4aa780f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ --- repos: - repo: https://github.com/psf/black - rev: 21.9b0 + rev: 21.10b0 hooks: - id: black language_version: python3.8 From 86e4e647d1e3a7680f9fc83590440dba9cd3e9f5 Mon Sep 17 00:00:00 2001 From: Kaspars Sprogis Date: Tue, 2 Nov 2021 15:38:02 +0100 Subject: [PATCH 0541/1520] Allow to preserve keys order in ConsoleRenderer. Related to #166 (#358) * Allow to preserve keys order in ConsoleRenderer. Related to #166 * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Add ConsoleRenderer new sort_keys param to changelog and populate ..versionadded * Remove obsolete OrderedDict for tests Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Hynek Schlawack --- CHANGELOG.rst | 3 ++- src/structlog/dev.py | 11 ++++++++++- tests/test_dev.py | 31 +++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4fed3df0..fe075bf6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,7 +24,8 @@ Deprecations: Changes: ^^^^^^^^ -*none* +- ``structlog.dev.ConsoleRenderer`` now has ``sort_keys`` boolean parameter which controls whether to sort keys when formatting keys output. `True` by default. + `#331 `_ ---- diff --git a/src/structlog/dev.py b/src/structlog/dev.py index af6ad361..7a66e3a5 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -235,6 +235,7 @@ class ConsoleRenderer: by default (rich_ taking precendence). You can also manually set it to `plain_traceback`, `better_traceback`, `rich_traceback`, or implement your own. + :param sort_keys: Whether to sort keys when formatting. `True` by default. Requires the colorama_ package if *colors* is `True` **on Windows**. @@ -265,6 +266,7 @@ class ConsoleRenderer: .. versionchanged:: 21.2 The colors keyword now defaults to True on non-Windows systems, and either True or False in Windows depending on whether colorama is installed. + .. versionadded:: 21.3.0 *sort_keys* """ def __init__( @@ -275,6 +277,7 @@ def __init__( repr_native_str: bool = False, level_styles: Optional[Styles] = None, exception_formatter: ExceptionFormatter = default_exception_formatter, + sort_keys: bool = True, ): styles: Styles if colors: @@ -316,6 +319,7 @@ def __init__( self._repr_native_str = repr_native_str self._exception_formatter = exception_formatter + self._sort_keys = sort_keys def _repr(self, val: Any) -> str: """ @@ -383,6 +387,11 @@ def __call__( stack = event_dict.pop("stack", None) exc = event_dict.pop("exception", None) exc_info = event_dict.pop("exc_info", None) + + event_dict_keys = event_dict.keys() + if self._sort_keys: + event_dict_keys = sorted(event_dict_keys) + sio.write( " ".join( self._styles.kv_key @@ -392,7 +401,7 @@ def __call__( + self._styles.kv_value + self._repr(event_dict[key]) + self._styles.reset - for key in sorted(event_dict.keys()) + for key in event_dict_keys ) ) diff --git a/tests/test_dev.py b/tests/test_dev.py index 3bb2b085..03a66fa9 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -208,6 +208,37 @@ def test_key_values(self, cr, styles, padded): + styles.reset ) == rv + def test_key_values_unsorted(self, styles, padded): + """ + Key-value pairs go in original order to the end. + """ + cr = dev.ConsoleRenderer(sort_keys=False) + + rv = cr( + None, + None, + {"event": "test", "key": "value", "foo": "bar"}, + ) + + assert ( + padded + + styles.kv_key + + "key" + + styles.reset + + "=" + + styles.kv_value + + "value" + + styles.reset + + " " + + styles.kv_key + + "foo" + + styles.reset + + "=" + + styles.kv_value + + "bar" + + styles.reset + ) == rv + @pytest.mark.parametrize("wrap", [True, False]) def test_exception_rendered(self, cr, padded, recwarn, wrap): """ From abc9312221547ed935e7b4f0904d2bf26f86516b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 2 Nov 2021 15:39:11 +0100 Subject: [PATCH 0542/1520] Update CHANGELOG.rst --- CHANGELOG.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index fe075bf6..1617244b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,8 +24,8 @@ Deprecations: Changes: ^^^^^^^^ -- ``structlog.dev.ConsoleRenderer`` now has ``sort_keys`` boolean parameter which controls whether to sort keys when formatting keys output. `True` by default. - `#331 `_ +- ``structlog.dev.ConsoleRenderer`` now has ``sort_keys`` boolean parameter that allows to disable the sorting of keys on output. + `#358 `_ ---- From a562e8b50b206024210dc56123e8f4a0dc367c67 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 2 Nov 2021 15:45:14 +0100 Subject: [PATCH 0543/1520] Fix types --- src/structlog/dev.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 7a66e3a5..0a70c259 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -12,7 +12,7 @@ import warnings from io import StringIO -from typing import Any, Optional, TextIO, Type, Union +from typing import Any, Iterable, Optional, TextIO, Type, Union from ._frames import _format_exception from .types import ( @@ -388,7 +388,7 @@ def __call__( exc = event_dict.pop("exception", None) exc_info = event_dict.pop("exc_info", None) - event_dict_keys = event_dict.keys() + event_dict_keys: Iterable[str] = event_dict.keys() if self._sort_keys: event_dict_keys = sorted(event_dict_keys) From 467d3c9c34192c571647c24e85ed9b0d562f7664 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 2 Nov 2021 15:55:09 +0100 Subject: [PATCH 0544/1520] Update AUTHORS.rst --- AUTHORS.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/AUTHORS.rst b/AUTHORS.rst index f9ee04d0..b1e56068 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -2,11 +2,10 @@ Authors ======= ``structlog`` is written and maintained by `Hynek Schlawack `_. -It’s inspired by previous work done by `Jean-Paul Calderone `_ and `David Reid `_. +It’s inspired by previous work by `Jean-Paul Calderone `_ and `David Reid `_. The development is kindly supported by `Variomedia AG `_. A full list of contributors can be found on GitHub’s `overview `_. -Some of them disapprove of the addition of thread local context data. :) The ``structlog`` logo has been contributed by `Russell Keith-Magee `_. From 5d5d391e2e48d733978c91da98a108365e7cf56b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 2 Nov 2021 16:19:22 +0100 Subject: [PATCH 0545/1520] Use latest pip for pypi-description tox target --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index 82124321..88ac9b42 100644 --- a/tox.ini +++ b/tox.ini @@ -111,6 +111,7 @@ deps = # lying around. depends = coverage-report commands = + pip install --upgrade pip pip wheel -w {envtmpdir}/build --no-deps . twine check {envtmpdir}/build/* From 3cda3ae2d60b0f0224a3a4e15014578c0fb09160 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 9 Nov 2021 07:30:41 +0100 Subject: [PATCH 0546/1520] [pre-commit.ci] pre-commit autoupdate (#363) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/PyCQA/isort: 5.9.3 → 5.10.0](https://github.com/PyCQA/isort/compare/5.9.3...5.10.0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f4aa780f..90a2caeb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,7 +7,7 @@ repos: language_version: python3.8 - repo: https://github.com/PyCQA/isort - rev: 5.9.3 + rev: 5.10.0 hooks: - id: isort additional_dependencies: [toml] From 88e73618f0756611aa6f25e8fc09f555b2d7ac24 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 10 Nov 2021 10:11:33 +0100 Subject: [PATCH 0547/1520] Bragging rights --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 3ddb435d..cef0271e 100644 --- a/README.rst +++ b/README.rst @@ -23,7 +23,7 @@ .. -begin-short- ``structlog`` makes logging in Python **faster**, **less painful**, and **more powerful** by adding **structure** to your log entries. -It has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio* or type hints along the way. +It has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio* or type hints along the way, and [influenced the design](https://twitter.com/sirupsen/status/638330548361019392) of [structured logging packages in other ecosystems](https://github.com/sirupsen/logrus). Thanks to its highly flexible design, it's up to you whether you want ``structlog`` to take care about the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's ``logging`` module. From 62f1eed3f6bfd42973a09f52d4e08d5df4104451 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 10 Nov 2021 12:31:10 +0100 Subject: [PATCH 0548/1520] Paul's blog is back online --- docs/why.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/why.rst b/docs/why.rst index c81c83ea..6a77f3f1 100644 --- a/docs/why.rst +++ b/docs/why.rst @@ -26,4 +26,4 @@ Structured logging means that you don't write hard-to-parse and hard-to-keep-con -.. _`Paul Querna`: https://web.archive.org/web/20170801134840/https://journal.paul.querna.org/articles/2011/12/26/log-for-machines-in-json/ +.. _`Paul Querna`: https://paul.querna.org/articles/2011/12/26/log-for-machines-in-json/ From 503e88e6fb211ec721108b802ecfbeb60ab303e0 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 10 Nov 2021 12:35:17 +0100 Subject: [PATCH 0549/1520] Argl RST --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index cef0271e..836a9d28 100644 --- a/README.rst +++ b/README.rst @@ -23,7 +23,7 @@ .. -begin-short- ``structlog`` makes logging in Python **faster**, **less painful**, and **more powerful** by adding **structure** to your log entries. -It has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio* or type hints along the way, and [influenced the design](https://twitter.com/sirupsen/status/638330548361019392) of [structured logging packages in other ecosystems](https://github.com/sirupsen/logrus). +It has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio* or type hints along the way, and `influenced the design `_ of `structured logging packages in other ecosystems `_. Thanks to its highly flexible design, it's up to you whether you want ``structlog`` to take care about the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's ``logging`` module. From 6650c69d22c0e5cf80bfe9ba3fced0fbc12af320 Mon Sep 17 00:00:00 2001 From: Moriyoshi Koizumi Date: Thu, 11 Nov 2021 13:47:28 +0900 Subject: [PATCH 0550/1520] Get TimeStamper working properly if datetime module is mocked before its instantiation (#364) * Get TimeStamper working properly if datetime module is mocked before the instantiation * Update CHANGELOG * Work around mypy bug Co-authored-by: Hynek Schlawack --- CHANGELOG.rst | 3 ++- src/structlog/processors.py | 18 ++++++++++++++---- tests/test_processors.py | 16 ++++++++++++++++ 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1617244b..3ca5f182 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -26,7 +26,8 @@ Changes: - ``structlog.dev.ConsoleRenderer`` now has ``sort_keys`` boolean parameter that allows to disable the sorting of keys on output. `#358 `_ - +- ``structlog.processors.TimeStamper`` now works well with FreezeGun even when it gets applied before the loggers are configured. + `#364 `_ ---- diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 4fcc074d..0ac47177 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -333,7 +333,17 @@ def _make_stamper( if fmt is None and not utc: raise ValueError("UNIX timestamps are always UTC.") - now = getattr(datetime.datetime, "utcnow" if utc else "now") + now: Callable[[], datetime.datetime] + + if utc: + + def now() -> datetime.datetime: + return datetime.datetime.utcnow() + + else: + + def now() -> datetime.datetime: + return datetime.datetime.now() if fmt is None: @@ -355,11 +365,11 @@ def stamper_iso_utc(event_dict: EventDict) -> EventDict: if utc: return stamper_iso_utc - else: - return stamper_iso_local + + return stamper_iso_local def stamper_fmt(event_dict: EventDict) -> EventDict: - event_dict[key] = now().strftime(fmt) + event_dict[key] = now().strftime(fmt) # type: ignore return event_dict diff --git a/tests/test_processors.py b/tests/test_processors.py index 47f2a6cf..eb050762 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -274,6 +274,22 @@ def test_pickle(self, fmt, utc, key, proto): None, None, {} ) + @pytest.mark.parametrize( + ("utc", "expect"), + [ + (True, "1980-03-25T16:00:00Z"), + (False, "1980-03-25T17:00:00"), + ], + ) + def test_apply_freezegun_after_instantiation(self, utc, expect): + """ + Instantiate TimeStamper after mocking datetime + """ + ts = TimeStamper(fmt="iso", utc=utc) + with freeze_time("1980-03-25 16:00:00", tz_offset=1): + d = ts(None, None, {}) + assert expect == d["timestamp"] + class TestFormatExcInfo: @pytest.mark.parametrize("ei", [False, None, ""]) From 8735cd09874fce1290efceba68f8e4bf7ca9d73c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 11 Nov 2021 06:59:16 +0100 Subject: [PATCH 0551/1520] stdlib/aio: Determine running loop for each log call aiothtp 3.8 started starting new loops on each run_app() which breaks if we cache the loop within loggers. This also ensures that it's possible to use `sync_bl` outside of loops. --- CHANGELOG.rst | 3 +++ src/structlog/stdlib.py | 5 +++-- tests/test_stdlib.py | 11 +++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 3ca5f182..3a7d4995 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -28,6 +28,9 @@ Changes: `#358 `_ - ``structlog.processors.TimeStamper`` now works well with FreezeGun even when it gets applied before the loggers are configured. `#364 `_ +- ``structlog.stdlib.AsyncBoundLogger`` now determines the running loop when logging, not on instantiation. + That has a minor performance impact, but makes it more robust when loops change (e.g. ``aiohttp.web.run_app()``), or you want to use ``sync_bl`` *before* a loop has started. + ---- diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 0da98eae..51751d87 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -470,8 +470,9 @@ async def _dispatch_to_sync( """ ctx = contextvars.copy_context() - await self._loop.run_in_executor( - self._executor, partial(ctx.run, partial(meth, event, *args, **kw)) + await asyncio.get_running_loop().run_in_executor( + self._executor, + lambda: ctx.run(lambda: meth(event, *args, **kw)), ) async def debug(self, event: str, *args: Any, **kw: Any) -> None: diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 1dfd75f0..3b62e224 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -37,6 +37,7 @@ get_logger, render_to_log_kwargs, ) +from structlog.testing import CapturedCall from structlog.types import BindableLogger from .additional_frame import additional_frame @@ -849,6 +850,16 @@ async def _abl(cl): reason="AsyncBoundLogger is only for Python 3.7 and later.", ) class TestAsyncBoundLogger: + def test_sync_bl(self, abl, cl): + """ + AsyncBoungLogger.sync_bl works outside of loops. + """ + abl.sync_bl.info("test") + + assert [ + CapturedCall(method_name="info", args=(), kwargs={"event": "test"}) + ] == cl.calls + @pytest.mark.asyncio async def test_protocol(self, abl): """ From 2341bedb8393f9dc10d12506a0a428f3b2d256f4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 12 Nov 2021 05:51:50 +0100 Subject: [PATCH 0552/1520] PositionalArgumentsFormatter: use augmented assignment Closes #366 Co-authored-by: Markus Elfring --- src/structlog/stdlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 51751d87..d6baaa8e 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -592,7 +592,7 @@ def __call__( if len(args) == 1 and isinstance(args[0], dict) and args[0]: args = args[0] - event_dict["event"] = event_dict["event"] % args + event_dict["event"] %= args if self.remove_positional_args and args is not None: del event_dict["positional_args"] From 4137fddf99bb6b681205b73f69fea04cad9ec652 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 12 Nov 2021 06:37:17 +0100 Subject: [PATCH 0553/1520] Minor doc polish --- README.rst | 6 ++++-- docs/thread-local.rst | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 836a9d28..e8e55797 100644 --- a/README.rst +++ b/README.rst @@ -65,6 +65,8 @@ Since log entries are dictionaries, you can start binding and re-binding key/val >>> log.info("user.logged_in", happy=True) 2020-11-18 09:18.28 [info ] user.logged_in another_key=42 happy=True some_key=23 user=hynek +You can also bind key/value pairs to `thread-local storage `_ and `contextvars `_. + Powerful Pipelines ================== @@ -139,9 +141,9 @@ Project Information ``structlog`` is dual-licensed under `Apache License, version 2 `_ and `MIT `_, available from `PyPI `_, the source code can be found on `GitHub `_, the documentation at https://www.structlog.org/. -We collect useful third party extension in `our wiki `_. +We collect useful third-party extension in `our wiki `_. -``structlog`` targets Python 3.6 and newer, and PyPy3. +``structlog`` targets Python 3.6 and later; including PyPy3. ``structlog`` for Enterprise diff --git a/docs/thread-local.rst b/docs/thread-local.rst index 3d97eeb1..50b3c511 100644 --- a/docs/thread-local.rst +++ b/docs/thread-local.rst @@ -187,6 +187,7 @@ The convenience of having a thread-local context comes at a price though: Otherwise each log call will result in an instantiation of a temporary BoundLogger. See `configuration` for more details. + - It `doesn't play well `_ with `os.fork` and thus `multiprocessing` (unless configured to use the ``spawn`` start method). The general sentiment against thread-locals is that they're hard to test. In this case we feel like this is an acceptable trade-off. From e86e079f748f8e05259287d4b97efa370dec81ac Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 12 Nov 2021 08:34:31 +0100 Subject: [PATCH 0554/1520] Add missing word --- docs/thread-local.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/thread-local.rst b/docs/thread-local.rst index 50b3c511..168a479a 100644 --- a/docs/thread-local.rst +++ b/docs/thread-local.rst @@ -27,7 +27,7 @@ In an ideal world, you would just stick to its immutable\ [*]_ bound loggers and However, we realize that passing loggers around is rather clunky and intrusive in practice. And since `practicality beats purity `_, ``structlog`` ships with the `structlog.threadlocal` module to help you to safely have global context storage. -.. [*] In the spirit of Python's 'consenting adults', ``structlog`` doesn't enforce the immutability with technical means. +.. [*] In the spirit of Python's "consenting adults" principle, ``structlog`` doesn't enforce the immutability with technical means. However, if you don't meddle with undocumented data, the objects can be safely considered immutable. From 0b2f363f72367dc7c938cc32b31d59cf8be06f27 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 12 Nov 2021 09:40:18 +0100 Subject: [PATCH 0555/1520] Apply SPDX license IDs --- conftest.py | 2 +- docs/conf.py | 1 + setup.py | 1 + src/structlog/__init__.py | 1 + src/structlog/_base.py | 1 + src/structlog/_config.py | 1 + src/structlog/_frames.py | 1 + src/structlog/_generic.py | 1 + src/structlog/_greenlets.py | 1 + src/structlog/_log_levels.py | 6 ++++++ src/structlog/_loggers.py | 1 + src/structlog/_utils.py | 1 + src/structlog/contextvars.py | 1 + src/structlog/dev.py | 1 + src/structlog/exceptions.py | 1 + src/structlog/processors.py | 2 ++ src/structlog/testing.py | 1 + src/structlog/threadlocal.py | 2 ++ src/structlog/twisted.py | 1 + src/structlog/types.py | 5 +++++ tests/__init__.py | 1 + tests/additional_frame.py | 1 + tests/test_base.py | 2 +- tests/test_config.py | 2 +- tests/test_contextvars.py | 1 + tests/test_dev.py | 1 + tests/test_frames.py | 2 +- tests/test_generic.py | 2 +- tests/test_log_levels.py | 1 + tests/test_loggers.py | 2 +- tests/test_processors.py | 2 +- tests/test_stdlib.py | 1 + tests/test_testing.py | 2 +- tests/test_threadlocal.py | 2 +- tests/test_twisted.py | 2 +- tests/test_utils.py | 2 +- tests/utils.py | 1 + typing_examples.py | 5 +++++ 38 files changed, 53 insertions(+), 11 deletions(-) diff --git a/conftest.py b/conftest.py index 31dbb9d8..a25ba8ef 100644 --- a/conftest.py +++ b/conftest.py @@ -1,8 +1,8 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. - import logging import sys diff --git a/docs/conf.py b/docs/conf.py index c07640f3..49e679f7 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. diff --git a/setup.py b/setup.py index 5a360636..4dfd26fa 100644 --- a/setup.py +++ b/setup.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 197a2e64..dd95f741 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. diff --git a/src/structlog/_base.py b/src/structlog/_base.py index 8c97ac93..b59c554e 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. diff --git a/src/structlog/_config.py b/src/structlog/_config.py index af3a1360..536494b1 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. diff --git a/src/structlog/_frames.py b/src/structlog/_frames.py index 827cef84..fa2292de 100644 --- a/src/structlog/_frames.py +++ b/src/structlog/_frames.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. diff --git a/src/structlog/_generic.py b/src/structlog/_generic.py index 3f1ca421..bd6ce133 100644 --- a/src/structlog/_generic.py +++ b/src/structlog/_generic.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. diff --git a/src/structlog/_greenlets.py b/src/structlog/_greenlets.py index e539d4da..d5916d68 100644 --- a/src/structlog/_greenlets.py +++ b/src/structlog/_greenlets.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index 58942b9b..8eed9d0d 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -1,6 +1,12 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the MIT License. See the LICENSE file in the root of this +# repository for complete details. + """ Extracted log level data used by both stdlib and native log level filters. """ + import logging from typing import Any, Callable, Type diff --git a/src/structlog/_loggers.py b/src/structlog/_loggers.py index 4fe0efce..1a6a448a 100644 --- a/src/structlog/_loggers.py +++ b/src/structlog/_loggers.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. diff --git a/src/structlog/_utils.py b/src/structlog/_utils.py index dc803963..e9a9cecb 100644 --- a/src/structlog/_utils.py +++ b/src/structlog/_utils.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. diff --git a/src/structlog/contextvars.py b/src/structlog/contextvars.py index 9a05c47f..f565b692 100644 --- a/src/structlog/contextvars.py +++ b/src/structlog/contextvars.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 0a70c259..91bd1ebe 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. diff --git a/src/structlog/exceptions.py b/src/structlog/exceptions.py index 7a1d8732..5b3b3203 100644 --- a/src/structlog/exceptions.py +++ b/src/structlog/exceptions.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 0ac47177..c3194795 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. @@ -5,6 +6,7 @@ """ Processors useful regardless of the logging framework. """ + import datetime import json import operator diff --git a/src/structlog/testing.py b/src/structlog/testing.py index bfae4219..1b62392f 100644 --- a/src/structlog/testing.py +++ b/src/structlog/testing.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index 31df92e5..dfea798e 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. @@ -7,6 +8,7 @@ See `thread-local`. """ + import contextlib import threading import uuid diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index f791e38f..f88dc97d 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. diff --git a/src/structlog/types.py b/src/structlog/types.py index c4a0dd4d..04378fa2 100644 --- a/src/structlog/types.py +++ b/src/structlog/types.py @@ -1,3 +1,8 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the MIT License. See the LICENSE file in the root of this +# repository for complete details. + """ Type information used throughout ``structlog``. diff --git a/tests/__init__.py b/tests/__init__.py index 3476c5d2..ef4a7624 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. diff --git a/tests/additional_frame.py b/tests/additional_frame.py index c7a46a60..319b2a9b 100644 --- a/tests/additional_frame.py +++ b/tests/additional_frame.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. diff --git a/tests/test_base.py b/tests/test_base.py index 62994611..ed2eef8a 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -1,8 +1,8 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. - import pytest from pretend import raiser, stub diff --git a/tests/test_config.py b/tests/test_config.py index 89c700fe..769090cf 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -1,8 +1,8 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. - import abc import pickle import warnings diff --git a/tests/test_contextvars.py b/tests/test_contextvars.py index 01539dcd..bb5c776a 100644 --- a/tests/test_contextvars.py +++ b/tests/test_contextvars.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. diff --git a/tests/test_dev.py b/tests/test_dev.py index 03a66fa9..a590d628 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. diff --git a/tests/test_frames.py b/tests/test_frames.py index 5fa273ce..3aa878fd 100644 --- a/tests/test_frames.py +++ b/tests/test_frames.py @@ -1,8 +1,8 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. - import sys import pytest diff --git a/tests/test_generic.py b/tests/test_generic.py index 30138286..2813de09 100644 --- a/tests/test_generic.py +++ b/tests/test_generic.py @@ -1,8 +1,8 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. - import pickle import pytest diff --git a/tests/test_log_levels.py b/tests/test_log_levels.py index 1253475a..607a3400 100644 --- a/tests/test_log_levels.py +++ b/tests/test_log_levels.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. diff --git a/tests/test_loggers.py b/tests/test_loggers.py index fe533964..52049801 100644 --- a/tests/test_loggers.py +++ b/tests/test_loggers.py @@ -1,8 +1,8 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. - import copy import pickle import sys diff --git a/tests/test_processors.py b/tests/test_processors.py index eb050762..85e58e4b 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -1,8 +1,8 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. - import datetime import json import pickle diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 3b62e224..f47a6016 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. diff --git a/tests/test_testing.py b/tests/test_testing.py index 13d4ea50..ddbf70dd 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -1,8 +1,8 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. - import pytest from structlog import get_config, get_logger, reset_defaults, testing diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py index 7251a2a1..5b7ff71e 100644 --- a/tests/test_threadlocal.py +++ b/tests/test_threadlocal.py @@ -1,8 +1,8 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. - import threading import pytest diff --git a/tests/test_twisted.py b/tests/test_twisted.py index 817dd328..00775ff1 100644 --- a/tests/test_twisted.py +++ b/tests/test_twisted.py @@ -1,8 +1,8 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. - import json import pytest diff --git a/tests/test_utils.py b/tests/test_utils.py index 3e537e29..c7241ee9 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,8 +1,8 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. - import errno import pytest diff --git a/tests/utils.py b/tests/utils.py index a1157f4c..79630d75 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. diff --git a/typing_examples.py b/typing_examples.py index 33e061bc..3f9852a1 100644 --- a/typing_examples.py +++ b/typing_examples.py @@ -1,3 +1,8 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the MIT License. See the LICENSE file in the root of this +# repository for complete details. + """ Make sure our configuration examples actually pass the type checker. """ From b8175f6730f3228d87c5a4502b07b80c173a4177 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 12 Nov 2021 14:28:12 +0100 Subject: [PATCH 0556/1520] Consistency --- src/structlog/_generic.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/structlog/_generic.py b/src/structlog/_generic.py index bd6ce133..3c758e34 100644 --- a/src/structlog/_generic.py +++ b/src/structlog/_generic.py @@ -6,6 +6,7 @@ """ Generic bound logger that can wrap anything. """ + from functools import partial from typing import Any, Dict From 044d9196bae27d6e8f37e279cacec8392f6918d7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 12 Nov 2021 15:16:44 +0100 Subject: [PATCH 0557/1520] Clarify contextvars.Token problems in intersphinx --- docs/conf.py | 6 ++++-- docs/contextvars.rst | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 49e679f7..f715b650 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -73,14 +73,16 @@ def find_version(*file_paths): ("py:class", "structlog.threadlocal.TLLogger"), ("py:class", "TextIO"), ("py:class", "TLLogger"), - ("py:class", "Token"), ("py:class", "traceback"), - ("py:class", "contextvars.Token"), ("py:class", "structlog._base.BoundLoggerBase"), ("py:class", "structlog.dev._Styles"), ("py:class", "structlog.types.EventDict"), ("py:obj", "sync_bl"), ("py:obj", "entries"), + # XXX: Remove after docs builder has 3.8.13/3.9.9/3.10.1: + # C.f. https://github.com/python/cpython/pull/29533 + ("py:obj", "contextvars.Token"), + ("py:class", "contextvars.Token"), ] # If true, '()' will be appended to :func: etc. cross-reference text. diff --git a/docs/contextvars.rst b/docs/contextvars.rst index 4dbd1d97..1c3bc484 100644 --- a/docs/contextvars.rst +++ b/docs/contextvars.rst @@ -63,7 +63,7 @@ The general flow mirrors the one for :doc:`thread-local `: event='hi there' a=None -If e.g. your request handler calls a helper function that needs to temporarily override some contextvars before restoring them back to their original values, you can use the :class:`~contextvars.contextvars.Token`\s returned by :func:`~structlog.contextvars.bind_contextvars` along with :func:`~structlog.contextvars.reset_contextvars` to accomplish this (much like how :meth:`contextvars.ContextVar.reset` works): +If e.g. your request handler calls a helper function that needs to temporarily override some contextvars before restoring them back to their original values, you can use the :class:`~contextvars.Token`\s returned by :func:`~structlog.contextvars.bind_contextvars` along with :func:`~structlog.contextvars.reset_contextvars` to accomplish this (much like how :meth:`contextvars.ContextVar.reset` works): .. code-block:: python From 30d19e7a2ab253ff8059a02b19fa1431b54b2314 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 12 Nov 2021 16:32:42 +0100 Subject: [PATCH 0558/1520] Improve docs --- docs/loggers.rst | 19 ++++++++++++------- docs/thread-local.rst | 4 +--- docs/why.rst | 9 +++------ 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/loggers.rst b/docs/loggers.rst index b8339ce4..36bed069 100644 --- a/docs/loggers.rst +++ b/docs/loggers.rst @@ -5,16 +5,21 @@ Loggers Bound Loggers ------------- -The center of ``structlog`` is the immutable log wrapper :class:`~structlog.BoundLogger`. +The centerpiece of ``structlog`` that you will interact with most is called a *bound logger*. +It is what you get back from `structlog.get_logger()` and call your logging methods on. -.. image:: _static/BoundLogger.svg +It consists of three parts: -What it does is: +.. image:: _static/BoundLogger.svg -- Store a *context dictionary* with key-value pairs that should be part of every log entry, -- store a list of :doc:`processors ` that are called on every log entry, -- and store a *logger* that it's wrapping. - This *can* be standard library's `logging.Logger` but absolutely doesn't have to. +#. A *context dictionary* that you can *bind* key/value pairs to. + This dictionary is *merged* into each log entry that is logged from *this logger specifically*. + That means that every logger has it own context, but it is possible to have global contexts too using `thread-local data ` and :doc:`contextvars`. +#. A list of :doc:`processors ` that are called on every log entry. +#. And finally a *logger* that it's wrapping. + This wrapped logger is reponsible for the *output* of the log entry that has been returned by the last processor. + This *can* be standard library's `logging.Logger`, but absolutely doesn't have to. + Bound loggers themselves do *not* do any I/O themselves. To manipulate the context dictionary, it offers to: diff --git a/docs/thread-local.rst b/docs/thread-local.rst index 168a479a..cc105626 100644 --- a/docs/thread-local.rst +++ b/docs/thread-local.rst @@ -22,13 +22,11 @@ Immutability --- David Reid ``structlog`` does its best to have as little global state as possible to achieve its goals. -In an ideal world, you would just stick to its immutable\ [*]_ bound loggers and reap all the rewards of having purely `immutable state `_. +In an ideal world, you would just stick to its immutable bound loggers and reap all the rewards of having purely `immutable state `_. However, we realize that passing loggers around is rather clunky and intrusive in practice. And since `practicality beats purity `_, ``structlog`` ships with the `structlog.threadlocal` module to help you to safely have global context storage. -.. [*] In the spirit of Python's "consenting adults" principle, ``structlog`` doesn't enforce the immutability with technical means. - However, if you don't meddle with undocumented data, the objects can be safely considered immutable. The ``merge_threadlocal`` Processor diff --git a/docs/why.rst b/docs/why.rst index 6a77f3f1..0dbb5fa8 100644 --- a/docs/why.rst +++ b/docs/why.rst @@ -12,9 +12,10 @@ Why… I believe these presumptions are **no longer correct** in server side software. - ---`Paul Querna`_ + ---`Paul Querna `_ -Structured logging means that you don't write hard-to-parse and hard-to-keep-consistent prose in your logs but that you log *events* that happen in a *context* instead. +Structured logging means that you don't write hard-to-parse and hard-to-keep-consistent prose in your log. +Instead, you log *events* that happen in a *context* of key/value pairs. …structlog? @@ -23,7 +24,3 @@ Structured logging means that you don't write hard-to-parse and hard-to-keep-con .. include:: ../README.rst :start-after: -begin-spiel- :end-before: -end-spiel- - - - -.. _`Paul Querna`: https://paul.querna.org/articles/2011/12/26/log-for-machines-in-json/ From 8cae793c697c56a1c01831f09b68ee9d464588ec Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 12 Nov 2021 16:33:37 +0100 Subject: [PATCH 0559/1520] Curverize fonts in BoundLogger.svg Looked bad on mobile. --- docs/_static/BoundLogger.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_static/BoundLogger.svg b/docs/_static/BoundLogger.svg index 1418058f..62152411 100644 --- a/docs/_static/BoundLogger.svg +++ b/docs/_static/BoundLogger.svg @@ -1 +1 @@ -BoundLogger{ "user": "Guido", "ip": "8.8.8.8", }Context- censor_ip() - add_timestamp() - format_to_json()Processorslogging.LoggerWrapped Logger + From ff4af5e7af2884897ac214069e97a93cbd1c2eef Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 15 Nov 2021 09:42:52 +0100 Subject: [PATCH 0560/1520] stdlib: add Mermaid.js chart to explain data flow in integration --- .gitignore | 1 + docs/conf.py | 1 + docs/standard-library.rst | 66 +++++++++++++++++++++++++++++++++++---- setup.py | 2 +- 4 files changed, 63 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index e2dfc7bb..440e17e7 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ dist docs/_build htmlcov pip-wheel-metadata +build diff --git a/docs/conf.py b/docs/conf.py index f715b650..c5d7ed4a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -36,6 +36,7 @@ def find_version(*file_paths): "sphinx.ext.doctest", "sphinx.ext.intersphinx", "sphinx.ext.viewcode", + "sphinxcontrib.mermaid", ] # Add any paths that contain templates here, relative to this directory. diff --git a/docs/standard-library.rst b/docs/standard-library.rst index 17546637..90932251 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -119,6 +119,20 @@ Rendering Within ``structlog`` This is the simplest approach where ``structlog`` does all the heavy lifting and passes a fully-formatted string to ``logging``. Chances are, this is all you need. +.. mermaid:: + :align: center + + flowchart TD + User + structlog + stdlib[Standard Library\ne.g. logging.StreamHandler] + + User --> |"structlog.get_logger().info('foo')"| structlog + User --> |"logging.getLogger().info('foo')"| stdlib + structlog --> |"logging.getLogger().info(#quot;{'event': 'foo'}#quot;)"| stdlib ==> Output + + Output + A basic configuration to output structured logs in JSON format looks like this: .. code-block:: python @@ -187,6 +201,23 @@ In this case *only* your own logs are formatted as JSON: Rendering Using `logging`-based Formatters ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +You can choose to use ``structlog`` only for building the event dictionary and leave all formatting -- additionally to the output -- to the standard library. + +.. mermaid:: + :align: center + + flowchart TD + User + structlog + stdlib[Standard Library\ne.g. logging.StreamHandler] + + User --> |"structlog.get_logger().info('foo', bar=42)"| structlog + User --> |"logging.getLogger().info('foo')"| stdlib + structlog --> |"logging.getLogger().info('foo', extra={"bar": 42})"| stdlib ==> Output + + Output + + .. code-block:: python import structlog @@ -249,14 +280,37 @@ Now both ``structlog`` and ``logging`` will emit JSON logs: Rendering Using ``structlog``-based Formatters Within `logging` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -``structlog`` comes with a `ProcessorFormatter` that can be used as a `logging.Formatter` in any stdlib `Handler ` object. +Finally, the most ambitious approach. +Here, you use ``structlog``'s `ProcessorFormatter` as a `logging.Formatter`. + +This means that ``structlog`` is responsible for formatting both its own log entries, as well those coming from calls to the standard library. +Consequently, the output is the duty of the standard library too. + +.. mermaid:: + :align: center + + flowchart TD + User + structlog + structlog2[structlog] + stdlib["Standard Library"] + + User --> |"structlog.get_logger().info(#quot;foo#quot;, bar=42)"| structlog + User --> |"logging.getLogger().info(#quot;foo#quot;)"| stdlib + structlog --> |"logging.getLogger().info(event_dict, {#quot;extra#quot;: {#quot;_logger#quot;: logger, #quot;_name#quot;: name})"| stdlib + + stdlib --> |"structlog.stdlib.ProcessorFormatter.format(logging.Record)"| structlog2 + structlog2 --> |"Returns a string that is passed into logging handlers.\nThis flow is controlled by the logging configuration."| stdlib2 + + stdlib2[Standard Library\ne.g. logging.StreamHandler] ==> Output + -The `ProcessorFormatter` has two parts to its API: +`ProcessorFormatter` has two parts to its API: -#. The `structlog.stdlib.ProcessorFormatter.wrap_for_formatter` method must be used as the last processor in `structlog.configure`, - it converts the processed event dict to something that the ``ProcessorFormatter`` understands. -#. The `ProcessorFormatter` itself, - which can wrap any ``structlog`` renderer to handle the output of both ``structlog`` and standard library events. +#. Instead of a renderer, the `structlog.stdlib.ProcessorFormatter.wrap_for_formatter` static method must be used as the last processor in the :doc:`processor chain `. + It converts the processed event dictionary into something that `ProcessorFormatter` understands. +#. The `ProcessorFormatter` itself, whose ``format()`` method gets called by standard library `logging` for every log entry (if you configure `logging` correctly). + It can wrap any ``structlog`` renderer to handle the output of both ``structlog`` and standard library events. Thus, the simplest possible configuration looks like the following: diff --git a/setup.py b/setup.py index 4dfd26fa..c3443a62 100644 --- a/setup.py +++ b/setup.py @@ -54,7 +54,7 @@ "pytest>=6.0", "simplejson", ], - "docs": ["furo", "sphinx", "twisted"], + "docs": ["furo", "sphinx", "sphinxcontrib-mermaid", "twisted"], } EXTRAS_REQUIRE["dev"] = ( EXTRAS_REQUIRE["tests"] + EXTRAS_REQUIRE["docs"] + ["pre-commit", "rich"] From eb4b8178b9955d12fb3de795e6a9d525429280e0 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 15 Nov 2021 10:31:09 +0100 Subject: [PATCH 0561/1520] Looks like https://docs.python.org/3 fixed contextvars.Token --- docs/conf.py | 4 ---- src/structlog/contextvars.py | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index c5d7ed4a..aa1b47e5 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -80,10 +80,6 @@ def find_version(*file_paths): ("py:class", "structlog.types.EventDict"), ("py:obj", "sync_bl"), ("py:obj", "entries"), - # XXX: Remove after docs builder has 3.8.13/3.9.9/3.10.1: - # C.f. https://github.com/python/cpython/pull/29533 - ("py:obj", "contextvars.Token"), - ("py:class", "contextvars.Token"), ] # If true, '()' will be appended to :func: etc. cross-reference text. diff --git a/src/structlog/contextvars.py b/src/structlog/contextvars.py index f565b692..3831ded0 100644 --- a/src/structlog/contextvars.py +++ b/src/structlog/contextvars.py @@ -106,12 +106,12 @@ def bind_contextvars(**kw: Any) -> "Mapping[str, contextvars.Token[Any]]": Use this instead of :func:`~structlog.BoundLogger.bind` when you want some context to be global (context-local). - Return the mapping of ``contextvars.Token``\s resulting - from setting the backing ``ContextVar``\s. + Return the mapping of `contextvars.Token`\s resulting + from setting the backing :class:`~contextvars.ContextVar`\s. Suitable for passing to :func:`reset_contextvars`. .. versionadded:: 20.1.0 - .. versionchanged:: 21.1.0 Return the ``contextvars.Token`` mapping + .. versionchanged:: 21.1.0 Return the `contextvars.Token` mapping rather than None. See also the toplevel note. """ rv = {} From 023539aae8aebe4ccd2510f2c20d03328e940a26 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 15 Nov 2021 16:59:02 +0100 Subject: [PATCH 0562/1520] Use a marmaid theme that is readable on dark --- docs/standard-library.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/standard-library.rst b/docs/standard-library.rst index 90932251..2e23c188 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -123,6 +123,7 @@ Chances are, this is all you need. :align: center flowchart TD + %%{ init: {'theme': 'neutral'} }%% User structlog stdlib[Standard Library\ne.g. logging.StreamHandler] @@ -207,6 +208,7 @@ You can choose to use ``structlog`` only for building the event dictionary and l :align: center flowchart TD + %%{ init: {'theme': 'neutral'} }%% User structlog stdlib[Standard Library\ne.g. logging.StreamHandler] @@ -290,6 +292,7 @@ Consequently, the output is the duty of the standard library too. :align: center flowchart TD + %%{ init: {'theme': 'neutral'} }%% User structlog structlog2[structlog] From c0aac6f62fb812439a612357491007a7c27e8f45 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 15 Nov 2021 19:03:55 +0100 Subject: [PATCH 0563/1520] [pre-commit.ci] pre-commit autoupdate (#368) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/PyCQA/isort: 5.10.0 → 5.10.1](https://github.com/PyCQA/isort/compare/5.10.0...5.10.1) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 90a2caeb..0c86365e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,7 +7,7 @@ repos: language_version: python3.8 - repo: https://github.com/PyCQA/isort - rev: 5.10.0 + rev: 5.10.1 hooks: - id: isort additional_dependencies: [toml] From 81491810c0bff7e987b5889f36271f19cf2be233 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 16 Nov 2021 15:34:24 +0100 Subject: [PATCH 0564/1520] Add changelog to project URLs --- setup.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index c3443a62..3d326fbf 100644 --- a/setup.py +++ b/setup.py @@ -15,6 +15,7 @@ NAME = "structlog" KEYWORDS = ["logging", "structured", "structure", "log"] PROJECT_URLS = { + "Changelog": "https://www.structlog.org/en/stable/changelog.html", "Documentation": "https://www.structlog.org/", "Bug Tracker": "https://github.com/hynek/structlog/issues", "Source Code": "https://github.com/hynek/structlog", @@ -101,9 +102,9 @@ def find_meta(meta): VERSION = find_meta("version") LONG = ( - "==============================================\n" - "``structlog``: : Structured Logging for Python\n" - "==============================================\n" + "============================================\n" + "``structlog``: Structured Logging for Python\n" + "============================================\n" + read("README.rst").split(".. -begin-short-")[1] + "\n\n" + "Release Information\n" From 5e6ea9c04e070f7ef0106ff1256c58ef54c03686 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 17 Nov 2021 08:45:22 +0100 Subject: [PATCH 0565/1520] Switch to flit with dynamic metadata via cog --- CHANGELOG.rst | 3 +- MANIFEST.in | 13 -- pyproject.toml | 253 +++++++++++++++++++++++++++++++++++++- setup.py | 146 ---------------------- src/structlog/__init__.py | 5 +- tox.ini | 21 ++-- 6 files changed, 267 insertions(+), 174 deletions(-) delete mode 100644 MANIFEST.in delete mode 100644 setup.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 3a7d4995..96cdb7f0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,7 +12,8 @@ The third digit is only for regressions. Backward-incompatible changes: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -*none* +- ``structlog`` switched its packaging to `flit `_. + Users shouldn't notice a difference, but (re-)packagers might. Deprecations: diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 3d03bf62..00000000 --- a/MANIFEST.in +++ /dev/null @@ -1,13 +0,0 @@ -include LICENSE LICENSE.apache2 LICENSE.mit conftest.py -include *.rst -include src/structlog/py.typed typing_examples.py - -exclude show_off.py -include *.ini *.yml *.yaml *.toml -graft .github -graft tests -recursive-exclude tests *.pyc - -graft docs -prune docs/_build -prune tests/.mypy_cache diff --git a/pyproject.toml b/pyproject.toml index beeb88ae..75fcd1ec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,112 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 + [build-system] -requires = ["setuptools>=40.6.0", "wheel"] -build-backend = "setuptools.build_meta" +requires = ["flit_core >=3.2,<4"] +build-backend = "flit_core.buildapi" +[project] +name = "structlog" +authors = [{name = "Hynek Schlawack", email = "hs@ox.cx"}] +dynamic = ["version", "description"] +requires-python = ">=3.6" +dependencies = [ + "typing-extensions; python_version<'3.8'" +] +license = { file = "LICENSE" } +keywords = ["logging", "structured", "structure", "log"] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "License :: OSI Approved :: MIT License", + "Natural Language :: English", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Programming Language :: Python", + "Topic :: Software Development :: Libraries :: Python Modules", + "Topic :: System :: Logging", +] + +[project.urls] +Changelog = "https://www.structlog.org/en/stable/changelog.html" +Documentation = "https://www.structlog.org/" +"Bug Tracker" = "https://github.com/hynek/structlog/issues" +"Source Code" = "https://github.com/hynek/structlog" +Funding = "https://github.com/sponsors/hynek" +Tidelift = "https://tidelift.com/subscription/pkg/pypi-structlog?utm_source=pypi-structlog&utm_medium=pypi" +Ko-fi = "https://ko-fi.com/the_hynek" + +[tool.flit.sdist] +include = [ + ".pre-commit-config.yaml", + ".readthedocs.yml", + "codecov.yml", + "*.ini", + "*.rst", + "LICENSE.*", + "docs", + "tests", + ".github", + "show_off.py", + "typing_examples.py", +] +exclude = [ + "docs/_build", + "tests/__pycache__", + "tests/.mypy_cache", +] + +[project.optional-dependencies] +tests = [ + "coverage[toml]", + "freezegun>=0.2.8", + "pretend", + "pytest-asyncio", + "pytest>=6.0", + "simplejson", +] +docs = [ + "furo", + "sphinx", + "sphinxcontrib-mermaid", + "twisted", +] + +# We make `dev = [` part of the output so cog doesn't dedent the list. +# Refresh using `tox -e cog` +# [[[cog +# import cog, pathlib, tomli +# cfg = tomli.loads(pathlib.Path("pyproject.toml").read_text()) +# opt = cfg["project"]["optional-dependencies"] +# dev = ["pre-commit", "rich", "cogapp", "tomli"] +# cog.outl("dev = [") +# for dep in dev + opt["tests"] + opt["docs"]: +# cog.outl(f' "{dep}",') +# ]]] +dev = [ + "pre-commit", + "rich", + "cogapp", + "tomli", + "coverage[toml]", + "freezegun>=0.2.8", + "pretend", + "pytest-asyncio", + "pytest>=6.0", + "simplejson", + "furo", + "sphinx", + "sphinxcontrib-mermaid", + "twisted", +# [[[end]]] +] [tool.pytest.ini_options] addopts = "-ra --strict-markers " @@ -47,3 +152,147 @@ line-length = 79 [tool.isort] profile = "attrs" + + +[project.readme] +content-type = "text/x-rst" +# Load README.rst, but remove header and badges. +# Refresh using `tox -e cog` +# [[[cog +# import cog, pathlib +# cog.out('text = """') +# cog.out(pathlib.Path("README.rst").read_text().split(".. -begin-short-")[1].lstrip().replace('"""', r'\"\"\"') + '"""') +# ]]] +text = """``structlog`` makes logging in Python **faster**, **less painful**, and **more powerful** by adding **structure** to your log entries. +It has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio* or type hints along the way, and `influenced the design `_ of `structured logging packages in other ecosystems `_. + +Thanks to its highly flexible design, it's up to you whether you want ``structlog`` to take care about the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's ``logging`` module. + +.. image:: https://github.com/hynek/structlog/blob/main/docs/_static/console_renderer.png?raw=true + +.. -end-short- + +Once you feel inspired to try it out, check out our friendly `Getting Started tutorial `_ that also contains detailed installation instructions! + +.. -begin-spiel- + +If you prefer videos over reading, check out this DjangoCon Europe 2019 talk by `Markus Holtermann `_: "`Logging Rethought 2: The Actions of Frank Taylor Jr. `_". + + +Easier Logging +============== + +You can stop writing prose and start thinking in terms of an event that happens in the context of key/value pairs: + +.. code-block:: pycon + + >>> from structlog import get_logger + >>> log = get_logger() + >>> log.info("key_value_logging", out_of_the_box=True, effort=0) + 2020-11-18 09:17.09 [info ] key_value_logging effort=0 out_of_the_box=True + +Each log entry is a meaningful dictionary instead of an opaque string now! + + +Data Binding +============ + +Since log entries are dictionaries, you can start binding and re-binding key/value pairs to your loggers to ensure they are present in every following logging call: + +.. code-block:: pycon + + >>> log = log.bind(user="anonymous", some_key=23) + >>> log = log.bind(user="hynek", another_key=42) + >>> log.info("user.logged_in", happy=True) + 2020-11-18 09:18.28 [info ] user.logged_in another_key=42 happy=True some_key=23 user=hynek + +You can also bind key/value pairs to `thread-local storage `_ and `contextvars `_. + + +Powerful Pipelines +================== + +Each log entry goes through a `processor pipeline `_ that is just a chain of functions that receive a dictionary and return a new dictionary that gets fed into the next function. +That allows for simple but powerful data manipulation: + +.. code-block:: python + + def timestamper(logger, log_method, event_dict): + \"\"\"Add a timestamp to each log entry.\"\"\" + event_dict["timestamp"] = time.time() + return event_dict + +There are `plenty of processors `_ for most common tasks coming with ``structlog``: + +- Collectors of `call stack information `_ ("How did this log entry happen?"), +- …and `exceptions `_ ("What happened‽"). +- Unicode encoders/decoders. +- Flexible `timestamping `_. + + +Formatting +========== + +``structlog`` is completely flexible about *how* the resulting log entry is emitted. +Since each log entry is a dictionary, it can be formatted to **any** format: + +- A colorful key/value format for `local development `_, +- `JSON `_ for easy parsing, +- or some standard format you have parsers for like nginx or Apache httpd. + +Internally, formatters are processors whose return value (usually a string) is passed into loggers that are responsible for the output of your message. +``structlog`` comes with multiple useful formatters out-of-the-box. + + +Output +====== + +``structlog`` is also very flexible with the final output of your log entries: + +- A **built-in** lightweight printer like in the examples above. + Easy to use and fast. +- Use the **standard library**'s or **Twisted**'s logging modules for compatibility. + In this case ``structlog`` works like a wrapper that formats a string and passes them off into existing systems that won't ever know that ``structlog`` even exists. + Or the other way round: ``structlog`` comes with a ``logging`` formatter that allows for processing third party log records. +- Don't format it to a string at all! + ``structlog`` passes you a dictionary and you can do with it whatever you want. + Reported uses cases are sending them out via network or saving them in a database. + + +Highly Testable +=============== + +``structlog`` is thouroughly tested and we see it as our duty to help you to achieve the same in *your* applications. +That's why it ships with a `bunch of helpers `_ to introspect your application's logging behavior with little-to-no boilerplate. + +.. -end-spiel- + +.. -begin-meta- + +Getting Help +============ + +Please use the ``structlog`` tag on `StackOverflow `_ to get help. + +Answering questions of your fellow developers is also a great way to help the project! + + +Project Information +=================== + +``structlog`` is dual-licensed under `Apache License, version 2 `_ and `MIT `_, available from `PyPI `_, the source code can be found on `GitHub `_, the documentation at https://www.structlog.org/. + +We collect useful third-party extension in `our wiki `_. + +``structlog`` targets Python 3.6 and later; including PyPy3. + + +``structlog`` for Enterprise +---------------------------- + +Available as part of the Tidelift Subscription. + +The maintainers of structlog and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. +`Learn more. `_ +""" +# [[[end]]] diff --git a/setup.py b/setup.py deleted file mode 100644 index 3d326fbf..00000000 --- a/setup.py +++ /dev/null @@ -1,146 +0,0 @@ -# SPDX-License-Identifier: MIT OR Apache-2.0 -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the MIT License. See the LICENSE file in the root of this -# repository for complete details. - -import codecs -import os -import re - -from setuptools import find_packages, setup - - -############################################################################### - -NAME = "structlog" -KEYWORDS = ["logging", "structured", "structure", "log"] -PROJECT_URLS = { - "Changelog": "https://www.structlog.org/en/stable/changelog.html", - "Documentation": "https://www.structlog.org/", - "Bug Tracker": "https://github.com/hynek/structlog/issues", - "Source Code": "https://github.com/hynek/structlog", - "Funding": "https://github.com/sponsors/hynek", - "Tidelift": "https://tidelift.com/subscription/pkg/pypi-structlog?" - "utm_source=pypi-structlog&utm_medium=pypi", - "Ko-fi": "https://ko-fi.com/the_hynek", -} -CLASSIFIERS = [ - "Development Status :: 5 - Production/Stable", - "Intended Audience :: Developers", - "License :: OSI Approved :: Apache Software License", - "License :: OSI Approved :: MIT License", - "Natural Language :: English", - "Operating System :: OS Independent", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: Implementation :: CPython", - "Programming Language :: Python :: Implementation :: PyPy", - "Programming Language :: Python", - "Topic :: Software Development :: Libraries :: Python Modules", -] -PYTHON_REQUIRES = ">=3.6" -INSTALL_REQUIRES = [ - "typing-extensions; python_version<'3.8'", -] -EXTRAS_REQUIRE = { - "tests": [ - "coverage[toml]", - "freezegun>=0.2.8", - "pretend", - "pytest-asyncio", - "pytest>=6.0", - "simplejson", - ], - "docs": ["furo", "sphinx", "sphinxcontrib-mermaid", "twisted"], -} -EXTRAS_REQUIRE["dev"] = ( - EXTRAS_REQUIRE["tests"] + EXTRAS_REQUIRE["docs"] + ["pre-commit", "rich"] -) - -############################################################################### - -HERE = os.path.abspath(os.path.dirname(__file__)) - - -def read(*parts): - """ - Build an absolute path from *parts* and and return the contents of the - resulting file. Assume UTF-8 encoding. - """ - with codecs.open(os.path.join(HERE, *parts), "rb", "utf-8") as f: - return f.read() - - -try: - PACKAGES -except NameError: - PACKAGES = find_packages(where="src") - -try: - META_PATH -except NameError: - META_PATH = os.path.join(HERE, "src", NAME, "__init__.py") -finally: - META_FILE = read(META_PATH) - - -def find_meta(meta): - """ - Extract __*meta*__ from META_FILE. - """ - meta_match = re.search( - fr"^__{meta}__ = ['\"]([^'\"]*)['\"]", META_FILE, re.M - ) - if meta_match: - return meta_match.group(1) - raise RuntimeError(f"Unable to find __{ meta }__ string.") - - -VERSION = find_meta("version") -LONG = ( - "============================================\n" - "``structlog``: Structured Logging for Python\n" - "============================================\n" - + read("README.rst").split(".. -begin-short-")[1] - + "\n\n" - + "Release Information\n" - + "===================\n\n" - + re.search( - r"(\d+.\d.\d \(.*?\)\r?\n.*?)\r?\n\r?\n\r?\n----\r?\n\r?\n\r?\n", - read("CHANGELOG.rst"), - re.S, - ).group(1) - + "\n\n`Full changelog " - + "`_.\n\n" - + read("AUTHORS.rst") -) - -if __name__ == "__main__": - setup( - name=NAME, - description=find_meta("description"), - license=find_meta("license"), - url=find_meta("uri"), - project_urls=PROJECT_URLS, - version=VERSION, - author=find_meta("author"), - author_email=find_meta("email"), - maintainer=find_meta("author"), - maintainer_email=find_meta("email"), - long_description=LONG, - long_description_content_type="text/x-rst", - keywords=KEYWORDS, - packages=PACKAGES, - package_dir={"": "src"}, - classifiers=CLASSIFIERS, - python_requires=PYTHON_REQUIRES, - install_requires=INSTALL_REQUIRES, - extras_require=EXTRAS_REQUIRE, - include_package_data=True, - zip_safe=False, - options={"bdist_wheel": {"universal": "1"}}, - ) diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index dd95f741..e940699f 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -4,10 +4,9 @@ # repository for complete details. """ -Structured logging for Python. +Structured Logging for Python """ - from structlog import dev, processors, stdlib, testing, threadlocal, types from structlog._base import BoundLoggerBase, get_context from structlog._config import ( @@ -46,7 +45,7 @@ __version__ = "21.3.0.dev0" __title__ = "structlog" -__description__ = "Structured Logging for Python" +__description__ = __doc__.strip() __uri__ = "https://www.structlog.org/" __author__ = "Hynek Schlawack" diff --git a/tox.ini b/tox.ini index 88ac9b42..c4c9b62f 100644 --- a/tox.ini +++ b/tox.ini @@ -7,15 +7,15 @@ python = 3.6: py36 3.7: py37 3.8: py38, docs, lint - 3.9: py39, manifest, mypy - 3.10: py310 + 3.9: py39, mypy + 3.10: py310, cog pypy3: pypy3 [tox] # Running tests on pypy3 is very slow, we don't need it for coverage, and it's # unlikely it'll ever break. Therefore, we only run it in CI -- just in case. -envlist = lint,mypy,{py36,py37,py38,py39,py310}-threads,py39-greenlets,py39-colorama,py310-be,py310-rich,docs,pypi-description,manifest,coverage-report +envlist = lint,mypy,cog,{py36,py37,py38,py39,py310}-threads,py39-greenlets,py39-colorama,py310-be,py310-rich,docs,pypi-description,coverage-report isolated_build = True @@ -40,6 +40,15 @@ deps = commands = mypy src typing_examples.py +[testenv:cog] +description = "Update pyproject.toml's metadata" +skip_install = true +deps = + cogapp + tomli +commands = python -m cogapp -r pyproject.toml + + [testenv] extras = tests deps = @@ -116,12 +125,6 @@ commands = twine check {envtmpdir}/build/* -[testenv:manifest] -skip_install = true -deps = check-manifest -commands = check-manifest - - [testenv:coverage-report] basepython = python3.9 deps = coverage[toml] From d99833ef539a6a9479e7a7e04e78c7f79d331276 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 17 Nov 2021 10:27:52 +0100 Subject: [PATCH 0566/1520] Move typing_examples.py to tests Let's keep the main dir cleaner. --- pyproject.toml | 1 - typing_examples.py => tests/typing_examples.py | 0 tox.ini | 2 +- 3 files changed, 1 insertion(+), 2 deletions(-) rename typing_examples.py => tests/typing_examples.py (100%) diff --git a/pyproject.toml b/pyproject.toml index 75fcd1ec..013d3015 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,7 +55,6 @@ include = [ "tests", ".github", "show_off.py", - "typing_examples.py", ] exclude = [ "docs/_build", diff --git a/typing_examples.py b/tests/typing_examples.py similarity index 100% rename from typing_examples.py rename to tests/typing_examples.py diff --git a/tox.ini b/tox.ini index c4c9b62f..0e96d171 100644 --- a/tox.ini +++ b/tox.ini @@ -37,7 +37,7 @@ deps = mypy rich twisted -commands = mypy src typing_examples.py +commands = mypy src tests/typing_examples.py [testenv:cog] From f38e04a4f6fbe04cbd8bd01c24971fe3fc386280 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 17 Nov 2021 11:25:43 +0100 Subject: [PATCH 0567/1520] Add some clarifications --- pyproject.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 013d3015..72ffc2d4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -76,10 +76,13 @@ docs = [ "sphinx", "sphinxcontrib-mermaid", "twisted", + ] +# Combine tests and docs and a few more dev tools to a dev environment. # We make `dev = [` part of the output so cog doesn't dedent the list. # Refresh using `tox -e cog` +# # [[[cog # import cog, pathlib, tomli # cfg = tomli.loads(pathlib.Path("pyproject.toml").read_text()) @@ -155,8 +158,11 @@ profile = "attrs" [project.readme] content-type = "text/x-rst" + # Load README.rst, but remove header and badges. # Refresh using `tox -e cog` +# Nothing except for the adapted README follows after here. +# # [[[cog # import cog, pathlib # cog.out('text = """') From d621f80311c696c96d22762a7bec540bf503ab93 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 17 Nov 2021 12:02:18 +0100 Subject: [PATCH 0568/1520] Use cog properly to get correct indentation c.f. https://twitter.com/nedbat/status/1460922059417075715 --- pyproject.toml | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 72ffc2d4..68638002 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,23 +80,20 @@ docs = [ ] # Combine tests and docs and a few more dev tools to a dev environment. -# We make `dev = [` part of the output so cog doesn't dedent the list. # Refresh using `tox -e cog` # -# [[[cog -# import cog, pathlib, tomli -# cfg = tomli.loads(pathlib.Path("pyproject.toml").read_text()) -# opt = cfg["project"]["optional-dependencies"] -# dev = ["pre-commit", "rich", "cogapp", "tomli"] -# cog.outl("dev = [") -# for dep in dev + opt["tests"] + opt["docs"]: -# cog.outl(f' "{dep}",') -# ]]] dev = [ "pre-commit", "rich", "cogapp", "tomli", + # [[[cog + # import cog, pathlib, tomli + # cfg = tomli.loads(pathlib.Path("pyproject.toml").read_text()) + # opt = cfg["project"]["optional-dependencies"] + # for dep in opt["tests"] + opt["docs"]: + # cog.outl(f'"{dep}",') + # ]]] "coverage[toml]", "freezegun>=0.2.8", "pretend", From 6417396f6ec82a206594cc0a8f489f9440a1335b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 17 Nov 2021 12:12:05 +0100 Subject: [PATCH 0569/1520] Switch to print-based cog API --- pyproject.toml | 18 +++++++++++++----- tox.ini | 2 +- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 68638002..ffe5d346 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -88,11 +88,11 @@ dev = [ "cogapp", "tomli", # [[[cog - # import cog, pathlib, tomli + # import pathlib, tomli # cfg = tomli.loads(pathlib.Path("pyproject.toml").read_text()) # opt = cfg["project"]["optional-dependencies"] # for dep in opt["tests"] + opt["docs"]: - # cog.outl(f'"{dep}",') + # print(f'"{dep}",') # ]]] "coverage[toml]", "freezegun>=0.2.8", @@ -161,9 +161,17 @@ content-type = "text/x-rst" # Nothing except for the adapted README follows after here. # # [[[cog -# import cog, pathlib -# cog.out('text = """') -# cog.out(pathlib.Path("README.rst").read_text().split(".. -begin-short-")[1].lstrip().replace('"""', r'\"\"\"') + '"""') +# import pathlib +# print( +# 'text = """' +# + pathlib.Path("README.rst") +# .read_text() +# .split(".. -begin-short-")[1] +# .lstrip() +# .replace('"""', r'\"\"\"') +# + '"""', +# end="" +# ) # ]]] text = """``structlog`` makes logging in Python **faster**, **less painful**, and **more powerful** by adding **structure** to your log entries. It has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio* or type hints along the way, and `influenced the design `_ of `structured logging packages in other ecosystems `_. diff --git a/tox.ini b/tox.ini index 0e96d171..b764319f 100644 --- a/tox.ini +++ b/tox.ini @@ -46,7 +46,7 @@ skip_install = true deps = cogapp tomli -commands = python -m cogapp -r pyproject.toml +commands = python -m cogapp -rP pyproject.toml [testenv] From 39ad6a4aa4150d22fac1b68e924e243eb4e0c039 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 17 Nov 2021 20:57:35 +0100 Subject: [PATCH 0570/1520] Update pyproject.toml --- pyproject.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ffe5d346..015af15b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -81,7 +81,7 @@ docs = [ # Combine tests and docs and a few more dev tools to a dev environment. # Refresh using `tox -e cog` -# + dev = [ "pre-commit", "rich", @@ -104,9 +104,10 @@ dev = [ "sphinx", "sphinxcontrib-mermaid", "twisted", -# [[[end]]] + # [[[end]]] ] + [tool.pytest.ini_options] addopts = "-ra --strict-markers " xfail_strict = true From 23ebae5c45d7b7b3dc5e20fe617a830a12046aa3 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 18 Nov 2021 06:44:34 +0100 Subject: [PATCH 0571/1520] Minor updates to pyproject.toml Require flit_core>=3.4 so we can rely on `pip install -e .` working. --- pyproject.toml | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 015af15b..3d13c4aa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,17 +1,16 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 [build-system] -requires = ["flit_core >=3.2,<4"] +requires = ["flit_core >=3.4,<4"] build-backend = "flit_core.buildapi" + [project] name = "structlog" authors = [{name = "Hynek Schlawack", email = "hs@ox.cx"}] dynamic = ["version", "description"] requires-python = ">=3.6" -dependencies = [ - "typing-extensions; python_version<'3.8'" -] +dependencies = ["typing-extensions; python_version<'3.8'"] license = { file = "LICENSE" } keywords = ["logging", "structured", "structure", "log"] classifiers = [ @@ -112,9 +111,7 @@ dev = [ addopts = "-ra --strict-markers " xfail_strict = true testpaths = "tests" -filterwarnings = [ - "once::Warning", -] +filterwarnings = ["once::Warning"] [tool.coverage.run] @@ -159,8 +156,8 @@ content-type = "text/x-rst" # Load README.rst, but remove header and badges. # Refresh using `tox -e cog` -# Nothing except for the adapted README follows after here. -# +# Nothing except for the adapted README follows after this point. + # [[[cog # import pathlib # print( From e3a185f06ebfddcadeef6772a39b82c0c8fe172a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 18 Nov 2021 06:51:15 +0100 Subject: [PATCH 0572/1520] Add notfound to sphinx --- docs/conf.py | 1 + pyproject.toml | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index aa1b47e5..4a3e16ba 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -31,6 +31,7 @@ def find_version(*file_paths): # -- General configuration ---------------------------------------------------- extensions = [ + "notfound.extension", "sphinx.ext.autodoc", "sphinx.ext.autodoc.typehints", "sphinx.ext.doctest", diff --git a/pyproject.toml b/pyproject.toml index 3d13c4aa..9261e2bc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -73,9 +73,9 @@ tests = [ docs = [ "furo", "sphinx", + "sphinx-notfound-page", "sphinxcontrib-mermaid", "twisted", - ] # Combine tests and docs and a few more dev tools to a dev environment. @@ -101,6 +101,7 @@ dev = [ "simplejson", "furo", "sphinx", + "sphinx-notfound-page", "sphinxcontrib-mermaid", "twisted", # [[[end]]] From a781b05254205bd5c93d8c2cc549e39ae61d36fd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 18 Nov 2021 07:23:32 +0100 Subject: [PATCH 0573/1520] Reduce padding in README to make it more readable --- README.rst | 4 ++-- pyproject.toml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index e8e55797..c16e62fc 100644 --- a/README.rst +++ b/README.rst @@ -48,7 +48,7 @@ You can stop writing prose and start thinking in terms of an event that happens >>> from structlog import get_logger >>> log = get_logger() >>> log.info("key_value_logging", out_of_the_box=True, effort=0) - 2020-11-18 09:17.09 [info ] key_value_logging effort=0 out_of_the_box=True + 2020-11-18 09:17.09 [info ] key_value_logging effort=0 out_of_the_box=True Each log entry is a meaningful dictionary instead of an opaque string now! @@ -63,7 +63,7 @@ Since log entries are dictionaries, you can start binding and re-binding key/val >>> log = log.bind(user="anonymous", some_key=23) >>> log = log.bind(user="hynek", another_key=42) >>> log.info("user.logged_in", happy=True) - 2020-11-18 09:18.28 [info ] user.logged_in another_key=42 happy=True some_key=23 user=hynek + 2020-11-18 09:18.28 [info ] user.logged_in another_key=42 happy=True some_key=23 user=hynek You can also bind key/value pairs to `thread-local storage `_ and `contextvars `_. diff --git a/pyproject.toml b/pyproject.toml index 9261e2bc..b621dca6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -198,7 +198,7 @@ You can stop writing prose and start thinking in terms of an event that happens >>> from structlog import get_logger >>> log = get_logger() >>> log.info("key_value_logging", out_of_the_box=True, effort=0) - 2020-11-18 09:17.09 [info ] key_value_logging effort=0 out_of_the_box=True + 2020-11-18 09:17.09 [info ] key_value_logging effort=0 out_of_the_box=True Each log entry is a meaningful dictionary instead of an opaque string now! @@ -213,7 +213,7 @@ Since log entries are dictionaries, you can start binding and re-binding key/val >>> log = log.bind(user="anonymous", some_key=23) >>> log = log.bind(user="hynek", another_key=42) >>> log.info("user.logged_in", happy=True) - 2020-11-18 09:18.28 [info ] user.logged_in another_key=42 happy=True some_key=23 user=hynek + 2020-11-18 09:18.28 [info ] user.logged_in another_key=42 happy=True some_key=23 user=hynek You can also bind key/value pairs to `thread-local storage `_ and `contextvars `_. From bb38ca8da9fbda34e56e6d9ad2b1490bb5a7fd25 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 18 Nov 2021 08:34:33 +0100 Subject: [PATCH 0574/1520] Ditch codecov (#369) Instead of uploading coverage data to flaky Codecov, store it within GitHub Actions and combine/report in a separate step. h/t https://github.com/cjolowicz/cookiecutter-hypermodern-python/blob/a82096f880420c334f289321328b0fac8e373b69/%7B%7Bcookiecutter.project_name%7D%7D/noxfile.py --- .github/workflows/main.yml | 37 +++++++++++++++++++++++++++---------- codecov.yml | 10 ---------- pyproject.toml | 1 - 3 files changed, 27 insertions(+), 21 deletions(-) delete mode 100644 codecov.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c2582700..e70e2f8f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,8 +12,6 @@ jobs: tests: name: "Python ${{ matrix.python-version }}" runs-on: "ubuntu-latest" - env: - USING_COVERAGE: "3.6,3.9,3.10" strategy: matrix: @@ -35,17 +33,36 @@ jobs: - name: "Run tox targets for ${{ matrix.python-version }}" run: "python -m tox" - - name: "Combine coverage" + - name: Upload coverage data + uses: "actions/upload-artifact@v2" + with: + name: coverage-data + path: ".coverage.*" + if-no-files-found: ignore + + coverage: + runs-on: "ubuntu-latest" + needs: tests + steps: + - uses: actions/checkout@v2 + - name: "Use latest Python so it understands all syntax" + uses: actions/setup-python@v2 + with: + python-version: "3.10" + + - name: "Install Coverage.py" + run: "python -m pip install --upgrade coverage[toml]" + + - name: "Download coverage data" + uses: actions/download-artifact@v2 + with: + name: coverage-data + + - name: "Combine & check coverage" run: | set -xe python -m coverage combine - python -m coverage xml - if: "contains(env.USING_COVERAGE, matrix.python-version)" - - name: Upload coverage to Codecov - if: "contains(env.USING_COVERAGE, matrix.python-version)" - uses: "codecov/codecov-action@v2" - with: - fail_ci_if_error: true + python -m coverage report --fail-under=100 package: name: "Build & verify package" diff --git a/codecov.yml b/codecov.yml deleted file mode 100644 index 60a1e5c1..00000000 --- a/codecov.yml +++ /dev/null @@ -1,10 +0,0 @@ ---- -comment: false -coverage: - status: - patch: - default: - target: "100" - project: - default: - target: "100" diff --git a/pyproject.toml b/pyproject.toml index b621dca6..b46c03ba 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,7 +46,6 @@ Ko-fi = "https://ko-fi.com/the_hynek" include = [ ".pre-commit-config.yaml", ".readthedocs.yml", - "codecov.yml", "*.ini", "*.rst", "LICENSE.*", From 98799884300bf0808482315b43db856b8966a4d1 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 18 Nov 2021 14:35:17 +0100 Subject: [PATCH 0575/1520] Implore people to update their pip --- .github/CONTRIBUTING.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst index 78eb2ae1..ff482b3c 100644 --- a/.github/CONTRIBUTING.rst +++ b/.github/CONTRIBUTING.rst @@ -131,6 +131,7 @@ Change into the newly created directory and **after activating your virtual envi .. code-block:: bash $ cd structlog + $ pip install --upgrade pip setuptools # PLEASE don't skip this step $ pip install -e .[dev] If you run the virtual environment’s Python and try to ``import structlog`` it should work! From 2de7da120c11c62b19d9838a02f73d67126a2452 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 18 Nov 2021 14:35:28 +0100 Subject: [PATCH 0576/1520] Those dumb quotes look dumb --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index c16e62fc..7c2729c3 100644 --- a/README.rst +++ b/README.rst @@ -35,7 +35,7 @@ Once you feel inspired to try it out, check out our friendly `Getting Started tu .. -begin-spiel- -If you prefer videos over reading, check out this DjangoCon Europe 2019 talk by `Markus Holtermann `_: "`Logging Rethought 2: The Actions of Frank Taylor Jr. `_". +If you prefer videos over reading, check out this DjangoCon Europe 2019 talk by `Markus Holtermann `_: `Logging Rethought 2: The Actions of Frank Taylor Jr. `_. Easier Logging From 6cdfaf337e6853d0b295c609fbbc805f1e9f5dcd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 18 Nov 2021 14:53:52 +0100 Subject: [PATCH 0577/1520] Uncramp links --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 7c2729c3..dd3108c3 100644 --- a/README.rst +++ b/README.rst @@ -35,7 +35,7 @@ Once you feel inspired to try it out, check out our friendly `Getting Started tu .. -begin-spiel- -If you prefer videos over reading, check out this DjangoCon Europe 2019 talk by `Markus Holtermann `_: `Logging Rethought 2: The Actions of Frank Taylor Jr. `_. +If you prefer videos over reading, check out `Markus Holtermann `_'s DjangoCon Europe 2019 talk: `Logging Rethought 2: The Actions of Frank Taylor Jr. `_ Easier Logging From d65d3be079f44c8f2ccee55d96ab24bc146614b0 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 18 Nov 2021 16:19:36 +0100 Subject: [PATCH 0578/1520] Too many adjectives --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index dd3108c3..018a8b16 100644 --- a/README.rst +++ b/README.rst @@ -106,12 +106,12 @@ Internally, formatters are processors whose return value (usually a string) is p Output ====== -``structlog`` is also very flexible with the final output of your log entries: +``structlog`` is also flexible with the final output of your log entries: - A **built-in** lightweight printer like in the examples above. Easy to use and fast. - Use the **standard library**'s or **Twisted**'s logging modules for compatibility. - In this case ``structlog`` works like a wrapper that formats a string and passes them off into existing systems that won't ever know that ``structlog`` even exists. + In this case ``structlog`` works like a wrapper that formats a string and passes them off into existing systems that won't know that ``structlog`` even exists. Or the other way round: ``structlog`` comes with a ``logging`` formatter that allows for processing third party log records. - Don't format it to a string at all! ``structlog`` passes you a dictionary and you can do with it whatever you want. From 809ca8e8ff45b55beddfd9464de388c733eedb3d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 19 Nov 2021 06:22:17 +0100 Subject: [PATCH 0579/1520] Streamline, don't use set -xe It's on by default: https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#jobsjob_idstepsshell --- .github/workflows/main.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e70e2f8f..8e95bab6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -22,9 +22,9 @@ jobs: - uses: "actions/setup-python@v2" with: python-version: "${{ matrix.python-version }}" + - name: "Install dependencies" run: | - set -xe python -VV python -m site python -m pip install --upgrade pip setuptools wheel @@ -45,10 +45,9 @@ jobs: needs: tests steps: - uses: actions/checkout@v2 - - name: "Use latest Python so it understands all syntax" - uses: actions/setup-python@v2 + - uses: actions/setup-python@v2 with: - python-version: "3.10" + python-version: "3.10" # Use latest, so it understands all syntax. - name: "Install Coverage.py" run: "python -m pip install --upgrade coverage[toml]" @@ -60,7 +59,6 @@ jobs: - name: "Combine & check coverage" run: | - set -xe python -m coverage combine python -m coverage report --fail-under=100 From 249c457e04255e8d5bf998e161595cbb042af5b4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 19 Nov 2021 06:24:45 +0100 Subject: [PATCH 0580/1520] Give it more air --- .github/workflows/main.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8e95bab6..f4852357 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,11 +8,11 @@ on: branches: ["main"] workflow_dispatch: + jobs: tests: name: "Python ${{ matrix.python-version }}" runs-on: "ubuntu-latest" - strategy: matrix: python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "pypy3"] @@ -40,9 +40,11 @@ jobs: path: ".coverage.*" if-no-files-found: ignore + coverage: runs-on: "ubuntu-latest" needs: tests + steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 @@ -62,6 +64,7 @@ jobs: python -m coverage combine python -m coverage report --fail-under=100 + package: name: "Build & verify package" runs-on: "ubuntu-latest" @@ -83,14 +86,14 @@ jobs: - name: "Check long_description" run: "python -m twine check dist/*" + install-dev: + name: "Verify dev env" + runs-on: "${{ matrix.os }}" strategy: matrix: os: ["ubuntu-latest", "windows-latest", "macos-latest"] - name: "Verify dev env" - runs-on: "${{ matrix.os }}" - steps: - uses: "actions/checkout@v2" - uses: "actions/setup-python@v2" From ea987ea15e1d57edfbf4f807dc9eef3a20cdc6f4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 19 Nov 2021 06:41:37 +0100 Subject: [PATCH 0581/1520] COLORS! --- .github/workflows/main.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f4852357..e07353e0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,6 +8,10 @@ on: branches: ["main"] workflow_dispatch: +env: + FORCE_COLOR: "1" # Make tools pretty. + TOX_TESTENV_PASSENV: "FORCE_COLOR" + jobs: tests: From d61bb262f32c45fb9c79f3523e38587ce65f1f19 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 19 Nov 2021 06:58:33 +0100 Subject: [PATCH 0582/1520] Lint on 3.10 --- .pre-commit-config.yaml | 8 ++++---- tox.ini | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0c86365e..63aaf3a6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,23 +1,23 @@ --- repos: - repo: https://github.com/psf/black - rev: 21.10b0 + rev: 21.11b1 hooks: - id: black - language_version: python3.8 + language_version: python3.10 - repo: https://github.com/PyCQA/isort rev: 5.10.1 hooks: - id: isort additional_dependencies: [toml] - language_version: python3.8 + language_version: python3.10 - repo: https://github.com/PyCQA/flake8 rev: 4.0.1 hooks: - id: flake8 - language_version: python3.8 + language_version: python3.10 exclude: docs/code_examples - repo: https://github.com/pre-commit/pre-commit-hooks diff --git a/tox.ini b/tox.ini index b764319f..a4e1c904 100644 --- a/tox.ini +++ b/tox.ini @@ -6,9 +6,9 @@ ignore = E203,W503,W504 python = 3.6: py36 3.7: py37 - 3.8: py38, docs, lint + 3.8: py38, docs 3.9: py39, mypy - 3.10: py310, cog + 3.10: py310, cog, lint pypy3: pypy3 @@ -20,7 +20,7 @@ isolated_build = True [testenv:lint] -basepython = python3.8 +basepython = python3.10 skip_install = true deps = pre-commit passenv = HOMEPATH # needed on Windows From 10c06b1cfdeccaeef7329c0b5f70c269d29a9a04 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 19 Nov 2021 08:10:51 +0100 Subject: [PATCH 0583/1520] Add HTML reports --- .github/workflows/main.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e07353e0..3be01fc0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -63,10 +63,16 @@ jobs: with: name: coverage-data - - name: "Combine & check coverage" - run: | - python -m coverage combine - python -m coverage report --fail-under=100 + - run: python -m coverage combine + - run: python -m coverage html --skip-covered --skip-empty + + - name: Upload coverage report + uses: "actions/upload-artifact@v2" + with: + name: html-report + path: htmlcov + + - run: python -m coverage report --fail-under=100 package: From 9e80df56042ba6a8583ee8920e7031eeb5760bba Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 19 Nov 2021 08:23:52 +0100 Subject: [PATCH 0584/1520] cog --- pyproject.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index b46c03ba..e698bdf3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -184,7 +184,7 @@ Once you feel inspired to try it out, check out our friendly `Getting Started tu .. -begin-spiel- -If you prefer videos over reading, check out this DjangoCon Europe 2019 talk by `Markus Holtermann `_: "`Logging Rethought 2: The Actions of Frank Taylor Jr. `_". +If you prefer videos over reading, check out `Markus Holtermann `_'s DjangoCon Europe 2019 talk: `Logging Rethought 2: The Actions of Frank Taylor Jr. `_ Easier Logging @@ -255,12 +255,12 @@ Internally, formatters are processors whose return value (usually a string) is p Output ====== -``structlog`` is also very flexible with the final output of your log entries: +``structlog`` is also flexible with the final output of your log entries: - A **built-in** lightweight printer like in the examples above. Easy to use and fast. - Use the **standard library**'s or **Twisted**'s logging modules for compatibility. - In this case ``structlog`` works like a wrapper that formats a string and passes them off into existing systems that won't ever know that ``structlog`` even exists. + In this case ``structlog`` works like a wrapper that formats a string and passes them off into existing systems that won't know that ``structlog`` even exists. Or the other way round: ``structlog`` comes with a ``logging`` formatter that allows for processing third party log records. - Don't format it to a string at all! ``structlog`` passes you a dictionary and you can do with it whatever you want. From 12e7f174fe2bc97b336ac20414425280f3aaef60 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 19 Nov 2021 08:24:30 +0100 Subject: [PATCH 0585/1520] Use current pypy version syntax --- .github/workflows/main.yml | 2 +- tox.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3be01fc0..321cdcde 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,7 +19,7 @@ jobs: runs-on: "ubuntu-latest" strategy: matrix: - python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "pypy3"] + python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "pypy-3.7"] steps: - uses: "actions/checkout@v2" diff --git a/tox.ini b/tox.ini index a4e1c904..8df690f5 100644 --- a/tox.ini +++ b/tox.ini @@ -9,7 +9,7 @@ python = 3.8: py38, docs 3.9: py39, mypy 3.10: py310, cog, lint - pypy3: pypy3 + pypy-3: pypy3 [tox] From aaba7e786ea47d5cee17afbf45ca5e766489c745 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 19 Nov 2021 08:25:26 +0100 Subject: [PATCH 0586/1520] Polish tox.ini --- tox.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tox.ini b/tox.ini index 8df690f5..051463c3 100644 --- a/tox.ini +++ b/tox.ini @@ -31,7 +31,7 @@ commands = pre-commit run --all-files description = Check types basepython = python3.9 extras = tests -# Need twisted & rich for stubs +# Need twisted & rich for stubs. # Otherwise mypy fails in tox. deps = mypy @@ -111,7 +111,7 @@ commands = [testenv:pypi-description] -basepython = python3.8 +basepython = python3.10 skip_install = true deps = twine @@ -126,11 +126,11 @@ commands = [testenv:coverage-report] -basepython = python3.9 +basepython = python3.10 deps = coverage[toml] skip_install = true parallel_show_output = true -depends = {py36,py37,py38,py39}-threads,py39-greenlets,py39-colorama,py39-be,py39-rich +depends = {py36,py310}-threads,py39-greenlets,py39-colorama,py310-be,py310-rich commands = coverage combine coverage report From eb4b567de6d244a0445b79a6ed8e8004d914ea16 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 19 Nov 2021 08:51:06 +0100 Subject: [PATCH 0587/1520] Better phrasing --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 321cdcde..10a0afdb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -15,7 +15,7 @@ env: jobs: tests: - name: "Python ${{ matrix.python-version }}" + name: "Run tests on ${{ matrix.python-version }}" runs-on: "ubuntu-latest" strategy: matrix: From 7147f5146144bbd8f78c442e31f529ef1b88ad1d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 19 Nov 2021 09:32:17 +0100 Subject: [PATCH 0588/1520] Update main.yml --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 10a0afdb..84424e78 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -15,7 +15,7 @@ env: jobs: tests: - name: "Run tests on ${{ matrix.python-version }}" + name: "Tests on ${{ matrix.python-version }}" runs-on: "ubuntu-latest" strategy: matrix: From 990b4d07039edebd516ff6fc148da6fe4856c65d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 19 Nov 2021 09:33:11 +0100 Subject: [PATCH 0589/1520] It's not just tests --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 84424e78..321cdcde 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -15,7 +15,7 @@ env: jobs: tests: - name: "Tests on ${{ matrix.python-version }}" + name: "Python ${{ matrix.python-version }}" runs-on: "ubuntu-latest" strategy: matrix: From b9558a66b40509f653f54df6af327f01b0f6fbf2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 19 Nov 2021 09:35:40 +0100 Subject: [PATCH 0590/1520] Compromise --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 321cdcde..cf001cd4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -15,7 +15,7 @@ env: jobs: tests: - name: "Python ${{ matrix.python-version }}" + name: "tox on ${{ matrix.python-version }}" runs-on: "ubuntu-latest" strategy: matrix: From 2f956be9535bfd4aac9833c3f48396e03d6e47e3 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 19 Nov 2021 14:31:25 +0100 Subject: [PATCH 0591/1520] Move docs closer to gh-actions and coverage-report to coverage runs --- tox.ini | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/tox.ini b/tox.ini index 051463c3..848389ae 100644 --- a/tox.ini +++ b/tox.ini @@ -19,6 +19,19 @@ envlist = lint,mypy,cog,{py36,py37,py38,py39,py310}-threads,py39-greenlets,py39- isolated_build = True +[testenv:docs] +# Keep basepython in sync with gh-actions and .readthedocs.yml. +basepython = python3.8 +extras = + docs +passenv = TERM +setenv = + PYTHONHASHSEED = 0 +commands = + sphinx-build -n -T -W -b html -d {envtmpdir}/doctrees docs docs/_build/html + sphinx-build -n -T -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html + + [testenv:lint] basepython = python3.10 skip_install = true @@ -97,17 +110,15 @@ deps = rich commands = coverage run -m pytest tests/test_dev.py {posargs} -[testenv:docs] -# Keep basepython in sync with gh-actions and .readthedocs.yml. -basepython = python3.8 -extras = - docs -passenv = TERM -setenv = - PYTHONHASHSEED = 0 +[testenv:coverage-report] +basepython = python3.10 +deps = coverage[toml] +skip_install = true +parallel_show_output = true +depends = {py36,py310}-threads,py39-greenlets,py39-colorama,py310-be,py310-rich commands = - sphinx-build -n -T -W -b html -d {envtmpdir}/doctrees docs docs/_build/html - sphinx-build -n -T -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html + coverage combine + coverage report [testenv:pypi-description] @@ -123,14 +134,3 @@ commands = pip install --upgrade pip pip wheel -w {envtmpdir}/build --no-deps . twine check {envtmpdir}/build/* - - -[testenv:coverage-report] -basepython = python3.10 -deps = coverage[toml] -skip_install = true -parallel_show_output = true -depends = {py36,py310}-threads,py39-greenlets,py39-colorama,py310-be,py310-rich -commands = - coverage combine - coverage report From ea9c965bc39f480197278e8a9af9ab7cdbdf1c7f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 19 Nov 2021 16:11:42 +0100 Subject: [PATCH 0592/1520] stdlib/ProcessorFormatter: allow for complete chains on top of records (#365) * stdlib/ProcessorFormatter: allow for complete chains on top of records * docs & remove_processors_meta * Add tests for processor vs processors handling * Demonstrate LogRecord extraction * Add more tests --- CHANGELOG.rst | 7 +++ docs/api.rst | 2 +- docs/standard-library.rst | 71 ++++++++++++++++------- src/structlog/stdlib.py | 116 +++++++++++++++++++++++++++++++------- tests/test_stdlib.py | 113 ++++++++++++++++++++++++++----------- 5 files changed, 232 insertions(+), 77 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 96cdb7f0..11745d6e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -31,6 +31,13 @@ Changes: `#364 `_ - ``structlog.stdlib.AsyncBoundLogger`` now determines the running loop when logging, not on instantiation. That has a minor performance impact, but makes it more robust when loops change (e.g. ``aiohttp.web.run_app()``), or you want to use ``sync_bl`` *before* a loop has started. +- ``structlog.stdlib.ProcessorFormatter`` now has a *processors* argument that allows to define a processor chain to run over *all* log entries. + + Before running the chain, two additional keys are added to the event dictionary: ``_record`` and ``_from_structlog``. + With them it's possible to extract information from ``logging.LogRecord``\s and differentiate between ``structlog`` and ``logging`` log entries while processing them. + + The old *processor* (singular) parameter is now deprecated, but no plans exist to remove it. + `#365 `_ ---- diff --git a/docs/api.rst b/docs/api.rst index c5f46165..ad6d5a5a 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -290,7 +290,7 @@ Please see :doc:`thread-local` for details. .. autoclass:: PositionalArgumentsFormatter .. autoclass:: ProcessorFormatter - :members: wrap_for_formatter + :members: wrap_for_formatter, remove_processors_meta `structlog.types` Module diff --git a/docs/standard-library.rst b/docs/standard-library.rst index 2e23c188..bc9d56a7 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -278,14 +278,14 @@ Now both ``structlog`` and ``logging`` will emit JSON logs: Keep this in mind if you only get the event name without any context, and exceptions are ostensibly swallowed. +.. _processor-formatter: Rendering Using ``structlog``-based Formatters Within `logging` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Finally, the most ambitious approach. -Here, you use ``structlog``'s `ProcessorFormatter` as a `logging.Formatter`. +Here, you use ``structlog``'s `ProcessorFormatter` as a `logging.Formatter` for both `logging` as well as ``structlog`` log entries. -This means that ``structlog`` is responsible for formatting both its own log entries, as well those coming from calls to the standard library. Consequently, the output is the duty of the standard library too. .. mermaid:: @@ -310,10 +310,12 @@ Consequently, the output is the duty of the standard library too. `ProcessorFormatter` has two parts to its API: -#. Instead of a renderer, the `structlog.stdlib.ProcessorFormatter.wrap_for_formatter` static method must be used as the last processor in the :doc:`processor chain `. +#. On the ``structlog`` side, the :doc:`processor chain ` must be configured to end with `structlog.stdlib.ProcessorFormatter.wrap_for_formatter` as the renderer. It converts the processed event dictionary into something that `ProcessorFormatter` understands. -#. The `ProcessorFormatter` itself, whose ``format()`` method gets called by standard library `logging` for every log entry (if you configure `logging` correctly). - It can wrap any ``structlog`` renderer to handle the output of both ``structlog`` and standard library events. +#. On the `logging` side, you must configure `ProcessorFormatter` as your formatter of choice. + `logging` then calls `ProcessorFormatter`'s ``format()`` method. + + For that, `ProcessorFormatter` wraps a processor chain that is responsible for rendering your log entries to strings. Thus, the simplest possible configuration looks like the following: @@ -331,7 +333,7 @@ Thus, the simplest possible configuration looks like the following: ) formatter = structlog.stdlib.ProcessorFormatter( - processor=structlog.dev.ConsoleRenderer(), + processors=[structlog.dev.ConsoleRenderer()], ) handler = logging.StreamHandler() @@ -349,14 +351,17 @@ which will allow both of these to work in other modules: >>> import structlog >>> logging.getLogger("stdlog").info("woo") - woo + woo _from_structlog=False _record= >>> structlog.get_logger("structlog").info("amazing", events="oh yes") - amazing events=oh yes + amazing _from_structlog=True _record= events=oh yes Of course, you probably want timestamps and log levels in your output. The `ProcessorFormatter` has a ``foreign_pre_chain`` argument which is responsible for adding properties to events from the standard library -- i.e. that do not originate from a ``structlog`` logger -- and which should in general match the ``processors`` argument to `structlog.configure` so you get a consistent output. -For example, to add timestamps, log levels, and traceback handling to your logs you should do: +``_from_structlog`` and ``_record`` allow your processors to determine whether the log entry is coming from ``structlog``, and to extract information from `logging.LogRecord`\s and add them to the event dictionary. +However, you probably don't want to have them in your log files, thus we've added the `ProcessorFormatter.remove_processors_meta` processor to do so conveniently. + +For example, to add timestamps, log levels, and traceback handling to your logs without ``_from_structlog`` and ``_record`` noise you should do: .. code-block:: python @@ -375,10 +380,15 @@ For example, to add timestamps, log levels, and traceback handling to your logs ) formatter = structlog.stdlib.ProcessorFormatter( - processor=structlog.dev.ConsoleRenderer(), # These run ONLY on `logging` entries that do NOT originate within # structlog. foreign_pre_chain=shared_processors, + # These run on ALL entries after the pre_chain is done. + processors=[ + # Remove _record & _from_structlog. + structlog.stdlib.ProcessorFormatter.remove_processors_meta, + structlog.dev.ConsoleRenderer(), + ], ) which (given the same ``logging.*`` calls as in the previous example) will result in: @@ -386,9 +396,9 @@ which (given the same ``logging.*`` calls as in the previous example) will resul .. code-block:: pycon >>> logging.getLogger("stdlog").info("woo") - 2017-03-06 14:59:20 [info ] woo + 2021-11-15 11:41:47 [info ] woo >>> structlog.get_logger("structlog").info("amazing", events="oh yes") - 2017-03-06 14:59:20 [info ] amazing events=oh yes + 2021-11-15 11:41:47 [info ] amazing events=oh yes This allows you to set up some sophisticated logging configurations. For example, to use the standard library's `logging.config.dictConfig` to log colored logs to the console and plain logs to a file you could do: @@ -406,18 +416,35 @@ For example, to use the standard library's `logging.config.dictConfig` to log co timestamper, ] + def extract_from_record(_, __, event_dict): + """ + Extract thread and process names and add them to the event dict. + """ + record = event_dict["_record"] + event_dict["thread_name"] = record.threadName + event_dict["process_name"] = record.processName + + return event_dict + logging.config.dictConfig({ "version": 1, "disable_existing_loggers": False, "formatters": { "plain": { "()": structlog.stdlib.ProcessorFormatter, - "processor": structlog.dev.ConsoleRenderer(colors=False), + "processors": [ + structlog.stdlib.ProcessorFormatter.remove_processors_meta, + structlog.dev.ConsoleRenderer(colors=False), + ], "foreign_pre_chain": pre_chain, }, "colored": { "()": structlog.stdlib.ProcessorFormatter, - "processor": structlog.dev.ConsoleRenderer(colors=True), + "processors": [ + extract_from_record, + structlog.stdlib.ProcessorFormatter.remove_processors_meta, + structlog.dev.ConsoleRenderer(colors=True), + ], "foreign_pre_chain": pre_chain, }, }, @@ -460,17 +487,19 @@ This defines two formatters: one plain and one colored. Both are run for each log entry. Log entries that do not originate from ``structlog``, are additionally pre-processed using a cached ``timestamper`` and :func:`~structlog.stdlib.add_log_level`. +Additionally, for both `logging` and ``structlog`` -- but only for the colorful logger -- we also extract some data from `logging.LogRecord`: + .. code-block:: pycon - >>> logging.getLogger().warning("bar") - 2017-03-06 11:49:27 [warning ] bar + >>> logging.getLogger().warning("bar") + 2021-11-15 13:26:52 [warning ] bar process_name=MainProcess thread_name=MainThread - >>> structlog.get_logger("structlog").warning("foo", x=42) - 2017-03-06 11:49:32 [warning ] foo x=42 + >>> structlog.get_logger("structlog").warning("foo", x=42) + 2021-11-15 13:26:52 [warning ] foo process_name=MainProcess thread_name=MainThread x=42 - >>> print(open("test.log").read()) - 2017-03-06 11:49:27 [warning ] bar - 2017-03-06 11:49:32 [warning ] foo x=42 + >>> pathlib.Path("test.log").read_text() + 2021-11-15 13:26:52 [warning ] bar + 2021-11-15 13:26:52 [warning ] foo x=42 (Sadly, you have to imagine the colors in the first two outputs.) diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index d6baaa8e..d9a555fa 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -682,46 +682,81 @@ def render_to_log_kwargs( class ProcessorFormatter(logging.Formatter): r""" - Call ``structlog`` processors on :`logging.LogRecord`\ s. + Call ``structlog`` processors on `logging.LogRecord`\s. - This `logging.Formatter` allows to configure :mod:`logging` to call - *processor* on ``structlog``-borne log entries (origin is determined solely - on the fact whether the ``msg`` field on the `logging.LogRecord` is - a dict or not). + This is an implementation of a `logging.Formatter` that can be used to + format log entries from both ``structlog`` and `logging`. - This allows for two interesting use cases: + Its static method `wrap_for_formatter` must be the final processor in + ``structlog``'s processor chain. - #. You can format non-``structlog`` log entries. - #. You can multiplex log records into multiple `logging.Handler`\ s. + Please refer to :ref:`processor-formatter` for examples. - Please refer to :doc:`standard-library` for examples. - - :param processor: A ``structlog`` processor. :param foreign_pre_chain: - If not `None`, it is used as an iterable of processors that is applied - to non-``structlog`` log entries before *processor*. If `None`, - formatting is left to :mod:`logging`. (default: `None`) + If not `None`, it is used as a processor chain that is applied to + **non**-``structlog`` log entries before the event dictionary is passed + to *processors*. (default: `None`) + :param processors: + A chain of ``structlog`` processors that is used to process **all** log + entries. The last one must render to a `str` which then gets passed on + to `logging` for output. + + Compared to ``structlog``'s regular processor chains, there's a few + differences: + + - The event dictionary contains two additional keys: + + #. ``_record``: a `logging.LogRecord` that either was created using + `logging` APIs, **or** is a wrapped ``structlog`` log entry + created by `wrap_for_formatter`. + #. ``_from_structlog``: a `bool` that indicates whether or not + ``_record`` was created by a ``structlog`` logger. + + Since you most likely don't want ``_record`` and + ``_from_structlog`` in your log files, we've added + the static method `remove_processors_meta` to ``ProcessorFormatter`` + that you can add just before your renderer. + + - Since this is a `logging` *formatter*, raising `structlog.DropEvent` + will crash your application. + :param keep_exc_info: ``exc_info`` on `logging.LogRecord`\ s is added to the ``event_dict`` and removed afterwards. Set this to ``True`` to keep it on the `logging.LogRecord`. (default: False) - :param keep_stack_info: Same as *keep_exc_info* except for Python 3's - ``stack_info``. (default: False) + :param keep_stack_info: Same as *keep_exc_info* except for ``stack_info``. + (default: False) :param logger: Logger which we want to push through the ``structlog`` processor chain. This parameter is necessary for some of the processors like `filter_by_level`. (default: None) :param pass_foreign_args: If True, pass a foreign log record's ``args`` attribute to the ``event_dict`` under ``positional_args`` key. (default: False) + :param processor: + A single ``structlog`` processor used for rendering the event + dictionary before passing it off to `logging`. Must return a `str`. + The event dictionary does **not** contain ``_record`` and + ``_from_structlog``. + + This parameter exists for historic reasons. Please consider using + *processors* instead. + + :raises TypeError: If both or neither *processor* and *processors* are + passed. .. versionadded:: 17.1.0 .. versionadded:: 17.2.0 *keep_exc_info* and *keep_stack_info* .. versionadded:: 19.2.0 *logger* .. versionadded:: 19.2.0 *pass_foreign_args* + .. versionadded:: 21.3.0 *processors* + .. deprecated:: 21.3.0 + *processor* (singular) in favor of *processors* (plural). Removal is not + planned. """ def __init__( self, - processor: Processor, + processor: Optional[Processor] = None, + processors: Optional[Sequence[Processor]] = (), foreign_pre_chain: Optional[Sequence[Processor]] = None, keep_exc_info: bool = False, keep_stack_info: bool = False, @@ -733,7 +768,22 @@ def __init__( fmt = kwargs.pop("fmt", "%(message)s") super().__init__(*args, fmt=fmt, **kwargs) # type: ignore - self.processor = processor + if processor and processors: + raise TypeError( + "The `processor` and `processors` arguments are mutually " + "exclusive." + ) + + self.processors: Sequence[Processor] + if processor is not None: + self.processors = (self.remove_processors_meta, processor) + elif processors: + self.processors = processors + else: + raise TypeError( + "Either `processor` or `processors` must be passed." + ) + self.foreign_pre_chain = foreign_pre_chain self.keep_exc_info = keep_exc_info self.keep_stack_info = keep_stack_info @@ -764,10 +814,16 @@ def format(self, record: logging.LogRecord) -> str: # processed by multiple logging formatters. LogRecord.getMessage # would transform our dict into a str. ed = record.msg.copy() # type: ignore + ed["_record"] = record + ed["_from_structlog"] = True else: logger = self.logger meth_name = record.levelname.lower() - ed = {"event": record.getMessage(), "_record": record} + ed = { + "event": record.getMessage(), + "_record": record, + "_from_structlog": False, + } if self.pass_foreign_args: ed["positional_args"] = record.args @@ -793,9 +849,10 @@ def format(self, record: logging.LogRecord) -> str: for proc in self.foreign_pre_chain or (): ed = proc(logger, meth_name, ed) - del ed["_record"] + for p in self.processors: + ed = p(logger, meth_name, ed) - record.msg = self.processor(logger, meth_name, ed) # type: ignore + record.msg = ed return super().format(record) @@ -813,3 +870,20 @@ def wrap_for_formatter( want to use `ProcessorFormatter` in your `logging` configuration. """ return (event_dict,), {"extra": {"_logger": logger, "_name": name}} + + @staticmethod + def remove_processors_meta( + _: WrappedLogger, __: str, event_dict: EventDict + ) -> EventDict: + """ + Remove ``_record`` and ``_from_structlog`` from *event_dict*. + + These keys are added to the event dictionary, before + `ProcessorFormatter`'s *processors* are run. + + .. versionadded:: 21.3.0 + """ + del event_dict["_record"] + del event_dict["_from_structlog"] + + return event_dict diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index f47a6016..c95fe846 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -11,7 +11,7 @@ import pytest -from pretend import call_recorder +from pretend import call_recorder, stub from structlog import ( PrintLogger, @@ -484,8 +484,8 @@ def test_add_extra_event_dict(self, event_dict): assert {"msg": "message", "extra": event_dict} == d -@pytest.fixture -def configure_for_pf(): +@pytest.fixture(name="configure_for_processor_formatter") +def _configure_for_processor_formatter(): """ Configure structlog to use ProcessorFormatter. @@ -511,15 +511,28 @@ def configure_logging( ): """ Configure logging to use ProcessorFormatter. + + Return a list that is filled with event dicts form calls. """ - return logging.config.dictConfig( + event_dicts = [] + + def capture(_, __, ed): + event_dicts.append(ed.copy()) + + return ed + + logging.config.dictConfig( { "version": 1, "disable_existing_loggers": False, "formatters": { "plain": { "()": ProcessorFormatter, - "processor": renderer, + "processors": [ + capture, + ProcessorFormatter.remove_processors_meta, + renderer, + ], "foreign_pre_chain": pre_chain, "format": "%(message)s [in %(funcName)s]", "logger": logger, @@ -543,24 +556,30 @@ def configure_logging( } ) + return event_dicts + +@pytest.mark.usefixtures("configure_for_processor_formatter") class TestProcessorFormatter: """ These are all integration tests because they're all about integration. """ - def test_foreign_delegate(self, configure_for_pf, capsys): + def test_foreign_delegate(self, capsys): """ If foreign_pre_chain is None, non-structlog log entries are delegated - to logging. + to logging. The processor chain's event dict is invoked with + `_from_structlog=False` """ - configure_logging(None) + calls = configure_logging(None) logging.getLogger().warning("foo") assert ("", "foo [in test_foreign_delegate]\n") == capsys.readouterr() + assert calls[0]["_from_structlog"] is False + assert isinstance(calls[0]["_record"], logging.LogRecord) - def test_clears_args(self, configure_for_pf, capsys): + def test_clears_args(self, capsys): """ We render our log records before sending it back to logging. Therefore we must clear `LogRecord.args` otherwise the user gets an @@ -576,9 +595,7 @@ def test_clears_args(self, configure_for_pf, capsys): "hello world. [in test_clears_args]\n", ) == capsys.readouterr() - def test_pass_foreign_args_true_sets_positional_args_key( - self, configure_for_pf, capsys - ): + def test_pass_foreign_args_true_sets_positional_args_key(self): """ If `pass_foreign_args` is `True` we set the `positional_args` key in the `event_dict` before clearing args. @@ -594,9 +611,9 @@ def test_pass_foreign_args_true_sets_positional_args_key( assert "positional_args" in event_dict assert positional_args == event_dict["positional_args"] - def test_log_dict(self, configure_for_pf, capsys): + def test_log_dict(self, capsys): """ - Test that dicts can be logged with std library loggers. + dicts can be logged with std library loggers. """ configure_logging(None) @@ -607,12 +624,12 @@ def test_log_dict(self, configure_for_pf, capsys): "{'foo': 'bar'} [in test_log_dict]\n", ) == capsys.readouterr() - def test_foreign_pre_chain(self, configure_for_pf, capsys): + def test_foreign_pre_chain(self, capsys): """ If foreign_pre_chain is an iterable, it's used to pre-process non-structlog log entries. """ - configure_logging((add_log_level,)) + configure_logging([add_log_level]) logging.getLogger().warning("foo") @@ -621,7 +638,7 @@ def test_foreign_pre_chain(self, configure_for_pf, capsys): "[warning ] foo [in test_foreign_pre_chain]\n", ) == capsys.readouterr() - def test_foreign_pre_chain_add_logger_name(self, configure_for_pf, capsys): + def test_foreign_pre_chain_add_logger_name(self, capsys): """ foreign_pre_chain works with add_logger_name processor. """ @@ -636,7 +653,7 @@ def test_foreign_pre_chain_add_logger_name(self, configure_for_pf, capsys): ) == capsys.readouterr() def test_foreign_chain_can_pass_dictionaries_without_excepting( - self, configure_for_pf, capsys + self, capsys ): """ If a foreign logger passes a dictionary to a logging function, @@ -657,7 +674,7 @@ def test_foreign_chain_can_pass_dictionaries_without_excepting( "test_foreign_chain_can_pass_dictionaries_without_excepting]\n", ) == capsys.readouterr() - def test_foreign_pre_chain_gets_exc_info(self, configure_for_pf, capsys): + def test_foreign_pre_chain_gets_exc_info(self): """ If non-structlog record contains exc_info, foreign_pre_chain functions have access to it. @@ -675,7 +692,7 @@ def test_foreign_pre_chain_gets_exc_info(self, configure_for_pf, capsys): assert "exc_info" in event_dict assert isinstance(event_dict["exc_info"], tuple) - def test_foreign_pre_chain_sys_exc_info(self, configure_for_pf, capsys): + def test_foreign_pre_chain_sys_exc_info(self): """ If a foreign_pre_chain function accesses sys.exc_info(), ProcessorFormatter should not have changed it. @@ -702,9 +719,7 @@ def add_excinfo(logger, log_method, event_dict): assert MyException is event_dict["exc_info"][0] - def test_other_handlers_get_original_record( - self, configure_for_pf, capsys - ): + def test_other_handlers_get_original_record(self): """ Logging handlers that come after the handler with ProcessorFormatter should receive original, unmodified record. @@ -713,9 +728,10 @@ def test_other_handlers_get_original_record( handler1 = logging.StreamHandler() handler1.setFormatter(ProcessorFormatter(JSONRenderer())) - handler2 = type("", (), {})() - handler2.handle = call_recorder(lambda record: None) - handler2.level = logging.INFO + handler2 = stub( + handle=call_recorder(lambda record: None), + level=logging.INFO, + ) logger = logging.getLogger() logger.addHandler(handler1) logger.addHandler(handler2) @@ -729,7 +745,7 @@ def test_other_handlers_get_original_record( assert "meh" == handler2_record.msg @pytest.mark.parametrize("keep", [True, False]) - def test_formatter_unsets_exc_info(self, configure_for_pf, capsys, keep): + def test_formatter_unsets_exc_info(self, capsys, keep): """ Stack traces doesn't get printed outside of the json document when keep_exc_info are set to False but preserved if set to True. @@ -767,7 +783,7 @@ def format_exc_info_fake(logger, name, event_dict): assert "Traceback (most recent call last):" in err @pytest.mark.parametrize("keep", [True, False]) - def test_formatter_unsets_stack_info(self, configure_for_pf, capsys, keep): + def test_formatter_unsets_stack_info(self, capsys, keep): """ Stack traces doesn't get printed outside of the json document when keep_stack_info are set to False but preserved if set to True. @@ -794,11 +810,11 @@ def test_formatter_unsets_stack_info(self, configure_for_pf, capsys, keep): else: assert 2 == err.count("Stack (most recent call last):") - def test_native(self, configure_for_pf, capsys): + def test_native(self, capsys): """ If the log entry comes from structlog, it's unpackaged and processed. """ - configure_logging(None) + eds = configure_logging(None) get_logger().warning("foo") @@ -806,13 +822,15 @@ def test_native(self, configure_for_pf, capsys): "", "[warning ] foo [in test_native]\n", ) == capsys.readouterr() + assert eds[0]["_from_structlog"] is True + assert isinstance(eds[0]["_record"], logging.LogRecord) - def test_native_logger(self, configure_for_pf, capsys): + def test_native_logger(self, capsys): """ If the log entry comes from structlog, it's unpackaged and processed. """ logger = logging.getLogger() - configure_logging(None, logger=logger) + eds = configure_logging(None, logger=logger) get_logger().warning("foo") @@ -820,13 +838,15 @@ def test_native_logger(self, configure_for_pf, capsys): "", "[warning ] foo [in test_native_logger]\n", ) == capsys.readouterr() + assert eds[0]["_from_structlog"] is True + assert isinstance(eds[0]["_record"], logging.LogRecord) - def test_foreign_pre_chain_filter_by_level(self, configure_for_pf, capsys): + def test_foreign_pre_chain_filter_by_level(self, capsys): """ foreign_pre_chain works with filter_by_level processor. """ logger = logging.getLogger() - configure_logging((filter_by_level,), logger=logger) + configure_logging([filter_by_level], logger=logger) configure( processors=[ProcessorFormatter.wrap_for_formatter], logger_factory=LoggerFactory(), @@ -840,6 +860,31 @@ def test_foreign_pre_chain_filter_by_level(self, configure_for_pf, capsys): "foo [in test_foreign_pre_chain_filter_by_level]\n", ) == capsys.readouterr() + def test_processor_and_processors(self): + """ + Passing both processor and processors raises a TypeError. + """ + with pytest.raises(TypeError, match="mutually exclusive"): + ProcessorFormatter(processor=1, processors=[1]) + + def test_no_renderer(self): + """ + Passing neither processor nor processors raises a TypeError. + """ + with pytest.raises(TypeError, match="must be passed"): + ProcessorFormatter() + + def test_remove_processors_meta(self): + """ + remove_processors_meta removes _record and _from_structlog. And only + them. + """ + assert {"foo": "bar"} == ProcessorFormatter.remove_processors_meta( + None, + None, + {"foo": "bar", "_record": "foo", "_from_structlog": True}, + ) + @pytest.fixture(name="abl") async def _abl(cl): From c48b1f0954fd9d6ca74ac39c43219c467a9fafdc Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 19 Nov 2021 16:22:13 +0100 Subject: [PATCH 0593/1520] Don't run pre-commit in CI, only update monthly --- .pre-commit-config.yaml | 3 +++ tox.ini | 7 ++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 63aaf3a6..55f665c9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,4 +1,7 @@ --- +ci: + autoupdate_schedule: monthly + repos: - repo: https://github.com/psf/black rev: 21.11b1 diff --git a/tox.ini b/tox.ini index 848389ae..ed342c55 100644 --- a/tox.ini +++ b/tox.ini @@ -2,20 +2,21 @@ ignore = E203,W503,W504 # Keep docs in sync with docs env and .readthedocs.yml. +# We don't run pre-commit in CI, because we use pre-commit.ci. [gh-actions] python = 3.6: py36 3.7: py37 3.8: py38, docs 3.9: py39, mypy - 3.10: py310, cog, lint + 3.10: py310, cog pypy-3: pypy3 [tox] # Running tests on pypy3 is very slow, we don't need it for coverage, and it's # unlikely it'll ever break. Therefore, we only run it in CI -- just in case. -envlist = lint,mypy,cog,{py36,py37,py38,py39,py310}-threads,py39-greenlets,py39-colorama,py310-be,py310-rich,docs,pypi-description,coverage-report +envlist = pre-commit,mypy,cog,{py36,py37,py38,py39,py310}-threads,py39-greenlets,py39-colorama,py310-be,py310-rich,docs,pypi-description,coverage-report isolated_build = True @@ -32,7 +33,7 @@ commands = sphinx-build -n -T -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html -[testenv:lint] +[testenv:pre-commit] basepython = python3.10 skip_install = true deps = pre-commit From b21e732997e1155ba86aa009d67b2015b5ed5042 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 19 Nov 2021 18:51:33 +0100 Subject: [PATCH 0594/1520] Add mascot to PyPI page --- pyproject.toml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index e698bdf3..8a413e7a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -162,6 +162,9 @@ content-type = "text/x-rst" # import pathlib # print( # 'text = """' +# ".. image:: https://www.structlog.org/en/stable/_static/structlog_logo_small_transparent.png\n" +# " :alt: structlog mascot\n" +# " :align: center\n\n" # + pathlib.Path("README.rst") # .read_text() # .split(".. -begin-short-")[1] @@ -171,7 +174,11 @@ content-type = "text/x-rst" # end="" # ) # ]]] -text = """``structlog`` makes logging in Python **faster**, **less painful**, and **more powerful** by adding **structure** to your log entries. +text = """.. image:: https://www.structlog.org/en/stable/_static/structlog_logo_small_transparent.png + :alt: structlog mascot + :align: center + +``structlog`` makes logging in Python **faster**, **less painful**, and **more powerful** by adding **structure** to your log entries. It has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio* or type hints along the way, and `influenced the design `_ of `structured logging packages in other ecosystems `_. Thanks to its highly flexible design, it's up to you whether you want ``structlog`` to take care about the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's ``logging`` module. From ee615ecad79ba1972b03bb90122d2019f36834c2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 20 Nov 2021 14:48:28 +0100 Subject: [PATCH 0595/1520] Add tox target to verify that pyproject.toml is up to date cog-wise --- tox.ini | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index ed342c55..765332a2 100644 --- a/tox.ini +++ b/tox.ini @@ -9,7 +9,7 @@ python = 3.7: py37 3.8: py38, docs 3.9: py39, mypy - 3.10: py310, cog + 3.10: py310, cog-check pypy-3: pypy3 @@ -58,11 +58,18 @@ commands = mypy src tests/typing_examples.py description = "Update pyproject.toml's metadata" skip_install = true deps = - cogapp + cogapp>=3.3.0 tomli commands = python -m cogapp -rP pyproject.toml +[testenv:cog-check] +description = "Ensure pyproject.toml is up to date" +skip_install = true +deps = {[testenv:cog]deps} +commands = python -m cogapp --check -P pyproject.toml + + [testenv] extras = tests deps = From 60bf1c7a7cf0cf317722672de6e0111b6e102dc3 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 20 Nov 2021 14:57:26 +0100 Subject: [PATCH 0596/1520] Dashes are confusing --- tox.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index 765332a2..9232b72c 100644 --- a/tox.ini +++ b/tox.ini @@ -9,7 +9,7 @@ python = 3.7: py37 3.8: py38, docs 3.9: py39, mypy - 3.10: py310, cog-check + 3.10: py310, cogCheck pypy-3: pypy3 @@ -63,7 +63,7 @@ deps = commands = python -m cogapp -rP pyproject.toml -[testenv:cog-check] +[testenv:cogCheck] description = "Ensure pyproject.toml is up to date" skip_install = true deps = {[testenv:cog]deps} From e0adf4d06e1cc371df1599968fc64ef4906cc2fb Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 20 Nov 2021 14:59:45 +0100 Subject: [PATCH 0597/1520] wtf --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index 9232b72c..1411ae6e 100644 --- a/tox.ini +++ b/tox.ini @@ -65,6 +65,7 @@ commands = python -m cogapp -rP pyproject.toml [testenv:cogCheck] description = "Ensure pyproject.toml is up to date" +basepython = python3.10 skip_install = true deps = {[testenv:cog]deps} commands = python -m cogapp --check -P pyproject.toml From 7fdd847f43fcc2125b02bd8cb2bfead68af241cc Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 20 Nov 2021 15:33:48 +0100 Subject: [PATCH 0598/1520] Accept that we haven't run pypy3 tests in months We have to add cogCheck to the envlist so it's run in CI. I've added it before cog, so every re-render is loudly announced to the user. --- .github/workflows/main.yml | 2 +- README.rst | 3 ++- docs/loggers.rst | 2 +- pyproject.toml | 3 ++- tests/test_config.py | 2 +- tox.ini | 5 +---- 6 files changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index cf001cd4..9c18283a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,7 +19,7 @@ jobs: runs-on: "ubuntu-latest" strategy: matrix: - python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "pypy-3.7"] + python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"] steps: - uses: "actions/checkout@v2" diff --git a/README.rst b/README.rst index 018a8b16..8ff0c6f2 100644 --- a/README.rst +++ b/README.rst @@ -143,7 +143,8 @@ Project Information We collect useful third-party extension in `our wiki `_. -``structlog`` targets Python 3.6 and later; including PyPy3. +``structlog`` targets Python 3.6 and later. +PyPy3 is known to work, but is not tested anymore. ``structlog`` for Enterprise diff --git a/docs/loggers.rst b/docs/loggers.rst index 36bed069..d4f369c0 100644 --- a/docs/loggers.rst +++ b/docs/loggers.rst @@ -101,7 +101,7 @@ As you can see, it accepts one mandatory and a few optional arguments: The class to save your context in. Particularly useful for `thread-local context storage `. - Since Python 3.6+ and PyPy have ordered dictionaries, the default is a plain `dict`. + Since all supported Python versions have ordered dictionaries, the default is a plain `dict`. Additionally, the following arguments are allowed too: diff --git a/pyproject.toml b/pyproject.toml index 8a413e7a..a448d494 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -299,7 +299,8 @@ Project Information We collect useful third-party extension in `our wiki `_. -``structlog`` targets Python 3.6 and later; including PyPy3. +``structlog`` targets Python 3.6 and later. +PyPy3 is known to work, but is not tested anymore. ``structlog`` for Enterprise diff --git a/tests/test_config.py b/tests/test_config.py index 769090cf..4f597c61 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -58,7 +58,7 @@ class Foo(metaclass=abc.ABCMeta): def test_default_context_class(): """ - Default context class is dict on Python 3.6+ and PyPy + Default context class is dict. """ assert dict is _BUILTIN_DEFAULT_CONTEXT_CLASS diff --git a/tox.ini b/tox.ini index 1411ae6e..bb6b78bd 100644 --- a/tox.ini +++ b/tox.ini @@ -10,13 +10,10 @@ python = 3.8: py38, docs 3.9: py39, mypy 3.10: py310, cogCheck - pypy-3: pypy3 [tox] -# Running tests on pypy3 is very slow, we don't need it for coverage, and it's -# unlikely it'll ever break. Therefore, we only run it in CI -- just in case. -envlist = pre-commit,mypy,cog,{py36,py37,py38,py39,py310}-threads,py39-greenlets,py39-colorama,py310-be,py310-rich,docs,pypi-description,coverage-report +envlist = pre-commit,mypy,cogCheck,cog,{py36,py37,py38,py39,py310}-threads,py39-greenlets,py39-colorama,py310-be,py310-rich,docs,pypi-description,coverage-report isolated_build = True From f21c50a5c1dc7a9bc1299e1cfc39ee06226cd4a2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 20 Nov 2021 15:43:00 +0100 Subject: [PATCH 0599/1520] Prepare 21.3.0 --- CHANGELOG.rst | 2 +- src/structlog/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 11745d6e..c2e4bb77 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,7 +5,7 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. -21.3.0 (UNRELEASED) +21.3.0 (2021-11-20) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index e940699f..6b9c3268 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -42,7 +42,7 @@ contextvars = None # type: ignore -__version__ = "21.3.0.dev0" +__version__ = "21.3.0" __title__ = "structlog" __description__ = __doc__.strip() From 76076630fbb6b1d690d5b507c89169983900e764 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 20 Nov 2021 15:49:19 +0100 Subject: [PATCH 0600/1520] Start new development cycle --- CHANGELOG.rst | 25 +++++++++++++++++++++++++ src/structlog/__init__.py | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c2e4bb77..72a2ff92 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,31 @@ Versions are year-based with a strict backward compatibility policy. The third digit is only for regressions. +21.4.0 (UNRELEASED) +------------------- + + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +*none* + + +Deprecations: +^^^^^^^^^^^^^ + +*none* + + +Changes: +^^^^^^^^ + +*none* + + +---- + + 21.3.0 (2021-11-20) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 6b9c3268..e1461dc7 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -42,7 +42,7 @@ contextvars = None # type: ignore -__version__ = "21.3.0" +__version__ = "21.4.0.dev0" __title__ = "structlog" __description__ = __doc__.strip() From 7d8e860d47cd7b8374e5346d90a5c00edf8d0ee4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 20 Nov 2021 16:18:26 +0100 Subject: [PATCH 0601/1520] Don't check dev env on macOS It's slow and I inevitably notice if something breaks. --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9c18283a..caf80cf4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -102,7 +102,7 @@ jobs: runs-on: "${{ matrix.os }}" strategy: matrix: - os: ["ubuntu-latest", "windows-latest", "macos-latest"] + os: ["ubuntu-latest", "windows-latest"] steps: - uses: "actions/checkout@v2" From e1324aa6374b649abfbb7b9425f5a274712f9791 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 21 Nov 2021 14:06:40 +0100 Subject: [PATCH 0602/1520] Make frame filtering test more tolerant --- tests/test_stdlib.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index c95fe846..f65d5793 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -84,12 +84,19 @@ def test_ignores_frames(self): The name guesser walks up the frames until it reaches a frame whose name is not from structlog or one of the configurable other names. """ + + # Compute the names to __main__ so it doesn't get thrown off if people + # install plugins that alter the frames. E.g. #370 + names = set() + f = sys._getframe() + while f.f_globals["__name__"] != "__main__": + names.add(f.f_globals["__name__"].split(".", 1)[0]) + f = f.f_back + assert ( "__main__" == additional_frame( - LoggerFactory( - ignore_frame_names=["tests.", "_pytest.", "pluggy"] - ) + LoggerFactory(ignore_frame_names=list(names)) ).name ) From 4c78ed4c69df5107a12a43480c43d83e06e9dd21 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 24 Nov 2021 09:59:10 +0100 Subject: [PATCH 0603/1520] Switch to markdown CoC so GitHub can find it --- .github/CODE_OF_CONDUCT.md | 133 ++++++++++++++++++++++++++++++++++++ .github/CODE_OF_CONDUCT.rst | 55 --------------- .github/CONTRIBUTING.rst | 2 +- 3 files changed, 134 insertions(+), 56 deletions(-) create mode 100644 .github/CODE_OF_CONDUCT.md delete mode 100644 .github/CODE_OF_CONDUCT.rst diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..1d8ad183 --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,133 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/.github/CODE_OF_CONDUCT.rst b/.github/CODE_OF_CONDUCT.rst deleted file mode 100644 index 56e8914c..00000000 --- a/.github/CODE_OF_CONDUCT.rst +++ /dev/null @@ -1,55 +0,0 @@ -Contributor Covenant Code of Conduct -==================================== - -Our Pledge ----------- - -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. - -Our Standards -------------- - -Examples of behavior that contributes to creating a positive environment include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a professional setting - -Our Responsibilities --------------------- - -Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. - -Scope ------ - -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. -Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. -Representation of a project may be further defined and clarified by project maintainers. - -Enforcement ------------ - -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hs@ox.cx. -All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. -The project team is obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. - -Attribution ------------ - -This Code of Conduct is adapted from the `Contributor Covenant `_, version 1.4, available at . diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst index ff482b3c..f5463b8f 100644 --- a/.github/CONTRIBUTING.rst +++ b/.github/CONTRIBUTING.rst @@ -185,7 +185,7 @@ Thank you for considering contributing to ``structlog``! .. _`PEP 8`: https://www.python.org/dev/peps/pep-0008/ .. _`PEP 257`: https://www.python.org/dev/peps/pep-0257/ .. _`good test docstrings`: https://jml.io/pages/test-docstrings.html -.. _`Code of Conduct`: https://github.com/hynek/structlog/blob/main/.github/CODE_OF_CONDUCT.rst +.. _`Code of Conduct`: https://github.com/hynek/structlog/blob/main/.github/CODE_OF_CONDUCT.md .. _changelog: https://github.com/hynek/structlog/blob/main/CHANGELOG.rst .. _`backward compatibility`: https://www.structlog.org/en/latest/backward-compatibility.html .. _tox: https://tox.readthedocs.io/ From bd1ab858e7905acfb56318e2d1cee4f0ecd5e6ac Mon Sep 17 00:00:00 2001 From: Irven Aelbrecht Date: Wed, 24 Nov 2021 16:16:10 +0100 Subject: [PATCH 0604/1520] fix __doc__ is None in optimized mode (#373) * :bug: fix __doc__ is None in optimised mode * :art: fix formatting * :ok_hand: improve descriptions --- CHANGELOG.rst | 3 ++- src/structlog/__init__.py | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 72a2ff92..6072bd5b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,7 +24,8 @@ Deprecations: Changes: ^^^^^^^^ -*none* +- Fixed import when running in optimized mode (``PYTHONOPTIMIZE=2``). + `#373 `_ ---- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index e1461dc7..ed8196a2 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -45,7 +45,12 @@ __version__ = "21.4.0.dev0" __title__ = "structlog" -__description__ = __doc__.strip() +if __doc__ is None: + # __doc__ is None when running with PYTHONOPTIMIZE=2 / -OO + __description__ = "" # pragma: no cover +else: + __description__ = __doc__.strip() + __uri__ = "https://www.structlog.org/" __author__ = "Hynek Schlawack" From e59bc6f0f01e92d486f37ac6206ff82e28d29384 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 24 Nov 2021 16:16:52 +0100 Subject: [PATCH 0605/1520] Fix indent --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 6072bd5b..68a8a6bd 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -25,7 +25,7 @@ Changes: ^^^^^^^^ - Fixed import when running in optimized mode (``PYTHONOPTIMIZE=2``). - `#373 `_ + `#373 `_ ---- From 1d66f67fbb519282db670999250cdd99474470be Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 24 Nov 2021 16:31:26 +0100 Subject: [PATCH 0606/1520] Add test to verify structlog can be imported when running with python -OO --- .gitignore | 1 + pyproject.toml | 5 ++++- src/structlog/__init__.py | 2 +- tests/test_optimized.py | 10 ++++++++++ tox.ini | 18 ++++++++++-------- 5 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 tests/test_optimized.py diff --git a/.gitignore b/.gitignore index 440e17e7..e57460b8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *.egg-info *.pyc +*.pyo .cache .coverage* .mypy_cache diff --git a/pyproject.toml b/pyproject.toml index a448d494..914b5eb1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -111,7 +111,10 @@ dev = [ addopts = "-ra --strict-markers " xfail_strict = true testpaths = "tests" -filterwarnings = ["once::Warning"] +filterwarnings = [ + "once::Warning", + "ignore:.*are you using python -O.*:pytest.PytestConfigWarning", +] [tool.coverage.run] diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index ed8196a2..1903858d 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -47,7 +47,7 @@ __title__ = "structlog" if __doc__ is None: # __doc__ is None when running with PYTHONOPTIMIZE=2 / -OO - __description__ = "" # pragma: no cover + __description__ = "" # type: ignore else: __description__ = __doc__.strip() diff --git a/tests/test_optimized.py b/tests/test_optimized.py new file mode 100644 index 00000000..408b9812 --- /dev/null +++ b/tests/test_optimized.py @@ -0,0 +1,10 @@ +def test_can_import(): + """ + Checks whether it's possible to import structlog. + + This is used as part of our check whether structlog is importable when + running with -OO / PYTHONOPTIMIZE=2. + """ + import structlog + + assert isinstance(structlog.__description__, str) diff --git a/tox.ini b/tox.ini index bb6b78bd..edc475d9 100644 --- a/tox.ini +++ b/tox.ini @@ -82,14 +82,16 @@ commands = python -m pytest {posargs} deps = twisted setenv = PYTHONHASHSEED = 0 -commands = coverage run -m pytest {posargs} +commands = python -m coverage run -m pytest {posargs} [testenv:py310-threads] deps = twisted setenv = PYTHONHASHSEED = 0 -commands = coverage run -m pytest {posargs} +commands = + python -m coverage run -m pytest {posargs} + python -OO -m coverage run -m pytest tests/test_optimized.py [testenv:py39-greenlets] @@ -98,22 +100,22 @@ deps = twisted setenv = PYTHONHASHSEED = 0 -commands = coverage run -m pytest {posargs} +commands = python -m coverage run -m pytest {posargs} [testenv:py39-colorama] deps = colorama -commands = coverage run -m pytest tests/test_dev.py {posargs} +commands = python -m coverage run -m pytest tests/test_dev.py {posargs} [testenv:py310-be] deps = better-exceptions -commands = coverage run -m pytest tests/test_dev.py {posargs} +commands = python -m coverage run -m pytest tests/test_dev.py {posargs} [testenv:py310-rich] deps = rich -commands = coverage run -m pytest tests/test_dev.py {posargs} +commands = python -m coverage run -m pytest tests/test_dev.py {posargs} [testenv:coverage-report] @@ -123,8 +125,8 @@ skip_install = true parallel_show_output = true depends = {py36,py310}-threads,py39-greenlets,py39-colorama,py310-be,py310-rich commands = - coverage combine - coverage report + python -m coverage combine + python -m coverage report [testenv:pypi-description] From 12528a33aad30b87c02ce098ca2d9d767bbd8deb Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 25 Nov 2021 06:11:07 +0100 Subject: [PATCH 0607/1520] Update PULL_REQUEST_TEMPLATE.md --- .github/PULL_REQUEST_TEMPLATE.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 7755e4c2..09efbe83 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,3 +1,8 @@ +# Summary + +Please tell us what your pull request is about here. + + # Pull Request Check List This is just a friendly reminder about the most common mistakes. Please make sure that you tick all boxes. But please read our [contribution guide](https://www.structlog.org/en/latest/contributing.html) at least once, it will save you unnecessary review cycles! From e5507ad2799a4773f03375c69289801e6a08f0a9 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 25 Nov 2021 06:32:06 +0100 Subject: [PATCH 0608/1520] Add missing TODO --- .github/PULL_REQUEST_TEMPLATE.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 09efbe83..af598664 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -10,9 +10,10 @@ This is just a friendly reminder about the most common mistakes. Please make su If an item doesn't apply to your pull request, **check it anyway** to make it apparent that there's nothing left to do. - [ ] Added **tests** for changed code. +- [ ] **New APIs** are added to [`typing_examples.py`](https://github.com/hynek/structlog/blob/main/tests/typing_examples.py). - [ ] Updated **documentation** for changed code. - [ ] New functions/classes have to be added to `docs/api.rst` by hand. - - [ ] Changed/added classes/methods/functions have appropriate `versionadded`, `versionchanged`, or `deprecated` [directives](http://www.sphinx-doc.org/en/stable/markup/para.html#directive-versionadded). Find the appropriate next version in our [``__init__.py``](https://github.com/hynek/structlog/blob/main/src/structlog/__init__.py) file. + - [ ] Changed/added classes/methods/functions have appropriate `versionadded`, `versionchanged`, or `deprecated` [directives](http://www.sphinx-doc.org/en/stable/markup/para.html#directive-versionadded). Find the appropriate next version in our [`__init__.py`](https://github.com/hynek/structlog/blob/main/src/structlog/__init__.py) file. - [ ] Documentation in `.rst` files is written using [semantic newlines](https://rhodesmill.org/brandon/2012/one-sentence-per-line/). - [ ] Changes (and possible deprecations) are documented in the [changelog](https://github.com/hynek/structlog/blob/main/CHANGELOG.rst). From 3647f475aac642b3cd2ca746037009734010ff91 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 25 Nov 2021 13:59:33 +0100 Subject: [PATCH 0609/1520] GitHub really wants us to use Markdown --- .github/CONTRIBUTING.md | 193 ++++++++++++++++++++++++++++++ .github/CONTRIBUTING.rst | 199 ------------------------------- .github/PULL_REQUEST_TEMPLATE.md | 2 +- docs/contributing.rst | 3 - docs/index.rst | 1 - 5 files changed, 194 insertions(+), 204 deletions(-) create mode 100644 .github/CONTRIBUTING.md delete mode 100644 .github/CONTRIBUTING.rst delete mode 100644 docs/contributing.rst diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 00000000..3f288ad0 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,193 @@ +# How To Contribute + +First off, thank you for considering contributing to `structlog`! +It's people like *you* who make it such a great tool for everyone. + +This document intends to make contribution more accessible by codifying tribal knowledge and expectations. +Don't be afraid to open half-finished PRs, and ask questions if something is unclear! + +Please note that this project is released with a Contributor [Code of Conduct](https://github.com/hynek/structlog/blob/main/.github/CODE_OF_CONDUCT.md). +By participating in this project you agree to abide by its terms. +Please report any harm to [Hynek Schlawack] in any way you find appropriate. + + +## Workflow + +- No contribution is too small! + Please submit as many fixes for typos and grammar bloopers as you can! +- Try to limit each pull request to *one* change only. +- Since we squash on merge, it's up to you how you handle updates to the main branch. + Whether you prefer to rebase on main or merge main into your branch, do whatever is more comfortable for you. +- *Always* add tests and docs for your code. + This is a hard rule; patches with missing tests or documentation can't be merged. +- Make sure your changes pass our [CI]. + You won't get any feedback until it's green unless you ask for it. +- Once you've addressed review feedback, make sure to bump the pull request with a short note, so we know you're done. +- Don’t break [backward compatibility](https://structlog.org/en/latest/backward-compatibility.html). + + +## Code + +- Obey [PEP 8](https://www.python.org/dev/peps/pep-0008/) and [PEP 257](https://www.python.org/dev/peps/pep-0257/). + We use the `"""`-on-separate-lines style for docstrings: + + ```python + def func(x): + """ + Do something. + + :param str x: A very important parameter. + + :rtype: str + """ + ``` +- If you add or change public APIs, tag the docstring using `.. versionadded:: 16.0.0 WHAT` or `.. versionchanged:: 16.2.0 WHAT`. +- We use [*isort*](https://github.com/PyCQA/isort) to sort our imports, and we use [*Black*](https://github.com/psf/black) with line length of 79 characters to format our code. + As long as you run our full [*tox*] suite before committing, or install our [*pre-commit*] hooks (ideally you'll do both – see [*Local Development Environment*](#local-development-environment) below), you won't have to spend any time on formatting your code at all. + If you don't, [CI] will catch it for you – but that seems like a waste of your time! + + +## Tests + +- Write your asserts as `expected == actual` to line them up nicely: + + ```python + x = f() + + assert 42 == x.some_attribute + assert "foo" == x._a_private_attribute + ``` + +- To run the test suite, all you need is a recent [*tox*]. + It will ensure the test suite runs with all dependencies against all Python versions just as it will in our [CI]. + If you lack some Python versions, you can can always limit the environments like `tox -e py38,py39`, or make it a non-failure using `tox --skip-missing-interpreters`. + + In that case you should look into [*asdf*](https://asdf-vm.com) or [*pyenv*](https://github.com/pyenv/pyenv), which make it very easy to install many different Python versions in parallel. +- Write [good test docstrings](https://jml.io/pages/test-docstrings.html). +- To ensure new features work well with the rest of the system, they should be also added to our [*Hypothesis*](https://hypothesis.readthedocs.io/) testing strategy, which can be found in `tests/strategies.py`. +- If you've changed or added public APIs, please update our type stubs (files ending in `.pyi`). + + +## Documentation + +- Use [semantic newlines] in [*reStructuredText*] files (files ending in `.rst`): + + ```rst + This is a sentence. + This is another sentence. + ``` + +- If you start a new section, add two blank lines before and one blank line after the header, except if two headers follow immediately after each other: + + ```rst + Last line of previous section. + + + Header of New Top Section + ------------------------- + + Header of New Section + ^^^^^^^^^^^^^^^^^^^^^ + + First line of new section. + ``` + + +### Changelog + +If your change is noteworthy, there needs to be a changelog entry in `CHANGELOG.rst` so our users can learn about it! + +- As with other docs, please use [semantic newlines] in the changelog. +- Wrap symbols like modules, functions, or classes into double backticks so they are rendered in a `monospace font`. +- Wrap arguments into asterisks like in docstrings: + `Added new argument *an_argument*.` +- If you mention functions or other callables, add parentheses at the end of their names: + `structlog.func()` or `structlog.Class.method()`. + This makes the changelog a lot more readable. +- Prefer simple past tense or constructions with "now". + For example: + + + Added ``structlog.func()``. + + ``structlog.func()`` now doesn't crash the Large Hadron Collider anymore when passed the *foobar* argument. + +Example entries: + +```rst +Added ``structlog.func()``. +The feature really *is* awesome. +``` + +or: + +```rst +``structlog.func()`` now doesn't crash the Large Hadron Collider anymore when passed the *foobar* argument. +The bug really *was* nasty. +``` + + +## Local Development Environment + +You can (and should) run our test suite using [*tox*]. +However, you’ll probably want a more traditional environment as well. +We highly recommend to develop using the latest Python release because we try to take advantage of modern features whenever possible. + +First create a [virtual environment](https://virtualenv.pypa.io/) so you don't break your system-wide Python installation. +It’s out of scope for this document to list all the ways to manage virtual environments in Python, but if you don’t already have a pet way, take some time to look at tools like [*direnv*](https://github.com/direnv/direnv/wiki/Python), [*virtualfish*](https://virtualfish.readthedocs.io/), and [*virtualenvwrapper*](https://virtualenvwrapper.readthedocs.io/). + +Next, get an up to date checkout of the *structlog* repository: + +```console +$ git clone git@github.com:hynek/structlog.git +``` + +or if you want to use git via `https`: + +```console +$ git clone https://github.com/hynek/structlog.git +``` + +Change into the newly created directory and **after activating your virtual environment** install an editable version of *structlog* along with its tests and docs requirements: + +```console +$ cd structlog +$ pip install --upgrade pip setuptools # PLEASE don't skip this step +$ pip install -e '.[dev]' +``` + +At this point, + +```console +$ python -m pytest +``` + +should work and pass, as should: + +```console +$ cd docs +$ make html +``` + +The built documentation can then be found in `docs/_build/html/`. + +To avoid committing code that violates our style guide, we strongly advise you to install [*pre-commit*] [^dev] hooks: + +```console +$ pre-commit install +``` + +You can also run them anytime (as our tox does) using: + +```console +$ pre-commit run --all-files +``` + +[^dev]: *pre-commit* should have been installed into your virtualenv automatically when you ran `pip install -e '.[dev]'` above. + If *pre-commit* is missing, your probably need to run `pip install -e '.[dev]'` again. + + +[CI]: https://github.com/hynek/structlog/actions +[Hynek Schlawack]: https://hynek.me/about/ +[*pre-commit*]: https://pre-commit.com/ +[*tox*]: https://https://tox.wiki/ +[semantic newlines]: https://rhodesmill.org/brandon/2012/one-sentence-per-line/ +[*reStructuredText*]: https://www.sphinx-doc.org/en/stable/usage/restructuredtext/basics.html diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst deleted file mode 100644 index f5463b8f..00000000 --- a/.github/CONTRIBUTING.rst +++ /dev/null @@ -1,199 +0,0 @@ -How To Contribute -================= - -First off, thank you for considering contributing to ``structlog``! -It's people like *you* who make it is such a great tool for everyone. - -This document is mainly to help you to get started by codifying tribal knowledge and expectations and make it more accessible to everyone. -But don't be afraid to open half-finished PRs and ask questions if something is unclear! - - -Support -------- - -In case you'd like to help out but don't want to deal with GitHub, there's a great opportunity: -help your fellow developers on `StackOverflow `_! - -The official tag is ``structlog`` and helping out in support frees us up to improve ``structlog`` instead! - - -Workflow --------- - -- No contribution is too small! - Please submit as many fixes for typos and grammar bloopers as you can! -- Try to limit each pull request to *one* change only. -- Since we squash on merge, it's up to you how you handle updates to the main branch. - Whether you prefer to rebase on main or merge main into your branch, do whatever is more comfortable for you. -- *Always* add tests and docs for your code. - This is a hard rule; patches with missing tests or documentation can't be merged. -- Make sure your changes pass our CI_. - You won't get any feedback until it's green unless you ask for it. -- Once you've addressed review feedback, make sure to bump the pull request with a short note, so we know you're done. -- Don’t break `backward compatibility`_. - - -Code ----- - -- Obey `PEP 8`_ and `PEP 257`_. - We use the ``"""``\ -on-separate-lines style for docstrings: - - .. code-block:: python - - def func(x): - """ - Do something. - - :param str x: A very important parameter. - - :rtype: str - """ -- If you add or change public APIs, tag the docstring using ``.. versionadded:: 16.0.0 WHAT`` or ``.. versionchanged:: 17.1.0 WHAT``. -- We use isort_ to sort our imports, and we follow the Black_ code style with a line length of 79 characters. - As long as you run our full tox suite before committing, or install our pre-commit_ hooks (ideally you'll do both -- see below "Local Development Environment"), you won't have to spend any time on formatting your code at all. - If you don't, CI will catch it for you -- but that seems like a waste of your time! - - -Tests ------ - -- Write your asserts as ``expected == actual`` to line them up nicely and leave an empty line before them: - - .. code-block:: python - - x = f() - - assert 42 == x.some_attribute - assert "foo" == x._a_private_attribute - -- To run the test suite, all you need is a recent tox_. - It will ensure the test suite runs with all dependencies against all Python versions just as it will in our CI. - If you lack some Python versions, you can can make it a non-failure using ``tox --skip-missing-interpreters`` (in that case you may want to look into asdf_ or pyenv_ that make it very easy to install many different Python versions in parallel). -- Write `good test docstrings`_. - - -Documentation -------------- - -- Use `semantic newlines`_ in reStructuredText_ files (files ending in ``.rst``): - - .. code-block:: rst - - This is a sentence. - This is another sentence. - -- If you start a new section, add two blank lines before and one blank line after the header except if two headers follow immediately after each other: - - .. code-block:: rst - - Last line of previous section. - - - Header of New Top Section - ------------------------- - - Header of New Section - ^^^^^^^^^^^^^^^^^^^^^ - - First line of new section. -- If your change is noteworthy, add an entry to the changelog_. - Use `semantic newlines`_, and add a link to your pull request: - - .. code-block:: rst - - - Added ``structlog.func()`` that does foo. - It's pretty cool. - `#1 `_ - - ``structlog.func()`` now doesn't crash the Large Hadron Collider anymore. - That was a nasty bug! - `#2 `_ - - -Local Development Environment ------------------------------ - -You can (and should) run our test suite using tox_. -However, you’ll probably want a more traditional environment as well. -We highly recommend to develop using the latest Python 3 release because you're more likely to catch certain bugs earlier. - -First create a `virtual environment `_. -It’s out of scope for this document to list all the ways to manage virtual environments in Python but if you don’t have already a pet way, take some time to look at tools like `pew `_, `virtualfish `_, and `virtualenvwrapper `_. - -Next get an up to date checkout of the ``structlog`` repository: - -.. code-block:: bash - - $ git checkout git@github.com:hynek/structlog.git - -Change into the newly created directory and **after activating your virtual environment** install an editable version of ``structlog`` along with its test and docs dependencies: - -.. code-block:: bash - - $ cd structlog - $ pip install --upgrade pip setuptools # PLEASE don't skip this step - $ pip install -e .[dev] - -If you run the virtual environment’s Python and try to ``import structlog`` it should work! - -At this point - -.. code-block:: bash - - $ python -m pytest - -should work and pass - -and - -.. code-block:: bash - - $ cd docs - $ make html - - -should build docs in ``docs/_build/html``. - -To avoid committing code that violates our style guide, we strongly advise you to install pre-commit_ [#f1]_ hooks: - -.. code-block:: bash - - $ pre-commit install - -You can also run them anytime using: - -.. code-block:: bash - - $ pre-commit run --all-files - -.. [#f1] pre-commit should have been installed into your virtualenv automatically when you ran ``pip install -e '.[dev]'`` above. - If pre-commit is missing, it may be that you need to re-run ``pip install -e '.[dev]'``. - -**** - -Again, this list is mainly to help you to get started by codifying tribal knowledge and expectations. -If something is unclear, feel free to ask for help! - -Please note that this project is released with a Contributor `Code of Conduct`_. -By participating in this project you agree to abide by its terms. -Please report any harm to `Hynek Schlawack`_ in any way you find appropriate. - -Thank you for considering contributing to ``structlog``! - - -.. _`Hynek Schlawack`: https://hynek.me/about/ -.. _`PEP 8`: https://www.python.org/dev/peps/pep-0008/ -.. _`PEP 257`: https://www.python.org/dev/peps/pep-0257/ -.. _`good test docstrings`: https://jml.io/pages/test-docstrings.html -.. _`Code of Conduct`: https://github.com/hynek/structlog/blob/main/.github/CODE_OF_CONDUCT.md -.. _changelog: https://github.com/hynek/structlog/blob/main/CHANGELOG.rst -.. _`backward compatibility`: https://www.structlog.org/en/latest/backward-compatibility.html -.. _tox: https://tox.readthedocs.io/ -.. _pyenv: https://github.com/pyenv/pyenv -.. _asdf: https://asdf-vm.com/ -.. _reStructuredText: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html -.. _semantic newlines: https://rhodesmill.org/brandon/2012/one-sentence-per-line/ -.. _CI: https://github.com/hynek/structlog/actions?query=workflow%3ACI -.. _black: https://github.com/psf/black -.. _pre-commit: https://pre-commit.com/ -.. _isort: https://github.com/PyCQA/isort diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index af598664..7c95b8a0 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -5,7 +5,7 @@ Please tell us what your pull request is about here. # Pull Request Check List -This is just a friendly reminder about the most common mistakes. Please make sure that you tick all boxes. But please read our [contribution guide](https://www.structlog.org/en/latest/contributing.html) at least once, it will save you unnecessary review cycles! +This is just a friendly reminder about the most common mistakes. Please make sure that you tick all boxes. But please read our [contribution guide](https://github.com/hynek/structlog/blob/main/.github/CONTRIBUTING.md) at least once, it will save you unnecessary review cycles! If an item doesn't apply to your pull request, **check it anyway** to make it apparent that there's nothing left to do. diff --git a/docs/contributing.rst b/docs/contributing.rst deleted file mode 100644 index 8fbb03c9..00000000 --- a/docs/contributing.rst +++ /dev/null @@ -1,3 +0,0 @@ -.. _contributing: - -.. include:: ../.github/CONTRIBUTING.rst diff --git a/docs/index.rst b/docs/index.rst index 451dce30..b0d56572 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -79,7 +79,6 @@ API Reference :maxdepth: 1 backward-compatibility - contributing license changelog From a0becf5662f5c4b2083cb245fe006b5d33f20650 Mon Sep 17 00:00:00 2001 From: Fernando Brito Date: Thu, 25 Nov 2021 14:15:17 +0100 Subject: [PATCH 0610/1520] Add threadlocal bound context manager (#371) * Add threadlocal bound context manager * Add threadlocal bound context manager * Add threadlocal bound context manager * Add threadlocal bound context manager * Add threadlocal bound context manager * Add threadlocal bound context manager * Add threadlocal bound context manager * Update CHANGELOG.rst * Update src/structlog/threadlocal.py * Update src/structlog/threadlocal.py * Fix typing * Add typing example Co-authored-by: Hynek Schlawack --- CHANGELOG.rst | 2 ++ docs/api.rst | 4 +++ src/structlog/threadlocal.py | 24 +++++++++++++ tests/test_threadlocal.py | 66 +++++++++++++++++++++++++++++++++++- tests/typing_examples.py | 3 ++ 5 files changed, 98 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 68a8a6bd..2df0b2d9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -26,6 +26,8 @@ Changes: - Fixed import when running in optimized mode (``PYTHONOPTIMIZE=2``). `#373 `_ +- Added the ``structlog.threadlocal.bound_threadlocal`` decorator/context manager to temporarily bind key/value pairs to a thread-local context. + `#371 `_ ---- diff --git a/docs/api.rst b/docs/api.rst index ad6d5a5a..ecc0cb8b 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -119,6 +119,10 @@ Modern Approach .. autofunction:: bind_threadlocal +.. autofunction:: unbind_threadlocal + +.. autofunction:: bound_threadlocal + .. autofunction:: get_threadlocal >>> from structlog.threadlocal import bind_threadlocal, get_threadlocal diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index dfea798e..00d30c4e 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -93,6 +93,9 @@ def tmp_bind( ) -> Generator[TLLogger, None, None]: """ Bind *tmp_values* to *logger* & memorize current state. Rewind afterwards. + + Only works with `structlog.threadlocal.wrap_dict`-based contexts. + Use :func:`~structlog.threadlocal.bound_threadlocal` for new code. """ saved = as_immutable(logger)._context try: @@ -255,6 +258,27 @@ def unbind_threadlocal(*keys: str) -> None: context.pop(key, None) +@contextlib.contextmanager +def bound_threadlocal(**kw: Any) -> Generator[None, None, None]: + """ + Bind *kw* to the current thread-local context. Unbind or restore *kw* + afterwards. Do **not** affect other keys. + + Can be used as a context manager or decorator. + + .. versionadded:: 21.4.0 + """ + context = get_threadlocal() + saved = {k: context[k] for k in context.keys() & kw.keys()} + + bind_threadlocal(**kw) + try: + yield + finally: + unbind_threadlocal(*kw.keys()) + bind_threadlocal(**saved) + + def _get_context() -> Context: try: return _CONTEXT.context diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py index 5b7ff71e..5ff70454 100644 --- a/tests/test_threadlocal.py +++ b/tests/test_threadlocal.py @@ -2,7 +2,7 @@ # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. - +import inspect import threading import pytest @@ -16,6 +16,7 @@ _CONTEXT, as_immutable, bind_threadlocal, + bound_threadlocal, clear_threadlocal, get_merged_threadlocal, get_threadlocal, @@ -368,3 +369,66 @@ def test_get_merged(self): log = structlog.get_logger().bind(y=2) assert {"x": 1, "y": 2} == get_merged_threadlocal(log) + + +class TestBoundThreadlocal: + def test_cleanup(self): + """ + Bindings are cleaned up + """ + with bound_threadlocal(x=42, y="foo"): + assert {"x": 42, "y": "foo"} == get_threadlocal() + + assert {} == get_threadlocal() + + def test_cleanup_conflict(self): + """ + Overwritten keys are restored after the clean up + """ + bind_threadlocal(x="original", z="unrelated") + with bound_threadlocal(x=42, y="foo"): + assert {"x": 42, "y": "foo", "z": "unrelated"} == get_threadlocal() + + assert {"x": "original", "z": "unrelated"} == get_threadlocal() + + def test_preserve_independent_bind(self): + """ + New bindings inside bound_threadlocal are preserved after the clean up + """ + with bound_threadlocal(x=42): + bind_threadlocal(y="foo") + assert {"x": 42, "y": "foo"} == get_threadlocal() + + assert {"y": "foo"} == get_threadlocal() + + def test_nesting_works(self): + """ + bound_threadlocal binds and unbinds even when nested + """ + with bound_threadlocal(l1=1): + assert {"l1": 1} == get_threadlocal() + + with bound_threadlocal(l2=2): + assert {"l1": 1, "l2": 2} == get_threadlocal() + + assert {"l1": 1} == get_threadlocal() + + assert {} == get_threadlocal() + + def test_as_decorator(self): + """ + bound_threadlocal can be used as a decorator and it preserves the name, + signature and documentation of the wrapped function. + """ + + @bound_threadlocal(x=42) + def wrapped(arg1): + """Wrapped documentation""" + bind_threadlocal(y=arg1) + assert {"x": 42, "y": arg1} == get_threadlocal() + + wrapped(23) + + assert "wrapped" == wrapped.__name__ + assert "(arg1)" == str(inspect.signature(wrapped)) + assert "Wrapped documentation" == wrapped.__doc__ diff --git a/tests/typing_examples.py b/tests/typing_examples.py index 3f9852a1..8ce999fe 100644 --- a/tests/typing_examples.py +++ b/tests/typing_examples.py @@ -213,3 +213,6 @@ def bytes_dumps( wrapper_class=structlog.stdlib.BoundLogger, cache_logger_on_first_use=True, ) + +with structlog.threadlocal.bound_threadlocal(x=42): + pass From 05c4b51004ac8bf0d24e52c421d8ecc6aaa433e3 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 25 Nov 2021 15:19:14 +0100 Subject: [PATCH 0611/1520] Add example for bound_threadlocal --- docs/thread-local.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/thread-local.rst b/docs/thread-local.rst index cc105626..553fc27f 100644 --- a/docs/thread-local.rst +++ b/docs/thread-local.rst @@ -47,6 +47,7 @@ The general flow of using these functions is: >>> from structlog.threadlocal import ( ... bind_threadlocal, + ... bound_threadlocal, ... clear_threadlocal, ... get_merged_threadlocal, ... get_threadlocal, @@ -69,6 +70,13 @@ The general flow of using these functions is: >>> # (perhaps by using structlog.get_logger() to create them). >>> log.msg("hi") a=1 event='hi' + >>> # You can also bind key/value pairs temporarily. + >>> with bound_threadlocal(b=2): + ... log.msg("hi") + a=1 b=2 event='hi' + >>> # Now it's gone again. + >>> log.msg("hi") + a=1 event='hi' >>> # You can access the current thread-local state. >>> get_threadlocal() {'a': 1} From e45b84beb3cc6134a3a548e7686ba2bc9a116d6e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 25 Nov 2021 15:44:18 +0100 Subject: [PATCH 0612/1520] Add structlog.contextvars.bound_contextvars, add missing example to thread-local.rst --- CHANGELOG.rst | 2 +- docs/api.rst | 1 + docs/contextvars.rst | 14 ++++++-- docs/thread-local.rst | 7 +++- src/structlog/contextvars.py | 24 ++++++++++++- tests/test_contextvars.py | 65 ++++++++++++++++++++++++++++++++++++ 6 files changed, 107 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2df0b2d9..3f8101f3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -26,7 +26,7 @@ Changes: - Fixed import when running in optimized mode (``PYTHONOPTIMIZE=2``). `#373 `_ -- Added the ``structlog.threadlocal.bound_threadlocal`` decorator/context manager to temporarily bind key/value pairs to a thread-local context. +- Added the ``structlog.threadlocal.bound_threadlocal`` and ``structlog.contextvars.bound_contextvars`` decorator/context managers to temporarily bind key/value pairs to a thread-local and context-local context. `#371 `_ diff --git a/docs/api.rst b/docs/api.rst index ecc0cb8b..29665204 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -175,6 +175,7 @@ Please see :doc:`thread-local` for details. .. automodule:: structlog.contextvars .. autofunction:: bind_contextvars +.. autofunction:: bound_contextvars .. autofunction:: get_contextvars .. autofunction:: get_merged_contextvars .. autofunction:: merge_contextvars diff --git a/docs/contextvars.rst b/docs/contextvars.rst index 1c3bc484..37438bcd 100644 --- a/docs/contextvars.rst +++ b/docs/contextvars.rst @@ -29,6 +29,7 @@ The general flow mirrors the one for :doc:`thread-local `: >>> from structlog.contextvars import ( ... bind_contextvars, + ... bound_contextvars, ... clear_contextvars, ... merge_contextvars, ... unbind_contextvars, @@ -42,7 +43,7 @@ The general flow mirrors the one for :doc:`thread-local `: ... ) >>> log = structlog.get_logger() >>> # At the top of your request handler (or, ideally, some general - >>> # middleware), clear the threadlocal context and bind some common + >>> # middleware), clear the contextvars-local context and bind some common >>> # values: >>> clear_contextvars() >>> bind_contextvars(a=1, b=2) @@ -51,11 +52,18 @@ The general flow mirrors the one for :doc:`thread-local `: >>> # (perhaps by using structlog.get_logger() to create them). >>> log.msg("hello") event='hello' a=1 b=2 - >>> # Use unbind_contextvars to remove a variable from the context + >>> # Use unbind_contextvars to remove a variable from the context. >>> unbind_contextvars("b") >>> log.msg("world") event='world' a=1 - >>> # And when we clear the threadlocal state again, it goes away. + >>> # You can also bind key/value pairs temporarily. + >>> with bound_contextvars(b=2): + ... log.msg("hi") + event='hi' a=1 b=2 + >>> # Now it's gone again. + >>> log.msg("hi") + event='hi' a=1 + >>> # And when we clear the contextvars state again, it goes away. >>> # a=None is printed due to the key_order argument passed to >>> # KeyValueRenderer, but it is NOT present anymore. >>> clear_contextvars() diff --git a/docs/thread-local.rst b/docs/thread-local.rst index 553fc27f..59694220 100644 --- a/docs/thread-local.rst +++ b/docs/thread-local.rst @@ -52,6 +52,7 @@ The general flow of using these functions is: ... get_merged_threadlocal, ... get_threadlocal, ... merge_threadlocal, + ... unbind_threadlocal, ... ) >>> from structlog import configure >>> configure( @@ -65,10 +66,14 @@ The general flow of using these functions is: >>> # middleware), clear the thread-local context and bind some common >>> # values: >>> clear_threadlocal() - >>> bind_threadlocal(a=1) + >>> bind_threadlocal(a=1, b=2) >>> # Then use loggers as per normal >>> # (perhaps by using structlog.get_logger() to create them). >>> log.msg("hi") + a=1 b=2 event='hi' + >>> # Use unbind_threadlocal to remove a variable from the context. + >>> unbind_threadlocal("b") + >>> log.msg("hi") a=1 event='hi' >>> # You can also bind key/value pairs temporarily. >>> with bound_threadlocal(b=2): diff --git a/src/structlog/contextvars.py b/src/structlog/contextvars.py index 3831ded0..a4500f8a 100644 --- a/src/structlog/contextvars.py +++ b/src/structlog/contextvars.py @@ -15,9 +15,10 @@ See :doc:`contextvars`. """ +import contextlib import contextvars -from typing import Any, Dict, Mapping +from typing import Any, Dict, Generator, Mapping import structlog @@ -154,3 +155,24 @@ def unbind_contextvars(*keys: str) -> None: structlog_k = f"{STRUCTLOG_KEY_PREFIX}{k}" if structlog_k in _CONTEXT_VARS: _CONTEXT_VARS[structlog_k].set(Ellipsis) + + +@contextlib.contextmanager +def bound_contextvars(**kw: Any) -> Generator[None, None, None]: + """ + Bind *kw* to the current context-local context. Unbind or restore *kw* + afterwards. Do **not** affect other keys. + + Can be used as a context manager or decorator. + + .. versionadded:: 21.4.0 + """ + context = get_contextvars() + saved = {k: context[k] for k in context.keys() & kw.keys()} + + bind_contextvars(**kw) + try: + yield + finally: + unbind_contextvars(*kw.keys()) + bind_contextvars(**saved) diff --git a/tests/test_contextvars.py b/tests/test_contextvars.py index bb5c776a..a64a6d47 100644 --- a/tests/test_contextvars.py +++ b/tests/test_contextvars.py @@ -4,6 +4,7 @@ # repository for complete details. import asyncio +import inspect import secrets import pytest @@ -13,6 +14,7 @@ from structlog.contextvars import ( _CONTEXT_VARS, bind_contextvars, + bound_contextvars, clear_contextvars, get_contextvars, get_merged_contextvars, @@ -230,3 +232,66 @@ def test_get_merged_merges_context(self): log = structlog.get_logger().bind(y=2) assert {"x": 1, "y": 2} == get_merged_contextvars(log) + + +class TestBoundContextvars: + def test_cleanup(self): + """ + Bindings are cleaned up + """ + with bound_contextvars(x=42, y="foo"): + assert {"x": 42, "y": "foo"} == get_contextvars() + + assert {} == get_contextvars() + + def test_cleanup_conflict(self): + """ + Overwritten keys are restored after the clean up + """ + bind_contextvars(x="original", z="unrelated") + with bound_contextvars(x=42, y="foo"): + assert {"x": 42, "y": "foo", "z": "unrelated"} == get_contextvars() + + assert {"x": "original", "z": "unrelated"} == get_contextvars() + + def test_preserve_independent_bind(self): + """ + New bindings inside bound_contextvars are preserved after the clean up + """ + with bound_contextvars(x=42): + bind_contextvars(y="foo") + assert {"x": 42, "y": "foo"} == get_contextvars() + + assert {"y": "foo"} == get_contextvars() + + def test_nesting_works(self): + """ + bound_contextvars binds and unbinds even when nested + """ + with bound_contextvars(l1=1): + assert {"l1": 1} == get_contextvars() + + with bound_contextvars(l2=2): + assert {"l1": 1, "l2": 2} == get_contextvars() + + assert {"l1": 1} == get_contextvars() + + assert {} == get_contextvars() + + def test_as_decorator(self): + """ + bound_contextvars can be used as a decorator and it preserves the + name, signature and documentation of the wrapped function. + """ + + @bound_contextvars(x=42) + def wrapped(arg1): + """Wrapped documentation""" + bind_contextvars(y=arg1) + assert {"x": 42, "y": arg1} == get_contextvars() + + wrapped(23) + + assert "wrapped" == wrapped.__name__ + assert "(arg1)" == str(inspect.signature(wrapped)) + assert "Wrapped documentation" == wrapped.__doc__ From 677b79452901d4befc47f0129dcb4b4bc4ee53db Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 25 Nov 2021 15:47:42 +0100 Subject: [PATCH 0613/1520] Simplify -OO handling --- src/structlog/__init__.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 1903858d..23301104 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -45,11 +45,8 @@ __version__ = "21.4.0.dev0" __title__ = "structlog" -if __doc__ is None: - # __doc__ is None when running with PYTHONOPTIMIZE=2 / -OO - __description__ = "" # type: ignore -else: - __description__ = __doc__.strip() +# __doc__ is None when running with PYTHONOPTIMIZE=2 / -OO +__description__ = (__doc__ or "").strip() __uri__ = "https://www.structlog.org/" From e5ad4fbd43020165c32c55bdd633a2acd904fed7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 25 Nov 2021 15:59:47 +0100 Subject: [PATCH 0614/1520] Update changelog --- CHANGELOG.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 3f8101f3..5c930d5e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,8 +1,7 @@ Changelog ========= -Versions are year-based with a strict backward compatibility policy. -The third digit is only for regressions. +Versions follow `CalVer `_ with a strict backwards compatibility policy. 21.4.0 (UNRELEASED) @@ -24,7 +23,7 @@ Deprecations: Changes: ^^^^^^^^ -- Fixed import when running in optimized mode (``PYTHONOPTIMIZE=2``). +- Fixed import when running in optimized mode (``PYTHONOPTIMIZE=2``, or ``python -OO``). `#373 `_ - Added the ``structlog.threadlocal.bound_threadlocal`` and ``structlog.contextvars.bound_contextvars`` decorator/context managers to temporarily bind key/value pairs to a thread-local and context-local context. `#371 `_ From 2c2bcc34a3e279754af8b966a163f35736520304 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 25 Nov 2021 16:08:51 +0100 Subject: [PATCH 0615/1520] Fold backwards compatibility policy into changelog --- .github/CONTRIBUTING.md | 2 +- CHANGELOG.rst | 9 +++++++++ docs/backward-compatibility.rst | 16 ---------------- docs/index.rst | 1 - 4 files changed, 10 insertions(+), 18 deletions(-) delete mode 100644 docs/backward-compatibility.rst diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 3f288ad0..dc500a9f 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -23,7 +23,7 @@ Please report any harm to [Hynek Schlawack] in any way you find appropriate. - Make sure your changes pass our [CI]. You won't get any feedback until it's green unless you ask for it. - Once you've addressed review feedback, make sure to bump the pull request with a short note, so we know you're done. -- Don’t break [backward compatibility](https://structlog.org/en/latest/backward-compatibility.html). +- Don’t break backwards compatibility. ## Code diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5c930d5e..f36076aa 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,6 +3,15 @@ Changelog Versions follow `CalVer `_ with a strict backwards compatibility policy. +Put simply, you shouldn't ever be afraid to upgrade ``structlog`` if you're using its public APIs. +Whenever there is a need to break compatibility, it is announced here in the changelog, and raises a ``DeprecationWarning`` for a year (if possible) before it's finally really broken. + +.. warning:: + + You cannot rely on the default settings and the `structlog.dev` module. + They may be adjusted in the future to provide a better experience when starting to use ``structlog``. + So please make sure to **always** properly configure your applications. + 21.4.0 (UNRELEASED) ------------------- diff --git a/docs/backward-compatibility.rst b/docs/backward-compatibility.rst deleted file mode 100644 index 0d5abb07..00000000 --- a/docs/backward-compatibility.rst +++ /dev/null @@ -1,16 +0,0 @@ -Backward Compatibility -====================== - -``structlog`` has a very strong backward compatibility policy that is inspired by the one of the `Twisted framework `_. - -Put simply, you shouldn't ever be afraid to upgrade ``structlog`` if you're using its public APIs. -If there will ever be need to break compatibility, it will be announced in the :doc:`changelog` and raise deprecation warning for a year before it's finally really broken. - - -.. _exemption: - -.. warning:: - - You cannot however rely on the default settings and the :mod:`structlog.dev` module. - They may be adjusted in the future to provide a better experience when starting to use ``structlog``. - So please make sure to **always** properly configure your applications. diff --git a/docs/index.rst b/docs/index.rst index b0d56572..cafa06d4 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -78,7 +78,6 @@ API Reference .. toctree:: :maxdepth: 1 - backward-compatibility license changelog From c31ec11a540f34a2602e88fa697b57a6fe6c13e3 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 25 Nov 2021 16:19:46 +0100 Subject: [PATCH 0616/1520] We don't need that comma --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f36076aa..9500ce5f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -32,7 +32,7 @@ Deprecations: Changes: ^^^^^^^^ -- Fixed import when running in optimized mode (``PYTHONOPTIMIZE=2``, or ``python -OO``). +- Fixed import when running in optimized mode (``PYTHONOPTIMIZE=2`` or ``python -OO``). `#373 `_ - Added the ``structlog.threadlocal.bound_threadlocal`` and ``structlog.contextvars.bound_contextvars`` decorator/context managers to temporarily bind key/value pairs to a thread-local and context-local context. `#371 `_ From e9e77e81a07325ffc2eaa260fa1ec47a7bab378f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 25 Nov 2021 16:32:48 +0100 Subject: [PATCH 0617/1520] Prepare 21.4.0 --- CHANGELOG.rst | 2 +- src/structlog/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9500ce5f..9b49bf7a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -13,7 +13,7 @@ Whenever there is a need to break compatibility, it is announced here in the cha So please make sure to **always** properly configure your applications. -21.4.0 (UNRELEASED) +21.4.0 (2021-11-25) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 23301104..6f2b3ea2 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -42,7 +42,7 @@ contextvars = None # type: ignore -__version__ = "21.4.0.dev0" +__version__ = "21.4.0" __title__ = "structlog" # __doc__ is None when running with PYTHONOPTIMIZE=2 / -OO From 0b2ec187dacb2a024c8d89cf3364c86b8174767b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 25 Nov 2021 16:36:31 +0100 Subject: [PATCH 0618/1520] Start new development cycle --- CHANGELOG.rst | 1 + src/structlog/__init__.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9b49bf7a..45621500 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,6 +12,7 @@ Whenever there is a need to break compatibility, it is announced here in the cha They may be adjusted in the future to provide a better experience when starting to use ``structlog``. So please make sure to **always** properly configure your applications. +.. changelog 21.4.0 (2021-11-25) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 6f2b3ea2..63103b3f 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -42,7 +42,7 @@ contextvars = None # type: ignore -__version__ = "21.4.0" +__version__ = "21.5.0.dev0" __title__ = "structlog" # __doc__ is None when running with PYTHONOPTIMIZE=2 / -OO From 3179b9c9a8ddb34da04cc4608cd9435d5580447d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 25 Nov 2021 16:39:28 +0100 Subject: [PATCH 0619/1520] Fix changelog --- CHANGELOG.rst | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 45621500..2b0239dc 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,6 +14,31 @@ Whenever there is a need to break compatibility, it is announced here in the cha .. changelog +21.5.0 (UNRELEASED) +------------------- + + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +*none* + + +Deprecations: +^^^^^^^^^^^^^ + +*none* + + +Changes: +^^^^^^^^ + +*none* + + +---- + + 21.4.0 (2021-11-25) ------------------- From 1eb4c2781d40ad490dc33361c51ef1b58a8c3e7e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 25 Nov 2021 16:44:24 +0100 Subject: [PATCH 0620/1520] This ain't YAML! --- .github/{SECURITY.yml => SECURITY.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{SECURITY.yml => SECURITY.md} (100%) diff --git a/.github/SECURITY.yml b/.github/SECURITY.md similarity index 100% rename from .github/SECURITY.yml rename to .github/SECURITY.md From d982589257c4f22d32426e775c5d02dd545e872f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 26 Nov 2021 07:15:49 +0100 Subject: [PATCH 0621/1520] Link to more concrete blog post --- .github/CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index dc500a9f..8c778a01 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -132,7 +132,7 @@ However, you’ll probably want a more traditional environment as well. We highly recommend to develop using the latest Python release because we try to take advantage of modern features whenever possible. First create a [virtual environment](https://virtualenv.pypa.io/) so you don't break your system-wide Python installation. -It’s out of scope for this document to list all the ways to manage virtual environments in Python, but if you don’t already have a pet way, take some time to look at tools like [*direnv*](https://github.com/direnv/direnv/wiki/Python), [*virtualfish*](https://virtualfish.readthedocs.io/), and [*virtualenvwrapper*](https://virtualenvwrapper.readthedocs.io/). +It’s out of scope for this document to list all the ways to manage virtual environments in Python, but if you don’t already have a pet way, take some time to look at tools like [*direnv*](https://hynek.me/til/python-project-local-venvs/), [*virtualfish*](https://virtualfish.readthedocs.io/), and [*virtualenvwrapper*](https://virtualenvwrapper.readthedocs.io/). Next, get an up to date checkout of the *structlog* repository: From 0cb65da7d2e71ccbd4f3162b26dc16b25f4eecad Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 26 Nov 2021 07:29:55 +0100 Subject: [PATCH 0622/1520] Add pyupgrade hook --- .pre-commit-config.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 55f665c9..6e6f7764 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,6 +9,12 @@ repos: - id: black language_version: python3.10 + - repo: https://github.com/asottile/pyupgrade + rev: v2.29.1 + hooks: + - id: pyupgrade + args: [--py36-plus] + - repo: https://github.com/PyCQA/isort rev: 5.10.1 hooks: From 57634ff4fc0a6666e75a37f44a8713c304f54d05 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 27 Nov 2021 10:54:09 +0100 Subject: [PATCH 0623/1520] Update CONTRIBUTING.md --- .github/CONTRIBUTING.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 8c778a01..b436e482 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -64,7 +64,6 @@ Please report any harm to [Hynek Schlawack] in any way you find appropriate. In that case you should look into [*asdf*](https://asdf-vm.com) or [*pyenv*](https://github.com/pyenv/pyenv), which make it very easy to install many different Python versions in parallel. - Write [good test docstrings](https://jml.io/pages/test-docstrings.html). -- To ensure new features work well with the rest of the system, they should be also added to our [*Hypothesis*](https://hypothesis.readthedocs.io/) testing strategy, which can be found in `tests/strategies.py`. - If you've changed or added public APIs, please update our type stubs (files ending in `.pyi`). @@ -107,8 +106,8 @@ If your change is noteworthy, there needs to be a changelog entry in `CHANGELOG. - Prefer simple past tense or constructions with "now". For example: - + Added ``structlog.func()``. - + ``structlog.func()`` now doesn't crash the Large Hadron Collider anymore when passed the *foobar* argument. + * Added `structlog.func()`. + * `structlog.func()` now doesn't crash the Large Hadron Collider anymore when passed the *foobar* argument. Example entries: From 4aa12526167dda3c998c1811d987a4c8e2b1941b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 28 Nov 2021 14:38:47 +0100 Subject: [PATCH 0624/1520] Use importlib.metadata to find the version in Sphinx docs --- docs/conf.py | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 4a3e16ba..4196e070 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -3,31 +3,13 @@ # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. -import codecs -import os -import re +from importlib.metadata import version -here = os.path.abspath(os.path.dirname(__file__)) - # We want an image in the README and include the README in the docs. suppress_warnings = ["image.nonlocal_uri"] -def read(*parts): - return codecs.open(os.path.join(here, *parts), "r").read() - - -def find_version(*file_paths): - version_file = read(*file_paths) - version_match = re.search( - r"^__version__ = ['\"]([^'\"]*)['\"]", version_file, re.M - ) - if version_match: - return version_match.group(1) - raise RuntimeError("Unable to find version string.") - - # -- General configuration ---------------------------------------------------- extensions = [ @@ -59,7 +41,7 @@ def find_version(*file_paths): # built documents. # # The short X.Y version. -version = find_version("..", "src", "structlog", "__init__.py") +version = version("structlog") # The full version, including alpha/beta/rc tags. release = "" exclude_patterns = ["_build"] From a20aa8b81a2005b28f4d6ab126b94d44b14be79f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 28 Nov 2021 14:54:31 +0100 Subject: [PATCH 0625/1520] Use correct release tag in docs --- docs/conf.py | 11 ++++++----- docs/index.rst | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 4196e070..c526fdda 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -3,7 +3,7 @@ # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. -from importlib.metadata import version +from importlib import metadata # We want an image in the README and include the README in the docs. @@ -39,11 +39,12 @@ # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. -# -# The short X.Y version. -version = version("structlog") + # The full version, including alpha/beta/rc tags. -release = "" +release = metadata.version("structlog") +# The short X.Y version. +version = release.rsplit(".", 1)[0] + exclude_patterns = ["_build"] # The reST default role (used for this markup: `text`) to use for all diff --git a/docs/index.rst b/docs/index.rst index cafa06d4..9685dccd 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -2,7 +2,7 @@ Structured Logging for Python ============================= -Release v\ |version| (`What's new? `). +Release v\ |release| (`What's new? `) .. include:: ../README.rst :start-after: -begin-short- From 74a9b5563df306e3cb10712c85fbd8b767bf0beb Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 28 Nov 2021 15:36:11 +0100 Subject: [PATCH 0626/1520] Shorten README and just link --- README.rst | 93 ++------------------------------------------------ docs/index.rst | 1 - docs/why.rst | 88 +++++++++++++++++++++++++++++++++++++++++++++-- pyproject.toml | 93 ++------------------------------------------------ 4 files changed, 89 insertions(+), 186 deletions(-) diff --git a/README.rst b/README.rst index 8ff0c6f2..daf0364c 100644 --- a/README.rst +++ b/README.rst @@ -31,101 +31,12 @@ Thanks to its highly flexible design, it's up to you whether you want ``structlo .. -end-short- -Once you feel inspired to try it out, check out our friendly `Getting Started tutorial `_ that also contains detailed installation instructions! +A short explanation on *why* structured logging is good for you, and why ``structlog`` is the right tool for the job can be found in the `Why chapter `_ of our documentation. -.. -begin-spiel- +Once you feel inspired to try it out, check out our friendly `Getting Started tutorial `_ that also contains detailed installation instructions! If you prefer videos over reading, check out `Markus Holtermann `_'s DjangoCon Europe 2019 talk: `Logging Rethought 2: The Actions of Frank Taylor Jr. `_ - -Easier Logging -============== - -You can stop writing prose and start thinking in terms of an event that happens in the context of key/value pairs: - -.. code-block:: pycon - - >>> from structlog import get_logger - >>> log = get_logger() - >>> log.info("key_value_logging", out_of_the_box=True, effort=0) - 2020-11-18 09:17.09 [info ] key_value_logging effort=0 out_of_the_box=True - -Each log entry is a meaningful dictionary instead of an opaque string now! - - -Data Binding -============ - -Since log entries are dictionaries, you can start binding and re-binding key/value pairs to your loggers to ensure they are present in every following logging call: - -.. code-block:: pycon - - >>> log = log.bind(user="anonymous", some_key=23) - >>> log = log.bind(user="hynek", another_key=42) - >>> log.info("user.logged_in", happy=True) - 2020-11-18 09:18.28 [info ] user.logged_in another_key=42 happy=True some_key=23 user=hynek - -You can also bind key/value pairs to `thread-local storage `_ and `contextvars `_. - - -Powerful Pipelines -================== - -Each log entry goes through a `processor pipeline `_ that is just a chain of functions that receive a dictionary and return a new dictionary that gets fed into the next function. -That allows for simple but powerful data manipulation: - -.. code-block:: python - - def timestamper(logger, log_method, event_dict): - """Add a timestamp to each log entry.""" - event_dict["timestamp"] = time.time() - return event_dict - -There are `plenty of processors `_ for most common tasks coming with ``structlog``: - -- Collectors of `call stack information `_ ("How did this log entry happen?"), -- …and `exceptions `_ ("What happened‽"). -- Unicode encoders/decoders. -- Flexible `timestamping `_. - - -Formatting -========== - -``structlog`` is completely flexible about *how* the resulting log entry is emitted. -Since each log entry is a dictionary, it can be formatted to **any** format: - -- A colorful key/value format for `local development `_, -- `JSON `_ for easy parsing, -- or some standard format you have parsers for like nginx or Apache httpd. - -Internally, formatters are processors whose return value (usually a string) is passed into loggers that are responsible for the output of your message. -``structlog`` comes with multiple useful formatters out-of-the-box. - - -Output -====== - -``structlog`` is also flexible with the final output of your log entries: - -- A **built-in** lightweight printer like in the examples above. - Easy to use and fast. -- Use the **standard library**'s or **Twisted**'s logging modules for compatibility. - In this case ``structlog`` works like a wrapper that formats a string and passes them off into existing systems that won't know that ``structlog`` even exists. - Or the other way round: ``structlog`` comes with a ``logging`` formatter that allows for processing third party log records. -- Don't format it to a string at all! - ``structlog`` passes you a dictionary and you can do with it whatever you want. - Reported uses cases are sending them out via network or saving them in a database. - - -Highly Testable -=============== - -``structlog`` is thouroughly tested and we see it as our duty to help you to achieve the same in *your* applications. -That's why it ships with a `bunch of helpers `_ to introspect your application's logging behavior with little-to-no boilerplate. - -.. -end-spiel- - .. -begin-meta- Getting Help diff --git a/docs/index.rst b/docs/index.rst index 9685dccd..a7605afd 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -19,7 +19,6 @@ First steps: User's Guide ============ - Basics ------ diff --git a/docs/why.rst b/docs/why.rst index 0dbb5fa8..18a25f7d 100644 --- a/docs/why.rst +++ b/docs/why.rst @@ -21,6 +21,88 @@ Instead, you log *events* that happen in a *context* of key/value pairs. …structlog? =========== -.. include:: ../README.rst - :start-after: -begin-spiel- - :end-before: -end-spiel- +Easier Logging +============== + +You can stop writing prose and start thinking in terms of an event that happens in the context of key/value pairs: + +.. code-block:: pycon + + >>> from structlog import get_logger + >>> log = get_logger() + >>> log.info("key_value_logging", out_of_the_box=True, effort=0) + 2020-11-18 09:17.09 [info ] key_value_logging effort=0 out_of_the_box=True + +Each log entry is a meaningful dictionary instead of an opaque string now! + + +Data Binding +============ + +Since log entries are dictionaries, you can start binding and re-binding key/value pairs to your loggers to ensure they are present in every following logging call: + +.. code-block:: pycon + + >>> log = log.bind(user="anonymous", some_key=23) + >>> log = log.bind(user="hynek", another_key=42) + >>> log.info("user.logged_in", happy=True) + 2020-11-18 09:18.28 [info ] user.logged_in another_key=42 happy=True some_key=23 user=hynek + +You can also bind key/value pairs to `thread-local storage `_ and `contextvars `_. + + +Powerful Pipelines +================== + +Each log entry goes through a `processor pipeline `_ that is just a chain of functions that receive a dictionary and return a new dictionary that gets fed into the next function. +That allows for simple but powerful data manipulation: + +.. code-block:: python + + def timestamper(logger, log_method, event_dict): + """Add a timestamp to each log entry.""" + event_dict["timestamp"] = time.time() + return event_dict + +There are `plenty of processors `_ for most common tasks coming with ``structlog``: + +- Collectors of `call stack information `_ ("How did this log entry happen?"), +- …and `exceptions `_ ("What happened‽"). +- Unicode encoders/decoders. +- Flexible `timestamping `_. + + +Formatting +========== + +``structlog`` is completely flexible about *how* the resulting log entry is emitted. +Since each log entry is a dictionary, it can be formatted to **any** format: + +- A colorful key/value format for `local development `_, +- `JSON `_ for easy parsing, +- or some standard format you have parsers for like nginx or Apache httpd. + +Internally, formatters are processors whose return value (usually a string) is passed into loggers that are responsible for the output of your message. +``structlog`` comes with multiple useful formatters out-of-the-box. + + +Output +====== + +``structlog`` is also flexible with the final output of your log entries: + +- A **built-in** lightweight printer like in the examples above. + Easy to use and fast. +- Use the **standard library**'s or **Twisted**'s logging modules for compatibility. + In this case ``structlog`` works like a wrapper that formats a string and passes them off into existing systems that won't know that ``structlog`` even exists. + Or the other way round: ``structlog`` comes with a ``logging`` formatter that allows for processing third party log records. +- Don't format it to a string at all! + ``structlog`` passes you a dictionary and you can do with it whatever you want. + Reported uses cases are sending them out via network or saving them in a database. + + +Highly Testable +=============== + +``structlog`` is thoroughly tested and we see it as our duty to help you to achieve the same in *your* applications. +That's why it ships with a `bunch of helpers `_ to introspect your application's logging behavior with little-to-no boilerplate. diff --git a/pyproject.toml b/pyproject.toml index 914b5eb1..e78a726c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -190,101 +190,12 @@ Thanks to its highly flexible design, it's up to you whether you want ``structlo .. -end-short- -Once you feel inspired to try it out, check out our friendly `Getting Started tutorial `_ that also contains detailed installation instructions! +A short explanation on *why* structured logging is good for you, and why ``structlog`` is the right tool for the job can be found in the `Why chapter `_ of our documentation. -.. -begin-spiel- +Once you feel inspired to try it out, check out our friendly `Getting Started tutorial `_ that also contains detailed installation instructions! If you prefer videos over reading, check out `Markus Holtermann `_'s DjangoCon Europe 2019 talk: `Logging Rethought 2: The Actions of Frank Taylor Jr. `_ - -Easier Logging -============== - -You can stop writing prose and start thinking in terms of an event that happens in the context of key/value pairs: - -.. code-block:: pycon - - >>> from structlog import get_logger - >>> log = get_logger() - >>> log.info("key_value_logging", out_of_the_box=True, effort=0) - 2020-11-18 09:17.09 [info ] key_value_logging effort=0 out_of_the_box=True - -Each log entry is a meaningful dictionary instead of an opaque string now! - - -Data Binding -============ - -Since log entries are dictionaries, you can start binding and re-binding key/value pairs to your loggers to ensure they are present in every following logging call: - -.. code-block:: pycon - - >>> log = log.bind(user="anonymous", some_key=23) - >>> log = log.bind(user="hynek", another_key=42) - >>> log.info("user.logged_in", happy=True) - 2020-11-18 09:18.28 [info ] user.logged_in another_key=42 happy=True some_key=23 user=hynek - -You can also bind key/value pairs to `thread-local storage `_ and `contextvars `_. - - -Powerful Pipelines -================== - -Each log entry goes through a `processor pipeline `_ that is just a chain of functions that receive a dictionary and return a new dictionary that gets fed into the next function. -That allows for simple but powerful data manipulation: - -.. code-block:: python - - def timestamper(logger, log_method, event_dict): - \"\"\"Add a timestamp to each log entry.\"\"\" - event_dict["timestamp"] = time.time() - return event_dict - -There are `plenty of processors `_ for most common tasks coming with ``structlog``: - -- Collectors of `call stack information `_ ("How did this log entry happen?"), -- …and `exceptions `_ ("What happened‽"). -- Unicode encoders/decoders. -- Flexible `timestamping `_. - - -Formatting -========== - -``structlog`` is completely flexible about *how* the resulting log entry is emitted. -Since each log entry is a dictionary, it can be formatted to **any** format: - -- A colorful key/value format for `local development `_, -- `JSON `_ for easy parsing, -- or some standard format you have parsers for like nginx or Apache httpd. - -Internally, formatters are processors whose return value (usually a string) is passed into loggers that are responsible for the output of your message. -``structlog`` comes with multiple useful formatters out-of-the-box. - - -Output -====== - -``structlog`` is also flexible with the final output of your log entries: - -- A **built-in** lightweight printer like in the examples above. - Easy to use and fast. -- Use the **standard library**'s or **Twisted**'s logging modules for compatibility. - In this case ``structlog`` works like a wrapper that formats a string and passes them off into existing systems that won't know that ``structlog`` even exists. - Or the other way round: ``structlog`` comes with a ``logging`` formatter that allows for processing third party log records. -- Don't format it to a string at all! - ``structlog`` passes you a dictionary and you can do with it whatever you want. - Reported uses cases are sending them out via network or saving them in a database. - - -Highly Testable -=============== - -``structlog`` is thouroughly tested and we see it as our duty to help you to achieve the same in *your* applications. -That's why it ships with a `bunch of helpers `_ to introspect your application's logging behavior with little-to-no boilerplate. - -.. -end-spiel- - .. -begin-meta- Getting Help From 7366dadff2cfea3e50ad6984497de2a0bd041f5e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 5 Dec 2021 05:21:37 +0100 Subject: [PATCH 0627/1520] We don't need coverage anymore --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index caf80cf4..11bc10d2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -32,7 +32,7 @@ jobs: python -VV python -m site python -m pip install --upgrade pip setuptools wheel - python -m pip install --upgrade coverage[toml] virtualenv tox tox-gh-actions + python -m pip install --upgrade virtualenv tox tox-gh-actions - name: "Run tox targets for ${{ matrix.python-version }}" run: "python -m tox" From 9dbe99f52b58139416116d1e3bbc1d860344cb8b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 5 Dec 2021 05:26:04 +0100 Subject: [PATCH 0628/1520] Update main.yml --- .github/workflows/main.yml | 47 +++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 11bc10d2..a4eddcf0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -11,6 +11,7 @@ on: env: FORCE_COLOR: "1" # Make tools pretty. TOX_TESTENV_PASSENV: "FORCE_COLOR" + PYTHON_LATEST: "3.10" jobs: @@ -53,27 +54,30 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 with: - python-version: "3.10" # Use latest, so it understands all syntax. + # Use latest Python, so it understands all syntax. + python-version: ${{env.PYTHON_LATEST}} - - name: "Install Coverage.py" - run: "python -m pip install --upgrade coverage[toml]" + - name: Install Coverage.py + run: python -m pip install --upgrade coverage[toml] - - name: "Download coverage data" + - name: Download coverage data uses: actions/download-artifact@v2 with: name: coverage-data - - run: python -m coverage combine - - run: python -m coverage html --skip-covered --skip-empty + - name: Combine coverage and fail if it's <100% + run: | + python -m coverage combine + python -m coverage html --skip-covered --skip-empty + python -m coverage report --fail-under=100 - - name: Upload coverage report - uses: "actions/upload-artifact@v2" + - name: Upload HTML report for failed check + uses: actions/upload-artifact@v2 with: name: html-report path: htmlcov - - - run: python -m coverage report --fail-under=100 - + if: ${{ failure() }} + package: name: "Build & verify package" @@ -83,16 +87,12 @@ jobs: - uses: "actions/checkout@v2" - uses: "actions/setup-python@v2" with: - python-version: "3.10" - - - name: "Install build, check-wheel-contents, and twine" - run: "python -m pip install build twine check-wheel-contents" - - name: "Build package" - run: "python -m build --sdist --wheel ." - - name: "List result" - run: "ls -l dist" - - name: "Check wheel contents" - run: "check-wheel-contents dist/*.whl" + python-version: ${{env.PYTHON_LATEST}} + + - run: "python -m pip install build twine check-wheel-contents" + - run: "python -m build --sdist --wheel ." + - run: "ls -l dist" + - run: "check-wheel-contents dist/*.whl" - name: "Check long_description" run: "python -m twine check dist/*" @@ -108,8 +108,7 @@ jobs: - uses: "actions/checkout@v2" - uses: "actions/setup-python@v2" with: - python-version: "3.10" - - name: "Install in dev mode" - run: "python -m pip install -e .[dev]" + python-version: ${{env.PYTHON_LATEST}} + - run: "python -m pip install -e .[dev]" - name: "Import package" run: "python -c 'import structlog; print(structlog.__version__)'" From d8d5e75ba779b31a96735486007cc2a281fe12b3 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 5 Dec 2021 05:57:01 +0100 Subject: [PATCH 0629/1520] Update main.yml --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a4eddcf0..22ee54d0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -77,7 +77,7 @@ jobs: name: html-report path: htmlcov if: ${{ failure() }} - + package: name: "Build & verify package" From 07e06a495cac665de3c074c478470e416c74d3a9 Mon Sep 17 00:00:00 2001 From: Etienne Wodey <44871469+airwoodix@users.noreply.github.com> Date: Sun, 5 Dec 2021 05:59:42 +0100 Subject: [PATCH 0630/1520] Add LogfmtRenderer (#376) * Add LogfmtRenderer * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Add LogfmtRenderer * LogfmtRenderer: update docstrings & changelog (from review) Co-authored-by: Hynek Schlawack * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Add LogfmtRenderer: remove logfmt dependency add bool_as_flag param Implement the rendering logic directly according to "specification" at https://pkg.go.dev/github.com/kr/logfmt * Add LogfmtRenderer: add to typing_examples.py Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Hynek Schlawack --- CHANGELOG.rst | 3 +- docs/api.rst | 10 +++ src/structlog/processors.py | 147 +++++++++++++++++++++++++++--------- tests/test_processors.py | 147 ++++++++++++++++++++++++++++++++++++ tests/typing_examples.py | 18 +++++ 5 files changed, 287 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2b0239dc..95cfd52a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -33,7 +33,8 @@ Deprecations: Changes: ^^^^^^^^ -*none* +- Added the ``structlog.processors.LogfmtRenderer`` processor to render log lines using the `logfmt `_ format. + `#376 `_ ---- diff --git a/docs/api.rst b/docs/api.rst index 29665204..4beb28ba 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -232,6 +232,16 @@ Please see :doc:`thread-local` for details. ... {"a": 42, "b": [1, 2, 3]}) 'b=[1, 2, 3] a=42' +.. autoclass:: LogfmtRenderer + + .. doctest:: + + >>> from structlog.processors import LogfmtRenderer + >>> event_dict = {"a": 42, "b": [1, 2, 3], "flag": True} + >>> LogfmtRenderer(sort_keys=True)(None, None, event_dict) + 'a=42 b="[1, 2, 3]" flag' + >>> LogfmtRenderer(key_order=["b", "a"], bool_as_flag=False)(None, None, event_dict) + 'b="[1, 2, 3]" a=42 flag=true' .. autofunction:: add_log_level diff --git a/src/structlog/processors.py b/src/structlog/processors.py index c3194795..1e2cfab1 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -75,42 +75,7 @@ def __init__( drop_missing: bool = False, repr_native_str: bool = True, ): - # Use an optimized version for each case. - if key_order and sort_keys is True: - - def ordered_items(event_dict: EventDict) -> List[Tuple[str, Any]]: - items = [] - for key in key_order: # type: ignore - value = event_dict.pop(key, None) - if value is not None or not drop_missing: - items.append((key, value)) - - items += sorted(event_dict.items()) - - return items - - elif key_order: - - def ordered_items(event_dict: EventDict) -> List[Tuple[str, Any]]: - items = [] - for key in key_order: # type: ignore - value = event_dict.pop(key, None) - if value is not None or not drop_missing: - items.append((key, value)) - - items += event_dict.items() - - return items - - elif sort_keys: - - def ordered_items(event_dict: EventDict) -> List[Tuple[str, Any]]: - return sorted(event_dict.items()) - - else: - ordered_items = operator.methodcaller("items") # type: ignore - - self._ordered_items = ordered_items + self._ordered_items = _items_sorter(sort_keys, key_order, drop_missing) if repr_native_str is True: self._repr = repr @@ -132,6 +97,114 @@ def __call__( ) +class LogfmtRenderer: + """ + Render ``event_dict`` using the logfmt_ format. + + .. _logfmt: https://brandur.org/logfmt + + :param sort_keys: Whether to sort keys when formatting. + :param key_order: List of keys that should be rendered in this exact + order. Missing keys are rendered with empty values, extra keys + depending on *sort_keys* and the dict class. + :param drop_missing: When ``True``, extra keys in *key_order* will be + dropped rather than rendered with empty values. + :param bool_as_flag: When ``True``, render ``{"flag": True}`` as + ``flag``, instead of ``flag=true``. ``{"flag": False}`` is + always rendered as ``flag=false``. + + :raises ValueError: If a key contains non printable or space characters. + + .. versionadded:: 21.5.0 + """ + + def __init__( + self, + sort_keys: bool = False, + key_order: Optional[Sequence[str]] = None, + drop_missing: bool = False, + bool_as_flag: bool = True, + ): + self._ordered_items = _items_sorter(sort_keys, key_order, drop_missing) + self.bool_as_flag = bool_as_flag + + def __call__( + self, _: WrappedLogger, __: str, event_dict: EventDict + ) -> str: + + elements: List[str] = [] + for key, value in self._ordered_items(event_dict): + if any(c <= " " for c in key): + raise ValueError(f'Invalid key: "{key}"') + + if value is None: + elements.append(f"{key}=") + continue + + if isinstance(value, bool): + if self.bool_as_flag and value: + elements.append(f"{key}") + continue + value = "true" if value else "false" + + value = f"{value}".replace('"', '\\"') + + if " " in value or "=" in value: + value = f'"{value}"' + + elements.append(f"{key}={value}") + + return " ".join(elements) + + +def _items_sorter( + sort_keys: bool, + key_order: Optional[Sequence[str]], + drop_missing: bool, +) -> Callable[[EventDict], List[Tuple[str, Any]]]: + """ + Return a function to sort items from an ``event_dict``. + + See `KeyValueRenderer` for an explanation of the parameters. + """ + # Use an optimized version for each case. + if key_order and sort_keys: + + def ordered_items(event_dict: EventDict) -> List[Tuple[str, Any]]: + items = [] + for key in key_order: # type: ignore + value = event_dict.pop(key, None) + if value is not None or not drop_missing: + items.append((key, value)) + + items += sorted(event_dict.items()) + + return items + + elif key_order: + + def ordered_items(event_dict: EventDict) -> List[Tuple[str, Any]]: + items = [] + for key in key_order: # type: ignore + value = event_dict.pop(key, None) + if value is not None or not drop_missing: + items.append((key, value)) + + items += event_dict.items() + + return items + + elif sort_keys: + + def ordered_items(event_dict: EventDict) -> List[Tuple[str, Any]]: + return sorted(event_dict.items()) + + else: + ordered_items = operator.methodcaller("items") # type: ignore + + return ordered_items + + class UnicodeEncoder: """ Encode unicode values in ``event_dict``. @@ -228,7 +301,7 @@ class JSONRenderer: def __init__( self, serializer: Callable[..., Union[str, bytes]] = json.dumps, - **dumps_kw: Any + **dumps_kw: Any, ) -> None: dumps_kw.setdefault("default", _json_fallback_handler) self._dumps_kw = dumps_kw diff --git a/tests/test_processors.py b/tests/test_processors.py index 85e58e4b..60c70fad 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -18,6 +18,7 @@ ExceptionPrettyPrinter, JSONRenderer, KeyValueRenderer, + LogfmtRenderer, StackInfoRenderer, TimeStamper, UnicodeDecoder, @@ -125,6 +126,152 @@ def test_repr_native_str(self, rns): assert 2 == cnt +class TestLogfmtRenderer: + def test_sort_keys(self, event_dict): + """ + Keys are sorted if sort_keys is set. + """ + rv = LogfmtRenderer(sort_keys=True)(None, None, event_dict) + + assert r'a= b="[3, 4]" x=7 y=test z="(1, 2)"' == rv + + def test_order_complete(self, event_dict): + """ + Orders keys according to key_order. + """ + rv = LogfmtRenderer(key_order=["y", "b", "a", "z", "x"])( + None, None, event_dict + ) + + assert r'y=test b="[3, 4]" a= z="(1, 2)" x=7' == rv + + def test_order_missing(self, event_dict): + """ + Missing keys get rendered as None. + """ + rv = LogfmtRenderer(key_order=["c", "y", "b", "a", "z", "x"])( + None, None, event_dict + ) + + assert r'c= y=test b="[3, 4]" a= z="(1, 2)" x=7' == rv + + def test_order_missing_dropped(self, event_dict): + """ + Missing keys get dropped + """ + rv = LogfmtRenderer( + key_order=["c", "y", "b", "a", "z", "x"], drop_missing=True + )(None, None, event_dict) + + assert r'y=test b="[3, 4]" a= z="(1, 2)" x=7' == rv + + def test_order_extra(self, event_dict): + """ + Extra keys get sorted if sort_keys=True. + """ + event_dict["B"] = "B" + event_dict["A"] = "A" + + rv = LogfmtRenderer( + key_order=["c", "y", "b", "a", "z", "x"], sort_keys=True + )(None, None, event_dict) + + assert ( + r'c= y=test b="[3, 4]" a= z="(1, 2)" x=7 A=A B=B' + ) == rv + + def test_order_sorted_missing_dropped(self, event_dict): + """ + Keys get sorted if sort_keys=True and extras get dropped. + """ + event_dict["B"] = "B" + event_dict["A"] = "A" + + rv = LogfmtRenderer( + key_order=["c", "y", "b", "a", "z", "x"], + sort_keys=True, + drop_missing=True, + )(None, None, event_dict) + + assert r'y=test b="[3, 4]" a= z="(1, 2)" x=7 A=A B=B' == rv + + def test_random_order(self, event_dict): + """ + No special ordering doesn't blow up. + """ + rv = LogfmtRenderer()(None, None, event_dict) + + assert isinstance(rv, str) + + def test_empty_event_dict(self): + """ + Empty event dict renders as empty string. + """ + rv = LogfmtRenderer()(None, None, {}) + + assert "" == rv + + def test_bool_as_flag(self): + """ + If activated, render ``{"a": True}`` as ``a`` instead of ``a=true``. + """ + event_dict = {"a": True, "b": False} + + rv_abbrev = LogfmtRenderer(bool_as_flag=True)(None, None, event_dict) + assert r"a b=false" == rv_abbrev + + rv_no_abbrev = LogfmtRenderer(bool_as_flag=False)( + None, None, event_dict + ) + assert r"a=true b=false" == rv_no_abbrev + + def test_reference_format(self): + """ + Test rendering according to example at + https://pkg.go.dev/github.com/kr/logfmt + """ + event_dict = { + "foo": "bar", + "a": 14, + "baz": "hello kitty", + "cool%story": "bro", + "f": True, + "%^asdf": True, + } + + rv = LogfmtRenderer()(None, None, event_dict) + assert 'foo=bar a=14 baz="hello kitty" cool%story=bro f %^asdf' == rv + + def test_equal_sign_or_space_in_value(self): + """ + Values with equal signs are always quoted. + """ + event_dict = { + "without": "somevalue", + "withequal": "some=value", + "withspace": "some value", + } + + rv = LogfmtRenderer()(None, None, event_dict) + assert ( + r'without=somevalue withequal="some=value" withspace="some value"' + == rv + ) + + def test_invalid_key(self): + """ + Keys cannot contain space characters. + """ + event_dict = { + "invalid key": "somevalue", + } + + with pytest.raises(ValueError) as e: + LogfmtRenderer()(None, None, event_dict) + + assert 'Invalid key: "invalid key"' == e.value.args[0] + + class TestJSONRenderer: def test_renders_json(self, event_dict): """ diff --git a/tests/typing_examples.py b/tests/typing_examples.py index 8ce999fe..d145e82f 100644 --- a/tests/typing_examples.py +++ b/tests/typing_examples.py @@ -175,6 +175,24 @@ def bytes_dumps( cache_logger_on_first_use=True, ) +structlog.configure( + processors=[ + structlog.stdlib.filter_by_level, + structlog.stdlib.add_logger_name, + structlog.stdlib.add_log_level, + structlog.stdlib.PositionalArgumentsFormatter(), + structlog.processors.TimeStamper(fmt="iso"), + structlog.processors.StackInfoRenderer(), + structlog.processors.format_exc_info, + structlog.processors.UnicodeDecoder(), + structlog.processors.LogfmtRenderer(), + ], + context_class=dict, + logger_factory=structlog.stdlib.LoggerFactory(), + wrapper_class=structlog.stdlib.BoundLogger, + cache_logger_on_first_use=True, +) + structlog.configure( processors=[ structlog.stdlib.filter_by_level, From cad14e066c5f181ecebea5d053bec28b8e215e4a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 5 Dec 2021 06:34:44 +0100 Subject: [PATCH 0631/1520] Update main.yml --- .github/workflows/main.yml | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 22ee54d0..efab30d8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,7 +16,7 @@ env: jobs: tests: - name: "tox on ${{ matrix.python-version }}" + name: tox on ${{ matrix.python-version }} runs-on: "ubuntu-latest" strategy: matrix: @@ -35,8 +35,7 @@ jobs: python -m pip install --upgrade pip setuptools wheel python -m pip install --upgrade virtualenv tox tox-gh-actions - - name: "Run tox targets for ${{ matrix.python-version }}" - run: "python -m tox" + - run: "python -m tox" - name: Upload coverage data uses: "actions/upload-artifact@v2" @@ -47,6 +46,7 @@ jobs: coverage: + name: Combine and check coverage. runs-on: "ubuntu-latest" needs: tests @@ -57,21 +57,19 @@ jobs: # Use latest Python, so it understands all syntax. python-version: ${{env.PYTHON_LATEST}} - - name: Install Coverage.py - run: python -m pip install --upgrade coverage[toml] + - run: python -m pip install --upgrade coverage[toml] - - name: Download coverage data - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v2 with: name: coverage-data - - name: Combine coverage and fail if it's <100% + - name: Combine coverage and fail if it's <100%. run: | python -m coverage combine python -m coverage html --skip-covered --skip-empty python -m coverage report --fail-under=100 - - name: Upload HTML report for failed check + - name: Upload HTML report if check failed. uses: actions/upload-artifact@v2 with: name: html-report @@ -80,25 +78,25 @@ jobs: package: - name: "Build & verify package" + name: Build & verify package runs-on: "ubuntu-latest" steps: - - uses: "actions/checkout@v2" - - uses: "actions/setup-python@v2" + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 with: python-version: ${{env.PYTHON_LATEST}} - - run: "python -m pip install build twine check-wheel-contents" - - run: "python -m build --sdist --wheel ." - - run: "ls -l dist" - - run: "check-wheel-contents dist/*.whl" - - name: "Check long_description" - run: "python -m twine check dist/*" + - run: python -m pip install build twine check-wheel-contents + - run: python -m build --sdist --wheel . + - run: ls -l dist + - run: check-wheel-contents dist/*.whl + - name: Check long_description + run: python -m twine check dist/* install-dev: - name: "Verify dev env" + name: Verify dev env runs-on: "${{ matrix.os }}" strategy: matrix: From 7c0f6cb08bc24cf91d1e81fe5ca9c816670e6267 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 6 Dec 2021 07:01:26 +0100 Subject: [PATCH 0632/1520] Clarify versioning and policy --- CHANGELOG.rst | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 95cfd52a..fffaa0fb 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,10 +1,14 @@ Changelog ========= -Versions follow `CalVer `_ with a strict backwards compatibility policy. +Versions follow `Calendar Versioning `_ with a strict backwards compatibility policy. -Put simply, you shouldn't ever be afraid to upgrade ``structlog`` if you're using its public APIs. -Whenever there is a need to break compatibility, it is announced here in the changelog, and raises a ``DeprecationWarning`` for a year (if possible) before it's finally really broken. +The **first digit** of the version is the year. +The **second digit** is incremented with each release, starting at 1 for each year. +The **third digit** is when we need to start branches for older releases (only for emergencies). + +You shouldn't ever be afraid to upgrade ``structlog`` if you're using its public APIs and pay attention to ``DeprecationWarning``\ s. +Whenever there is a need to break compatibility, it is announced here in the changelog and raises a ``DeprecationWarning`` for a year (if possible) before it's finally really broken. .. warning:: From 9efda8511a36f4a0e3e3d49cb8322ccfd6633834 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 6 Dec 2021 18:23:00 +0100 Subject: [PATCH 0633/1520] [pre-commit.ci] pre-commit autoupdate (#379) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/psf/black: 21.11b1 → 21.12b0](https://github.com/psf/black/compare/21.11b1...21.12b0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6e6f7764..011f5770 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/psf/black - rev: 21.11b1 + rev: 21.12b0 hooks: - id: black language_version: python3.10 From 3e28d6530fc96f1d8691e442644c18b6f3a1463a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 8 Dec 2021 10:45:50 +0100 Subject: [PATCH 0634/1520] Move typing back to main directory Everything tests is ignored by mypy per our mypy.ini --- tox.ini | 2 +- tests/typing_examples.py => typing_examples.py | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/typing_examples.py => typing_examples.py (100%) diff --git a/tox.ini b/tox.ini index edc475d9..edf16868 100644 --- a/tox.ini +++ b/tox.ini @@ -48,7 +48,7 @@ deps = mypy rich twisted -commands = mypy src tests/typing_examples.py +commands = mypy src typing_examples.py [testenv:cog] diff --git a/tests/typing_examples.py b/typing_examples.py similarity index 100% rename from tests/typing_examples.py rename to typing_examples.py From 9208a2c7b39a85dd93b1625daeb48755d1d71573 Mon Sep 17 00:00:00 2001 From: Iwan Aucamp Date: Sun, 5 Dec 2021 14:33:19 +0100 Subject: [PATCH 0635/1520] Add stdlib.ExtraAdder This processor adds extra attributes from LogRecord objects to the event_dict, and can be useful for making values passed in the extra parameter of the logging module's log methods pass through to output as additional properties. Fixes #209 --- CHANGELOG.rst | 3 + docs/api.rst | 2 + docs/standard-library.rst | 9 +++ src/structlog/stdlib.py | 63 +++++++++++++++++ tests/test_stdlib.py | 143 ++++++++++++++++++++++++++++++++++++-- typing_examples.py | 9 ++- 6 files changed, 223 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index fffaa0fb..4b65f5e4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -39,6 +39,9 @@ Changes: - Added the ``structlog.processors.LogfmtRenderer`` processor to render log lines using the `logfmt `_ format. `#376 `_ +- Added the ``structlog.stdlib.ExtraAdder`` processor that adds extra attributes of ``logging.LogRecord`` objects to the event dictionary. + This processor can be used for adding data passed in the ``extra`` parameter of the ``logging`` module's log methods to the event dictionary. + `#377 `_ ---- diff --git a/docs/api.rst b/docs/api.rst index 4beb28ba..47571931 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -302,6 +302,8 @@ Please see :doc:`thread-local` for details. .. autofunction:: add_logger_name +.. autofunction:: ExtraAdder + .. autoclass:: PositionalArgumentsFormatter .. autoclass:: ProcessorFormatter diff --git a/docs/standard-library.rst b/docs/standard-library.rst index bc9d56a7..a51da43f 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -76,6 +76,11 @@ Processors `add_logger_name`: Adds the name of the logger to the event dictionary under the key ``logger``. +`ExtraAdder`: + Add extra attributes of `logging.LogRecord` objects to the event dictionary. + + This processor can be used for adding data passed in the ``extra`` parameter of the `logging` module's log methods to the event dictionary. + :func:`~structlog.stdlib.add_log_level`: Adds the log level to the event dictionary under the key ``level``. @@ -413,6 +418,10 @@ For example, to use the standard library's `logging.config.dictConfig` to log co # Add the log level and a timestamp to the event_dict if the log entry # is not from structlog. structlog.stdlib.add_log_level, + # Add extra attributes of LogRecord objects to the event dictionary + # so that values passed in the extra parameter of log methods pass + # through to log output. + structlog.stdlib.ExtraAdder(), timestamper, ] diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index d9a555fa..d0a4942f 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -10,6 +10,7 @@ """ import asyncio +import functools import logging import sys @@ -17,6 +18,7 @@ from typing import ( Any, Callable, + Collection, Dict, Iterable, List, @@ -43,6 +45,7 @@ "add_log_level_number", "add_log_level", "add_logger_name", + "ExtraAdder", "BoundLogger", "filter_by_level", "get_logger", @@ -664,6 +667,66 @@ def add_logger_name( return event_dict +_LOG_RECORD_KEYS = logging.LogRecord( + "name", 0, "pathname", 0, "msg", tuple(), None +).__dict__.keys() + + +class ExtraAdder: + """ + Add extra attributes of `logging.LogRecord` objects to the event + dictionary. + + This processor can be used for adding data passed in the ``extra`` + parameter of the `logging` module's log methods to the event dictionary. + + :param allow: An optional collection of attributes that, if present in + `logging.LogRecord` objects, will be copied to event dictionaries. + + If ``allow`` is None all attributes of `logging.LogRecord` objects that + do not exist on a standard `logging.LogRecord` object will be copied to + event dictionaries. + + .. versionadded:: 21.5.0 + """ + + __slots__ = ["_copier"] + + def __init__(self, allow: Optional[Collection[str]] = None) -> None: + self._copier: Callable[[EventDict, logging.LogRecord], None] + if allow is not None: + self._copier = functools.partial(self._copy_allowed, [*allow]) + else: + self._copier = self._copy_all + + def __call__( + self, logger: logging.Logger, name: str, event_dict: EventDict + ) -> EventDict: + record: Optional[logging.LogRecord] = event_dict.get("_record") + if record is not None: + self._copier(event_dict, record) + return event_dict + + @classmethod + def _copy_all( + cls, event_dict: EventDict, record: logging.LogRecord + ) -> None: + for key, value in record.__dict__.items(): + if key not in _LOG_RECORD_KEYS: + event_dict[key] = value + + @classmethod + def _copy_allowed( + cls, + allow: Collection[str], + event_dict: EventDict, + record: logging.LogRecord, + ) -> None: + for key in allow: + if key in record.__dict__: + event_dict[key] = record.__dict__[key] + + def render_to_log_kwargs( _: logging.Logger, __: str, event_dict: EventDict ) -> EventDict: diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index f65d5793..f639ff9c 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -9,6 +9,9 @@ import os import sys +from io import StringIO +from typing import Any, Callable, Collection, Dict, Optional, Set + import pytest from pretend import call_recorder, stub @@ -27,6 +30,7 @@ from structlog.stdlib import ( AsyncBoundLogger, BoundLogger, + ExtraAdder, LoggerFactory, PositionalArgumentsFormatter, ProcessorFormatter, @@ -39,7 +43,7 @@ render_to_log_kwargs, ) from structlog.testing import CapturedCall -from structlog.types import BindableLogger +from structlog.types import BindableLogger, EventDict from .additional_frame import additional_frame @@ -428,8 +432,8 @@ def test_log_level_alias_normalized(self): assert "warning" == event_dict["level"] -@pytest.fixture -def log_record(): +@pytest.fixture(name="make_log_record") +def _make_log_record(): """ A LogRecord factory. """ @@ -461,17 +465,146 @@ def test_logger_name_added(self): assert name == event_dict["logger"] - def test_logger_name_added_with_record(self, log_record): + def test_logger_name_added_with_record(self, make_log_record): """ The logger name is deduced from the LogRecord if provided. """ name = "sample-name" - record = log_record(name=name) + record = make_log_record(name=name) event_dict = add_logger_name(None, None, {"_record": record}) assert name == event_dict["logger"] +def extra_dict() -> Dict[str, Any]: + """ + A dict to be passed in the `extra` parameter of the `logging` module's log + methods. + """ + return { + "this": "is", + "some": "extra values", + "x_int": 4, + "x_bool": True, + } + + +@pytest.fixture(name="extra_dict") +def extra_dict_fixture(): + return extra_dict() + + +class TestExtraAdder: + @pytest.mark.parametrize( + "allow, misses", + [ + (None, None), + ({}, None), + *[({key}, None) for key in extra_dict().keys()], + ({"missing"}, {"missing"}), + ({"missing", "keys"}, {"missing"}), + ({"this", "x_int"}, None), + ], + ) + def test_add_extra( + self, + make_log_record: Callable[[], logging.LogRecord], + extra_dict: Dict[str, Any], + allow: Optional[Collection[str]], + misses: Optional[Set[str]], + ): + """ + Extra attributes of a LogRecord object are added to the event dict. + """ + record: logging.LogRecord = make_log_record() + record.__dict__.update(extra_dict) + event_dict = {"_record": record, "ed_key": "ed_value"} + expected = self._copy_allowed(event_dict, extra_dict, allow) + + if allow is None: + actual = ExtraAdder()(None, None, event_dict) + assert expected == actual + actual = ExtraAdder(allow)(None, None, event_dict) + assert expected == actual + if misses: + assert misses.isdisjoint(expected.keys()) + + def test_no_record(self): + """ + If the event_dict has no LogRecord, do nothing. + """ + actual = ExtraAdder()(None, None, {}) + + assert {} == actual + + @pytest.mark.parametrize( + "allow, misses", + [ + (None, None), + ({}, None), + *[({key}, None) for key in extra_dict().keys()], + ({"missing"}, {"missing"}), + ({"missing", "keys"}, {"missing"}), + ({"this", "x_int"}, None), + ], + ) + def test_add_extra_e2e( + self, + extra_dict: Dict[str, Any], + allow: Optional[Collection[str]], + misses: Optional[Set[str]], + ): + """ + Values passed in the `extra` parameter of the `logging` module's log + methods pass through to log output. + """ + logger = logging.Logger(sys._getframe().f_code.co_name) + string_io = StringIO() + handler = logging.StreamHandler(string_io) + formatter = ProcessorFormatter( + foreign_pre_chain=[ExtraAdder(allow)], + processors=[JSONRenderer()], + ) + handler.setFormatter(formatter) + handler.setLevel(0) + logger.addHandler(handler) + logger.setLevel(0) + logging.warning("allow = %s", allow) + + event_dict = {"event": "Some text"} + expected = self._copy_allowed(event_dict, extra_dict, allow) + + logger.info("Some %s", "text", extra=extra_dict) + actual = { + key: value + for key, value in json.loads(string_io.getvalue()).items() + if not key.startswith("_") + } + + assert expected == actual + if misses: + assert misses.isdisjoint(expected.keys()) + + @classmethod + def _copy_allowed( + cls, + event_dict: EventDict, + extra_dict: Dict[str, Any], + allow: Optional[Collection[str]], + ) -> EventDict: + if allow is None: + return {**event_dict, **extra_dict} + else: + return { + **event_dict, + **{ + key: value + for key, value in extra_dict.items() + if key in allow + }, + } + + class TestRenderToLogKW: def test_default(self): """ diff --git a/typing_examples.py b/typing_examples.py index d145e82f..8f2b4311 100644 --- a/typing_examples.py +++ b/typing_examples.py @@ -91,7 +91,14 @@ def bytes_dumps( formatter = structlog.stdlib.ProcessorFormatter( processor=structlog.dev.ConsoleRenderer(), - foreign_pre_chain=shared_processors, + foreign_pre_chain=[ + structlog.stdlib.ExtraAdder(), + structlog.stdlib.ExtraAdder(allow=None), + structlog.stdlib.ExtraAdder(None), + structlog.stdlib.ExtraAdder(allow=["k1", "k2"]), + structlog.stdlib.ExtraAdder({"k1", "k2"}), + *shared_processors, + ], ) From 7cd9815c7cebc8ecaad69d438d0b05ee4a8a237f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 10 Dec 2021 08:43:26 +0100 Subject: [PATCH 0636/1520] Check yaml & consistency --- .github/workflows/main.yml | 35 +++++++++++++++++------------------ .pre-commit-config.yaml | 1 + 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index efab30d8..b618222e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,44 +10,44 @@ on: env: FORCE_COLOR: "1" # Make tools pretty. - TOX_TESTENV_PASSENV: "FORCE_COLOR" + TOX_TESTENV_PASSENV: FORCE_COLOR PYTHON_LATEST: "3.10" jobs: tests: name: tox on ${{ matrix.python-version }} - runs-on: "ubuntu-latest" + runs-on: ubuntu-latest strategy: matrix: python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"] steps: - - uses: "actions/checkout@v2" - - uses: "actions/setup-python@v2" + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 with: - python-version: "${{ matrix.python-version }}" + python-version: ${{ matrix.python-version }} - - name: "Install dependencies" + - name: Install dependencies run: | python -VV python -m site python -m pip install --upgrade pip setuptools wheel python -m pip install --upgrade virtualenv tox tox-gh-actions - - run: "python -m tox" + - run: python -m tox - name: Upload coverage data - uses: "actions/upload-artifact@v2" + uses: actions/upload-artifact@v2 with: name: coverage-data - path: ".coverage.*" + path: .coverage.* if-no-files-found: ignore coverage: - name: Combine and check coverage. - runs-on: "ubuntu-latest" + name: Combine & check coverage. + runs-on: ubuntu-latest needs: tests steps: @@ -63,7 +63,7 @@ jobs: with: name: coverage-data - - name: Combine coverage and fail if it's <100%. + - name: Combine coverage & fail if it's <100%. run: | python -m coverage combine python -m coverage html --skip-covered --skip-empty @@ -79,7 +79,7 @@ jobs: package: name: Build & verify package - runs-on: "ubuntu-latest" + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -103,10 +103,9 @@ jobs: os: ["ubuntu-latest", "windows-latest"] steps: - - uses: "actions/checkout@v2" - - uses: "actions/setup-python@v2" + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 with: python-version: ${{env.PYTHON_LATEST}} - - run: "python -m pip install -e .[dev]" - - name: "Import package" - run: "python -c 'import structlog; print(structlog.__version__)'" + - run: python -m pip install -e .[dev] + - run: python -c 'import structlog; print(structlog.__version__)' diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 011f5770..b05c569c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -36,3 +36,4 @@ repos: - id: end-of-file-fixer - id: debug-statements - id: check-toml + - id: check-yaml From 8eb1f9a23b71b1bd177dadb1ee1e1d44a0844f34 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 10 Dec 2021 14:43:37 +0100 Subject: [PATCH 0637/1520] Add some hints to pr template ref #377 --- .github/PULL_REQUEST_TEMPLATE.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 7c95b8a0..6b75cee0 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -5,16 +5,20 @@ Please tell us what your pull request is about here. # Pull Request Check List -This is just a friendly reminder about the most common mistakes. Please make sure that you tick all boxes. But please read our [contribution guide](https://github.com/hynek/structlog/blob/main/.github/CONTRIBUTING.md) at least once, it will save you unnecessary review cycles! +This is just a friendly reminder about the most common mistakes. Please make sure that you tick all boxes. +But please read our [contribution guide](https://github.com/hynek/structlog/blob/main/.github/CONTRIBUTING.md) at least once, it will save you unnecessary review cycles! If an item doesn't apply to your pull request, **check it anyway** to make it apparent that there's nothing left to do. - [ ] Added **tests** for changed code. + - The CI fails with less than 100% coverage. - [ ] **New APIs** are added to [`typing_examples.py`](https://github.com/hynek/structlog/blob/main/tests/typing_examples.py). - [ ] Updated **documentation** for changed code. - [ ] New functions/classes have to be added to `docs/api.rst` by hand. - [ ] Changed/added classes/methods/functions have appropriate `versionadded`, `versionchanged`, or `deprecated` [directives](http://www.sphinx-doc.org/en/stable/markup/para.html#directive-versionadded). Find the appropriate next version in our [`__init__.py`](https://github.com/hynek/structlog/blob/main/src/structlog/__init__.py) file. - [ ] Documentation in `.rst` files is written using [semantic newlines](https://rhodesmill.org/brandon/2012/one-sentence-per-line/). - [ ] Changes (and possible deprecations) are documented in the [changelog](https://github.com/hynek/structlog/blob/main/CHANGELOG.rst). +- [ ] Consider granting push permissions to the PR branch, so maintainers can fix minor issues themselves without pestering you. -If you have *any* questions to *any* of the points above, just **submit and ask**! This checklist is here to *help* you, not to deter you from contributing! +If you have *any* questions to *any* of the points above, just **submit and ask**! +This checklist is here to *help* you, not to deter you from contributing! From 661e644a358091d53f3018c3feb0a92408aeedeb Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 10 Dec 2021 14:46:42 +0100 Subject: [PATCH 0638/1520] Fix comma splice --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 6b75cee0..2185fd19 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -6,7 +6,7 @@ Please tell us what your pull request is about here. # Pull Request Check List This is just a friendly reminder about the most common mistakes. Please make sure that you tick all boxes. -But please read our [contribution guide](https://github.com/hynek/structlog/blob/main/.github/CONTRIBUTING.md) at least once, it will save you unnecessary review cycles! +But please read our [contribution guide](https://github.com/hynek/structlog/blob/main/.github/CONTRIBUTING.md) at least once; it will save you unnecessary review cycles! If an item doesn't apply to your pull request, **check it anyway** to make it apparent that there's nothing left to do. From 812d3c5936fc23ee4aa2d6282bc8ef26ef7a265a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 10 Dec 2021 14:49:41 +0100 Subject: [PATCH 0639/1520] Add CI blurb to contributing guide too --- .github/CONTRIBUTING.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index b436e482..8dd49d0f 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -22,6 +22,9 @@ Please report any harm to [Hynek Schlawack] in any way you find appropriate. This is a hard rule; patches with missing tests or documentation can't be merged. - Make sure your changes pass our [CI]. You won't get any feedback until it's green unless you ask for it. + For the CI to pass, the coverage must be 100%. + If you have problems to test something, open anyway and ask for advice. + In some situations, we may agree to add an `# pragma: no cover`. - Once you've addressed review feedback, make sure to bump the pull request with a short note, so we know you're done. - Don’t break backwards compatibility. From bfe541efd589a59eb2f284ed04ea82192d886e48 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 10 Dec 2021 15:12:20 +0100 Subject: [PATCH 0640/1520] More semantic newlines --- .github/PULL_REQUEST_TEMPLATE.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 2185fd19..8ccbbb11 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -5,7 +5,8 @@ Please tell us what your pull request is about here. # Pull Request Check List -This is just a friendly reminder about the most common mistakes. Please make sure that you tick all boxes. +This is just a friendly reminder about the most common mistakes. +Please make sure that you tick all boxes. But please read our [contribution guide](https://github.com/hynek/structlog/blob/main/.github/CONTRIBUTING.md) at least once; it will save you unnecessary review cycles! If an item doesn't apply to your pull request, **check it anyway** to make it apparent that there's nothing left to do. @@ -15,9 +16,10 @@ If an item doesn't apply to your pull request, **check it anyway** to make it ap - [ ] **New APIs** are added to [`typing_examples.py`](https://github.com/hynek/structlog/blob/main/tests/typing_examples.py). - [ ] Updated **documentation** for changed code. - [ ] New functions/classes have to be added to `docs/api.rst` by hand. - - [ ] Changed/added classes/methods/functions have appropriate `versionadded`, `versionchanged`, or `deprecated` [directives](http://www.sphinx-doc.org/en/stable/markup/para.html#directive-versionadded). Find the appropriate next version in our [`__init__.py`](https://github.com/hynek/structlog/blob/main/src/structlog/__init__.py) file. -- [ ] Documentation in `.rst` files is written using [semantic newlines](https://rhodesmill.org/brandon/2012/one-sentence-per-line/). -- [ ] Changes (and possible deprecations) are documented in the [changelog](https://github.com/hynek/structlog/blob/main/CHANGELOG.rst). + - [ ] Changed/added classes/methods/functions have appropriate `versionadded`, `versionchanged`, or `deprecated` [directives](http://www.sphinx-doc.org/en/stable/markup/para.html#directive-versionadded). + Find the appropriate next version in our [`__init__.py`](https://github.com/hynek/structlog/blob/main/src/structlog/__init__.py) file. +- [ ] Documentation in `.rst` and `.md` files is written using [**semantic newlines**](https://rhodesmill.org/brandon/2012/one-sentence-per-line/). +- [ ] Changes (and possible deprecations) are documented in the [**changelog**](https://github.com/hynek/structlog/blob/main/CHANGELOG.rst). - [ ] Consider granting push permissions to the PR branch, so maintainers can fix minor issues themselves without pestering you. If you have *any* questions to *any* of the points above, just **submit and ask**! From e7e22daa5719c3433cca1ca3260284b0460fff48 Mon Sep 17 00:00:00 2001 From: Iwan Aucamp Date: Sat, 11 Dec 2021 07:19:06 +0100 Subject: [PATCH 0641/1520] Link to explanation of "Allow edits from maintainers". (#384) --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 8ccbbb11..c1513e3c 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -20,7 +20,7 @@ If an item doesn't apply to your pull request, **check it anyway** to make it ap Find the appropriate next version in our [`__init__.py`](https://github.com/hynek/structlog/blob/main/src/structlog/__init__.py) file. - [ ] Documentation in `.rst` and `.md` files is written using [**semantic newlines**](https://rhodesmill.org/brandon/2012/one-sentence-per-line/). - [ ] Changes (and possible deprecations) are documented in the [**changelog**](https://github.com/hynek/structlog/blob/main/CHANGELOG.rst). -- [ ] Consider granting push permissions to the PR branch, so maintainers can fix minor issues themselves without pestering you. +- [ ] Consider granting [push permissions to the PR branch](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork), so maintainers can fix minor issues themselves without pestering you. If you have *any* questions to *any* of the points above, just **submit and ask**! This checklist is here to *help* you, not to deter you from contributing! From 9446227b451730b05a8b618848403feedc4b7597 Mon Sep 17 00:00:00 2001 From: Iwan Aucamp Date: Sat, 11 Dec 2021 07:21:35 +0100 Subject: [PATCH 0642/1520] Fixed spelling mistakes in comments (#383) --- src/structlog/dev.py | 2 +- src/structlog/stdlib.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 91bd1ebe..b5da0016 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -233,7 +233,7 @@ class ConsoleRenderer: `ConsoleRenderer.get_default_level_styles` :param exception_formatter: A callable to render ``exc_infos``. If rich_ or better-exceptions_ are installed, they are used for pretty-printing - by default (rich_ taking precendence). You can also manually set it to + by default (rich_ taking precedence). You can also manually set it to `plain_traceback`, `better_traceback`, `rich_traceback`, or implement your own. :param sort_keys: Whether to sort keys when formatting. `True` by default. diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index d0a4942f..736b784d 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -383,7 +383,7 @@ class AsyncBoundLogger: sync_bl: BoundLogger - # Blantant lie, we use a property for _context. Need this for Protocol + # Blatant lie, we use a property for _context. Need this for Protocol # though. _context: Context From 51132d54a2681c41d3ae6ccc5d226cf114dfbeab Mon Sep 17 00:00:00 2001 From: Iwan Aucamp Date: Sat, 11 Dec 2021 08:32:24 +0100 Subject: [PATCH 0643/1520] Add an explaining comment to ExtraAdder (#382) --- src/structlog/stdlib.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 736b784d..7db47de8 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -695,6 +695,9 @@ class ExtraAdder: def __init__(self, allow: Optional[Collection[str]] = None) -> None: self._copier: Callable[[EventDict, logging.LogRecord], None] if allow is not None: + # The contents of allow is copied to a new list so that changes to + # the list passed into the constructor does not change the + # behaviour of this processor. self._copier = functools.partial(self._copy_allowed, [*allow]) else: self._copier = self._copy_all From 0b5e53401fb833c2fc71ded07690b1bc26e653cd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 13 Dec 2021 09:33:33 +0100 Subject: [PATCH 0644/1520] Move types from func definitions into descriptions --- docs/conf.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/conf.py b/docs/conf.py index c526fdda..044a9786 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -73,6 +73,10 @@ # unit titles (such as .. function::). # add_module_names = True +# Move type hints into the description block, instead of the func definition. +autodoc_typehints = "description" +autodoc_typehints_description_target = "documented" + # -- Options for HTML output -------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for From 1948c2346e1cd4f85f50257b8f4c0967f8918b63 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 16 Dec 2021 09:35:39 +0100 Subject: [PATCH 0645/1520] Comment out explainers for less noise in PRs --- .github/PULL_REQUEST_TEMPLATE.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index c1513e3c..fd5f87bb 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,15 +1,17 @@ # Summary -Please tell us what your pull request is about here. + # Pull Request Check List + - [ ] Added **tests** for changed code. - The CI fails with less than 100% coverage. @@ -22,5 +24,7 @@ If an item doesn't apply to your pull request, **check it anyway** to make it ap - [ ] Changes (and possible deprecations) are documented in the [**changelog**](https://github.com/hynek/structlog/blob/main/CHANGELOG.rst). - [ ] Consider granting [push permissions to the PR branch](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork), so maintainers can fix minor issues themselves without pestering you. + From 0605473ccc13698e9c090cfd14e620f3de1ae6a3 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 16 Dec 2021 09:36:15 +0100 Subject: [PATCH 0646/1520] Looks like pepy.tech is not backfilling --- README.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.rst b/README.rst index daf0364c..354cd667 100644 --- a/README.rst +++ b/README.rst @@ -15,9 +15,6 @@ PyPI release - - Downloads per month -

    .. -begin-short- From 80110eefa380dceaa5d5601fd183da45d268b3f7 Mon Sep 17 00:00:00 2001 From: Iwan Aucamp Date: Thu, 16 Dec 2021 13:19:51 +0100 Subject: [PATCH 0647/1520] Add CallsiteParameterAdder processor (#385) * Add CallsiteParameterAdder processor `structlog.processor.CallsiteParameterAdder` adds parameters of the callsite that an event dictionary orginated from to the event dictionary. This processor can be used to enrich events dictionaries with information such as the function name, line number and filename that an event dictionary orignated from. * Some fixes - Fixed typos - Fixed wording - Removed stray function call. * Remove `structlog.processors.CALLSITE_PARAMETERS` Having this as a public documented module variable does not add value and only creates future liability. * Remove debugging code * Update tests/utils.py Fix typo Co-authored-by: Hynek Schlawack * Update src/structlog/processors.py Fix typo Co-authored-by: Hynek Schlawack * Fixes and changes from review - remove mock_getframe and use `additional_frame` instead. - use `n/a` instead of `MainProcess` if the process name cannot be determined. - use pytest.fail instead of `ValueError` - Add `ClassVar` to class variables `_handlers` and `_all_parameters`. - Don't make CallsiteParameter a subclass of `str`. * Added newlines before assert blocks in tests Co-authored-by: Hynek Schlawack --- CHANGELOG.rst | 3 + docs/api.rst | 5 + docs/standard-library.rst | 6 + src/structlog/_utils.py | 17 ++ src/structlog/processors.py | 193 +++++++++++++++++++ tests/test_processors.py | 360 ++++++++++++++++++++++++++++++++++++ tests/test_utils.py | 64 ++++++- typing_examples.py | 38 ++++ 8 files changed, 685 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4b65f5e4..52047294 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -42,6 +42,9 @@ Changes: - Added the ``structlog.stdlib.ExtraAdder`` processor that adds extra attributes of ``logging.LogRecord`` objects to the event dictionary. This processor can be used for adding data passed in the ``extra`` parameter of the ``logging`` module's log methods to the event dictionary. `#377 `_ +- Added the ``structlog.processor.CallsiteParameterAdder`` processor that adds parameters of the callsite that an event dictionary orginated from to the event dictionary. + This processor can be used to enrich events dictionaries with information such as the function name, line number and filename that an event dictionary orignated from. + `#380 `_ ---- diff --git a/docs/api.rst b/docs/api.rst index 47571931..5c07f306 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -276,6 +276,11 @@ Please see :doc:`thread-local` for details. >>> TimeStamper(fmt="%Y", key="year")(None, None, {}) # doctest: +SKIP {'year': '2013'} +.. autoclass:: CallsiteParameter + :members: + +.. autoclass:: CallsiteParameterAdder + `structlog.stdlib` Module ------------------------- diff --git a/docs/standard-library.rst b/docs/standard-library.rst index a51da43f..ec3c5366 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -166,6 +166,12 @@ A basic configuration to output structured logs in JSON format looks like this: structlog.processors.format_exc_info, # If some value is in bytes, decode it to a unicode str. structlog.processors.UnicodeDecoder(), + # Add callsite parameters. + structlog.processors.CallsiteParameterAdder( + CallsiteParameter.FILENAME, + CallsiteParameter.FUNC_NAME, + CallsiteParameter.LINENO, + ), # Render the final event dict as JSON. structlog.processors.JSONRenderer() ], diff --git a/src/structlog/_utils.py b/src/structlog/_utils.py index e9a9cecb..4202ef01 100644 --- a/src/structlog/_utils.py +++ b/src/structlog/_utils.py @@ -8,6 +8,7 @@ """ import errno +import sys from typing import Any, Callable @@ -27,3 +28,19 @@ def until_not_interrupted(f: Callable[..., Any], *args: Any, **kw: Any) -> Any: if e.args[0] == errno.EINTR: continue raise + + +def get_processname() -> str: + # based on code from + # https://github.com/python/cpython/blob/313f92a57bc3887026ec16adb536bb2b7580ce47/Lib/logging/__init__.py#L342-L352 + processname = "n/a" + mp: Any = sys.modules.get("multiprocessing") + if mp is not None: + # Errors may occur if multiprocessing has not finished loading + # yet - e.g. if a custom import hook causes third-party code + # to run when multiprocessing calls import. + try: + processname = mp.current_process().name + except Exception: + pass + return processname diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 1e2cfab1..6b3a1548 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -8,18 +8,27 @@ """ import datetime +import enum +import inspect import json +import logging import operator +import os import sys +import threading import time from typing import ( Any, Callable, + ClassVar, + Collection, Dict, List, + NamedTuple, Optional, Sequence, + Set, TextIO, Tuple, Union, @@ -31,6 +40,7 @@ _format_stack, ) from ._log_levels import _NAME_TO_LEVEL, add_log_level +from ._utils import get_processname from .types import EventDict, ExcInfo, WrappedLogger @@ -45,6 +55,8 @@ "format_exc_info", "ExceptionPrettyPrinter", "StackInfoRenderer", + "CallsiteParameter", + "CallsiteParameterAdder", ] @@ -531,3 +543,184 @@ def __call__( ) return event_dict + + +class CallsiteParameter(enum.Enum): + """ + Callsite parameters that can be added to an event dictionary with the + `structlog.processors.CallsiteParameterAdder` processor class. + + The string values of the members of this enum will be used as the keys for + the callsite parameters in the event dictionary. + + .. versionadded:: 21.5.0 + """ + + #: The full path to the python source file of the callsite. + PATHNAME = "pathname" + #: The basename part of the full path to the python source file of the + #: callsite. + FILENAME = "filename" + #: The python module the callsite was in. This mimicks the module attribute + #: of `logging.LogRecord` objects and will be the basename, without + #: extension, of the full path to the python source file of the callsite. + MODULE = "module" + #: The name of the function that the callsite was in. + FUNC_NAME = "func_name" + #: The line number of the callsite. + LINENO = "lineno" + #: The ID of the thread the callsite was executed in. + THREAD = "thread" + #: The name of the thread the callsite was executed in. + THREAD_NAME = "thread_name" + #: The ID of the process the callsite was executed in. + PROCESS = "process" + #: The name of the process the callsite was executed in. + PROCESS_NAME = "process_name" + + +class CallsiteParameterAdder: + """ + Adds parameters of the callsite that an event dictionary originated from to + the event dictionary. This processor can be used to enrich events + dictionaries with information such as the function name, line number and + filename that an event dictionary originated from. + + .. warning:: + This processor cannot detect the correct callsite for invocation of + async functions. + + If the event dictionary has an embedded `logging.LogRecord` object and did + not originate from `structlog` then the callsite information will be + determined from the `logging.LogRecord` object. For event dictionaries + without an embedded `logging.LogRecord` object the callsite will be + determined from the stack trace, ignoring all intra-structlog calls, calls + from the `logging` module, and stack frames from modules with names that + start with values in ``additional_ignores``, if it is specified. + + The keys used for callsite parameters in the event dictionary are the + string values of `CallsiteParameter` enum members. + + :param parameters: + A collection of `CallsiteParameter` values that should be added to the + event dictionary. + + :param additional_ignores: + Additional names with which a stack frame's module name must not + start for it to be considered when determening the callsite. + + .. note:: + When used with `structlog.stdlib.ProcessorFormatter` the most efficient + configuration is to either use this processor in ``foreign_pre_chain`` + of `structlog.stdlib.ProcessorFormatter` and in ``processors`` of + `structlog.configure`, or to use it in ``processors`` of + `structlog.stdlib.ProcessorFormatter` without using it in + ``processors`` of `structlog.configure` and ``foreign_pre_chain`` of + `structlog.stdlib.ProcessorFormatter`. + + .. versionadded:: 21.5.0 + """ + + _handlers: ClassVar[ + Dict[CallsiteParameter, Callable[[str, inspect.Traceback], Any]] + ] = { + CallsiteParameter.PATHNAME: ( + lambda module, frame_info: frame_info.filename + ), + CallsiteParameter.FILENAME: ( + lambda module, frame_info: os.path.basename(frame_info.filename) + ), + CallsiteParameter.MODULE: ( + lambda module, frame_info: os.path.splitext( + os.path.basename(frame_info.filename) + )[0] + ), + CallsiteParameter.FUNC_NAME: ( + lambda module, frame_info: frame_info.function + ), + CallsiteParameter.LINENO: ( + lambda module, frame_info: frame_info.lineno + ), + CallsiteParameter.THREAD: ( + lambda module, frame_info: threading.get_ident() + ), + CallsiteParameter.THREAD_NAME: ( + lambda module, frame_info: threading.current_thread().name + ), + CallsiteParameter.PROCESS: (lambda module, frame_info: os.getpid()), + CallsiteParameter.PROCESS_NAME: ( + lambda module, frame_info: get_processname() + ), + } + _record_attribute_map: ClassVar[Dict[CallsiteParameter, str]] = { + CallsiteParameter.PATHNAME: "pathname", + CallsiteParameter.FILENAME: "filename", + CallsiteParameter.MODULE: "module", + CallsiteParameter.FUNC_NAME: "funcName", + CallsiteParameter.LINENO: "lineno", + CallsiteParameter.THREAD: "thread", + CallsiteParameter.THREAD_NAME: "threadName", + CallsiteParameter.PROCESS: "process", + CallsiteParameter.PROCESS_NAME: "processName", + } + + _all_parameters: ClassVar[Set[CallsiteParameter]] = set(CallsiteParameter) + + class _RecordMapping(NamedTuple): + event_dict_key: str + record_attribute: str + + __slots__ = [ + "_active_handlers", + "_additional_ignores", + "_record_mappings", + ] + + def __init__( + self, + parameters: Collection[CallsiteParameter] = _all_parameters, + additional_ignores: Optional[List[str]] = None, + ) -> None: + if additional_ignores is None: + additional_ignores = [] + # Ignore stack frames from the logging module. They will occur if this + # processor is used in ProcessorFormatter, and additionally the logging + # module should not be logging using structlog. + self._additional_ignores = ["logging", *additional_ignores] + self._active_handlers: List[ + Tuple[CallsiteParameter, Callable[[str, inspect.Traceback], Any]] + ] = [] + self._record_mappings: List[ + "CallsiteParameterAdder._RecordMapping" + ] = [] + for parameter in parameters: + self._active_handlers.append( + (parameter, self._handlers[parameter]) + ) + self._record_mappings.append( + self._RecordMapping( + parameter.value, + self._record_attribute_map[parameter], + ) + ) + + def __call__( + self, logger: logging.Logger, name: str, event_dict: EventDict + ) -> EventDict: + record: Optional[logging.LogRecord] = event_dict.get("_record") + from_structlog: Optional[bool] = event_dict.get("_from_structlog") + # If the event dictionary has a record, but it comes from structlog, + # then the callsite parameters of the record will not be correct. + if record is not None and not from_structlog: + for mapping in self._record_mappings: + event_dict[mapping.event_dict_key] = record.__dict__[ + mapping.record_attribute + ] + else: + frame, module = _find_first_app_frame_and_name( + additional_ignores=self._additional_ignores + ) + frame_info = inspect.getframeinfo(frame) + for parameter, handler in self._active_handlers: + event_dict[parameter.value] = handler(module, frame_info) + return event_dict diff --git a/tests/test_processors.py b/tests/test_processors.py index 60c70fad..e7c3d5b2 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -4,9 +4,18 @@ # repository for complete details. import datetime +import functools +import inspect +import itertools import json +import logging +import os import pickle import sys +import threading + +from io import StringIO +from typing import Any, Dict, List, Optional, Set import pytest @@ -14,7 +23,11 @@ import structlog +from structlog import BoundLogger +from structlog._utils import get_processname from structlog.processors import ( + CallsiteParameter, + CallsiteParameterAdder, ExceptionPrettyPrinter, JSONRenderer, KeyValueRenderer, @@ -27,7 +40,10 @@ _json_fallback_handler, format_exc_info, ) +from structlog.stdlib import ProcessorFormatter from structlog.threadlocal import wrap_dict +from structlog.types import EventDict +from tests.additional_frame import additional_frame try: @@ -714,3 +730,347 @@ def test_py3_exception_no_traceback(self): e = ValueError() assert (e.__class__, e, None) == _figure_out_exc_info(e) + + +class TestCallsiteParameterAdder: + parameter_strings = { + "pathname", + "filename", + "module", + "func_name", + "lineno", + "thread", + "thread_name", + "process", + "process_name", + } + + _all_parameters = set(CallsiteParameter) + + def test_all_parameters(self) -> None: + """ + All callsite parameters are included in ``self.parameter_strings`` and + the dictionary returned by ``self.get_callsite_parameters`` contains + keys for all callsite parameters. + """ + + assert self.parameter_strings == { + member.value for member in self._all_parameters + } + assert self.parameter_strings == self.get_callsite_parameters().keys() + + @pytest.mark.xfail( + reason=( + "CallsiteParameterAdder cannot " + "determine the callsite for async calls." + ) + ) + @pytest.mark.asyncio + async def test_async(self) -> None: + """ + Callsite information for async invocations are correct. + """ + try: + string_io = StringIO() + + class StingIOLogger(structlog.PrintLogger): + def __init__(self): + super().__init__(file=string_io) + + processor = self.make_processor(None, ["concurrent", "threading"]) + structlog.configure( + processors=[processor, JSONRenderer()], + logger_factory=StingIOLogger, + wrapper_class=structlog.stdlib.AsyncBoundLogger, + cache_logger_on_first_use=True, + ) + + logger = structlog.stdlib.get_logger() + + callsite_params = self.get_callsite_parameters() + await logger.info("baz") + + assert {"event": "baz", **callsite_params} == json.loads( + string_io.getvalue() + ) + + finally: + structlog.reset_defaults() + + def test_additional_ignores(self, monkeypatch: pytest.MonkeyPatch) -> None: + """ + Stack frames from modules with names that start with values in + `additional_ignores` are ignored when determining the callsite. + """ + test_message = "test message" + additional_ignores = ["tests.additional_frame"] + processor = self.make_processor(None, additional_ignores) + event_dict: EventDict = {"event": test_message} + + # `functools.partial` is used instead of a lambda because a lambda will + # add an additional frame in a module that should not be ignored. + _sys_getframe = functools.partial(additional_frame, sys._getframe) + + # WARNING: The below three lines are sensitive to relative line numbers + # (i.e. the invocation of processor must be two lines after the + # invocation of get_callsite_parameters) and is order sensitive (i.e. + # monkeypatch.setattr must occur after get_callsite_parameters but + # before invocation of processor). + callsite_params = self.get_callsite_parameters(2) + monkeypatch.setattr(sys, "_getframe", value=_sys_getframe) + actual = processor(None, None, event_dict) + + expected = { + "event": test_message, + **callsite_params, + } + + assert expected == actual + + @pytest.mark.parametrize( + "origin, parameter_strings", + itertools.product( + ["logging", "structlog"], + [ + None, + *[{parameter} for parameter in parameter_strings], + set(), + parameter_strings, + {"pathname", "filename"}, + {"module", "func_name"}, + ], + ), + ) + def test_processor( + self, + origin: str, + parameter_strings: Optional[Set[str]], + ): + """ + The correct callsite parameters are added to event dictionaries. + """ + test_message = "test message" + processor = self.make_processor(parameter_strings) + if origin == "structlog": + event_dict: EventDict = {"event": test_message} + callsite_params = self.get_callsite_parameters() + actual = processor(None, None, event_dict) + elif origin == "logging": + callsite_params = self.get_callsite_parameters() + record = logging.LogRecord( + "name", + logging.INFO, + callsite_params["pathname"], + callsite_params["lineno"], + test_message, + None, + None, + callsite_params["func_name"], + ) + event_dict: EventDict = { + "event": test_message, + "_record": record, + "_from_structlog": False, + } + actual = processor(None, None, event_dict) + else: + pytest.fail(f"invalid origin {origin}") + actual = { + key: value + for key, value in actual.items() + if not key.startswith("_") + } + callsite_params = self.filter_parameter_dict( + callsite_params, parameter_strings + ) + expected = { + "event": test_message, + **callsite_params, + } + + assert expected == actual + + @pytest.mark.parametrize( + "setup, origin, parameter_strings", + itertools.product( + ["common-without-pre", "common-with-pre", "shared", "everywhere"], + ["logging", "structlog"], + [ + None, + *[{parameter} for parameter in parameter_strings], + set(), + parameter_strings, + {"pathname", "filename"}, + {"module", "func_name"}, + ], + ), + ) + def test_e2e( + self, + setup: str, + origin: str, + parameter_strings: Optional[Set[str]], + ) -> None: + """ + Logging output contains the correct callsite parameters. + """ + logger = logging.Logger(sys._getframe().f_code.co_name) + string_io = StringIO() + handler = logging.StreamHandler(string_io) + processors = [self.make_processor(parameter_strings)] + if setup == "common-without-pre": + common_processors = processors + formatter = ProcessorFormatter( + processors=[*processors, JSONRenderer()] + ) + elif setup == "common-with-pre": + common_processors = processors + formatter = ProcessorFormatter( + foreign_pre_chain=processors, + processors=[JSONRenderer()], + ) + elif setup == "shared": + common_processors = [] + formatter = ProcessorFormatter( + processors=[*processors, JSONRenderer()], + ) + elif setup == "everywhere": + common_processors = processors + formatter = ProcessorFormatter( + foreign_pre_chain=processors, + processors=[*processors, JSONRenderer()], + ) + else: + pytest.fail(f"invalid setup {setup}") + handler.setFormatter(formatter) + handler.setLevel(0) + logger.addHandler(handler) + logger.setLevel(0) + + test_message = "test message" + if origin == "logging": + callsite_params = self.get_callsite_parameters() + logger.info(test_message) + elif origin == "structlog": + ctx: Dict[str, Any] = {} + bound_logger = BoundLogger( + logger, + [*common_processors, ProcessorFormatter.wrap_for_formatter], + ctx, + ) + callsite_params = self.get_callsite_parameters() + bound_logger.info(test_message) + else: + pytest.fail(f"invalid origin {origin}") + + callsite_params = self.filter_parameter_dict( + callsite_params, parameter_strings + ) + actual = { + key: value + for key, value in json.loads(string_io.getvalue()).items() + if not key.startswith("_") + } + expected = { + "event": test_message, + **callsite_params, + } + + assert expected == actual + + @classmethod + def make_processor( + cls, + parameter_strings: Optional[Set[str]], + additional_ignores: Optional[List[str]] = None, + ) -> CallsiteParameterAdder: + """ + Creates a ``CallsiteParameterAdder`` with parameters matching the + supplied ``parameter_strings`` values and with the supplied + ``additional_ignores`` values. + + :param parameter_strings: + Strings for which corresponding ``CallsiteParameters`` should be + included in the resulting ``CallsiteParameterAdded``. + :param additional_ignores: + Used as ``additional_ignores`` for the resulting + ``CallsiteParameterAdded``. + """ + if parameter_strings is None: + return CallsiteParameterAdder( + additional_ignores=additional_ignores + ) + else: + parameters = cls.filter_parameters(parameter_strings) + return CallsiteParameterAdder( + parameters=parameters, + additional_ignores=additional_ignores, + ) + + @classmethod + def filter_parameters( + cls, parameter_strings: Optional[Set[str]] + ) -> Set[CallsiteParameter]: + """ + Returns a set containing all ``CallsiteParameter`` members with values + that are in ``parameter_strings``. + + :param parameter_strings: + The parameters strings for which corresponding + ``CallsiteParameter`` members should be + returned. If this value is `None` then all + ``CallsiteParameter`` will be returned. + """ + if parameter_strings is None: + return cls._all_parameters + return { + parameter + for parameter in cls._all_parameters + if parameter.value in parameter_strings + } + + @classmethod + def filter_parameter_dict( + cls, input: Dict[str, Any], parameter_strings: Optional[Set[str]] + ) -> Dict[str, Any]: + """ + Returns a dictionary that is equivalent to ``input`` but with all keys + not in ``parameter_strings`` removed. + + :param parameter_strings: + The keys to keep in the dictionary, if this value is ``None`` then + all keys matching ``cls.parameter_strings`` are kept. + """ + if parameter_strings is None: + parameter_strings = cls.parameter_strings + return { + key: value + for key, value in input.items() + if key in parameter_strings + } + + @classmethod + def get_callsite_parameters(cls, offset: int = 1) -> Dict[str, Any]: + """ + This function creates dictionary of callsite parameters for the line + that is ``offset`` lines after the invocation of this function. + + :param offset: + The amount of lines after the invocation of this function that + callsite parameters should be generated for. + """ + frame_info = inspect.stack()[1] + frame_traceback = inspect.getframeinfo(frame_info[0]) + return { + "pathname": frame_traceback.filename, + "filename": os.path.basename(frame_traceback.filename), + "module": os.path.splitext( + os.path.basename(frame_traceback.filename) + )[0], + "func_name": frame_info.function, + "lineno": frame_info.lineno + offset, + "thread": threading.get_ident(), + "thread_name": threading.current_thread().name, + "process": os.getpid(), + "process_name": get_processname(), + } diff --git a/tests/test_utils.py b/tests/test_utils.py index c7241ee9..87a8f2fd 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -4,12 +4,14 @@ # repository for complete details. import errno +import multiprocessing +import sys import pytest from pretend import raiser -from structlog._utils import until_not_interrupted +from structlog._utils import get_processname, until_not_interrupted class TestUntilNotInterrupted: @@ -35,3 +37,63 @@ def raise_on_first_three(): until_not_interrupted(raise_on_first_three) assert 3 == calls[0] + + +class TestGetProcessname: + def test_default(self): + """ + The returned process name matches the name of the current process from + the `multiprocessing` module. + """ + assert get_processname() == multiprocessing.current_process().name + + def test_changed(self, monkeypatch: pytest.MonkeyPatch): + """ + The returned process name matches the name of the current process from + the `multiprocessing` module if it is not the default. + """ + tmp_name = "fakename" + monkeypatch.setattr( + target=multiprocessing.current_process(), + name="name", + value=tmp_name, + ) + + assert get_processname() == tmp_name + + def test_no_multiprocessing(self, monkeypatch: pytest.MonkeyPatch) -> None: + """ + The returned process name is the default process name if the + `multiprocessing` module is not available. + """ + tmp_name = "fakename" + monkeypatch.setattr( + target=multiprocessing.current_process(), + name="name", + value=tmp_name, + ) + monkeypatch.setattr( + target=sys, + name="modules", + value={}, + ) + + assert get_processname() == "n/a" + + def test_exception(self, monkeypatch: pytest.MonkeyPatch) -> None: + """ + The returned process name is the default process name when an exception + is thrown when an attempt is made to retrieve the current process name + from the `multiprocessing` module. + """ + + def _current_process() -> None: + raise RuntimeError("test") + + monkeypatch.setattr( + target=multiprocessing, + name="current_process", + value=_current_process, + ) + + assert get_processname() == "n/a" diff --git a/typing_examples.py b/typing_examples.py index 8f2b4311..571cf3b7 100644 --- a/typing_examples.py +++ b/typing_examples.py @@ -14,6 +14,8 @@ import structlog +from structlog.processors import CallsiteParameter + bl = structlog.get_logger() bl.msg("hello", whom="world", x=42, y={}) @@ -67,6 +69,42 @@ def bytes_dumps( processor=structlog.dev.ConsoleRenderer(), ) +formatter = structlog.stdlib.ProcessorFormatter( + processors=[ + structlog.processors.CallsiteParameterAdder(), + structlog.processors.CallsiteParameterAdder( + set(CallsiteParameter), ["threading"] + ), + structlog.processors.CallsiteParameterAdder( + set(CallsiteParameter), additional_ignores=["threading"] + ), + structlog.processors.CallsiteParameterAdder( + parameters=set(CallsiteParameter), additional_ignores=["threading"] + ), + structlog.processors.CallsiteParameterAdder( + [ + CallsiteParameter.FILENAME, + CallsiteParameter.FUNC_NAME, + CallsiteParameter.LINENO, + ] + ), + structlog.processors.CallsiteParameterAdder( + parameters=[ + CallsiteParameter.FILENAME, + CallsiteParameter.FUNC_NAME, + CallsiteParameter.LINENO, + ] + ), + structlog.processors.CallsiteParameterAdder( + parameters=[ + CallsiteParameter.FILENAME, + CallsiteParameter.FUNC_NAME, + CallsiteParameter.LINENO, + ] + ), + ], +) + handler = logging.StreamHandler() handler.setFormatter(formatter) root_logger = logging.getLogger() From b3ad5af282e9cee5a9b0c99314843b7a3cb6915c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 16 Dec 2021 13:21:52 +0100 Subject: [PATCH 0648/1520] Link 209 for context --- CHANGELOG.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 52047294..c49cd341 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -41,6 +41,7 @@ Changes: `#376 `_ - Added the ``structlog.stdlib.ExtraAdder`` processor that adds extra attributes of ``logging.LogRecord`` objects to the event dictionary. This processor can be used for adding data passed in the ``extra`` parameter of the ``logging`` module's log methods to the event dictionary. + `#209 `_ `#377 `_ - Added the ``structlog.processor.CallsiteParameterAdder`` processor that adds parameters of the callsite that an event dictionary orginated from to the event dictionary. This processor can be used to enrich events dictionaries with information such as the function name, line number and filename that an event dictionary orignated from. From 2d66103ded9c790f1e71c7864c12dbb772923c9f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 16 Dec 2021 13:40:32 +0100 Subject: [PATCH 0649/1520] Remove bogus link --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c49cd341..bc5452e6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -222,7 +222,7 @@ Backward-incompatible changes: You can regain the old behavior by using ``structlog.configure(wrapper_class=structlog.BoundLogger)``. Please note that due to the various interactions between settings, it's possible that you encounter even more errors. - We **strongly** urge you to always configure all possible settings since the default configuration is *not* covered by our `backward compatibility policy `_. + We **strongly** urge you to always configure all possible settings since the default configuration is *not* covered by our backwards-compatibility policy. Deprecations: From a67b226c02ddf6238ad48838bc40294b0874d5e9 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 16 Dec 2021 13:43:02 +0100 Subject: [PATCH 0650/1520] Consistency --- CHANGELOG.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index bc5452e6..b14c2ba6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,7 +1,7 @@ Changelog ========= -Versions follow `Calendar Versioning `_ with a strict backwards compatibility policy. +Versions follow `Calendar Versioning `_ with a strict backwards-compatibility policy. The **first digit** of the version is the year. The **second digit** is incremented with each release, starting at 1 for each year. @@ -238,7 +238,7 @@ Changes: - ``structlog`` has now type hints for all of its APIs! Since ``structlog`` is highly dynamic and configurable, this led to a few concessions like a specialized ``structlog.stdlib.get_logger()`` whose only difference to ``structlog.get_logger()`` is that it has the correct type hints. - We consider them provisional for the time being – i.e. the backward compatibility does not apply to them in its full strength until we feel we got it right. + We consider them provisional for the time being – i.e. the backwards-compatibility does not apply to them in its full strength until we feel we got it right. Please feel free to provide feedback! `#223 `_, `#282 `_ @@ -520,7 +520,7 @@ Backward-incompatible changes: - The default renderer now is ``structlog.dev.ConsoleRenderer`` if you don't configure ``structlog``. Colors are used if available and human-friendly timestamps are prepended. - This is in line with our backward `compatibility policy `_ that explicitly excludes default settings. + This is in line with our backwards-compatibility policy that explicitly excludes default settings. Changes: @@ -783,7 +783,7 @@ Changes: Changes: ^^^^^^^^ -- Promote to stable, thus henceforth a strict backward compatibility policy is put into effect. +- Promote to stable, thus henceforth a strict backwards-compatibility policy is put into effect. - Add ``key_order`` option to ``structlog.processors.KeyValueRenderer`` for more predictable log entries with any ``dict`` class. - ``structlog.PrintLogger`` now uses proper I/O routines and is thus viable not only for examples but also for production. - Enhance Twisted support by offering JSONification of non-structlog log entries. From 858c5c8fb83416c7889364623ad521ce6bb23004 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 16 Dec 2021 13:43:37 +0100 Subject: [PATCH 0651/1520] Prepare 21.5.0 --- CHANGELOG.rst | 2 +- src/structlog/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b14c2ba6..39030ab2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -18,7 +18,7 @@ Whenever there is a need to break compatibility, it is announced here in the cha .. changelog -21.5.0 (UNRELEASED) +21.5.0 (2021-12-16) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 63103b3f..48d3387e 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -42,7 +42,7 @@ contextvars = None # type: ignore -__version__ = "21.5.0.dev0" +__version__ = "21.5.0" __title__ = "structlog" # __doc__ is None when running with PYTHONOPTIMIZE=2 / -OO From 887f66ad0b18c145a5f681ce14ab4a8e69bd9689 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 16 Dec 2021 13:48:14 +0100 Subject: [PATCH 0652/1520] Start new development cycle --- CHANGELOG.rst | 24 ++++++++++++++++++++++++ src/structlog/__init__.py | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 39030ab2..8414488b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -18,6 +18,30 @@ Whenever there is a need to break compatibility, it is announced here in the cha .. changelog +XX.Y.Z (UNRELEASED) +------------------- + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +*none* + + +Deprecations: +^^^^^^^^^^^^^ + +*none* + + +Changes: +^^^^^^^^ + +*none* + + +---- + + 21.5.0 (2021-12-16) ------------------- diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 48d3387e..b70a2278 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -42,7 +42,7 @@ contextvars = None # type: ignore -__version__ = "21.5.0" +__version__ = "21.6.0.dev0" __title__ = "structlog" # __doc__ is None when running with PYTHONOPTIMIZE=2 / -OO From 812c31d4ab5c4f022b1d24711e083f3474ca30b2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 17 Dec 2021 07:36:14 +0100 Subject: [PATCH 0653/1520] Declare end of year --- src/structlog/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index b70a2278..40e1d94d 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -42,7 +42,7 @@ contextvars = None # type: ignore -__version__ = "21.6.0.dev0" +__version__ = "22.1.0.dev0" __title__ = "structlog" # __doc__ is None when running with PYTHONOPTIMIZE=2 / -OO From 20547532c299ff4a0b631028281ca334602f9de3 Mon Sep 17 00:00:00 2001 From: The Alchemist Date: Wed, 29 Dec 2021 02:29:36 -0500 Subject: [PATCH 0654/1520] tiny grammar fix (#389) --- docs/standard-library.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/standard-library.rst b/docs/standard-library.rst index ec3c5366..3e788c68 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -11,7 +11,7 @@ If you're a heavy `logging` user, your `help Date: Wed, 29 Dec 2021 09:18:08 +0100 Subject: [PATCH 0655/1520] Use correct words --- CHANGELOG.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8414488b..42c5a345 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,9 +3,9 @@ Changelog Versions follow `Calendar Versioning `_ with a strict backwards-compatibility policy. -The **first digit** of the version is the year. -The **second digit** is incremented with each release, starting at 1 for each year. -The **third digit** is when we need to start branches for older releases (only for emergencies). +The **first number** of the version is the year. +The **second number** is incremented with each release, starting at 1 for each year. +The **third number** is when we need to start branches for older releases (only for emergencies). You shouldn't ever be afraid to upgrade ``structlog`` if you're using its public APIs and pay attention to ``DeprecationWarning``\ s. Whenever there is a need to break compatibility, it is announced here in the changelog and raises a ``DeprecationWarning`` for a year (if possible) before it's finally really broken. From dd66887097c53773cd2470d4041ca27e62cb209c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 3 Jan 2022 18:15:11 +0100 Subject: [PATCH 0656/1520] [pre-commit.ci] pre-commit autoupdate (#391) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b05c569c..97940bb4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,7 +10,7 @@ repos: language_version: python3.10 - repo: https://github.com/asottile/pyupgrade - rev: v2.29.1 + rev: v2.31.0 hooks: - id: pyupgrade args: [--py36-plus] @@ -30,7 +30,7 @@ repos: exclude: docs/code_examples - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.0.1 + rev: v4.1.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer From 3932475b444e2bd9e94a167eaceb87380e0e326e Mon Sep 17 00:00:00 2001 From: Iwan Aucamp Date: Wed, 12 Jan 2022 09:47:19 +0100 Subject: [PATCH 0657/1520] Narrow the return type of bind,unbind,try_unbind,new in subclass (#392) * Narrow the return type of bind,unbind,try_unbind,new in subclass This narrows the return type of `bind`,`unbind`,`try_unbind` and `new` in `FilteringBoundLogger` to return `FilteringBoundLogger` instead of `BindableLogger`. This makes it easier to use structlog in a typed context like this: ```python def typecheck_filtering_return() -> None: fblogger: FilteringBoundLogger = structlog.get_logger(__name__) fblog = fblogger.bind(key1="value1", key2="value2", key3="value3") fblog.info("values bound") fblog = fblog.unbind("key1") fblog.debug("value unbound") fblog = fblog.try_unbind("bad_key") fblog.warn("no value unbound because key not defined") fblog = fblog.new(new="value") fblog.info("this is a whole new logger") ``` Without this change the above example will result in a type error when using `mypy --strict` as the type of `fblog` will be `BindableLogger` which does not have an `info` method: ```console typing_examples.py:288: error: "BindableLogger" has no attribute "info" typing_examples.py:290: error: "BindableLogger" has no attribute "debug" typing_examples.py:292: error: "BindableLogger" has no attribute "warn" typing_examples.py:294: error: "BindableLogger" has no attribute "info" Found 4 errors in 1 file (checked 19 source files) ``` * Fix bad link in CHANGELOG.rst --- CHANGELOG.rst | 6 ++++-- src/structlog/types.py | 28 ++++++++++++++++++++++++++++ typing_examples.py | 13 +++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 42c5a345..1ee209a4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -18,7 +18,7 @@ Whenever there is a need to break compatibility, it is announced here in the cha .. changelog -XX.Y.Z (UNRELEASED) +22.1.0 (UNRELEASED) ------------------- Backward-incompatible changes: @@ -36,7 +36,9 @@ Deprecations: Changes: ^^^^^^^^ -*none* +- Overloaded the ``bind``, ``unbind``, ``try_unbind`` and ``new`` methods in the ``FilteringBoundLogger`` `Protocol `_. + This makes it easier to use objects of type ``FilteringBoundLogger`` in a typed context. + `#392 `_ ---- diff --git a/src/structlog/types.py b/src/structlog/types.py index 04378fa2..69aa7f7e 100644 --- a/src/structlog/types.py +++ b/src/structlog/types.py @@ -130,6 +130,34 @@ class FilteringBoundLogger(BindableLogger, Protocol): .. versionadded:: 20.2.0 """ + def bind(self, **new_values: Any) -> "FilteringBoundLogger": + """ + Return a new logger with *new_values* added to the existing ones. + + .. versionadded:: 22.1.0 + """ + + def unbind(self, *keys: str) -> "FilteringBoundLogger": + """ + Return a new logger with *keys* removed from the context. + + .. versionadded:: 22.1.0 + """ + + def try_unbind(self, *keys: str) -> "FilteringBoundLogger": + """ + Like :meth:`unbind`, but best effort: missing keys are ignored. + + .. versionadded:: 22.1.0 + """ + + def new(self, **new_values: Any) -> "FilteringBoundLogger": + """ + Clear context and binds *initial_values* using `bind`. + + .. versionadded:: 22.1.0 + """ + def debug(self, event: str, **kw: Any) -> Any: """ Log *event* with **kw** at **debug** level. diff --git a/typing_examples.py b/typing_examples.py index 571cf3b7..02fc9106 100644 --- a/typing_examples.py +++ b/typing_examples.py @@ -15,6 +15,7 @@ import structlog from structlog.processors import CallsiteParameter +from structlog.types import FilteringBoundLogger bl = structlog.get_logger() @@ -279,3 +280,15 @@ def bytes_dumps( with structlog.threadlocal.bound_threadlocal(x=42): pass + + +def typecheck_filtering_return() -> None: + fblogger: FilteringBoundLogger = structlog.get_logger(__name__) + fblog = fblogger.bind(key1="value1", key2="value2", key3="value3") + fblog.info("values bound") + fblog = fblog.unbind("key1") + fblog.debug("value unbound") + fblog = fblog.try_unbind("bad_key") + fblog.warn("no value unbound because key not defined") + fblog = fblog.new(new="value") + fblog.info("this is a whole new logger") From 020e9dc4ebd76e98d76d20b9edaf00c56bc9550e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 26 Jan 2022 11:34:17 +0100 Subject: [PATCH 0658/1520] Build docs on 3.10, clean up nitpick ignores --- .github/workflows/main.yml | 4 ++-- .readthedocs.yml | 11 ++++++++--- docs/conf.py | 12 ++++-------- tox.ini | 6 +++--- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b618222e..4d2efd60 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -97,10 +97,10 @@ jobs: install-dev: name: Verify dev env - runs-on: "${{ matrix.os }}" + runs-on: ${{ matrix.os }} strategy: matrix: - os: ["ubuntu-latest", "windows-latest"] + os: [ubuntu-latest, windows-latest] steps: - uses: actions/checkout@v2 diff --git a/.readthedocs.yml b/.readthedocs.yml index 009da9ff..d335c40d 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -1,9 +1,14 @@ --- version: 2 -python: - # Keep version in sync with tox.ini (docs and gh-actions). - version: 3.8 +formats: all + +build: + os: ubuntu-20.04 + tools: + # Keep version in sync with tox.ini (docs and gh-actions). + python: "3.10" +python: install: - method: pip path: . diff --git a/docs/conf.py b/docs/conf.py index 044a9786..14c6adb8 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -52,18 +52,14 @@ default_role = "any" nitpick_ignore = [ - ("py:class", "BinaryIO"), + ("py:class", "Context"), ("py:class", "ILogObserver"), ("py:class", "PlainFileObserver"), - ("py:class", "structlog.threadlocal.TLLogger"), - ("py:class", "TextIO"), - ("py:class", "TLLogger"), - ("py:class", "traceback"), - ("py:class", "structlog._base.BoundLoggerBase"), + ("py:class", "Processor"), + ("py:class", "WrappedLogger"), ("py:class", "structlog.dev._Styles"), + ("py:class", "structlog.threadlocal.TLLogger"), ("py:class", "structlog.types.EventDict"), - ("py:obj", "sync_bl"), - ("py:obj", "entries"), ] # If true, '()' will be appended to :func: etc. cross-reference text. diff --git a/tox.ini b/tox.ini index edf16868..9e25962a 100644 --- a/tox.ini +++ b/tox.ini @@ -7,9 +7,9 @@ ignore = E203,W503,W504 python = 3.6: py36 3.7: py37 - 3.8: py38, docs + 3.8: py38 3.9: py39, mypy - 3.10: py310, cogCheck + 3.10: py310, cogCheck, docs [tox] @@ -19,7 +19,7 @@ isolated_build = True [testenv:docs] # Keep basepython in sync with gh-actions and .readthedocs.yml. -basepython = python3.8 +basepython = python3.10 extras = docs passenv = TERM From 21f75520c0feda728117d8c747e412cd9f12f291 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 26 Jan 2022 11:46:19 +0100 Subject: [PATCH 0659/1520] Drop Python 3.6 It's EOL and pytest-asyncio dropped it too. Supporting multiple versions is not worth the hassle. --- .github/workflows/main.yml | 2 +- .pre-commit-config.yaml | 4 +--- CHANGELOG.rst | 2 +- README.rst | 2 +- conftest.py | 3 --- pyproject.toml | 8 +++----- src/structlog/__init__.py | 15 +++++++++------ src/structlog/stdlib.py | 7 +------ tox.ini | 12 ++++++------ 9 files changed, 23 insertions(+), 32 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4d2efd60..f316d455 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"] + python-version: ["3.7", "3.8", "3.9", "3.10"] steps: - uses: actions/checkout@v2 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 97940bb4..ec0f3904 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,20 +7,18 @@ repos: rev: 21.12b0 hooks: - id: black - language_version: python3.10 - repo: https://github.com/asottile/pyupgrade rev: v2.31.0 hooks: - id: pyupgrade - args: [--py36-plus] + args: [--py37-plus] - repo: https://github.com/PyCQA/isort rev: 5.10.1 hooks: - id: isort additional_dependencies: [toml] - language_version: python3.10 - repo: https://github.com/PyCQA/flake8 rev: 4.0.1 diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1ee209a4..b266e6e9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,7 +24,7 @@ Whenever there is a need to break compatibility, it is announced here in the cha Backward-incompatible changes: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -*none* +- Python 3.6 is not supported anymore. Deprecations: diff --git a/README.rst b/README.rst index 354cd667..cc71a3c9 100644 --- a/README.rst +++ b/README.rst @@ -51,7 +51,7 @@ Project Information We collect useful third-party extension in `our wiki `_. -``structlog`` targets Python 3.6 and later. +``structlog`` targets Python 3.7 and later. PyPy3 is known to work, but is not tested anymore. diff --git a/conftest.py b/conftest.py index a25ba8ef..d48e530e 100644 --- a/conftest.py +++ b/conftest.py @@ -4,7 +4,6 @@ # repository for complete details. import logging -import sys from io import StringIO @@ -69,7 +68,5 @@ def _cl(): collect_ignore = [] -if sys.version_info[:2] < (3, 7): - collect_ignore.append("tests/test_contextvars.py") if twisted is None: collect_ignore.append("tests/test_twisted.py") diff --git a/pyproject.toml b/pyproject.toml index e78a726c..30e1c478 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ build-backend = "flit_core.buildapi" name = "structlog" authors = [{name = "Hynek Schlawack", email = "hs@ox.cx"}] dynamic = ["version", "description"] -requires-python = ">=3.6" +requires-python = ">=3.7" dependencies = ["typing-extensions; python_version<'3.8'"] license = { file = "LICENSE" } keywords = ["logging", "structured", "structure", "log"] @@ -21,7 +21,6 @@ classifiers = [ "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", @@ -108,12 +107,11 @@ dev = [ [tool.pytest.ini_options] -addopts = "-ra --strict-markers " +addopts = "-ra --strict-markers" xfail_strict = true testpaths = "tests" filterwarnings = [ "once::Warning", - "ignore:.*are you using python -O.*:pytest.PytestConfigWarning", ] @@ -213,7 +211,7 @@ Project Information We collect useful third-party extension in `our wiki `_. -``structlog`` targets Python 3.6 and later. +``structlog`` targets Python 3.7 and later. PyPy3 is known to work, but is not tested anymore. diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 40e1d94d..6351fb48 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -7,7 +7,15 @@ Structured Logging for Python """ -from structlog import dev, processors, stdlib, testing, threadlocal, types +from structlog import ( + contextvars, + dev, + processors, + stdlib, + testing, + threadlocal, + types, +) from structlog._base import BoundLoggerBase, get_context from structlog._config import ( configure, @@ -36,11 +44,6 @@ except ImportError: twisted = None # type: ignore -try: - from structlog import contextvars -except ImportError: - contextvars = None # type: ignore - __version__ = "22.1.0.dev0" diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 7db47de8..c9f2d8d6 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -10,6 +10,7 @@ """ import asyncio +import contextvars import functools import logging import sys @@ -35,12 +36,6 @@ from .types import Context, EventDict, ExcInfo, Processor, WrappedLogger -try: - import contextvars -except ImportError: - contextvars = None # type: ignore - - __all__ = [ "add_log_level_number", "add_log_level", diff --git a/tox.ini b/tox.ini index 9e25962a..233d9942 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,6 @@ ignore = E203,W503,W504 # We don't run pre-commit in CI, because we use pre-commit.ci. [gh-actions] python = - 3.6: py36 3.7: py37 3.8: py38 3.9: py39, mypy @@ -13,7 +12,7 @@ python = [tox] -envlist = pre-commit,mypy,cogCheck,cog,{py36,py37,py38,py39,py310}-threads,py39-greenlets,py39-colorama,py310-be,py310-rich,docs,pypi-description,coverage-report +envlist = pre-commit,mypy,cogCheck,cog,{py37,py38,py39,py310}-threads,py39-greenlets,py39-colorama,py310-be,py310-rich,docs,pypi-description,coverage-report isolated_build = True @@ -77,12 +76,13 @@ setenv = commands = python -m pytest {posargs} -# For missing contextvars. -[testenv:py36-threads] +# For missing types +[testenv:py37-threads] deps = twisted setenv = PYTHONHASHSEED = 0 -commands = python -m coverage run -m pytest {posargs} +commands = + python -m coverage run -m pytest {posargs} [testenv:py310-threads] @@ -123,7 +123,7 @@ basepython = python3.10 deps = coverage[toml] skip_install = true parallel_show_output = true -depends = {py36,py310}-threads,py39-greenlets,py39-colorama,py310-be,py310-rich +depends = py37-threads,py310-threads,py39-greenlets,py39-colorama,py310-be,py310-rich commands = python -m coverage combine python -m coverage report From a77d9385695c2f29cc2d9bfec1cadf782174f324 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 26 Jan 2022 11:40:02 +0100 Subject: [PATCH 0660/1520] Fix pytest-asyncio warnings --- pyproject.toml | 5 +++-- tests/test_stdlib.py | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 30e1c478..d5a41382 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -64,7 +64,7 @@ tests = [ "coverage[toml]", "freezegun>=0.2.8", "pretend", - "pytest-asyncio", + "pytest-asyncio>=0.17", "pytest>=6.0", "simplejson", ] @@ -94,7 +94,7 @@ dev = [ "coverage[toml]", "freezegun>=0.2.8", "pretend", - "pytest-asyncio", + "pytest-asyncio>=0.17", "pytest>=6.0", "simplejson", "furo", @@ -113,6 +113,7 @@ testpaths = "tests" filterwarnings = [ "once::Warning", ] +asyncio_mode = "strict" [tool.coverage.run] diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index f639ff9c..4847b4d2 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -13,6 +13,7 @@ from typing import Any, Callable, Collection, Dict, Optional, Set import pytest +import pytest_asyncio from pretend import call_recorder, stub @@ -1026,7 +1027,7 @@ def test_remove_processors_meta(self): ) -@pytest.fixture(name="abl") +@pytest_asyncio.fixture(name="abl") async def _abl(cl): return AsyncBoundLogger(cl, context={}, processors=[]) From 60792bc8557907bfc817eae4621cc1b3a214fe0e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 29 Jan 2022 17:51:34 +0100 Subject: [PATCH 0661/1520] Add additional_ignores to StackInfoRenderer Fixes #396 --- CHANGELOG.rst | 2 ++ src/structlog/processors.py | 20 ++++++++++++++++---- tests/test_generic.py | 4 +--- tests/test_processors.py | 12 ++++++++++++ 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b266e6e9..1ef4c4ca 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -39,6 +39,8 @@ Changes: - Overloaded the ``bind``, ``unbind``, ``try_unbind`` and ``new`` methods in the ``FilteringBoundLogger`` `Protocol `_. This makes it easier to use objects of type ``FilteringBoundLogger`` in a typed context. `#392 `_ +- ``structlog.processors.StackInfoRenderer`` now has an *additional_ignores* parameter that allows you to filter out your own logging layer. + `#396 `_ ---- diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 6b3a1548..78c764d1 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -526,20 +526,32 @@ class StackInfoRenderer: Add stack information with key ``stack`` if ``stack_info`` is `True`. Useful when you want to attach a stack dump to a log entry without - involving an exception. + involving an exception and works analogously to the *stack_info* argument + of the Python standard library logging. - It works analogously to the *stack_info* argument of the Python 3 standard - library logging. + :param additional_ignores: By default, stack frames coming from + ``structlog`` are ignored. With this argument you can add additional + names that are ignored, before the stack starts being rendered. They + are matched using ``startswith()``, so they don't have to match + exactly. The names are used to find the first relevant name, therefore + once a frame is found that doesn't start with ``structlog`` or one of + *additional_ignores*, **no filtering** is applied to subsequent frames. .. versionadded:: 0.4.0 + .. versionadded:: 22.1.0 *additional_ignores* """ + __slots__ = ["_additional_ignores"] + + def __init__(self, additional_ignores: Optional[List[str]] = None) -> None: + self._additional_ignores = additional_ignores + def __call__( self, logger: WrappedLogger, name: str, event_dict: EventDict ) -> EventDict: if event_dict.pop("stack_info", None): event_dict["stack"] = _format_stack( - _find_first_app_frame_and_name()[0] + _find_first_app_frame_and_name(self._additional_ignores)[0] ) return event_dict diff --git a/tests/test_generic.py b/tests/test_generic.py index 2813de09..7f30ac77 100644 --- a/tests/test_generic.py +++ b/tests/test_generic.py @@ -51,12 +51,10 @@ def test_proxies_anything(self): assert "log", "foo" == b.log("foo") assert "gol", "bar" == b.gol("bar") - @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL + 1)) + @pytest.mark.parametrize("proto", range(3, pickle.HIGHEST_PROTOCOL + 1)) def test_pickle(self, proto): """ Can be pickled and unpickled. - - Works only on Python 3: TypeError: can't pickle instancemethod objects """ b = BoundLogger( ReturnLogger(), diff --git a/tests/test_processors.py b/tests/test_processors.py index e7c3d5b2..723f8479 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -708,6 +708,18 @@ def test_renders_correct_stack(self, sir): assert 'ed = sir(None, None, {"stack_info": True})' in ed["stack"] + def test_additional_ignores(self): + """ + Filtering of names works. + """ + sir = StackInfoRenderer(["tests.additional_frame"]) + + ed = additional_frame( + functools.partial(sir, None, None, {"stack_info": True}) + ) + + assert "additional_frame.py" not in ed["stack"] + class TestFigureOutExcInfo: @pytest.mark.parametrize("true_value", [True, 1, 1.1]) From 1346216e9a9145c6177e0bfd3b2fcd281502802a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 29 Jan 2022 17:52:50 +0100 Subject: [PATCH 0662/1520] Document that our Python 3-only package only supports Python 3 pickling --- CHANGELOG.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1ef4c4ca..87fb1e79 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -25,6 +25,7 @@ Backward-incompatible changes: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Python 3.6 is not supported anymore. +- Pickling is now only possible with protocol version 3 and newer. Deprecations: From 7e603edca75a2b5fb2bf83f1cbee6fde10ad971a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 7 Feb 2022 07:16:23 +0100 Subject: [PATCH 0663/1520] Ensure type hints pass on all Python versions --- tox.ini | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tox.ini b/tox.ini index 233d9942..0faa25a7 100644 --- a/tox.ini +++ b/tox.ini @@ -5,10 +5,10 @@ ignore = E203,W503,W504 # We don't run pre-commit in CI, because we use pre-commit.ci. [gh-actions] python = - 3.7: py37 - 3.8: py38 + 3.7: py37, mypy + 3.8: py38, mypy 3.9: py39, mypy - 3.10: py310, cogCheck, docs + 3.10: py310, mypy, cogCheck, docs [tox] @@ -39,7 +39,6 @@ commands = pre-commit run --all-files [testenv:mypy] description = Check types -basepython = python3.9 extras = tests # Need twisted & rich for stubs. # Otherwise mypy fails in tox. From 6a17bcfeb19d9dd3ecf5d7b9185ee7e5a4210045 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 7 Feb 2022 07:16:57 +0100 Subject: [PATCH 0664/1520] pre-commit autoupdate --- .pre-commit-config.yaml | 2 +- tests/test_twisted.py | 19 ++++++++----------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ec0f3904..d829c90c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/psf/black - rev: 21.12b0 + rev: 22.1.0 hooks: - id: black diff --git a/tests/test_twisted.py b/tests/test_twisted.py index 00775ff1..b171472f 100644 --- a/tests/test_twisted.py +++ b/tests/test_twisted.py @@ -77,18 +77,15 @@ def test_errWithFailure(self): except ValueError: # Use str() for comparison to avoid tricky # deep-compares of Failures. - assert ( - str( - ( - (), - { - "_stuff": Failure(ValueError()), - "_why": "foo=42 event='event'", - }, - ) + assert str( + ( + (), + { + "_stuff": Failure(ValueError()), + "_why": "foo=42 event='event'", + }, ) - == str(bl.err("event", foo=42)) - ) + ) == str(bl.err("event", foo=42)) class TestExtractStuffAndWhy: From b09d0528c4163c68ffe666716af9d5664e0aaae6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 7 Feb 2022 07:22:10 +0100 Subject: [PATCH 0665/1520] Don't fail fast --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f316d455..272d24f7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,6 +19,7 @@ jobs: name: tox on ${{ matrix.python-version }} runs-on: ubuntu-latest strategy: + fail-fast: false matrix: python-version: ["3.7", "3.8", "3.9", "3.10"] From 30736d643c64308d3d00953c22a8f3d1e4e39f1f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 7 Feb 2022 07:36:56 +0100 Subject: [PATCH 0666/1520] Exclude 3.7 from mypy --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 0faa25a7..c9776035 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,7 @@ ignore = E203,W503,W504 # We don't run pre-commit in CI, because we use pre-commit.ci. [gh-actions] python = - 3.7: py37, mypy + 3.7: py37 # mypy on 3.7 fails but there's nothing we can do about it 3.8: py38, mypy 3.9: py39, mypy 3.10: py310, mypy, cogCheck, docs From 41496ec16b3608706dcaa84a4cede11a3c47d65d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tin=20Tvrtkovi=C4=87?= Date: Fri, 11 Feb 2022 08:48:45 +0100 Subject: [PATCH 0667/1520] PrintLogger: switch to print (#399) * PrintLogger: switch to print * Add monkeypatching test --- src/structlog/_loggers.py | 23 +++++++++-------------- tests/test_loggers.py | 16 +++++++++++++++- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/structlog/_loggers.py b/src/structlog/_loggers.py index 1a6a448a..d1aebe9c 100644 --- a/src/structlog/_loggers.py +++ b/src/structlog/_loggers.py @@ -12,6 +12,7 @@ import threading from pickle import PicklingError +from sys import stderr, stdout from typing import IO, Any, BinaryIO, Dict, Optional, TextIO from structlog._utils import until_not_interrupted @@ -49,9 +50,7 @@ class PrintLogger: """ def __init__(self, file: Optional[TextIO] = None): - self._file = file or sys.stdout - self._write = self._file.write - self._flush = self._file.flush + self._file = file or stdout self._lock = _get_lock_for_file(self._file) @@ -59,10 +58,10 @@ def __getstate__(self) -> str: """ Our __getattr__ magic makes this necessary. """ - if self._file is sys.stdout: + if self._file is stdout: return "stdout" - elif self._file is sys.stderr: + elif self._file is stderr: return "stderr" raise PicklingError( @@ -74,19 +73,17 @@ def __setstate__(self, state: Any) -> None: Our __getattr__ magic makes this necessary. """ if state == "stdout": - self._file = sys.stdout + self._file = stdout else: - self._file = sys.stderr + self._file = stderr - self._write = self._file.write - self._flush = self._file.flush self._lock = _get_lock_for_file(self._file) def __deepcopy__(self, memodict: Dict[Any, Any] = {}) -> "PrintLogger": """ Create a new PrintLogger with the same attributes. Similar to pickling. """ - if self._file not in (sys.stdout, sys.stderr): + if self._file not in (stdout, stderr): raise copy.error( "Only PrintLoggers to sys.stdout and sys.stderr " "can be deepcopied." @@ -94,8 +91,6 @@ def __deepcopy__(self, memodict: Dict[Any, Any] = {}) -> "PrintLogger": newself = self.__class__(self._file) - newself._write = newself._file.write - newself._flush = newself._file.flush newself._lock = _get_lock_for_file(newself._file) return newself @@ -107,9 +102,9 @@ def msg(self, message: str) -> None: """ Print *message*. """ + f = self._file if self._file is not stdout else None with self._lock: - until_not_interrupted(self._write, message + "\n") - until_not_interrupted(self._flush) + until_not_interrupted(print, message, file=f, flush=True) log = debug = info = warn = warning = msg fatal = failure = err = error = critical = exception = msg diff --git a/tests/test_loggers.py b/tests/test_loggers.py index 52049801..d0a8dbb0 100644 --- a/tests/test_loggers.py +++ b/tests/test_loggers.py @@ -7,7 +7,7 @@ import pickle import sys -from io import BytesIO +from io import BytesIO, StringIO import pytest @@ -125,6 +125,20 @@ def test_deepcopy_no_stdout(self, tmp_path): assert "hello\n" == p.read_text() + def test_stdout_monkeypatch(self, monkeypatch, capsys): + """ + If stdout gets monkeypatched, the new instance receives the output. + """ + p = PrintLogger() + new_stdout = StringIO() + monkeypatch.setattr(sys, "stdout", new_stdout) + p.msg("hello") + + out, err = capsys.readouterr() + assert "hello\n" == new_stdout.getvalue() + assert "" == out + assert "" == err + class TestPrintLoggerFactory: def test_does_not_cache(self): From 09f4313ce374af2dad14a506c1a25d808e6f85a9 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 11 Feb 2022 08:56:31 +0100 Subject: [PATCH 0668/1520] Add changelogs for #399 --- CHANGELOG.rst | 2 ++ src/structlog/_loggers.py | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 87fb1e79..1d672ad3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -42,6 +42,8 @@ Changes: `#392 `_ - ``structlog.processors.StackInfoRenderer`` now has an *additional_ignores* parameter that allows you to filter out your own logging layer. `#396 `_ +- ``structlog.PrintLogger`` -- that is used by default -- now uses ``print()`` for printing, making it a better citizen for interactive terminal applications. + `#399 `_ ---- diff --git a/src/structlog/_loggers.py b/src/structlog/_loggers.py index d1aebe9c..1c5ab734 100644 --- a/src/structlog/_loggers.py +++ b/src/structlog/_loggers.py @@ -47,6 +47,10 @@ class PrintLogger: Also very useful for testing and examples since logging is finicky in doctests. + + .. versionchanged:: 22.1 + The implementation has been switched to use `print` for better + monkeypatchability. """ def __init__(self, file: Optional[TextIO] = None): From 5871e78d48600436289db90282a7a11976f835f6 Mon Sep 17 00:00:00 2001 From: Galen Rice Date: Thu, 10 Mar 2022 02:03:06 -0500 Subject: [PATCH 0669/1520] fix: use a noop with the same signature as the real one for make_filtering_bound_logger (#401) In my team's app, we're using `make_filtering_bound_logger`, which is working fine except in one corner case. Another developer introduced a bug that was missed in review and testing, and it only appears at runtime when the log level is DEBUG or below: log.debug(x=y) Obviously this is incorrect: there needs to be an `event` string in this call. However, the original `_nop` method that gets returned has no checks for this missing argument, so their (admittedly poor) testing didn't turn up a problem at this line. Later when running at DEBUG level to research a different issue, the entire app failed to start up because of this call alone. This change *should* operate identically, but returns a more explicit method with the same signature as the original. This should indicate to developers that even though the call is unused at higher log levels, it may still be incorrect; and that kind of error should not pass silently. --- CHANGELOG.rst | 3 +++ src/structlog/_log_levels.py | 2 +- tests/test_log_levels.py | 24 +++++++++++++++++++++++- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1d672ad3..0a21df76 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -26,6 +26,9 @@ Backward-incompatible changes: - Python 3.6 is not supported anymore. - Pickling is now only possible with protocol version 3 and newer. +- ``structlog.make_filtering_bound_logger()`` now returns a method with the same signature for all log levels, whether they are active or not. + This ensures that invalid calls to inactive log levels are caught immediately and don't explode once the log level changes. + `#401 `_ Deprecations: diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index 8eed9d0d..a4c98bcd 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -67,7 +67,7 @@ def add_log_level( return event_dict -def _nop(*args: Any, **kw: Any) -> Any: +def _nop(self: Any, event: str, **kw: Any) -> Any: return None diff --git a/tests/test_log_levels.py b/tests/test_log_levels.py index 607a3400..1c648e13 100644 --- a/tests/test_log_levels.py +++ b/tests/test_log_levels.py @@ -34,12 +34,34 @@ def test_exact_level(self, bl, cl): def test_one_below(self, bl, cl): """ - if log level is exactly the min_level, log. + if log level is below the min_level, don't log. """ bl.debug("nope") assert [] == cl.calls + def test_filter_bound_below_missing_event_string(self, bl, cl): + """ + Missing event arg causes exception below min_level. + """ + with pytest.raises(TypeError) as exc_info: + bl.debug(missing="event string!") + assert exc_info.type is TypeError + + message = "missing 1 required positional argument: 'event'" + assert message in exc_info.value.args[0] + + def test_filter_bound_exact_missing_event_string(self, bl, cl): + """ + Missing event arg causes exception even at min_level. + """ + with pytest.raises(TypeError) as exc_info: + bl.info(missing="event string!") + assert exc_info.type is TypeError + + message = "missing 1 required positional argument: 'event'" + assert message in exc_info.value.args[0] + def test_exception(self, bl, cl): """ exception ensures that exc_info is set to True, unless it's already From 506867be6076e17e3fafe6163b331117e934e748 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 14 Mar 2022 14:18:33 +0100 Subject: [PATCH 0670/1520] Admit wrong name --- src/structlog/stdlib.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index c9f2d8d6..34a257e5 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -523,7 +523,8 @@ class LoggerFactory: :param ignore_frame_names: When guessing the name of a logger, skip frames whose names *start* with one of these. For example, in pyramid applications you'll want to set it to - ``["venusian", "pyramid.config"]``. + ``["venusian", "pyramid.config"]``. This argument is + called *additional_ignores* in other APIs throughout `structlog`. """ def __init__(self, ignore_frame_names: Optional[List[str]] = None): From bdc6110b958dede434381da25100c4f80a0d54ca Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 14 Mar 2022 14:19:13 +0100 Subject: [PATCH 0671/1520] pre-commit autoupdate --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d829c90c..e5d6bb0c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: black - repo: https://github.com/asottile/pyupgrade - rev: v2.31.0 + rev: v2.31.1 hooks: - id: pyupgrade args: [--py37-plus] From e20ca64c0c35ea857dd084fa67c269bc823fbde1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tin=20Tvrtkovi=C4=87?= Date: Wed, 16 Mar 2022 12:30:23 +0100 Subject: [PATCH 0672/1520] Implement WriteLogger (#403) * Implement WriteLogger * Fix type hint * Rewrite tests to use fixtures * Refactor fixture * Add to changelog * PR tweaks * More tweaks * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Unused imports Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Hynek Schlawack --- CHANGELOG.rst | 2 + src/structlog/_loggers.py | 124 +++++++++++++++++++++++++++++++++++--- tests/test_loggers.py | 92 +++++++++++++++++++--------- 3 files changed, 182 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0a21df76..bb800a14 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -47,6 +47,8 @@ Changes: `#396 `_ - ``structlog.PrintLogger`` -- that is used by default -- now uses ``print()`` for printing, making it a better citizen for interactive terminal applications. `#399 `_ +- Added ``structlog.WriteLogger``, a faster but more low-level alternative to ``structlog.PrintLogger``. + `#403 `_ ---- diff --git a/src/structlog/_loggers.py b/src/structlog/_loggers.py index 1c5ab734..9fd80509 100644 --- a/src/structlog/_loggers.py +++ b/src/structlog/_loggers.py @@ -7,18 +7,20 @@ Logger wrapper and helper class. """ +from __future__ import annotations + import copy import sys import threading from pickle import PicklingError from sys import stderr, stdout -from typing import IO, Any, BinaryIO, Dict, Optional, TextIO +from typing import IO, Any, BinaryIO, TextIO from structlog._utils import until_not_interrupted -WRITE_LOCKS: Dict[IO[Any], threading.Lock] = {} +WRITE_LOCKS: dict[IO[Any], threading.Lock] = {} def _get_lock_for_file(file: IO[Any]) -> threading.Lock: @@ -53,7 +55,7 @@ class PrintLogger: monkeypatchability. """ - def __init__(self, file: Optional[TextIO] = None): + def __init__(self, file: TextIO | None = None): self._file = file or stdout self._lock = _get_lock_for_file(self._file) @@ -83,7 +85,7 @@ def __setstate__(self, state: Any) -> None: self._lock = _get_lock_for_file(self._file) - def __deepcopy__(self, memodict: Dict[Any, Any] = {}) -> "PrintLogger": + def __deepcopy__(self, memodict: dict[Any, Any] = {}) -> PrintLogger: """ Create a new PrintLogger with the same attributes. Similar to pickling. """ @@ -127,13 +129,119 @@ class PrintLoggerFactory: .. versionadded:: 0.4.0 """ - def __init__(self, file: Optional[TextIO] = None): + def __init__(self, file: TextIO | None = None): self._file = file def __call__(self, *args: Any) -> PrintLogger: return PrintLogger(self._file) +class WriteLogger: + """ + Write events into a file. + + :param file: File to print to. (default: `sys.stdout`) + + >>> from structlog import WriteLogger + >>> WriteLogger().msg("hello") + hello + + Useful if you follow + `current logging best practices `. + + Also very useful for testing and examples since logging is finicky in + doctests. + + A little faster and a little less versatile than the PrintLogger. + + .. versionadded:: 22.1 + """ + + def __init__(self, file: TextIO | None = None): + self._file = file or sys.stdout + self._write = self._file.write + self._flush = self._file.flush + + self._lock = _get_lock_for_file(self._file) + + def __getstate__(self) -> str: + """ + Our __getattr__ magic makes this necessary. + """ + if self._file is stdout: + return "stdout" + + elif self._file is stderr: + return "stderr" + + raise PicklingError( + "Only WriteLoggers to sys.stdout and sys.stderr can be pickled." + ) + + def __setstate__(self, state: Any) -> None: + """ + Our __getattr__ magic makes this necessary. + """ + if state == "stdout": + self._file = stdout + else: + self._file = stderr + + self._lock = _get_lock_for_file(self._file) + + def __deepcopy__(self, memodict: dict[Any, Any] = {}) -> WriteLogger: + """ + Create a new WriteLogger with the same attributes. Similar to pickling. + """ + if self._file not in (sys.stdout, sys.stderr): + raise copy.error( + "Only WriteLoggers to sys.stdout and sys.stderr " + "can be deepcopied." + ) + + newself = self.__class__(self._file) + + newself._write = newself._file.write + newself._flush = newself._file.flush + newself._lock = _get_lock_for_file(newself._file) + + return newself + + def __repr__(self) -> str: + return f"" + + def msg(self, message: str) -> None: + """ + Write and flush *message*. + """ + with self._lock: + until_not_interrupted(self._write, message + "\n") + until_not_interrupted(self._flush) + + log = debug = info = warn = warning = msg + fatal = failure = err = error = critical = exception = msg + + +class WriteLoggerFactory: + r""" + Produce `WriteLogger`\ s. + + To be used with `structlog.configure`\ 's ``logger_factory``. + + :param file: File to print to. (default: `sys.stdout`) + + Positional arguments are silently ignored. + + .. versionadded:: 22.1 + """ + + def __init__(self, file: TextIO | None = None): + self._file = file + + def __call__(self, *args: Any) -> WriteLogger: + return WriteLogger(self._file) + + class BytesLogger: r""" Writes bytes into a file. @@ -149,7 +257,7 @@ class BytesLogger: """ __slots__ = ("_file", "_write", "_flush", "_lock") - def __init__(self, file: Optional[BinaryIO] = None): + def __init__(self, file: BinaryIO | None = None): self._file = file or sys.stdout.buffer self._write = self._file.write self._flush = self._file.flush @@ -183,7 +291,7 @@ def __setstate__(self, state: Any) -> None: self._flush = self._file.flush self._lock = _get_lock_for_file(self._file) - def __deepcopy__(self, memodict: Dict[Any, Any] = {}) -> "BytesLogger": + def __deepcopy__(self, memodict: dict[Any, Any] = {}) -> BytesLogger: """ Create a new BytesLogger with the same attributes. Similar to pickling. """ @@ -230,7 +338,7 @@ class BytesLoggerFactory: """ __slots__ = ("_file",) - def __init__(self, file: Optional[BinaryIO] = None): + def __init__(self, file: BinaryIO | None = None): self._file = file def __call__(self, *args: Any) -> BytesLogger: diff --git a/tests/test_loggers.py b/tests/test_loggers.py index d0a8dbb0..de5b1d52 100644 --- a/tests/test_loggers.py +++ b/tests/test_loggers.py @@ -17,70 +17,75 @@ BytesLoggerFactory, PrintLogger, PrintLoggerFactory, + WriteLogger, + WriteLoggerFactory, ) from .utils import stdlib_log_methods -class TestPrintLogger: - def test_prints_to_stdout_by_default(self, capsys): +class TestLoggers: + """ + Tests common to the Print and WriteLoggers. + """ + + @pytest.fixture(name="logger_cls", params=(WriteLogger, PrintLogger)) + @staticmethod + def _logger_cls(request): + return request.param + + def test_prints_to_stdout_by_default(self, logger_cls, capsys): """ Instantiating without arguments gives conveniently a logger to standard out. """ - PrintLogger().msg("hello") + logger_cls().msg("hello") out, err = capsys.readouterr() assert "hello\n" == out assert "" == err - def test_prints_to_correct_file(self, tmpdir, capsys): + def test_prints_to_correct_file(self, logger_cls, tmpdir, capsys): """ Supplied files are respected. """ f = tmpdir.join("test.log") fo = f.open("w") - PrintLogger(fo).msg("hello") + logger_cls(fo).msg("hello") out, err = capsys.readouterr() assert "" == out == err fo.close() assert "hello\n" == f.read() - def test_repr(self): - """ - __repr__ makes sense. - """ - assert repr(PrintLogger()).startswith(" Date: Wed, 16 Mar 2022 12:35:51 +0100 Subject: [PATCH 0673/1520] Finish up WriteLogger integration --- CHANGELOG.rst | 3 ++- docs/api.rst | 5 +++++ docs/performance.rst | 2 +- src/structlog/__init__.py | 18 +++++++++++------- tests/test_loggers.py | 4 ++-- 5 files changed, 21 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index bb800a14..a858dd49 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -47,7 +47,8 @@ Changes: `#396 `_ - ``structlog.PrintLogger`` -- that is used by default -- now uses ``print()`` for printing, making it a better citizen for interactive terminal applications. `#399 `_ -- Added ``structlog.WriteLogger``, a faster but more low-level alternative to ``structlog.PrintLogger``. +- Added ``structlog.WriteLogger``, a faster -- but more low-level -- alternative to ``structlog.PrintLogger``. + It works the way ``PrintLogger`` used to work in previous versions. `#403 `_ diff --git a/docs/api.rst b/docs/api.rst index 5c07f306..3c4482da 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -54,6 +54,11 @@ API Reference .. autoclass:: PrintLoggerFactory +.. autoclass:: WriteLogger + :members: msg, err, debug, info, warning, error, critical, log, failure, fatal + +.. autoclass:: WriteLoggerFactory + .. autoclass:: BytesLogger :members: msg, err, debug, info, warning, error, critical, log, failure, fatal diff --git a/docs/performance.rst b/docs/performance.rst index 5657a57b..87c05d43 100644 --- a/docs/performance.rst +++ b/docs/performance.rst @@ -40,7 +40,7 @@ Here are a few hints how to get most out of ``structlog`` in production: Therefore, you can't set this option if you e.g. plan on passing loggers around using `multiprocessing`. #. Avoid sending your log entries through the standard library if you can: its dynamic nature and flexibility make it a major bottleneck. - Instead use `structlog.PrintLoggerFactory` or -- if your serializer returns bytes (e.g. orjson_) -- `structlog.BytesLoggerFactory`. + Instead use `structlog.WriteLoggerFactory` or -- if your serializer returns bytes (e.g. orjson_) -- `structlog.BytesLoggerFactory`. You can still configure `logging` for packages that you don't control, but avoid it for your *own* log entries. diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 6351fb48..0b0a0813 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -34,6 +34,8 @@ BytesLoggerFactory, PrintLogger, PrintLoggerFactory, + WriteLogger, + WriteLoggerFactory, ) from structlog.exceptions import DropEvent from structlog.testing import ReturnLogger, ReturnLoggerFactory @@ -65,27 +67,29 @@ "BoundLoggerBase", "BytesLogger", "BytesLoggerFactory", - "DropEvent", - "PrintLogger", - "PrintLoggerFactory", - "ReturnLogger", - "ReturnLoggerFactory", - "configure", "configure_once", + "configure", "contextvars", "dev", - "getLogger", + "DropEvent", "get_config", "get_context", "get_logger", + "getLogger", "is_configured", "make_filtering_bound_logger", + "PrintLogger", + "PrintLoggerFactory", "processors", "reset_defaults", + "ReturnLogger", + "ReturnLoggerFactory", "stdlib", "testing", "threadlocal", "twisted", "types", "wrap_logger", + "WriteLogger", + "WriteLoggerFactory", ] diff --git a/tests/test_loggers.py b/tests/test_loggers.py index de5b1d52..348000e6 100644 --- a/tests/test_loggers.py +++ b/tests/test_loggers.py @@ -11,8 +11,7 @@ import pytest -from structlog._loggers import ( - WRITE_LOCKS, +from structlog import ( BytesLogger, BytesLoggerFactory, PrintLogger, @@ -20,6 +19,7 @@ WriteLogger, WriteLoggerFactory, ) +from structlog._loggers import WRITE_LOCKS from .utils import stdlib_log_methods From d816d23bb7c65bf51cd7640f2ff38dd41e16a838 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 17 Mar 2022 14:12:05 +0100 Subject: [PATCH 0674/1520] Bump actions to v3 --- .github/workflows/main.yml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 272d24f7..02664cad 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -24,8 +24,8 @@ jobs: python-version: ["3.7", "3.8", "3.9", "3.10"] steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-python@v3 with: python-version: ${{ matrix.python-version }} @@ -39,7 +39,7 @@ jobs: - run: python -m tox - name: Upload coverage data - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: coverage-data path: .coverage.* @@ -52,15 +52,15 @@ jobs: needs: tests steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-python@v3 with: # Use latest Python, so it understands all syntax. python-version: ${{env.PYTHON_LATEST}} - run: python -m pip install --upgrade coverage[toml] - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v3 with: name: coverage-data @@ -71,7 +71,7 @@ jobs: python -m coverage report --fail-under=100 - name: Upload HTML report if check failed. - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: html-report path: htmlcov @@ -83,8 +83,8 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-python@v3 with: python-version: ${{env.PYTHON_LATEST}} @@ -104,8 +104,8 @@ jobs: os: [ubuntu-latest, windows-latest] steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-python@v3 with: python-version: ${{env.PYTHON_LATEST}} - run: python -m pip install -e .[dev] From a60d829593b1ae1ba77fe8b1aa6ba3d7fd017fb0 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 22 Mar 2022 06:08:36 +0100 Subject: [PATCH 0675/1520] Add changelog entry for #404 --- CHANGELOG.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a858dd49..5bbc038b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -50,6 +50,8 @@ Changes: - Added ``structlog.WriteLogger``, a faster -- but more low-level -- alternative to ``structlog.PrintLogger``. It works the way ``PrintLogger`` used to work in previous versions. `#403 `_ +- Added better support for monkeypatched ``sys.stdout``\ s. + `#404 `_ ---- From 87f9dec5078c50b2fc75753c67be868b53ec2bf9 Mon Sep 17 00:00:00 2001 From: Brad Beattie <79596181+bbeattie-phxlabs@users.noreply.github.com> Date: Tue, 22 Mar 2022 01:06:42 -0400 Subject: [PATCH 0676/1520] Handle monkey-patched stdout (#404) * Handle monkey-patched stdout In some Python environments (e.g. Maya 2022's mayapy.exe), sys.stdout has been monkey-patched to something other than the expected stdout. As such, it doesn't actually have an `isatty` method and raises an AttributeError in response. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- src/structlog/_config.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 536494b1..2f072c72 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -40,7 +40,10 @@ set_exc_info, TimeStamper(fmt="%Y-%m-%d %H:%M.%S", utc=False), ConsoleRenderer( - colors=_use_colors and sys.stdout is not None and sys.stdout.isatty() + colors=_use_colors + and sys.stdout is not None + and hasattr(sys.stdout, "isatty") + and sys.stdout.isatty() ), ] _BUILTIN_DEFAULT_CONTEXT_CLASS = cast(Type[Context], dict) From 1c468cfed639f2ef4cb294b141a222f721ee4bbd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 2 Apr 2022 14:50:36 +0200 Subject: [PATCH 0677/1520] Move mypy config into pyproject.toml --- mypy.ini | 28 ---------------------------- pyproject.toml | 19 +++++++++++++++++++ src/structlog/dev.py | 2 +- 3 files changed, 20 insertions(+), 29 deletions(-) delete mode 100644 mypy.ini diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index ea371b92..00000000 --- a/mypy.ini +++ /dev/null @@ -1,28 +0,0 @@ -[mypy] -# show error messages from unrelated files -follow_imports = normal - -# suppress errors about unsatisfied imports -ignore_missing_imports = True - -# be strict -check_untyped_defs = True -disallow_any_generics = True -disallow_incomplete_defs = True -disallow_untyped_calls = True -disallow_untyped_defs = True -no_implicit_optional = True -strict_optional = True -warn_no_return = True -warn_redundant_casts = True -warn_unreachable = True -warn_unused_ignores = True - -# sometimes redefinition is just fine -allow_redefinition = True - -[mypy-tests.*] -ignore_errors = True - -[mypy-conftest] -ignore_errors = True diff --git a/pyproject.toml b/pyproject.toml index d5a41382..f4f6c3e7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -153,6 +153,25 @@ line-length = 79 profile = "attrs" +[tool.mypy] +warn_unused_ignores = true +follow_imports = "normal" +ignore_missing_imports = true +disallow_untyped_calls = true +warn_no_return = true +warn_redundant_casts = true +disallow_untyped_defs = true +check_untyped_defs = true + +[[tool.mypy.overrides]] +module = "tests.*" +ignore_errors = true + +[[tool.mypy.overrides]] +module = "conftest.*" +ignore_errors = true + + [project.readme] content-type = "text/x-rst" diff --git a/src/structlog/dev.py b/src/structlog/dev.py index b5da0016..7f932924 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -202,7 +202,7 @@ def better_traceback(sio: TextIO, exc_info: ExcInfo) -> None: if rich is not None: default_exception_formatter = rich_traceback -elif better_exceptions is not None: # type: ignore +elif better_exceptions is not None: default_exception_formatter = better_traceback else: default_exception_formatter = plain_traceback From cebea7997e8adca7b1a32509a26497841b9c1f2c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 3 Apr 2022 13:02:43 +0200 Subject: [PATCH 0678/1520] Move changelog to Markdown and Keep a Changelog --- .github/CONTRIBUTING.md | 27 +- .github/PULL_REQUEST_TEMPLATE.md | 2 +- CHANGELOG.md | 659 ++++++++++++++++++++++++ CHANGELOG.rst | 838 ------------------------------- docs/changelog.md | 2 + docs/changelog.rst | 1 - docs/conf.py | 1 + pyproject.toml | 2 + 8 files changed, 682 insertions(+), 850 deletions(-) create mode 100644 CHANGELOG.md delete mode 100644 CHANGELOG.rst create mode 100644 docs/changelog.md delete mode 100644 docs/changelog.rst diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 8dd49d0f..1c92aeeb 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -72,7 +72,7 @@ Please report any harm to [Hynek Schlawack] in any way you find appropriate. ## Documentation -- Use [semantic newlines] in [*reStructuredText*] files (files ending in `.rst`): +- Use [semantic newlines] in [*reStructuredText*] and *Markdown* files (files ending in `.rst` and `.md`): ```rst This is a sentence. @@ -97,10 +97,15 @@ Please report any harm to [Hynek Schlawack] in any way you find appropriate. ### Changelog -If your change is noteworthy, there needs to be a changelog entry in `CHANGELOG.rst` so our users can learn about it! +If your change is noteworthy, there needs to be a changelog entry in [`CHANGELOG.md`](https://github.com/hynek/structlog/blob/main/CHANGELOG.md), so our users can learn about it! +- The changelog follows the [*Keep a Changelog*](https://keepachangelog.com/en/1.0.0/) standard. + Please add the best-fitting section if it's missing for the current release. + We use the following order: `Security`, `Removed`, `Deprecated`, `Added`, `Changed`, `Fixed`. - As with other docs, please use [semantic newlines] in the changelog. -- Wrap symbols like modules, functions, or classes into double backticks so they are rendered in a `monospace font`. +- Make the last line a link to your pull request. + You probably have to open it first to know the number. +- Wrap symbols like modules, functions, or classes into backticks so they are rendered in a `monospace font`. - Wrap arguments into asterisks like in docstrings: `Added new argument *an_argument*.` - If you mention functions or other callables, add parentheses at the end of their names: @@ -112,18 +117,20 @@ If your change is noteworthy, there needs to be a changelog entry in `CHANGELOG. * Added `structlog.func()`. * `structlog.func()` now doesn't crash the Large Hadron Collider anymore when passed the *foobar* argument. -Example entries: +#### Example entries -```rst -Added ``structlog.func()``. -The feature really *is* awesome. +```markdown +- Added `structlog.func()`. + The feature really *is* awesome. + [#1](https://github.com/hynek/structlog/pull/1) ``` or: -```rst -``structlog.func()`` now doesn't crash the Large Hadron Collider anymore when passed the *foobar* argument. -The bug really *was* nasty. +```markdown +- `structlog.func()` now doesn't crash the Large Hadron Collider anymore when passed the *foobar* argument. + The bug really *was* nasty. + [#1](https://github.com/hynek/structlog/pull/1) ``` diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index fd5f87bb..ec7e8c0e 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -21,7 +21,7 @@ If an item doesn't apply to your pull request, **check it anyway** to make it ap - [ ] Changed/added classes/methods/functions have appropriate `versionadded`, `versionchanged`, or `deprecated` [directives](http://www.sphinx-doc.org/en/stable/markup/para.html#directive-versionadded). Find the appropriate next version in our [`__init__.py`](https://github.com/hynek/structlog/blob/main/src/structlog/__init__.py) file. - [ ] Documentation in `.rst` and `.md` files is written using [**semantic newlines**](https://rhodesmill.org/brandon/2012/one-sentence-per-line/). -- [ ] Changes (and possible deprecations) are documented in the [**changelog**](https://github.com/hynek/structlog/blob/main/CHANGELOG.rst). +- [ ] Changes (and possible deprecations) are documented in the [**changelog**](https://github.com/hynek/structlog/blob/main/CHANGELOG.md). - [ ] Consider granting [push permissions to the PR branch](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork), so maintainers can fix minor issues themselves without pestering you. + +## [Unreleased](https://github.com/hynek/structlog/compare/21.5.0...HEAD) + +### Removed + +- Python 3.6 is not supported anymore. +- Pickling is now only possible with protocol version 3 and newer. + + +### Added + +- `structlog.processors.StackInfoRenderer` now has an *additional_ignores* parameter that allows you to filter out your own logging layer. + [#396](https://github.com/hynek/structlog/issues/396) +- Added `structlog.WriteLogger`, a faster -- but more low-level -- alternative to `structlog.PrintLogger`. + It works the way `PrintLogger` used to work in previous versions. + [#403](https://github.com/hynek/structlog/pull/403) + [#404](https://github.com/hynek/structlog/pull/404) + + +### Changed + +- `structlog.make_filtering_bound_logger()` now returns a method with the same signature for all log levels, whether they are active or not. + This ensures that invalid calls to inactive log levels are caught immediately and don't explode once the log level changes. + [#401](https://github.com/hynek/structlog/pull/401) +- `structlog.PrintLogger` -- that is used by default -- now uses `print()` for printing, making it a better citizen for interactive terminal applications. + [#399](https://github.com/hynek/structlog/pull/399) + + +### Fixed + +- Overloaded the `bind`, `unbind`, `try_unbind` and `new` methods in the `FilteringBoundLogger` [Protocol](https://docs.python.org/3/library/typing.html#typing.Protocol). + This makes it easier to use objects of type `FilteringBoundLogger` in a typed context. + [#392](https://github.com/hynek/structlog/pull/392) +- Monkeypatched `sys.stdout`s are now handled more gracefully. + [#404](https://github.com/hynek/structlog/pull/404) + + +## [21.5.0](https://github.com/hynek/structlog/compare/21.4.0...21.5.0) - 2021-12-16 + +### Added + +- Added the `structlog.processors.LogfmtRenderer` processor to render log lines using the [*logfmt*](https://brandur.org/logfmt) format. + [#376](https://github.com/hynek/structlog/pull/376) +- Added the `structlog.stdlib.ExtraAdder` processor that adds extra attributes of `logging.LogRecord` objects to the event dictionary. + This processor can be used for adding data passed in the `extra` parameter of the `logging` module's log methods to the event dictionary. + [#209](https://github.com/hynek/structlog/pull/209), + [#377](https://github.com/hynek/structlog/pull/377) +- Added the `structlog.processor.CallsiteParameterAdder` processor that adds parameters of the callsite that an event dictionary originated from to the event dictionary. + This processor can be used to enrich events dictionaries with information such as the function name, line number and filename that an event dictionary originated from. + [#380](https://github.com/hynek/structlog/pull/380) + + +## [21.4.0](https://github.com/hynek/structlog/compare/21.3.0...21.4.0) - 2021-11-25 + +### Added + +- Added the `structlog.threadlocal.bound_threadlocal` and `structlog.contextvars.bound_contextvars` decorator/context managers to temporarily bind key/value pairs to a thread-local and context-local context. + [#371](https://github.com/hynek/structlog/pull/371) + + +### Fixed + +- Fixed import when running in optimized mode (`PYTHONOPTIMIZE=2` or `python -OO`) +. + [#373](https://github.com/hynek/structlog/pull/373) + + +## [21.3.0](https://github.com/hynek/structlog/compare/21.2.0...21.3.0) - 2021-11-20 + +### Added + +- `structlog.dev.ConsoleRenderer` now has `sort_keys` boolean parameter that allows to disable the sorting of keys on output. + [#358](https://github.com/hynek/structlog/pull/358) + + +### Changed + +- `structlog` switched its packaging to [*flit*](https://flit.readthedocs.io/). Users shouldn't notice a difference, but (re-)packagers might. +- `structlog.stdlib.AsyncBoundLogger` now determines the running loop when logging, not on instantiation. + That has a minor performance impact, but makes it more robust when loops change (e.g. `aiohttp.web.run_app()`), or you want to use `sync_bl` *before* a loop has started. + + +### Fixed + +- `structlog.processors.TimeStamper` now works well with [*FreezeGun*](https://github.com/spulec/freezegun) even when it gets applied before the loggers are configured. + [#364](https://github.com/hynek/structlog/pull/364) + +- `structlog.stdlib.ProcessorFormatter` now has a *processors* argument that allows to define a processor chain to run over *all* log entries. + + Before running the chain, two additional keys are added to the event dictionary: `_record` and `_from_structlog`. + With them it's possible to extract information from `logging.LogRecord`s and differentiate between `structlog` and `logging` log entries while processing them. + + The old *processor* (singular) parameter is now deprecated, but no plans exist to remove it. + [#365](https://github.com/hynek/structlog/pull/365) + + +## [21.2.0](https://github.com/hynek/structlog/compare/21.1.0...21.2.0) - 2021-10-12 + +### Added + +- `structlog.threadlocal.get_threadlocal()` and `structlog.contextvars.get_contextvars()` can now be used to get a copy of the current thread-local/context-local context that has been bound using `structlog.threadlocal.bind_threadlocal()` and `structlog.contextvars.bind_contextvars()`. + [#331](https://github.com/hynek/structlog/pull/331), + [#337](https://github.com/hynek/structlog/pull/337) +- `structlog.threadlocal.get_merged_threadlocal(bl)` and `structlog.contextvars.get_merged_contextvars(bl)` do the same, but also merge the context from a bound logger *bl*. + Same pull requests as previous change. +- `structlog.contextvars.bind_contextvars()` now returns a mapping of keys to `contextvars.Token`s, allowing you to reset values using the new `structlog.contextvars.reset_contextvars()`. + [#339](https://github.com/hynek/structlog/pull/339) +- Exception rendering in `structlog.dev.ConsoleLogger` is now configurable using the `exception_formatter` setting. + If either the [*rich*](https://github.com/willmcgugan/rich) or the [*better-exceptions*](https://github.com/qix-/better-exceptions) package is present, `structlog` will use them for pretty-printing tracebacks. + *rich* takes precedence over *better-exceptions* if both are present. + + This only works if `format_exc_info` is **absent** in the processor chain. + [#330](https://github.com/hynek/structlog/pull/330), + [#349](https://github.com/hynek/structlog/pull/349) +- The final processor can now return a `bytearray` (additionally to `str` and `bytes`). + [#344](https://github.com/hynek/structlog/issues/344) + + +### Changed + +- To implement pretty exceptions (see Changes below), `structlog.dev.ConsoleRenderer` now formats exceptions itself. + + Make sure to remove `format_exc_info` from your processor chain if you configure `structlog` manually. + This change is not really breaking, because the old use-case will keep working as before. + However if you pass `pretty_exceptions=True` (which is the default if either `rich` or `better-exceptions` is installed), a warning will be raised and the exception will be rendered without prettification. +- All use of [*colorama*](https://github.com/tartley/colorama) on non-Windows systems has been excised. + Thus, colors are now enabled by default in `structlog.dev.ConsoleRenderer` on non-Windows systems. + You can keep using *colorama* to customize colors, of course. + [#345](https://github.com/hynek/structlog/pull/345) + + +### Fixed + +- `structlog` is now importable if `sys.stdout` is `None` (e.g. when running using `pythonw`). [#313](https://github.com/hynek/structlog/issues/313) + + +## [21.1.0](https://github.com/hynek/structlog/compare/20.2.0...21.1.0) - 2021-02-18 + +### Changed + +- `structlog.dev.ConsoleRenderer` will now look for a `logger_name` key if no `logger` key is set. + [#295](https://github.com/hynek/structlog/pull/295) + + +### Fixed + +- `structlog.threadlocal.wrap_dict()` now has a correct type annotation. + [#290](https://github.com/hynek/structlog/pull/290) +- Fix isolation in `structlog.contextvars`. + [#302](https://github.com/hynek/structlog/pull/302) +- The default configuration and loggers are pickleable again. + [#301](https://github.com/hynek/structlog/pull/301) + + +## [20.2.0](https://github.com/hynek/structlog/compare/20.1.0...20.2.0) - 2020-12-31 + +### Removed + +- Python 2.7 and 3.5 aren't supported anymore. + The package meta data should ensure that you keep getting 20.1.0 on those versions. + [#244](https://github.com/hynek/structlog/pull/244) + + +### Deprecated + +- Accessing the `_context` attribute of a bound logger is now deprecated. + Please use the new `structlog.get_context()`. + + +### Added + +- `structlog` has now type hints for all of its APIs! + Since `structlog` is highly dynamic and configurable, this led to a few concessions like a specialized `structlog.stdlib.get_logger()` whose only difference to `structlog.get_logger()` is that it has the correct type hints. + + We consider them provisional for the time being – i.e. the backwards-compatibility does not apply to them in its full strength until we feel we got it right. + Please feel free to provide feedback! + [#223](https://github.com/hynek/structlog/issues/223), + [#282](https://github.com/hynek/structlog/issues/282) +- Added `structlog.make_filtering_logger` that can be used like `configure(wrapper_class=make_filtering_bound_logger(logging.INFO))`. + It creates a highly optimized bound logger whose inactive methods only consist of a `return None`. + This is now also the default logger. +- As a complement, `structlog.stdlib.add_log_level()` can now additionally be imported as `structlog.processors.add_log_level` since it just adds the method name to the event dict. +- Added `structlog.BytesLogger` to avoid unnecessary encoding round trips. + Concretely this is useful with *orjson* which returns bytes. + [#271](https://github.com/hynek/structlog/issues/271) +- The final processor now also may return bytes that are passed untouched to the wrapped logger. +- `structlog.get_context()` allows you to retrieve the original context of a bound logger. [#266](https://github.com/hynek/structlog/issues/266), +- Added `structlog.testing.CapturingLogger` for more unit testing goodness. +- Added `structlog.stdlib.AsyncBoundLogger` that executes logging calls in a thread executor and therefore doesn't block. + [#245](https://github.com/hynek/structlog/pull/245) + + +### Changed + +- The default bound logger (`wrapper_class`) if you don't configure `structlog` has changed. + It's mostly compatible with the old one but a few uncommon methods like `log`, `failure`, or `err` don't exist anymore. + + You can regain the old behavior by using `structlog.configure(wrapper_class=structlog.BoundLogger)`. + + Please note that due to the various interactions between settings, it's possible that you encounter even more errors. + We **strongly** urge you to always configure all possible settings since the default configuration is *not* covered by our backwards-compatibility policy. +- `structlog.processors.add_log_level()` is now part of the default configuration. +- `structlog.stdlib.ProcessorFormatter` no longer uses exceptions for control flow, allowing `foreign_pre_chain` processors to use `sys.exc_info()` to access the real exception. + + +### Fixed + +- `structlog.PrintLogger` now supports `copy.deepcopy()`. + [#268](https://github.com/hynek/structlog/issues/268) + + +## [20.1.0](https://github.com/hynek/structlog/compare/19.2.0...20.1.0) - 2020-01-28 + +### Deprecated + +- This is the last version to support Python 2.7 (including PyPy) and 3.5. + All following versions will only support Python 3.6 or later. + + +### Added + +- Added a new module `structlog.contextvars` that allows to have a global but context-local `structlog` context the same way as with `structlog.threadlocal` since 19.2.0. + [#201](https://github.com/hynek/structlog/issues/201), + [#236](https://github.com/hynek/structlog/pull/236) +- Added a new module `structlog.testing` for first class testing support. + The first entry is the context manager `capture_logs()` that allows to make assertions about structured log calls. + [#14](https://github.com/hynek/structlog/issues/14), + [#234](https://github.com/hynek/structlog/pull/234) +- Added `structlog.threadlocal.unbind_threadlocal()`. + [#239](https://github.com/hynek/structlog/pull/239) + + +### Fixed + +- The logger created by `structlog.get_logger()` is not detected as an abstract method anymore, when attached to an abstract base class. + [#229](https://github.com/hynek/structlog/issues/229) +- *colorama* isn't initialized lazily on Windows anymore because it breaks rendering. + [#232](https://github.com/hynek/structlog/issues/232), + [#242](https://github.com/hynek/structlog/pull/242) + + +## [19.2.0](https://github.com/hynek/structlog/compare/19.1.0...19.2.0) - 2019-10-16 + +### Removed + +- Python 3.4 is not supported anymore. +It has been unsupported by the Python core team for a while now and its PyPI downloads are negligible. + + It's very unlikely that `structlog` will break under 3.4 anytime soon, but we don't test it anymore. + + +### Added + +- Full Python 3.8 support for `structlog.stdlib`. +- Added more pass-through properties to `structlog.stdlib.BoundLogger`. To makes it easier to use it as a drop-in replacement for `logging.Logger`. + [#198](https://github.com/hynek/structlog/issues/198) +- Added new processor `structlog.dev.set_exc_info()` that will set `exc_info=True` if the method's name is `exception` and `exc_info` isn't set at all. + *This is only necessary when the standard library integration is not used*. + It fixes the problem that in the default configuration, `structlog.get_logger().exception("hi")` in an `except` block would not print the exception without passing `exc_info=True` to it explicitly. + [#130](https://github.com/hynek/structlog/issues/130), + [#173](https://github.com/hynek/structlog/issues/173), + [#200](https://github.com/hynek/structlog/issues/200), + [#204](https://github.com/hynek/structlog/issues/204) +- Added a new thread-local API that allows binding values to a thread-local context explicitly without affecting the default behavior of `bind()`. + [#222](https://github.com/hynek/structlog/issues/222), + [#225](https://github.com/hynek/structlog/issues/225) +- Added *pass_foreign_args* argument to `structlog.stdlib.ProcessorFormatter`. It allows to pass a foreign log record's *args* attribute to the event dictionary under the `positional_args` key. + [#228](https://github.com/hynek/structlog/issues/228) + + + +### Changed + +- `structlog.stdlib.ProcessorFormatter` now takes a logger object as an optional keyword argument. + This makes `ProcessorFormatter` work properly with `stuctlog.stdlib.filter_by_level()`. + [#219](https://github.com/hynek/structlog/issues/219) +- `structlog.dev.ConsoleRenderer` now calls `str()` on the event value. [#221](https://github.com/hynek/structlog/issues/221) + + +### Fixed + +- `structlog.dev.ConsoleRenderer` now uses no colors by default, if *colorama* is not available. + [#215](https://github.com/hynek/structlog/issues/215) +- `structlog.dev.ConsoleRenderer` now initializes *colorama* lazily, to prevent accidental side-effects just by importing `structlog`. + [#210](https://github.com/hynek/structlog/issues/210) +- A best effort has been made to make as much of `structlog` pickleable as possible to make it friendlier with `multiprocessing` and similar libraries. + Some classes can only be pickled on Python 3 or using the [dill](https://pypi.org/project/dill/) library though and that is very unlikely to change. + + So far, the configuration proxy, `structlog.processor.TimeStamper`, `structlog.BoundLogger`, `structlog.PrintLogger` and `structlog.dev.ConsoleRenderer` have been made pickleable. + Please report if you need any another class fixed. + [#126](https://github.com/hynek/structlog/issues/126) + + +## [19.1.0](https://github.com/hynek/structlog/compare/18.2.0...19.1.0) - 2019-02-02 + +### Added + +- `structlog.ReturnLogger` and `structlog.PrintLogger` now have a `fatal()` log method. + [#181](https://github.com/hynek/structlog/issues/181) + + +### Changed + +- As announced in 18.1.0, `pip install -e .[dev]` now installs all development dependencies. + Sorry for the inconveniences this undoubtedly will cause! +- `structlog` now tolerates passing through `dict`s to stdlib logging. + [#187](https://github.com/hynek/structlog/issues/187), + [#188](https://github.com/hynek/structlog/pull/188), + [#189](https://github.com/hynek/structlog/pull/189) + + +### Fixed + +- Under certain (rather unclear) circumstances, the frame extraction could throw an `SystemError: error return without exception set`. + A workaround has been added. + [#174](https://github.com/hynek/structlog/issues/174) + + +## [18.2.0](https://github.com/hynek/structlog/compare/18.1.0...18.2.0) - 2018-09-05 + +### Added + +- Added `structlog.stdlib.add_log_level_number()` processor that adds the level *number* to the event dictionary. + Can be used to simplify log filtering. + [#151](https://github.com/hynek/structlog/pull/151) +- `structlog.processors.JSONRenderer` now allows for overwriting the *default* argument of its serializer. + [#77](https://github.com/hynek/structlog/pull/77), + [#163](https://github.com/hynek/structlog/pull/163) +- Added `try_unbind()` that works like `unbind()` but doesn't raise a `KeyError` if one of the keys is missing. + [#171](https://github.com/hynek/structlog/pull/171) + + +## [18.1.0](https://github.com/hynek/structlog/compare/17.2.0...18.1.0) - 2018-01-27 + +### Deprecated + +- The meaning of the `structlog[dev]` installation target will change from "colorful output" to "dependencies to develop `structlog`" in 19.1.0. + + The main reason behind this decision is that it's impossible to have a `structlog` in your normal dependencies and additionally a `structlog[dev]` for development (`pip` will report an error). + + +### Added + +- `structlog.dev.ConsoleRenderer` now accepts a *force_colors* argument to output colored logs even if the destination is not a tty. + Use this option if your logs are stored in files that are intended to be streamed to the console. +- `structlog.dev.ConsoleRenderer` now accepts a *level_styles* argument for overriding the colors for individual levels, as well as to add new levels. + See the docs for `ConsoleRenderer.get_default_level_styles()` for usage. + [#139](https://github.com/hynek/structlog/pull/139) +- Added `structlog.is_configured()` to check whether or not `structlog` has been configured. +- Added `structlog.get_config()` to introspect current configuration. + + +### Changed + +- Empty strings are valid events now. + [#110](https://github.com/hynek/structlog/issues/110) +- `structlog.stdlib.BoundLogger.exception()` now uses the `exc_info` argument if it has been passed instead of setting it unconditionally to `True`. [#149](https://github.com/hynek/structlog/pull/149) +- Default configuration now uses plain `dict`s on Python 3.6+ and PyPy since they are ordered by default. + + +### Fixed +- Do not encapsulate Twisted failures twice with newer versions of Twisted. + [#144](https://github.com/hynek/structlog/issues/144) + + +## [17.2.0](https://github.com/hynek/structlog/compare/17.1.0...17.2.0) - 2017-05-15 + +### Added + +- `structlog.stdlib.ProcessorFormatter` now accepts *keep_exc_info* and *keep_stack_info* arguments to control what to do with this information on log records. + Most likely you want them both to be `False` therefore it's the default. + [#109](https://github.com/hynek/structlog/issues/109) + + +### Fixed +- `structlog.stdlib.add_logger_name()` now works in `structlog.stdlib.ProcessorFormatter`'s `foreign_pre_chain`. + [#112](https://github.com/hynek/structlog/issues/112) +- Clear log record args in `structlog.stdlib.ProcessorFormatter` after rendering. + This fix is for you if you tried to use it and got `TypeError: not all arguments converted during string formatting` exceptions. + [#116](https://github.com/hynek/structlog/issues/116), + [#117](https://github.com/hynek/structlog/issues/117) + + +## [17.1.0](https://github.com/hynek/structlog/compare/16.1.0...17.1.0) - 2017-04-24 + +The main features of this release are massive improvements in standard library's `logging` integration. +Have a look at the updated [standard library chapter](https://www.structlog.org/en/stable/standard-library.html) on how to use them! +Special thanks go to [Fabian Büchler](https://github.com/fabianbuechler), [Gilbert Gilb's](https://github.com/gilbsgilbs), [Iva Kaneva](https://github.com/if-fi), [insolite](https://github.com/insolite), and [sky-code](https://github.com/sky-code), that made them possible. + + +### Added + +- Added `structlog.stdlib.render_to_log_kwargs()`. + This allows you to use `logging`-based formatters to take care of rendering your entries. + [#98](https://github.com/hynek/structlog/issues/98) +- Added `structlog.stdlib.ProcessorFormatter` which does the opposite: This allows you to run `structlog` processors on arbitrary `logging.LogRecords`. + [#79](https://github.com/hynek/structlog/issues/79), + [#105](https://github.com/hynek/structlog/issues/105) +- Added *repr_native_str* to `structlog.processors.KeyValueRenderer` and `structlog.dev.ConsoleRenderer`. + This allows for human-readable non-ASCII output on Python 2 (`repr()` on Python 2 behaves like `ascii()` on Python 3 in that regard). + As per compatibility policy, it's on (original behavior) in `KeyValueRenderer` and off (human-friendly behavior) in `ConsoleRenderer`. + [#94](https://github.com/hynek/structlog/issues/94) +- Added *colors* argument to `structlog.dev.ConsoleRenderer` and made it the default renderer. + [#78](https://github.com/hynek/structlog/pull/78) + + +### Changed + +- The default renderer now is `structlog.dev.ConsoleRenderer` if you don't configure `structlog`. + Colors are used if available and human-friendly timestamps are prepended. + This is in line with our backwards-compatibility policy that explicitly excludes default settings. +- UNIX epoch timestamps from `structlog.processors.TimeStamper` are more precise now. +- Positional arguments are now removed even if they are empty. + [#82](https://github.com/hynek/structlog/pull/82) + + +## Fixed + +- Fixed bug with Python 3 and `structlog.stdlib.BoundLogger.log()`. + Error log level was not reproducible and was logged as exception one time out of two. + [#92](https://github.com/hynek/structlog/pull/92) + + +## [16.1.0](https://github.com/hynek/structlog/compare/16.0.0...16.1.0) - 2016-05-24 + +### Removed + +- Python 3.3 and 2.6 aren't supported anymore. + They may work by chance but any effort to keep them working has ceased. + + The last Python 2.6 release was on October 29, 2013 and isn't supported by the CPython core team anymore. + Major Python packages like Django and Twisted dropped Python 2.6 a while ago already. + + Python 3.3 never had a significant user base and wasn't part of any distribution's LTS release. + + +### Added + +- Added a `drop_missing` argument to `KeyValueRenderer`. + If `key_order` is used and a key is missing a value, it's not rendered at all instead of being rendered as `None`. + [#67](https://github.com/hynek/structlog/pull/67) + + +### Fixed + +- Exceptions without a `__traceback__` are now also rendered on Python 3. +- Don't cache loggers in lazy proxies returned from `get_logger()`. + This lead to in-place mutation of them if used before configuration which in turn lead to the problem that configuration was applied only partially to them later. + [#72](https://github.com/hynek/structlog/pull/72) + + +## [16.0.0](https://github.com/hynek/structlog/compare/15.3.0...16.0.0) - 2016-01-28 + +### Added + +- Added `structlog.dev.ConsoleRenderer` that renders the event dictionary aligned and with colors. +- Added `structlog.processors.UnicodeDecoder` that will decode all byte string values in an event dictionary to Unicode. +- Added `serializer` parameter to `structlog.processors.JSONRenderer` which allows for using different (possibly faster) JSON encoders than the standard library. + + +### Changed + +- `structlog.processors.ExceptionPrettyPrinter` and `structlog.processors.format_exc_info` now support passing of Exceptions on Python 3. +- [*six*](https://six.readthedocs.io/) is now used for compatibility. + + +### Fixed + +- The context is now cleaned up when exiting `structlog.threadlocal.tmp_bind` in case of exceptions. + [#64](https://github.com/hynek/structlog/issues/64) +- Be more more lenient about missing `__name__`s. + [#62](https://github.com/hynek/structlog/pull/62) + + +## [15.3.0](https://github.com/hynek/structlog/compare/15.2.0...15.3.0) - 2015-09-25 + +### Added + +- Officially support Python 3.5. +- Added `structlog.ReturnLogger.failure` and `structlog.PrintLogger.failure` as preparation for the new Twisted logging system. + + +### Fixed + +- Tolerate frames without a `__name__`, better. + [#58](https://github.com/hynek/structlog/pull/58) + + +## [15.2.0](https://github.com/hynek/structlog/compare/15.1.0...15.2.0) - 2015-06-10 + +### Added + +- Added option to specify target key in `structlog.processors.TimeStamper` processor. + [#51](https://github.com/hynek/structlog/pull/51) + + +### Changed + +- Allow empty lists of processors. + This is a valid use case since [#26](https://github.com/hynek/structlog/issues/26) has been merged. + Before, supplying an empty list resulted in the defaults being used. +- Better support of `logging.Logger.exception` within `structlog`. + [#52](https://github.com/hynek/structlog/pull/52) + + +### Fixed + +- Prevent Twisted's `log.err` from quoting strings rendered by `structlog.twisted.JSONRenderer`. + + +## [15.1.0](https://github.com/hynek/structlog/compare/15.0.0...15.1.0) - 2015-02-24 + +### Fixed + +- Tolerate frames without a `__name__` when guessing callsite names. + + +## [15.0.0](https://github.com/hynek/structlog/compare/0.4.2...15.0.0) - 2015-01-23 + +### Added + +- Added `structlog.stdlib.add_log_level` and `structlog.stdlib.add_logger_name` processors. + [#44](https://github.com/hynek/structlog/pull/44) +- Added `structlog.stdlib.BoundLogger.log`. + [#42](https://github.com/hynek/structlog/pull/42) +- Added `structlog.stdlib.BoundLogger.exception`. + [#22](https://github.com/hynek/structlog/pull/22) + + +### Changed + +- Pass positional arguments to stdlib wrapped loggers that use string formatting. + [#19](https://github.com/hynek/structlog/pull/19) +- `structlog` is now dually licensed under the [Apache License, Version 2](https://choosealicense.com/licenses/apache/) and the [MIT](https://choosealicense.com/licenses/mit/) license. + Therefore it is now legal to use `structlog` with [GPLv2](https://choosealicense.com/licenses/gpl-2.0/)-licensed projects. + [#28](https://github.com/hynek/structlog/pull/28) + + +## [0.4.2](https://github.com/hynek/structlog/compare/0.4.1...0.4.2) - 2014-07-26 + +### Removed + +- Drop support for Python 3.2. + There is no justification to add complexity for a Python version that nobody uses. + If you are one of the [0.350%](https://alexgaynor.net/2014/jan/03/pypi-download-statistics/) that use Python 3.2, please stick to the 0.4 branch; critical bugs will still be fixed. + + +### Added + +- Officially support Python 3.4. +- Allow final processor to return a dictionary. + See the adapting chapter. + [#26](https://github.com/hynek/structlog/issues/26) +- Test Twisted-related code on Python 3 (with some caveats). + + +### Fixed + +- Fixed a memory leak in greenlet code that emulates thread locals. + It shouldn't matter in practice unless you use multiple wrapped dicts within one program that is rather unlikely. + [#8](https://github.com/hynek/structlog/pull/8) +- `structlog.PrintLogger` now is thread-safe. +- `from structlog import *` works now (but you still shouldn't use it). + + +## [0.4.1](https://github.com/hynek/structlog/compare/0.4.0...0.4.1) - 2013-12-19 + +### Changed + +- Don't cache proxied methods in `structlog.threadlocal._ThreadLocalDictWrapper`. This doesn't affect regular users. + + +### Fixed + +- Various doc fixes. + + +## [0.4.0](https://github.com/hynek/structlog/compare/0.3.2...0.4.0) - 2013-11-10 + +### Added + +- Added `structlog.processors.StackInfoRenderer` for adding stack information to log entries without involving exceptions. + Also added it to default processor chain. + [#6](https://github.com/hynek/structlog/pull/6) +- Allow optional positional arguments for `structlog.get_logger` that are passed to logger factories. + The standard library factory uses this for explicit logger naming. + [#12](https://github.com/hynek/structlog/pull/12) +- Add `structlog.processors.ExceptionPrettyPrinter` for development and testing when multiline log entries aren't just acceptable but even helpful. +- Allow the standard library name guesser to ignore certain frame names. + This is useful together with frameworks. +- Add meta data (e.g. function names, line numbers) extraction for wrapped stdlib loggers. [#5](https://github.com/hynek/structlog/pull/5) + + +## [0.3.2](https://github.com/hynek/structlog/compare/0.3.1...0.3.2) - 2013-09-27 + +### Fixed + +- Fix stdlib's name guessing. + + +## [0.3.1](https://github.com/hynek/structlog/compare/0.3.0...0.3.1) - 2013-09-26 + +### Fixed + +- Added forgotten `structlog.processors.TimeStamper` to API documentation. + + +## [0.3.0](https://github.com/hynek/structlog/compare/0.2.0...0.3.0) - 2013-09-23 + +### Changes: + +- Greatly enhanced and polished the documentation and added a new theme based on Write The Docs, requests, and Flask. +- Add Python Standard Library-specific BoundLogger that has an explicit API instead of intercepting unknown method calls. + See `structlog.stdlib.BoundLogger`. +- `structlog.ReturnLogger` now allows arbitrary positional and keyword arguments. +- Add Twisted-specific BoundLogger that has an explicit API instead of intercepting unknown method calls. + See `structlog.twisted.BoundLogger`. +- Allow logger proxies that are returned by `structlog.get_logger` and `structlog.wrap_logger` to cache the BoundLogger they assemble according to configuration on first use. + See the chapter on performance and the `cache_logger_on_first_use` argument of `structlog.configure` and `structlog.wrap_logger`. +- Extract a common base class for loggers that does nothing except keeping the context state. + This makes writing custom loggers much easier and more straight-forward. See `structlog.BoundLoggerBase`. + + +## [0.2.0](https://github.com/hynek/structlog/compare/0.1.0...0.2.0) - 2013-09-17 + +### Added + +- Add `key_order` option to `structlog.processors.KeyValueRenderer` for more predictable log entries with any `dict` class. +- Enhance Twisted support by offering JSONification of non-structlog log entries. +- Allow for custom serialization in `structlog.twisted.JSONRenderer` without abusing `__repr__`. + + +### Changed + +- Promote to stable, thus henceforth a strict backwards-compatibility policy is put into effect. +- `structlog.PrintLogger` now uses proper I/O routines and is thus viable not only for examples but also for production. + + +## [0.1.0](https://github.com/hynek/structlog/tree/0.1.0) - 2013-09-16 + +Initial release. diff --git a/CHANGELOG.rst b/CHANGELOG.rst deleted file mode 100644 index 5bbc038b..00000000 --- a/CHANGELOG.rst +++ /dev/null @@ -1,838 +0,0 @@ -Changelog -========= - -Versions follow `Calendar Versioning `_ with a strict backwards-compatibility policy. - -The **first number** of the version is the year. -The **second number** is incremented with each release, starting at 1 for each year. -The **third number** is when we need to start branches for older releases (only for emergencies). - -You shouldn't ever be afraid to upgrade ``structlog`` if you're using its public APIs and pay attention to ``DeprecationWarning``\ s. -Whenever there is a need to break compatibility, it is announced here in the changelog and raises a ``DeprecationWarning`` for a year (if possible) before it's finally really broken. - -.. warning:: - - You cannot rely on the default settings and the `structlog.dev` module. - They may be adjusted in the future to provide a better experience when starting to use ``structlog``. - So please make sure to **always** properly configure your applications. - -.. changelog - -22.1.0 (UNRELEASED) -------------------- - -Backward-incompatible changes: -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -- Python 3.6 is not supported anymore. -- Pickling is now only possible with protocol version 3 and newer. -- ``structlog.make_filtering_bound_logger()`` now returns a method with the same signature for all log levels, whether they are active or not. - This ensures that invalid calls to inactive log levels are caught immediately and don't explode once the log level changes. - `#401 `_ - - -Deprecations: -^^^^^^^^^^^^^ - -*none* - - -Changes: -^^^^^^^^ - -- Overloaded the ``bind``, ``unbind``, ``try_unbind`` and ``new`` methods in the ``FilteringBoundLogger`` `Protocol `_. - This makes it easier to use objects of type ``FilteringBoundLogger`` in a typed context. - `#392 `_ -- ``structlog.processors.StackInfoRenderer`` now has an *additional_ignores* parameter that allows you to filter out your own logging layer. - `#396 `_ -- ``structlog.PrintLogger`` -- that is used by default -- now uses ``print()`` for printing, making it a better citizen for interactive terminal applications. - `#399 `_ -- Added ``structlog.WriteLogger``, a faster -- but more low-level -- alternative to ``structlog.PrintLogger``. - It works the way ``PrintLogger`` used to work in previous versions. - `#403 `_ -- Added better support for monkeypatched ``sys.stdout``\ s. - `#404 `_ - - ----- - - -21.5.0 (2021-12-16) -------------------- - - -Backward-incompatible changes: -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -*none* - - -Deprecations: -^^^^^^^^^^^^^ - -*none* - - -Changes: -^^^^^^^^ - -- Added the ``structlog.processors.LogfmtRenderer`` processor to render log lines using the `logfmt `_ format. - `#376 `_ -- Added the ``structlog.stdlib.ExtraAdder`` processor that adds extra attributes of ``logging.LogRecord`` objects to the event dictionary. - This processor can be used for adding data passed in the ``extra`` parameter of the ``logging`` module's log methods to the event dictionary. - `#209 `_ - `#377 `_ -- Added the ``structlog.processor.CallsiteParameterAdder`` processor that adds parameters of the callsite that an event dictionary orginated from to the event dictionary. - This processor can be used to enrich events dictionaries with information such as the function name, line number and filename that an event dictionary orignated from. - `#380 `_ - - ----- - - -21.4.0 (2021-11-25) -------------------- - - -Backward-incompatible changes: -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -*none* - - -Deprecations: -^^^^^^^^^^^^^ - -*none* - - -Changes: -^^^^^^^^ - -- Fixed import when running in optimized mode (``PYTHONOPTIMIZE=2`` or ``python -OO``). - `#373 `_ -- Added the ``structlog.threadlocal.bound_threadlocal`` and ``structlog.contextvars.bound_contextvars`` decorator/context managers to temporarily bind key/value pairs to a thread-local and context-local context. - `#371 `_ - - ----- - - -21.3.0 (2021-11-20) -------------------- - - -Backward-incompatible changes: -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -- ``structlog`` switched its packaging to `flit `_. - Users shouldn't notice a difference, but (re-)packagers might. - - -Deprecations: -^^^^^^^^^^^^^ - -*none* - - -Changes: -^^^^^^^^ - -- ``structlog.dev.ConsoleRenderer`` now has ``sort_keys`` boolean parameter that allows to disable the sorting of keys on output. - `#358 `_ -- ``structlog.processors.TimeStamper`` now works well with FreezeGun even when it gets applied before the loggers are configured. - `#364 `_ -- ``structlog.stdlib.AsyncBoundLogger`` now determines the running loop when logging, not on instantiation. - That has a minor performance impact, but makes it more robust when loops change (e.g. ``aiohttp.web.run_app()``), or you want to use ``sync_bl`` *before* a loop has started. -- ``structlog.stdlib.ProcessorFormatter`` now has a *processors* argument that allows to define a processor chain to run over *all* log entries. - - Before running the chain, two additional keys are added to the event dictionary: ``_record`` and ``_from_structlog``. - With them it's possible to extract information from ``logging.LogRecord``\s and differentiate between ``structlog`` and ``logging`` log entries while processing them. - - The old *processor* (singular) parameter is now deprecated, but no plans exist to remove it. - `#365 `_ - - ----- - - -21.2.0 (2021-10-12) -------------------- - - -Backward-incompatible changes: -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -- To implement pretty exceptions (see Changes below), ``structlog.dev.ConsoleRenderer`` now formats exceptions itself. - - Make sure to remove ``format_exc_info`` from your processor chain if you configure ``structlog`` manually. - This change is not really breaking, because the old use-case will keep working as before. - However if you pass ``pretty_exceptions=True`` (which is the default if either ``rich`` or ``better-exceptions`` is installed), a warning will be raised and the exception will be renderered without prettyfication. - - -Deprecations: -^^^^^^^^^^^^^ - -*none* - - -Changes: -^^^^^^^^ - -- ``structlog`` is now importable if ``sys.stdout`` is ``None`` (e.g. when running using ``pythonw``). - `#313 `_ -- ``structlog.threadlocal.get_threadlocal()`` and ``structlog.contextvars.get_contextvars()`` can now be used to get a copy of the current thread-local/context-local context that has been bound using ``structlog.threadlocal.bind_threadlocal()`` and ``structlog.contextvars.bind_contextvars()``. - `#331 `_ - `#337 `_ -- ``structlog.threadlocal.get_merged_threadlocal(bl)`` and ``structlog.contextvars.get_merged_contextvars(bl)`` do the same, but also merge the context from a bound logger *bl*. - Same pull requests as previous change. -- ``structlog.contextvars.bind_contextvars()`` now returns a mapping of keys to ``contextvars.Token``\s, allowing you to reset values using the new ``structlog.contextvars.reset_contextvars()``. - `#339 `_ -- Exception rendering in ``structlog.dev.ConsoleLogger`` is now configurable using the ``exception_formatter`` setting. - If either the `rich `_ or the `better-exceptions `_ package is present, ``structlog`` will use them for pretty-printing tracebacks. - ``rich`` takes precedence over ``better-exceptions`` if both are present. - - This only works if ``format_exc_info`` is **absent** in the processor chain. - `#330 `_ - `#349 `_ -- All use of ``colorama`` on non-Windows systems has been excised. - Thus, colors are now enabled by default in ``structlog.dev.ConsoleRenderer`` on non-Windows systems. - You can keep using ``colorama`` to customize colors, of course. - `#345 `_ -- The final processor can now return a ``bytearray`` (additionally to ``str`` and ``bytes``). - `#344 `_ - - ----- - - -21.1.0 (2021-02-18) -------------------- - - -Backward-incompatible changes: -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -*none* - - -Deprecations: -^^^^^^^^^^^^^ - -*none* - - -Changes: -^^^^^^^^ - -- ``structlog.threadlocal.wrap_dict()`` now has a correct type annotation. - `#290 `_ -- Fix isolation in ``structlog.contextvars``. - `#302 `_ -- The default configuration and loggers are pickleable again. - `#301 `_ -- ``structlog.dev.ConsoleRenderer`` will now look for a ``logger_name`` key if no - ``logger`` key is set. - `#295 `_ - - ----- - - -20.2.0 (2020-12-31) -------------------- - - -Backward-incompatible changes: -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -- Python 2.7 and 3.5 aren't supported anymore. - The package meta data should ensure that you keep getting 20.1.0 on those versions. - `#244 `_ - -- ``structlog`` is now fully type-annotated. - This won't break your applications, but if you use Mypy, it will most likely break your CI. - - Check out the new chapter on typing for details. - -- The default bound logger (``wrapper_class``) if you don't configure ``structlog`` has changed. - It's mostly compatible with the old one but a few uncommon methods like ``log``, ``failure``, or ``err`` don't exist anymore. - - You can regain the old behavior by using ``structlog.configure(wrapper_class=structlog.BoundLogger)``. - - Please note that due to the various interactions between settings, it's possible that you encounter even more errors. - We **strongly** urge you to always configure all possible settings since the default configuration is *not* covered by our backwards-compatibility policy. - - -Deprecations: -^^^^^^^^^^^^^ - -- Accessing the ``_context`` attribute of a bound logger is now deprecated. - Please use the new ``structlog.get_context()``. - - -Changes: -^^^^^^^^ - -- ``structlog`` has now type hints for all of its APIs! - Since ``structlog`` is highly dynamic and configurable, this led to a few concessions like a specialized ``structlog.stdlib.get_logger()`` whose only difference to ``structlog.get_logger()`` is that it has the correct type hints. - - We consider them provisional for the time being – i.e. the backwards-compatibility does not apply to them in its full strength until we feel we got it right. - Please feel free to provide feedback! - `#223 `_, - `#282 `_ -- Added ``structlog.make_filtering_logger`` that can be used like ``configure(wrapper_class=make_filtering_bound_logger(logging.INFO))``. - It creates a highly optimized bound logger whose inactive methods only consist of a ``return None``. - This is now also the default logger. -- As a complement, ``structlog.stdlib.add_log_level()`` can now additionally be imported as ``structlog.processors.add_log_level`` since it just adds the method name to the event dict. -- ``structlog.processors.add_log_level()`` is now part of the default configuration. -- ``structlog.stdlib.ProcessorFormatter`` no longer uses exceptions for control flow, allowing ``foreign_pre_chain`` processors to use ``sys.exc_info()`` to access the real exception. -- Added ``structlog.BytesLogger`` to avoid unnecessary encoding round trips. - Concretely this is useful with *orjson* which returns bytes. - `#271 `_ -- The final processor now also may return bytes that are passed untouched to the wrapped logger. -- ``structlog.get_context()`` allows you to retrieve the original context of a bound logger. - `#266 `_, -- ``structlog.PrintLogger`` now supports ``copy.deepcopy()``. - `#268 `_ -- Added ``structlog.testing.CapturingLogger`` for more unit testing goodness. -- Added ``structlog.stdlib.AsyncBoundLogger`` that executes logging calls in a thread executor and therefore doesn't block. - `#245 `_ - - ----- - - -20.1.0 (2020-01-28) -------------------- - - -Backward-incompatible changes: -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -*none* - - -Deprecations: -^^^^^^^^^^^^^ - -- This is the last version to support Python 2.7 (including PyPy) and 3.5. - All following versions will only support Python 3.6 or later. - - -Changes: -^^^^^^^^ - -- Added a new module ``structlog.contextvars`` that allows to have a global but context-local ``structlog`` context the same way as with ``structlog.threadlocal`` since 19.2.0. - `#201 `_, - `#236 `_ -- Added a new module ``structlog.testing`` for first class testing support. - The first entry is the context manager ``capture_logs()`` that allows to make assertions about structured log calls. - `#14 `_, - `#234 `_ -- Added ``structlog.threadlocal.unbind_threadlocal()``. - `#239 `_ -- The logger created by ``structlog.get_logger()`` is not detected as an abstract method anymore, when attached to an abstract base class. - `#229 `_ -- ``colorama`` isn't initialized lazily on Windows anymore because it breaks rendering. - `#232 `_, - `#242 `_ - - ----- - - -19.2.0 (2019-10-16) -------------------- - - -Backward-incompatible changes: -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -- Python 3.4 is not supported anymore. - It has been unsupported by the Python core team for a while now and its PyPI downloads are negligible. - - It's very unlikely that ``structlog`` will break under 3.4 anytime soon, but we don't test it anymore. - - -Deprecations: -^^^^^^^^^^^^^ - -*none* - - -Changes: -^^^^^^^^ - -- Full Python 3.8 support for ``structlog.stdlib``. -- Added more pass-through properties to ``structlog.stdlib.BoundLogger``. - To makes it easier to use it as a drop-in replacement for ``logging.Logger``. - `#198 `_ -- ``structlog.stdlib.ProcessorFormatter`` now takes a logger object as an optional keyword argument. - This makes ``ProcessorFormatter`` work properly with ``stuctlog.stdlib.filter_by_level()``. - `#219 `_ -- ``structlog.dev.ConsoleRenderer`` now uses no colors by default, if ``colorama`` is not available. - `#215 `_ -- ``structlog.dev.ConsoleRenderer`` now initializes ``colorama`` lazily, to prevent accidental side-effects just by importing ``structlog``. - `#210 `_ -- Added new processor ``structlog.dev.set_exc_info()`` that will set ``exc_info=True`` if the method's name is ``exception`` and ``exc_info`` isn't set at all. - *This is only necessary when the standard library integration is not used*. - It fixes the problem that in the default configuration, ``structlog.get_logger().exception("hi")`` in an ``except`` block would not print the exception without passing ``exc_info=True`` to it explicitly. - `#130 `_, - `#173 `_, - `#200 `_, - `#204 `_ -- A best effort has been made to make as much of ``structlog`` pickleable as possible to make it friendlier with ``multiprocessing`` and similar libraries. - Some classes can only be pickled on Python 3 or using the `dill `_ library though and that is very unlikely to change. - - So far, the configuration proxy, ``structlog.processor.TimeStamper``, ``structlog.BoundLogger``, ``structlog.PrintLogger`` and ``structlog.dev.ConsoleRenderer`` have been made pickelable. - Please report if you need any another class fixed. - `#126 `_ -- Added a new thread-local API that allows binding values to a thread-local context explicitly without affecting the default behavior of ``bind()``. - `#222 `_, - `#225 `_ -- Added ``pass_foreign_args`` argument to ``structlog.stdlib.ProcessorFormatter``. - It allows to pass a foreign log record's ``args`` attribute to the event dictionary under the ``positional_args`` key. - `#228 `_ -- ``structlog.dev.ConsoleRenderer`` now calls ``str()`` on the event value. - `#221 `_ - - ----- - - -19.1.0 (2019-02-02) -------------------- - - -Backward-incompatible changes: -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -- As announced in 18.1.0, ``pip install -e .[dev]`` now installs all development dependencies. - Sorry for the inconveniences this undoubtedly will cause! - - -Deprecations: -^^^^^^^^^^^^^ - -*none* - - -Changes: -^^^^^^^^ - -- ``structlog.ReturnLogger`` and ``structlog.PrintLogger`` now have a ``fatal()`` log method. - `#181 `_ -- Under certain (rather unclear) circumstances, the frame extraction could throw an ``SystemError: error return without exception set``. - A workaround has been added. - `#174 `_ -- ``structlog`` now tolerates passing through ``dict``\ s to stdlib logging. - `#187 `_, - `#188 `_, - `#189 `_ - - ----- - - -18.2.0 (2018-09-05) -------------------- - - -Backward-incompatible changes: -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -*none* - - -Deprecations: -^^^^^^^^^^^^^ - -*none* - - -Changes: -^^^^^^^^ - -- Added ``structlog.stdlib.add_log_level_number()`` processor that adds the level *number* to the event dictionary. - Can be used to simplify log filtering. - `#151 `_ -- ``structlog.processors.JSONRenderer`` now allows for overwriting the *default* argument of its serializer. - `#77 `_, - `#163 `_ -- Added ``try_unbind()`` that works like ``unbind()`` but doesn't raise a ``KeyError`` if one of the keys is missing. - `#171 `_ - - ----- - - -18.1.0 (2018-01-27) -------------------- - - -Backward-incompatible changes: -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -*none* - - -Deprecations: -^^^^^^^^^^^^^ - -- The meaning of the ``structlog[dev]`` installation target will change from "colorful output" to "dependencies to develop ``structlog``" in 19.1.0. - - The main reason behind this decision is that it's impossible to have a ``structlog`` in your normal dependencies and additionally a ``structlog[dev]`` for development (``pip`` will report an error). - - -Changes: -^^^^^^^^ - -- Empty strings are valid events now. - `#110 `_ -- Do not encapsulate Twisted failures twice with newer versions of Twisted. - `#144 `_ -- ``structlog.dev.ConsoleRenderer`` now accepts a *force_colors* argument to output colored logs even if the destination is not a tty. - Use this option if your logs are stored in files that are intended to be streamed to the console. -- ``structlog.dev.ConsoleRenderer`` now accepts a *level_styles* argument for overriding the colors for individual levels, as well as to add new levels. - See the docs for ``ConsoleRenderer.get_default_level_styles()`` for usage. - `#139 `_ -- ``structlog.stdlib.BoundLogger.exception()`` now uses the ``exc_info`` argument if it has been passed instead of setting it unconditionally to ``True``. - `#149 `_ -- Default configuration now uses plain ``dict``\ s on Python 3.6+ and PyPy since they are ordered by default. -- Added ``structlog.is_configured()`` to check whether or not ``structlog`` has been configured. -- Added ``structlog.get_config()`` to introspect current configuration. - - ----- - - -17.2.0 (2017-05-15) -------------------- - - -Backward-incompatible changes: -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -*none* - - -Deprecations: -^^^^^^^^^^^^^ - -*none* - - -Changes: -^^^^^^^^ - -- ``structlog.stdlib.ProcessorFormatter`` now accepts *keep_exc_info* and *keep_stack_info* arguments to control what to do with this information on log records. - Most likely you want them both to be ``False`` therefore it's the default. - `#109 `_ -- ``structlog.stdlib.add_logger_name()`` now works in ``structlog.stdlib.ProcessorFormatter``'s ``foreign_pre_chain``. - `#112 `_ -- Clear log record args in ``structlog.stdlib.ProcessorFormatter`` after rendering. - This fix is for you if you tried to use it and got ``TypeError: not all arguments converted during string formatting`` exceptions. - `#116 `_, - `#117 `_ - - ----- - - -17.1.0 (2017-04-24) -------------------- - -The main features of this release are massive improvements in standard library's ``logging`` integration. -Have a look at the updated `standard library chapter `_ on how to use them! -Special thanks go to -`Fabian Büchler `_, -`Gilbert Gilb's `_, -`Iva Kaneva `_, -`insolite `_, -and `sky-code `_, -that made them possible. - - -Backward-incompatible changes: -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -- The default renderer now is ``structlog.dev.ConsoleRenderer`` if you don't configure ``structlog``. - Colors are used if available and human-friendly timestamps are prepended. - This is in line with our backwards-compatibility policy that explicitly excludes default settings. - - -Changes: -^^^^^^^^ - -- Added ``structlog.stdlib.render_to_log_kwargs()``. - This allows you to use ``logging``-based formatters to take care of rendering your entries. - `#98 `_ -- Added ``structlog.stdlib.ProcessorFormatter`` which does the opposite: - This allows you to run ``structlog`` processors on arbitrary ``logging.LogRecords``. - `#79 `_, - `#105 `_ -- UNIX epoch timestamps from ``structlog.processors.TimeStamper`` are more precise now. -- Added *repr_native_str* to ``structlog.processors.KeyValueRenderer`` and ``structlog.dev.ConsoleRenderer``. - This allows for human-readable non-ASCII output on Python 2 (``repr()`` on Python 2 behaves like ``ascii()`` on Python 3 in that regard). - As per compatibility policy, it's on (original behavior) in ``KeyValueRenderer`` and off (humand-friendly behavior) in ``ConsoleRenderer``. - `#94 `_ -- Added *colors* argument to ``structlog.dev.ConsoleRenderer`` and made it the default renderer. - `#78 `_ -- Fixed bug with Python 3 and ``structlog.stdlib.BoundLogger.log()``. - Error log level was not reproductible and was logged as exception one time out of two. - `#92 `_ -- Positional arguments are now removed even if they are empty. - `#82 `_ - - ----- - - -16.1.0 (2016-05-24) -------------------- - -Backward-incompatible changes: -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -- Python 3.3 and 2.6 aren't supported anymore. - They may work by chance but any effort to keep them working has ceased. - - The last Python 2.6 release was on October 29, 2013 and isn't supported by the CPython core team anymore. - Major Python packages like Django and Twisted dropped Python 2.6 a while ago already. - - Python 3.3 never had a significant user base and wasn't part of any distribution's LTS release. - -Changes: -^^^^^^^^ - -- Add a ``drop_missing`` argument to ``KeyValueRenderer``. - If ``key_order`` is used and a key is missing a value, it's not rendered at all instead of being rendered as ``None``. - `#67 `_ -- Exceptions without a ``__traceback__`` are now also rendered on Python 3. -- Don't cache loggers in lazy proxies returned from ``get_logger()``. - This lead to in-place mutation of them if used before configuration which in turn lead to the problem that configuration was applied only partially to them later. - `#72 `_ - - ----- - - -16.0.0 (2016-01-28) -------------------- - -Changes: -^^^^^^^^ - -- ``structlog.processors.ExceptionPrettyPrinter`` and ``structlog.processors.format_exc_info`` now support passing of Exceptions on Python 3. -- Clean up the context when exiting ``structlog.threadlocal.tmp_bind`` in case of exceptions. - `#64 `_ -- Be more more lenient about missing ``__name__``\ s. - `#62 `_ -- Add ``structlog.dev.ConsoleRenderer`` that renders the event dictionary aligned and with colors. -- Use `six `_ for compatibility. -- Add ``structlog.processors.UnicodeDecoder`` that will decode all byte string values in an event dictionary to Unicode. -- Add ``serializer`` parameter to ``structlog.processors.JSONRenderer`` which allows for using different (possibly faster) JSON encoders than the standard library. - - ----- - - -15.3.0 (2015-09-25) -------------------- - -Changes: -^^^^^^^^ - -- Tolerate frames without a ``__name__``, better. - `#58 `_ -- Officially support Python 3.5. -- Add ``structlog.ReturnLogger.failure`` and ``structlog.PrintLogger.failure`` as preparation for the new Twisted logging system. - - ----- - - -15.2.0 (2015-06-10) -------------------- - -Changes: -^^^^^^^^ - -- Allow empty lists of processors. - This is a valid use case since `#26 `_ has been merged. - Before, supplying an empty list resulted in the defaults being used. -- Prevent Twisted's ``log.err`` from quoting strings rendered by ``structlog.twisted.JSONRenderer``. -- Better support of ``logging.Logger.exception`` within ``structlog``. - `#52 `_ -- Add option to specify target key in ``structlog.processors.TimeStamper`` processor. - `#51 `_ - - ----- - - -15.1.0 (2015-02-24) -------------------- - -Changes: -^^^^^^^^ - -- Tolerate frames without a ``__name__``. - - ----- - - -15.0.0 (2015-01-23) -------------------- - -Changes: -^^^^^^^^ - -- Add ``structlog.stdlib.add_log_level`` and ``structlog.stdlib.add_logger_name`` processors. - `#44 `_ -- Add ``structlog.stdlib.BoundLogger.log``. - `#42 `_ -- Pass positional arguments to stdlib wrapped loggers that use string formatting. - `#19 `_ -- ``structlog`` is now dually licensed under the `Apache License, Version 2 `_ and the `MIT `_ license. - Therefore it is now legal to use structlog with `GPLv2 `_-licensed projects. - `#28 `_ -- Add ``structlog.stdlib.BoundLogger.exception``. - `#22 `_ - - ----- - - -0.4.2 (2014-07-26) ------------------- - -Changes: -^^^^^^^^ - -- Fixed a memory leak in greenlet code that emulates thread locals. - It shouldn't matter in practice unless you use multiple wrapped dicts within one program that is rather unlikely. - `#8 `_ -- ``structlog.PrintLogger`` now is thread-safe. -- Test Twisted-related code on Python 3 (with some caveats). -- Drop support for Python 3.2. - There is no justification to add complexity for a Python version that nobody uses. - If you are one of the `0.350% `_ that use Python 3.2, please stick to the 0.4 branch; critical bugs will still be fixed. -- Officially support Python 3.4. -- Allow final processor to return a dictionary. - See the adapting chapter. - `#26`_ -- ``from structlog import *`` works now (but you still shouldn't use it). - - ----- - - -0.4.1 (2013-12-19) ------------------- - -Changes: -^^^^^^^^ - -- Don't cache proxied methods in ``structlog.threadlocal._ThreadLocalDictWrapper``. - This doesn't affect regular users. -- Various doc fixes. - - ----- - - -0.4.0 (2013-11-10) ------------------- - - -Backward-incompatible changes: -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Changes: -^^^^^^^^ - -- Add ``structlog.processors.StackInfoRenderer`` for adding stack information to log entries without involving exceptions. - Also added it to default processor chain. - `#6 `_ -- Allow optional positional arguments for ``structlog.get_logger`` that are passed to logger factories. - The standard library factory uses this for explicit logger naming. - `#12 `_ -- Add ``structlog.processors.ExceptionPrettyPrinter`` for development and testing when multiline log entries aren't just acceptable but even helpful. -- Allow the standard library name guesser to ignore certain frame names. - This is useful together with frameworks. -- Add meta data (e.g. function names, line numbers) extraction for wrapped stdlib loggers. - `#5 `_ - - ----- - - -0.3.2 (2013-09-27) ------------------- - -Changes: -^^^^^^^^ - -- Fix stdlib's name guessing. - - ----- - - -0.3.1 (2013-09-26) ------------------- - -Changes: -^^^^^^^^ - -- Add forgotten ``structlog.processors.TimeStamper`` to API documentation. - - ----- - - -0.3.0 (2013-09-23) ------------------- - -Changes: -^^^^^^^^ - -- Greatly enhanced and polished the documentation and added a new theme based on Write The Docs, requests, and Flask. -- Add Python Standard Library-specific BoundLogger that has an explicit API instead of intercepting unknown method calls. - See ``structlog.stdlib.BoundLogger``. -- ``structlog.ReturnLogger`` now allows arbitrary positional and keyword arguments. -- Add Twisted-specific BoundLogger that has an explicit API instead of intercepting unknown method calls. - See ``structlog.twisted.BoundLogger``. -- Allow logger proxies that are returned by ``structlog.get_logger`` and ``structlog.wrap_logger`` to cache the BoundLogger they assemble according to configuration on first use. - See the chapter on performance and the ``cache_logger_on_first_use`` argument of ``structlog.configure`` and ``structlog.wrap_logger``. -- Extract a common base class for loggers that does nothing except keeping the context state. - This makes writing custom loggers much easier and more straight-forward. - See ``structlog.BoundLoggerBase``. - - ----- - - -0.2.0 (2013-09-17) ------------------- - -Changes: -^^^^^^^^ - -- Promote to stable, thus henceforth a strict backwards-compatibility policy is put into effect. -- Add ``key_order`` option to ``structlog.processors.KeyValueRenderer`` for more predictable log entries with any ``dict`` class. -- ``structlog.PrintLogger`` now uses proper I/O routines and is thus viable not only for examples but also for production. -- Enhance Twisted support by offering JSONification of non-structlog log entries. -- Allow for custom serialization in ``structlog.twisted.JSONRenderer`` without abusing ``__repr__``. - - ----- - - -0.1.0 (2013-09-16) ------------------- - -Initial release. diff --git a/docs/changelog.md b/docs/changelog.md new file mode 100644 index 00000000..66efc0fe --- /dev/null +++ b/docs/changelog.md @@ -0,0 +1,2 @@ +```{include} ../CHANGELOG.md +``` diff --git a/docs/changelog.rst b/docs/changelog.rst deleted file mode 100644 index 565b0521..00000000 --- a/docs/changelog.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../CHANGELOG.rst diff --git a/docs/conf.py b/docs/conf.py index 14c6adb8..fb18920f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -13,6 +13,7 @@ # -- General configuration ---------------------------------------------------- extensions = [ + "myst_parser", "notfound.extension", "sphinx.ext.autodoc", "sphinx.ext.autodoc.typehints", diff --git a/pyproject.toml b/pyproject.toml index f4f6c3e7..8afe7e98 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -70,6 +70,7 @@ tests = [ ] docs = [ "furo", + "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", @@ -98,6 +99,7 @@ dev = [ "pytest>=6.0", "simplejson", "furo", + "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", From 72e99a80846afaacd2f356afff8a84ae49ff8b8a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 3 Apr 2022 13:28:46 +0200 Subject: [PATCH 0679/1520] pre-commit autoupdate --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e5d6bb0c..0ae70d3d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/psf/black - rev: 22.1.0 + rev: 22.3.0 hooks: - id: black From dcccf49390861e621d839e0c5a5f95b5a8d7b653 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 20 Apr 2022 07:34:21 +0200 Subject: [PATCH 0680/1520] Deprecate structlog.threadlocal (#409) * Deprecate structlog.threadlocal Fixes #406 * Add PR link --- CHANGELOG.md | 7 ++ docs/api.rst | 70 ++------------- docs/contextvars.rst | 13 ++- docs/index.rst | 2 +- docs/thread-local.rst | 112 +++++++++--------------- pyproject.toml | 5 +- src/structlog/threadlocal.py | 65 +++++++++++++- tests/test_contextvars.py | 4 - tests/test_processors.py | 7 +- tests/test_threadlocal.py | 165 ++++++++++++++++++++++------------- tox.ini | 17 +--- 11 files changed, 246 insertions(+), 221 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4241343d..3b68702d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,13 @@ So please make sure to **always** properly configure your applications. - Pickling is now only possible with protocol version 3 and newer. +### Deprecated + +- The entire `structlog.threadlocal` module is deprecated. + Please use the primitives from `structlog.contextvars` instead. + [#409](https://github.com/hynek/structlog/pull/409) + + ### Added - `structlog.processors.StackInfoRenderer` now has an *additional_ignores* parameter that allows you to filter out your own logging layer. diff --git a/docs/api.rst b/docs/api.rst index 3c4482da..723eaf12 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -4,7 +4,7 @@ API Reference ============= .. note:: - The examples here use a very simplified configuration using the minimalistic `structlog.processors.KeyValueRenderer` for brevity and to enable doctests. + The examples here use a very simplified configuration using the minimalist `structlog.processors.KeyValueRenderer` for brevity and to enable doctests. The output is going to be different (nicer!) with the default configuration. @@ -112,68 +112,6 @@ API Reference .. autoclass:: ReturnLoggerFactory - -`structlog.threadlocal` Module ------------------------------- - -.. automodule:: structlog.threadlocal - - -Modern Approach -~~~~~~~~~~~~~~~ - -.. autofunction:: bind_threadlocal - -.. autofunction:: unbind_threadlocal - -.. autofunction:: bound_threadlocal - -.. autofunction:: get_threadlocal - - >>> from structlog.threadlocal import bind_threadlocal, get_threadlocal - >>> bind_threadlocal(x=1) - >>> get_threadlocal() - {'x': 1} - -.. autofunction:: get_merged_threadlocal - - >>> from structlog import get_logger - >>> from structlog.threadlocal import bind_threadlocal, get_merged_threadlocal - >>> bind_threadlocal(x=1) - >>> log = get_logger() - >>> log = log.bind(y=2) - >>> get_merged_threadlocal(log) - {'x': 1, 'y': 2} - -.. autofunction:: merge_threadlocal - -.. autofunction:: clear_threadlocal - - -Old Approach -~~~~~~~~~~~~ - -The following APIs use a different approach, that we discourage nowadays. -Please see :doc:`thread-local` for details. - -.. autofunction:: wrap_dict - -.. autofunction:: tmp_bind(logger, **tmp_values) - - >>> from structlog import wrap_logger, PrintLogger - >>> from structlog.threadlocal import tmp_bind, wrap_dict - >>> logger = wrap_logger(PrintLogger(), context_class=wrap_dict(dict)) - >>> with tmp_bind(logger, x=5) as tmp_logger: - ... logger = logger.bind(y=3) - ... tmp_logger.msg("event") - x=5 y=3 event='event' - >>> logger.msg("event") - event='event' - - -.. autofunction:: as_immutable - - `structlog.contextvars` Module ------------------------------ @@ -188,6 +126,12 @@ Please see :doc:`thread-local` for details. .. autofunction:: unbind_contextvars .. autofunction:: reset_contextvars +`structlog.threadlocal` Module +------------------------------ + +.. automodule:: structlog.threadlocal + :noindex: + .. _procs: diff --git a/docs/contextvars.rst b/docs/contextvars.rst index 37438bcd..bf58d1fd 100644 --- a/docs/contextvars.rst +++ b/docs/contextvars.rst @@ -12,18 +12,25 @@ Context Variables import structlog structlog.reset_defaults() -With the introduction of :mod:`contextvars` in Python 3.7, there is a way of having a global context that is local to the current context and even works in concurrent code such as code using :mod:`asyncio`. +The :mod:`contextvars` module in the Python standard library allows having a global ``structlog`` context that is local to the current execution context. +The execution context can be thread-local, concurrent code such as code using :mod:`asyncio`, or `greenlet `_. + +For example, you may want to bind certain values like a request ID or the peer's IP address at the beginning of a web request and have them logged out along with the local contexts you build within our views. For that ``structlog`` provides the `structlog.contextvars` module with a set of functions to bind variables to a context-local context. -This context is safe to be used in asynchronous code. +This context is safe to be used both in threaded as well as asynchronous code. -The general flow mirrors the one for :doc:`thread-local `: +The general flow is: - Use `structlog.configure` with `structlog.contextvars.merge_contextvars` as your first processor. - Call `structlog.contextvars.clear_contextvars` at the beginning of your request handler (or whenever you want to reset the context-local context). - Call `structlog.contextvars.bind_contextvars` and `structlog.contextvars.unbind_contextvars` instead of your bound logger's ``bind()`` and ``unbind()`` when you want to bind and unbind key-value pairs to the context-local context. + You can also use the `structlog.contextvars.bound_contextvars` context manager/decorator. - Use ``structlog`` as normal. Loggers act as they always do, but the `structlog.contextvars.merge_contextvars` processor ensures that any context-local binds get included in all of your log messages. +- If you want to access the context-local storage, you use `structlog.contextvars.get_contextvars` and `structlog.contextvars.get_merged_contextvars`. + +We're sorry the word *context* means three different things in this itemization depending on...context. .. doctest:: diff --git a/docs/index.rst b/docs/index.rst index a7605afd..13f35ad2 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -30,7 +30,6 @@ Basics loggers configuration testing - thread-local contextvars processors examples @@ -60,6 +59,7 @@ Advanced Topics custom-wrappers performance + thread-local API Reference diff --git a/docs/thread-local.rst b/docs/thread-local.rst index 59694220..d5ed5007 100644 --- a/docs/thread-local.rst +++ b/docs/thread-local.rst @@ -1,5 +1,12 @@ -Thread-Local Context -==================== +Legacy Thread-local Context +=========================== + +.. warning:: + The ``structlog.threadlocal`` module is deprecated as of ``structlog`` 22.1.0 in favor of :doc:`contextvars`. + + The standard library :mod:`contextvars` module provides a more feature-rich superset of the thread-local APIs and works with thread-local data, async code, and greenlets. + + Therefore, as of 22.1.0, the ``structlog.threadlocal`` is frozen and will be removed after May 2023. .. testsetup:: * @@ -14,21 +21,6 @@ Thread-Local Context structlog.reset_defaults() -Immutability ------------- - - You should call some functions with some arguments. - - --- David Reid - -``structlog`` does its best to have as little global state as possible to achieve its goals. -In an ideal world, you would just stick to its immutable bound loggers and reap all the rewards of having purely `immutable state `_. - -However, we realize that passing loggers around is rather clunky and intrusive in practice. -And since `practicality beats purity `_, ``structlog`` ships with the `structlog.threadlocal` module to help you to safely have global context storage. - - - The ``merge_threadlocal`` Processor ----------------------------------- @@ -43,55 +35,13 @@ The general flow of using these functions is: Loggers act as they always do, but the `structlog.threadlocal.merge_threadlocal` processor ensures that any thread-local binds get included in all of your log messages. - If you want to access the thread-local storage, you use `structlog.threadlocal.get_threadlocal` and `structlog.threadlocal.get_merged_threadlocal`. -.. doctest:: +These functions map 1:1 to the :doc:`contextvars` APIs, so please use those instead: - >>> from structlog.threadlocal import ( - ... bind_threadlocal, - ... bound_threadlocal, - ... clear_threadlocal, - ... get_merged_threadlocal, - ... get_threadlocal, - ... merge_threadlocal, - ... unbind_threadlocal, - ... ) - >>> from structlog import configure - >>> configure( - ... processors=[ - ... merge_threadlocal, - ... structlog.processors.KeyValueRenderer(), - ... ] - ... ) - >>> log = structlog.get_logger() - >>> # At the top of your request handler (or, ideally, some general - >>> # middleware), clear the thread-local context and bind some common - >>> # values: - >>> clear_threadlocal() - >>> bind_threadlocal(a=1, b=2) - >>> # Then use loggers as per normal - >>> # (perhaps by using structlog.get_logger() to create them). - >>> log.msg("hi") - a=1 b=2 event='hi' - >>> # Use unbind_threadlocal to remove a variable from the context. - >>> unbind_threadlocal("b") - >>> log.msg("hi") - a=1 event='hi' - >>> # You can also bind key/value pairs temporarily. - >>> with bound_threadlocal(b=2): - ... log.msg("hi") - a=1 b=2 event='hi' - >>> # Now it's gone again. - >>> log.msg("hi") - a=1 event='hi' - >>> # You can access the current thread-local state. - >>> get_threadlocal() - {'a': 1} - >>> # Or get it merged with a bound logger. - >>> get_merged_threadlocal(log.bind(example=True)) - {'a': 1, 'example': True} - >>> # And when we clear the thread-local state again, it goes away. - >>> clear_threadlocal() - >>> log.msg("hi there") - event='hi there' +- `structlog.contextvars.merge_contextvars` +- `structlog.contextvars.clear_contextvars` +- `structlog.contextvars.bind_contextvars` +- `structlog.contextvars.get_contextvars` +- `structlog.contextvars.get_merged_contextvars` Thread-local Contexts @@ -99,7 +49,8 @@ Thread-local Contexts ``structlog`` also provides thread-local context storage in a form that you may already know from `Flask `_ and that makes the *entire context* global to your thread or greenlet. -This makes its behavior more difficult to reason about which is why we generally recommend to use the `merge_threadlocal` route. +This makes its behavior more difficult to reason about which is why we generally recommend to use the `merge_contextvars` route. +Therefore, there are currently no plans to re-implement this behavior on top of context variables. Wrapped Dicts @@ -200,8 +151,29 @@ The convenience of having a thread-local context comes at a price though: See `configuration` for more details. - It `doesn't play well `_ with `os.fork` and thus `multiprocessing` (unless configured to use the ``spawn`` start method). -The general sentiment against thread-locals is that they're hard to test. -In this case we feel like this is an acceptable trade-off. -You can easily write deterministic tests using a call-capturing processor if you use the API properly (cf. warning above). -This big red box is also what separates immutable local from mutable global data. + +API +--- + +.. module:: structlog.threadlocal + +.. autofunction:: bind_threadlocal + +.. autofunction:: unbind_threadlocal + +.. autofunction:: bound_threadlocal + +.. autofunction:: get_threadlocal + +.. autofunction:: get_merged_threadlocal + +.. autofunction:: merge_threadlocal + +.. autofunction:: clear_threadlocal + +.. autofunction:: wrap_dict + +.. autofunction:: tmp_bind(logger, **tmp_values) + +.. autofunction:: as_immutable diff --git a/pyproject.toml b/pyproject.toml index 8afe7e98..52ce4b68 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -115,7 +115,7 @@ testpaths = "tests" filterwarnings = [ "once::Warning", ] -asyncio_mode = "strict" +asyncio_mode = "auto" [tool.coverage.run] @@ -129,6 +129,9 @@ source = ["src", ".tox/*/site-packages"] [tool.coverage.report] show_missing = true skip_covered = true +omit = [ + "src/structlog/_greenlets.py", +] exclude_lines = [ # a more strict default pragma "\\# pragma: no cover\\b", diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index 00d30c4e..5cf551e0 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -4,14 +4,19 @@ # repository for complete details. """ -Primitives to keep context global but thread (and greenlet) local. +**Deprecated** primitives to keep context global but thread (and greenlet) +local. -See `thread-local`. +See `thread-local`, but please use :doc:`contextvars` instead. + +.. deprecated:: 22.1.0 """ import contextlib +import sys import threading import uuid +import warnings from typing import Any, Dict, Generator, Iterator, Type, TypeVar @@ -33,12 +38,42 @@ def _determine_threadlocal() -> Type[Any]: return local - return GreenThreadLocal + return GreenThreadLocal # pragma: no cover ThreadLocal = _determine_threadlocal() +def _deprecated() -> None: + """ + Raise a warning with best-effort stacklevel adjustment. + """ + callsite = "" + try: + f = sys._getframe() + callsite = f.f_back.f_back.f_globals["__name__"] # type: ignore + except Exception: # pragma: no cover + pass + + # Avoid double warnings if TL functions call themselves. + if callsite == "structlog.threadlocal": + return + + stacklevel = 3 + # If a function is used as a decorator, we need to add two stack levels. + # This logic will probably break eventually, but it's not worth any more + # complexity. + if callsite == "contextlib": + stacklevel += 2 + + warnings.warn( + "`structlog.threadlocal` is deprecated, please use " + "`structlog.contextvars` instead.", + DeprecationWarning, + stacklevel=stacklevel, + ) + + def wrap_dict(dict_class: Type[Context]) -> Type[Context]: """ Wrap a dict-like class and return the resulting class. @@ -46,7 +81,10 @@ def wrap_dict(dict_class: Type[Context]) -> Type[Context]: The wrapped class and used to keep global in the current thread. :param dict_class: Class used for keeping context. + + .. deprecated:: 22.1.0 """ + _deprecated() Wrapped = type( "WrappedDict-" + str(uuid.uuid4()), (_ThreadLocalDictWrapper,), {} ) @@ -67,7 +105,10 @@ def as_immutable(logger: TLLogger) -> TLLogger: thread local state. :returns: :class:`~structlog.BoundLogger` with an immutable context. + + .. deprecated:: 22.1.0 """ + _deprecated() if isinstance(logger, BoundLoggerLazyProxy): logger = logger.bind() # type: ignore @@ -96,7 +137,10 @@ def tmp_bind( Only works with `structlog.threadlocal.wrap_dict`-based contexts. Use :func:`~structlog.threadlocal.bound_threadlocal` for new code. + + .. deprecated:: 22.1.0 """ + _deprecated() saved = as_immutable(logger)._context try: yield logger.bind(**tmp_values) # type: ignore @@ -181,7 +225,9 @@ def get_threadlocal() -> Context: Return a copy of the current thread-local context. .. versionadded:: 21.2.0 + .. deprecated:: 22.1.0 """ + _deprecated() return _get_context().copy() @@ -191,7 +237,9 @@ def get_merged_threadlocal(bound_logger: BindableLogger) -> Context: from *bound_logger*. .. versionadded:: 21.2.0 + .. deprecated:: 22.1.0 """ + _deprecated() ctx = _get_context().copy() ctx.update(structlog.get_context(bound_logger)) @@ -212,7 +260,10 @@ def merge_threadlocal( .. versionchanged:: 20.1.0 This function used to be called ``merge_threadlocal_context`` and that name is still kept around for backward compatibility. + + .. deprecated:: 22.1.0 """ + _deprecated() context = _get_context().copy() context.update(event_dict) @@ -231,7 +282,9 @@ def clear_threadlocal() -> None: request-handling code. .. versionadded:: 19.2.0 + .. deprecated:: 22.1.0 """ + _deprecated() _CONTEXT.context = {} @@ -243,7 +296,9 @@ def bind_threadlocal(**kw: Any) -> None: context to be global (thread-local). .. versionadded:: 19.2.0 + .. deprecated:: 22.1.0 """ + _deprecated() _get_context().update(kw) @@ -252,7 +307,9 @@ def unbind_threadlocal(*keys: str) -> None: Tries to remove bound *keys* from threadlocal logging context if present. .. versionadded:: 20.1.0 + .. deprecated:: 22.1.0 """ + _deprecated() context = _get_context() for key in keys: context.pop(key, None) @@ -267,7 +324,9 @@ def bound_threadlocal(**kw: Any) -> Generator[None, None, None]: Can be used as a context manager or decorator. .. versionadded:: 21.4.0 + .. deprecated:: 22.1.0 """ + _deprecated() context = get_threadlocal() saved = {k: context[k] for k in context.keys() & kw.keys()} diff --git a/tests/test_contextvars.py b/tests/test_contextvars.py index a64a6d47..4117ef35 100644 --- a/tests/test_contextvars.py +++ b/tests/test_contextvars.py @@ -24,10 +24,6 @@ ) -# All test coroutines will be treated as marked. -pytestmark = pytest.mark.asyncio - - @pytest.fixture(autouse=True) def _clear_contextvars(): """ diff --git a/tests/test_processors.py b/tests/test_processors.py index 723f8479..6258ea1e 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -305,9 +305,10 @@ def test_FallbackEncoder_handles_ThreadLocalDictWrapped_dicts(self): """ Our fallback handling handles properly ThreadLocalDictWrapper values. """ - s = json.dumps( - wrap_dict(dict)({"a": 42}), default=_json_fallback_handler - ) + with pytest.deprecated_call(): + d = wrap_dict(dict) + + s = json.dumps(d({"a": 42}), default=_json_fallback_handler) assert '{"a": 42}' == s diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py index 5ff70454..62d877f4 100644 --- a/tests/test_threadlocal.py +++ b/tests/test_threadlocal.py @@ -39,27 +39,30 @@ def _clear_threadlocal(): """ Make sure all tests start with a clean slate. """ - clear_threadlocal() + with pytest.deprecated_call(): + clear_threadlocal() -@pytest.fixture -def D(): +@pytest.fixture(name="D") +def _D(): """ Returns a dict wrapped in _ThreadLocalDictWrapper. """ - return wrap_dict(dict) + with pytest.deprecated_call(): + return wrap_dict(dict) -@pytest.fixture -def log(logger): +@pytest.fixture(name="log") +def _log(logger): """ Returns a ReturnLogger with a freshly wrapped dict. """ - return wrap_logger(logger, context_class=wrap_dict(dict)) + with pytest.deprecated_call(): + return wrap_logger(logger, context_class=wrap_dict(dict)) -@pytest.fixture -def logger(): +@pytest.fixture(name="logger") +def _logger(): """ Returns a simple logger stub with a *msg* method that takes one argument which gets returned. @@ -73,7 +76,7 @@ def test_bind(self, log): tmp_bind does not modify the thread-local state. """ log = log.bind(y=23) - with tmp_bind(log, x=42, y="foo") as tmp_log: + with pytest.deprecated_call(), tmp_bind(log, x=42, y="foo") as tmp_log: assert ( {"y": "foo", "x": 42} == tmp_log._context._dict @@ -86,7 +89,7 @@ def test_bind_exc(self, log): tmp_bind cleans up properly on exceptions. """ log = log.bind(y=23) - with pytest.raises(ValueError): + with pytest.raises(ValueError), pytest.deprecated_call(): with tmp_bind(log, x=42, y="foo") as tmp_log: assert ( {"y": "foo", "x": 42} @@ -104,7 +107,8 @@ def test_does_not_affect_global(self, log): A logger from as_mutable is independent from thread local state. """ log = log.new(x=42) - il = as_immutable(log) + with pytest.deprecated_call(): + il = as_immutable(log) assert isinstance(il._context, dict) @@ -118,7 +122,8 @@ def test_converts_proxy(self, log): as_immutable converts a BoundLoggerLazyProxy into a concrete bound logger. """ - il = as_immutable(log) + with pytest.deprecated_call(): + il = as_immutable(log) assert isinstance(il._context, dict) assert isinstance(il, BoundLoggerBase) @@ -127,9 +132,11 @@ def test_idempotency(self, log): """ as_immutable on an as_immutable logger works. """ - il = as_immutable(log) + with pytest.deprecated_call(): + il = as_immutable(log) - assert isinstance(as_immutable(il), BoundLoggerBase) + with pytest.deprecated_call(): + assert isinstance(as_immutable(il), BoundLoggerBase) class TestThreadLocalDict: @@ -138,8 +145,9 @@ def test_wrap_returns_distinct_classes(self): Each call to wrap_dict returns a distinct new class whose context is independent from others. """ - D1 = wrap_dict(dict) - D2 = wrap_dict(dict) + with pytest.deprecated_call(): + D1 = wrap_dict(dict) + D2 = wrap_dict(dict) assert D1 != D2 assert D1 is not D2 @@ -167,7 +175,8 @@ def run(self): self._d["tl"] = 23 - d = wrap_dict(dict)() + with pytest.deprecated_call(): + d = wrap_dict(dict)() d["tl"] = 42 t = TestThread(d) t.start() @@ -186,7 +195,8 @@ def test_context_is_global_to_thread(self, D): assert {"a": 42, "b": 23} == d1._dict == d2._dict == d3._dict assert d1 == d2 == d3 - D_ = wrap_dict(dict) + with pytest.deprecated_call(): + D_ = wrap_dict(dict) d_ = D_({"a": 42, "b": 23}) assert d1 != d_ @@ -230,7 +240,8 @@ def test_is_greenlet_local(self, D): """ Context is shared between greenlets. """ - d = wrap_dict(dict)() + with pytest.deprecated_call(): + d = wrap_dict(dict)() d["switch"] = 42 def run(): @@ -296,55 +307,70 @@ def test_bind_and_merge(self): Binding a variable causes it to be included in the result of merge_threadlocal. """ - bind_threadlocal(a=1) + with pytest.deprecated_call(): + bind_threadlocal(a=1) - assert {"a": 1, "b": 2} == merge_threadlocal(None, None, {"b": 2}) + with pytest.deprecated_call(): + assert {"a": 1, "b": 2} == merge_threadlocal(None, None, {"b": 2}) def test_clear(self): """ The thread-local context can be cleared, causing any previously bound variables to not be included in merge_threadlocal's result. """ - bind_threadlocal(a=1) - clear_threadlocal() + with pytest.deprecated_call(): + bind_threadlocal(a=1) + + with pytest.deprecated_call(): + clear_threadlocal() - assert {"b": 2} == merge_threadlocal(None, None, {"b": 2}) + with pytest.deprecated_call(): + assert {"b": 2} == merge_threadlocal(None, None, {"b": 2}) def test_merge_works_without_bind(self): """ merge_threadlocal returns values as normal even when there has been no previous calls to bind_threadlocal. """ - assert {"b": 2} == merge_threadlocal(None, None, {"b": 2}) + with pytest.deprecated_call(): + assert {"b": 2} == merge_threadlocal(None, None, {"b": 2}) def test_multiple_binds(self): """ Multiple calls to bind_threadlocal accumulate values instead of replacing them. """ - bind_threadlocal(a=1, b=2) - bind_threadlocal(c=3) + with pytest.deprecated_call(): + bind_threadlocal(a=1, b=2) + bind_threadlocal(c=3) - assert {"a": 1, "b": 2, "c": 3} == merge_threadlocal( - None, None, {"b": 2} - ) + with pytest.deprecated_call(): + assert {"a": 1, "b": 2, "c": 3} == merge_threadlocal( + None, None, {"b": 2} + ) def test_unbind_threadlocal(self): """ Test that unbinding from threadlocal works for keys that exist and does not raise error when they do not exist. """ - bind_threadlocal(a=234, b=34) + with pytest.deprecated_call(): + bind_threadlocal(a=234, b=34) - assert {"a": 234, "b": 34} == get_threadlocal() + with pytest.deprecated_call(): + assert {"a": 234, "b": 34} == get_threadlocal() - unbind_threadlocal("a") + with pytest.deprecated_call(): + unbind_threadlocal("a") - assert {"b": 34} == get_threadlocal() + with pytest.deprecated_call(): + assert {"b": 34} == get_threadlocal() - unbind_threadlocal("non-existing-key") + with pytest.deprecated_call(): + unbind_threadlocal("non-existing-key") - assert {"b": 34} == get_threadlocal() + with pytest.deprecated_call(): + assert {"b": 34} == get_threadlocal() def test_get_context_no_context(self): """ @@ -357,18 +383,21 @@ def test_get_context_no_context(self): with pytest.raises(AttributeError): _CONTEXT.context - assert {} == get_threadlocal() + with pytest.deprecated_call(): + assert {} == get_threadlocal() def test_get_merged(self): """ Returns a copy of the threadlocal context merged with the logger's context. """ - bind_threadlocal(x=1) + with pytest.deprecated_call(): + bind_threadlocal(x=1) log = structlog.get_logger().bind(y=2) - assert {"x": 1, "y": 2} == get_merged_threadlocal(log) + with pytest.deprecated_call(): + assert {"x": 1, "y": 2} == get_merged_threadlocal(log) class TestBoundThreadlocal: @@ -376,44 +405,55 @@ def test_cleanup(self): """ Bindings are cleaned up """ - with bound_threadlocal(x=42, y="foo"): - assert {"x": 42, "y": "foo"} == get_threadlocal() + with pytest.deprecated_call(): + with bound_threadlocal(x=42, y="foo"): + assert {"x": 42, "y": "foo"} == get_threadlocal() - assert {} == get_threadlocal() + with pytest.deprecated_call(): + assert {} == get_threadlocal() def test_cleanup_conflict(self): """ Overwritten keys are restored after the clean up """ - bind_threadlocal(x="original", z="unrelated") - with bound_threadlocal(x=42, y="foo"): - assert {"x": 42, "y": "foo", "z": "unrelated"} == get_threadlocal() + with pytest.deprecated_call(): + bind_threadlocal(x="original", z="unrelated") + with bound_threadlocal(x=42, y="foo"): + assert { + "x": 42, + "y": "foo", + "z": "unrelated", + } == get_threadlocal() - assert {"x": "original", "z": "unrelated"} == get_threadlocal() + with pytest.deprecated_call(): + assert {"x": "original", "z": "unrelated"} == get_threadlocal() def test_preserve_independent_bind(self): """ New bindings inside bound_threadlocal are preserved after the clean up """ - with bound_threadlocal(x=42): - bind_threadlocal(y="foo") - assert {"x": 42, "y": "foo"} == get_threadlocal() + with pytest.deprecated_call(): + with bound_threadlocal(x=42): + bind_threadlocal(y="foo") + assert {"x": 42, "y": "foo"} == get_threadlocal() - assert {"y": "foo"} == get_threadlocal() + with pytest.deprecated_call(): + assert {"y": "foo"} == get_threadlocal() def test_nesting_works(self): """ bound_threadlocal binds and unbinds even when nested """ - with bound_threadlocal(l1=1): - assert {"l1": 1} == get_threadlocal() + with pytest.deprecated_call(): + with bound_threadlocal(l1=1): + assert {"l1": 1} == get_threadlocal() - with bound_threadlocal(l2=2): - assert {"l1": 1, "l2": 2} == get_threadlocal() + with bound_threadlocal(l2=2): + assert {"l1": 1, "l2": 2} == get_threadlocal() - assert {"l1": 1} == get_threadlocal() + assert {"l1": 1} == get_threadlocal() - assert {} == get_threadlocal() + assert {} == get_threadlocal() def test_as_decorator(self): """ @@ -424,10 +464,15 @@ def test_as_decorator(self): @bound_threadlocal(x=42) def wrapped(arg1): """Wrapped documentation""" - bind_threadlocal(y=arg1) - assert {"x": 42, "y": arg1} == get_threadlocal() + with pytest.deprecated_call(): + bind_threadlocal(y=arg1) + + with pytest.deprecated_call(): + assert {"x": 42, "y": arg1} == get_threadlocal() - wrapped(23) + # I can't find a way for the warnings to be raised from the decorator. + with pytest.deprecated_call(): + wrapped(23) assert "wrapped" == wrapped.__name__ assert "(arg1)" == str(inspect.signature(wrapped)) diff --git a/tox.ini b/tox.ini index c9776035..4cb6ebcc 100644 --- a/tox.ini +++ b/tox.ini @@ -12,7 +12,7 @@ python = [tox] -envlist = pre-commit,mypy,cogCheck,cog,{py37,py38,py39,py310}-threads,py39-greenlets,py39-colorama,py310-be,py310-rich,docs,pypi-description,coverage-report +envlist = pre-commit,mypy,cogCheck,cog,py37,py38,py39,py310,py39-colorama,py310-be,py310-rich,docs,pypi-description,coverage-report isolated_build = True @@ -76,7 +76,7 @@ commands = python -m pytest {posargs} # For missing types -[testenv:py37-threads] +[testenv:py37] deps = twisted setenv = PYTHONHASHSEED = 0 @@ -84,7 +84,7 @@ commands = python -m coverage run -m pytest {posargs} -[testenv:py310-threads] +[testenv:py310] deps = twisted setenv = PYTHONHASHSEED = 0 @@ -93,15 +93,6 @@ commands = python -OO -m coverage run -m pytest tests/test_optimized.py -[testenv:py39-greenlets] -deps = - greenlet - twisted -setenv = - PYTHONHASHSEED = 0 -commands = python -m coverage run -m pytest {posargs} - - [testenv:py39-colorama] deps = colorama commands = python -m coverage run -m pytest tests/test_dev.py {posargs} @@ -122,7 +113,7 @@ basepython = python3.10 deps = coverage[toml] skip_install = true parallel_show_output = true -depends = py37-threads,py310-threads,py39-greenlets,py39-colorama,py310-be,py310-rich +depends = py37,py310,py39-colorama,py310-be,py310-rich commands = python -m coverage combine python -m coverage report From 881d84145fa8364596317ffd04ed54eb66fb17fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20B=C3=BCchler?= Date: Sat, 23 Apr 2022 11:06:01 +0200 Subject: [PATCH 0681/1520] Apply capture_logs to initialized bound loggers (#412) Fixes #408 --- CHANGELOG.md | 2 ++ src/structlog/testing.py | 16 +++++++++++++--- tests/test_testing.py | 30 ++++++++++++++++++++++++++++-- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b68702d..b034603f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,8 @@ So please make sure to **always** properly configure your applications. [#401](https://github.com/hynek/structlog/pull/401) - `structlog.PrintLogger` -- that is used by default -- now uses `print()` for printing, making it a better citizen for interactive terminal applications. [#399](https://github.com/hynek/structlog/pull/399) +- `structlog.testing.capture_logs` now works for already initialized bound loggers. + [#408](https://github.com/hynek/structlog/pull/412) ### Fixed diff --git a/src/structlog/testing.py b/src/structlog/testing.py index 1b62392f..075ab449 100644 --- a/src/structlog/testing.py +++ b/src/structlog/testing.py @@ -59,12 +59,22 @@ def capture_logs() -> Generator[List[EventDict], None, None]: .. versionadded:: 20.1.0 """ cap = LogCapture() - old_processors = get_config()["processors"] + # Modify `_Configuration.default_processors` set via `configure` but always + # keep the list instance intact to not break references held by bound + # loggers. + processors = get_config()["processors"] + old_processors = processors.copy() try: - configure(processors=[cap]) + # clear processors list and use LogCapture for testing + processors.clear() + processors.append(cap) + configure(processors=processors) yield cap.entries finally: - configure(processors=old_processors) + # remove LogCapture and restore original processors + processors.clear() + processors.extend(old_processors) + configure(processors=processors) class ReturnLogger: diff --git a/tests/test_testing.py b/tests/test_testing.py index ddbf70dd..99b4a75c 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -10,6 +10,7 @@ CapturedCall, CapturingLogger, CapturingLoggerFactory, + LogCapture, ReturnLogger, ReturnLoggerFactory, ) @@ -46,11 +47,16 @@ def test_restores_processors_on_success(self): exit. """ orig_procs = self.get_active_procs() + assert len(orig_procs) > 1 with testing.capture_logs(): - assert orig_procs is not self.get_active_procs() + modified_procs = self.get_active_procs() + assert len(modified_procs) == 1 + assert isinstance(modified_procs[0], LogCapture) - assert orig_procs is self.get_active_procs() + restored_procs = self.get_active_procs() + assert orig_procs is restored_procs + assert len(restored_procs) > 1 def test_restores_processors_on_error(self): """ @@ -64,6 +70,26 @@ def test_restores_processors_on_error(self): assert orig_procs is self.get_active_procs() + def test_captures_bound_logers(self): + """ + Even logs from already bound loggers are captured and their processors + restored on exit. + """ + logger = get_logger("bound").bind(foo="bar") + logger.info("ensure logger is bound") + + with testing.capture_logs() as logs: + logger.info("hello", answer=42) + + assert logs == [ + { + "event": "hello", + "answer": 42, + "foo": "bar", + "log_level": "info", + } + ] + class TestReturnLogger: # @pytest.mark.parametrize("method", stdlib_log_methods) From 223216e2bbde9d4c0cd8dda644e8b9c01136e366 Mon Sep 17 00:00:00 2001 From: zifot Date: Mon, 25 Apr 2022 19:44:32 +0200 Subject: [PATCH 0682/1520] Fix configuration example for stdlib (#414) * Fix configuration example for stdlib Those changes make the example directly copy-pastable * Use a set instead of a tuple to conform with project style guide Co-authored-by: Hynek Schlawack --- docs/standard-library.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/standard-library.rst b/docs/standard-library.rst index 3e788c68..115d575a 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -168,9 +168,11 @@ A basic configuration to output structured logs in JSON format looks like this: structlog.processors.UnicodeDecoder(), # Add callsite parameters. structlog.processors.CallsiteParameterAdder( - CallsiteParameter.FILENAME, - CallsiteParameter.FUNC_NAME, - CallsiteParameter.LINENO, + { + structlog.processors.CallsiteParameter.FILENAME, + structlog.processors.CallsiteParameter.FUNC_NAME, + structlog.processors.CallsiteParameter.LINENO, + } ), # Render the final event dict as JSON. structlog.processors.JSONRenderer() From 5cb5f8c228ac23a86d7e7aeb316b26d3134211f5 Mon Sep 17 00:00:00 2001 From: Florian Ludwig Date: Tue, 26 Apr 2022 09:48:09 +0200 Subject: [PATCH 0683/1520] add log() to BoundLoggerFiltering* (#413) Co-authored-by: Hynek Schlawack --- CHANGELOG.md | 3 ++- src/structlog/_log_levels.py | 10 ++++++++-- tests/test_log_levels.py | 16 ++++++++++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b034603f..5909e68f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,12 +41,13 @@ So please make sure to **always** properly configure your applications. [#403](https://github.com/hynek/structlog/pull/403) [#404](https://github.com/hynek/structlog/pull/404) - ### Changed - `structlog.make_filtering_bound_logger()` now returns a method with the same signature for all log levels, whether they are active or not. This ensures that invalid calls to inactive log levels are caught immediately and don't explode once the log level changes. [#401](https://github.com/hynek/structlog/pull/401) +- `structlog.make_filtering_bound_logger()` now returns a `log()` method to closer match BoundLogger signature + [#413](https://github.com/hynek/structlog/pull/413) - `structlog.PrintLogger` -- that is used by default -- now uses `print()` for printing, making it a better citizen for interactive terminal applications. [#399](https://github.com/hynek/structlog/pull/399) - `structlog.testing.capture_logs` now works for already initialized bound loggers. diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index a4c98bcd..43f53f35 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -9,7 +9,7 @@ import logging -from typing import Any, Callable, Type +from typing import Any, Callable, Dict, Type from ._base import BoundLoggerBase from .types import EventDict, FilteringBoundLogger @@ -127,7 +127,13 @@ def meth(self: Any, event: str, **kw: Any) -> Any: return meth - meths = {} + def log(self: Any, level: int, event: str, **kw: Any) -> Any: + if level < min_level: + return None + name = _LEVEL_TO_NAME[level] + return self._proxy_to_logger(name, event, **kw) + + meths: Dict[str, Callable] = {"log": log} for lvl, name in _LEVEL_TO_NAME.items(): meths[name] = make_method(lvl) diff --git a/tests/test_log_levels.py b/tests/test_log_levels.py index 1c648e13..42528876 100644 --- a/tests/test_log_levels.py +++ b/tests/test_log_levels.py @@ -40,6 +40,22 @@ def test_one_below(self, bl, cl): assert [] == cl.calls + def test_log_exact_level(self, bl, cl): + """ + if log level is exactly the min_level, log. + """ + bl.log(logging.INFO, "yep") + + assert [("info", (), {"event": "yep"})] == cl.calls + + def test_log_one_below(self, bl, cl): + """ + if log level is below the min_level, don't log. + """ + bl.log(logging.DEBUG, "nope") + + assert [] == cl.calls + def test_filter_bound_below_missing_event_string(self, bl, cl): """ Missing event arg causes exception below min_level. From ac4d9ad443bf3e0aec7592153d858b3ba8155279 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 26 Apr 2022 09:53:55 +0200 Subject: [PATCH 0684/1520] Add docs for #413 --- CHANGELOG.md | 5 +++-- src/structlog/_log_levels.py | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5909e68f..45c44e9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,14 +40,15 @@ So please make sure to **always** properly configure your applications. It works the way `PrintLogger` used to work in previous versions. [#403](https://github.com/hynek/structlog/pull/403) [#404](https://github.com/hynek/structlog/pull/404) +- `structlog.make_filtering_bound_logger()`-returned loggers now also have a `log()` method to match the `structlog.stdlib.BoundLogger` signature closer. + [#413](https://github.com/hynek/structlog/pull/413) + ### Changed - `structlog.make_filtering_bound_logger()` now returns a method with the same signature for all log levels, whether they are active or not. This ensures that invalid calls to inactive log levels are caught immediately and don't explode once the log level changes. [#401](https://github.com/hynek/structlog/pull/401) -- `structlog.make_filtering_bound_logger()` now returns a `log()` method to closer match BoundLogger signature - [#413](https://github.com/hynek/structlog/pull/413) - `structlog.PrintLogger` -- that is used by default -- now uses `print()` for printing, making it a better citizen for interactive terminal applications. [#399](https://github.com/hynek/structlog/pull/399) - `structlog.testing.capture_logs` now works for already initialized bound loggers. diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index 43f53f35..e15726a3 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -84,6 +84,9 @@ def make_filtering_bound_logger(min_level: int) -> Type[FilteringBoundLogger]: The logger is optimized such that log levels below *min_level* only consist of a ``return None``. + Additionally it has a ``log(self, level: int, **kw: Any)`` method to mirror + `logging.Logger.log` and `structlog.stdlib.BoundLogger.log`. + Compared to using ``structlog``'s standard library integration and the `structlog.stdlib.filter_by_level` processor: @@ -101,6 +104,7 @@ def make_filtering_bound_logger(min_level: int) -> Type[FilteringBoundLogger]: .. versionadded:: 20.2.0 .. versionchanged:: 21.1.0 The returned loggers are now pickleable. + .. versionadded:: 20.1.0 The ``log()`` method. """ return _LEVEL_TO_FILTERING_LOGGER[min_level] From d386e08394980dd09651c0dfa3e7e7ccab8df89d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 2 May 2022 11:42:48 -0600 Subject: [PATCH 0685/1520] [pre-commit.ci] pre-commit autoupdate (#416) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v2.31.1 → v2.32.0](https://github.com/asottile/pyupgrade/compare/v2.31.1...v2.32.0) - [github.com/pre-commit/pre-commit-hooks: v4.1.0 → v4.2.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.1.0...v4.2.0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0ae70d3d..21689a60 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: black - repo: https://github.com/asottile/pyupgrade - rev: v2.31.1 + rev: v2.32.0 hooks: - id: pyupgrade args: [--py37-plus] @@ -28,7 +28,7 @@ repos: exclude: docs/code_examples - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.1.0 + rev: v4.2.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer From 3b792a0ad93b557cf8b07c80e41a8225b410cb43 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 13 May 2022 07:36:53 +0200 Subject: [PATCH 0686/1520] Replace threadlocals by contextvars in performance.rst --- docs/performance.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/performance.rst b/docs/performance.rst index 87c05d43..024b871e 100644 --- a/docs/performance.rst +++ b/docs/performance.rst @@ -61,7 +61,7 @@ Here's an example for a production-ready non-asyncio ``structlog`` configuration cache_logger_on_first_use=True, wrapper_class=structlog.make_filtering_bound_logger(logging.INFO), processors=[ - structlog.threadlocal.merge_threadlocal, + structlog.contextvars.merge_contextvars, structlog.processors.add_log_level, structlog.processors.format_exc_info, structlog.processors.TimeStamper(fmt="iso", utc=True), @@ -75,7 +75,7 @@ It has the following properties: - Caches all loggers on first use. - Filters all log entries below the ``info`` log level **very** efficiently. The ``debug`` method literally consists of ``return None``. -- Supports `thread-local`. +- Supports :doc:`contextvars` (thread-local contexts). - Adds the log level name. - Renders exceptions. - Adds an `ISO 8601 `_ timestamp under the ``timestamp`` key in the UTC timezone. From 0eb3449fd316f97ede8790b171c57c9fcf5ff981 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 13 May 2022 07:42:03 +0200 Subject: [PATCH 0687/1520] Separate Token section --- docs/contextvars.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/contextvars.rst b/docs/contextvars.rst index bf58d1fd..9fa9c8b8 100644 --- a/docs/contextvars.rst +++ b/docs/contextvars.rst @@ -78,6 +78,9 @@ We're sorry the word *context* means three different things in this itemization event='hi there' a=None +Support for contextvars.Token +----------------------------- + If e.g. your request handler calls a helper function that needs to temporarily override some contextvars before restoring them back to their original values, you can use the :class:`~contextvars.Token`\s returned by :func:`~structlog.contextvars.bind_contextvars` along with :func:`~structlog.contextvars.reset_contextvars` to accomplish this (much like how :meth:`contextvars.ContextVar.reset` works): .. code-block:: python From 159f3b20f98c14e76af3d78a4283c88962d7a919 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 14 May 2022 13:21:57 +0200 Subject: [PATCH 0688/1520] Fix JSONRenderer's API docs Co-authored-by: Stefan Scherfke --- src/structlog/processors.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 78c764d1..309bf195 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -287,17 +287,16 @@ def __call__( class JSONRenderer: """ - Render the ``event_dict`` using ``serializer(event_dict, **json_kw)``. + Render the ``event_dict`` using ``serializer(event_dict, **dumps_kw)``. - :param json_kw: Are passed unmodified to *serializer*. If *default* + :param dumps_kw: Are passed unmodified to *serializer*. If *default* is passed, it will disable support for ``__structlog__``-based serialization. :param serializer: A :func:`json.dumps`-compatible callable that will be used to format the string. This can be used to use alternative - JSON encoders like `simplejson - `_ or `RapidJSON - `_ (faster but Python - 3-only) (default: :func:`json.dumps`). + JSON encoders like `orjson `__ or + `RapidJSON `_ (default: + :func:`json.dumps`). .. versionadded:: 0.2.0 Support for ``__structlog__`` serialization method. From 7e981d05abad610504f9c472bd867976dbbf5ae7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 19 May 2022 07:43:29 +0200 Subject: [PATCH 0689/1520] Use proper endashes --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45c44e9e..879e93b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,7 +36,7 @@ So please make sure to **always** properly configure your applications. - `structlog.processors.StackInfoRenderer` now has an *additional_ignores* parameter that allows you to filter out your own logging layer. [#396](https://github.com/hynek/structlog/issues/396) -- Added `structlog.WriteLogger`, a faster -- but more low-level -- alternative to `structlog.PrintLogger`. +- Added `structlog.WriteLogger`, a faster – but more low-level – alternative to `structlog.PrintLogger`. It works the way `PrintLogger` used to work in previous versions. [#403](https://github.com/hynek/structlog/pull/403) [#404](https://github.com/hynek/structlog/pull/404) @@ -49,7 +49,7 @@ So please make sure to **always** properly configure your applications. - `structlog.make_filtering_bound_logger()` now returns a method with the same signature for all log levels, whether they are active or not. This ensures that invalid calls to inactive log levels are caught immediately and don't explode once the log level changes. [#401](https://github.com/hynek/structlog/pull/401) -- `structlog.PrintLogger` -- that is used by default -- now uses `print()` for printing, making it a better citizen for interactive terminal applications. +- `structlog.PrintLogger` – that is used by default – now uses `print()` for printing, making it a better citizen for interactive terminal applications. [#399](https://github.com/hynek/structlog/pull/399) - `structlog.testing.capture_logs` now works for already initialized bound loggers. [#408](https://github.com/hynek/structlog/pull/412) From 78b2f0ad16d451475bb5c3181f32b2d9c8a6a8ef Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 20 May 2022 07:46:06 +0200 Subject: [PATCH 0690/1520] Add clarifications to changelog --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 879e93b5..a9f7c157 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,11 @@ So please make sure to **always** properly configure your applications. - The entire `structlog.threadlocal` module is deprecated. Please use the primitives from `structlog.contextvars` instead. + + If you're using the modern APIs (`bind_threadlocal()` / `merge_threadlocal()`) it's enough to replace them 1:1 with their `contextvars` counterparts. + The old approach around `wrap_dict()` has been discouraged for a while. + + Currently there are no concrete plans to remove the module, but no patches against it will be accepted from now on. [#409](https://github.com/hynek/structlog/pull/409) @@ -60,7 +65,7 @@ So please make sure to **always** properly configure your applications. - Overloaded the `bind`, `unbind`, `try_unbind` and `new` methods in the `FilteringBoundLogger` [Protocol](https://docs.python.org/3/library/typing.html#typing.Protocol). This makes it easier to use objects of type `FilteringBoundLogger` in a typed context. [#392](https://github.com/hynek/structlog/pull/392) -- Monkeypatched `sys.stdout`s are now handled more gracefully. +- Monkeypatched `sys.stdout`s are now handled more gracefully by `ConsoleRenderer` (that's used by default). [#404](https://github.com/hynek/structlog/pull/404) From 1012f5606b356d4fe1a9027513602c758bf51ab8 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 20 May 2022 10:28:47 +0200 Subject: [PATCH 0691/1520] Add support for 3.11-beta (#418) --- .github/workflows/main.yml | 2 +- tests/test_processors.py | 3 ++- tests/test_threadlocal.py | 5 ++++- tox.ini | 5 +++-- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 02664cad..66ef3e33 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -21,7 +21,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.7", "3.8", "3.9", "3.10"] + python-version: ["3.7", "3.8", "3.9", "3.10", "3.11.0-beta - 3.11"] steps: - uses: actions/checkout@v3 diff --git a/tests/test_processors.py b/tests/test_processors.py index 6258ea1e..8658ed6e 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -494,7 +494,8 @@ def test_gets_exc_info_on_bool(self): d = format_exc_info(None, None, {"exc_info": True}) assert "exc_info" not in d - assert 'raise ValueError("test")\nValueError: test' in d["exception"] + assert 'raise ValueError("test")' in d["exception"] + assert "ValueError: test" in d["exception"] def test_exception_on_py3(self, monkeypatch): """ diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py index 62d877f4..eac054c4 100644 --- a/tests/test_threadlocal.py +++ b/tests/test_threadlocal.py @@ -273,7 +273,10 @@ def test_delattr_missing(self, D): with pytest.raises(AttributeError) as e: d._tl.__delattr__("does_not_exist") - assert "does_not_exist" == e.value.args[0] + assert e.value.args[0] in ( + "does_not_exist", + "'_thread._local' object has no attribute 'does_not_exist'", + ) def test_del(self, D): """ diff --git a/tox.ini b/tox.ini index 4cb6ebcc..14b4733d 100644 --- a/tox.ini +++ b/tox.ini @@ -9,10 +9,11 @@ python = 3.8: py38, mypy 3.9: py39, mypy 3.10: py310, mypy, cogCheck, docs + 3.11: py311 [tox] -envlist = pre-commit,mypy,cogCheck,cog,py37,py38,py39,py310,py39-colorama,py310-be,py310-rich,docs,pypi-description,coverage-report +envlist = pre-commit,mypy,cogCheck,cog,py37,py38,py39,py310,py39-colorama,py310-be,py310-rich,py311,docs,pypi-description,coverage-report isolated_build = True @@ -69,7 +70,7 @@ commands = python -m cogapp --check -P pyproject.toml [testenv] extras = tests deps = - threads,colorama: twisted + colorama: twisted setenv = PYTHONHASHSEED = 0 commands = python -m pytest {posargs} From caad9df405ad41dc61639af2518b4c5634cb94f3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 6 Jun 2022 19:59:21 +0200 Subject: [PATCH 0692/1520] [pre-commit.ci] pre-commit autoupdate (#422) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 21689a60..2c3b5379 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: black - repo: https://github.com/asottile/pyupgrade - rev: v2.32.0 + rev: v2.32.1 hooks: - id: pyupgrade args: [--py37-plus] From 14d2bd7427222b4d6ee399114de806e25607584f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 29 Jun 2022 12:50:56 +0200 Subject: [PATCH 0693/1520] Clean docs of thread-local examples and mentions --- docs/code_examples/flask_/webapp.py | 6 +++--- docs/examples.rst | 10 +++++----- docs/getting-started.rst | 2 +- docs/loggers.rst | 3 +-- docs/why.rst | 2 +- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/docs/code_examples/flask_/webapp.py b/docs/code_examples/flask_/webapp.py index 3940e9bd..34fde75a 100644 --- a/docs/code_examples/flask_/webapp.py +++ b/docs/code_examples/flask_/webapp.py @@ -17,8 +17,8 @@ def some_route(): # You would put this into some kind of middleware or processor so it's set # automatically for all requests in all views. - structlog.threadlocal.clear_threadlocal() - structlog.threadlocal.bind_threadlocal( + structlog.contextvars.clear_contextvars() + structlog.contextvars.bind_contextvars( view=flask.request.path, request_id=str(uuid.uuid4()), peer=flask.request.access_route[0], @@ -41,7 +41,7 @@ def some_route(): ) structlog.configure( processors=[ - structlog.threadlocal.merge_threadlocal, # <--!!! + structlog.contextvars.merge_contextvars, # <--!!! structlog.processors.KeyValueRenderer( key_order=["event", "view", "peer"] ), diff --git a/docs/examples.rst b/docs/examples.rst index 996b68b2..d7f2afe4 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -9,7 +9,7 @@ This chapter is intended to give you a taste of realistic usage of ``structlog`` Flask and Thread-Local Data --------------------------- -Let's assume you want to bind a unique request ID, the URL path, and the peer's IP to every log entry: +Let's assume you want to bind a unique request ID, the URL path, and the peer's IP to every log entry by storing it in thread-local storage that is managed by context variables: .. literalinclude:: code_examples/flask_/webapp.py :language: python @@ -30,12 +30,12 @@ As you can see, ``view``, ``peer``, and ``request_id`` are present in **both** l While wrapped loggers are *immutable* by default, this example demonstrates how to circumvent that using a thread-local storage for request-wide context: -1. `structlog.threadlocal.clear_threadlocal()` ensures the thread-local storage is empty for each request. -2. `structlog.threadlocal.bind_threadlocal()` puts your key-value pairs into thread-local storage. -3. The `structlog.threadlocal.merge_threadlocal()` processor merges the thread-local context into the event dict. +1. `structlog.contextvars.clear_contextvars()` ensures the thread-local storage is empty for each request. +2. `structlog.contextvars.bind_contextvars()` puts your key-value pairs into thread-local storage. +3. The `structlog.contextvars.merge_contextvars()` processor merges the thread-local context into the event dict. Please note that the ``user`` field is only present in the view because it wasn't bound into the thread-local storage. -See `thread-local` for more details. +See :doc:`contextvars` for more details. ---- diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 786d5df8..42c3bbe2 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -113,7 +113,7 @@ For ``structlog``, a log entry is just a dictionary called *event dict[ionary]*: Convenient key-value-based logging is great to have on its own. - Python keeps dictionaries ordered by keys by default. - The recommended way of binding values is the one in these examples: creating new loggers with a new context. - If you're okay with giving up immutable local state for convenience, you can also use `thread/greenlet local storage ` or :doc:`context variables ` for the context. + If you're okay with giving up immutable local state for convenience, you can also use :doc:`context variables ` for the context. Manipulating Log Entries in Flight diff --git a/docs/loggers.rst b/docs/loggers.rst index d4f369c0..fddc2fa9 100644 --- a/docs/loggers.rst +++ b/docs/loggers.rst @@ -14,7 +14,7 @@ It consists of three parts: #. A *context dictionary* that you can *bind* key/value pairs to. This dictionary is *merged* into each log entry that is logged from *this logger specifically*. - That means that every logger has it own context, but it is possible to have global contexts too using `thread-local data ` and :doc:`contextvars`. + That means that every logger has it own context, but it is possible to have global contexts using :doc:`context variables `. #. A list of :doc:`processors ` that are called on every log entry. #. And finally a *logger* that it's wrapping. This wrapped logger is reponsible for the *output* of the log entry that has been returned by the last processor. @@ -99,7 +99,6 @@ As you can see, it accepts one mandatory and a few optional arguments: **context_class** The class to save your context in. - Particularly useful for `thread-local context storage `. Since all supported Python versions have ordered dictionaries, the default is a plain `dict`. diff --git a/docs/why.rst b/docs/why.rst index 18a25f7d..3856af8e 100644 --- a/docs/why.rst +++ b/docs/why.rst @@ -48,7 +48,7 @@ Since log entries are dictionaries, you can start binding and re-binding key/val >>> log.info("user.logged_in", happy=True) 2020-11-18 09:18.28 [info ] user.logged_in another_key=42 happy=True some_key=23 user=hynek -You can also bind key/value pairs to `thread-local storage `_ and `contextvars `_. +You can also bind key/value pairs to :doc:`context variables ` that look global, but are local to your thread or *asyncio* context (i.e. often your request). Powerful Pipelines From 29999de658568a3de45d1514349f6ffcca585bad Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 29 Jun 2022 12:54:13 +0200 Subject: [PATCH 0694/1520] Clarify no need for other loggers --- docs/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index 13f35ad2..b92fc3b6 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -40,7 +40,7 @@ Basics Integration with Existing Systems --------------------------------- -``structlog`` can be used immediately with *any* existing logger. +``structlog`` can be used immediately with *any* existing logger, or with the one with that it ships. However it comes with special wrappers for the Python standard library and Twisted that are optimized for their respective underlying loggers and contain less magic. .. toctree:: From a8936b9a6f07b5da55c4c28fc73dfab30c20a06d Mon Sep 17 00:00:00 2001 From: Stefan Scherfke Date: Wed, 29 Jun 2022 13:10:27 +0200 Subject: [PATCH 0695/1520] Add traceback parser for structured tracebacks (#407) * Add traceback parser for structured tracebacks * Make format_exception extensible with formatters * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update src/structlog/processors.py Co-authored-by: Hynek Schlawack * Fix tests and docstrings * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fix more test issues * Run pytest with "-vv" for debugging purposes * Fix * Add documentation * Add a changelog entry * Add typing examples * Add json_tracebacks() shortcut * Remove -vv for pytest in tox.ini * Update CHANGELOG.md Co-authored-by: Hynek Schlawack * Update CHANGELOG.md Co-authored-by: Hynek Schlawack * Rename JSONFormatter to DictFormatter * Apply final fixes * Rename some *Formatter classes to sth. better Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Hynek Schlawack --- CHANGELOG.md | 7 + docs/api.rst | 55 +++- docs/logging-best-practices.rst | 36 ++ src/structlog/__init__.py | 2 + src/structlog/dev.py | 4 +- src/structlog/processors.py | 93 +++++- src/structlog/tracebacks.py | 261 +++++++++++++++ src/structlog/types.py | 26 +- tests/test_processors.py | 52 ++- tests/test_tracebacks.py | 563 ++++++++++++++++++++++++++++++++ typing_examples.py | 18 + 11 files changed, 1078 insertions(+), 39 deletions(-) create mode 100644 src/structlog/tracebacks.py create mode 100644 tests/test_tracebacks.py diff --git a/CHANGELOG.md b/CHANGELOG.md index a9f7c157..87ae7a0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,10 @@ So please make sure to **always** properly configure your applications. [#404](https://github.com/hynek/structlog/pull/404) - `structlog.make_filtering_bound_logger()`-returned loggers now also have a `log()` method to match the `structlog.stdlib.BoundLogger` signature closer. [#413](https://github.com/hynek/structlog/pull/413) +- Added structured logging of tracebacks via the `structlog.tracebacks` module, + and most notably the `structlog.tracebacks.ExceptionDictTransformer` which can be used with the new `structlog.processors.ExceptionRenderer` to render JSON tracebacks. + [#407](https://github.com/hynek/structlog/pull/407) +- `structlog.processors.format_exc_info()` is no longer a function, but an instance of `structlog.processors.ExceptionRenderer`. ### Changed @@ -58,6 +62,9 @@ So please make sure to **always** properly configure your applications. [#399](https://github.com/hynek/structlog/pull/399) - `structlog.testing.capture_logs` now works for already initialized bound loggers. [#408](https://github.com/hynek/structlog/pull/412) +- `structlog.processors.format_exc_info()` is no longer a function, but an instance of `structlog.processors.ExceptionRenderer`. + Its behavior has not changed. + [#407](https://github.com/hynek/structlog/pull/407) ### Fixed diff --git a/docs/api.rst b/docs/api.rst index 723eaf12..471ca9a2 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -170,6 +170,27 @@ API Reference If you choose to pass a *default* parameter as part of *json_kw*, support for ``__structlog__`` is disabled. This can be useful when used together with more elegant serialization methods like :func:`functools.singledispatch`: `Better Python Object Serialization `_. + .. tip:: + + If you use this processor, you may also wish to add structured tracebacks for exceptions. + You can do this by adding the :class:`~structlog.processors.dict_tracebacks` to your list of processors: + + .. doctest:: + + >>> structlog.configure( + ... processors=[ + ... structlog.processors.dict_tracebacks, + ... structlog.processors.JSONRenderer(), + ... ], + ... ) + >>> log = structlog.get_logger() + >>> var = "spam" + >>> try: + ... 1 / 0 + ... except ZeroDivisionError: + ... log.exception("Cannot compute!") + {"event": "Cannot compute!", "exception": [{"exc_type": "ZeroDivisionError", "exc_value": "division by zero", "syntax_error": null, "is_cause": false, "frames": [{"filename": "", "lineno": 2, "name": "", "line": "", "locals": {..., "var": "spam"}}]}]} + .. autoclass:: KeyValueRenderer .. doctest:: @@ -198,6 +219,8 @@ API Reference .. autoclass:: UnicodeEncoder +.. autoclass:: ExceptionRenderer + .. autofunction:: format_exc_info .. doctest:: @@ -209,6 +232,17 @@ API Reference ... format_exc_info(None, None, {"exc_info": True}) # doctest: +ELLIPSIS {'exception': 'Traceback (most recent call last):... +.. autofunction:: dict_tracebacks + + .. doctest:: + + >>> from structlog.processors import dict_tracebacks + >>> try: + ... raise ValueError("onoes") + ... except ValueError: + ... dict_tracebacks(None, None, {"exc_info": True}) # doctest: +ELLIPSIS + {'exception': [{'exc_type': 'ValueError', 'exc_value': 'onoes', ..., 'frames': [{'filename': ... + .. autoclass:: StackInfoRenderer .. autoclass:: ExceptionPrettyPrinter @@ -264,6 +298,19 @@ API Reference :members: wrap_for_formatter, remove_processors_meta +`structlog.tracebacks` Module +----------------------------- + +.. automodule:: structlog.tracebacks + +.. autofunction:: extract +.. autoclass:: ExceptionDictTransformer +.. autoclass:: Trace +.. autoclass:: Stack +.. autoclass:: Frame +.. autoclass:: SyntaxError_ + + `structlog.types` Module ------------------------ @@ -290,12 +337,18 @@ API Reference Currently Sphinx has no support for Protocols, so please click ``[source]`` for this entry to see the full definition. +.. autoclass:: ExceptionTransformer + + .. note:: + + Currently Sphinx has no support for Protocols, so please click ``[source]`` for this entry to see the full definition. + .. autodata:: EventDict .. autodata:: WrappedLogger .. autodata:: Processor .. autodata:: Context .. autodata:: ExcInfo -.. autodata:: ExceptionFormatter +.. autodata:: ExceptionRenderer `structlog.twisted` Module diff --git a/docs/logging-best-practices.rst b/docs/logging-best-practices.rst index 20fa5ced..c9e68f11 100644 --- a/docs/logging-best-practices.rst +++ b/docs/logging-best-practices.rst @@ -27,6 +27,42 @@ The less noise, the more insights. At Stripe, this concept is called `Canonical Log Lines `_. +Pretty Printing vs. Structured Output +===================================== + +Colorful and pretty printed log messages are nice during development when you locally run your code. + +However, in production you should emit structured output (like JSON) which is a lot easier to parse by log aggregators. +Since you already log in a structured way, writing JSON output with structlogs comes very naturally. +You can even generate structured exception tracebacks. +This makes analyzing errors easier, since log aggregators can render JSON much better than multiline strings with a lot escaped quotation marks. + +Here is a simple example of how you can have pretty logs during development and JSON output when your app is running in a production context: + +.. doctest:: + + >>> import sys + >>> import structlog + >>> + >>> shared_processors = [ + ... # Processors that have nothing to do with output, + ... # e.g., add timestamps or log level names. + ... ] + >>> if sys.stderr.isatty(): + ... # Pretty printing when we run in a terminal session. + ... # Automatically prints pretty tracebacks when "rich" is installed + ... processors = shared_processors + [ + ... structlog.dev.ConsoleRenderer(), + ... ] + ... else: + ... # Print JSON when we run, e.g., in a Docker container. + ... # Also print structured tracebacks. + ... processors = shared_processors + [ + ... structlog.processors.dict_tracebacks, + ... structlog.processors.JSONRenderer(), + ... ] + >>> structlog.configure(processors) + Centralized Logging =================== diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 0b0a0813..af96227d 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -14,6 +14,7 @@ stdlib, testing, threadlocal, + tracebacks, types, ) from structlog._base import BoundLoggerBase, get_context @@ -87,6 +88,7 @@ "stdlib", "testing", "threadlocal", + "tracebacks", "twisted", "types", "wrap_logger", diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 7f932924..70152f0d 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -18,7 +18,7 @@ from ._frames import _format_exception from .types import ( EventDict, - ExceptionFormatter, + ExceptionRenderer, ExcInfo, Protocol, WrappedLogger, @@ -277,7 +277,7 @@ def __init__( force_colors: bool = False, repr_native_str: bool = False, level_styles: Optional[Styles] = None, - exception_formatter: ExceptionFormatter = default_exception_formatter, + exception_formatter: ExceptionRenderer = default_exception_formatter, sort_keys: bool = True, ): styles: Styles diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 309bf195..1292eaf8 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -41,7 +41,8 @@ ) from ._log_levels import _NAME_TO_LEVEL, add_log_level from ._utils import get_processname -from .types import EventDict, ExcInfo, WrappedLogger +from .tracebacks import ExceptionDictTransformer +from .types import EventDict, ExceptionTransformer, ExcInfo, WrappedLogger __all__ = [ @@ -53,6 +54,7 @@ "UnicodeDecoder", "JSONRenderer", "format_exc_info", + "dict_tracebacks", "ExceptionPrettyPrinter", "StackInfoRenderer", "CallsiteParameter", @@ -343,30 +345,83 @@ def _json_fallback_handler(obj: Any) -> Any: return repr(obj) -def format_exc_info( - logger: WrappedLogger, name: str, event_dict: EventDict -) -> EventDict: +class ExceptionRenderer: """ - Replace an ``exc_info`` field by an ``exception`` string field: + Replace an ``exc_info`` field with an ``exception`` field which is rendered + by *exception_formatter*. - If *event_dict* contains the key ``exc_info``, there are two possible + The contents of the ``exception`` field depends on the return value of the + :class:`.ExceptionTransformer` that is used: + + - The default produces a formatted string via Python's built-in traceback + formatting. + - The :class:`~structlog.tracebacks.ExceptionDictTransformer` a list of + stack dicts that can be serialized to JSON. + + If *event_dict* contains the key ``exc_info``, there are three possible behaviors: - - If the value is a tuple, render it into the key ``exception``. - - If the value is an Exception render it into the key ``exception``. - - If the value true but no tuple, obtain exc_info ourselves and render - that. + 1. If the value is a tuple, render it into the key ``exception``. + 2. If the value is an Exception render it into the key ``exception``. + 3. If the value true but no tuple, obtain exc_info ourselves and render + that. If there is no ``exc_info`` key, the *event_dict* is not touched. This behavior is analogue to the one of the stdlib's logging. + + :param exception_formatter: A callable that is used to format the exception + from the ``exc_info`` field. + + .. versionadded:: 22.1 """ - exc_info = event_dict.pop("exc_info", None) - if exc_info: - event_dict["exception"] = _format_exception( - _figure_out_exc_info(exc_info) - ) - return event_dict + def __init__( + self, + exception_formatter: ExceptionTransformer = _format_exception, + ) -> None: + self.format_exception = exception_formatter + + def __call__( + self, logger: WrappedLogger, name: str, event_dict: EventDict + ) -> EventDict: + exc_info = event_dict.pop("exc_info", None) + if exc_info: + event_dict["exception"] = self.format_exception( + _figure_out_exc_info(exc_info) + ) + + return event_dict + + +format_exc_info = ExceptionRenderer() +""" +Replace an ``exc_info`` field with an ``exception`` string field using +Python's built-in traceback formatting. + +If *event_dict* contains the key ``exc_info``, there are three possible +behaviors: + +1. If the value is a tuple, render it into the key ``exception``. +2. If the value is an Exception render it into the key ``exception``. +3. If the value is true but no tuple, obtain exc_info ourselves and render + that. + +If there is no ``exc_info`` key, the *event_dict* is not touched. +This behavior is analogue to the one of the stdlib's logging. +""" + +dict_tracebacks = ExceptionRenderer(ExceptionDictTransformer()) +""" +Replace an ``exc_info`` field with an ``exception`` field containing structured +tracebacks suiteable for, e.g., JSON output. + +It is a shortcut for :class:`ExceptionRenderer` with a +:class:`~structlog.tracebacks.ExceptionDictTransformer`. + +The treatment of the ``exc_info`` key is identical to `format_exc_info`. + +.. versionadded:: 22.1 +""" class TimeStamper: @@ -499,7 +554,11 @@ class ExceptionPrettyPrinter: Added support for passing exceptions as ``exc_info`` on Python 3. """ - def __init__(self, file: Optional[TextIO] = None) -> None: + def __init__( + self, + file: Optional[TextIO] = None, + exception_formatter: ExceptionTransformer = _format_exception, + ) -> None: if file is not None: self._file = file else: diff --git a/src/structlog/tracebacks.py b/src/structlog/tracebacks.py new file mode 100644 index 00000000..66817e08 --- /dev/null +++ b/src/structlog/tracebacks.py @@ -0,0 +1,261 @@ +""" +Extract a structured traceback from an exception. + +Copied and adapted from Rich: +https://github.com/Textualize/rich/blob/972dedff/rich/traceback.py +""" +import os + +from dataclasses import asdict, dataclass, field +from traceback import walk_tb +from types import TracebackType +from typing import Any, Dict, List, Optional, Tuple, Type, Union + +from .types import ExcInfo + + +__all__ = [ + "ExceptionDictTransformer", + "Frame", + "Stack", + "SyntaxError_", + "Trace", + "extract", + "safe_str", + "to_repr", +] + + +SHOW_LOCALS = True +LOCALS_MAX_STRING = 80 +MAX_FRAMES = 50 + +OptExcInfo = Union[ExcInfo, Tuple[None, None, None]] + + +@dataclass +class Frame: + """ + Represents a single stack frame. + """ + + filename: str + lineno: int + name: str + line: str = "" + locals: Optional[Dict[str, str]] = None + + +@dataclass +class SyntaxError_: + """ + Contains detailed information about :exc:`SyntaxError` exceptions. + """ + + offset: int + filename: str + line: str + lineno: int + msg: str + + +@dataclass +class Stack: + """ + Represents an exception and a list of stack frames. + """ + + exc_type: str + exc_value: str + syntax_error: Optional[SyntaxError_] = None + is_cause: bool = False + frames: List[Frame] = field(default_factory=list) + + +@dataclass +class Trace: + """ + Container for a list of stack traces. + """ + + stacks: List[Stack] + + +def safe_str(_object: Any) -> str: + """Don't allow exceptions from __str__ to propegate.""" + try: + return str(_object) + except Exception as error: + return f"" + + +def to_repr(obj: Any, max_string: Optional[int] = None) -> str: + """Get repr string for an object, but catch errors.""" + if isinstance(obj, str): + obj_repr = obj + else: + try: + obj_repr = repr(obj) + except Exception as error: + obj_repr = f"" + + if max_string is not None and len(obj_repr) > max_string: + truncated = len(obj_repr) - max_string + obj_repr = f"{obj_repr[:max_string]!r}+{truncated}" + + return obj_repr + + +def extract( + exc_type: Type[BaseException], + exc_value: BaseException, + traceback: Optional[TracebackType], + *, + show_locals: bool = False, + locals_max_string: int = LOCALS_MAX_STRING, +) -> Trace: + """ + Extract traceback information. + + :param exc_type: Exception type. + :param exc_value: Exception value. + :param traceback: Python Traceback object. + :param show_locals: Enable display of local variables. Defaults to False. + :param locals_max_string: Maximum length of string before truncating, or + ``None`` to disable. + :param max_frames: Maximum number of frames in each stack + + :returns: A Trace instance with structured information about all + exceptions. + + .. versionadded:: 22.1 + """ + + stacks: List[Stack] = [] + is_cause = False + + while True: + stack = Stack( + exc_type=safe_str(exc_type.__name__), + exc_value=safe_str(exc_value), + is_cause=is_cause, + ) + + if isinstance(exc_value, SyntaxError): + stack.syntax_error = SyntaxError_( + offset=exc_value.offset or 0, + filename=exc_value.filename or "?", + lineno=exc_value.lineno or 0, + line=exc_value.text or "", + msg=exc_value.msg, + ) + + stacks.append(stack) + append = stack.frames.append # pylint: disable=no-member + + for frame_summary, line_no in walk_tb(traceback): + filename = frame_summary.f_code.co_filename + if filename and not filename.startswith("<"): + filename = os.path.abspath(filename) + frame = Frame( + filename=filename or "?", + lineno=line_no, + name=frame_summary.f_code.co_name, + locals={ + key: to_repr(value, max_string=locals_max_string) + for key, value in frame_summary.f_locals.items() + } + if show_locals + else None, + ) + append(frame) + + cause = getattr(exc_value, "__cause__", None) + if cause and cause.__traceback__: + exc_type = cause.__class__ + exc_value = cause + traceback = cause.__traceback__ + is_cause = True + continue + + cause = exc_value.__context__ + if ( + cause + and cause.__traceback__ + and not getattr(exc_value, "__suppress_context__", False) + ): + exc_type = cause.__class__ + exc_value = cause + traceback = cause.__traceback__ + is_cause = False + continue + + # No cover, code is reached but coverage doesn't recognize it. + break # pragma: no cover + + trace = Trace(stacks=stacks) + return trace + + +class ExceptionDictTransformer: + """ + Return a list of exception stack dictionaries for for an excpetion. + + These dictionaries are based on :class:`Stack` instances generated by + :func:`extract()` and can be dumped to JSON. + + :param show_locals: Whether or not to include the values of a stack frame's + local variables. + :param locals_max_string: The maximum length after which long string + representations are truncated. + :param max_frames: Maximum number of frames in each stack. Frames are + removed from the inside out. The idea is, that the first frames + represent your code responsible for the exception and last frames the + code where the exception actually happened. With larger web + frameworks, this does not always work, so you should stick with the + default. + """ + + def __init__( + self, + show_locals: bool = True, + locals_max_string: int = LOCALS_MAX_STRING, + max_frames: int = MAX_FRAMES, + ) -> None: + if locals_max_string < 0: + raise ValueError( + f'"locals_max_string" must be >= 0: {locals_max_string}' + ) + if max_frames < 2: + raise ValueError(f'"max_frames" must be >= 2: {max_frames}') + self.show_locals = show_locals + self.locals_max_string = locals_max_string + self.max_frames = max_frames + + def __call__(self, exc_info: ExcInfo) -> List[Dict[str, Any]]: + trace = extract( + *exc_info, + show_locals=self.show_locals, + locals_max_string=self.locals_max_string, + ) + + for stack in trace.stacks: + if len(stack.frames) <= self.max_frames: + continue + + half = ( + self.max_frames // 2 + ) # Force int division to handle odd numbers correctly + fake_frame = Frame( + filename="", + lineno=-1, + name=f"Skipped frames: {len(stack.frames) - (2 * half)}", + ) + stack.frames[:] = [ + *stack.frames[:half], + fake_frame, + *stack.frames[-half:], + ] + + stack_dicts = [asdict(stack) for stack in trace.stacks] + return stack_dicts diff --git a/src/structlog/types.py b/src/structlog/types.py index 69aa7f7e..5c9b22ce 100644 --- a/src/structlog/types.py +++ b/src/structlog/types.py @@ -87,7 +87,7 @@ """ -ExceptionFormatter = Callable[[TextIO, ExcInfo], None] +ExceptionRenderer = Callable[[TextIO, ExcInfo], None] """ A callable that pretty-prints an `ExcInfo` into a file-like object. @@ -97,6 +97,30 @@ """ +@runtime_checkable +class ExceptionTransformer(Protocol): + """ + **Protocol:** A callable that transforms an `ExcInfo` into another + datastructure. + + The result should be something that your renderer can work with, e.g., a + ``str`` or a JSON-serializable ``dict``. + + Used by `structlog.processors.format_exc_info()` and + `structlog.processors.ExceptionPrettyPrinter`. + + :param exc_info: Is the exception tuple to format + + :returns: Anything that can be rendered by the last processor in your + chain, e.g., a string or a JSON-serializable structure. + + .. versionadded:: 22.1 + """ + + def __call__(self, exc_info: ExcInfo) -> Any: + ... + + @runtime_checkable class BindableLogger(Protocol): """ diff --git a/tests/test_processors.py b/tests/test_processors.py index 8658ed6e..dbb53643 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -29,6 +29,7 @@ CallsiteParameter, CallsiteParameterAdder, ExceptionPrettyPrinter, + ExceptionRenderer, JSONRenderer, KeyValueRenderer, LogfmtRenderer, @@ -456,29 +457,37 @@ def test_apply_freezegun_after_instantiation(self, utc, expect): class TestFormatExcInfo: + def test_custom_formatter(self): + """ + The exception formatter can be changed. + """ + try: + raise ValueError("test") + except ValueError as e: + formatter = ExceptionRenderer(lambda _: "There is no exception!") + assert formatter(None, None, {"exc_info": e}) == { + "exception": "There is no exception!" + } + @pytest.mark.parametrize("ei", [False, None, ""]) def test_nop(self, ei): """ If exc_info is falsey, only remove the key. """ - assert {} == format_exc_info(None, None, {"exc_info": ei}) + assert {} == ExceptionRenderer()(None, None, {"exc_info": ei}) def test_nop_missing(self): """ If event dict doesn't contain exc_info, do nothing. """ - assert {} == format_exc_info(None, None, {}) + assert {} == ExceptionRenderer()(None, None, {}) - def test_formats_tuple(self, monkeypatch): + def test_formats_tuple(self): """ If exc_info is a tuple, it is used. """ - monkeypatch.setattr( - structlog.processors, - "_format_exception", - lambda exc_info: exc_info, - ) - d = format_exc_info(None, None, {"exc_info": (None, None, 42)}) + formatter = ExceptionRenderer(lambda exc_info: exc_info) + d = formatter(None, None, {"exc_info": (None, None, 42)}) assert {"exception": (None, None, 42)} == d @@ -491,25 +500,21 @@ def test_gets_exc_info_on_bool(self): try: raise ValueError("test") except ValueError: - d = format_exc_info(None, None, {"exc_info": True}) + d = ExceptionRenderer()(None, None, {"exc_info": True}) assert "exc_info" not in d assert 'raise ValueError("test")' in d["exception"] assert "ValueError: test" in d["exception"] - def test_exception_on_py3(self, monkeypatch): + def test_exception(self): """ Passing exceptions as exc_info is valid on Python 3. """ - monkeypatch.setattr( - structlog.processors, - "_format_exception", - lambda exc_info: exc_info, - ) try: raise ValueError("test") except ValueError as e: - d = format_exc_info(None, None, {"exc_info": e}) + formatter = ExceptionRenderer(lambda exc_info: exc_info) + d = formatter(None, None, {"exc_info": e}) assert {"exception": (ValueError, e, e.__traceback__)} == d else: @@ -519,12 +524,23 @@ def test_exception_without_traceback(self): """ If an Exception is missing a traceback, render it anyway. """ - rv = format_exc_info( + rv = ExceptionRenderer()( None, None, {"exc_info": Exception("no traceback!")} ) assert {"exception": "Exception: no traceback!"} == rv + def test_format_exception(self): + """ + "format_exception" is the "ExceptionRenderer" with default settings. + """ + try: + raise ValueError("test") + except ValueError as e: + a = format_exc_info(None, None, {"exc_info": e}) + b = ExceptionRenderer()(None, None, {"exc_info": e}) + assert a == b + class TestUnicodeEncoder: def test_encodes(self): diff --git a/tests/test_tracebacks.py b/tests/test_tracebacks.py new file mode 100644 index 00000000..fd55ec6a --- /dev/null +++ b/tests/test_tracebacks.py @@ -0,0 +1,563 @@ +import sys + +from pathlib import Path +from typing import Any, Dict, Optional + +import pytest + +from structlog import tracebacks + + +@pytest.mark.parametrize("data, expected", [(3, "3"), ("spam", "spam")]) +def test_save_str(data: Any, expected: str): + """ + "safe_str()" returns the str repr of an object. + """ + assert tracebacks.safe_str(data) == expected + + +def test_safe_str_error(): + """ + "safe_str()" does not fail if __str__() raises an exception. + """ + + class Baam: + def __str__(self) -> str: + raise ValueError("BAAM!") + + pytest.raises(ValueError, str, Baam()) + assert tracebacks.safe_str(Baam()) == "" + + +@pytest.mark.parametrize( + "data, max_len, expected", + [ + (3, None, "3"), + ("spam", None, "spam"), + (b"spam", None, "b'spam'"), + ("bacon", 3, "'bac'+2"), + ("bacon", 4, "'baco'+1"), + ("bacon", 5, "bacon"), + ], +) +def test_to_repr(data: Any, max_len: Optional[int], expected: str): + assert tracebacks.to_repr(data, max_string=max_len) == expected + + +def test_to_repr_error(): + """ + "to_repr()" does not fail if __repr__() raises an exception. + """ + + class Baam: + def __repr__(self) -> str: + raise ValueError("BAAM!") + + pytest.raises(ValueError, repr, Baam()) + assert tracebacks.to_repr(Baam()) == "" + + +def test_simple_exception(): + """ + Tracebacks are parsed for simple, single exceptions. + """ + try: + 1 / 0 + except Exception as e: + trace = tracebacks.extract(type(e), e, e.__traceback__) + + assert trace.stacks == [ + tracebacks.Stack( + exc_type="ZeroDivisionError", + exc_value="division by zero", + syntax_error=None, + is_cause=False, + frames=[ + tracebacks.Frame( + filename=__file__, + lineno=65, + name="test_simple_exception", + line="", + locals=None, + ), + ], + ), + ] + + +def test_raise_hide_cause(): + """ + If "raise ... from None" is used, the trace looks like from a simple + exception. + """ + try: + try: + 1 / 0 + except ArithmeticError: + raise ValueError("onoes") from None + except Exception as e: + trace = tracebacks.extract(type(e), e, e.__traceback__) + + assert trace.stacks == [ + tracebacks.Stack( + exc_type="ValueError", + exc_value="onoes", + syntax_error=None, + is_cause=False, + frames=[ + tracebacks.Frame( + filename=__file__, + lineno=97, + name="test_raise_hide_cause", + line="", + locals=None, + ), + ], + ), + ] + + +def test_raise_with_cause(): + """ + If "raise ... from orig" is used, the orig trace is included and marked as + cause. + """ + try: + try: + 1 / 0 + except ArithmeticError as orig_exc: + raise ValueError("onoes") from orig_exc + except Exception as e: + trace = tracebacks.extract(type(e), e, e.__traceback__) + + assert trace.stacks == [ + tracebacks.Stack( + exc_type="ValueError", + exc_value="onoes", + syntax_error=None, + is_cause=False, + frames=[ + tracebacks.Frame( + filename=__file__, + lineno=129, + name="test_raise_with_cause", + line="", + locals=None, + ), + ], + ), + tracebacks.Stack( + exc_type="ZeroDivisionError", + exc_value="division by zero", + syntax_error=None, + is_cause=True, + frames=[ + tracebacks.Frame( + filename=__file__, + lineno=127, + name="test_raise_with_cause", + line="", + locals=None, + ), + ], + ), + ] + + +def test_raise_with_cause_no_tb(): + """ + If an exception's cause has no traceback, that cause is ignored. + """ + try: + raise ValueError("onoes") from RuntimeError("I am fake") + except Exception as e: + trace = tracebacks.extract(type(e), e, e.__traceback__) + + assert trace.stacks == [ + tracebacks.Stack( + exc_type="ValueError", + exc_value="onoes", + syntax_error=None, + is_cause=False, + frames=[ + tracebacks.Frame( + filename=__file__, + lineno=172, + name="test_raise_with_cause_no_tb", + line="", + locals=None, + ), + ], + ), + ] + + +def test_raise_nested(): + """ + If an exc is raised during handling another one, the orig trace is + included. + """ + try: + try: + 1 / 0 + except ArithmeticError: + raise ValueError("onoes") + except Exception as e: + trace = tracebacks.extract(type(e), e, e.__traceback__) + + assert trace.stacks == [ + tracebacks.Stack( + exc_type="ValueError", + exc_value="onoes", + syntax_error=None, + is_cause=False, + frames=[ + tracebacks.Frame( + filename=__file__, + lineno=204, + name="test_raise_nested", + line="", + locals=None, + ), + ], + ), + tracebacks.Stack( + exc_type="ZeroDivisionError", + exc_value="division by zero", + syntax_error=None, + is_cause=False, + frames=[ + tracebacks.Frame( + filename=__file__, + lineno=202, + name="test_raise_nested", + line="", + locals=None, + ), + ], + ), + ] + + +def test_raise_no_msg(): + """ + If exception classes (not instances) are raised, "exc_value" is an empty + string. + """ + try: + raise RuntimeError + except Exception as e: + trace = tracebacks.extract(type(e), e, e.__traceback__) + + assert trace.stacks == [ + tracebacks.Stack( + exc_type="RuntimeError", + exc_value="", + syntax_error=None, + is_cause=False, + frames=[ + tracebacks.Frame( + filename=__file__, + lineno=248, + name="test_raise_no_msg", + line="", + locals=None, + ), + ], + ), + ] + + +def test_syntax_error(): + """ + For SyntaxError, extra info about that error is added to the trace. + """ + try: + # raises SyntaxError: invalid syntax + eval("2 +* 2") + except SyntaxError as e: + trace = tracebacks.extract(type(e), e, e.__traceback__) + + assert trace.stacks == [ + tracebacks.Stack( + exc_type="SyntaxError", + exc_value="invalid syntax (, line 1)", + syntax_error=tracebacks.SyntaxError_( + offset=4, + filename="", + line="2 +* 2", + lineno=1, + msg="invalid syntax", + ), + is_cause=False, + frames=[ + tracebacks.Frame( + filename=__file__, + lineno=277, + name="test_syntax_error", + line="", + locals=None, + ), + ], + ), + ] + + +def test_filename_with_bracket(): + """ + Filenames with brackets (e.g., "") are handled properly. + """ + try: + exec(compile("1/0", filename="", mode="exec")) + except Exception as e: + trace = tracebacks.extract(type(e), e, e.__traceback__) + + assert trace.stacks == [ + tracebacks.Stack( + exc_type="ZeroDivisionError", + exc_value="division by zero", + syntax_error=None, + is_cause=False, + frames=[ + tracebacks.Frame( + filename=__file__, + lineno=311, + name="test_filename_with_bracket", + line="", + locals=None, + ), + tracebacks.Frame( + filename="", + lineno=1, + name="", + line="", + locals=None, + ), + ], + ), + ] + + +def test_filename_not_a_file(): + """ + "Invalid" filenames are appended to CWD as if they were actual files. + """ + try: + exec(compile("1/0", filename="string", mode="exec")) + except Exception as e: + trace = tracebacks.extract(type(e), e, e.__traceback__) + + assert trace.stacks == [ + tracebacks.Stack( + exc_type="ZeroDivisionError", + exc_value="division by zero", + syntax_error=None, + is_cause=False, + frames=[ + tracebacks.Frame( + filename=__file__, + lineno=346, + name="test_filename_not_a_file", + line="", + locals=None, + ), + tracebacks.Frame( + filename=str(Path.cwd().joinpath("string")), + lineno=1, + name="", + line="", + locals=None, + ), + ], + ), + ] + + +def test_show_locals(): + """ + Local variables in each frame can optionally be captured. + """ + + def bar(a): + print(1 / a) + + def foo(a): + bar(a) + + try: + foo(0) + except Exception as e: + trace = tracebacks.extract( + type(e), e, e.__traceback__, show_locals=True + ) + + stack_locals = [f.locals for f in trace.stacks[0].frames] + # The first frames contain functions with "random" memory addresses, + # so we only check the variable names: + assert stack_locals[0].keys() == {"foo", "e", "bar"} + assert stack_locals[1].keys() == {"a", "bar"} + assert stack_locals[2] == {"a": "0"} + + +def test_recursive(): + """ + Recursion errors give a lot of frames but don't break stuff. + """ + + def foo(n): + return bar(n) + + def bar(n): + return foo(n) + + try: + foo(1) + except Exception as e: + trace = tracebacks.extract(type(e), e, e.__traceback__) + + frames = trace.stacks[0].frames + trace.stacks[0].frames = [] + + assert trace.stacks == [ + tracebacks.Stack( + exc_type="RecursionError", + exc_value="maximum recursion depth exceeded", + syntax_error=None, + is_cause=False, + frames=[], + ), + ] + assert ( + len(frames) > sys.getrecursionlimit() - 50 + ) # Buffer for frames from pytest + assert frames[0] == tracebacks.Frame( + filename=__file__, + lineno=414, + name="test_recursive", + ) + # Depending on whether we invoke pytest directly or run tox, either "foo()" + # or "bar()" is at the end of the stack. + assert frames[-1] in [ + tracebacks.Frame( + filename=__file__, + lineno=408, + name="foo", + ), + tracebacks.Frame( + filename=__file__, + lineno=411, + name="bar", + ), + ] + + +def test_json_traceback(): + try: + 1 / 0 + except Exception as e: + format_json = tracebacks.ExceptionDictTransformer(show_locals=False) + result = format_json((type(e), e, e.__traceback__)) + assert result == [ + { + "exc_type": "ZeroDivisionError", + "exc_value": "division by zero", + "frames": [ + { + "filename": __file__, + "line": "", + "lineno": 456, + "locals": None, + "name": "test_json_traceback", + } + ], + "is_cause": False, + "syntax_error": None, + }, + ] + + +def test_json_traceback_locals_max_string(): + try: + _var = "spamspamspam" # noqa + 1 / 0 + except Exception as e: + result = tracebacks.ExceptionDictTransformer(locals_max_string=4)( + (type(e), e, e.__traceback__) + ) + assert result == [ + { + "exc_type": "ZeroDivisionError", + "exc_value": "division by zero", + "frames": [ + { + "filename": __file__, + "line": "", + "lineno": 482, + "locals": { + "_var": "'spam'+8", + "e": "'Zero'+33", + }, + "name": "test_json_traceback_locals_max_string", + } + ], + "is_cause": False, + "syntax_error": None, + }, + ] + + +@pytest.mark.parametrize( + "max_frames, expected_frames, skipped_idx, skipped_count", + [ + # (0, 1, 0, 3), + # (1, 1, 0, 3), + (2, 3, 1, 2), + (3, 3, 1, 2), + (4, 4, -1, 0), + (5, 4, -1, 0), + ], +) +def test_json_traceback_max_frames( + max_frames: int, expected_frames: int, skipped_idx: int, skipped_count: int +): + def spam(): + return 1 / 0 + + def eggs(): + spam() + + def bacon(): + eggs() + + try: + bacon() + except Exception as e: + format_json = tracebacks.ExceptionDictTransformer( + show_locals=False, max_frames=max_frames + ) + result = format_json((type(e), e, e.__traceback__)) + trace = result[0] + assert len(trace["frames"]) == expected_frames, trace["frames"] + if skipped_count: + assert trace["frames"][skipped_idx] == { + "filename": "", + "line": "", + "lineno": -1, + "locals": None, + "name": f"Skipped frames: {skipped_count}", + } + else: + assert not any(f["lineno"] == -1 for f in trace["frames"]) + + +@pytest.mark.parametrize( + "kwargs", + [ + {"locals_max_string": -1}, + {"max_frames": -1}, + {"max_frames": 0}, + {"max_frames": 1}, + ], +) +def test_json_traceback_value_error(kwargs: Dict[str, Any]): + pytest.raises(ValueError, tracebacks.ExceptionDictTransformer, **kwargs) diff --git a/typing_examples.py b/typing_examples.py index 02fc9106..6e8b5b75 100644 --- a/typing_examples.py +++ b/typing_examples.py @@ -292,3 +292,21 @@ def typecheck_filtering_return() -> None: fblog.warn("no value unbound because key not defined") fblog = fblog.new(new="value") fblog.info("this is a whole new logger") + + +# Structured tracebacks and ExceptionRenderer with ExceptionDictTransformer +struct_tb: structlog.tracebacks.Trace = structlog.tracebacks.extract( + ValueError, ValueError("onoes"), None +) +try: + raise ValueError("onoes") +except ValueError as e: + struct_tb = structlog.tracebacks.extract(type(e), e, e.__traceback__) +structlog.configure( + processors=[ + structlog.processors.ExceptionRenderer( + structlog.tracebacks.ExceptionDictTransformer() + ), + structlog.processors.JSONRenderer(), + ] +) From d07e50309ed1c0a488a00732a4ebe0d6cb8e72eb Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 29 Jun 2022 13:11:25 +0200 Subject: [PATCH 0696/1520] Fix typo --- docs/logging-best-practices.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/logging-best-practices.rst b/docs/logging-best-practices.rst index c9e68f11..c1c90796 100644 --- a/docs/logging-best-practices.rst +++ b/docs/logging-best-practices.rst @@ -33,7 +33,7 @@ Pretty Printing vs. Structured Output Colorful and pretty printed log messages are nice during development when you locally run your code. However, in production you should emit structured output (like JSON) which is a lot easier to parse by log aggregators. -Since you already log in a structured way, writing JSON output with structlogs comes very naturally. +Since you already log in a structured way, writing JSON output with ``structlog`` comes naturally. You can even generate structured exception tracebacks. This makes analyzing errors easier, since log aggregators can render JSON much better than multiline strings with a lot escaped quotation marks. From fcff4bdb2613944a3deb5b6536aada98159e9284 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 29 Jun 2022 13:15:08 +0200 Subject: [PATCH 0697/1520] Remove duplicate changelog entry --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87ae7a0d..dd3a072a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,7 +50,6 @@ So please make sure to **always** properly configure your applications. - Added structured logging of tracebacks via the `structlog.tracebacks` module, and most notably the `structlog.tracebacks.ExceptionDictTransformer` which can be used with the new `structlog.processors.ExceptionRenderer` to render JSON tracebacks. [#407](https://github.com/hynek/structlog/pull/407) -- `structlog.processors.format_exc_info()` is no longer a function, but an instance of `structlog.processors.ExceptionRenderer`. ### Changed From cf8d6f05a5c683125896985c10fbf11a139085e1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 4 Jul 2022 21:46:09 +0200 Subject: [PATCH 0698/1520] [pre-commit.ci] pre-commit autoupdate (#426) --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2c3b5379..e2108bfd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,12 +4,12 @@ ci: repos: - repo: https://github.com/psf/black - rev: 22.3.0 + rev: 22.6.0 hooks: - id: black - repo: https://github.com/asottile/pyupgrade - rev: v2.32.1 + rev: v2.34.0 hooks: - id: pyupgrade args: [--py37-plus] @@ -28,7 +28,7 @@ repos: exclude: docs/code_examples - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.2.0 + rev: v4.3.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer From 930ff0ff61e8e010c98c531ccbacf159572d788b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 6 Jul 2022 16:32:18 +0200 Subject: [PATCH 0699/1520] stdlib.render_to_log_kwargs: fix handling of special kwargs (#427) * stdlib.render_to_log_kwargs: fix handling of special kwargs Co-authored-by: Serhii Tereshchenko * Add second PR# Co-authored-by: Serhii Tereshchenko --- CHANGELOG.md | 4 ++++ conftest.py | 4 ++-- src/structlog/stdlib.py | 12 +++++++++++- tests/test_stdlib.py | 28 ++++++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd3a072a..2fc744e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,6 +73,10 @@ So please make sure to **always** properly configure your applications. [#392](https://github.com/hynek/structlog/pull/392) - Monkeypatched `sys.stdout`s are now handled more gracefully by `ConsoleRenderer` (that's used by default). [#404](https://github.com/hynek/structlog/pull/404) +- `structlog.stdlib.render_to_log_kwargs()` now correctly handles the presence of `exc_info`, `stack_info`, and `stackLevel` in the event dictionary. + They are transformed into proper keyword arguments instead of putting them into the `extra` dictionary. + [#424](https://github.com/hynek/structlog/issues/424), + [#427](https://github.com/hynek/structlog/issues/427) ## [21.5.0](https://github.com/hynek/structlog/compare/21.4.0...21.5.0) - 2021-12-16 diff --git a/conftest.py b/conftest.py index d48e530e..10cb5834 100644 --- a/conftest.py +++ b/conftest.py @@ -41,8 +41,8 @@ def _sio(): return StringIO() -@pytest.fixture -def event_dict(): +@pytest.fixture(name="event_dict") +def _event_dict(): """ An example event dictionary with multiple value types w/o the event itself. """ diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 34a257e5..f6ad2b12 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -738,8 +738,18 @@ def render_to_log_kwargs( This allows you to defer formatting to `logging`. .. versionadded:: 17.1.0 + .. versionchanged:: 22.1.0 ``exc_info``, ``stack_info``, and ``stackLevel`` + are passed as proper kwargs and not put into ``extra``. """ - return {"msg": event_dict.pop("event"), "extra": event_dict} + return { + "msg": event_dict.pop("event"), + "extra": event_dict, + **{ + kw: event_dict.pop(kw) + for kw in ("exc_info", "stack_info", "stackLevel") + if kw in event_dict + }, + } class ProcessorFormatter(logging.Formatter): diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 4847b4d2..ac09f4bb 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -624,6 +624,34 @@ def test_add_extra_event_dict(self, event_dict): assert {"msg": "message", "extra": event_dict} == d + def test_handles_special_kw(self, event_dict): + """ + "exc_info", "stack_info", and "stackLevel" aren't passed as extras. + + Cf. https://github.com/hynek/structlog/issues/424 + """ + del event_dict["a"] # needs a repr + event_dict["event"] = "message" + + event_dict["exc_info"] = True + event_dict["stack_info"] = False + event_dict["stackLevel"] = 1 + + d = render_to_log_kwargs(None, None, event_dict) + + assert { + "msg": "message", + "exc_info": True, + "stack_info": False, + "stackLevel": 1, + "extra": { + "b": [3, 4], + "x": 7, + "y": "test", + "z": (1, 2), + }, + } == d + @pytest.fixture(name="configure_for_processor_formatter") def _configure_for_processor_formatter(): From fe6895d094ae2009c0d5a648225440d6b1627f3b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 15 Jul 2022 17:54:21 +0100 Subject: [PATCH 0700/1520] Add intro blurb for screenshot --- README.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.rst b/README.rst index cc71a3c9..d58044bd 100644 --- a/README.rst +++ b/README.rst @@ -24,6 +24,8 @@ It has been successfully used in production at every scale since **2013**, while Thanks to its highly flexible design, it's up to you whether you want ``structlog`` to take care about the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's ``logging`` module. +``structlog`` comes with support for JSON, `logfmt `_, as well as pretty console output out-of-the-box: + .. image:: https://github.com/hynek/structlog/blob/main/docs/_static/console_renderer.png?raw=true .. -end-short- From 637f30aeb313863223154164b5442f03b1240f7e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 15 Jul 2022 18:15:26 +0100 Subject: [PATCH 0701/1520] Search is pointless with Furo --- docs/index.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index b92fc3b6..146a1405 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -86,4 +86,3 @@ Indices and tables - `genindex` - `modindex` -- `search` From 9a67f0bcdbd45d6511bd94127af60c4d95cfeed9 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 20 Jul 2022 07:47:04 +0200 Subject: [PATCH 0702/1520] Fix cog --- pyproject.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 52ce4b68..c783d9da 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -209,6 +209,8 @@ It has been successfully used in production at every scale since **2013**, while Thanks to its highly flexible design, it's up to you whether you want ``structlog`` to take care about the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's ``logging`` module. +``structlog`` comes with support for JSON, `logfmt `_, as well as pretty console output out-of-the-box: + .. image:: https://github.com/hynek/structlog/blob/main/docs/_static/console_renderer.png?raw=true .. -end-short- From a15b71d9f86f675ada0f0a0871251eb7af867e00 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 20 Jul 2022 09:08:53 +0200 Subject: [PATCH 0703/1520] Add structlog.stdlib.recreate_defaults (#428) Co-authored-by: Pradyun Gedam --- CHANGELOG.md | 3 + docs/api.rst | 2 + docs/getting-started.rst | 9 ++- docs/standard-library.rst | 4 ++ src/structlog/_config.py | 5 +- src/structlog/stdlib.py | 134 ++++++++++++++++++++++++-------------- tests/test_stdlib.py | 33 ++++++++++ 7 files changed, 137 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fc744e1..4a94bb0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,9 @@ So please make sure to **always** properly configure your applications. - Added structured logging of tracebacks via the `structlog.tracebacks` module, and most notably the `structlog.tracebacks.ExceptionDictTransformer` which can be used with the new `structlog.processors.ExceptionRenderer` to render JSON tracebacks. [#407](https://github.com/hynek/structlog/pull/407) +- `structlog.stdlib.recreate_defaults(log_level=logging.NOTSET)` that recreates `structlog`'s defaults on top of standard library's `logging`. + It optionally also configures `logging` to log to standard out at the passed log level. + [#428](https://github.com/hynek/structlog/pull/428) ### Changed diff --git a/docs/api.rst b/docs/api.rst index 471ca9a2..0c349cbb 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -270,6 +270,8 @@ API Reference .. automodule:: structlog.stdlib +.. autofunction:: recreate_defaults + .. autofunction:: get_logger .. autoclass:: BoundLogger diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 42c3bbe2..7fe65b89 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -62,10 +62,13 @@ Using the defaults, as above, is equivalent to:: log = structlog.get_logger() .. note:: - For brevity and to enable doctests, all further examples in ``structlog``'s documentation use the more simplistic `structlog.processors.KeyValueRenderer()` without timestamps. - `structlog.make_filtering_bound_logger()` (re-)uses `logging`'s log levels, but doesn't use it at all. - The exposed API is `FilteringBoundLogger`. + - `structlog.stdlib.recreate_defaults()` allows you to switch ``structlog`` to using standard library's `logging` module for output for better interoperability with just one function call. + + - `structlog.make_filtering_bound_logger()` (re-)uses `logging`'s log levels, but doesn't use it at all. + The exposed API is `FilteringBoundLogger`. + + - For brevity and to enable doctests, all further examples in ``structlog``'s documentation use the more simplistic `structlog.processors.KeyValueRenderer()` without timestamps. There you go, structured logging! However, this alone wouldn't warrant its own package. diff --git a/docs/standard-library.rst b/docs/standard-library.rst index 115d575a..19d71130 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -7,6 +7,10 @@ In other words, you should be able to replace your call to `logging.getLogger` b If you run into incompatibilities, it is a *bug* so please take the time to `report it `_! If you're a heavy `logging` user, your `help `_ to ensure a better compatibility would be highly appreciated! +.. note:: + + The quickest way to get started with ``structlog`` and `logging` is `structlog.stdlib.recreate_defaults()` that will recreate the default configuration on top of `logging` and optionally configure `logging` for you. + Just Enough ``logging`` ----------------------- diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 2f072c72..c069dfdd 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -30,9 +30,10 @@ """ -.. note:: + Any changes to these defaults must be reflected in: - Any changes to these defaults must be reflected in `getting-started`. + - `getting-started`. + - structlog.stdlib.recreate_defaults()'s docstring. """ _BUILTIN_DEFAULT_PROCESSORS: Sequence[Processor] = [ add_log_level, diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index f6ad2b12..0496b244 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -9,6 +9,8 @@ See also :doc:`structlog's standard library support `. """ +from __future__ import annotations + import asyncio import contextvars import functools @@ -16,20 +18,12 @@ import sys from functools import partial -from typing import ( - Any, - Callable, - Collection, - Dict, - Iterable, - List, - Optional, - Sequence, - Tuple, -) +from typing import Any, Callable, Collection, Iterable, Sequence + +from structlog.processors import StackInfoRenderer +from . import _config from ._base import BoundLoggerBase -from ._config import get_logger as _generic_get_logger from ._frames import _find_first_app_frame_and_name, _format_stack from ._log_levels import _LEVEL_TO_NAME, _NAME_TO_LEVEL, add_log_level from .exceptions import DropEvent @@ -47,10 +41,58 @@ "LoggerFactory", "PositionalArgumentsFormatter", "ProcessorFormatter", + "recreate_defaults", "render_to_log_kwargs", ] +def recreate_defaults(*, log_level: int | None = logging.NOTSET) -> None: + """ + Recreate defaults on top of standard library's logging. + + The output looks the same, but goes through `logging`. + + As with vanilla defaults, the backwards-compatibility guarantees don't + apply to the settings applied here. + + :param log_level: If `None`, don't configure standard library logging **at + all**. + + Otherwise configure it to log to `sys.stdout` at *log_level* + (``logging.NOTSET`` being the default). + + If you need more control over `logging`, pass `None` here and configure + it yourself. + + .. versionadded:: 22.1 + """ + if log_level is not None: + kw = {} + # 3.7 doesn't have the force keyword and we don't care enough to + # re-implement it. + if sys.version_info >= (3, 8): + kw = {"force": True} + + logging.basicConfig( + format="%(message)s", + stream=sys.stdout, + level=log_level, + **kw, # type: ignore + ) + + _config.reset_defaults() + _config.configure( + processors=[ + add_log_level, + StackInfoRenderer(), + _config._BUILTIN_DEFAULT_PROCESSORS[-2], # TimeStamper + _config._BUILTIN_DEFAULT_PROCESSORS[-1], # ConsoleRenderer + ], + wrapper_class=BoundLogger, + logger_factory=LoggerFactory(), + ) + + _SENTINEL = object() @@ -62,14 +104,14 @@ class _FixedFindCallerLogger(logging.Logger): def findCaller( self, stack_info: bool = False, stacklevel: int = 1 - ) -> Tuple[str, int, str, Optional[str]]: + ) -> tuple[str, int, str, str | None]: """ Finds the first caller frame outside of structlog so that the caller info is populated for wrapping stdlib. This logger gets set as the default one when using LoggerFactory. """ - sinfo: Optional[str] + sinfo: str | None f, name = _find_first_app_frame_and_name(["logging"]) if stack_info: sinfo = _format_stack(f) @@ -98,13 +140,13 @@ class BoundLogger(BoundLoggerBase): _logger: logging.Logger - def bind(self, **new_values: Any) -> "BoundLogger": + def bind(self, **new_values: Any) -> BoundLogger: """ Return a new logger with *new_values* added to the existing ones. """ return super().bind(**new_values) # type: ignore - def unbind(self, *keys: str) -> "BoundLogger": + def unbind(self, *keys: str) -> BoundLogger: """ Return a new logger with *keys* removed from the context. @@ -112,7 +154,7 @@ def unbind(self, *keys: str) -> "BoundLogger": """ return super().unbind(*keys) # type: ignore - def try_unbind(self, *keys: str) -> "BoundLogger": + def try_unbind(self, *keys: str) -> BoundLogger: """ Like :meth:`unbind`, but best effort: missing keys are ignored. @@ -120,7 +162,7 @@ def try_unbind(self, *keys: str) -> "BoundLogger": """ return super().try_unbind(*keys) # type: ignore - def new(self, **new_values: Any) -> "BoundLogger": + def new(self, **new_values: Any) -> BoundLogger: """ Clear context and binds *initial_values* using `bind`. @@ -130,21 +172,19 @@ def new(self, **new_values: Any) -> "BoundLogger": """ return super().new(**new_values) # type: ignore - def debug(self, event: Optional[str] = None, *args: Any, **kw: Any) -> Any: + def debug(self, event: str | None = None, *args: Any, **kw: Any) -> Any: """ Process event and call `logging.Logger.debug` with the result. """ return self._proxy_to_logger("debug", event, *args, **kw) - def info(self, event: Optional[str] = None, *args: Any, **kw: Any) -> Any: + def info(self, event: str | None = None, *args: Any, **kw: Any) -> Any: """ Process event and call `logging.Logger.info` with the result. """ return self._proxy_to_logger("info", event, *args, **kw) - def warning( - self, event: Optional[str] = None, *args: Any, **kw: Any - ) -> Any: + def warning(self, event: str | None = None, *args: Any, **kw: Any) -> Any: """ Process event and call `logging.Logger.warning` with the result. """ @@ -152,22 +192,20 @@ def warning( warn = warning - def error(self, event: Optional[str] = None, *args: Any, **kw: Any) -> Any: + def error(self, event: str | None = None, *args: Any, **kw: Any) -> Any: """ Process event and call `logging.Logger.error` with the result. """ return self._proxy_to_logger("error", event, *args, **kw) - def critical( - self, event: Optional[str] = None, *args: Any, **kw: Any - ) -> Any: + def critical(self, event: str | None = None, *args: Any, **kw: Any) -> Any: """ Process event and call `logging.Logger.critical` with the result. """ return self._proxy_to_logger("critical", event, *args, **kw) def exception( - self, event: Optional[str] = None, *args: Any, **kw: Any + self, event: str | None = None, *args: Any, **kw: Any ) -> Any: """ Process event and call `logging.Logger.error` with the result, @@ -178,7 +216,7 @@ def exception( return self.error(event, *args, **kw) def log( - self, level: int, event: Optional[str] = None, *args: Any, **kw: Any + self, level: int, event: str | None = None, *args: Any, **kw: Any ) -> Any: """ Process *event* and call the appropriate logging method depending on @@ -191,7 +229,7 @@ def log( def _proxy_to_logger( self, method_name: str, - event: Optional[str] = None, + event: str | None = None, *event_args: str, **event_kw: Any, ) -> Any: @@ -262,7 +300,7 @@ def setLevel(self, level: int) -> None: def findCaller( self, stack_info: bool = False - ) -> Tuple[str, int, str, Optional[str]]: + ) -> tuple[str, int, str, str | None]: """ Calls :meth:`logging.Logger.findCaller` with unmodified arguments. """ @@ -275,9 +313,9 @@ def makeRecord( fn: str, lno: int, msg: str, - args: Tuple[Any, ...], + args: tuple[Any, ...], exc_info: ExcInfo, - func: Optional[str] = None, + func: str | None = None, extra: Any = None, ) -> logging.LogRecord: """ @@ -351,7 +389,7 @@ def get_logger(*args: Any, **initial_values: Any) -> BoundLogger: .. versionadded:: 20.2.0 """ - return _generic_get_logger(*args, **initial_values) + return _config.get_logger(*args, **initial_values) class AsyncBoundLogger: @@ -414,7 +452,7 @@ def __init__( def _context(self) -> Context: return self.sync_bl._context - def bind(self, **new_values: Any) -> "AsyncBoundLogger": + def bind(self, **new_values: Any) -> AsyncBoundLogger: return AsyncBoundLogger( # logger, processors and context are within sync_bl. These # arguments are ignored if _sync_bl is passed. *vroom vroom* over @@ -426,7 +464,7 @@ def bind(self, **new_values: Any) -> "AsyncBoundLogger": _loop=self._loop, ) - def new(self, **new_values: Any) -> "AsyncBoundLogger": + def new(self, **new_values: Any) -> AsyncBoundLogger: return AsyncBoundLogger( # c.f. comment in bind logger=None, # type: ignore @@ -436,7 +474,7 @@ def new(self, **new_values: Any) -> "AsyncBoundLogger": _loop=self._loop, ) - def unbind(self, *keys: str) -> "AsyncBoundLogger": + def unbind(self, *keys: str) -> AsyncBoundLogger: return AsyncBoundLogger( # c.f. comment in bind logger=None, # type: ignore @@ -446,7 +484,7 @@ def unbind(self, *keys: str) -> "AsyncBoundLogger": _loop=self._loop, ) - def try_unbind(self, *keys: str) -> "AsyncBoundLogger": + def try_unbind(self, *keys: str) -> AsyncBoundLogger: return AsyncBoundLogger( # c.f. comment in bind logger=None, # type: ignore @@ -460,8 +498,8 @@ async def _dispatch_to_sync( self, meth: Callable[..., Any], event: str, - args: Tuple[Any, ...], - kw: Dict[str, Any], + args: tuple[Any, ...], + kw: dict[str, Any], ) -> None: """ Merge contextvars and log using the sync logger in a thread pool. @@ -527,7 +565,7 @@ class LoggerFactory: called *additional_ignores* in other APIs throughout `structlog`. """ - def __init__(self, ignore_frame_names: Optional[List[str]] = None): + def __init__(self, ignore_frame_names: list[str] | None = None): self._ignore = ignore_frame_names logging.setLoggerClass(_FixedFindCallerLogger) @@ -688,7 +726,7 @@ class ExtraAdder: __slots__ = ["_copier"] - def __init__(self, allow: Optional[Collection[str]] = None) -> None: + def __init__(self, allow: Collection[str] | None = None) -> None: self._copier: Callable[[EventDict, logging.LogRecord], None] if allow is not None: # The contents of allow is copied to a new list so that changes to @@ -701,7 +739,7 @@ def __init__(self, allow: Optional[Collection[str]] = None) -> None: def __call__( self, logger: logging.Logger, name: str, event_dict: EventDict ) -> EventDict: - record: Optional[logging.LogRecord] = event_dict.get("_record") + record: logging.LogRecord | None = event_dict.get("_record") if record is not None: self._copier(event_dict, record) return event_dict @@ -827,12 +865,12 @@ class ProcessorFormatter(logging.Formatter): def __init__( self, - processor: Optional[Processor] = None, - processors: Optional[Sequence[Processor]] = (), - foreign_pre_chain: Optional[Sequence[Processor]] = None, + processor: Processor | None = None, + processors: Sequence[Processor] | None = (), + foreign_pre_chain: Sequence[Processor] | None = None, keep_exc_info: bool = False, keep_stack_info: bool = False, - logger: Optional[logging.Logger] = None, + logger: logging.Logger | None = None, pass_foreign_args: bool = False, *args: Any, **kwargs: Any, @@ -931,7 +969,7 @@ def format(self, record: logging.LogRecord) -> str: @staticmethod def wrap_for_formatter( logger: logging.Logger, name: str, event_dict: EventDict - ) -> Tuple[Tuple[EventDict], Dict[str, Dict[str, Any]]]: + ) -> tuple[tuple[EventDict], dict[str, dict[str, Any]]]: """ Wrap *logger*, *name*, and *event_dict*. diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index ac09f4bb..3cfdc069 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -24,6 +24,7 @@ get_context, reset_defaults, ) +from structlog._config import _CONFIG from structlog._log_levels import _NAME_TO_LEVEL, CRITICAL, WARN from structlog.dev import ConsoleRenderer from structlog.exceptions import DropEvent @@ -41,6 +42,7 @@ add_logger_name, filter_by_level, get_logger, + recreate_defaults, render_to_log_kwargs, ) from structlog.testing import CapturedCall @@ -1196,3 +1198,34 @@ async def test_integration(self, capsys): } == json.loads(capsys.readouterr().out) reset_defaults() + + +@pytest.mark.parametrize("log_level", [None, 45]) +def test_recreate_defaults(log_level): + """ + Recreate defaults configures structlog and -- if asked -- logging. + """ + reset_defaults() + + logging.basicConfig( + stream=sys.stderr, + level=1, + force=True, + ) + + recreate_defaults(log_level=log_level) + + assert BoundLogger is _CONFIG.default_wrapper_class + assert dict is _CONFIG.default_context_class + assert isinstance(_CONFIG.logger_factory, LoggerFactory) + + # 3.7 doesn't have the force keyword and we don't care enough to + # re-implement it. + if sys.version_info < (3, 8): + return + + log = get_logger().bind() + if log_level is not None: + assert log_level == log.getEffectiveLevel() + else: + assert 1 == log.getEffectiveLevel() From 4a61fc49e80ba8776184052e69aff9078c23410d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 20 Jul 2022 09:09:26 +0200 Subject: [PATCH 0704/1520] Make project information easier to parse/understand --- README.rst | 25 ++++++++++--------------- pyproject.toml | 25 ++++++++++--------------- 2 files changed, 20 insertions(+), 30 deletions(-) diff --git a/README.rst b/README.rst index d58044bd..73e2682a 100644 --- a/README.rst +++ b/README.rst @@ -38,23 +38,17 @@ If you prefer videos over reading, check out `Markus Holtermann `_ to get help. - -Answering questions of your fellow developers is also a great way to help the project! - - Project Information =================== -``structlog`` is dual-licensed under `Apache License, version 2 `_ and `MIT `_, available from `PyPI `_, the source code can be found on `GitHub `_, the documentation at https://www.structlog.org/. - -We collect useful third-party extension in `our wiki `_. - -``structlog`` targets Python 3.7 and later. -PyPy3 is known to work, but is not tested anymore. +- **License**: dual-licensed under `Apache License, version 2 `_ and `MIT `_ +- **PyPI**: https://pypi.org/project/structlog/ +- **Source Code**: https://github.com/hynek/structlog +- **Documentation**: https://www.structlog.org/ +- **Changelog**: https://www.structlog.org/en/stable/changelog.html +- **Get Help**: please use the ``structlog`` tag on `StackOverflow `_ +- **Third-party Extensions**: https://github.com/hynek/structlog/wiki/Third-party-Extensions +- **Supported Python Versions**: 3.7 and later ``structlog`` for Enterprise @@ -62,5 +56,6 @@ PyPy3 is known to work, but is not tested anymore. Available as part of the Tidelift Subscription. -The maintainers of structlog and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. +The maintainers of structlog and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. +Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. `Learn more. `_ diff --git a/pyproject.toml b/pyproject.toml index c783d9da..6c52ddf5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -223,23 +223,17 @@ If you prefer videos over reading, check out `Markus Holtermann `_ to get help. - -Answering questions of your fellow developers is also a great way to help the project! - - Project Information =================== -``structlog`` is dual-licensed under `Apache License, version 2 `_ and `MIT `_, available from `PyPI `_, the source code can be found on `GitHub `_, the documentation at https://www.structlog.org/. - -We collect useful third-party extension in `our wiki `_. - -``structlog`` targets Python 3.7 and later. -PyPy3 is known to work, but is not tested anymore. +- **License**: dual-licensed under `Apache License, version 2 `_ and `MIT `_ +- **PyPI**: https://pypi.org/project/structlog/ +- **Source Code**: https://github.com/hynek/structlog +- **Documentation**: https://www.structlog.org/ +- **Changelog**: https://www.structlog.org/en/stable/changelog.html +- **Get Help**: please use the ``structlog`` tag on `StackOverflow `_ +- **Third-party Extensions**: https://github.com/hynek/structlog/wiki/Third-party-Extensions +- **Supported Python Versions**: 3.7 and later ``structlog`` for Enterprise @@ -247,7 +241,8 @@ PyPy3 is known to work, but is not tested anymore. Available as part of the Tidelift Subscription. -The maintainers of structlog and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. +The maintainers of structlog and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. +Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. `Learn more. `_ """ # [[[end]]] From d46cf681278125980794500202baf89774d4e3b4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 20 Jul 2022 10:38:21 +0200 Subject: [PATCH 0705/1520] Add structlog.processors.EventRenamer --- CHANGELOG.md | 5 ++ docs/api.rst | 11 ++++ src/structlog/dev.py | 7 ++- src/structlog/processors.py | 116 +++++++++++++++++++++++------------- tests/test_dev.py | 12 +++- tests/test_processors.py | 31 ++++++++++ 6 files changed, 139 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a94bb0c..840b7c7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,11 @@ So please make sure to **always** properly configure your applications. - `structlog.stdlib.recreate_defaults(log_level=logging.NOTSET)` that recreates `structlog`'s defaults on top of standard library's `logging`. It optionally also configures `logging` to log to standard out at the passed log level. [#428](https://github.com/hynek/structlog/pull/428) +- `structlog.processors.EventRenamer` allows you to rename the hitherto hard-coded event dict key `event` to something else. + Optionally, you can rename another key to `event` at the same time, too. + So adding `EventRenamer(to="msg", replace_by="_event")` to your processor pipeline will rename the standard `event` key to `msg` and then rename the `_event` key to `event`. + This allows you to use the `event` key in your own log files and to have consistent log message keys across languages. +- `structlog.dev.ConsoleRenderer(event_key="event")` now allows to customize the name of the key that is used for the log message. ### Changed diff --git a/docs/api.rst b/docs/api.rst index 0c349cbb..edb810bb 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -213,6 +213,17 @@ API Reference >>> LogfmtRenderer(key_order=["b", "a"], bool_as_flag=False)(None, None, event_dict) 'b="[1, 2, 3]" a=42 flag=true' +.. autoclass:: EventRenamer + + So if you want your log message to be ``msg`` and use ``event`` for something custom: + + .. doctest:: + + >>> from structlog.processors import EventRenamer + >>> event_dict = {"event": "something happened", "_event": "our event!"} + >>> EventRenamer("msg", "_event")(None, None, event_dict) + {'msg': 'something happened', 'event': 'our event!'} + .. autofunction:: add_log_level .. autoclass:: UnicodeDecoder diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 70152f0d..89bbfb17 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -237,6 +237,8 @@ class ConsoleRenderer: `plain_traceback`, `better_traceback`, `rich_traceback`, or implement your own. :param sort_keys: Whether to sort keys when formatting. `True` by default. + :param event_key: The key to look for the main log message. Needed when + you rename it e.g. using `structlog.processors.EventRenamer`. Requires the colorama_ package if *colors* is `True` **on Windows**. @@ -268,6 +270,7 @@ class ConsoleRenderer: non-Windows systems, and either True or False in Windows depending on whether colorama is installed. .. versionadded:: 21.3.0 *sort_keys* + .. versionadded:: 22.1 *event_key* """ def __init__( @@ -279,6 +282,7 @@ def __init__( level_styles: Optional[Styles] = None, exception_formatter: ExceptionRenderer = default_exception_formatter, sort_keys: bool = True, + event_key: str = "event", ): styles: Styles if colors: @@ -321,6 +325,7 @@ def __init__( self._repr_native_str = repr_native_str self._exception_formatter = exception_formatter self._sort_keys = sort_keys + self._event_key = event_key def _repr(self, val: Any) -> str: """ @@ -361,7 +366,7 @@ def __call__( ) # force event to str for compatibility with standard library - event = event_dict.pop("event", None) + event = event_dict.pop(self._event_key, None) if not isinstance(event, str): event = str(event) diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 1292eaf8..f898fde9 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -7,6 +7,8 @@ Processors useful regardless of the logging framework. """ +from __future__ import annotations + import datetime import enum import inspect @@ -23,15 +25,9 @@ Callable, ClassVar, Collection, - Dict, - List, NamedTuple, - Optional, Sequence, - Set, TextIO, - Tuple, - Union, ) from ._frames import ( @@ -47,18 +43,19 @@ __all__ = [ "_NAME_TO_LEVEL", # some people rely on it being here - "KeyValueRenderer", - "TimeStamper", "add_log_level", - "UnicodeEncoder", - "UnicodeDecoder", - "JSONRenderer", - "format_exc_info", + "CallsiteParameter", + "CallsiteParameterAdder", "dict_tracebacks", + "EventRenamer", "ExceptionPrettyPrinter", + "format_exc_info", + "JSONRenderer", + "KeyValueRenderer", "StackInfoRenderer", - "CallsiteParameter", - "CallsiteParameterAdder", + "TimeStamper", + "UnicodeDecoder", + "UnicodeEncoder", ] @@ -85,7 +82,7 @@ class KeyValueRenderer: def __init__( self, sort_keys: bool = False, - key_order: Optional[Sequence[str]] = None, + key_order: Sequence[str] | None = None, drop_missing: bool = False, repr_native_str: bool = True, ): @@ -135,7 +132,7 @@ class LogfmtRenderer: def __init__( self, sort_keys: bool = False, - key_order: Optional[Sequence[str]] = None, + key_order: Sequence[str] | None = None, drop_missing: bool = False, bool_as_flag: bool = True, ): @@ -146,7 +143,7 @@ def __call__( self, _: WrappedLogger, __: str, event_dict: EventDict ) -> str: - elements: List[str] = [] + elements: list[str] = [] for key, value in self._ordered_items(event_dict): if any(c <= " " for c in key): raise ValueError(f'Invalid key: "{key}"') @@ -173,9 +170,9 @@ def __call__( def _items_sorter( sort_keys: bool, - key_order: Optional[Sequence[str]], + key_order: Sequence[str] | None, drop_missing: bool, -) -> Callable[[EventDict], List[Tuple[str, Any]]]: +) -> Callable[[EventDict], list[tuple[str, Any]]]: """ Return a function to sort items from an ``event_dict``. @@ -184,7 +181,7 @@ def _items_sorter( # Use an optimized version for each case. if key_order and sort_keys: - def ordered_items(event_dict: EventDict) -> List[Tuple[str, Any]]: + def ordered_items(event_dict: EventDict) -> list[tuple[str, Any]]: items = [] for key in key_order: # type: ignore value = event_dict.pop(key, None) @@ -197,7 +194,7 @@ def ordered_items(event_dict: EventDict) -> List[Tuple[str, Any]]: elif key_order: - def ordered_items(event_dict: EventDict) -> List[Tuple[str, Any]]: + def ordered_items(event_dict: EventDict) -> list[tuple[str, Any]]: items = [] for key in key_order: # type: ignore value = event_dict.pop(key, None) @@ -210,7 +207,7 @@ def ordered_items(event_dict: EventDict) -> List[Tuple[str, Any]]: elif sort_keys: - def ordered_items(event_dict: EventDict) -> List[Tuple[str, Any]]: + def ordered_items(event_dict: EventDict) -> list[tuple[str, Any]]: return sorted(event_dict.items()) else: @@ -313,7 +310,7 @@ class JSONRenderer: def __init__( self, - serializer: Callable[..., Union[str, bytes]] = json.dumps, + serializer: Callable[..., str | bytes] = json.dumps, **dumps_kw: Any, ) -> None: dumps_kw.setdefault("default", _json_fallback_handler) @@ -322,7 +319,7 @@ def __init__( def __call__( self, logger: WrappedLogger, name: str, event_dict: EventDict - ) -> Union[str, bytes]: + ) -> str | bytes: """ The return type of this depends on the return type of self._dumps. """ @@ -441,7 +438,7 @@ class TimeStamper: def __init__( self, - fmt: Optional[str] = None, + fmt: str | None = None, utc: bool = True, key: str = "timestamp", ) -> None: @@ -454,10 +451,10 @@ def __call__( ) -> EventDict: return self._stamper(event_dict) - def __getstate__(self) -> Dict[str, Any]: + def __getstate__(self) -> dict[str, Any]: return {"fmt": self.fmt, "utc": self.utc, "key": self.key} - def __setstate__(self, state: Dict[str, Any]) -> None: + def __setstate__(self, state: dict[str, Any]) -> None: self.fmt = state["fmt"] self.utc = state["utc"] self.key = state["key"] @@ -466,7 +463,7 @@ def __setstate__(self, state: Dict[str, Any]) -> None: def _make_stamper( - fmt: Optional[str], utc: bool, key: str + fmt: str | None, utc: bool, key: str ) -> Callable[[EventDict], EventDict]: """ Create a stamper function. @@ -556,7 +553,7 @@ class ExceptionPrettyPrinter: def __init__( self, - file: Optional[TextIO] = None, + file: TextIO | None = None, exception_formatter: ExceptionTransformer = _format_exception, ) -> None: if file is not None: @@ -601,7 +598,7 @@ class StackInfoRenderer: __slots__ = ["_additional_ignores"] - def __init__(self, additional_ignores: Optional[List[str]] = None) -> None: + def __init__(self, additional_ignores: list[str] | None = None) -> None: self._additional_ignores = additional_ignores def __call__( @@ -692,7 +689,7 @@ class CallsiteParameterAdder: """ _handlers: ClassVar[ - Dict[CallsiteParameter, Callable[[str, inspect.Traceback], Any]] + dict[CallsiteParameter, Callable[[str, inspect.Traceback], Any]] ] = { CallsiteParameter.PATHNAME: ( lambda module, frame_info: frame_info.filename @@ -722,7 +719,7 @@ class CallsiteParameterAdder: lambda module, frame_info: get_processname() ), } - _record_attribute_map: ClassVar[Dict[CallsiteParameter, str]] = { + _record_attribute_map: ClassVar[dict[CallsiteParameter, str]] = { CallsiteParameter.PATHNAME: "pathname", CallsiteParameter.FILENAME: "filename", CallsiteParameter.MODULE: "module", @@ -734,7 +731,7 @@ class CallsiteParameterAdder: CallsiteParameter.PROCESS_NAME: "processName", } - _all_parameters: ClassVar[Set[CallsiteParameter]] = set(CallsiteParameter) + _all_parameters: ClassVar[set[CallsiteParameter]] = set(CallsiteParameter) class _RecordMapping(NamedTuple): event_dict_key: str @@ -749,7 +746,7 @@ class _RecordMapping(NamedTuple): def __init__( self, parameters: Collection[CallsiteParameter] = _all_parameters, - additional_ignores: Optional[List[str]] = None, + additional_ignores: list[str] | None = None, ) -> None: if additional_ignores is None: additional_ignores = [] @@ -757,12 +754,10 @@ def __init__( # processor is used in ProcessorFormatter, and additionally the logging # module should not be logging using structlog. self._additional_ignores = ["logging", *additional_ignores] - self._active_handlers: List[ - Tuple[CallsiteParameter, Callable[[str, inspect.Traceback], Any]] - ] = [] - self._record_mappings: List[ - "CallsiteParameterAdder._RecordMapping" + self._active_handlers: list[ + tuple[CallsiteParameter, Callable[[str, inspect.Traceback], Any]] ] = [] + self._record_mappings: list[CallsiteParameterAdder._RecordMapping] = [] for parameter in parameters: self._active_handlers.append( (parameter, self._handlers[parameter]) @@ -777,8 +772,8 @@ def __init__( def __call__( self, logger: logging.Logger, name: str, event_dict: EventDict ) -> EventDict: - record: Optional[logging.LogRecord] = event_dict.get("_record") - from_structlog: Optional[bool] = event_dict.get("_from_structlog") + record: logging.LogRecord | None = event_dict.get("_record") + from_structlog: bool | None = event_dict.get("_from_structlog") # If the event dictionary has a record, but it comes from structlog, # then the callsite parameters of the record will not be correct. if record is not None and not from_structlog: @@ -794,3 +789,42 @@ def __call__( for parameter, handler in self._active_handlers: event_dict[parameter.value] = handler(module, frame_info) return event_dict + + +class EventRenamer: + r""" + Rename the ``event`` key in event dicts. + + This is useful if you want to use consistent log message keys across + platforms and/or use the ``event`` key for something custom. + + .. warning:: + + It's recommended to put this processor right before the renderer, since + some processors may rely on the presence and meaning of the ``event`` + key. + + :param to: Rename ``event_dict["event"]`` to ``event_dict[to]`` + :param replace_by: Rename ``event_dict[replace_by]`` to + ``event_dict["event"]``. *replace_by* missing from ``event_dict`` is + handled gracefully. + + .. versionadded:: 22.1 + """ + + def __init__(self, to: str, replace_by: str | None = None): + self.to = to + self.replace_by = replace_by + + def __call__( + self, logger: logging.Logger, name: str, event_dict: EventDict + ) -> EventDict: + event = event_dict.pop("event") + event_dict[self.to] = event + + if self.replace_by is not None: + replace_by = event_dict.pop(self.replace_by, None) + if replace_by is not None: + event_dict["event"] = replace_by + + return event_dict diff --git a/tests/test_dev.py b/tests/test_dev.py index a590d628..6e3df5b7 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -85,7 +85,7 @@ def test_timestamp(self, cr, styles, unpadded): assert (styles.timestamp + "42" + styles.reset + " " + unpadded) == rv - def test_event_stringified(self, cr, styles, unpadded): + def test_event_stringified(self, cr, unpadded): """ Event is cast to string. """ @@ -95,6 +95,16 @@ def test_event_stringified(self, cr, styles, unpadded): assert unpadded == rv + def test_event_renamed(self): + """ + Uses respects if the event key has been renamed. + """ + cr = dev.ConsoleRenderer(colors=False, event_key="msg") + + assert "new event name event=something custom" == cr( + None, None, {"msg": "new event name", "event": "something custom"} + ) + def test_level(self, cr, styles, padded): """ Levels are rendered aligned, in square brackets, and color coded. diff --git a/tests/test_processors.py b/tests/test_processors.py index dbb53643..5ec55b4e 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -28,6 +28,7 @@ from structlog.processors import ( CallsiteParameter, CallsiteParameterAdder, + EventRenamer, ExceptionPrettyPrinter, ExceptionRenderer, JSONRenderer, @@ -1104,3 +1105,33 @@ def get_callsite_parameters(cls, offset: int = 1) -> Dict[str, Any]: "process": os.getpid(), "process_name": get_processname(), } + + +class TestRenameKey: + def test_rename_once(self): + """ + Renaming event to something else works. + """ + assert {"msg": "hi", "foo": "bar"} == EventRenamer("msg")( + None, None, {"event": "hi", "foo": "bar"} + ) + + def test_rename_twice(self): + """ + Renaming both from and to `event` works. + """ + assert { + "msg": "hi", + "event": "fabulous", + "foo": "bar", + } == EventRenamer("msg", "_event")( + None, None, {"event": "hi", "foo": "bar", "_event": "fabulous"} + ) + + def test_replace_by_key_is_optional(self): + """ + The key that is renamed to `event` doesn't have to exist. + """ + assert {"msg": "hi", "foo": "bar"} == EventRenamer("msg", "missing")( + None, None, {"event": "hi", "foo": "bar"} + ) From 9d26ca9762252d6d208b6da75117b8c65d6aad8a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 20 Jul 2022 10:41:20 +0200 Subject: [PATCH 0706/1520] Re-add pepy.tech --- README.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.rst b/README.rst index 73e2682a..d2de5816 100644 --- a/README.rst +++ b/README.rst @@ -15,6 +15,9 @@ PyPI release + + Downloads per month +

    .. -begin-short- From 70deda6f095bae2bcd7301a05f98f47ac5272868 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 20 Jul 2022 10:55:36 +0200 Subject: [PATCH 0707/1520] Clarify license in docs, cleanup index --- README.rst | 2 +- docs/index.rst | 5 +++-- docs/license.rst | 4 ++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index d2de5816..2ada6cb8 100644 --- a/README.rst +++ b/README.rst @@ -44,7 +44,7 @@ If you prefer videos over reading, check out `Markus Holtermann `_ and `MIT `_ +- **License**: *dual* `Apache License, version 2 and MIT `_ - **PyPI**: https://pypi.org/project/structlog/ - **Source Code**: https://github.com/hynek/structlog - **Documentation**: https://www.structlog.org/ diff --git a/docs/index.rst b/docs/index.rst index 146a1405..eb0244b5 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -70,12 +70,13 @@ API Reference api - .. include:: ../README.rst :start-after: -begin-meta- + +.. stop Sphinx from complaints about orphaned docs, we link them elsewhere .. toctree:: - :maxdepth: 1 + :hidden: license changelog diff --git a/docs/license.rst b/docs/license.rst index d9bd3d9a..850d591b 100644 --- a/docs/license.rst +++ b/docs/license.rst @@ -3,6 +3,10 @@ License and Hall of Fame ``structlog`` is licensed both under the `Apache License, Version 2 `_ and the `MIT license `_. +Any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. + +--- + The reason for that is to be both protected against patent claims by own contributors and still allow the usage within GPLv2 software. For more legal details, see `this issue `_ on the bug tracker of PyCA's ``cryptography`` project. From d36624056d9f0028abf8eadc500eb0c9065dc50d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 20 Jul 2022 10:57:29 +0200 Subject: [PATCH 0708/1520] Fix grammar & clarity --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 840b7c7b..8faa4433 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ The format is based on [*Keep a Changelog*](https://keepachangelog.com/en/1.0.0/ The **first number** of the version is the year. The **second number** is incremented with each release, starting at 1 for each year. -The **third number** is when we need to start branches for older releases (only for emergencies). +The **third number** is for emergencies when we need to start branches for older releases. You shouldn't ever be afraid to upgrade `structlog` if you're using its public APIs and pay attention to `DeprecationWarning`s. Whenever there is a need to break compatibility, it is announced here in the changelog and raises a `DeprecationWarning` for a year (if possible) before it's finally really broken. From 414475db1a4982142fdd4e5327602b0dd43e0ba8 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 20 Jul 2022 11:06:31 +0200 Subject: [PATCH 0709/1520] Add structlog.contextvars.merge_contextvars to default config --- CHANGELOG.md | 2 ++ docs/getting-started.rst | 1 + pyproject.toml | 2 +- src/structlog/_config.py | 2 ++ src/structlog/stdlib.py | 5 +++-- 5 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8faa4433..f4b2b4d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -72,6 +72,8 @@ So please make sure to **always** properly configure your applications. - `structlog.processors.format_exc_info()` is no longer a function, but an instance of `structlog.processors.ExceptionRenderer`. Its behavior has not changed. [#407](https://github.com/hynek/structlog/pull/407) +- The default configuration now includes the `structlog.contextvars.merge_contextvars` processor. + That means you can use [`structlog.contextvars`](https://www.structlog.org/en/stable/contextvars.html) features without configuring `structlog`. ### Fixed diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 7fe65b89..7698888d 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -48,6 +48,7 @@ Using the defaults, as above, is equivalent to:: structlog.configure( processors=[ + structlog.contextvars.merge_contextvars, structlog.processors.add_log_level, structlog.processors.StackInfoRenderer(), structlog.dev.set_exc_info, diff --git a/pyproject.toml b/pyproject.toml index 6c52ddf5..f51e6bd8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -226,7 +226,7 @@ If you prefer videos over reading, check out `Markus Holtermann `_ and `MIT `_ +- **License**: *dual* `Apache License, version 2 and MIT `_ - **PyPI**: https://pypi.org/project/structlog/ - **Source Code**: https://github.com/hynek/structlog - **Documentation**: https://www.structlog.org/ diff --git a/src/structlog/_config.py b/src/structlog/_config.py index c069dfdd..e878c3e2 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -24,6 +24,7 @@ from ._log_levels import make_filtering_bound_logger from ._loggers import PrintLoggerFactory +from .contextvars import merge_contextvars from .dev import ConsoleRenderer, _use_colors, set_exc_info from .processors import StackInfoRenderer, TimeStamper, add_log_level from .types import BindableLogger, Context, Processor, WrappedLogger @@ -36,6 +37,7 @@ - structlog.stdlib.recreate_defaults()'s docstring. """ _BUILTIN_DEFAULT_PROCESSORS: Sequence[Processor] = [ + merge_contextvars, add_log_level, StackInfoRenderer(), set_exc_info, diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 0496b244..208b1372 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -20,13 +20,13 @@ from functools import partial from typing import Any, Callable, Collection, Iterable, Sequence -from structlog.processors import StackInfoRenderer - from . import _config from ._base import BoundLoggerBase from ._frames import _find_first_app_frame_and_name, _format_stack from ._log_levels import _LEVEL_TO_NAME, _NAME_TO_LEVEL, add_log_level +from .contextvars import merge_contextvars from .exceptions import DropEvent +from .processors import StackInfoRenderer from .types import Context, EventDict, ExcInfo, Processor, WrappedLogger @@ -83,6 +83,7 @@ def recreate_defaults(*, log_level: int | None = logging.NOTSET) -> None: _config.reset_defaults() _config.configure( processors=[ + merge_contextvars, add_log_level, StackInfoRenderer(), _config._BUILTIN_DEFAULT_PROCESSORS[-2], # TimeStamper From 6fb6e7a7b83427f7b0c87ce2a8b0371f43ac75b2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 20 Jul 2022 11:40:53 +0200 Subject: [PATCH 0710/1520] Add annotations future import to src/* for consistency --- docs/conf.py | 3 +- src/structlog/__init__.py | 2 ++ src/structlog/_base.py | 18 ++++++----- src/structlog/_config.py | 62 ++++++++++++++++-------------------- src/structlog/_frames.py | 7 ++-- src/structlog/_generic.py | 8 +++-- src/structlog/_greenlets.py | 2 ++ src/structlog/_log_levels.py | 10 +++--- src/structlog/_utils.py | 2 ++ src/structlog/contextvars.py | 14 ++++---- src/structlog/dev.py | 6 ++-- src/structlog/exceptions.py | 2 ++ src/structlog/testing.py | 14 ++++---- src/structlog/threadlocal.py | 10 +++--- src/structlog/tracebacks.py | 23 +++++++------ src/structlog/twisted.py | 17 +++++----- src/structlog/types.py | 18 ++++++----- 17 files changed, 120 insertions(+), 98 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index fb18920f..3fdfc433 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -54,11 +54,12 @@ nitpick_ignore = [ ("py:class", "Context"), + ("py:class", "EventDict"), ("py:class", "ILogObserver"), ("py:class", "PlainFileObserver"), ("py:class", "Processor"), + ("py:class", "Styles"), ("py:class", "WrappedLogger"), - ("py:class", "structlog.dev._Styles"), ("py:class", "structlog.threadlocal.TLLogger"), ("py:class", "structlog.types.EventDict"), ] diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index af96227d..a48c4da3 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -7,6 +7,8 @@ Structured Logging for Python """ +from __future__ import annotations + from structlog import ( contextvars, dev, diff --git a/src/structlog/_base.py b/src/structlog/_base.py index b59c554e..f34cc9c5 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -7,7 +7,9 @@ Logger wrapper and helper class. """ -from typing import Any, Dict, Iterable, Mapping, Optional, Sequence, Tuple +from __future__ import annotations + +from typing import Any, Iterable, Mapping, Sequence from structlog.exceptions import DropEvent @@ -65,7 +67,7 @@ def __eq__(self, other: Any) -> bool: def __ne__(self, other: Any) -> bool: return not self.__eq__(other) - def bind(self, **new_values: Any) -> "BoundLoggerBase": + def bind(self, **new_values: Any) -> BoundLoggerBase: """ Return a new logger with *new_values* added to the existing ones. """ @@ -75,7 +77,7 @@ def bind(self, **new_values: Any) -> "BoundLoggerBase": self._context.__class__(self._context, **new_values), ) - def unbind(self, *keys: str) -> "BoundLoggerBase": + def unbind(self, *keys: str) -> BoundLoggerBase: """ Return a new logger with *keys* removed from the context. @@ -87,7 +89,7 @@ def unbind(self, *keys: str) -> "BoundLoggerBase": return bl - def try_unbind(self, *keys: str) -> "BoundLoggerBase": + def try_unbind(self, *keys: str) -> BoundLoggerBase: """ Like :meth:`unbind`, but best effort: missing keys are ignored. @@ -99,7 +101,7 @@ def try_unbind(self, *keys: str) -> "BoundLoggerBase": return bl - def new(self, **new_values: Any) -> "BoundLoggerBase": + def new(self, **new_values: Any) -> BoundLoggerBase: """ Clear context and binds *initial_values* using `bind`. @@ -114,8 +116,8 @@ def new(self, **new_values: Any) -> "BoundLoggerBase": # Helper methods for sub-classing concrete BoundLoggers. def _process_event( - self, method_name: str, event: Optional[str], event_kw: Dict[str, Any] - ) -> Tuple[Sequence[Any], Mapping[str, Any]]: + self, method_name: str, event: str | None, event_kw: dict[str, Any] + ) -> tuple[Sequence[Any], Mapping[str, Any]]: """ Combines creates an ``event_dict`` and runs the chain. @@ -175,7 +177,7 @@ def _process_event( ) def _proxy_to_logger( - self, method_name: str, event: Optional[str] = None, **event_kw: Any + self, method_name: str, event: str | None = None, **event_kw: Any ) -> Any: """ Run processor chain on event & call *method_name* on wrapped logger. diff --git a/src/structlog/_config.py b/src/structlog/_config.py index e878c3e2..52e40e7a 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -7,20 +7,12 @@ Global state department. Don't reload this module or everything breaks. """ +from __future__ import annotations import sys import warnings -from typing import ( - Any, - Callable, - Dict, - Iterable, - Optional, - Sequence, - Type, - cast, -) +from typing import Any, Callable, Iterable, Sequence, Type, cast from ._log_levels import make_filtering_bound_logger from ._loggers import PrintLoggerFactory @@ -62,7 +54,7 @@ class _Configuration: is_configured: bool = False default_processors: Iterable[Processor] = _BUILTIN_DEFAULT_PROCESSORS[:] - default_context_class: Type[Context] = _BUILTIN_DEFAULT_CONTEXT_CLASS + default_context_class: type[Context] = _BUILTIN_DEFAULT_CONTEXT_CLASS default_wrapper_class: Any = _BUILTIN_DEFAULT_WRAPPER_CLASS logger_factory: Callable[ ..., WrappedLogger @@ -87,7 +79,7 @@ def is_configured() -> bool: return _CONFIG.is_configured -def get_config() -> Dict[str, Any]: +def get_config() -> dict[str, Any]: """ Get a dictionary with the current configuration. @@ -146,12 +138,12 @@ def get_logger(*args: Any, **initial_values: Any) -> Any: def wrap_logger( logger: WrappedLogger, - processors: Optional[Iterable[Processor]] = None, - wrapper_class: Optional[Type[BindableLogger]] = None, - context_class: Optional[Type[Context]] = None, - cache_logger_on_first_use: Optional[bool] = None, - logger_factory_args: Optional[Iterable[Any]] = None, - **initial_values: Any + processors: Iterable[Processor] | None = None, + wrapper_class: type[BindableLogger] | None = None, + context_class: type[Context] | None = None, + cache_logger_on_first_use: bool | None = None, + logger_factory_args: Iterable[Any] | None = None, + **initial_values: Any, ) -> Any: """ Create a new bound logger for an arbitrary *logger*. @@ -189,11 +181,11 @@ def wrap_logger( def configure( - processors: Optional[Iterable[Processor]] = None, - wrapper_class: Optional[Type[BindableLogger]] = None, - context_class: Optional[Type[Context]] = None, - logger_factory: Optional[Callable[..., WrappedLogger]] = None, - cache_logger_on_first_use: Optional[bool] = None, + processors: Iterable[Processor] | None = None, + wrapper_class: type[BindableLogger] | None = None, + context_class: type[Context] | None = None, + logger_factory: Callable[..., WrappedLogger] | None = None, + cache_logger_on_first_use: bool | None = None, ) -> None: """ Configures the **global** defaults. @@ -239,11 +231,11 @@ def configure( def configure_once( - processors: Optional[Iterable[Processor]] = None, - wrapper_class: Optional[Type[BindableLogger]] = None, - context_class: Optional[Type[Context]] = None, - logger_factory: Optional[Callable[..., WrappedLogger]] = None, - cache_logger_on_first_use: Optional[bool] = None, + processors: Iterable[Processor] | None = None, + wrapper_class: type[BindableLogger] | None = None, + context_class: type[Context] | None = None, + logger_factory: Callable[..., WrappedLogger] | None = None, + cache_logger_on_first_use: bool | None = None, ) -> None: """ Configures if structlog isn't configured yet. @@ -298,11 +290,11 @@ class BoundLoggerLazyProxy: def __init__( self, logger: WrappedLogger, - wrapper_class: Optional[Type[BindableLogger]] = None, - processors: Optional[Iterable[Processor]] = None, - context_class: Optional[Type[Context]] = None, - cache_logger_on_first_use: Optional[bool] = None, - initial_values: Optional[Dict[str, Any]] = None, + wrapper_class: type[BindableLogger] | None = None, + processors: Iterable[Processor] | None = None, + context_class: type[Context] | None = None, + cache_logger_on_first_use: bool | None = None, + initial_values: dict[str, Any] | None = None, logger_factory_args: Any = None, ) -> None: self._logger = logger @@ -398,13 +390,13 @@ def __getattr__(self, name: str) -> Any: return getattr(bl, name) - def __getstate__(self) -> Dict[str, Any]: + def __getstate__(self) -> dict[str, Any]: """ Our __getattr__ magic makes this necessary. """ return self.__dict__ - def __setstate__(self, state: Dict[str, Any]) -> None: + def __setstate__(self, state: dict[str, Any]) -> None: """ Our __getattr__ magic makes this necessary. """ diff --git a/src/structlog/_frames.py b/src/structlog/_frames.py index fa2292de..84842421 100644 --- a/src/structlog/_frames.py +++ b/src/structlog/_frames.py @@ -3,12 +3,13 @@ # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. +from __future__ import annotations + import sys import traceback from io import StringIO from types import FrameType -from typing import List, Optional, Tuple from .types import ExcInfo @@ -31,8 +32,8 @@ def _format_exception(exc_info: ExcInfo) -> str: def _find_first_app_frame_and_name( - additional_ignores: Optional[List[str]] = None, -) -> Tuple[FrameType, str]: + additional_ignores: list[str] | None = None, +) -> tuple[FrameType, str]: """ Remove all intra-structlog calls and return the relevant app frame. diff --git a/src/structlog/_generic.py b/src/structlog/_generic.py index 3c758e34..bce8fd9f 100644 --- a/src/structlog/_generic.py +++ b/src/structlog/_generic.py @@ -7,8 +7,10 @@ Generic bound logger that can wrap anything. """ +from __future__ import annotations + from functools import partial -from typing import Any, Dict +from typing import Any from structlog._base import BoundLoggerBase @@ -38,13 +40,13 @@ def __getattr__(self, method_name: str) -> Any: return wrapped - def __getstate__(self) -> Dict[str, Any]: + def __getstate__(self) -> dict[str, Any]: """ Our __getattr__ magic makes this necessary. """ return self.__dict__ - def __setstate__(self, state: Dict[str, Any]) -> None: + def __setstate__(self, state: dict[str, Any]) -> None: """ Our __getattr__ magic makes this necessary. """ diff --git a/src/structlog/_greenlets.py b/src/structlog/_greenlets.py index d5916d68..43db1c10 100644 --- a/src/structlog/_greenlets.py +++ b/src/structlog/_greenlets.py @@ -9,6 +9,8 @@ Fails to import if not running under greenlet. """ +from __future__ import annotations + from typing import Any from weakref import WeakKeyDictionary diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index e15726a3..e664164d 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -7,9 +7,11 @@ Extracted log level data used by both stdlib and native log level filters. """ +from __future__ import annotations + import logging -from typing import Any, Callable, Dict, Type +from typing import Any, Callable from ._base import BoundLoggerBase from .types import EventDict, FilteringBoundLogger @@ -77,7 +79,7 @@ def exception(self: FilteringBoundLogger, event: str, **kw: Any) -> Any: return self.error(event, **kw) -def make_filtering_bound_logger(min_level: int) -> Type[FilteringBoundLogger]: +def make_filtering_bound_logger(min_level: int) -> type[FilteringBoundLogger]: """ Create a new `FilteringBoundLogger` that only logs *min_level* or higher. @@ -110,7 +112,7 @@ def make_filtering_bound_logger(min_level: int) -> Type[FilteringBoundLogger]: return _LEVEL_TO_FILTERING_LOGGER[min_level] -def _make_filtering_bound_logger(min_level: int) -> Type[FilteringBoundLogger]: +def _make_filtering_bound_logger(min_level: int) -> type[FilteringBoundLogger]: """ Create a new `FilteringBoundLogger` that only logs *min_level* or higher. @@ -137,7 +139,7 @@ def log(self: Any, level: int, event: str, **kw: Any) -> Any: name = _LEVEL_TO_NAME[level] return self._proxy_to_logger(name, event, **kw) - meths: Dict[str, Callable] = {"log": log} + meths: dict[str, Callable] = {"log": log} for lvl, name in _LEVEL_TO_NAME.items(): meths[name] = make_method(lvl) diff --git a/src/structlog/_utils.py b/src/structlog/_utils.py index 4202ef01..715ec631 100644 --- a/src/structlog/_utils.py +++ b/src/structlog/_utils.py @@ -7,6 +7,8 @@ Generic utilities. """ +from __future__ import annotations + import errno import sys diff --git a/src/structlog/contextvars.py b/src/structlog/contextvars.py index a4500f8a..e6c2e5cf 100644 --- a/src/structlog/contextvars.py +++ b/src/structlog/contextvars.py @@ -15,10 +15,12 @@ See :doc:`contextvars`. """ +from __future__ import annotations + import contextlib import contextvars -from typing import Any, Dict, Generator, Mapping +from typing import Any, Generator, Mapping import structlog @@ -31,10 +33,10 @@ # For proper isolation, we have to use a dict of ContextVars instead of a # single ContextVar with a dict. # See https://github.com/hynek/structlog/pull/302 for details. -_CONTEXT_VARS: Dict[str, contextvars.ContextVar[Any]] = {} +_CONTEXT_VARS: dict[str, contextvars.ContextVar[Any]] = {} -def get_contextvars() -> Dict[str, Any]: +def get_contextvars() -> dict[str, Any]: """ Return a copy of the ``structlog``-specific context-local context. @@ -50,7 +52,7 @@ def get_contextvars() -> Dict[str, Any]: return rv -def get_merged_contextvars(bound_logger: BindableLogger) -> Dict[str, Any]: +def get_merged_contextvars(bound_logger: BindableLogger) -> dict[str, Any]: """ Return a copy of the current context-local context merged with the context from *bound_logger*. @@ -100,7 +102,7 @@ def clear_contextvars() -> None: k.set(Ellipsis) -def bind_contextvars(**kw: Any) -> "Mapping[str, contextvars.Token[Any]]": +def bind_contextvars(**kw: Any) -> Mapping[str, contextvars.Token[Any]]: r""" Put keys and values into the context-local context. @@ -129,7 +131,7 @@ def bind_contextvars(**kw: Any) -> "Mapping[str, contextvars.Token[Any]]": return rv -def reset_contextvars(**kw: "contextvars.Token[Any]") -> None: +def reset_contextvars(**kw: contextvars.Token[Any]) -> None: r""" Reset contextvars corresponding to the given Tokens. diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 89bbfb17..d404b4fc 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -9,11 +9,13 @@ See also the narrative documentation in `development`. """ +from __future__ import annotations + import sys import warnings from io import StringIO -from typing import Any, Iterable, Optional, TextIO, Type, Union +from typing import Any, Iterable, TextIO, Type, Union from ._frames import _format_exception from .types import ( @@ -279,7 +281,7 @@ def __init__( colors: bool = _use_colors, force_colors: bool = False, repr_native_str: bool = False, - level_styles: Optional[Styles] = None, + level_styles: Styles | None = None, exception_formatter: ExceptionRenderer = default_exception_formatter, sort_keys: bool = True, event_key: str = "event", diff --git a/src/structlog/exceptions.py b/src/structlog/exceptions.py index 5b3b3203..af46a357 100644 --- a/src/structlog/exceptions.py +++ b/src/structlog/exceptions.py @@ -7,6 +7,8 @@ Exceptions factored out to avoid import loops. """ +from __future__ import annotations + class DropEvent(BaseException): """ diff --git a/src/structlog/testing.py b/src/structlog/testing.py index 075ab449..13ce6696 100644 --- a/src/structlog/testing.py +++ b/src/structlog/testing.py @@ -11,8 +11,10 @@ See :doc:`testing`. """ +from __future__ import annotations + from contextlib import contextmanager -from typing import Any, Dict, Generator, List, NamedTuple, NoReturn, Tuple +from typing import Any, Generator, NamedTuple, NoReturn from ._config import configure, get_config from .exceptions import DropEvent @@ -33,7 +35,7 @@ class LogCapture: .. versionadded:: 20.1.0 """ - entries: List[EventDict] + entries: list[EventDict] def __init__(self) -> None: self.entries = [] @@ -48,7 +50,7 @@ def __call__( @contextmanager -def capture_logs() -> Generator[List[EventDict], None, None]: +def capture_logs() -> Generator[list[EventDict], None, None]: """ Context manager that appends all logging statements to its yielded list while it is active. Disables all configured processors for the duration @@ -137,8 +139,8 @@ class CapturedCall(NamedTuple): """ method_name: str - args: Tuple[Any, ...] - kwargs: Dict[str, Any] + args: tuple[Any, ...] + kwargs: dict[str, Any] class CapturingLogger: @@ -153,7 +155,7 @@ class CapturingLogger: .. versionadded:: 20.2.0 """ - calls: List[CapturedCall] + calls: list[CapturedCall] def __init__(self) -> None: self.calls = [] diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index 5cf551e0..09b05c94 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -12,13 +12,15 @@ .. deprecated:: 22.1.0 """ +from __future__ import annotations + import contextlib import sys import threading import uuid import warnings -from typing import Any, Dict, Generator, Iterator, Type, TypeVar +from typing import Any, Generator, Iterator, TypeVar import structlog @@ -26,7 +28,7 @@ from .types import BindableLogger, Context, EventDict, WrappedLogger -def _determine_threadlocal() -> Type[Any]: +def _determine_threadlocal() -> type[Any]: """ Return a dict-like threadlocal storage depending on whether we run with greenlets or not. @@ -74,7 +76,7 @@ def _deprecated() -> None: ) -def wrap_dict(dict_class: Type[Context]) -> Type[Context]: +def wrap_dict(dict_class: type[Context]) -> type[Context]: """ Wrap a dict-like class and return the resulting class. @@ -162,7 +164,7 @@ class _ThreadLocalDictWrapper: """ _tl: Any - _dict_class: Type[Dict[str, Any]] + _dict_class: type[dict[str, Any]] def __init__(self, *args: Any, **kw: Any) -> None: """ diff --git a/src/structlog/tracebacks.py b/src/structlog/tracebacks.py index 66817e08..64d72c2e 100644 --- a/src/structlog/tracebacks.py +++ b/src/structlog/tracebacks.py @@ -4,12 +4,15 @@ Copied and adapted from Rich: https://github.com/Textualize/rich/blob/972dedff/rich/traceback.py """ + +from __future__ import annotations + import os from dataclasses import asdict, dataclass, field from traceback import walk_tb from types import TracebackType -from typing import Any, Dict, List, Optional, Tuple, Type, Union +from typing import Any, Tuple, Union from .types import ExcInfo @@ -43,7 +46,7 @@ class Frame: lineno: int name: str line: str = "" - locals: Optional[Dict[str, str]] = None + locals: dict[str, str] | None = None @dataclass @@ -67,9 +70,9 @@ class Stack: exc_type: str exc_value: str - syntax_error: Optional[SyntaxError_] = None + syntax_error: SyntaxError_ | None = None is_cause: bool = False - frames: List[Frame] = field(default_factory=list) + frames: list[Frame] = field(default_factory=list) @dataclass @@ -78,7 +81,7 @@ class Trace: Container for a list of stack traces. """ - stacks: List[Stack] + stacks: list[Stack] def safe_str(_object: Any) -> str: @@ -89,7 +92,7 @@ def safe_str(_object: Any) -> str: return f"" -def to_repr(obj: Any, max_string: Optional[int] = None) -> str: +def to_repr(obj: Any, max_string: int | None = None) -> str: """Get repr string for an object, but catch errors.""" if isinstance(obj, str): obj_repr = obj @@ -107,9 +110,9 @@ def to_repr(obj: Any, max_string: Optional[int] = None) -> str: def extract( - exc_type: Type[BaseException], + exc_type: type[BaseException], exc_value: BaseException, - traceback: Optional[TracebackType], + traceback: TracebackType | None, *, show_locals: bool = False, locals_max_string: int = LOCALS_MAX_STRING, @@ -131,7 +134,7 @@ def extract( .. versionadded:: 22.1 """ - stacks: List[Stack] = [] + stacks: list[Stack] = [] is_cause = False while True: @@ -232,7 +235,7 @@ def __init__( self.locals_max_string = locals_max_string self.max_frames = max_frames - def __call__(self, exc_info: ExcInfo) -> List[Dict[str, Any]]: + def __call__(self, exc_info: ExcInfo) -> list[dict[str, Any]]: trace = extract( *exc_info, show_locals=self.show_locals, diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index f88dc97d..618d3463 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -10,10 +10,12 @@ See also :doc:`structlog's Twisted support `. """ +from __future__ import annotations + import json import sys -from typing import Any, Callable, Dict, Optional, Sequence, TextIO, Tuple +from typing import Any, Callable, Sequence, TextIO from twisted.python import log from twisted.python.failure import Failure @@ -42,13 +44,13 @@ class BoundLogger(BoundLoggerBase): """ - def msg(self, event: Optional[str] = None, **kw: Any) -> Any: + def msg(self, event: str | None = None, **kw: Any) -> Any: """ Process event and call ``log.msg()`` with the result. """ return self._proxy_to_logger("msg", event, **kw) - def err(self, event: Optional[str] = None, **kw: Any) -> Any: + def err(self, event: str | None = None, **kw: Any) -> Any: """ Process event and call ``log.err()`` with the result. """ @@ -79,7 +81,7 @@ def __call__(self, *args: Any) -> WrappedLogger: _FAIL_TYPES = (BaseException, Failure) -def _extractStuffAndWhy(eventDict: EventDict) -> Tuple[Any, Any, EventDict]: +def _extractStuffAndWhy(eventDict: EventDict) -> tuple[Any, Any, EventDict]: """ Removes all possible *_why*s and *_stuff*s, analyzes exc_info and returns a tuple of ``(_stuff, _why, eventDict)``. @@ -173,7 +175,7 @@ def __call__( # type: ignore logger: WrappedLogger, name: str, eventDict: EventDict, - ) -> Tuple[Sequence[Any], Dict[str, Any]]: + ) -> tuple[Sequence[Any], dict[str, Any]]: _stuff, _why, eventDict = _extractStuffAndWhy(eventDict) if name == "err": eventDict["event"] = _why @@ -292,9 +294,8 @@ class EventAdapter: def __init__( self, - dictRenderer: Optional[ - Callable[[WrappedLogger, str, EventDict], str] - ] = None, + dictRenderer: Callable[[WrappedLogger, str, EventDict], str] + | None = None, ) -> None: """ :param dictRenderer: A processor used to format the log message. diff --git a/src/structlog/types.py b/src/structlog/types.py index 5c9b22ce..01f06d81 100644 --- a/src/structlog/types.py +++ b/src/structlog/types.py @@ -12,6 +12,8 @@ .. versionadded:: 20.2 """ +from __future__ import annotations + import sys from types import TracebackType @@ -132,16 +134,16 @@ class BindableLogger(Protocol): _context: Context - def bind(self, **new_values: Any) -> "BindableLogger": + def bind(self, **new_values: Any) -> BindableLogger: ... - def unbind(self, *keys: str) -> "BindableLogger": + def unbind(self, *keys: str) -> BindableLogger: ... - def try_unbind(self, *keys: str) -> "BindableLogger": + def try_unbind(self, *keys: str) -> BindableLogger: ... - def new(self, **new_values: Any) -> "BindableLogger": + def new(self, **new_values: Any) -> BindableLogger: ... @@ -154,28 +156,28 @@ class FilteringBoundLogger(BindableLogger, Protocol): .. versionadded:: 20.2.0 """ - def bind(self, **new_values: Any) -> "FilteringBoundLogger": + def bind(self, **new_values: Any) -> FilteringBoundLogger: """ Return a new logger with *new_values* added to the existing ones. .. versionadded:: 22.1.0 """ - def unbind(self, *keys: str) -> "FilteringBoundLogger": + def unbind(self, *keys: str) -> FilteringBoundLogger: """ Return a new logger with *keys* removed from the context. .. versionadded:: 22.1.0 """ - def try_unbind(self, *keys: str) -> "FilteringBoundLogger": + def try_unbind(self, *keys: str) -> FilteringBoundLogger: """ Like :meth:`unbind`, but best effort: missing keys are ignored. .. versionadded:: 22.1.0 """ - def new(self, **new_values: Any) -> "FilteringBoundLogger": + def new(self, **new_values: Any) -> FilteringBoundLogger: """ Clear context and binds *initial_values* using `bind`. From 9b2458b1e215251e2e4aa9f0701e98ec03cae9ec Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 20 Jul 2022 11:47:16 +0200 Subject: [PATCH 0711/1520] Clarify licensing/contribution of trackbacks.py --- src/structlog/tracebacks.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/structlog/tracebacks.py b/src/structlog/tracebacks.py index 64d72c2e..733d7a19 100644 --- a/src/structlog/tracebacks.py +++ b/src/structlog/tracebacks.py @@ -1,7 +1,13 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the MIT License. See the LICENSE file in the root of this +# repository for complete details. + """ Extract a structured traceback from an exception. -Copied and adapted from Rich: +Contributed by Will McGugan (see +https://github.com/hynek/structlog/pull/407#issuecomment-1150926246) from Rich: https://github.com/Textualize/rich/blob/972dedff/rich/traceback.py """ From 63e1dcd99504d75df31e79ce292d35cb016fec3b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 20 Jul 2022 12:09:11 +0200 Subject: [PATCH 0712/1520] Steal Rust's dual-license handling again Also try to stop GitHub from complaining about an unknown license by renaming it. --- LICENSE => COPYRIGHT | 6 +++--- LICENSE.apache2 => LICENSE-APACHE | 0 LICENSE.mit => LICENSE-MIT | 2 +- NOTICE | 2 ++ docs/license.rst | 4 ++-- pyproject.toml | 6 ++++-- 6 files changed, 12 insertions(+), 8 deletions(-) rename LICENSE => COPYRIGHT (52%) rename LICENSE.apache2 => LICENSE-APACHE (100%) rename LICENSE.mit => LICENSE-MIT (94%) create mode 100644 NOTICE diff --git a/LICENSE b/COPYRIGHT similarity index 52% rename from LICENSE rename to COPYRIGHT index 0ee13911..480e3e23 100644 --- a/LICENSE +++ b/COPYRIGHT @@ -1,10 +1,10 @@ Licensed under either of -- Apache License, Version 2.0 (LICENSE.apache or ) -- or MIT license (LICENSE.mit or ) +- Apache License, Version 2.0 (LICENSE-APACHE or ) +- or MIT license (LICENSE-MIT or ) at your option. Any contribution intentionally submitted for inclusion in the work by you, as -defined in the Apache-2.0 license, shall be dual licensed as above, without any +defined in the Apache-2.0 license, shall be dual-licensed as above, without any additional terms or conditions. diff --git a/LICENSE.apache2 b/LICENSE-APACHE similarity index 100% rename from LICENSE.apache2 rename to LICENSE-APACHE diff --git a/LICENSE.mit b/LICENSE-MIT similarity index 94% rename from LICENSE.mit rename to LICENSE-MIT index cdaa1f7e..c92f9b69 100644 --- a/LICENSE.mit +++ b/LICENSE-MIT @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013 Hynek Schlawack +Copyright (c) 2013 Hynek Schlawack and the structlog contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NOTICE b/NOTICE new file mode 100644 index 00000000..ad0c5978 --- /dev/null +++ b/NOTICE @@ -0,0 +1,2 @@ +structlog +Copyright 2013 Hynek Schlawack and the structlog contributors diff --git a/docs/license.rst b/docs/license.rst index 850d591b..25001344 100644 --- a/docs/license.rst +++ b/docs/license.rst @@ -12,8 +12,8 @@ For more legal details, see `this issue `_ -- `MIT `_ +- `Apache License 2.0 `_ +- `MIT `_ .. _authors: diff --git a/pyproject.toml b/pyproject.toml index f51e6bd8..50d3593d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ authors = [{name = "Hynek Schlawack", email = "hs@ox.cx"}] dynamic = ["version", "description"] requires-python = ">=3.7" dependencies = ["typing-extensions; python_version<'3.8'"] -license = { file = "LICENSE" } +license = { file = "COPYRIGHT" } keywords = ["logging", "structured", "structure", "log"] classifiers = [ "Development Status :: 5 - Production/Stable", @@ -25,6 +25,7 @@ classifiers = [ "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Programming Language :: Python", @@ -47,7 +48,8 @@ include = [ ".readthedocs.yml", "*.ini", "*.rst", - "LICENSE.*", + "COPYRIGHT", + "LICENSE*", "docs", "tests", ".github", From 6b30f493aecfb19650815aa3e22d13b13560e0d6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 20 Jul 2022 12:24:15 +0200 Subject: [PATCH 0713/1520] Fix broken links --- CHANGELOG.md | 5 +++-- docs/api.rst | 2 +- docs/configuration.rst | 4 ++-- docs/getting-started.rst | 2 +- docs/logging-best-practices.rst | 2 +- docs/twisted.rst | 2 +- src/structlog/twisted.py | 20 ++++++++++---------- 7 files changed, 19 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4b2b4d2..c0395b67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -129,7 +129,8 @@ So please make sure to **always** properly configure your applications. ### Changed -- `structlog` switched its packaging to [*flit*](https://flit.readthedocs.io/). Users shouldn't notice a difference, but (re-)packagers might. +- `structlog` switched its packaging to [*flit*](https://flit.pypa.io/). + Users shouldn't notice a difference, but (re-)packagers might. - `structlog.stdlib.AsyncBoundLogger` now determines the running loop when logging, not on instantiation. That has a minor performance impact, but makes it more robust when loops change (e.g. `aiohttp.web.run_app()`), or you want to use `sync_bl` *before* a loop has started. @@ -160,7 +161,7 @@ So please make sure to **always** properly configure your applications. - `structlog.contextvars.bind_contextvars()` now returns a mapping of keys to `contextvars.Token`s, allowing you to reset values using the new `structlog.contextvars.reset_contextvars()`. [#339](https://github.com/hynek/structlog/pull/339) - Exception rendering in `structlog.dev.ConsoleLogger` is now configurable using the `exception_formatter` setting. - If either the [*rich*](https://github.com/willmcgugan/rich) or the [*better-exceptions*](https://github.com/qix-/better-exceptions) package is present, `structlog` will use them for pretty-printing tracebacks. + If either the [*rich*](https://github.com/Textualize/rich) or the [*better-exceptions*](https://github.com/qix-/better-exceptions) package is present, `structlog` will use them for pretty-printing tracebacks. *rich* takes precedence over *better-exceptions* if both are present. This only works if `format_exc_info` is **absent** in the processor chain. diff --git a/docs/api.rst b/docs/api.rst index edb810bb..10776b79 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -336,7 +336,7 @@ API Reference .. method:: __init__(self, wrapped_logger: WrappedLogger, processors: Iterable[Processor], context: Context) -> None :noindex: - Unfortunately it's impossible to define initializers using `PEP 544 `_ Protocols. + Unfortunately it's impossible to define initializers using :pep:`544` Protocols. They currently also have to carry a `Context` as a ``_context`` attribute. diff --git a/docs/configuration.rst b/docs/configuration.rst index 13f928b4..2e8dfe89 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -163,7 +163,7 @@ If you use standard library's logging, it makes sense to configure them next to `Application constructor `_. **Twisted** - The `plugin definition `_ is the best place. - If your app is not a plugin, put it into your `tac file `_. + The `plugin definition `_ is the best place. + If your app is not a plugin, put it into your `tac file `_. If you have no choice but *have* to configure on import time in module-global scope, or can't rule out for other reasons that that your `structlog.configure` gets called more than once, ``structlog`` offers `structlog.configure_once` that raises a warning if ``structlog`` has been configured before (no matter whether using `structlog.configure` or :func:`~structlog.configure_once`) but doesn't change anything. diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 7698888d..3f19119f 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -205,6 +205,6 @@ If you want to see more code, make sure to check out the `examples`! .. _`standard out`: https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29 .. _recipe: https://docs.python.org/3/howto/logging-cookbook.html#implementing-structured-logging -.. _rich: https://github.com/willmcgugan/rich +.. _rich: https://github.com/Textualize/rich .. _`better-exceptions`: https://github.com/qix-/better-exceptions .. _colorama: https://pypi.org/project/colorama/ diff --git a/docs/logging-best-practices.rst b/docs/logging-best-practices.rst index c1c90796..e1003539 100644 --- a/docs/logging-best-practices.rst +++ b/docs/logging-best-practices.rst @@ -98,7 +98,7 @@ Additionally, `Graylog's Extended Log Format`_ (GELF) allows for structured data .. _Logstash: https://www.elastic.co/logstash .. _Kibana: https://www.elastic.co/kibana .. _Elasticsearch: https://www.elastic.co/elasticsearch -.. _`Graylog's Extended Log Format`: https://docs.graylog.org/en/latest/pages/gelf.html +.. _`Graylog's Extended Log Format`: https://docs.graylog.org/docs/gelf .. _`standard out`: https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29 .. _syslogd: https://en.wikipedia.org/wiki/Syslogd .. _`twelve-factor app methodology`: https://12factor.net/logs diff --git a/docs/twisted.rst b/docs/twisted.rst index 1174cde3..ace0b7a8 100644 --- a/docs/twisted.rst +++ b/docs/twisted.rst @@ -30,7 +30,7 @@ Processors `structlog.twisted.EventAdapter` This is useful if you have an existing Twisted application and just want to wrap your loggers for now. - It takes care of transforming your event dictionary into something `twisted.python.log.err `_ can digest. + It takes care of transforming your event dictionary into something `twisted.python.log.err `_ can digest. For example:: diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index 618d3463..5fc9dad2 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -4,7 +4,7 @@ # repository for complete details. """ -Processors and tools specific to the `Twisted `_ +Processors and tools specific to the `Twisted `_ networking engine. See also :doc:`structlog's Twisted support `. @@ -150,8 +150,8 @@ def __repr__(self) -> str: class JSONRenderer(GenericJSONRenderer): """ - Behaves like `structlog.processors.JSONRenderer` except that it - formats tracebacks and failures itself if called with ``err()``. + Behaves like `structlog.processors.JSONRenderer` except that it formats + tracebacks and failures itself if called with ``err()``. .. note:: @@ -159,9 +159,9 @@ class JSONRenderer(GenericJSONRenderer): and *not* ``err()`` which renders failures in separate lines. Therefore it will break your tests that contain assertions using - `flushLoggedErrors `_. + `flushLoggedErrors + `_. *Not* an adapter like `EventAdapter` but a real formatter. Also does *not* require to be adapted using it. @@ -227,8 +227,8 @@ class JSONLogObserverWrapper: :param ILogObserver observer: Twisted log observer to wrap. For example :class:`PlainFileObserver` or Twisted's stock `FileLogObserver - `_ + `_ .. versionadded:: 0.2.0 """ @@ -281,8 +281,8 @@ class EventAdapter: Adapt an ``event_dict`` to Twisted logging system. Particularly, make a wrapped `twisted.python.log.err - `_ behave as expected. + `_ + behave as expected. :param dictRenderer: Renderer that is used for the actual log message. Please note that structlog comes with a dedicated `JSONRenderer`. From 646e9fcbf170c81acdfbf6847d42c208f970afb1 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 20 Jul 2022 12:44:29 +0200 Subject: [PATCH 0714/1520] Add NOTICE to sdist --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 50d3593d..a7072dc7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,6 +50,7 @@ include = [ "*.rst", "COPYRIGHT", "LICENSE*", + "NOTICE", "docs", "tests", ".github", From 425b7e12c7c66bd7e0c91cb9edf2430ceac110cf Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 20 Jul 2022 13:04:37 +0200 Subject: [PATCH 0715/1520] Ignore compare links (they may not exist yet) --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 3fdfc433..3baf63eb 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -145,7 +145,7 @@ # GitHub has rate limits linkcheck_ignore = [ - r"https://github.com/.*/(issues|pull)/\d+", + r"https://github.com/.*/(issues|pull|compare)/\d+", r"https://twitter.com/.*", ] From 0ca06b75855cdd927804f3cb17e824db0370d7ad Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 20 Jul 2022 13:06:03 +0200 Subject: [PATCH 0716/1520] Prepare 22.1.0 --- CHANGELOG.md | 2 +- src/structlog/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0395b67..eb0a6926 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ So please make sure to **always** properly configure your applications. -## [Unreleased](https://github.com/hynek/structlog/compare/21.5.0...HEAD) +## [22.1.0](https://github.com/hynek/structlog/compare/21.5.0...22.1.0) - 2022-07-20 ### Removed diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index a48c4da3..188afe1f 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -50,7 +50,7 @@ twisted = None # type: ignore -__version__ = "22.1.0.dev0" +__version__ = "22.1.0" __title__ = "structlog" # __doc__ is None when running with PYTHONOPTIMIZE=2 / -OO From e4d8a663931421c5e4e7ce653a08de0084c3703f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 20 Jul 2022 13:20:15 +0200 Subject: [PATCH 0717/1520] Start new development cycle --- CHANGELOG.md | 3 +++ src/structlog/__init__.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb0a6926..c7866007 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,9 @@ So please make sure to **always** properly configure your applications. + +## [Unreleased](https://github.com/hynek/structlog/compare/22.1.0...HEAD) + ## [22.1.0](https://github.com/hynek/structlog/compare/21.5.0...22.1.0) - 2022-07-20 ### Removed diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 188afe1f..23328236 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -50,7 +50,7 @@ twisted = None # type: ignore -__version__ = "22.1.0" +__version__ = "22.2.0.dev0" __title__ = "structlog" # __doc__ is None when running with PYTHONOPTIMIZE=2 / -OO From f123768e820376338e5048b7c87e29db0b0b3f94 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 20 Jul 2022 13:36:06 +0200 Subject: [PATCH 0718/1520] Fix typo --- src/structlog/tracebacks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/tracebacks.py b/src/structlog/tracebacks.py index 733d7a19..ac250271 100644 --- a/src/structlog/tracebacks.py +++ b/src/structlog/tracebacks.py @@ -208,7 +208,7 @@ def extract( class ExceptionDictTransformer: """ - Return a list of exception stack dictionaries for for an excpetion. + Return a list of exception stack dictionaries for for an exception. These dictionaries are based on :class:`Stack` instances generated by :func:`extract()` and can be dumped to JSON. From a6c50f074840cf7b1203ab446a6633a255bdf80d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 28 Jul 2022 10:59:52 +0200 Subject: [PATCH 0719/1520] Minor doc polish --- .github/CONTRIBUTING.md | 2 +- README.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 1c92aeeb..2140b244 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -26,7 +26,7 @@ Please report any harm to [Hynek Schlawack] in any way you find appropriate. If you have problems to test something, open anyway and ask for advice. In some situations, we may agree to add an `# pragma: no cover`. - Once you've addressed review feedback, make sure to bump the pull request with a short note, so we know you're done. -- Don’t break backwards compatibility. +- Don’t break backwards-compatibility. ## Code diff --git a/README.rst b/README.rst index 2ada6cb8..ecc78aa8 100644 --- a/README.rst +++ b/README.rst @@ -44,7 +44,7 @@ If you prefer videos over reading, check out `Markus Holtermann `_ +- **License**: *dual* `Apache License, version 2 and MIT `_ - **PyPI**: https://pypi.org/project/structlog/ - **Source Code**: https://github.com/hynek/structlog - **Documentation**: https://www.structlog.org/ From 55dabbebe6d3bae5be334263ee9b2d6f58cfc3c5 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 28 Jul 2022 17:05:22 +0200 Subject: [PATCH 0720/1520] De-duplicate using modern pip --- pyproject.toml | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index a7072dc7..28694e68 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -79,35 +79,13 @@ docs = [ "sphinxcontrib-mermaid", "twisted", ] - -# Combine tests and docs and a few more dev tools to a dev environment. -# Refresh using `tox -e cog` - dev = [ + "structlog[tests,docs]", "pre-commit", "rich", "cogapp", "tomli", - # [[[cog - # import pathlib, tomli - # cfg = tomli.loads(pathlib.Path("pyproject.toml").read_text()) - # opt = cfg["project"]["optional-dependencies"] - # for dep in opt["tests"] + opt["docs"]: - # print(f'"{dep}",') - # ]]] - "coverage[toml]", - "freezegun>=0.2.8", - "pretend", - "pytest-asyncio>=0.17", - "pytest>=6.0", - "simplejson", - "furo", - "myst-parser", - "sphinx", - "sphinx-notfound-page", - "sphinxcontrib-mermaid", - "twisted", - # [[[end]]] + "mypy", ] @@ -229,7 +207,7 @@ If you prefer videos over reading, check out `Markus Holtermann `_ +- **License**: *dual* `Apache License, version 2 and MIT `_ - **PyPI**: https://pypi.org/project/structlog/ - **Source Code**: https://github.com/hynek/structlog - **Documentation**: https://www.structlog.org/ From 88863fbf61932e349bc1bbe82ada4a91c0afb455 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 28 Jul 2022 17:05:46 +0200 Subject: [PATCH 0721/1520] De-duplicate dunder names @Julian-style Shamelessly stolen and adapted from jsonschema. Co-authored-by: Julian Berman --- pyproject.toml | 8 ++++++-- src/structlog/__init__.py | 34 +++++++++++++++++++++++++++------- tests/test_optimized.py | 10 ---------- tests/test_utils.py | 33 +++++++++++++++++++++++++++++++++ tox.ini | 1 - 5 files changed, 66 insertions(+), 20 deletions(-) delete mode 100644 tests/test_optimized.py diff --git a/pyproject.toml b/pyproject.toml index 28694e68..f7ca41ab 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,10 +7,10 @@ build-backend = "flit_core.buildapi" [project] name = "structlog" +version = "22.2.0.dev0" +description = "Structured Logging for Python" authors = [{name = "Hynek Schlawack", email = "hs@ox.cx"}] -dynamic = ["version", "description"] requires-python = ">=3.7" -dependencies = ["typing-extensions; python_version<'3.8'"] license = { file = "COPYRIGHT" } keywords = ["logging", "structured", "structure", "log"] classifiers = [ @@ -32,6 +32,10 @@ classifiers = [ "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: System :: Logging", ] +dependencies = [ + "typing-extensions; python_version<'3.8'", + "importlib_metadata;python_version<'3.8'", +] [project.urls] Changelog = "https://www.structlog.org/en/stable/changelog.html" diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 23328236..ffaecb5d 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -3,9 +3,6 @@ # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. -""" -Structured Logging for Python -""" from __future__ import annotations @@ -50,11 +47,7 @@ twisted = None # type: ignore -__version__ = "22.2.0.dev0" - __title__ = "structlog" -# __doc__ is None when running with PYTHONOPTIMIZE=2 / -OO -__description__ = (__doc__ or "").strip() __uri__ = "https://www.structlog.org/" @@ -97,3 +90,30 @@ "WriteLogger", "WriteLoggerFactory", ] + + +def __getattr__(name: str) -> str: + dunder_to_metadata = { + "__version__": "version", + "__description__": "summary", + } + if name not in dunder_to_metadata.keys(): + raise AttributeError(f"module {__name__} has no attribute {name}") + + import sys + import warnings + + if sys.version_info < (3, 8): + import importlib_metadata as metadata + else: + from importlib import metadata + + warnings.warn( + f"Accessing structlog.{name} is deprecated and will be " + "removed in a future release. Use importlib.metadata directly " + "to query for structlog's version.", + DeprecationWarning, + stacklevel=2, + ) + + return metadata.metadata("structlog")[dunder_to_metadata[name]] diff --git a/tests/test_optimized.py b/tests/test_optimized.py deleted file mode 100644 index 408b9812..00000000 --- a/tests/test_optimized.py +++ /dev/null @@ -1,10 +0,0 @@ -def test_can_import(): - """ - Checks whether it's possible to import structlog. - - This is used as part of our check whether structlog is importable when - running with -OO / PYTHONOPTIMIZE=2. - """ - import structlog - - assert isinstance(structlog.__description__, str) diff --git a/tests/test_utils.py b/tests/test_utils.py index 87a8f2fd..0df2f99f 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -7,10 +7,18 @@ import multiprocessing import sys + +if sys.version_info < (3, 8): + import importlib_metadata as metadata +else: + from importlib import metadata + import pytest from pretend import raiser +import structlog + from structlog._utils import get_processname, until_not_interrupted @@ -97,3 +105,28 @@ def _current_process() -> None: ) assert get_processname() == "n/a" + + +class TestLegacyMetadataHack: + def test_version(self): + """ + structlog.__version__ returns the correct version. + """ + with pytest.deprecated_call(): + assert metadata.version("structlog") == structlog.__version__ + + def test_description(self): + """ + structlog.__description__ returns the correct description. + """ + with pytest.deprecated_call(): + assert "Structured Logging for Python" == structlog.__description__ + + def test_does_not_exist(self): + """ + Asking for unsupported dunders raises an AttributeError. + """ + with pytest.raises( + AttributeError, match="module structlog has no attribute __yolo__" + ): + structlog.__yolo__ diff --git a/tox.ini b/tox.ini index 14b4733d..45bb447e 100644 --- a/tox.ini +++ b/tox.ini @@ -91,7 +91,6 @@ setenv = PYTHONHASHSEED = 0 commands = python -m coverage run -m pytest {posargs} - python -OO -m coverage run -m pytest tests/test_optimized.py [testenv:py39-colorama] From fcf0f301dd3efeb9f7db8b08a33b1384ec2de5c2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 29 Jul 2022 10:37:49 +0200 Subject: [PATCH 0722/1520] Switch build backend to Hatch (#435) --- .gitignore | 8 +++++++- CHANGELOG.md | 5 +++++ pyproject.toml | 23 ++--------------------- 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/.gitignore b/.gitignore index e57460b8..26796235 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,19 @@ *.egg-info *.pyc *.pyo +.DS_Store .cache .coverage* +.direnv +.envrc .mypy_cache .pytest_cache .tox +.vscode +benchmarks +build dist docs/_build htmlcov pip-wheel-metadata -build +tmp diff --git a/CHANGELOG.md b/CHANGELOG.md index c7866007..96c13056 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,11 @@ So please make sure to **always** properly configure your applications. ## [Unreleased](https://github.com/hynek/structlog/compare/22.1.0...HEAD) +### Changed + +- The build backend has been switched to [*Hatch*](https://hatch.pypa.io/). + + ## [22.1.0](https://github.com/hynek/structlog/compare/21.5.0...22.1.0) - 2022-07-20 ### Removed diff --git a/pyproject.toml b/pyproject.toml index f7ca41ab..71e34580 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 [build-system] -requires = ["flit_core >=3.4,<4"] -build-backend = "flit_core.buildapi" +requires = ["hatchling"] +build-backend = "hatchling.build" [project] @@ -46,25 +46,6 @@ Funding = "https://github.com/sponsors/hynek" Tidelift = "https://tidelift.com/subscription/pkg/pypi-structlog?utm_source=pypi-structlog&utm_medium=pypi" Ko-fi = "https://ko-fi.com/the_hynek" -[tool.flit.sdist] -include = [ - ".pre-commit-config.yaml", - ".readthedocs.yml", - "*.ini", - "*.rst", - "COPYRIGHT", - "LICENSE*", - "NOTICE", - "docs", - "tests", - ".github", - "show_off.py", -] -exclude = [ - "docs/_build", - "tests/__pycache__", - "tests/.mypy_cache", -] [project.optional-dependencies] tests = [ From 6a1c5740314de5865d1b350dbce4177db0e9725d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 29 Jul 2022 10:38:02 +0200 Subject: [PATCH 0723/1520] Generalize error message --- src/structlog/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index ffaecb5d..35a41507 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -111,7 +111,7 @@ def __getattr__(name: str) -> str: warnings.warn( f"Accessing structlog.{name} is deprecated and will be " "removed in a future release. Use importlib.metadata directly " - "to query for structlog's version.", + "to query for structlog's packaging metadata.", DeprecationWarning, stacklevel=2, ) From 4e297c6d5df7a53e0e55d9366d1a63d2404f4c8c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 29 Jul 2022 14:50:18 +0200 Subject: [PATCH 0724/1520] Deduplicate the rest of metadata too --- pyproject.toml | 2 +- src/structlog/__init__.py | 18 ++++++++----- tests/test_packaging.py | 55 +++++++++++++++++++++++++++++++++++++++ tests/test_utils.py | 33 ----------------------- 4 files changed, 68 insertions(+), 40 deletions(-) create mode 100644 tests/test_packaging.py diff --git a/pyproject.toml b/pyproject.toml index 71e34580..466e5864 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,8 +38,8 @@ dependencies = [ ] [project.urls] -Changelog = "https://www.structlog.org/en/stable/changelog.html" Documentation = "https://www.structlog.org/" +Changelog = "https://www.structlog.org/en/stable/changelog.html" "Bug Tracker" = "https://github.com/hynek/structlog/issues" "Source Code" = "https://github.com/hynek/structlog" Funding = "https://github.com/sponsors/hynek" diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 35a41507..c0ec50ec 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -49,10 +49,7 @@ __title__ = "structlog" -__uri__ = "https://www.structlog.org/" - __author__ = "Hynek Schlawack" -__email__ = "hs@ox.cx" __license__ = "MIT or Apache License, Version 2.0" __copyright__ = "Copyright (c) 2013 " + __author__ @@ -96,6 +93,8 @@ def __getattr__(name: str) -> str: dunder_to_metadata = { "__version__": "version", "__description__": "summary", + "__uri__": "", + "__email__": "", } if name not in dunder_to_metadata.keys(): raise AttributeError(f"module {__name__} has no attribute {name}") @@ -104,9 +103,9 @@ def __getattr__(name: str) -> str: import warnings if sys.version_info < (3, 8): - import importlib_metadata as metadata + from importlib_metadata import metadata else: - from importlib import metadata + from importlib.metadata import metadata warnings.warn( f"Accessing structlog.{name} is deprecated and will be " @@ -116,4 +115,11 @@ def __getattr__(name: str) -> str: stacklevel=2, ) - return metadata.metadata("structlog")[dunder_to_metadata[name]] + meta = metadata("structlog") + + if name == "__uri__": + return meta["Project-URL"].split(" ", 1)[-1] + elif name == "__email__": + return meta["Author-email"].split("<", 1)[1].rstrip(">") + + return meta[dunder_to_metadata[name]] diff --git a/tests/test_packaging.py b/tests/test_packaging.py new file mode 100644 index 00000000..6628c002 --- /dev/null +++ b/tests/test_packaging.py @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the MIT License. See the LICENSE file in the root of this +# repository for complete details. + +import sys + +import pytest + +import structlog + + +if sys.version_info < (3, 8): + import importlib_metadata as metadata +else: + from importlib import metadata + + +class TestLegacyMetadataHack: + def test_version(self): + """ + structlog.__version__ returns the correct version. + """ + with pytest.deprecated_call(): + assert metadata.version("structlog") == structlog.__version__ + + def test_description(self): + """ + structlog.__description__ returns the correct description. + """ + with pytest.deprecated_call(): + assert "Structured Logging for Python" == structlog.__description__ + + def test_uri(self): + """ + structlog.__uri__ returns the correct project URL. + """ + with pytest.deprecated_call(): + assert "https://www.structlog.org/" == structlog.__uri__ + + def test_email(self): + """ + structlog.__email__ returns Hynek's email address. + """ + with pytest.deprecated_call(): + assert "hs@ox.cx" == structlog.__email__ + + def test_does_not_exist(self): + """ + Asking for unsupported dunders raises an AttributeError. + """ + with pytest.raises( + AttributeError, match="module structlog has no attribute __yolo__" + ): + structlog.__yolo__ diff --git a/tests/test_utils.py b/tests/test_utils.py index 0df2f99f..87a8f2fd 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -7,18 +7,10 @@ import multiprocessing import sys - -if sys.version_info < (3, 8): - import importlib_metadata as metadata -else: - from importlib import metadata - import pytest from pretend import raiser -import structlog - from structlog._utils import get_processname, until_not_interrupted @@ -105,28 +97,3 @@ def _current_process() -> None: ) assert get_processname() == "n/a" - - -class TestLegacyMetadataHack: - def test_version(self): - """ - structlog.__version__ returns the correct version. - """ - with pytest.deprecated_call(): - assert metadata.version("structlog") == structlog.__version__ - - def test_description(self): - """ - structlog.__description__ returns the correct description. - """ - with pytest.deprecated_call(): - assert "Structured Logging for Python" == structlog.__description__ - - def test_does_not_exist(self): - """ - Asking for unsupported dunders raises an AttributeError. - """ - with pytest.raises( - AttributeError, match="module structlog has no attribute __yolo__" - ): - structlog.__yolo__ From 3494b6fb4a81ce25c9d5d79275fd298d5c76c7c7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 31 Jul 2022 07:02:23 +0200 Subject: [PATCH 0725/1520] dev: clarify colorama Clarify `force_colors` is Windows-only & `colors` only dependent on colorama on Windows. --- src/structlog/dev.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index d404b4fc..6aff8e9f 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -219,11 +219,11 @@ class ConsoleRenderer: in colors and with extra context. :param pad_event: Pad the event to this many characters. - :param colors: Use colors for a nicer output. `True` by default if - colorama_ is installed. + :param colors: Use colors for a nicer output. `True` by default. On + Windows only if colorama_ is installed. :param force_colors: Force colors even for non-tty destinations. Use this option if your logs are stored in a file that is meant - to be streamed to the console. + to be streamed to the console. Only meaningful on Windows. :param repr_native_str: When `True`, `repr` is also applied to native strings (i.e. unicode on Python 3 and bytes on Python 2). Setting this to `False` is useful if you want to have human-readable From 7f9453cd01e7edce15d7ef393db16061d00c03c7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 1 Aug 2022 08:12:15 +0200 Subject: [PATCH 0726/1520] Mention pipelineability --- docs/loggers.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/loggers.rst b/docs/loggers.rst index fddc2fa9..0d714cc8 100644 --- a/docs/loggers.rst +++ b/docs/loggers.rst @@ -16,6 +16,7 @@ It consists of three parts: This dictionary is *merged* into each log entry that is logged from *this logger specifically*. That means that every logger has it own context, but it is possible to have global contexts using :doc:`context variables `. #. A list of :doc:`processors ` that are called on every log entry. + Each processor receives the return value of its predecessor passed as an argument. #. And finally a *logger* that it's wrapping. This wrapped logger is reponsible for the *output* of the log entry that has been returned by the last processor. This *can* be standard library's `logging.Logger`, but absolutely doesn't have to. From 473eb70fd26149ff47a1aca9ced1aae34d8cedf6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 1 Aug 2022 15:35:43 +0200 Subject: [PATCH 0727/1520] Simplify pre-commit --- .pre-commit-config.yaml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e2108bfd..67c988db 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,6 +2,9 @@ ci: autoupdate_schedule: monthly +default_language_version: + python: python3.10 + repos: - repo: https://github.com/psf/black rev: 22.6.0 @@ -9,7 +12,7 @@ repos: - id: black - repo: https://github.com/asottile/pyupgrade - rev: v2.34.0 + rev: v2.37.3 hooks: - id: pyupgrade args: [--py37-plus] @@ -20,11 +23,15 @@ repos: - id: isort additional_dependencies: [toml] + - repo: https://github.com/asottile/yesqa + rev: v1.3.0 + hooks: + - id: yesqa + - repo: https://github.com/PyCQA/flake8 - rev: 4.0.1 + rev: 5.0.2 hooks: - id: flake8 - language_version: python3.10 exclude: docs/code_examples - repo: https://github.com/pre-commit/pre-commit-hooks From 6e2e8c6025fb90484c5e6c5ff2fd3e96a61854cf Mon Sep 17 00:00:00 2001 From: Day Barr Date: Wed, 3 Aug 2022 19:42:26 +0100 Subject: [PATCH 0728/1520] Avoid deprecated thread locals from best practices (#438) --- docs/logging-best-practices.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/logging-best-practices.rst b/docs/logging-best-practices.rst index e1003539..45355bb6 100644 --- a/docs/logging-best-practices.rst +++ b/docs/logging-best-practices.rst @@ -22,7 +22,7 @@ Canonical Log Lines Generally speaking, having as few log entries per request as possible is a good thing. The less noise, the more insights. -``structlog``'s ability to :ref:`bind data to loggers incrementally ` -- plus :doc:`thread-local context storage ` -- can help you to minimize the output to a *single log entry*. +``structlog``'s ability to :ref:`bind data to loggers incrementally ` -- plus :doc:`loggers that are local to the current execution context ` -- can help you to minimize the output to a *single log entry*. At Stripe, this concept is called `Canonical Log Lines `_. From b066ab18b6ff8a16645d00f3d3be12b2af0e07a0 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 15 Aug 2022 09:10:33 +0200 Subject: [PATCH 0729/1520] Update python action --- .github/workflows/main.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 66ef3e33..598dc0d1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -25,7 +25,7 @@ jobs: steps: - uses: actions/checkout@v3 - - uses: actions/setup-python@v3 + - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} @@ -53,7 +53,7 @@ jobs: steps: - uses: actions/checkout@v3 - - uses: actions/setup-python@v3 + - uses: actions/setup-python@v4 with: # Use latest Python, so it understands all syntax. python-version: ${{env.PYTHON_LATEST}} @@ -84,7 +84,7 @@ jobs: steps: - uses: actions/checkout@v3 - - uses: actions/setup-python@v3 + - uses: actions/setup-python@v4 with: python-version: ${{env.PYTHON_LATEST}} @@ -105,7 +105,7 @@ jobs: steps: - uses: actions/checkout@v3 - - uses: actions/setup-python@v3 + - uses: actions/setup-python@v4 with: python-version: ${{env.PYTHON_LATEST}} - run: python -m pip install -e .[dev] From 955384dcbaf7a2a3e80ea8b3d3ad326fa900bdae Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 15 Aug 2022 11:01:40 +0200 Subject: [PATCH 0730/1520] Consistency --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 598dc0d1..bb6bb6d2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -3,9 +3,9 @@ name: CI on: push: - branches: ["main"] + branches: [main] pull_request: - branches: ["main"] + branches: [main] workflow_dispatch: env: From 0283d16bf9c49f8c082dc473b18890149853baa7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 19 Aug 2022 06:58:38 +0200 Subject: [PATCH 0731/1520] Build wheels from sdists in CI cf. https://github.com/python-attrs/attrs/pull/1012 --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bb6bb6d2..06a3339f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -89,7 +89,7 @@ jobs: python-version: ${{env.PYTHON_LATEST}} - run: python -m pip install build twine check-wheel-contents - - run: python -m build --sdist --wheel . + - run: python -m build - run: ls -l dist - run: check-wheel-contents dist/*.whl - name: Check long_description From cf366f3128daaf17297b339b4f69a6f8e569019b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 20 Aug 2022 11:10:51 +0200 Subject: [PATCH 0732/1520] Use build-and-inspect-python-package --- .github/workflows/main.yml | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 06a3339f..f5a34cc0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -84,17 +84,7 @@ jobs: steps: - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 - with: - python-version: ${{env.PYTHON_LATEST}} - - - run: python -m pip install build twine check-wheel-contents - - run: python -m build - - run: ls -l dist - - run: check-wheel-contents dist/*.whl - - name: Check long_description - run: python -m twine check dist/* - + - uses: hynek/build-and-inspect-python-package@v0.1 install-dev: name: Verify dev env From 8b60ff53590b102dc10f189c5a2fb1cad8ef2ecc Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 22 Aug 2022 16:29:44 +0200 Subject: [PATCH 0733/1520] Rename ci workflow to a meaningful name --- .github/workflows/{main.yml => ci.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{main.yml => ci.yml} (100%) diff --git a/.github/workflows/main.yml b/.github/workflows/ci.yml similarity index 100% rename from .github/workflows/main.yml rename to .github/workflows/ci.yml From a0a3462bc845ba213f0283991f9e5833c8d10ad2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 22 Aug 2022 16:32:37 +0200 Subject: [PATCH 0734/1520] Update build-and-inspect-python-package --- .github/workflows/ci.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f5a34cc0..b977cd92 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,11 +9,10 @@ on: workflow_dispatch: env: - FORCE_COLOR: "1" # Make tools pretty. + FORCE_COLOR: "1" # Make tools pretty. TOX_TESTENV_PASSENV: FORCE_COLOR PYTHON_LATEST: "3.10" - jobs: tests: name: tox on ${{ matrix.python-version }} @@ -45,7 +44,6 @@ jobs: path: .coverage.* if-no-files-found: ignore - coverage: name: Combine & check coverage. runs-on: ubuntu-latest @@ -77,14 +75,13 @@ jobs: path: htmlcov if: ${{ failure() }} - package: name: Build & verify package runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: hynek/build-and-inspect-python-package@v0.1 + - uses: hynek/build-and-inspect-python-package@v1 install-dev: name: Verify dev env From 6d50b90ca3a65ede5a4d6d855cbd294ec979396e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 22 Aug 2022 18:08:34 +0200 Subject: [PATCH 0735/1520] Mention option 4 --- docs/standard-library.rst | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/docs/standard-library.rst b/docs/standard-library.rst index 19d71130..62e6b0cc 100644 --- a/docs/standard-library.rst +++ b/docs/standard-library.rst @@ -119,7 +119,7 @@ Suggested Configurations This is the price of flexibility and unfortunately -- given the different needs of our users -- we can't make it any simpler without compromising someone's use-cases. However, once it is set up, you can rely on not having to ever touch it again. -Depending *where* you'd like to do your formatting, you can take one of three approaches: +Depending *where* you'd like to do your formatting, you can take one of four approaches: Rendering Within ``structlog`` @@ -263,7 +263,7 @@ You can choose to use ``structlog`` only for building the event dictionary and l ) Now you have the event dict available within each log record. -If you want all your log entries (i.e. also those not from your app/``structlog``) to be formatted as JSON, you can use the `python-json-logger library `_: +If you want all your log entries (i.e. also those not from your app/``structlog``) to be formatted as JSON, you can use the python-json-logger_ library: .. code-block:: python @@ -528,4 +528,15 @@ If you leave ``foreign_pre_chain`` as `None`, formatting will be left to `loggin Meaning: you can define a ``format`` for `ProcessorFormatter` too! +Don't Integrate +^^^^^^^^^^^^^^^ + +The most straight-forward option is to configure standard library `logging` close enough to what ``structlog`` is logging and leaving it at that. + +Since these are usually log entries from third parties that don't take advantage of ``structlog``'s features, this is surprisingly often a perfectly adequate approach. + +For instance, if you log JSON in production, configure `logging` to use python-json-logger_ to make it print JSON too, and then tweak the configuration to match their outputs. + + .. _`12 factor app`: https://12factor.net/logs +.. _python-json-logger: https://github.com/madzak/python-json-logger> From a43eb62a9d37cd24419ecf14ec2af249e94948bf Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 22 Aug 2022 18:09:06 +0200 Subject: [PATCH 0736/1520] pre-commit autoupdate --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 67c988db..f4489812 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,12 +24,12 @@ repos: additional_dependencies: [toml] - repo: https://github.com/asottile/yesqa - rev: v1.3.0 + rev: v1.4.0 hooks: - id: yesqa - repo: https://github.com/PyCQA/flake8 - rev: 5.0.2 + rev: 5.0.4 hooks: - id: flake8 exclude: docs/code_examples From 39f5e8d48f332feb101e62d00c663bd272bf6688 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 23 Aug 2022 08:55:50 +0200 Subject: [PATCH 0737/1520] Move all top-level docs to Markdown & switch to fancy pypi readme --- .gitignore | 2 - AUTHORS.md | 9 ++++ AUTHORS.rst | 11 ----- CHANGELOG.md | 1 - README.md | 56 ++++++++++++++++++++++++ README.rst | 64 --------------------------- docs/index.rst | 16 ++++--- docs/license.md | 18 ++++++++ docs/license.rst | 20 --------- pyproject.toml | 112 +++++++++++++---------------------------------- tox.ini | 22 +--------- 11 files changed, 127 insertions(+), 204 deletions(-) create mode 100644 AUTHORS.md delete mode 100644 AUTHORS.rst create mode 100644 README.md delete mode 100644 README.rst create mode 100644 docs/license.md delete mode 100644 docs/license.rst diff --git a/.gitignore b/.gitignore index 26796235..e8dbed0c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -*.egg-info *.pyc *.pyo .DS_Store @@ -15,5 +14,4 @@ build dist docs/_build htmlcov -pip-wheel-metadata tmp diff --git a/AUTHORS.md b/AUTHORS.md new file mode 100644 index 00000000..c000cc10 --- /dev/null +++ b/AUTHORS.md @@ -0,0 +1,9 @@ +# Authors + +`structlog` is written and maintained by [Hynek Schlawack](https://hynek.me/). It’s inspired by previous work by [Jean-Paul Calderone](https://github.com/exarkun) and [David Reid](https://github.com/dreid). + +The development is kindly supported by my employer [Variomedia AG](https://www.variomedia.de/), ``structlog`` [Tidelift subscribers](https://tidelift.com/subscription/pkg/pypi-structlog?utm_source=pypi-structlog&utm_medium=referral&utm_campaign=enterprise&utm_term=repo), and all my amazing [GitHub Sponsors](https://github.com/sponsors/hynek). + +A full list of contributors can be found on GitHub’s [overview](https://github.com/hynek/structlog/graphs/contributors). + +The `structlog` logo has been contributed by [Russell Keith-Magee](https://github.com/freakboy3742). diff --git a/AUTHORS.rst b/AUTHORS.rst deleted file mode 100644 index b1e56068..00000000 --- a/AUTHORS.rst +++ /dev/null @@ -1,11 +0,0 @@ -Authors -======= - -``structlog`` is written and maintained by `Hynek Schlawack `_. -It’s inspired by previous work by `Jean-Paul Calderone `_ and `David Reid `_. - -The development is kindly supported by `Variomedia AG `_. - -A full list of contributors can be found on GitHub’s `overview `_. - -The ``structlog`` logo has been contributed by `Russell Keith-Magee `_. diff --git a/CHANGELOG.md b/CHANGELOG.md index 96c13056..d12d8e9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,6 @@ So please make sure to **always** properly configure your applications. - ## [Unreleased](https://github.com/hynek/structlog/compare/22.1.0...HEAD) ### Changed diff --git a/README.md b/README.md new file mode 100644 index 00000000..4a5a2525 --- /dev/null +++ b/README.md @@ -0,0 +1,56 @@ +

    + + structlog + +

    +

    + + Documentation + + + License: MIT / Apache 2.0 + + + PyPI release + + + Downloads per month + +

    + + + +`structlog` makes logging in Python **faster**, **less painful**, and **more powerful** by adding **structure** to your log entries. It has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio* or type hints along the way, and [influenced the design](https://twitter.com/sirupsen/status/638330548361019392) of [structured logging packages in other ecosystems](https://github.com/sirupsen/logrus). + +Thanks to its highly flexible design, it's up to you whether you want `structlog` to take care about the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's `logging` module. + +`structlog` comes with support for JSON, [*logfmt*](https://brandur.org/logfmt), as well as pretty console output out-of-the-box: + +![image](https://github.com/hynek/structlog/blob/main/docs/_static/console_renderer.png?raw=true) + + + +A short explanation on *why* structured logging is good for you, and why `structlog` is the right tool for the job can be found in the [Why chapter](https://www.structlog.org/en/stable/why.html) of our documentation. + +Once you feel inspired to try it out, check out our friendly [Getting Started tutorial](https://www.structlog.org/en/stable/getting-started.html) that also contains detailed installation instructions! + +If you prefer videos over reading, check out [Markus Holtermann](https://twitter.com/m_holtermann)'s DjangoCon Europe 2019 talk: [*Logging Rethought 2: The Actions of Frank Taylor Jr.*](https://www.youtube.com/watch?v=Y5eyEgyHLLo) + + +# Project Information + +- **License**: *dual* [Apache License, version 2 and MIT](https://www.structlog.org/en/stable/license.html) +- **PyPI**: +- **Source Code**: +- **Documentation**: +- **Changelog**: +- **Get Help**: please use the `structlog` tag on [StackOverflow](https://stackoverflow.com/questions/tagged/structlog) +- **Third-party Extensions**: +- **Supported Python Versions**: 3.7 and later + + +## `structlog` for Enterprise + +Available as part of the Tidelift Subscription. + +The maintainers of structlog and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. [Learn more.](https://tidelift.com/subscription/pkg/pypi-structlog?utm_source=pypi-structlog&utm_medium=referral&utm_campaign=readme) diff --git a/README.rst b/README.rst deleted file mode 100644 index ecc78aa8..00000000 --- a/README.rst +++ /dev/null @@ -1,64 +0,0 @@ -.. raw:: html - -

    - - structlog - -

    -

    - - Documentation - - - License: MIT / Apache 2.0 - - - PyPI release - - - Downloads per month - -

    - -.. -begin-short- - -``structlog`` makes logging in Python **faster**, **less painful**, and **more powerful** by adding **structure** to your log entries. -It has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio* or type hints along the way, and `influenced the design `_ of `structured logging packages in other ecosystems `_. - -Thanks to its highly flexible design, it's up to you whether you want ``structlog`` to take care about the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's ``logging`` module. - -``structlog`` comes with support for JSON, `logfmt `_, as well as pretty console output out-of-the-box: - -.. image:: https://github.com/hynek/structlog/blob/main/docs/_static/console_renderer.png?raw=true - -.. -end-short- - -A short explanation on *why* structured logging is good for you, and why ``structlog`` is the right tool for the job can be found in the `Why chapter `_ of our documentation. - -Once you feel inspired to try it out, check out our friendly `Getting Started tutorial `_ that also contains detailed installation instructions! - -If you prefer videos over reading, check out `Markus Holtermann `_'s DjangoCon Europe 2019 talk: `Logging Rethought 2: The Actions of Frank Taylor Jr. `_ - -.. -begin-meta- - -Project Information -=================== - -- **License**: *dual* `Apache License, version 2 and MIT `_ -- **PyPI**: https://pypi.org/project/structlog/ -- **Source Code**: https://github.com/hynek/structlog -- **Documentation**: https://www.structlog.org/ -- **Changelog**: https://www.structlog.org/en/stable/changelog.html -- **Get Help**: please use the ``structlog`` tag on `StackOverflow `_ -- **Third-party Extensions**: https://github.com/hynek/structlog/wiki/Third-party-Extensions -- **Supported Python Versions**: 3.7 and later - - -``structlog`` for Enterprise ----------------------------- - -Available as part of the Tidelift Subscription. - -The maintainers of structlog and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. -Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. -`Learn more. `_ diff --git a/docs/index.rst b/docs/index.rst index eb0244b5..0ee9baa6 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -4,9 +4,10 @@ Structured Logging for Python Release v\ |release| (`What's new? `) -.. include:: ../README.rst - :start-after: -begin-short- - :end-before: -end-short- +.. include:: ../README.md + :parser: myst_parser.sphinx_ + :start-after: + :end-before: First steps: @@ -70,8 +71,13 @@ API Reference api -.. include:: ../README.rst - :start-after: -begin-meta- + +Project Information +=================== + +.. include:: ../README.md + :parser: myst_parser.sphinx_ + :start-after: # Project Information .. stop Sphinx from complaints about orphaned docs, we link them elsewhere diff --git a/docs/license.md b/docs/license.md new file mode 100644 index 00000000..e1081459 --- /dev/null +++ b/docs/license.md @@ -0,0 +1,18 @@ +# License and Hall of Fame + +`structlog` is licensed both under the [Apache License, Version 2](https://choosealicense.com/licenses/apache/) and the [MIT license](https://choosealicense.com/licenses/mit/). + +Any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. + +--- + +The reason for that is to be both protected against patent claims by own contributors and still allow the usage within GPLv2 software. For more legal details, see [this issue](https://github.com/pyca/cryptography/issues/1209) on the bug tracker of PyCA's `cryptography` project. + +The full license texts can be also found in the source code repository: + +- [Apache License 2.0](https://github.com/hynek/structlog/blob/main/LICENSE-APACHE) +- [MIT](https://github.com/hynek/structlog/blob/main/LICENSE-MIT) + + +```{include} ../AUTHORS.md +``` diff --git a/docs/license.rst b/docs/license.rst deleted file mode 100644 index 25001344..00000000 --- a/docs/license.rst +++ /dev/null @@ -1,20 +0,0 @@ -License and Hall of Fame -======================== - -``structlog`` is licensed both under the `Apache License, Version 2 `_ and the `MIT license `_. - -Any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. - ---- - -The reason for that is to be both protected against patent claims by own contributors and still allow the usage within GPLv2 software. -For more legal details, see `this issue `_ on the bug tracker of PyCA's ``cryptography`` project. - -The full license texts can be also found in the source code repository: - -- `Apache License 2.0 `_ -- `MIT `_ - -.. _authors: - -.. include:: ../AUTHORS.rst diff --git a/pyproject.toml b/pyproject.toml index 466e5864..383e5a9a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,15 +1,16 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 [build-system] -requires = ["hatchling"] +requires = ["hatchling", "hatch-fancy-pypi-readme"] build-backend = "hatchling.build" [project] +dynamic = ["readme"] name = "structlog" version = "22.2.0.dev0" description = "Structured Logging for Python" -authors = [{name = "Hynek Schlawack", email = "hs@ox.cx"}] +authors = [{ name = "Hynek Schlawack", email = "hs@ox.cx" }] requires-python = ">=3.7" license = { file = "COPYRIGHT" } keywords = ["logging", "structured", "structure", "log"] @@ -34,7 +35,7 @@ classifiers = [ ] dependencies = [ "typing-extensions; python_version<'3.8'", - "importlib_metadata;python_version<'3.8'", + "importlib_metadata; python_version<'3.8'", ] [project.urls] @@ -64,23 +65,14 @@ docs = [ "sphinxcontrib-mermaid", "twisted", ] -dev = [ - "structlog[tests,docs]", - "pre-commit", - "rich", - "cogapp", - "tomli", - "mypy", -] +dev = ["structlog[tests,docs]", "pre-commit", "rich", "mypy"] [tool.pytest.ini_options] -addopts = "-ra --strict-markers" -xfail_strict = true +addopts = ["-ra", "--strict-markers", "--strict-config"] testpaths = "tests" -filterwarnings = [ - "once::Warning", -] +xfail_strict = true +filterwarnings = ["once::Warning"] asyncio_mode = "auto" @@ -95,9 +87,7 @@ source = ["src", ".tox/*/site-packages"] [tool.coverage.report] show_missing = true skip_covered = true -omit = [ - "src/structlog/_greenlets.py", -] +omit = ["src/structlog/_greenlets.py"] exclude_lines = [ # a more strict default pragma "\\# pragma: no cover\\b", @@ -143,72 +133,32 @@ module = "conftest.*" ignore_errors = true -[project.readme] -content-type = "text/x-rst" - -# Load README.rst, but remove header and badges. -# Refresh using `tox -e cog` -# Nothing except for the adapted README follows after this point. - -# [[[cog -# import pathlib -# print( -# 'text = """' -# ".. image:: https://www.structlog.org/en/stable/_static/structlog_logo_small_transparent.png\n" -# " :alt: structlog mascot\n" -# " :align: center\n\n" -# + pathlib.Path("README.rst") -# .read_text() -# .split(".. -begin-short-")[1] -# .lstrip() -# .replace('"""', r'\"\"\"') -# + '"""', -# end="" -# ) -# ]]] -text = """.. image:: https://www.structlog.org/en/stable/_static/structlog_logo_small_transparent.png - :alt: structlog mascot - :align: center - -``structlog`` makes logging in Python **faster**, **less painful**, and **more powerful** by adding **structure** to your log entries. -It has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio* or type hints along the way, and `influenced the design `_ of `structured logging packages in other ecosystems `_. - -Thanks to its highly flexible design, it's up to you whether you want ``structlog`` to take care about the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's ``logging`` module. +[tool.hatch.metadata.hooks.fancy-pypi-readme] +content-type = "text/markdown" -``structlog`` comes with support for JSON, `logfmt `_, as well as pretty console output out-of-the-box: +[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]] +text = '''

    + structlog mascot +

    +''' -.. image:: https://github.com/hynek/structlog/blob/main/docs/_static/console_renderer.png?raw=true +[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]] +path = "README.md" +start-after = "\n" +end-before = "\n" -.. -end-short- +[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]] +text = """ -A short explanation on *why* structured logging is good for you, and why ``structlog`` is the right tool for the job can be found in the `Why chapter `_ of our documentation. -Once you feel inspired to try it out, check out our friendly `Getting Started tutorial `_ that also contains detailed installation instructions! +## Release Information -If you prefer videos over reading, check out `Markus Holtermann `_'s DjangoCon Europe 2019 talk: `Logging Rethought 2: The Actions of Frank Taylor Jr. `_ - -.. -begin-meta- - -Project Information -=================== - -- **License**: *dual* `Apache License, version 2 and MIT `_ -- **PyPI**: https://pypi.org/project/structlog/ -- **Source Code**: https://github.com/hynek/structlog -- **Documentation**: https://www.structlog.org/ -- **Changelog**: https://www.structlog.org/en/stable/changelog.html -- **Get Help**: please use the ``structlog`` tag on `StackOverflow `_ -- **Third-party Extensions**: https://github.com/hynek/structlog/wiki/Third-party-Extensions -- **Supported Python Versions**: 3.7 and later - - -``structlog`` for Enterprise ----------------------------- - -Available as part of the Tidelift Subscription. - -The maintainers of structlog and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. -Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. -`Learn more. `_ """ -# [[[end]]] + +[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]] +path = "CHANGELOG.md" +start-after = "" +pattern = "\n(###.+?)\n## " diff --git a/tox.ini b/tox.ini index 45bb447e..646af9ca 100644 --- a/tox.ini +++ b/tox.ini @@ -8,12 +8,12 @@ python = 3.7: py37 # mypy on 3.7 fails but there's nothing we can do about it 3.8: py38, mypy 3.9: py39, mypy - 3.10: py310, mypy, cogCheck, docs + 3.10: py310, mypy, docs 3.11: py311 [tox] -envlist = pre-commit,mypy,cogCheck,cog,py37,py38,py39,py310,py39-colorama,py310-be,py310-rich,py311,docs,pypi-description,coverage-report +envlist = pre-commit,mypy,py37,py38,py39,py310,py39-colorama,py310-be,py310-rich,py311,docs,pypi-description,coverage-report isolated_build = True @@ -31,7 +31,6 @@ commands = [testenv:pre-commit] -basepython = python3.10 skip_install = true deps = pre-commit passenv = HOMEPATH # needed on Windows @@ -50,23 +49,6 @@ deps = commands = mypy src typing_examples.py -[testenv:cog] -description = "Update pyproject.toml's metadata" -skip_install = true -deps = - cogapp>=3.3.0 - tomli -commands = python -m cogapp -rP pyproject.toml - - -[testenv:cogCheck] -description = "Ensure pyproject.toml is up to date" -basepython = python3.10 -skip_install = true -deps = {[testenv:cog]deps} -commands = python -m cogapp --check -P pyproject.toml - - [testenv] extras = tests deps = From 18e53cc36c4b4d268e48d2d5184866dcafc7caf6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 23 Aug 2022 09:05:55 +0200 Subject: [PATCH 0738/1520] Create codeql-analysis.yml --- .github/workflows/codeql-analysis.yml | 72 +++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 00000000..044899c4 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,72 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ "main" ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ "main" ] + schedule: + - cron: '41 3 * * 6' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'python' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 From 1af4d6e31b934e7ebdaa2593c52b5d9e951904ca Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 23 Aug 2022 09:08:34 +0200 Subject: [PATCH 0739/1520] Trim trailing whitespace --- .github/workflows/codeql-analysis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 044899c4..66958308 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -48,11 +48,11 @@ jobs: # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. - + # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs # queries: security-extended,security-and-quality - + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild @@ -61,7 +61,7 @@ jobs: # ℹ️ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - # If the Autobuild fails above, remove it and uncomment the following three lines. + # If the Autobuild fails above, remove it and uncomment the following three lines. # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. # - run: | From 709ac65659c1a7b33d78c7efb9c3a15c6a6bd0e8 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 23 Aug 2022 09:31:06 +0200 Subject: [PATCH 0740/1520] Don't install pre-commit ourselves --- .github/CONTRIBUTING.md | 144 +++++++++++++++++++++------------------- pyproject.toml | 2 +- 2 files changed, 78 insertions(+), 68 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 2140b244..d31577a9 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,6 +1,6 @@ # How To Contribute -First off, thank you for considering contributing to `structlog`! +Thank you for considering contributing to `structlog`! It's people like *you* who make it such a great tool for everyone. This document intends to make contribution more accessible by codifying tribal knowledge and expectations. @@ -11,15 +11,23 @@ By participating in this project you agree to abide by its terms. Please report any harm to [Hynek Schlawack] in any way you find appropriate. +## Support + +In case you'd like to help out but don't want to deal with GitHub, there's a great opportunity: +help your fellow developers on [Stack Overflow](https://stackoverflow.com/questions/tagged/structlog)! + +The official tag is `structlog` and helping out in support frees us up to improve `structlog` instead! + + ## Workflow - No contribution is too small! Please submit as many fixes for typos and grammar bloopers as you can! - Try to limit each pull request to *one* change only. -- Since we squash on merge, it's up to you how you handle updates to the main branch. - Whether you prefer to rebase on main or merge main into your branch, do whatever is more comfortable for you. +- Since we squash on merge, it's up to you how you handle updates to the `main branch. + Whether you prefer to rebase on `main` or merge `main` into your branch, do whatever is more comfortable for you. - *Always* add tests and docs for your code. - This is a hard rule; patches with missing tests or documentation can't be merged. + This is a hard rule; patches with missing tests or documentation won't be merged. - Make sure your changes pass our [CI]. You won't get any feedback until it's green unless you ask for it. For the CI to pass, the coverage must be 100%. @@ -29,13 +37,75 @@ Please report any harm to [Hynek Schlawack] in any way you find appropriate. - Don’t break backwards-compatibility. +## Local Development Environment + +You can (and should) run our test suite using [*tox*]. +However, you’ll probably want a more traditional environment as well. +We highly recommend to develop using the latest Python release because we try to take advantage of modern features whenever possible. + +First create a [virtual environment](https://virtualenv.pypa.io/) so you don't break your system-wide Python installation. +It’s out of scope for this document to list all the ways to manage virtual environments in Python, but if you don’t already have a pet way, take some time to look at tools like [*direnv*](https://hynek.me/til/python-project-local-venvs/), [*virtualfish*](https://virtualfish.readthedocs.io/), and [*virtualenvwrapper*](https://virtualenvwrapper.readthedocs.io/). + +Next, get an up to date checkout of the *structlog* repository: + +```console +$ git clone git@github.com:hynek/structlog.git +``` + +or if you prefer to use *Git* via `https`: + +```console +$ git clone https://github.com/hynek/structlog.git +``` + +Change into the newly created directory and **after activating your virtual environment** install an editable version of *structlog* along with its tests and docs requirements: + +```console +$ cd structlog +$ pip install --upgrade pip wheel setuptools # PLEASE don't skip this step +$ pip install -e '.[dev]' +``` + +At this point, + +```console +$ python -m pytest +``` + +should work and pass, as should: + +```console +$ cd docs +$ make html +``` + +The built documentation can then be found in `docs/_build/html/`. + +--- + +To avoid committing code that violates our style guide, we strongly advise you to install [*pre-commit*] and its hooks: + +```console +$ pre-commit install +``` + +This is not strictly necessary, because our [*tox*] file contains an environment that runs: + +```console +$ pre-commit run --all-files +``` + +and our CI has integration with [pre-commit.ci](https://pre-commit.ci). +But it's way more comfortable to run it locally and *git* catching avoidable errors. + + ## Code - Obey [PEP 8](https://www.python.org/dev/peps/pep-0008/) and [PEP 257](https://www.python.org/dev/peps/pep-0257/). We use the `"""`-on-separate-lines style for docstrings: ```python - def func(x): + def func(x: str) -> str: """ Do something. @@ -46,7 +116,7 @@ Please report any harm to [Hynek Schlawack] in any way you find appropriate. ``` - If you add or change public APIs, tag the docstring using `.. versionadded:: 16.0.0 WHAT` or `.. versionchanged:: 16.2.0 WHAT`. - We use [*isort*](https://github.com/PyCQA/isort) to sort our imports, and we use [*Black*](https://github.com/psf/black) with line length of 79 characters to format our code. - As long as you run our full [*tox*] suite before committing, or install our [*pre-commit*] hooks (ideally you'll do both – see [*Local Development Environment*](#local-development-environment) below), you won't have to spend any time on formatting your code at all. + As long as you run our full [*tox*] suite before committing, or install our [*pre-commit*] hooks (ideally you'll do both – see [*Local Development Environment*](#local-development-environment) above), you won't have to spend any time on formatting your code at all. If you don't, [CI] will catch it for you – but that seems like a waste of your time! @@ -72,7 +142,7 @@ Please report any harm to [Hynek Schlawack] in any way you find appropriate. ## Documentation -- Use [semantic newlines] in [*reStructuredText*] and *Markdown* files (files ending in `.rst` and `.md`): +- Use [semantic newlines] in [*reStructuredText*] and [*Markdown*](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax) files (files ending in `.rst` and `.md`): ```rst This is a sentence. @@ -134,66 +204,6 @@ or: ``` -## Local Development Environment - -You can (and should) run our test suite using [*tox*]. -However, you’ll probably want a more traditional environment as well. -We highly recommend to develop using the latest Python release because we try to take advantage of modern features whenever possible. - -First create a [virtual environment](https://virtualenv.pypa.io/) so you don't break your system-wide Python installation. -It’s out of scope for this document to list all the ways to manage virtual environments in Python, but if you don’t already have a pet way, take some time to look at tools like [*direnv*](https://hynek.me/til/python-project-local-venvs/), [*virtualfish*](https://virtualfish.readthedocs.io/), and [*virtualenvwrapper*](https://virtualenvwrapper.readthedocs.io/). - -Next, get an up to date checkout of the *structlog* repository: - -```console -$ git clone git@github.com:hynek/structlog.git -``` - -or if you want to use git via `https`: - -```console -$ git clone https://github.com/hynek/structlog.git -``` - -Change into the newly created directory and **after activating your virtual environment** install an editable version of *structlog* along with its tests and docs requirements: - -```console -$ cd structlog -$ pip install --upgrade pip setuptools # PLEASE don't skip this step -$ pip install -e '.[dev]' -``` - -At this point, - -```console -$ python -m pytest -``` - -should work and pass, as should: - -```console -$ cd docs -$ make html -``` - -The built documentation can then be found in `docs/_build/html/`. - -To avoid committing code that violates our style guide, we strongly advise you to install [*pre-commit*] [^dev] hooks: - -```console -$ pre-commit install -``` - -You can also run them anytime (as our tox does) using: - -```console -$ pre-commit run --all-files -``` - -[^dev]: *pre-commit* should have been installed into your virtualenv automatically when you ran `pip install -e '.[dev]'` above. - If *pre-commit* is missing, your probably need to run `pip install -e '.[dev]'` again. - - [CI]: https://github.com/hynek/structlog/actions [Hynek Schlawack]: https://hynek.me/about/ [*pre-commit*]: https://pre-commit.com/ diff --git a/pyproject.toml b/pyproject.toml index 383e5a9a..41d42008 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,7 +65,7 @@ docs = [ "sphinxcontrib-mermaid", "twisted", ] -dev = ["structlog[tests,docs]", "pre-commit", "rich", "mypy"] +dev = ["structlog[tests,docs]", "rich", "mypy"] [tool.pytest.ini_options] From 01be5789072c3db61219e54047ba7af774132571 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 23 Aug 2022 09:35:38 +0200 Subject: [PATCH 0741/1520] Mypy doesn't need tests extra --- tox.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/tox.ini b/tox.ini index 646af9ca..edd54f96 100644 --- a/tox.ini +++ b/tox.ini @@ -39,7 +39,6 @@ commands = pre-commit run --all-files [testenv:mypy] description = Check types -extras = tests # Need twisted & rich for stubs. # Otherwise mypy fails in tox. deps = From eed5ea6c4888d8cef27c21e0f60f20e8fd814fd2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 23 Aug 2022 09:52:38 +0200 Subject: [PATCH 0742/1520] Simplify tox.ini --- pyproject.toml | 5 ++++- tox.ini | 36 +++++++++--------------------------- 2 files changed, 13 insertions(+), 28 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 41d42008..716c8486 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,6 +57,9 @@ tests = [ "pytest>=6.0", "simplejson", ] +# Need twisted & rich for stubs. +# Otherwise mypy fails in tox. +typing = ["mypy", "rich", "twisted"] docs = [ "furo", "myst-parser", @@ -65,7 +68,7 @@ docs = [ "sphinxcontrib-mermaid", "twisted", ] -dev = ["structlog[tests,docs]", "rich", "mypy"] +dev = ["structlog[tests,typing,docs]"] [tool.pytest.ini_options] diff --git a/tox.ini b/tox.ini index edd54f96..294bbcbf 100644 --- a/tox.ini +++ b/tox.ini @@ -20,11 +20,8 @@ isolated_build = True [testenv:docs] # Keep basepython in sync with gh-actions and .readthedocs.yml. basepython = python3.10 -extras = - docs +extras = docs passenv = TERM -setenv = - PYTHONHASHSEED = 0 commands = sphinx-build -n -T -W -b html -d {envtmpdir}/doctrees docs docs/_build/html sphinx-build -n -T -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html @@ -33,45 +30,30 @@ commands = [testenv:pre-commit] skip_install = true deps = pre-commit -passenv = HOMEPATH # needed on Windows -commands = pre-commit run --all-files +commands = pre-commit run --all-files --show-diff-on-failure [testenv:mypy] description = Check types -# Need twisted & rich for stubs. -# Otherwise mypy fails in tox. -deps = - mypy - rich - twisted +extras = typing commands = mypy src typing_examples.py [testenv] extras = tests -deps = - colorama: twisted -setenv = - PYTHONHASHSEED = 0 +setenv = PYTHONHASHSEED = 0 commands = python -m pytest {posargs} -# For missing types +# For missing types we get from typing-extensions [testenv:py37] deps = twisted -setenv = - PYTHONHASHSEED = 0 -commands = - python -m coverage run -m pytest {posargs} +commands = python -m coverage run -m pytest {posargs} [testenv:py310] deps = twisted -setenv = - PYTHONHASHSEED = 0 -commands = - python -m coverage run -m pytest {posargs} +commands = {[testenv:py37]commands} [testenv:py39-colorama] @@ -81,12 +63,12 @@ commands = python -m coverage run -m pytest tests/test_dev.py {posargs} [testenv:py310-be] deps = better-exceptions -commands = python -m coverage run -m pytest tests/test_dev.py {posargs} +commands = {[testenv:py39-colorama]commands} [testenv:py310-rich] deps = rich -commands = python -m coverage run -m pytest tests/test_dev.py {posargs} +commands = {[testenv:py39-colorama]commands} [testenv:coverage-report] From da5f90c2975041d03395be5ec4f5da8f621ed257 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 24 Aug 2022 06:00:53 +0200 Subject: [PATCH 0743/1520] Add fake setup.py to make GitHub recognize us Co-authored-by: Seth Michael Larson <18519037+sethmlarson@users.noreply.github.com> --- pyproject.toml | 6 ++++++ setup.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 setup.py diff --git a/pyproject.toml b/pyproject.toml index 716c8486..026f30a2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,6 +71,12 @@ docs = [ dev = ["structlog[tests,typing,docs]"] +[tool.hatch.build] +# Just a fake stub to make GitHub recognize us. +# See the file for details. +exclude = ["setup.py"] + + [tool.pytest.ini_options] addopts = ["-ra", "--strict-markers", "--strict-config"] testpaths = "tests" diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..bc5545d2 --- /dev/null +++ b/setup.py @@ -0,0 +1,31 @@ +import sys + +from setuptools import setup + + +sys.stderr.write( + """ +=============================== +Unsupported installation method +=============================== + +structlog no longer supports installation with `python setup.py install`. +Please use `python -m pip install .` instead. +""" +) +sys.exit(1) + + +# The below code will never execute, however GitHub is particularly +# picky about where it finds Python packaging metadata. +# See: https://github.com/github/feedback/discussions/6456 +# +# To be removed once GitHub catches up. + +setup( + name="structlog", + install_requires=[ + "typing-extensions; python_version<'3.8'", + "importlib_metadata; python_version<'3.8'", + ], +) From f976b929c56b7cfc671386bee68e82035b3cc58b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 24 Aug 2022 06:52:39 +0200 Subject: [PATCH 0744/1520] Switch to hatch-vcs --- .github/workflows/ci.yml | 2 ++ pyproject.toml | 10 +++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b977cd92..ffd89909 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,8 +11,10 @@ on: env: FORCE_COLOR: "1" # Make tools pretty. TOX_TESTENV_PASSENV: FORCE_COLOR + SETUPTOOLS_SCM_PRETEND_VERSION: "1.0" # avoid warnings about shallow checkout PYTHON_LATEST: "3.10" + jobs: tests: name: tox on ${{ matrix.python-version }} diff --git a/pyproject.toml b/pyproject.toml index 026f30a2..060efc42 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,14 +1,13 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 [build-system] -requires = ["hatchling", "hatch-fancy-pypi-readme"] +requires = ["hatchling", "hatch-vcs", "hatch-fancy-pypi-readme"] build-backend = "hatchling.build" [project] -dynamic = ["readme"] +dynamic = ["readme", "version"] name = "structlog" -version = "22.2.0.dev0" description = "Structured Logging for Python" authors = [{ name = "Hynek Schlawack", email = "hs@ox.cx" }] requires-python = ">=3.7" @@ -71,6 +70,11 @@ docs = [ dev = ["structlog[tests,typing,docs]"] +[tool.hatch.version] +source = "vcs" +raw-options = { version_scheme = "no-guess-dev" } + + [tool.hatch.build] # Just a fake stub to make GitHub recognize us. # See the file for details. From d93015464cc70af7c1d1cb0dcd73910944f388fb Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 24 Aug 2022 08:51:02 +0200 Subject: [PATCH 0745/1520] Fancy up readme --- .github/workflows/ci.yml | 2 ++ README.md | 16 ++++++++++------ docs/index.rst | 2 +- pyproject.toml | 21 ++++++++++++++++++--- 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ffd89909..502eb1bc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -84,6 +84,8 @@ jobs: steps: - uses: actions/checkout@v3 - uses: hynek/build-and-inspect-python-package@v1 + - run: python -m pip install hatch-fancy-pypi-readme + - run: python -m hatch_fancy_pypi_readme install-dev: name: Verify dev env diff --git a/README.md b/README.md index 4a5a2525..735a8197 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,10 @@ -

    - - structlog - -

    +

    +

    + + structlog + +

    +

    Documentation @@ -37,7 +39,9 @@ Once you feel inspired to try it out, check out our friendly [Getting Started tu If you prefer videos over reading, check out [Markus Holtermann](https://twitter.com/m_holtermann)'s DjangoCon Europe 2019 talk: [*Logging Rethought 2: The Actions of Frank Taylor Jr.*](https://www.youtube.com/watch?v=Y5eyEgyHLLo) -# Project Information + + +## Project Information - **License**: *dual* [Apache License, version 2 and MIT](https://www.structlog.org/en/stable/license.html) - **PyPI**: diff --git a/docs/index.rst b/docs/index.rst index 0ee9baa6..29cbe0cf 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -77,7 +77,7 @@ Project Information .. include:: ../README.md :parser: myst_parser.sphinx_ - :start-after: # Project Information + :start-after: ## Project Information .. stop Sphinx from complaints about orphaned docs, we link them elsewhere diff --git a/pyproject.toml b/pyproject.toml index 060efc42..c864298b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -163,15 +163,30 @@ path = "README.md" start-after = "\n" end-before = "\n" +[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]] +path = "README.md" +start-after = "\n" + [[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]] text = """ -## Release Information +## Release Information for """ -""" +[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]] +path = "CHANGELOG.md" +start-after = "" +# pattern = "\n## (.+?)\n### " +pattern = "## ([^\n]+?\n\n)###" [[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]] path = "CHANGELOG.md" start-after = "" -pattern = "\n(###.+?)\n## " +pattern = "\n(###.+?\n)## " + +[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]] +text = "\n## Credits\n" + +[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]] +path = "AUTHORS.md" +start-after = "# Authors\n" From 3b3d4f53d25bf20304abf1b3af20a1bde2b247b2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 24 Aug 2022 09:44:20 +0200 Subject: [PATCH 0746/1520] Get correct version in package ci --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 502eb1bc..54fdd6aa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -80,9 +80,13 @@ jobs: package: name: Build & verify package runs-on: ubuntu-latest + env: + SETUPTOOLS_SCM_PRETEND_VERSION: "" steps: - uses: actions/checkout@v3 + with: + fetch-depth: 0 # get correct version - uses: hynek/build-and-inspect-python-package@v1 - run: python -m pip install hatch-fancy-pypi-readme - run: python -m hatch_fancy_pypi_readme From c9652a2643bb7be6071de89497e93ca1bcff4abb Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 26 Aug 2022 17:44:45 +0200 Subject: [PATCH 0747/1520] Housekeeping --- .github/CONTRIBUTING.md | 2 +- .github/workflows/ci.yml | 2 +- AUTHORS.md | 2 +- pyproject.toml | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index d31577a9..62d63f5b 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -207,6 +207,6 @@ or: [CI]: https://github.com/hynek/structlog/actions [Hynek Schlawack]: https://hynek.me/about/ [*pre-commit*]: https://pre-commit.com/ -[*tox*]: https://https://tox.wiki/ +[*tox*]: https://tox.wiki/ [semantic newlines]: https://rhodesmill.org/brandon/2012/one-sentence-per-line/ [*reStructuredText*]: https://www.sphinx-doc.org/en/stable/usage/restructuredtext/basics.html diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 54fdd6aa..fa305201 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,7 @@ jobs: run: | python -VV python -m site - python -m pip install --upgrade pip setuptools wheel + python -m pip install --upgrade pip wheel python -m pip install --upgrade virtualenv tox tox-gh-actions - run: python -m tox diff --git a/AUTHORS.md b/AUTHORS.md index c000cc10..de7354fa 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -2,7 +2,7 @@ `structlog` is written and maintained by [Hynek Schlawack](https://hynek.me/). It’s inspired by previous work by [Jean-Paul Calderone](https://github.com/exarkun) and [David Reid](https://github.com/dreid). -The development is kindly supported by my employer [Variomedia AG](https://www.variomedia.de/), ``structlog`` [Tidelift subscribers](https://tidelift.com/subscription/pkg/pypi-structlog?utm_source=pypi-structlog&utm_medium=referral&utm_campaign=enterprise&utm_term=repo), and all my amazing [GitHub Sponsors](https://github.com/sponsors/hynek). +The development is kindly supported by my employer [Variomedia AG](https://www.variomedia.de/), ``structlog`` [Tidelift subscribers](https://tidelift.com/subscription/pkg/pypi-structlog?utm_source=pypi-structlog&utm_medium=referral&utm_campaign=enterprise&utm_term=repo), and all my amazing [GitHub Sponsors](https://github.com/sponsors/hynek). A full list of contributors can be found on GitHub’s [overview](https://github.com/hynek/structlog/graphs/contributors). diff --git a/pyproject.toml b/pyproject.toml index c864298b..9668c640 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -176,7 +176,6 @@ text = """ [[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]] path = "CHANGELOG.md" start-after = "" -# pattern = "\n## (.+?)\n### " pattern = "## ([^\n]+?\n\n)###" [[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]] From be950cb245e0868947107dddd107fd357c82987d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 5 Sep 2022 23:18:09 +0200 Subject: [PATCH 0748/1520] [pre-commit.ci] pre-commit autoupdate (#440) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f4489812..d59f7cb1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,7 +7,7 @@ default_language_version: repos: - repo: https://github.com/psf/black - rev: 22.6.0 + rev: 22.8.0 hooks: - id: black From f18acfe289bc6ccb94abc06d51fdf73254061642 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 8 Sep 2022 16:34:06 +0200 Subject: [PATCH 0749/1520] No reason for RTD to be a dotfile --- .readthedocs.yml => readthedocs.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .readthedocs.yml => readthedocs.yml (100%) diff --git a/.readthedocs.yml b/readthedocs.yml similarity index 100% rename from .readthedocs.yml rename to readthedocs.yml From b579ffaf9e48a24603602433649525c22da6078c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 11 Sep 2022 12:14:33 +0200 Subject: [PATCH 0750/1520] Stop using confusing msg() method across the docs --- docs/api.rst | 8 ++++---- .../code_examples/getting-started/imaginary_web.py | 6 +++--- .../getting-started/imaginary_web_better.py | 6 +++--- docs/configuration.rst | 4 ++-- docs/contextvars.rst | 14 +++++++------- docs/custom-wrappers.rst | 8 ++++---- docs/getting-started.rst | 14 ++++++++------ docs/testing.rst | 6 +++--- src/structlog/_base.py | 4 ++-- src/structlog/_config.py | 2 +- src/structlog/_loggers.py | 4 ++-- src/structlog/testing.py | 4 ++-- 12 files changed, 41 insertions(+), 39 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 10776b79..1455cd31 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -97,11 +97,11 @@ API Reference >>> from pprint import pprint >>> cl = structlog.testing.CapturingLogger() - >>> cl.msg("hello") - >>> cl.msg("hello", when="again") + >>> cl.info("hello") + >>> cl.info("hello", when="again") >>> pprint(cl.calls) - [CapturedCall(method_name='msg', args=('hello',), kwargs={}), - CapturedCall(method_name='msg', args=('hello',), kwargs={'when': 'again'})] + [CapturedCall(method_name='info', args=('hello',), kwargs={}), + CapturedCall(method_name='info', args=('hello',), kwargs={'when': 'again'})] .. autoclass:: CapturingLoggerFactory .. autoclass:: CapturedCall diff --git a/docs/code_examples/getting-started/imaginary_web.py b/docs/code_examples/getting-started/imaginary_web.py index 14494bd8..f64bc7c9 100644 --- a/docs/code_examples/getting-started/imaginary_web.py +++ b/docs/code_examples/getting-started/imaginary_web.py @@ -8,11 +8,11 @@ def view(request): user_agent = request.get("HTTP_USER_AGENT", "UNKNOWN") peer_ip = request.client_addr if something: - log.msg("something", user_agent=user_agent, peer_ip=peer_ip) + log.info("something", user_agent=user_agent, peer_ip=peer_ip) return "something" elif something_else: - log.msg("something_else", user_agent=user_agent, peer_ip=peer_ip) + log.info("something_else", user_agent=user_agent, peer_ip=peer_ip) return "something_else" else: - log.msg("else", user_agent=user_agent, peer_ip=peer_ip) + log.info("else", user_agent=user_agent, peer_ip=peer_ip) return "else" diff --git a/docs/code_examples/getting-started/imaginary_web_better.py b/docs/code_examples/getting-started/imaginary_web_better.py index ffd34337..44a33214 100644 --- a/docs/code_examples/getting-started/imaginary_web_better.py +++ b/docs/code_examples/getting-started/imaginary_web_better.py @@ -13,11 +13,11 @@ def view(request): if foo: log = log.bind(foo=foo) if something: - log.msg("something") + log.info("something") return "something" elif something_else: - log.msg("something_else") + log.info("something_else") return "something_else" else: - log.msg("else") + log.info("else") return "else" diff --git a/docs/configuration.rst b/docs/configuration.rst index 2e8dfe89..8a38e53f 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -40,7 +40,7 @@ Thus the :ref:`example ` from the previous chapter could have been written >>> configure(processors=[proc]) >>> log = get_logger() - >>> log.msg("hello world") + >>> log.info("hello world") I got called with {'event': 'hello world'} {'event': 'hello world'} @@ -52,7 +52,7 @@ Configuration also applies to :func:`~structlog.wrap_logger` because that's what >>> configure(processors=[proc], context_class=dict) >>> log = wrap_logger(PrintLogger()) - >>> log.msg("hello world") + >>> log.info("hello world") I got called with {'event': 'hello world'} {'event': 'hello world'} diff --git a/docs/contextvars.rst b/docs/contextvars.rst index 9fa9c8b8..b14dc321 100644 --- a/docs/contextvars.rst +++ b/docs/contextvars.rst @@ -57,24 +57,24 @@ We're sorry the word *context* means three different things in this itemization {'a': at ...>, 'b': at ...>} >>> # Then use loggers as per normal >>> # (perhaps by using structlog.get_logger() to create them). - >>> log.msg("hello") + >>> log.info("hello") event='hello' a=1 b=2 >>> # Use unbind_contextvars to remove a variable from the context. >>> unbind_contextvars("b") - >>> log.msg("world") + >>> log.info("world") event='world' a=1 >>> # You can also bind key/value pairs temporarily. >>> with bound_contextvars(b=2): - ... log.msg("hi") + ... log.info("hi") event='hi' a=1 b=2 >>> # Now it's gone again. - >>> log.msg("hi") + >>> log.info("hi") event='hi' a=1 >>> # And when we clear the contextvars state again, it goes away. >>> # a=None is printed due to the key_order argument passed to >>> # KeyValueRenderer, but it is NOT present anymore. >>> clear_contextvars() - >>> log.msg("hi there") + >>> log.info("hi there") event='hi there' a=None @@ -88,9 +88,9 @@ If e.g. your request handler calls a helper function that needs to temporarily o def foo(): bind_contextvars(a=1) _helper() - log.msg("a is restored!") # a=1 + log.info("a is restored!") # a=1 def _helper(): tokens = bind_contextvars(a=2) - log.msg("a is overridden") # a=2 + log.info("a is overridden") # a=2 reset_contextvars(**tokens) diff --git a/docs/custom-wrappers.rst b/docs/custom-wrappers.rst index 74916dc7..5e431a66 100644 --- a/docs/custom-wrappers.rst +++ b/docs/custom-wrappers.rst @@ -35,14 +35,14 @@ It's much easier to demonstrate with an example: >>> from structlog import BoundLoggerBase, PrintLogger, wrap_logger >>> class SemanticLogger(BoundLoggerBase): - ... def msg(self, event, **kw): + ... def info(self, event, **kw): ... if not "status" in kw: - ... return self._proxy_to_logger("msg", event, status="ok", **kw) + ... return self._proxy_to_logger("info", event, status="ok", **kw) ... else: - ... return self._proxy_to_logger("msg", event, **kw) + ... return self._proxy_to_logger("info", event, **kw) ... ... def user_error(self, event, **kw): - ... self.msg(event, status="user_error", **kw) + ... self.info(event, status="user_error", **kw) >>> log = wrap_logger(PrintLogger(), wrapper_class=SemanticLogger) >>> log = log.bind(user="fprefect") >>> log.user_error("user.forgot_towel") diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 3f19119f..0273a5e2 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -27,12 +27,14 @@ And indeed, the simplest possible usage looks like this >>> import structlog >>> log = structlog.get_logger() - >>> log.msg("greeted", whom="world", more_than_a_string=[1, 2, 3]) # doctest: +SKIP - 2016-09-17 10:13.45 greeted more_than_a_string=[1, 2, 3] whom='world' + >>> log.info("greeted", whom="world", more_than_a_string=[1, 2, 3]) # doctest: +SKIP + 2022-09-11 11:58.26 [info ] greeted more_than_a_string=[1, 2, 3] whom=world Here, ``structlog`` takes full advantage of its hopefully useful default settings: - Output is sent to `standard out`_ instead of exploding into the user's face or doing nothing. +- It imitates standard library `logging`'s log levels for familiarity -- even if you're not using any of your integrations. + By default, no level-based filtering is done, but it comes with a very fast filtering machinery in the form of `structlog.make_filtering_bound_logger()`. - All keywords are formatted using `structlog.dev.ConsoleRenderer`. That in turn uses `repr` to serialize all values to strings. Thus, it's easy to add support for logging of your own objects\ [*]_. @@ -66,7 +68,7 @@ Using the defaults, as above, is equivalent to:: - `structlog.stdlib.recreate_defaults()` allows you to switch ``structlog`` to using standard library's `logging` module for output for better interoperability with just one function call. - - `structlog.make_filtering_bound_logger()` (re-)uses `logging`'s log levels, but doesn't use it at all. + - `structlog.make_filtering_bound_logger()` (re-)uses `logging`'s log levels, but doesn't use `logging` at all. The exposed API is `FilteringBoundLogger`. - For brevity and to enable doctests, all further examples in ``structlog``'s documentation use the more simplistic `structlog.processors.KeyValueRenderer()` without timestamps. @@ -93,7 +95,7 @@ At this point, you'll be tempted to write a closure like :: def log_closure(event): - log.msg(event, user_agent=user_agent, peer_ip=peer_ip) + log.info(event, user_agent=user_agent, peer_ip=peer_ip) inside of the view. Problem solved? @@ -145,7 +147,7 @@ Now you have to tell ``structlog`` about your processor by `configuring >> structlog.configure(processors=[timestamper, structlog.processors.KeyValueRenderer()]) - >>> structlog.get_logger().msg("hi") # doctest: +SKIP + >>> structlog.get_logger().info("hi") # doctest: +SKIP event='hi' time='2018-01-21T09:37:36.976816' @@ -165,7 +167,7 @@ So assuming you want to follow `best practices ` and ren .. doctest:: >>> structlog.configure(processors=[structlog.processors.JSONRenderer()]) - >>> structlog.get_logger().msg("hi") + >>> structlog.get_logger().info("hi") {"event": "hi"} diff --git a/docs/testing.rst b/docs/testing.rst index 61ef820a..fa1d7c9c 100644 --- a/docs/testing.rst +++ b/docs/testing.rst @@ -64,10 +64,10 @@ Additionally ``structlog`` also ships with a logger that just returns whatever i .. doctest:: >>> from structlog import ReturnLogger - >>> ReturnLogger().msg(42) == 42 + >>> ReturnLogger().info(42) == 42 True >>> obj = ["hi"] - >>> ReturnLogger().msg(obj) is obj + >>> ReturnLogger().info(obj) is obj True - >>> ReturnLogger().msg("hello", when="again") + >>> ReturnLogger().info("hello", when="again") (('hello',), {'when': 'again'}) diff --git a/src/structlog/_base.py b/src/structlog/_base.py index f34cc9c5..1121d72d 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -129,7 +129,7 @@ def _process_event( :param event: The event -- usually the first positional argument to a logger. :param event_kw: Additional event keywords. For example if someone - calls ``log.msg("foo", bar=42)``, *event* would to be ``"foo"`` + calls ``log.info("foo", bar=42)``, *event* would to be ``"foo"`` and *event_kw* ``{"bar": 42}``. :raises: `structlog.DropEvent` if log entry should be dropped. @@ -192,7 +192,7 @@ def _proxy_to_logger( :param event: The event -- usually the first positional argument to a logger. :param event_kw: Additional event keywords. For example if someone - calls ``log.msg("foo", bar=42)``, *event* would to be ``"foo"`` + calls ``log.info("foo", bar=42)``, *event* would to be ``"foo"`` and *event_kw* ``{"bar": 42}``. .. note:: diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 52e40e7a..e19fec44 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -104,7 +104,7 @@ def get_logger(*args: Any, **initial_values: Any) -> Any: >>> from structlog import get_logger >>> log = get_logger(y=23) - >>> log.msg("hello", x=42) + >>> log.info("hello", x=42) y=23 x=42 event='hello' :param args: *Optional* positional arguments that are passed unmodified to diff --git a/src/structlog/_loggers.py b/src/structlog/_loggers.py index 9fd80509..e2cd6f18 100644 --- a/src/structlog/_loggers.py +++ b/src/structlog/_loggers.py @@ -41,7 +41,7 @@ class PrintLogger: :param file: File to print to. (default: `sys.stdout`) >>> from structlog import PrintLogger - >>> PrintLogger().msg("hello") + >>> PrintLogger().info("hello") hello Useful if you follow @@ -143,7 +143,7 @@ class WriteLogger: :param file: File to print to. (default: `sys.stdout`) >>> from structlog import WriteLogger - >>> WriteLogger().msg("hello") + >>> WriteLogger().info("hello") hello Useful if you follow diff --git a/src/structlog/testing.py b/src/structlog/testing.py index 13ce6696..a64315d0 100644 --- a/src/structlog/testing.py +++ b/src/structlog/testing.py @@ -84,9 +84,9 @@ class ReturnLogger: Return the arguments that it's called with. >>> from structlog import ReturnLogger - >>> ReturnLogger().msg("hello") + >>> ReturnLogger().info("hello") 'hello' - >>> ReturnLogger().msg("hello", when="again") + >>> ReturnLogger().info("hello", when="again") (('hello',), {'when': 'again'}) .. versionchanged:: 0.3.0 From 80e25c2eb04e25248b0700df71db0ecf03df040f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 11 Sep 2022 12:36:06 +0200 Subject: [PATCH 0751/1520] Use transparent logo & move text into text --- README.md | 15 ++++++++------- docs/_static/structlog_logo_transparent.png | Bin 0 -> 79862 bytes 2 files changed, 8 insertions(+), 7 deletions(-) create mode 100644 docs/_static/structlog_logo_transparent.png diff --git a/README.md b/README.md index 735a8197..3724fe12 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,11 @@ -

    -

    - - structlog - -

    -

    +# structlog: Structured Logging for Python + +

    + + structlog + +

    +

    Documentation diff --git a/docs/_static/structlog_logo_transparent.png b/docs/_static/structlog_logo_transparent.png new file mode 100644 index 0000000000000000000000000000000000000000..e52c5635f887799c3c66e5e62b3dad4f2f321030 GIT binary patch literal 79862 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%0D8FIDD;UFU$Hw+0f!Flo#0!tLriLurW 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 Date: Sat, 17 Sep 2022 14:05:37 +0200 Subject: [PATCH 0752/1520] Simplify CI --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fa305201..4bed734b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,6 +12,8 @@ env: FORCE_COLOR: "1" # Make tools pretty. TOX_TESTENV_PASSENV: FORCE_COLOR SETUPTOOLS_SCM_PRETEND_VERSION: "1.0" # avoid warnings about shallow checkout + PIP_DISABLE_PIP_VERSION_CHECK: 1 + PIP_NO_PYTHON_VERSION_WARNING: 1 PYTHON_LATEST: "3.10" @@ -34,7 +36,6 @@ jobs: run: | python -VV python -m site - python -m pip install --upgrade pip wheel python -m pip install --upgrade virtualenv tox tox-gh-actions - run: python -m tox From 5cd9fb4a86299f3c04befbc342a116f480586abe Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 17 Sep 2022 15:51:12 +0200 Subject: [PATCH 0753/1520] Add 16x16 icon used for docsets --- docs/_static/docset-icon.png | Bin 0 -> 1389 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/_static/docset-icon.png diff --git a/docs/_static/docset-icon.png b/docs/_static/docset-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..d83f09c6d28b0c694f30e29b5f64c3cc950882da GIT binary patch literal 1389 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>iln8El(n8T0|T?J zuCB4RbeOwNf}eq}gNC}2n1Q+!&<)yJ8ZmzEvED9uG0w>WhGsf)K*3l)v$A+ATSIvX z5&pagv!ZAV4J8Sncz~m(je)$bnp8!Cb#Azsgs7m6p+ae#Rb#rnnXa6SgixTPW=F2G ztA(ngiBfmIi?^-1v6d`QusFu5Gtb4tN{x?~+dy3sXmWYHwV{TLjD(<-o@{%LQ)Y;X zi@6FYOw{F6B$E9N8JO6Bp`~wNU}$7ypdsUJqv~Y?3}04Y_*h$8+u7Oa=;-kC z^DE1WnCr^<*=snPDe0+6ad2>GYHAuA8v}z^P7dT91_nl;IaP6fb&39^QQox~A^D-+ z;clJ@UY=EnL8VDD!mf@^wWY&I}5$5Q=NbTSQcj$=dCxT%+ue+xFp`*+d(hhN53%2ydcVa zVu^cyP5h*afcDbp-Xf2Q#qQH9y($x}TQVJ|S9oQGnxscMO|A}|Ru?g?!mA_4xhv1b z&QQ+9T-nv$)X~8%$ip%>(z+_yt~kcBx6swX)X>Aj)7#tI$;rvwNCy~7Fz|g8L3GxG_aUy{2f<1jP=3Fihe!bpc!?FE|kJ;-R zDl7|XbzWSQcKz|mS^U)Rl*)glMoa$w&EYG1{@lXx$;;28j*qND~b^6J+6rkOVN#5=*w`a150h2rfdx@v7EBiA}L0(n)mUzFf zKxt`D7sn8Z%Zvhy@Be|6Gcc*CYiMd|>o7C0fSt~&t5;o9s}D>*Yz*uS3>=)sCUx}< zjZMuhre>hb&CO$O(c0GD(b?6~ZE3~Jz`$p1)6?DC*FRz6q{&lk`GMKr&VK5&=`&`| znmuRkJO^NY7jSZ(GJnC8g^Lz1nX}Xdn2815+?Oq1v2x0))oa$adU!Gj35$63tXscf z zT6RuuUVcGgkt{Hc%NLiFmX%j1C@NJ}DXXY5tbU)V*~t3a1L#ZD64!{5l*E!$tK_0o zAjM#0U}U6gV5w_p7-DE(Wo&F^YN%~sU}a!%g(vVPiiX_$l+3hB+!~e!zDxyb(16=e pl9`)YT#}eufY4(eVrXn-Y;I)?wdC^blw6=522WQ%mvv4FO#l|6o9h4o literal 0 HcmV?d00001 From 149897572cb69a0b97fdabcda9ec4db51f688d90 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 17 Sep 2022 17:02:47 +0200 Subject: [PATCH 0754/1520] Build docsets in CI (#441) --- .github/workflows/build-docset.yml | 31 ++++++++++++++++++++++++++++++ .gitignore | 1 + tox.ini | 8 ++++++++ 3 files changed, 40 insertions(+) create mode 100644 .github/workflows/build-docset.yml diff --git a/.github/workflows/build-docset.yml b/.github/workflows/build-docset.yml new file mode 100644 index 00000000..6360d28d --- /dev/null +++ b/.github/workflows/build-docset.yml @@ -0,0 +1,31 @@ +--- +name: Build a documentation set bundle. + +on: + push: + tags: ["*"] + pull_request: + branches: [main] + workflow_dispatch: + +env: + PIP_DISABLE_PIP_VERSION_CHECK: 1 + PIP_NO_PYTHON_VERSION_WARNING: 1 + +jobs: + docset: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: "3.10" + + - run: pip install tox + + - run: tox -e docset + + - uses: actions/upload-artifact@v3 + with: + name: docset + path: structlog.docset diff --git a/.gitignore b/.gitignore index e8dbed0c..f1f3ce69 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ dist docs/_build htmlcov tmp +structlog.docset diff --git a/tox.ini b/tox.ini index 294bbcbf..25792c31 100644 --- a/tox.ini +++ b/tox.ini @@ -95,3 +95,11 @@ commands = pip install --upgrade pip pip wheel -w {envtmpdir}/build --no-deps . twine check {envtmpdir}/build/* + + +[testenv:docset] +deps = doc2dash +extras = docs +commands = + sphinx-build -n -T -W -b html -d {envtmpdir}/doctrees docs docs/_build/html + doc2dash --index-page index.html --icon docs/_static/docset-icon.png --online-redirect-url https://www.structlog.org/en/latest/ docs/_build/html From 5a47102c110ad3ce43a50c340cf525dd6a4824f9 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 17 Sep 2022 17:03:52 +0200 Subject: [PATCH 0755/1520] Simplify --- .github/workflows/build-docset.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/build-docset.yml b/.github/workflows/build-docset.yml index 6360d28d..c9e9993e 100644 --- a/.github/workflows/build-docset.yml +++ b/.github/workflows/build-docset.yml @@ -4,8 +4,6 @@ name: Build a documentation set bundle. on: push: tags: ["*"] - pull_request: - branches: [main] workflow_dispatch: env: @@ -27,5 +25,4 @@ jobs: - uses: actions/upload-artifact@v3 with: - name: docset path: structlog.docset From ea48e16ad2cef352b2409fd8af8a566c2b6edccc Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 17 Sep 2022 17:05:22 +0200 Subject: [PATCH 0756/1520] Shorten name, it gets cropped --- .github/workflows/build-docset.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-docset.yml b/.github/workflows/build-docset.yml index c9e9993e..56bd0fbe 100644 --- a/.github/workflows/build-docset.yml +++ b/.github/workflows/build-docset.yml @@ -1,5 +1,5 @@ --- -name: Build a documentation set bundle. +name: Build docset on: push: From faaad16a74a950938bb7514c168e794998c62650 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 17 Sep 2022 17:08:02 +0200 Subject: [PATCH 0757/1520] Simplify --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4bed734b..c20ce8d3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,7 +36,7 @@ jobs: run: | python -VV python -m site - python -m pip install --upgrade virtualenv tox tox-gh-actions + python -m pip install --upgrade tox tox-gh-actions - run: python -m tox From 13e80e9383b89a49b8da899a457720d65be318a7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 17 Sep 2022 17:10:44 +0200 Subject: [PATCH 0758/1520] Add hires icon --- docs/_static/docset-icon@2x.png | Bin 0 -> 3021 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/_static/docset-icon@2x.png diff --git a/docs/_static/docset-icon@2x.png b/docs/_static/docset-icon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..81a099d9659877e8b7577d954f3ac8a77e9bf61d GIT binary patch literal 3021 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 E58qIo{{R30 literal 0 HcmV?d00001 From ba8d3fb01ab81b42c45be46461010f82b7a7d5e5 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 17 Sep 2022 17:13:30 +0200 Subject: [PATCH 0759/1520] Proper artifact name --- .github/workflows/build-docset.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-docset.yml b/.github/workflows/build-docset.yml index 56bd0fbe..43782563 100644 --- a/.github/workflows/build-docset.yml +++ b/.github/workflows/build-docset.yml @@ -25,4 +25,5 @@ jobs: - uses: actions/upload-artifact@v3 with: + name: structlog.docset path: structlog.docset From 96da12c5c58cde275d5aab4179f81ef41eb01755 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 17 Sep 2022 17:17:13 +0200 Subject: [PATCH 0760/1520] Add 2x icon to docset --- tox.ini | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tox.ini b/tox.ini index 25792c31..11cb84a9 100644 --- a/tox.ini +++ b/tox.ini @@ -100,6 +100,11 @@ commands = [testenv:docset] deps = doc2dash extras = docs +allowlist_externals = + rm + cp commands = + rm -rf structlog.docset docs/_build sphinx-build -n -T -W -b html -d {envtmpdir}/doctrees docs docs/_build/html doc2dash --index-page index.html --icon docs/_static/docset-icon.png --online-redirect-url https://www.structlog.org/en/latest/ docs/_build/html + cp docs/_static/docset-icon@2x.png structlog.docset/icon@2x.png From 5cdf0b6e1b226abc780ad44f7744d04a9aadea9e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 17 Sep 2022 17:24:59 +0200 Subject: [PATCH 0761/1520] Already tar it up in CI --- .github/workflows/build-docset.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-docset.yml b/.github/workflows/build-docset.yml index 43782563..fede21c2 100644 --- a/.github/workflows/build-docset.yml +++ b/.github/workflows/build-docset.yml @@ -22,8 +22,9 @@ jobs: - run: pip install tox - run: tox -e docset + - run: tar --exclude='.DS_Store' -cvzf structlog.tgz structlog.docset - uses: actions/upload-artifact@v3 with: - name: structlog.docset - path: structlog.docset + name: docset + path: structlog.tgz From a42548b3b2ae1aba88b361df1da60e53f7f79d1c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 17 Sep 2022 17:26:36 +0200 Subject: [PATCH 0762/1520] We need the version for the docset --- .github/workflows/build-docset.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build-docset.yml b/.github/workflows/build-docset.yml index fede21c2..609f7196 100644 --- a/.github/workflows/build-docset.yml +++ b/.github/workflows/build-docset.yml @@ -15,6 +15,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 + with: + fetch-depth: 0 # get correct version - uses: actions/setup-python@v4 with: python-version: "3.10" From 562bd5dc51755d359368a24a404a6d81922b7ed2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 18 Sep 2022 07:09:38 +0200 Subject: [PATCH 0763/1520] Add codespell --- .pre-commit-config.yaml | 7 ++++++- docs/loggers.rst | 2 +- src/structlog/processors.py | 4 ++-- src/structlog/stdlib.py | 12 +++++------- tests/test_loggers.py | 34 ++++++++++++++++++---------------- tests/test_processors.py | 12 ++++++------ tests/test_stdlib.py | 6 +++--- 7 files changed, 41 insertions(+), 36 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d59f7cb1..83d2826b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,7 +12,7 @@ repos: - id: black - repo: https://github.com/asottile/pyupgrade - rev: v2.37.3 + rev: v2.38.0 hooks: - id: pyupgrade args: [--py37-plus] @@ -34,6 +34,11 @@ repos: - id: flake8 exclude: docs/code_examples + - repo: https://github.com/codespell-project/codespell + rev: v2.2.1 + hooks: + - id: codespell + - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.3.0 hooks: diff --git a/docs/loggers.rst b/docs/loggers.rst index 0d714cc8..e7622a4b 100644 --- a/docs/loggers.rst +++ b/docs/loggers.rst @@ -18,7 +18,7 @@ It consists of three parts: #. A list of :doc:`processors ` that are called on every log entry. Each processor receives the return value of its predecessor passed as an argument. #. And finally a *logger* that it's wrapping. - This wrapped logger is reponsible for the *output* of the log entry that has been returned by the last processor. + This wrapped logger is responsible for the *output* of the log entry that has been returned by the last processor. This *can* be standard library's `logging.Logger`, but absolutely doesn't have to. Bound loggers themselves do *not* do any I/O themselves. diff --git a/src/structlog/processors.py b/src/structlog/processors.py index f898fde9..2bb594a9 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -410,7 +410,7 @@ def __call__( dict_tracebacks = ExceptionRenderer(ExceptionDictTransformer()) """ Replace an ``exc_info`` field with an ``exception`` field containing structured -tracebacks suiteable for, e.g., JSON output. +tracebacks suitable for, e.g., JSON output. It is a shortcut for :class:`ExceptionRenderer` with a :class:`~structlog.tracebacks.ExceptionDictTransformer`. @@ -628,7 +628,7 @@ class CallsiteParameter(enum.Enum): #: The basename part of the full path to the python source file of the #: callsite. FILENAME = "filename" - #: The python module the callsite was in. This mimicks the module attribute + #: The python module the callsite was in. This mimics the module attribute #: of `logging.LogRecord` objects and will be the basename, without #: extension, of the full path to the python source file of the callsite. MODULE = "module" diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 208b1372..49f015d5 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -246,10 +246,8 @@ def _proxy_to_logger( return super()._proxy_to_logger(method_name, event=event, **event_kw) - # - # Pass-through attributes and methods to mimick the stdlib's logger + # Pass-through attributes and methods to mimic the stdlib's logger # interface. - # @property def name(self) -> str: @@ -622,10 +620,10 @@ def __call__( ) -> EventDict: args = event_dict.get("positional_args") - # Mimick the formatting behaviour of the stdlib's logging - # module, which accepts both positional arguments and a single - # dict argument. The "single dict" check is the same one as the - # stdlib's logging module performs in LogRecord.__init__(). + # Mimic the formatting behaviour of the stdlib's logging module, which + # accepts both positional arguments and a single dict argument. The + # "single dict" check is the same one as the stdlib's logging module + # performs in LogRecord.__init__(). if args: if len(args) == 1 and isinstance(args[0], dict) and args[0]: args = args[0] diff --git a/tests/test_loggers.py b/tests/test_loggers.py index 348000e6..315be5a1 100644 --- a/tests/test_loggers.py +++ b/tests/test_loggers.py @@ -45,18 +45,19 @@ def test_prints_to_stdout_by_default(self, logger_cls, capsys): assert "hello\n" == out assert "" == err - def test_prints_to_correct_file(self, logger_cls, tmpdir, capsys): + def test_prints_to_correct_file(self, logger_cls, tmp_path, capsys): """ Supplied files are respected. """ - f = tmpdir.join("test.log") - fo = f.open("w") - logger_cls(fo).msg("hello") - out, err = capsys.readouterr() + p = tmp_path / "test.log" + + with p.open("w") as f: + logger_cls(f).msg("hello") + out, err = capsys.readouterr() - assert "" == out == err - fo.close() - assert "hello\n" == f.read() + assert "" == out == err + + assert "hello\n" == p.read_text() def test_lock(self, logger_cls, sio): """ @@ -213,18 +214,19 @@ def test_prints_to_stdout_by_default(self, capsys): assert "hellö\n" == out assert "" == err - def test_prints_to_correct_file(self, tmpdir, capsys): + def test_prints_to_correct_file(self, tmp_path, capsys): """ Supplied files are respected. """ - f = tmpdir.join("test.log") - fo = f.open("wb") - BytesLogger(fo).msg(b"hello") - out, err = capsys.readouterr() + p = tmp_path / "test.log" + + with p.open("wb") as f: + BytesLogger(f).msg(b"hello") + out, err = capsys.readouterr() - assert "" == out == err - fo.close() - assert "hello\n" == f.read() + assert "" == out == err + + assert "hello\n" == p.read_text() def test_repr(self): """ diff --git a/tests/test_processors.py b/tests/test_processors.py index 5ec55b4e..63ae2dcd 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -548,25 +548,25 @@ def test_encodes(self): """ Unicode strings get encoded (as UTF-8 by default). """ - ue = UnicodeEncoder() + e = UnicodeEncoder() - assert {"foo": b"b\xc3\xa4r"} == ue(None, None, {"foo": "b\xe4r"}) + assert {"foo": b"b\xc3\xa4r"} == e(None, None, {"foo": "b\xe4r"}) def test_passes_arguments(self): """ Encoding options are passed into the encoding call. """ - ue = UnicodeEncoder("latin1", "xmlcharrefreplace") + e = UnicodeEncoder("latin1", "xmlcharrefreplace") - assert {"foo": b"–"} == ue(None, None, {"foo": "\u2013"}) + assert {"foo": b"–"} == e(None, None, {"foo": "\u2013"}) def test_bytes_nop(self): """ If the string is already bytes, don't do anything. """ - ue = UnicodeEncoder() + e = UnicodeEncoder() - assert {"foo": b"b\xc3\xa4r"} == ue(None, None, {"foo": b"b\xc3\xa4r"}) + assert {"foo": b"b\xc3\xa4r"} == e(None, None, {"foo": b"b\xc3\xa4r"}) class TestUnicodeDecoder: diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 3cfdc069..bd81b648 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -854,7 +854,7 @@ def test_foreign_pre_chain_gets_exc_info(self): configure_logging((test_processor,), renderer=KeyValueRenderer()) try: - raise RuntimeError("oh noo") + raise RuntimeError("oh no") except Exception: logging.getLogger().exception("okay") @@ -882,7 +882,7 @@ def add_excinfo(logger, log_method, event_dict): ) try: - raise MyException("oh noo") + raise MyException("oh no") except Exception: logging.getLogger().error("okay") @@ -938,7 +938,7 @@ def format_exc_info_fake(logger, name, event_dict): logger.handlers[0].setFormatter(formatter) try: - raise RuntimeError("oh noo") + raise RuntimeError("oh no") except Exception: logging.getLogger().exception("seen worse") From 2449a983718938f170f07d951c0678280be90153 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 18 Sep 2022 10:21:59 +0200 Subject: [PATCH 0764/1520] Add tar-ing of docset too --- .gitignore | 1 + tox.ini | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index f1f3ce69..89b4da12 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ docs/_build htmlcov tmp structlog.docset +structlog.tgz diff --git a/tox.ini b/tox.ini index 11cb84a9..df06c4e6 100644 --- a/tox.ini +++ b/tox.ini @@ -103,8 +103,10 @@ extras = docs allowlist_externals = rm cp + tar commands = - rm -rf structlog.docset docs/_build + rm -rf structlog.docset structlog.tgz docs/_build sphinx-build -n -T -W -b html -d {envtmpdir}/doctrees docs docs/_build/html doc2dash --index-page index.html --icon docs/_static/docset-icon.png --online-redirect-url https://www.structlog.org/en/latest/ docs/_build/html cp docs/_static/docset-icon@2x.png structlog.docset/icon@2x.png + tar --exclude='.DS_Store' -cvzf structlog.tgz structlog.docset From b1579b35bf75604a8e18f12966d8c4fa82c29f8b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 29 Sep 2022 10:45:06 +0200 Subject: [PATCH 0765/1520] Fix mypy (#447) --- .github/workflows/ci.yml | 77 ++++++++++++++++++++++++++++++------ pyproject.toml | 14 ++++--- src/structlog/__init__.py | 2 +- src/structlog/_base.py | 2 +- src/structlog/_config.py | 10 +++-- src/structlog/_log_levels.py | 2 +- src/structlog/dev.py | 16 ++++---- src/structlog/processors.py | 14 ++++--- src/structlog/stdlib.py | 26 ++++++------ src/structlog/threadlocal.py | 20 +++++----- src/structlog/twisted.py | 18 +++++---- src/structlog/types.py | 3 -- tox.ini | 8 ++-- 13 files changed, 138 insertions(+), 74 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c20ce8d3..bc2e7905 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,12 +11,11 @@ on: env: FORCE_COLOR: "1" # Make tools pretty. TOX_TESTENV_PASSENV: FORCE_COLOR + PIP_DISABLE_PIP_VERSION_CHECK: "1" + PIP_NO_PYTHON_VERSION_WARNING: "1" SETUPTOOLS_SCM_PRETEND_VERSION: "1.0" # avoid warnings about shallow checkout - PIP_DISABLE_PIP_VERSION_CHECK: 1 - PIP_NO_PYTHON_VERSION_WARNING: 1 PYTHON_LATEST: "3.10" - jobs: tests: name: tox on ${{ matrix.python-version }} @@ -24,19 +23,19 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11.0-beta - 3.11"] + python-version: + - "3.7" + - "3.8" + - "3.9" + - "3.10" + - "~3.11.0-0" steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - - - name: Install dependencies - run: | - python -VV - python -m site - python -m pip install --upgrade tox tox-gh-actions + - run: python -m pip install --upgrade wheel tox tox-gh-actions - run: python -m tox @@ -78,6 +77,39 @@ jobs: path: htmlcov if: ${{ failure() }} + mypy: + name: mypy on ${{ matrix.python-version }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: + - "3.8" + - "3.9" + - "3.10" + - "~3.11.0-0" + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - run: python -m pip install --upgrade wheel tox + + - run: python -m tox -e mypy + + docs: + name: Build docs & run doctests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: "3.10" + - run: python -m pip install --upgrade wheel tox + + - run: python -m tox -e docs + package: name: Build & verify package runs-on: ubuntu-latest @@ -87,7 +119,7 @@ jobs: steps: - uses: actions/checkout@v3 with: - fetch-depth: 0 # get correct version + fetch-depth: 0 # get correct version - uses: hynek/build-and-inspect-python-package@v1 - run: python -m pip install hatch-fancy-pypi-readme - run: python -m hatch_fancy_pypi_readme @@ -106,3 +138,26 @@ jobs: python-version: ${{env.PYTHON_LATEST}} - run: python -m pip install -e .[dev] - run: python -c 'import structlog; print(structlog.__version__)' + + # Ensure everything required is passing for branch protection. + required-checks-pass: + if: always() + + needs: + - coverage + - docs + - install-dev + - package + + runs-on: ubuntu-latest + + steps: + - name: Harden Runner + uses: step-security/harden-runner@v1 + with: + egress-policy: block + + - name: Decide whether the needed jobs succeeded or failed + uses: re-actors/alls-green@release/v1 + with: + jobs: ${{ toJSON(needs) }} diff --git a/pyproject.toml b/pyproject.toml index 9668c640..73f58691 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -128,14 +128,16 @@ profile = "attrs" [tool.mypy] -warn_unused_ignores = true +strict = true + +show_error_codes = true +enable_error_code = ["ignore-without-code"] + follow_imports = "normal" ignore_missing_imports = true -disallow_untyped_calls = true -warn_no_return = true -warn_redundant_casts = true -disallow_untyped_defs = true -check_untyped_defs = true + +warn_return_any = false + [[tool.mypy.overrides]] module = "tests.*" diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index c0ec50ec..7099e27c 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -44,7 +44,7 @@ try: from structlog import twisted except ImportError: - twisted = None # type: ignore + twisted = None # type: ignore[assignment] __title__ = "structlog" diff --git a/src/structlog/_base.py b/src/structlog/_base.py index 1121d72d..78ed5fba 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -166,7 +166,7 @@ def _process_event( elif isinstance(event_dict, tuple): # In this case we assume that the last processor returned a tuple # of ``(args, kwargs)`` and pass it right through. - return event_dict # type: ignore + return event_dict # type: ignore[return-value] elif isinstance(event_dict, dict): return (), event_dict else: diff --git a/src/structlog/_config.py b/src/structlog/_config.py index e19fec44..47f1e792 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -225,7 +225,7 @@ def configure( if context_class is not None: _CONFIG.default_context_class = context_class if logger_factory is not None: - _CONFIG.logger_factory = logger_factory # type: ignore + _CONFIG.logger_factory = logger_factory if cache_logger_on_first_use is not None: _CONFIG.cache_logger_on_first_use = cache_logger_on_first_use @@ -267,7 +267,7 @@ def reset_defaults() -> None: _CONFIG.default_processors = _BUILTIN_DEFAULT_PROCESSORS[:] _CONFIG.default_wrapper_class = _BUILTIN_DEFAULT_WRAPPER_CLASS _CONFIG.default_context_class = _BUILTIN_DEFAULT_CONTEXT_CLASS - _CONFIG.logger_factory = _BUILTIN_DEFAULT_LOGGER_FACTORY # type: ignore + _CONFIG.logger_factory = _BUILTIN_DEFAULT_LOGGER_FACTORY _CONFIG.cache_logger_on_first_use = _BUILTIN_CACHE_LOGGER_ON_FIRST_USE @@ -335,7 +335,9 @@ def bind(self, **new_values: Any) -> BindableLogger: cls = self._wrapper_class or _CONFIG.default_wrapper_class # Looks like Protocols ignore definitions of __init__ so we have to # silence Mypy here. - logger = cls(_logger, processors=procs, context=ctx) # type: ignore + logger = cls( + _logger, processors=procs, context=ctx # type: ignore[call-arg] + ) def finalized_bind(**new_values: Any) -> BindableLogger: """ @@ -350,7 +352,7 @@ def finalized_bind(**new_values: Any) -> BindableLogger: self._cache_logger_on_first_use is None and _CONFIG.cache_logger_on_first_use is True ): - self.bind = finalized_bind # type: ignore + self.bind = finalized_bind # type: ignore[assignment] return finalized_bind(**new_values) diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index e664164d..4c1cb5c8 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -139,7 +139,7 @@ def log(self: Any, level: int, event: str, **kw: Any) -> Any: name = _LEVEL_TO_NAME[level] return self._proxy_to_logger(name, event, **kw) - meths: dict[str, Callable] = {"log": log} + meths: dict[str, Callable[..., Any]] = {"log": log} for lvl, name in _LEVEL_TO_NAME.items(): meths[name] = make_method(lvl) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 6aff8e9f..b132cce8 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -18,13 +18,13 @@ from typing import Any, Iterable, TextIO, Type, Union from ._frames import _format_exception -from .types import ( - EventDict, - ExceptionRenderer, - ExcInfo, - Protocol, - WrappedLogger, -) +from .types import EventDict, ExceptionRenderer, ExcInfo, WrappedLogger + + +if sys.version_info >= (3, 8): + from typing import Protocol +else: + from typing_extensions import Protocol try: @@ -43,7 +43,7 @@ from rich.console import Console from rich.traceback import Traceback except ImportError: - rich = None # type: ignore + rich = None # type: ignore[assignment] __all__ = [ diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 2bb594a9..0a89cfc3 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -183,7 +183,7 @@ def _items_sorter( def ordered_items(event_dict: EventDict) -> list[tuple[str, Any]]: items = [] - for key in key_order: # type: ignore + for key in key_order: # type: ignore[union-attr] value = event_dict.pop(key, None) if value is not None or not drop_missing: items.append((key, value)) @@ -196,7 +196,7 @@ def ordered_items(event_dict: EventDict) -> list[tuple[str, Any]]: def ordered_items(event_dict: EventDict) -> list[tuple[str, Any]]: items = [] - for key in key_order: # type: ignore + for key in key_order: # type: ignore[union-attr] value = event_dict.pop(key, None) if value is not None or not drop_missing: items.append((key, value)) @@ -211,7 +211,9 @@ def ordered_items(event_dict: EventDict) -> list[tuple[str, Any]]: return sorted(event_dict.items()) else: - ordered_items = operator.methodcaller("items") # type: ignore + ordered_items = operator.methodcaller( # type: ignore[assignment] + "items" + ) return ordered_items @@ -507,7 +509,7 @@ def stamper_iso_utc(event_dict: EventDict) -> EventDict: return stamper_iso_local def stamper_fmt(event_dict: EventDict) -> EventDict: - event_dict[key] = now().strftime(fmt) # type: ignore + event_dict[key] = now().strftime(fmt) # type: ignore[arg-type] return event_dict @@ -522,9 +524,9 @@ def _figure_out_exc_info(v: Any) -> ExcInfo: if isinstance(v, BaseException): return (v.__class__, v, v.__traceback__) elif isinstance(v, tuple): - return v # type: ignore + return v # type: ignore[return-value] elif v: - return sys.exc_info() # type: ignore + return sys.exc_info() # type: ignore[return-value] return v diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 49f015d5..2564b531 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -77,7 +77,7 @@ def recreate_defaults(*, log_level: int | None = logging.NOTSET) -> None: format="%(message)s", stream=sys.stdout, level=log_level, - **kw, # type: ignore + **kw, # type: ignore[arg-type] ) _config.reset_defaults() @@ -145,7 +145,7 @@ def bind(self, **new_values: Any) -> BoundLogger: """ Return a new logger with *new_values* added to the existing ones. """ - return super().bind(**new_values) # type: ignore + return super().bind(**new_values) # type: ignore[return-value] def unbind(self, *keys: str) -> BoundLogger: """ @@ -153,7 +153,7 @@ def unbind(self, *keys: str) -> BoundLogger: :raises KeyError: If the key is not part of the context. """ - return super().unbind(*keys) # type: ignore + return super().unbind(*keys) # type: ignore[return-value] def try_unbind(self, *keys: str) -> BoundLogger: """ @@ -161,7 +161,7 @@ def try_unbind(self, *keys: str) -> BoundLogger: .. versionadded:: 18.2.0 """ - return super().try_unbind(*keys) # type: ignore + return super().try_unbind(*keys) # type: ignore[return-value] def new(self, **new_values: Any) -> BoundLogger: """ @@ -171,7 +171,7 @@ def new(self, **new_values: Any) -> BoundLogger: those wrapped by `structlog.threadlocal.wrap_dict` when threads are re-used. """ - return super().new(**new_values) # type: ignore + return super().new(**new_values) # type: ignore[return-value] def debug(self, event: str | None = None, *args: Any, **kw: Any) -> Any: """ @@ -447,7 +447,7 @@ def __init__( # we're a BindableLogger. # Instances would've been correctly recognized as such, however the class # not and we need the class in `structlog.configure()`. - @property # type: ignore + @property # type: ignore[no-redef] def _context(self) -> Context: return self.sync_bl._context @@ -456,7 +456,7 @@ def bind(self, **new_values: Any) -> AsyncBoundLogger: # logger, processors and context are within sync_bl. These # arguments are ignored if _sync_bl is passed. *vroom vroom* over # purity. - logger=None, # type: ignore + logger=None, # type: ignore[arg-type] processors=(), context={}, _sync_bl=self.sync_bl.bind(**new_values), @@ -466,7 +466,7 @@ def bind(self, **new_values: Any) -> AsyncBoundLogger: def new(self, **new_values: Any) -> AsyncBoundLogger: return AsyncBoundLogger( # c.f. comment in bind - logger=None, # type: ignore + logger=None, # type: ignore[arg-type] processors=(), context={}, _sync_bl=self.sync_bl.new(**new_values), @@ -476,7 +476,7 @@ def new(self, **new_values: Any) -> AsyncBoundLogger: def unbind(self, *keys: str) -> AsyncBoundLogger: return AsyncBoundLogger( # c.f. comment in bind - logger=None, # type: ignore + logger=None, # type: ignore[arg-type] processors=(), context={}, _sync_bl=self.sync_bl.unbind(*keys), @@ -486,7 +486,7 @@ def unbind(self, *keys: str) -> AsyncBoundLogger: def try_unbind(self, *keys: str) -> AsyncBoundLogger: return AsyncBoundLogger( # c.f. comment in bind - logger=None, # type: ignore + logger=None, # type: ignore[arg-type] processors=(), context={}, _sync_bl=self.sync_bl.try_unbind(*keys), @@ -875,7 +875,7 @@ def __init__( **kwargs: Any, ) -> None: fmt = kwargs.pop("fmt", "%(message)s") - super().__init__(*args, fmt=fmt, **kwargs) # type: ignore + super().__init__(*args, fmt=fmt, **kwargs) # type: ignore[misc] if processor and processors: raise TypeError( @@ -917,12 +917,12 @@ def format(self, record: logging.LogRecord) -> str: # Both attached by wrap_for_formatter if self.logger is not None: logger = self.logger - meth_name = record._name # type: ignore + meth_name = record._name # type: ignore[attr-defined] # We need to copy because it's possible that the same record gets # processed by multiple logging formatters. LogRecord.getMessage # would transform our dict into a str. - ed = record.msg.copy() # type: ignore + ed = record.msg.copy() # type: ignore[attr-defined] ed["_record"] = record ed["_from_structlog"] = True else: diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index 09b05c94..2ecd8621 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -53,7 +53,9 @@ def _deprecated() -> None: callsite = "" try: f = sys._getframe() - callsite = f.f_back.f_back.f_globals["__name__"] # type: ignore + callsite = f.f_back.f_back.f_globals[ # type: ignore[union-attr] + "__name__" + ] except Exception: # pragma: no cover pass @@ -90,8 +92,8 @@ def wrap_dict(dict_class: type[Context]) -> type[Context]: Wrapped = type( "WrappedDict-" + str(uuid.uuid4()), (_ThreadLocalDictWrapper,), {} ) - Wrapped._tl = ThreadLocal() # type: ignore - Wrapped._dict_class = dict_class # type: ignore + Wrapped._tl = ThreadLocal() # type: ignore[attr-defined] + Wrapped._dict_class = dict_class # type: ignore[attr-defined] return Wrapped @@ -112,15 +114,15 @@ def as_immutable(logger: TLLogger) -> TLLogger: """ _deprecated() if isinstance(logger, BoundLoggerLazyProxy): - logger = logger.bind() # type: ignore + logger = logger.bind() # type: ignore[assignment] try: - ctx = logger._context._tl.dict_.__class__( # type: ignore - logger._context._dict # type: ignore + ctx = logger._context._tl.dict_.__class__( # type: ignore[union-attr] + logger._context._dict # type: ignore[union-attr] ) bl = logger.__class__( - logger._logger, # type: ignore - processors=logger._processors, # type: ignore + logger._logger, # type: ignore[attr-defined, call-arg] + processors=logger._processors, # type: ignore[attr-defined] context={}, ) bl._context = ctx @@ -145,7 +147,7 @@ def tmp_bind( _deprecated() saved = as_immutable(logger)._context try: - yield logger.bind(**tmp_values) # type: ignore + yield logger.bind(**tmp_values) # type: ignore[misc] finally: logger._context.clear() logger._context.update(saved) diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index 5fc9dad2..a390ba2a 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -108,12 +108,12 @@ def _extractStuffAndWhy(eventDict: EventDict) -> tuple[Any, Any, EventDict]: _why = event if not _stuff and sys.exc_info() != (None, None, None): - _stuff = Failure() # type: ignore + _stuff = Failure() # type: ignore[no-untyped-call] # Either we used the error ourselves or the user supplied one for # formatting. Avoid log.err() to dump another traceback into the log. if isinstance(_stuff, BaseException) and not isinstance(_stuff, Failure): - _stuff = Failure(_stuff) # type: ignore + _stuff = Failure(_stuff) # type: ignore[no-untyped-call] return _stuff, _why, eventDict @@ -170,7 +170,7 @@ class JSONRenderer(GenericJSONRenderer): `plainJSONStdOutLogger` for pure-JSON logs. """ - def __call__( # type: ignore + def __call__( # type: ignore[override] self, logger: WrappedLogger, name: str, @@ -181,13 +181,13 @@ def __call__( # type: ignore eventDict["event"] = _why if isinstance(_stuff, Failure): eventDict["exception"] = _stuff.getTraceback(detail="verbose") - _stuff.cleanFailure() # type: ignore + _stuff.cleanFailure() # type: ignore[no-untyped-call] else: eventDict["event"] = _why return ( ( ReprWrapper( - GenericJSONRenderer.__call__( # type: ignore + GenericJSONRenderer.__call__( # type: ignore[arg-type] self, logger, name, eventDict ) ), @@ -215,7 +215,9 @@ def __init__(self, file: TextIO) -> None: def __call__(self, eventDict: EventDict) -> None: until_not_interrupted( - self._write, textFromEventDict(eventDict) + "\n" # type: ignore + self._write, + textFromEventDict(eventDict) # type: ignore[arg-type, operator] + + "\n", ) until_not_interrupted(self._flush) @@ -241,7 +243,9 @@ def __call__(self, eventDict: EventDict) -> str: eventDict["message"] = ( json.dumps( { - "event": textFromEventDict(eventDict), # type: ignore + "event": textFromEventDict( + eventDict # type: ignore[arg-type] + ), "system": eventDict.get("system"), } ), diff --git a/src/structlog/types.py b/src/structlog/types.py index 01f06d81..adc840c7 100644 --- a/src/structlog/types.py +++ b/src/structlog/types.py @@ -31,9 +31,6 @@ ) -# This construct works better with Mypy. -# Doing the obvious ImportError route leads to an 'Incompatible import of -# "Protocol"' error. if sys.version_info >= (3, 8): from typing import Protocol, runtime_checkable else: diff --git a/tox.ini b/tox.ini index df06c4e6..adb22da3 100644 --- a/tox.ini +++ b/tox.ini @@ -6,9 +6,9 @@ ignore = E203,W503,W504 [gh-actions] python = 3.7: py37 # mypy on 3.7 fails but there's nothing we can do about it - 3.8: py38, mypy - 3.9: py39, mypy - 3.10: py310, mypy, docs + 3.8: py38 + 3.9: py39 + 3.10: py310 3.11: py311 @@ -18,7 +18,7 @@ isolated_build = True [testenv:docs] -# Keep basepython in sync with gh-actions and .readthedocs.yml. +# Keep basepython in sync with ci.yml/docs and .readthedocs.yml. basepython = python3.10 extras = docs passenv = TERM From a97e44510b4f7bab63dfe3d21461730d5d8b8d2f Mon Sep 17 00:00:00 2001 From: Step Security Bot Date: Thu, 29 Sep 2022 01:50:08 -0700 Subject: [PATCH 0766/1520] [StepSecurity] ci: Harden GitHub Actions (#445) * [StepSecurity] ci: Harden GitHub Actions in build-docset.yml * [StepSecurity] ci: Harden GitHub Actions in ci.yml * [StepSecurity] ci: Harden GitHub Actions in codeql-analysis.yml Co-authored-by: Hynek Schlawack --- .github/workflows/build-docset.yml | 8 ++++++++ .github/workflows/ci.yml | 20 ++++++++++++++++++++ .github/workflows/codeql-analysis.yml | 8 ++++++++ 3 files changed, 36 insertions(+) diff --git a/.github/workflows/build-docset.yml b/.github/workflows/build-docset.yml index 609f7196..7f8e660f 100644 --- a/.github/workflows/build-docset.yml +++ b/.github/workflows/build-docset.yml @@ -10,10 +10,18 @@ env: PIP_DISABLE_PIP_VERSION_CHECK: 1 PIP_NO_PYTHON_VERSION_WARNING: 1 +permissions: # added using https://github.com/step-security/secure-workflows + contents: read + jobs: docset: runs-on: ubuntu-latest steps: + - name: Harden Runner + uses: step-security/harden-runner@v1 + with: + egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs + - uses: actions/checkout@v3 with: fetch-depth: 0 # get correct version diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bc2e7905..7e84864f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,6 +31,11 @@ jobs: - "~3.11.0-0" steps: + - name: Harden Runner + uses: step-security/harden-runner@v1 + with: + egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs + - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: @@ -52,6 +57,11 @@ jobs: needs: tests steps: + - name: Harden Runner + uses: step-security/harden-runner@v1 + with: + egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs + - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: @@ -117,6 +127,11 @@ jobs: SETUPTOOLS_SCM_PRETEND_VERSION: "" steps: + - name: Harden Runner + uses: step-security/harden-runner@v1 + with: + egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs + - uses: actions/checkout@v3 with: fetch-depth: 0 # get correct version @@ -132,6 +147,11 @@ jobs: os: [ubuntu-latest, windows-latest] steps: + - name: Harden Runner + uses: step-security/harden-runner@v1 + with: + egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs + - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 66958308..d2cba807 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -20,6 +20,9 @@ on: schedule: - cron: '41 3 * * 6' +permissions: # added using https://github.com/step-security/secure-workflows + contents: read + jobs: analyze: name: Analyze @@ -37,6 +40,11 @@ jobs: # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support steps: + - name: Harden Runner + uses: step-security/harden-runner@v1 + with: + egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs + - name: Checkout repository uses: actions/checkout@v3 From 12a8898925fe011ce5d1b3d1f25e2d97526cf140 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 29 Sep 2022 11:02:13 +0200 Subject: [PATCH 0767/1520] Block CI egress (#448) --- .github/workflows/ci.yml | 29 +++++++-- .github/workflows/codeql-analysis.yml | 86 +++++++++------------------ 2 files changed, 54 insertions(+), 61 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7e84864f..118b8aa9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,6 +16,9 @@ env: SETUPTOOLS_SCM_PRETEND_VERSION: "1.0" # avoid warnings about shallow checkout PYTHON_LATEST: "3.10" +permissions: + contents: read + jobs: tests: name: tox on ${{ matrix.python-version }} @@ -34,7 +37,13 @@ jobs: - name: Harden Runner uses: step-security/harden-runner@v1 with: - egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs + egress-policy: block + allowed-endpoints: > + api.github.com:443 + files.pythonhosted.org:443 + github.com:443 + objects.githubusercontent.com:443 + pypi.org:443 - uses: actions/checkout@v3 - uses: actions/setup-python@v4 @@ -60,7 +69,11 @@ jobs: - name: Harden Runner uses: step-security/harden-runner@v1 with: - egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs + egress-policy: block + allowed-endpoints: > + files.pythonhosted.org:443 + github.com:443 + pypi.org:443 - uses: actions/checkout@v3 - uses: actions/setup-python@v4 @@ -130,7 +143,11 @@ jobs: - name: Harden Runner uses: step-security/harden-runner@v1 with: - egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs + egress-policy: block + allowed-endpoints: > + files.pythonhosted.org:443 + github.com:443 + pypi.org:443 - uses: actions/checkout@v3 with: @@ -150,7 +167,11 @@ jobs: - name: Harden Runner uses: step-security/harden-runner@v1 with: - egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs + egress-policy: block + allowed-endpoints: > + files.pythonhosted.org:443 + github.com:443 + pypi.org:443 - uses: actions/checkout@v3 - uses: actions/setup-python@v4 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index d2cba807..dc28ba5a 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,26 +1,14 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# name: "CodeQL" on: push: - branches: [ "main" ] + branches: ["main"] pull_request: - # The branches below must be a subset of the branches above - branches: [ "main" ] + branches: ["main"] schedule: - - cron: '41 3 * * 6' + - cron: "41 3 * * 6" -permissions: # added using https://github.com/step-security/secure-workflows +permissions: contents: read jobs: @@ -35,46 +23,30 @@ jobs: strategy: fail-fast: false matrix: - language: [ 'python' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] - # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + language: ["python"] steps: - - name: Harden Runner - uses: step-security/harden-runner@v1 - with: - egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - - name: Checkout repository - uses: actions/checkout@v3 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - - # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs - # queries: security-extended,security-and-quality - - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v2 - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - # If the Autobuild fails above, remove it and uncomment the following three lines. - # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. - - # - run: | - # echo "Run, Build Application using script" - # ./location_of_script_within_repo/buildscript.sh - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + - name: Harden Runner + uses: step-security/harden-runner@v1 + with: + egress-policy: block + allowed-endpoints: > + api.github.com:443 + bootstrap.pypa.io:443 + files.pythonhosted.org:443 + github.com:443 + pypi.org:443 + + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 From 2205ff9543f868191b9f8cdb4befe9f14fba2b5a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 4 Oct 2022 08:41:36 +0200 Subject: [PATCH 0768/1520] [pre-commit.ci] pre-commit autoupdate (#452) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v2.38.0 → v2.38.2](https://github.com/asottile/pyupgrade/compare/v2.38.0...v2.38.2) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 83d2826b..96d5a6df 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,7 +12,7 @@ repos: - id: black - repo: https://github.com/asottile/pyupgrade - rev: v2.38.0 + rev: v2.38.2 hooks: - id: pyupgrade args: [--py37-plus] From 6ec42844340787cbeb952202d0947b561a3b2cfc Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Tue, 4 Oct 2022 09:20:19 +0200 Subject: [PATCH 0769/1520] Fix typo on `why.rst` (#449) Co-authored-by: Hynek Schlawack --- docs/why.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/why.rst b/docs/why.rst index 3856af8e..48ea1c53 100644 --- a/docs/why.rst +++ b/docs/why.rst @@ -98,7 +98,7 @@ Output Or the other way round: ``structlog`` comes with a ``logging`` formatter that allows for processing third party log records. - Don't format it to a string at all! ``structlog`` passes you a dictionary and you can do with it whatever you want. - Reported uses cases are sending them out via network or saving them in a database. + Reported use cases are sending them out via network or saving them in a database. Highly Testable From e77c4f187fff120d581cfc27ca6176e532aa54ac Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Thu, 6 Oct 2022 10:44:20 +0200 Subject: [PATCH 0770/1520] Update getting-started.rst (#451) * Update getting-started.rst * Update docs/getting-started.rst Co-authored-by: Hynek Schlawack --- docs/getting-started.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 0273a5e2..5684d405 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -158,7 +158,7 @@ Finally you want to have control over the actual format of your log entries. As you may have noticed in the previous section, renderers are just processors too. It's also important to note, that they do not necessarily have to render your event dictionary to a string. -It depends on the *logger* that is wrapped by ``structlog`` what kind of input it should get. +The output that is required from the renderer depends on the input that the *logger* that is wrapped by ``structlog`` needs. However, in most cases it's gonna be strings. From d6bc544d14cbd70cce84518bb92ef20e552a0e42 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Thu, 6 Oct 2022 10:59:50 +0200 Subject: [PATCH 0771/1520] Update getting-started.rst (#450) * Update getting-started.rst * Update docs/getting-started.rst Co-authored-by: Hynek Schlawack --- docs/getting-started.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 5684d405..9f0d7764 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -90,9 +90,7 @@ Imagine a hypothetical web application that wants to log out all relevant data w :language: python The calls themselves are nice and straight to the point, however you're repeating yourself all over the place. -At this point, you'll be tempted to write a closure like - -:: +At this point, you'll be tempted to write a closure like:: def log_closure(event): log.info(event, user_agent=user_agent, peer_ip=peer_ip) From fb9237b19ce431d8bf5d44b60b2b888212c54d1e Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Thu, 6 Oct 2022 11:17:06 +0200 Subject: [PATCH 0772/1520] Update contextvars.rst (#453) * Update contextvars.rst * Update docs/contextvars.rst Co-authored-by: Hynek Schlawack --- docs/contextvars.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contextvars.rst b/docs/contextvars.rst index b14dc321..2f0a0117 100644 --- a/docs/contextvars.rst +++ b/docs/contextvars.rst @@ -30,7 +30,7 @@ The general flow is: Loggers act as they always do, but the `structlog.contextvars.merge_contextvars` processor ensures that any context-local binds get included in all of your log messages. - If you want to access the context-local storage, you use `structlog.contextvars.get_contextvars` and `structlog.contextvars.get_merged_contextvars`. -We're sorry the word *context* means three different things in this itemization depending on...context. +We're sorry the word *context* means three different things in this itemization depending on ... context. .. doctest:: From 18644a6784659926185d34f56abae6f29bede20d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 6 Oct 2022 18:11:54 +0200 Subject: [PATCH 0773/1520] We're better than this --- pyproject.toml | 6 ------ setup.py | 31 ------------------------------- 2 files changed, 37 deletions(-) delete mode 100644 setup.py diff --git a/pyproject.toml b/pyproject.toml index 73f58691..0a97c76e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,12 +75,6 @@ source = "vcs" raw-options = { version_scheme = "no-guess-dev" } -[tool.hatch.build] -# Just a fake stub to make GitHub recognize us. -# See the file for details. -exclude = ["setup.py"] - - [tool.pytest.ini_options] addopts = ["-ra", "--strict-markers", "--strict-config"] testpaths = "tests" diff --git a/setup.py b/setup.py deleted file mode 100644 index bc5545d2..00000000 --- a/setup.py +++ /dev/null @@ -1,31 +0,0 @@ -import sys - -from setuptools import setup - - -sys.stderr.write( - """ -=============================== -Unsupported installation method -=============================== - -structlog no longer supports installation with `python setup.py install`. -Please use `python -m pip install .` instead. -""" -) -sys.exit(1) - - -# The below code will never execute, however GitHub is particularly -# picky about where it finds Python packaging metadata. -# See: https://github.com/github/feedback/discussions/6456 -# -# To be removed once GitHub catches up. - -setup( - name="structlog", - install_requires=[ - "typing-extensions; python_version<'3.8'", - "importlib_metadata; python_version<'3.8'", - ], -) From 6ada4b2e31c18cb9db551fa95ad71c8f3963a757 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 7 Oct 2022 15:11:27 +0200 Subject: [PATCH 0774/1520] Move conftest out of the way --- pyproject.toml | 5 ----- conftest.py => tests/conftest.py | 5 ----- tests/test_twisted.py | 33 +++++++++++++++++++------------- 3 files changed, 20 insertions(+), 23 deletions(-) rename conftest.py => tests/conftest.py (93%) diff --git a/pyproject.toml b/pyproject.toml index 0a97c76e..049df9ba 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -127,7 +127,6 @@ strict = true show_error_codes = true enable_error_code = ["ignore-without-code"] -follow_imports = "normal" ignore_missing_imports = true warn_return_any = false @@ -137,10 +136,6 @@ warn_return_any = false module = "tests.*" ignore_errors = true -[[tool.mypy.overrides]] -module = "conftest.*" -ignore_errors = true - [tool.hatch.metadata.hooks.fancy-pypi-readme] content-type = "text/markdown" diff --git a/conftest.py b/tests/conftest.py similarity index 93% rename from conftest.py rename to tests/conftest.py index 10cb5834..ae66a011 100644 --- a/conftest.py +++ b/tests/conftest.py @@ -65,8 +65,3 @@ def _stdlib_log_methods(request): @pytest.fixture(name="cl") def _cl(): return CapturingLogger() - - -collect_ignore = [] -if twisted is None: - collect_ignore.append("tests/test_twisted.py") diff --git a/tests/test_twisted.py b/tests/test_twisted.py index b171472f..5b930319 100644 --- a/tests/test_twisted.py +++ b/tests/test_twisted.py @@ -8,23 +8,30 @@ import pytest from pretend import call_recorder -from twisted.python.failure import Failure -from twisted.python.log import ILogObserver from structlog import ReturnLogger from structlog._config import _CONFIG from structlog.processors import KeyValueRenderer -from structlog.twisted import ( - BoundLogger, - EventAdapter, - JSONLogObserverWrapper, - JSONRenderer, - LoggerFactory, - PlainFileLogObserver, - ReprWrapper, - _extractStuffAndWhy, - plainJSONStdOutLogger, -) + + +try: + from twisted.python.failure import Failure + from twisted.python.log import ILogObserver + + from structlog.twisted import ( + BoundLogger, + EventAdapter, + JSONLogObserverWrapper, + JSONRenderer, + LoggerFactory, + PlainFileLogObserver, + ReprWrapper, + _extractStuffAndWhy, + plainJSONStdOutLogger, + ) + +except ImportError: + pytest.skip(allow_module_level=True) def test_LoggerFactory(): From 193e8ee3a775a29d2c075f698acaccc8c438782e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 7 Oct 2022 15:47:46 +0200 Subject: [PATCH 0775/1520] Add changelog entry for package metadata deprecation --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d12d8e9e..a8550ee6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,12 @@ So please make sure to **always** properly configure your applications. ## [Unreleased](https://github.com/hynek/structlog/compare/22.1.0...HEAD) +### Deprecated + +- Accessing package metadata as attributes on the `structlog` module is deprecated (e.g. `structlog.__version__`). + Please use [`importlib.metadata`](https://docs.python.org/3.10/library/importlib.metadata.html) instead (for Python 3.7: the [*importlib-metadata*](https://pypi.org/project/importlib-metadata/) PyPI package). + + ### Changed - The build backend has been switched to [*Hatch*](https://hatch.pypa.io/). From db09d30edc28101344c31f9f1e33ac4ec786045e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 7 Oct 2022 16:23:59 +0200 Subject: [PATCH 0776/1520] Add OpenSSF badge --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 3724fe12..c35f7e50 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,9 @@ License: MIT / Apache 2.0 + + + PyPI release From 742ed69a32c516230a803bcadd0218dad1a2ddc1 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 7 Oct 2022 17:02:04 +0200 Subject: [PATCH 0777/1520] Simplify credits --- AUTHORS.md | 9 --------- README.md | 14 +++++++++++++- docs/index.rst | 2 +- docs/license.md | 7 ++++++- pyproject.toml | 17 ++++++----------- 5 files changed, 26 insertions(+), 23 deletions(-) delete mode 100644 AUTHORS.md diff --git a/AUTHORS.md b/AUTHORS.md deleted file mode 100644 index de7354fa..00000000 --- a/AUTHORS.md +++ /dev/null @@ -1,9 +0,0 @@ -# Authors - -`structlog` is written and maintained by [Hynek Schlawack](https://hynek.me/). It’s inspired by previous work by [Jean-Paul Calderone](https://github.com/exarkun) and [David Reid](https://github.com/dreid). - -The development is kindly supported by my employer [Variomedia AG](https://www.variomedia.de/), ``structlog`` [Tidelift subscribers](https://tidelift.com/subscription/pkg/pypi-structlog?utm_source=pypi-structlog&utm_medium=referral&utm_campaign=enterprise&utm_term=repo), and all my amazing [GitHub Sponsors](https://github.com/sponsors/hynek). - -A full list of contributors can be found on GitHub’s [overview](https://github.com/hynek/structlog/graphs/contributors). - -The `structlog` logo has been contributed by [Russell Keith-Magee](https://github.com/freakboy3742). diff --git a/README.md b/README.md index c35f7e50..b8f6f12b 100644 --- a/README.md +++ b/README.md @@ -43,11 +43,23 @@ Once you feel inspired to try it out, check out our friendly [Getting Started tu If you prefer videos over reading, check out [Markus Holtermann](https://twitter.com/m_holtermann)'s DjangoCon Europe 2019 talk: [*Logging Rethought 2: The Actions of Frank Taylor Jr.*](https://www.youtube.com/watch?v=Y5eyEgyHLLo) +## Credits + +`structlog` is written and maintained by [Hynek Schlawack](https://hynek.me/). +It’s inspired by previous work by [Jean-Paul Calderone](https://github.com/exarkun) and [David Reid](https://github.com/dreid). + +The development is kindly supported by my employer [Variomedia AG](https://www.variomedia.de/), ``structlog`` [Tidelift subscribers](https://tidelift.com/subscription/pkg/pypi-structlog), and all my amazing [GitHub Sponsors](https://github.com/sponsors/hynek). + +A full list of contributors can be found in GitHub’s [overview](https://github.com/hynek/structlog/graphs/contributors). + +The `structlog` logo has been contributed by [Russell Keith-Magee](https://github.com/freakboy3742). + + ## Project Information -- **License**: *dual* [Apache License, version 2 and MIT](https://www.structlog.org/en/stable/license.html) +- **License**: *dual* [Apache License, version 2 and MIT](https://www.structlog.org/en/latest/license.html) - **PyPI**: - **Source Code**: - **Documentation**: diff --git a/docs/index.rst b/docs/index.rst index 29cbe0cf..e64353c0 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -67,7 +67,7 @@ API Reference ============= .. toctree:: - :maxdepth: 4 + :maxdepth: 2 api diff --git a/docs/license.md b/docs/license.md index e1081459..0bac6d79 100644 --- a/docs/license.md +++ b/docs/license.md @@ -14,5 +14,10 @@ The full license texts can be also found in the source code repository: - [MIT](https://github.com/hynek/structlog/blob/main/LICENSE-MIT) -```{include} ../AUTHORS.md +## Credits + +```{include} ../README.md +:parser: myst_parser.sphinx_ +:start-after: "## Credits" +:end-before: ``` diff --git a/pyproject.toml b/pyproject.toml index 049df9ba..8eea6f7e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 [build-system] -requires = ["hatchling", "hatch-vcs", "hatch-fancy-pypi-readme"] +requires = ["hatchling", "hatch-vcs", "hatch-fancy-pypi-readme>=22.8.0"] build-backend = "hatchling.build" @@ -162,12 +162,9 @@ start-after = "\n" text = """ -## Release Information for """ +## Release Information -[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]] -path = "CHANGELOG.md" -start-after = "" -pattern = "## ([^\n]+?\n\n)###" +""" [[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]] path = "CHANGELOG.md" @@ -175,8 +172,6 @@ start-after = "" pattern = "\n(###.+?\n)## " [[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]] -text = "\n## Credits\n" - -[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]] -path = "AUTHORS.md" -start-after = "# Authors\n" +path = "README.md" +start-at = "## Credits" +end-before = "" From 7b513b84f084a53839f39a5a026fccc81bf5ad3e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 7 Oct 2022 18:54:30 +0200 Subject: [PATCH 0778/1520] Streamline docs & start MySTifying --- .../processors/conditional_dropper.py | 4 +- docs/conf.py | 5 + docs/configuration.rst | 23 -- docs/{contextvars.rst => contextvars.md} | 84 +++++-- docs/development.md | 47 ++++ docs/development.rst | 45 ---- docs/examples.md | 74 ++++++ docs/examples.rst | 117 ---------- docs/frameworks.md | 30 +++ docs/getting-started.md | 216 ++++++++++++++++++ docs/getting-started.rst | 210 ----------------- docs/index.rst | 28 ++- docs/processors.rst | 4 +- docs/types.md | 26 +++ docs/types.rst | 43 ---- 15 files changed, 486 insertions(+), 470 deletions(-) rename docs/{contextvars.rst => contextvars.md} (50%) create mode 100644 docs/development.md delete mode 100644 docs/development.rst create mode 100644 docs/examples.md delete mode 100644 docs/examples.rst create mode 100644 docs/frameworks.md create mode 100644 docs/getting-started.md delete mode 100644 docs/getting-started.rst create mode 100644 docs/types.md delete mode 100644 docs/types.rst diff --git a/docs/code_examples/processors/conditional_dropper.py b/docs/code_examples/processors/conditional_dropper.py index e22034da..255504ae 100644 --- a/docs/code_examples/processors/conditional_dropper.py +++ b/docs/code_examples/processors/conditional_dropper.py @@ -17,5 +17,5 @@ def __call__(self, logger, method_name, event_dict): """ if event_dict.get("peer") == self._peer_to_ignore: raise DropEvent - else: - return event_dict + + return event_dict diff --git a/docs/conf.py b/docs/conf.py index 3baf63eb..674ca17b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -23,6 +23,11 @@ "sphinxcontrib.mermaid", ] +myst_enable_extensions = [ + "colon_fence", + "smartquotes", +] + # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] diff --git a/docs/configuration.rst b/docs/configuration.rst index 8a38e53f..104a6a64 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -144,26 +144,3 @@ The :ref:`Twisted example ` shows how easy it is for Twisted. Calling `structlog.get_logger` without configuration gives you a perfectly useful `structlog.PrintLogger`. We don't believe silent loggers are a sensible default. - - -Where to Configure ------------------- - -The best place to perform your configuration varies with applications and frameworks. -Ideally as late as possible but *before* non-framework (i.e. your) code is executed. -If you use standard library's logging, it makes sense to configure them next to each other. - -**Django** - See `Third-Party Extensions `_ in the wiki. - -**Flask** - See `Logging `_. - -**Pyramid** - `Application constructor `_. - -**Twisted** - The `plugin definition `_ is the best place. - If your app is not a plugin, put it into your `tac file `_. - -If you have no choice but *have* to configure on import time in module-global scope, or can't rule out for other reasons that that your `structlog.configure` gets called more than once, ``structlog`` offers `structlog.configure_once` that raises a warning if ``structlog`` has been configured before (no matter whether using `structlog.configure` or :func:`~structlog.configure_once`) but doesn't change anything. diff --git a/docs/contextvars.rst b/docs/contextvars.md similarity index 50% rename from docs/contextvars.rst rename to docs/contextvars.md index 2f0a0117..a4816306 100644 --- a/docs/contextvars.rst +++ b/docs/contextvars.md @@ -1,37 +1,41 @@ -.. _contextvars: +(contextvars)= -Context Variables -================= +# Context Variables +```{eval-rst} .. testsetup:: * import structlog +``` +```{eval-rst} .. testcleanup:: * import structlog structlog.reset_defaults() +``` -The :mod:`contextvars` module in the Python standard library allows having a global ``structlog`` context that is local to the current execution context. -The execution context can be thread-local, concurrent code such as code using :mod:`asyncio`, or `greenlet `_. +The {mod}`contextvars` module in the Python standard library allows having a global `structlog` context that is local to the current execution context. +The execution context can be thread-local, concurrent code such as code using {mod}`asyncio`, or [*greenlet*](https://greenlet.readthedocs.io/). For example, you may want to bind certain values like a request ID or the peer's IP address at the beginning of a web request and have them logged out along with the local contexts you build within our views. -For that ``structlog`` provides the `structlog.contextvars` module with a set of functions to bind variables to a context-local context. +For that `structlog` provides the `structlog.contextvars` module with a set of functions to bind variables to a context-local context. This context is safe to be used both in threaded as well as asynchronous code. The general flow is: - Use `structlog.configure` with `structlog.contextvars.merge_contextvars` as your first processor. - Call `structlog.contextvars.clear_contextvars` at the beginning of your request handler (or whenever you want to reset the context-local context). -- Call `structlog.contextvars.bind_contextvars` and `structlog.contextvars.unbind_contextvars` instead of your bound logger's ``bind()`` and ``unbind()`` when you want to bind and unbind key-value pairs to the context-local context. +- Call `structlog.contextvars.bind_contextvars` and `structlog.contextvars.unbind_contextvars` instead of your bound logger's `bind()` and `unbind()` when you want to bind and unbind key-value pairs to the context-local context. You can also use the `structlog.contextvars.bound_contextvars` context manager/decorator. -- Use ``structlog`` as normal. +- Use `structlog` as normal. Loggers act as they always do, but the `structlog.contextvars.merge_contextvars` processor ensures that any context-local binds get included in all of your log messages. - If you want to access the context-local storage, you use `structlog.contextvars.get_contextvars` and `structlog.contextvars.get_merged_contextvars`. We're sorry the word *context* means three different things in this itemization depending on ... context. +```{eval-rst} .. doctest:: >>> from structlog.contextvars import ( @@ -77,20 +81,60 @@ We're sorry the word *context* means three different things in this itemization >>> log.info("hi there") event='hi there' a=None +``` -Support for contextvars.Token ------------------------------ +## Support for `contextvars.Token` -If e.g. your request handler calls a helper function that needs to temporarily override some contextvars before restoring them back to their original values, you can use the :class:`~contextvars.Token`\s returned by :func:`~structlog.contextvars.bind_contextvars` along with :func:`~structlog.contextvars.reset_contextvars` to accomplish this (much like how :meth:`contextvars.ContextVar.reset` works): +If e.g. your request handler calls a helper function that needs to temporarily override some contextvars before restoring them back to their original values, you can use the {class}`~contextvars.Token`s returned by {func}`~structlog.contextvars.bind_contextvars` along with {func}`~structlog.contextvars.reset_contextvars` to accomplish this (much like how {meth}`contextvars.ContextVar.reset` works): -.. code-block:: python +```python +def foo(): + bind_contextvars(a=1) + _helper() + log.info("a is restored!") # a=1 - def foo(): - bind_contextvars(a=1) - _helper() - log.info("a is restored!") # a=1 +def _helper(): + tokens = bind_contextvars(a=2) + log.info("a is overridden") # a=2 + reset_contextvars(**tokens) +``` - def _helper(): - tokens = bind_contextvars(a=2) - log.info("a is overridden") # a=2 - reset_contextvars(**tokens) +(flask-example)= + +## Example: Flask and Thread-Local Data + +Let's assume you want to bind a unique request ID, the URL path, and the peer's IP to every log entry by storing it in thread-local storage that is managed by context variables: + +```{literalinclude} code_examples/flask_/webapp.py +:language: python +``` + +`some_module.py` + +```{literalinclude} code_examples/flask_/some_module.py +:language: python +``` + +This would result among other the following lines to be printed: + +```text +event='user logged in' view='/login' peer='127.0.0.1' user='test-user' request_id='e08ddf0d-23a5-47ce-b20e-73ab8877d736' +event='user did something' view='/login' peer='127.0.0.1' something='shot_in_foot' request_id='e08ddf0d-23a5-47ce-b20e-73ab8877d736' +``` + +As you can see, `view`, `peer`, and `request_id` are present in **both** log entries. + +While wrapped loggers are *immutable* by default, this example demonstrates how to circumvent that using a thread-local storage for request-wide context: + +1. `structlog.contextvars.clear_contextvars()` ensures the thread-local storage is empty for each request. +2. `structlog.contextvars.bind_contextvars()` puts your key-value pairs into thread-local storage. +3. The `structlog.contextvars.merge_contextvars()` processor merges the thread-local context into the event dict. + +Please note that the `user` field is only present in the view because it wasn't bound into the thread-local storage. +See {doc}`contextvars` for more details. + +___ + +`structlog.stdlib.LoggerFactory` is a totally magic-free class that just deduces the name of the caller's module and does a `logging.getLogger` with it. +It's used by `structlog.get_logger` to rid you of logging boilerplate in application code. +If you prefer to name your standard library loggers explicitly, a positional argument to `structlog.get_logger` gets passed to the factory and used as the name. diff --git a/docs/development.md b/docs/development.md new file mode 100644 index 00000000..2bdc5966 --- /dev/null +++ b/docs/development.md @@ -0,0 +1,47 @@ +# Development + +To make development a more pleasurable experience, `structlog` comes with the {mod}`structlog.dev` module. + +The highlight is {class}`structlog.dev.ConsoleRenderer` that offers nicely aligned and colorful[^win] console output. + +[^win]: Requires the [*colorama* package](https://pypi.org/project/colorama/) on Windows. + +If either of the [*rich*](https://rich.readthedocs.io/) or [*better-exceptions*](https://github.com/Qix-/better-exceptions) packages is installed, it will also pretty-print exceptions with helpful contextual data. +*rich* takes precedence over *better-exceptions*, but you can configure it by passing {func}`structlog.dev.plain_traceback` or {func}`structlog.dev.better_traceback` for the `exception_formatter` parameter of {class}`~structlog.dev.ConsoleRenderer`. + +The following output is rendered using *rich*: + +```{figure} _static/console_renderer.png +Colorful console output by ConsoleRenderer. +``` + +You can find the code for the output above [in the repo](https://github.com/hynek/structlog/blob/main/show_off.py). + +To use it, just add it as a renderer to your processor chain. +It will recognize logger names, log levels, time stamps, stack infos, and `exc_info` as produced by `structlog`'s processors and render them in special ways. + +:::{warning} +For pretty exceptions to work, {func}`~structlog.processors.format_exc_info` must be **absent** from the processors chain. +::: + +`structlog`'s default configuration already uses {class}`~structlog.dev.ConsoleRenderer`, therefore if you want nice colorful output on the console, you don't have to do anything except installing *colorama* and *better-exceptions*. +If you want to use it along with standard library logging, we suggest the following configuration: + +```python +import structlog + +structlog.configure( + processors=[ + structlog.stdlib.add_logger_name, + structlog.stdlib.add_log_level, + structlog.stdlib.PositionalArgumentsFormatter(), + structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M.%S"), + structlog.processors.StackInfoRenderer(), + structlog.dev.ConsoleRenderer() # <=== + ], + context_class=dict, + logger_factory=structlog.stdlib.LoggerFactory(), + wrapper_class=structlog.stdlib.BoundLogger, + cache_logger_on_first_use=True, +) +``` diff --git a/docs/development.rst b/docs/development.rst deleted file mode 100644 index 7ff65a0b..00000000 --- a/docs/development.rst +++ /dev/null @@ -1,45 +0,0 @@ -Development -=========== - -To make development a more pleasurable experience, ``structlog`` comes with the `structlog.dev` module. - -The highlight is `structlog.dev.ConsoleRenderer` that offers nicely aligned and colorful (requires the `colorama package `_ if on Windows) console output. - -If one of the `rich `_ or `better-exceptions `_ packages is installed, it will also pretty-print exceptions with helpful contextual data. -``rich`` takes precedence over ``better-exceptions``, but you can configure it by passing `structlog.dev.plain_traceback` or `structlog.dev.better_traceback` for the ``exception_formatter`` parameter of `ConsoleRenderer`. - -The following output is rendered using ``rich``: - -.. figure:: _static/console_renderer.png - :alt: Colorful console output by ConsoleRenderer. - -You can find the code for the output above `in the repo `_. - -To use it, just add it as a renderer to your processor chain. -It will recognize logger names, log levels, time stamps, stack infos, and ``exc_info`` as produced by ``structlog``'s processors and render them in special ways. - -.. warning:: - - For pretty exceptions to work, `format_exc_info` must be **absent** from the processors chain. - -``structlog``'s default configuration already uses `ConsoleRenderer`, therefore if you want nice colorful output on the console, you don't have to do anything except installing *colorama* and *better-exceptions*. -If you want to use it along with standard library logging, we suggest the following configuration: - -.. code-block:: python - - import structlog - - structlog.configure( - processors=[ - structlog.stdlib.add_logger_name, - structlog.stdlib.add_log_level, - structlog.stdlib.PositionalArgumentsFormatter(), - structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M.%S"), - structlog.processors.StackInfoRenderer(), - structlog.dev.ConsoleRenderer() # <=== - ], - context_class=dict, - logger_factory=structlog.stdlib.LoggerFactory(), - wrapper_class=structlog.stdlib.BoundLogger, - cache_logger_on_first_use=True, - ) diff --git a/docs/examples.md b/docs/examples.md new file mode 100644 index 00000000..ab9a2921 --- /dev/null +++ b/docs/examples.md @@ -0,0 +1,74 @@ +# Examples + +This chapter is intended to give you a taste of realistic usage of `structlog`. + +(processors-examples)= + +## Processors + +{doc}`processors` are a both simple and powerful feature of `structlog`. + +The following example demonstrates how easy it is to add timestamps, censor passwords, filter out log entries below your log level before they even get rendered, and get your output as JSON for convenient parsing. +It also demonstrates how to use `structlog.wrap_logger` that allows you to use `structlog` without any global configuration (a rather uncommon pattern, but can be useful): + +```{eval-rst} +.. doctest:: + + >>> import datetime, logging, sys + >>> from structlog import wrap_logger + >>> from structlog.processors import JSONRenderer + >>> from structlog.stdlib import filter_by_level + >>> logging.basicConfig(stream=sys.stdout, format="%(message)s") + >>> def add_timestamp(_, __, event_dict): + ... event_dict["timestamp"] = datetime.datetime.utcnow() + ... return event_dict + >>> def censor_password(_, __, event_dict): + ... pw = event_dict.get("password") + ... if pw: + ... event_dict["password"] = "*CENSORED*" + ... return event_dict + >>> log = wrap_logger( + ... logging.getLogger(__name__), + ... processors=[ + ... filter_by_level, + ... add_timestamp, + ... censor_password, + ... JSONRenderer(indent=1, sort_keys=True) + ... ] + ... ) + >>> log.info("something.filtered") + >>> log.warning("something.not_filtered", password="secret") # doctest: +ELLIPSIS + { + "event": "something.not_filtered", + "password": "*CENSORED*", + "timestamp": "datetime.datetime(..., ..., ..., ..., ...)" + } +``` + +`structlog` comes with many handy processors build right in, so check the {ref}`API documentation ` before you write your own. +For example, you probably don't want to write your own timestamper. + +(twisted-example)= + +## Twisted, and Logging Out Objects + +If you prefer to log less but with more context in each entry, you can bind everything important to your logger and log it out with each log entry. + +```{literalinclude} code_examples/twisted_echo.py +:language: python +``` + +gives you something like: + +```text +... peer='127.0.0.1' connection_id='1c6c0cb5-...' count=1 data='123\n' event='echoed data!' +... peer='127.0.0.1' connection_id='1c6c0cb5-...' count=2 data='456\n' event='echoed data!' +... peer='127.0.0.1' connection_id='1c6c0cb5-...' count=3 data='foo\n' event='echoed data!' +... peer='10.10.0.1' connection_id='85234511-...' count=1 data='cba\n' event='echoed data!' +... peer='127.0.0.1' connection_id='1c6c0cb5-...' count=4 data='bar\n' event='echoed data!' +``` + +Since Twisted's logging system is a bit peculiar, `structlog` ships with an {class}`adapter ` so it keeps behaving like you'd expect it to behave. + +I'd also like to point out the Counter class that doesn't do anything spectacular but gets bound *once* per connection to the logger and since its repr is the number itself, it's logged out correctly for each event. +This shows off the strength of keeping a dict of objects for context instead of passing around serialized strings. diff --git a/docs/examples.rst b/docs/examples.rst deleted file mode 100644 index d7f2afe4..00000000 --- a/docs/examples.rst +++ /dev/null @@ -1,117 +0,0 @@ -Examples -======== - -This chapter is intended to give you a taste of realistic usage of ``structlog``. - - -.. _flask-example: - -Flask and Thread-Local Data ---------------------------- - -Let's assume you want to bind a unique request ID, the URL path, and the peer's IP to every log entry by storing it in thread-local storage that is managed by context variables: - -.. literalinclude:: code_examples/flask_/webapp.py - :language: python - -``some_module.py`` - -.. literalinclude:: code_examples/flask_/some_module.py - :language: python - -This would result among other the following lines to be printed: - -.. code:: text - - event='user logged in' view='/login' peer='127.0.0.1' user='test-user' request_id='e08ddf0d-23a5-47ce-b20e-73ab8877d736' - event='user did something' view='/login' peer='127.0.0.1' something='shot_in_foot' request_id='e08ddf0d-23a5-47ce-b20e-73ab8877d736' - -As you can see, ``view``, ``peer``, and ``request_id`` are present in **both** log entries. - -While wrapped loggers are *immutable* by default, this example demonstrates how to circumvent that using a thread-local storage for request-wide context: - -1. `structlog.contextvars.clear_contextvars()` ensures the thread-local storage is empty for each request. -2. `structlog.contextvars.bind_contextvars()` puts your key-value pairs into thread-local storage. -3. The `structlog.contextvars.merge_contextvars()` processor merges the thread-local context into the event dict. - -Please note that the ``user`` field is only present in the view because it wasn't bound into the thread-local storage. -See :doc:`contextvars` for more details. - ----- - -`structlog.stdlib.LoggerFactory` is a totally magic-free class that just deduces the name of the caller's module and does a `logging.getLogger` with it. -It's used by `structlog.get_logger` to rid you of logging boilerplate in application code. -If you prefer to name your standard library loggers explicitly, a positional argument to `structlog.get_logger` gets passed to the factory and used as the name. - - -.. _processors-examples: - -Processors ----------- - -:doc:`processors` are a both simple and powerful feature of ``structlog``. - -The following example demonstrates how easy it is to add timestamps, censor passwords, filter out log entries below your log level before they even get rendered, and get your output as JSON for convenient parsing. -It also demonstrates how to use `structlog.wrap_logger` that allows you to use ``structlog`` without any global configuration (a rather uncommon pattern, but can be useful): - -.. doctest:: - - >>> import datetime, logging, sys - >>> from structlog import wrap_logger - >>> from structlog.processors import JSONRenderer - >>> from structlog.stdlib import filter_by_level - >>> logging.basicConfig(stream=sys.stdout, format="%(message)s") - >>> def add_timestamp(_, __, event_dict): - ... event_dict["timestamp"] = datetime.datetime.utcnow() - ... return event_dict - >>> def censor_password(_, __, event_dict): - ... pw = event_dict.get("password") - ... if pw: - ... event_dict["password"] = "*CENSORED*" - ... return event_dict - >>> log = wrap_logger( - ... logging.getLogger(__name__), - ... processors=[ - ... filter_by_level, - ... add_timestamp, - ... censor_password, - ... JSONRenderer(indent=1, sort_keys=True) - ... ] - ... ) - >>> log.info("something.filtered") - >>> log.warning("something.not_filtered", password="secret") # doctest: +ELLIPSIS - { - "event": "something.not_filtered", - "password": "*CENSORED*", - "timestamp": "datetime.datetime(..., ..., ..., ..., ...)" - } - -``structlog`` comes with many handy processors build right in, so check the :ref:`API documentation ` before you write your own. -For example, you probably don't want to write your own timestamper. - - -.. _twisted-example: - -Twisted, and Logging Out Objects --------------------------------- - -If you prefer to log less but with more context in each entry, you can bind everything important to your logger and log it out with each log entry. - - -.. literalinclude:: code_examples/twisted_echo.py - :language: python - -gives you something like: - -.. code:: text - - ... peer='127.0.0.1' connection_id='1c6c0cb5-...' count=1 data='123\n' event='echoed data!' - ... peer='127.0.0.1' connection_id='1c6c0cb5-...' count=2 data='456\n' event='echoed data!' - ... peer='127.0.0.1' connection_id='1c6c0cb5-...' count=3 data='foo\n' event='echoed data!' - ... peer='10.10.0.1' connection_id='85234511-...' count=1 data='cba\n' event='echoed data!' - ... peer='127.0.0.1' connection_id='1c6c0cb5-...' count=4 data='bar\n' event='echoed data!' - -Since Twisted's logging system is a bit peculiar, ``structlog`` ships with an :class:`adapter ` so it keeps behaving like you'd expect it to behave. - -I'd also like to point out the Counter class that doesn't do anything spectacular but gets bound *once* per connection to the logger and since its repr is the number itself, it's logged out correctly for each event. -This shows off the strength of keeping a dict of objects for context instead of passing around serialized strings. diff --git a/docs/frameworks.md b/docs/frameworks.md new file mode 100644 index 00000000..4b2ad48e --- /dev/null +++ b/docs/frameworks.md @@ -0,0 +1,30 @@ +# Frameworks + +To have consistent log output, it makes sense to configure `structlog` *before* any logging is done. +The best place to perform your configuration varies with applications and frameworks. +If you use standard library's logging, it makes sense to configure them next to each other. + +If you have no choice but *have* to configure on import time in module-global scope, or can't rule out for other reasons that that your {func}`structlog.configure` gets called more than once, `structlog` offers {func}`structlog.configure_once` that raises a warning if `structlog` has been configured before (no matter whether using {func}`structlog.configure` or {func}`~structlog.configure_once`) but doesn't change anything. + + +## Django + +[*django-structlog*](https://pypi.org/project/django-structlog/) is a popular and well-maintained package that does all the heavy lifting. + + +## Flask + +See Flask's [Logging docs](https://flask.palletsprojects.com/en/latest/logging/). + +Generally speaking: put it *before* instantiating `flask.Flask`. + + +## Pyramid + +[Application constructor](https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/startup.html#the-startup-process>). + + +## Twisted + +The [plugin definition](https://docs.twisted.org/en/stable/core/howto/plugin.html) is the best place. +If your app is not a plugin, put it into your [tac file](https://docs.twisted.org/en/stable/core/howto/application.html). diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 00000000..06ddc5b5 --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,216 @@ +# Getting Started + +(install)= + +## Installation + +`structlog` can be easily installed using: + +``` +$ pip install structlog +``` + +If you want pretty exceptions in development (you know you do!), additionally install either [*rich*] or [*better-exceptions*]. +Try both to find out which one you like better -- the screenshot in the README and docs homepage is rendered by *rich*. + +On Windows, you also have to install [*colorama*] if you want colorful output beside exceptions. + + +## Your First Log Entry + +A lot of effort went into making `structlog` accessible without reading pages of documentation. +And indeed, the simplest possible usage looks like this +(if you're reading this on a small screen, you may have to scroll the example horizontally to see the full output): + +```{eval-rst} +.. doctest:: + + >>> import structlog + >>> log = structlog.get_logger() + >>> log.info("greeted", whom="world", more_than_a_string=[1, 2, 3]) # doctest: +SKIP + 2022-09-11 11:58.26 [info ] greeted more_than_a_string=[1, 2, 3] whom=world +``` + +Here, `structlog` takes full advantage of its hopefully useful default settings: + +- Output is sent to [standard out] instead of exploding into the user's face or doing nothing. +- It imitates standard library `logging`'s log levels for familiarity -- even if you're not using any of your integrations. + By default, no level-based filtering is done, but it comes with a very fast filtering machinery in the form of `structlog.make_filtering_bound_logger()`. +- All keywords are formatted using `structlog.dev.ConsoleRenderer`. + That in turn uses `repr` to serialize all values to strings. + Thus, it's easy to add support for logging of your own objects[^prod-json]. +- On Windows, if you have [*colorama*] installed, it's rendered in nice {doc}`colors `. + Other OSes do not need colorama for nice colors. +- If you have [*rich*] or [*better-exceptions*] installed, exceptions will be rendered in colors and with additional helpful information. + +[^prod-json]: In production, you're more likely to use {class}`~structlog.processors.JSONRenderer` that can also be customized using a `__structlog__` method so you don't have to change your repr methods to something they weren't originally intended for. + +It should be noted that even in most complex logging setups the example would still look just like that thanks to `configuration`. +Using the defaults, as above, is equivalent to: + +``` +import logging +import structlog + +structlog.configure( + processors=[ + structlog.contextvars.merge_contextvars, + structlog.processors.add_log_level, + structlog.processors.StackInfoRenderer(), + structlog.dev.set_exc_info, + structlog.processors.TimeStamper(), + structlog.dev.ConsoleRenderer() + ], + wrapper_class=structlog.make_filtering_bound_logger(logging.NOTSET), + context_class=dict, + logger_factory=structlog.PrintLoggerFactory(), + cache_logger_on_first_use=False +) +log = structlog.get_logger() +``` + +:::{note} +- `structlog.stdlib.recreate_defaults()` allows you to switch `structlog` to using standard library's `logging` module for output for better interoperability with just one function call. +- `structlog.make_filtering_bound_logger()` (re-)uses `logging`'s log levels, but doesn't use `logging` at all. + The exposed API is `FilteringBoundLogger`. +- For brevity and to enable doctests, all further examples in `structlog`'s documentation use the more simplistic `structlog.processors.KeyValueRenderer()` without timestamps. +::: + +There you go, structured logging! +However, this alone wouldn't warrant its own package. +After all, there's even a [recipe] on structured logging for the standard library. +So let's go a step further. + +(building-ctx)= + +## Building a Context + +Imagine a hypothetical web application that wants to log out all relevant data with just the API from above: + +```{literalinclude} code_examples/getting-started/imaginary_web.py +:language: python +``` + +The calls themselves are nice and straight to the point, however you're repeating yourself all over the place. +At this point, you'll be tempted to write a closure like: + +``` +def log_closure(event): + log.info(event, user_agent=user_agent, peer_ip=peer_ip) +``` + +inside of the view. +Problem solved? +Not quite. +What if the parameters are introduced step by step? +Do you really want to have a logging closure in each of your views? + +Let's have a look at a better approach: + +```{literalinclude} code_examples/getting-started/imaginary_web_better.py +:language: python +``` + +Suddenly your logger becomes your closure! + +For `structlog`, a log entry is just a dictionary called *event dict\[ionary\]*: + +- You can pre-build a part of the dictionary step by step. + These pre-saved values are called the *context*. +- As soon as an *event* happens -- which is a dictionary too -- it is merged together with the *context* to an *event dict* and logged out. +- If you don't like the concept of pre-building a context: just don't! + Convenient key-value-based logging is great to have on its own. +- Python keeps dictionaries ordered by keys by default. +- The recommended way of binding values is the one in these examples: creating new loggers with a new context. + If you're okay with giving up immutable local state for convenience, you can also use {doc}`context variables ` for the context. + + +## Manipulating Log Entries in Flight + +Now that your log events are dictionaries, it's also much easier to manipulate them than if it were plain strings. + +To facilitate that, `structlog` has the concept of {doc}`processor chains `. +A processor is a callable like a function that receives the event dictionary along with two other arguments and returns a new event dictionary that may or may not differ from the one it got passed. +The next processor in the chain receives that returned dictionary instead of the original one. + +Let's assume you wanted to add a timestamp to every event dict. +The processor would look like this: + +```{eval-rst} +.. doctest:: + + >>> import datetime + >>> def timestamper(_, __, event_dict): + ... event_dict["time"] = datetime.datetime.now().isoformat() + ... return event_dict +``` + +Plain Python, plain dictionaries. +Now you have to tell `structlog` about your processor by {doc}`configuring ` it: + +```{eval-rst} +.. doctest:: + + >>> structlog.configure(processors=[timestamper, structlog.processors.KeyValueRenderer()]) + >>> structlog.get_logger().info("hi") # doctest: +SKIP + event='hi' time='2018-01-21T09:37:36.976816' + +``` + +## Rendering + +Finally you want to have control over the actual format of your log entries. + +As you may have noticed in the previous section, renderers are just processors too. +It's also important to note, that they do not necessarily have to render your event dictionary to a string. +The output that is required from the renderer depends on the input that the *logger* that is wrapped by `structlog` needs. + +However, in most cases it's gonna be strings. + +So assuming you want to follow {doc}`best practices ` and render your event dictionary to JSON that is picked up by a log aggregation system like ELK or Graylog, `structlog` comes with batteries included -- you just have to tell it to use its {class}`~structlog.processors.JSONRenderer`: + +```{eval-rst} +.. doctest:: + + >>> structlog.configure(processors=[structlog.processors.JSONRenderer()]) + >>> structlog.get_logger().info("hi") + {"event": "hi"} + +``` + +## `structlog` and Standard Library's `logging` + +`structlog`'s primary application isn't printing though. +Instead, it's intended to wrap your *existing* loggers and **add** *structure* and *incremental context building* to them. +For that, `structlog` is *completely* agnostic of your underlying logger -- you can use it with any logger you like. + +The most prominent example of such an 'existing logger' is without doubt the logging module in the standard library. +To make this common case as simple as possible, `structlog` comes with some tools to help you: + +```{eval-rst} +.. doctest:: + + >>> import logging + >>> logging.basicConfig() + >>> from structlog.stdlib import LoggerFactory + >>> structlog.configure(logger_factory=LoggerFactory()) # doctest: +SKIP + >>> log = structlog.get_logger() + >>> log.warning("it works!", difficulty="easy") # doctest: +SKIP + WARNING:structlog...:difficulty='easy' event='it works!' +``` + +In other words, you tell `structlog` that you would like to use the standard library logger factory and keep calling {func}`~structlog.get_logger` like before. + +Since `structlog` is mainly used together with standard library's logging, there's {doc}`more ` goodness to make it as fast and convenient as possible. + +## Liked what you saw? + +Now you're all set for the rest of the user's guide and can start reading about {doc}`bound loggers ` -- the heart of `structlog`. +If you want to see more code, make sure to check out the `examples`! + + +[*better-exceptions*]: https://github.com/qix-/better-exceptions +[*colorama*]: https://pypi.org/project/colorama/ +[recipe]: https://docs.python.org/3/howto/logging-cookbook.html#implementing-structured-logging +[*rich*]: https://github.com/Textualize/rich +[standard out]: https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29 diff --git a/docs/getting-started.rst b/docs/getting-started.rst deleted file mode 100644 index 9f0d7764..00000000 --- a/docs/getting-started.rst +++ /dev/null @@ -1,210 +0,0 @@ -Getting Started -=============== - -.. _install: - -Installation ------------- - -``structlog`` can be easily installed using:: - - $ pip install structlog - -If you want pretty exceptions in development (you know you do!), additionally install either rich_ or `better-exceptions`_. -Try both to find out which one you like better -- the screenshot in the README and docs homepage is rendered by ``rich``. - -On Windows, you also have to install colorama_ if you want colorful output beside exceptions. - - -Your First Log Entry --------------------- - -A lot of effort went into making ``structlog`` accessible without reading pages of documentation. -And indeed, the simplest possible usage looks like this -(if you're reading this on a small screen, you may have to scroll the example horizontally to see the full output): - -.. doctest:: - - >>> import structlog - >>> log = structlog.get_logger() - >>> log.info("greeted", whom="world", more_than_a_string=[1, 2, 3]) # doctest: +SKIP - 2022-09-11 11:58.26 [info ] greeted more_than_a_string=[1, 2, 3] whom=world - -Here, ``structlog`` takes full advantage of its hopefully useful default settings: - -- Output is sent to `standard out`_ instead of exploding into the user's face or doing nothing. -- It imitates standard library `logging`'s log levels for familiarity -- even if you're not using any of your integrations. - By default, no level-based filtering is done, but it comes with a very fast filtering machinery in the form of `structlog.make_filtering_bound_logger()`. -- All keywords are formatted using `structlog.dev.ConsoleRenderer`. - That in turn uses `repr` to serialize all values to strings. - Thus, it's easy to add support for logging of your own objects\ [*]_. -- On Windows, if you have colorama_ installed, it's rendered in nice `colors `. - Other OSes do not need colorama for nice colors. -- If you have rich_ or `better-exceptions`_ installed, exceptions will be rendered in colors and with additional helpful information. - -It should be noted that even in most complex logging setups the example would still look just like that thanks to `configuration`. -Using the defaults, as above, is equivalent to:: - - import logging - import structlog - - structlog.configure( - processors=[ - structlog.contextvars.merge_contextvars, - structlog.processors.add_log_level, - structlog.processors.StackInfoRenderer(), - structlog.dev.set_exc_info, - structlog.processors.TimeStamper(), - structlog.dev.ConsoleRenderer() - ], - wrapper_class=structlog.make_filtering_bound_logger(logging.NOTSET), - context_class=dict, - logger_factory=structlog.PrintLoggerFactory(), - cache_logger_on_first_use=False - ) - log = structlog.get_logger() - -.. note:: - - - `structlog.stdlib.recreate_defaults()` allows you to switch ``structlog`` to using standard library's `logging` module for output for better interoperability with just one function call. - - - `structlog.make_filtering_bound_logger()` (re-)uses `logging`'s log levels, but doesn't use `logging` at all. - The exposed API is `FilteringBoundLogger`. - - - For brevity and to enable doctests, all further examples in ``structlog``'s documentation use the more simplistic `structlog.processors.KeyValueRenderer()` without timestamps. - -There you go, structured logging! -However, this alone wouldn't warrant its own package. -After all, there's even a recipe_ on structured logging for the standard library. -So let's go a step further. - - -.. _building-ctx: - -Building a Context ------------------- - -Imagine a hypothetical web application that wants to log out all relevant data with just the API from above: - -.. literalinclude:: code_examples/getting-started/imaginary_web.py - :language: python - -The calls themselves are nice and straight to the point, however you're repeating yourself all over the place. -At this point, you'll be tempted to write a closure like:: - - def log_closure(event): - log.info(event, user_agent=user_agent, peer_ip=peer_ip) - -inside of the view. -Problem solved? -Not quite. -What if the parameters are introduced step by step? -Do you really want to have a logging closure in each of your views? - -Let's have a look at a better approach: - -.. literalinclude:: code_examples/getting-started/imaginary_web_better.py - :language: python - -Suddenly your logger becomes your closure! - -For ``structlog``, a log entry is just a dictionary called *event dict[ionary]*: - -- You can pre-build a part of the dictionary step by step. - These pre-saved values are called the *context*. -- As soon as an *event* happens -- which is a dictionary too -- it is merged together with the *context* to an *event dict* and logged out. -- If you don't like the concept of pre-building a context: just don't! - Convenient key-value-based logging is great to have on its own. -- Python keeps dictionaries ordered by keys by default. -- The recommended way of binding values is the one in these examples: creating new loggers with a new context. - If you're okay with giving up immutable local state for convenience, you can also use :doc:`context variables ` for the context. - - -Manipulating Log Entries in Flight ----------------------------------- - -Now that your log events are dictionaries, it's also much easier to manipulate them than if it were plain strings. - -To facilitate that, ``structlog`` has the concept of :doc:`processor chains `. -A processor is a callable like a function that receives the event dictionary along with two other arguments and returns a new event dictionary that may or may not differ from the one it got passed. -The next processor in the chain receives that returned dictionary instead of the original one. - -Let's assume you wanted to add a timestamp to every event dict. -The processor would look like this: - -.. doctest:: - - >>> import datetime - >>> def timestamper(_, __, event_dict): - ... event_dict["time"] = datetime.datetime.now().isoformat() - ... return event_dict - -Plain Python, plain dictionaries. -Now you have to tell ``structlog`` about your processor by `configuring ` it: - -.. doctest:: - - >>> structlog.configure(processors=[timestamper, structlog.processors.KeyValueRenderer()]) - >>> structlog.get_logger().info("hi") # doctest: +SKIP - event='hi' time='2018-01-21T09:37:36.976816' - - -Rendering ---------- - -Finally you want to have control over the actual format of your log entries. - -As you may have noticed in the previous section, renderers are just processors too. -It's also important to note, that they do not necessarily have to render your event dictionary to a string. -The output that is required from the renderer depends on the input that the *logger* that is wrapped by ``structlog`` needs. - -However, in most cases it's gonna be strings. - -So assuming you want to follow `best practices ` and render your event dictionary to JSON that is picked up by a log aggregation system like ELK or Graylog, ``structlog`` comes with batteries included -- you just have to tell it to use its :class:`~structlog.processors.JSONRenderer`: - -.. doctest:: - - >>> structlog.configure(processors=[structlog.processors.JSONRenderer()]) - >>> structlog.get_logger().info("hi") - {"event": "hi"} - - -``structlog`` and Standard Library's ``logging`` ------------------------------------------------- - -``structlog``'s primary application isn't printing though. -Instead, it's intended to wrap your *existing* loggers and **add** *structure* and *incremental context building* to them. -For that, ``structlog`` is *completely* agnostic of your underlying logger -- you can use it with any logger you like. - -The most prominent example of such an 'existing logger' is without doubt the logging module in the standard library. -To make this common case as simple as possible, ``structlog`` comes with some tools to help you: - -.. doctest:: - - >>> import logging - >>> logging.basicConfig() - >>> from structlog.stdlib import LoggerFactory - >>> structlog.configure(logger_factory=LoggerFactory()) # doctest: +SKIP - >>> log = structlog.get_logger() - >>> log.warning("it works!", difficulty="easy") # doctest: +SKIP - WARNING:structlog...:difficulty='easy' event='it works!' - -In other words, you tell ``structlog`` that you would like to use the standard library logger factory and keep calling :func:`~structlog.get_logger` like before. - -Since ``structlog`` is mainly used together with standard library's logging, there's `more ` goodness to make it as fast and convenient as possible. - - -Liked what you saw? -------------------- - -Now you're all set for the rest of the user's guide and can start reading about :doc:`bound loggers ` -- the heart of ``structlog``. -If you want to see more code, make sure to check out the `examples`! - -.. [*] In production, you're more likely to use :class:`~structlog.processors.JSONRenderer` that can also be customized using a ``__structlog__`` method so you don't have to change your repr methods to something they weren't originally intended for. - - -.. _`standard out`: https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29 -.. _recipe: https://docs.python.org/3/howto/logging-cookbook.html#implementing-structured-logging -.. _rich: https://github.com/Textualize/rich -.. _`better-exceptions`: https://github.com/qix-/better-exceptions -.. _colorama: https://pypi.org/project/colorama/ diff --git a/docs/index.rst b/docs/index.rst index e64353c0..3862d6e9 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -10,10 +10,11 @@ Release v\ |release| (`What's new? `) :end-before: -First steps: +First Steps +=========== - If you're not sure whether ``structlog`` is for you, have a look at `why`. -- If you can't wait to log your first entry, start at `getting-started` and then work yourself through the basic docs. +- If you can't wait to log your first entry, start at `getting-started` and then work yourself through our tutorial. - Once you have basic grasp of how ``structlog`` works, acquaint yourself with the `integrations <#integration-with-existing-systems>`_ ``structlog`` is shipping with. @@ -24,17 +25,17 @@ Basics ------ .. toctree:: - :maxdepth: 1 + :maxdepth: 2 why getting-started loggers configuration - testing - contextvars processors + contextvars examples development + testing types @@ -45,21 +46,30 @@ Integration with Existing Systems However it comes with special wrappers for the Python standard library and Twisted that are optimized for their respective underlying loggers and contain less magic. .. toctree:: - :maxdepth: 1 + :maxdepth: 2 + frameworks standard-library twisted - logging-best-practices Advanced Topics --------------- .. toctree:: - :maxdepth: 1 + :maxdepth: 2 - custom-wrappers + logging-best-practices performance + custom-wrappers + + +Deprecated Features +------------------- + +.. toctree:: + :maxdepth: 1 + thread-local diff --git a/docs/processors.rst b/docs/processors.rst index 7686d22d..8d3efe89 100644 --- a/docs/processors.rst +++ b/docs/processors.rst @@ -136,9 +136,11 @@ More examples can be found in the :ref:`examples ` chapter. For a list of shipped processors, check out the :ref:`API documentation `. -Third Party Packages +Third-Party Packages -------------------- +``structlog`` was specifically designed to be as composable and reusable as possible, so whatever you're missing: +chances are, you can solve it with a processor! Since processors are self-contained callables, it's easy to write your own and to share them in separate packages. We collect those packages in our `GitHub Wiki `_ and encourage you to add your package too! diff --git a/docs/types.md b/docs/types.md new file mode 100644 index 00000000..fd68d319 --- /dev/null +++ b/docs/types.md @@ -0,0 +1,26 @@ +# Type Hints + +Static type hints -- together with a type checker like [Mypy](https://mypy.readthedocs.io/en/stable/) -- are an excellent way to make your code more robust, self-documenting, and maintainable in the long run. +And as of 20.2.0, `structlog` comes with type hints for all of its APIs. + +Since `structlog` is highly configurable and tries to give a clean facade to its users, adding types without breaking compatibility -- while remaining useful! -- was a formidable task. + +______________________________________________________________________ + +The main problem is that `structlog.get_logger()` returns whatever you've configured the bound logger to be. +The only commonality are the binding methods like `bind()` and we've extracted them into the {class}`structlog.types.BindableLogger` {class}`~typing.Protocol`. +But using that as a return type is worse than useless, because you'd have to use `typing.cast` on every logger returned by `structlog.get_logger()`, if you wanted to actually call any logging methods. + +The second problem is that said `bind()` and its cousins are inherited from a common base class (a [big](https://www.youtube.com/watch?v=3MNVP9-hglc) [mistake](https://python-patterns.guide/gang-of-four/composition-over-inheritance/) in hindsight) and can't know what concrete class subclasses them and therefore what type they are returning. + +The chosen solution is adding `structlog.stdlib.get_logger()` that just calls `structlog.get_logger()` but has the correct type hints and adding `structlog.stdlib.BoundLogger.bind` et al that also only delegate to the base class. + +`structlog.get_logger()` is typed as returning {any}`typing.Any` so you can use your own type annotation and stick to the old APIs, if that's what you prefer: + +``` +import structlog + +logger: structlog.stdlib.BoundLogger = structlog.get_logger() +logger.info("hi") # <- ok +logger.msg("hi") # <- Mypy: 'error: "BoundLogger" has no attribute "msg"' +``` diff --git a/docs/types.rst b/docs/types.rst deleted file mode 100644 index a7db5e41..00000000 --- a/docs/types.rst +++ /dev/null @@ -1,43 +0,0 @@ -Type Hints -========== - -Static type hints -- together with a type checker like `Mypy `_ -- are an excellent way to make your code more robust, self-documenting, and maintainable in the long run. -And as of 20.2.0, ``structlog`` comes with type hints for all of its APIs. - -Since ``structlog`` is highly configurable and tries to give a clean facade to its users, adding types without breaking compatibility, while remaining useful was a formidable task. - -If you used ``structlog`` and Mypy before 20.2.0, you will probably find that Mypy is failing now. -As a quick fix, add the following lines into your ``mypy.ini`` that should be at the root of your project directory (and must start with a ``[mypy]`` section): - -.. code:: ini - - [mypy-structlog.*] - follow_imports = skip - -It will ignore ``structlog``'s type stubs until you're ready to adapt your code base to them. - - ----- - -The main problem is that `structlog.get_logger()` returns whatever you've configured the bound logger to be. -The only commonality are the binding methods like ``bind()`` and we've extracted them into the `structlog.types.BindableLogger` :class:`~typing.Protocol`. -But using that as a return type is worse than useless, because you'd have to use `typing.cast` on every logger returned by `structlog.get_logger()`, if you wanted to actually call any logging methods. - -The second problem is that said ``bind()`` and its cousins are inherited from a common base class (a `big `_ `mistake `_ in hindsight) and can't know what concrete class subclasses them and therefore what type they are returning. - -The chosen solution is adding `structlog.stdlib.get_logger()` that just calls `structlog.get_logger()` but has the correct type hints and adding `structlog.stdlib.BoundLogger.bind` et al that also only delegate to the base class. - -`structlog.get_logger()` is typed as returning `typing.Any` so you can use your own type annotation and stick to the old APIs, if that's what you prefer: - -.. code:: - - import structlog - - logger: structlog.stdlib.BoundLogger = structlog.get_logger() - logger.info("hi") # <- ok - logger.msg("hi") # <- Mypy: 'error: "BoundLogger" has no attribute "msg"' - ----- - -Rather sooner than later, the concept of the base class will be replaced by proper delegation that will put the context-related methods into a proper class (with proxy stubs for backward compatibility). -In the end, we're already delegating anyway. From b0cbe8565c0f7e3cbd22ef6566649f40d7e67188 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 8 Oct 2022 14:23:05 +0200 Subject: [PATCH 0779/1520] Spiel --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b8f6f12b..77644874 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,13 @@ -`structlog` makes logging in Python **faster**, **less painful**, and **more powerful** by adding **structure** to your log entries. It has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio* or type hints along the way, and [influenced the design](https://twitter.com/sirupsen/status/638330548361019392) of [structured logging packages in other ecosystems](https://github.com/sirupsen/logrus). +

    Simple. Powerful. Fast. Pick three.

    -Thanks to its highly flexible design, it's up to you whether you want `structlog` to take care about the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's `logging` module. +`structlog` makes logging in Python **less painful**, **more powerful**, and **much faster**, by adding **structure** to your log entries and moving control to simple **functions**. + +It has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio* or type hints along the way, and [while influencing the design](https://twitter.com/sirupsen/status/638330548361019392) of [structured logging packages in other ecosystems](https://github.com/sirupsen/logrus). + +Thanks to its highly flexible design, it's up to you whether you want `structlog` to take care of the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's `logging` module. `structlog` comes with support for JSON, [*logfmt*](https://brandur.org/logfmt), as well as pretty console output out-of-the-box: @@ -38,7 +42,7 @@ Thanks to its highly flexible design, it's up to you whether you want `structlog A short explanation on *why* structured logging is good for you, and why `structlog` is the right tool for the job can be found in the [Why chapter](https://www.structlog.org/en/stable/why.html) of our documentation. -Once you feel inspired to try it out, check out our friendly [Getting Started tutorial](https://www.structlog.org/en/stable/getting-started.html) that also contains detailed installation instructions! +Once you feel inspired to try it out, check out our friendly [Getting Started tutorial](https://www.structlog.org/en/stable/getting-started.html). If you prefer videos over reading, check out [Markus Holtermann](https://twitter.com/m_holtermann)'s DjangoCon Europe 2019 talk: [*Logging Rethought 2: The Actions of Frank Taylor Jr.*](https://www.youtube.com/watch?v=Y5eyEgyHLLo) @@ -46,7 +50,7 @@ If you prefer videos over reading, check out [Markus Holtermann](https://twitter ## Credits `structlog` is written and maintained by [Hynek Schlawack](https://hynek.me/). -It’s inspired by previous work by [Jean-Paul Calderone](https://github.com/exarkun) and [David Reid](https://github.com/dreid). +The idea of bound loggers is inspired by previous work by [Jean-Paul Calderone](https://github.com/exarkun) and [David Reid](https://github.com/dreid). The development is kindly supported by my employer [Variomedia AG](https://www.variomedia.de/), ``structlog`` [Tidelift subscribers](https://tidelift.com/subscription/pkg/pypi-structlog), and all my amazing [GitHub Sponsors](https://github.com/sponsors/hynek). From fc0a88f58c1ee9dc820df6eabd435b447d9235df Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 8 Oct 2022 14:32:37 +0200 Subject: [PATCH 0780/1520] simplify landing page. --- docs/index.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 3862d6e9..dd1081ca 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,6 +1,6 @@ -============================= -Structured Logging for Python -============================= +========= +structlog +========= Release v\ |release| (`What's new? `) From 3225cff4f4e0d8cfbf1e6b4ee792c40ab6ac2823 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 8 Oct 2022 14:47:01 +0200 Subject: [PATCH 0781/1520] Fix version handling in docs --- README.md | 6 +++--- docs/conf.py | 3 +++ docs/index.rst | 4 +++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 77644874..1702d69a 100644 --- a/README.md +++ b/README.md @@ -24,15 +24,15 @@

    - -

    Simple. Powerful. Fast. Pick three.

    + + `structlog` makes logging in Python **less painful**, **more powerful**, and **much faster**, by adding **structure** to your log entries and moving control to simple **functions**. It has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio* or type hints along the way, and [while influencing the design](https://twitter.com/sirupsen/status/638330548361019392) of [structured logging packages in other ecosystems](https://github.com/sirupsen/logrus). -Thanks to its highly flexible design, it's up to you whether you want `structlog` to take care of the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's `logging` module. +Thanks to its highly flexible design, *you* choose whether you want `structlog` to take care of the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's `logging` module. `structlog` comes with support for JSON, [*logfmt*](https://brandur.org/logfmt), as well as pretty console output out-of-the-box: diff --git a/docs/conf.py b/docs/conf.py index 674ca17b..770b49d9 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -51,6 +51,9 @@ # The short X.Y version. version = release.rsplit(".", 1)[0] +if "dev" in release: + release = version = "UNRELEASED" + exclude_patterns = ["_build"] # The reST default role (used for this markup: `text`) to use for all diff --git a/docs/index.rst b/docs/index.rst index dd1081ca..57e66c36 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -2,7 +2,9 @@ structlog ========= -Release v\ |release| (`What's new? `) +*Simple. Powerful. Fast. Pick three.* + +Release |release| (`What's new? `) .. include:: ../README.md :parser: myst_parser.sphinx_ From 5124c031cea120c1d8d4389b7b5375332b42623a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 8 Oct 2022 14:50:09 +0200 Subject: [PATCH 0782/1520] Fix ConsoleLogger's second separator --- src/structlog/_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 47f1e792..36b602c5 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -33,7 +33,7 @@ add_log_level, StackInfoRenderer(), set_exc_info, - TimeStamper(fmt="%Y-%m-%d %H:%M.%S", utc=False), + TimeStamper(fmt="%Y-%m-%d %H:%M:%S", utc=False), ConsoleRenderer( colors=_use_colors and sys.stdout is not None From a4347aab54a18614097513b81c56c65a636c8df7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 8 Oct 2022 14:53:35 +0200 Subject: [PATCH 0783/1520] Add changelog entry --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a8550ee6..a74fc2f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,11 @@ So please make sure to **always** properly configure your applications. - The build backend has been switched to [*Hatch*](https://hatch.pypa.io/). +### Fixed + +- The timestamps in the default configuration now use the correct separator (`:`) for seconds. + + ## [22.1.0](https://github.com/hynek/structlog/compare/21.5.0...22.1.0) - 2022-07-20 ### Removed From 6e066602f6df7b4bd69561802e46542538f3be4a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 8 Oct 2022 15:23:24 +0200 Subject: [PATCH 0784/1520] Re-add links to getting started --- docs/getting-started.md | 76 ++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 47 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 06ddc5b5..8545b48a 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -6,7 +6,7 @@ `structlog` can be easily installed using: -``` +```console $ pip install structlog ``` @@ -19,8 +19,7 @@ On Windows, you also have to install [*colorama*] if you want colorful output be ## Your First Log Entry A lot of effort went into making `structlog` accessible without reading pages of documentation. -And indeed, the simplest possible usage looks like this -(if you're reading this on a small screen, you may have to scroll the example horizontally to see the full output): +As a result, the simplest possible usage looks like this: ```{eval-rst} .. doctest:: @@ -28,27 +27,24 @@ And indeed, the simplest possible usage looks like this >>> import structlog >>> log = structlog.get_logger() >>> log.info("greeted", whom="world", more_than_a_string=[1, 2, 3]) # doctest: +SKIP - 2022-09-11 11:58.26 [info ] greeted more_than_a_string=[1, 2, 3] whom=world + 2022-09-11 11:58:26 [info ] greeted more_than_a_string=[1, 2, 3] whom=world ``` Here, `structlog` takes full advantage of its hopefully useful default settings: - Output is sent to [standard out] instead of exploding into the user's face or doing nothing. -- It imitates standard library `logging`'s log levels for familiarity -- even if you're not using any of your integrations. - By default, no level-based filtering is done, but it comes with a very fast filtering machinery in the form of `structlog.make_filtering_bound_logger()`. -- All keywords are formatted using `structlog.dev.ConsoleRenderer`. +- It imitates standard library {mod}`logging`'s log levels for familiarity -- even if you're not using any of your integrations. + By default, no level-based filtering is done, but it comes with a very fast filtering machinery in the form of {func}`structlog.make_filtering_bound_logger()`. +- All keywords are formatted using {class}`structlog.dev.ConsoleRenderer`. That in turn uses `repr` to serialize all values to strings. - Thus, it's easy to add support for logging of your own objects[^prod-json]. -- On Windows, if you have [*colorama*] installed, it's rendered in nice {doc}`colors `. - Other OSes do not need colorama for nice colors. + Thus, it's easy to add support for logging of your own objects. +- It's rendered in nice {doc}`colors ` (the [*colorama*] package is needed on Windows). - If you have [*rich*] or [*better-exceptions*] installed, exceptions will be rendered in colors and with additional helpful information. -[^prod-json]: In production, you're more likely to use {class}`~structlog.processors.JSONRenderer` that can also be customized using a `__structlog__` method so you don't have to change your repr methods to something they weren't originally intended for. - -It should be noted that even in most complex logging setups the example would still look just like that thanks to `configuration`. +Please note that even in most complex logging setups the example would still look just like that thanks to {doc}`configuration`. Using the defaults, as above, is equivalent to: -``` +```python import logging import structlog @@ -71,12 +67,14 @@ log = structlog.get_logger() :::{note} - `structlog.stdlib.recreate_defaults()` allows you to switch `structlog` to using standard library's `logging` module for output for better interoperability with just one function call. -- `structlog.make_filtering_bound_logger()` (re-)uses `logging`'s log levels, but doesn't use `logging` at all. - The exposed API is `FilteringBoundLogger`. -- For brevity and to enable doctests, all further examples in `structlog`'s documentation use the more simplistic `structlog.processors.KeyValueRenderer()` without timestamps. +- {func}`structlog.make_filtering_bound_logger()` (re-)uses {any}`logging`'s log levels, but doesn't use `logging` at all. + The exposed API is {class}`structlog.types.FilteringBoundLogger`. +- For brevity and to enable doctests, all further examples in `structlog`'s documentation use the more simplistic {class}`structlog.processors.KeyValueRenderer()` without timestamps. ::: -There you go, structured logging! +Here you go, structured logging! + + However, this alone wouldn't warrant its own package. After all, there's even a [recipe] on structured logging for the standard library. So let's go a step further. @@ -92,9 +90,11 @@ Imagine a hypothetical web application that wants to log out all relevant data w ``` The calls themselves are nice and straight to the point, however you're repeating yourself all over the place. +It's easy to forget to add a key-value pair in one of the incantations. + At this point, you'll be tempted to write a closure like: -``` +```python def log_closure(event): log.info(event, user_agent=user_agent, peer_ip=peer_ip) ``` @@ -103,7 +103,7 @@ inside of the view. Problem solved? Not quite. What if the parameters are introduced step by step? -Do you really want to have a logging closure in each of your views? +And do you really want to have a logging closure in each of your views? Let's have a look at a better approach: @@ -120,14 +120,13 @@ For `structlog`, a log entry is just a dictionary called *event dict\[ionary\]*: - As soon as an *event* happens -- which is a dictionary too -- it is merged together with the *context* to an *event dict* and logged out. - If you don't like the concept of pre-building a context: just don't! Convenient key-value-based logging is great to have on its own. -- Python keeps dictionaries ordered by keys by default. - The recommended way of binding values is the one in these examples: creating new loggers with a new context. - If you're okay with giving up immutable local state for convenience, you can also use {doc}`context variables ` for the context. + If you're okay with giving up immutable local state for convenience, you can also use thread-local {doc}`context variables ` for the context. ## Manipulating Log Entries in Flight -Now that your log events are dictionaries, it's also much easier to manipulate them than if it were plain strings. +Now that your log events are dictionaries, it's also much easier to manipulate them than if they were plain strings. To facilitate that, `structlog` has the concept of {doc}`processor chains `. A processor is a callable like a function that receives the event dictionary along with two other arguments and returns a new event dictionary that may or may not differ from the one it got passed. @@ -154,7 +153,6 @@ Now you have to tell `structlog` about your processor by {doc}`configuring >> structlog.configure(processors=[timestamper, structlog.processors.KeyValueRenderer()]) >>> structlog.get_logger().info("hi") # doctest: +SKIP event='hi' time='2018-01-21T09:37:36.976816' - ``` ## Rendering @@ -162,7 +160,7 @@ Now you have to tell `structlog` about your processor by {doc}`configuring ` an >>> structlog.configure(processors=[structlog.processors.JSONRenderer()]) >>> structlog.get_logger().info("hi") {"event": "hi"} - ``` ## `structlog` and Standard Library's `logging` -`structlog`'s primary application isn't printing though. -Instead, it's intended to wrap your *existing* loggers and **add** *structure* and *incremental context building* to them. -For that, `structlog` is *completely* agnostic of your underlying logger -- you can use it with any logger you like. - -The most prominent example of such an 'existing logger' is without doubt the logging module in the standard library. -To make this common case as simple as possible, `structlog` comes with some tools to help you: +While `structlog`'s loggers are very fast and sufficient for the majority of our users, you're not bound to them. +Instead, it's been designed from day one to wrap your *existing* loggers and **add** *structure* and *incremental context building* to them. -```{eval-rst} -.. doctest:: - - >>> import logging - >>> logging.basicConfig() - >>> from structlog.stdlib import LoggerFactory - >>> structlog.configure(logger_factory=LoggerFactory()) # doctest: +SKIP - >>> log = structlog.get_logger() - >>> log.warning("it works!", difficulty="easy") # doctest: +SKIP - WARNING:structlog...:difficulty='easy' event='it works!' -``` +The most prominent example of such an "existing logger" is without doubt the logging module in the standard library. +To make this common case as simple as possible, `structlog` comes with [some tools](standard-library) to help you. -In other words, you tell `structlog` that you would like to use the standard library logger factory and keep calling {func}`~structlog.get_logger` like before. +As noted before, the fastest way to transform `structlog` into a `logging`-friendly package is calling {func}`structlog.stdlib.recreate_defaults()`. -Since `structlog` is mainly used together with standard library's logging, there's {doc}`more ` goodness to make it as fast and convenient as possible. ## Liked what you saw? -Now you're all set for the rest of the user's guide and can start reading about {doc}`bound loggers ` -- the heart of `structlog`. -If you want to see more code, make sure to check out the `examples`! +Now you're all set for the rest of the user's guide and can start reading about [bound loggers](loggers) -- the heart of `structlog`. [*better-exceptions*]: https://github.com/qix-/better-exceptions From 5e43a9b06dd503df344f00ac1e80186737291918 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 8 Oct 2022 15:28:39 +0200 Subject: [PATCH 0785/1520] Re-add links to contextvars.md --- docs/contextvars.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/contextvars.md b/docs/contextvars.md index a4816306..d0a6a01e 100644 --- a/docs/contextvars.md +++ b/docs/contextvars.md @@ -16,22 +16,22 @@ ``` The {mod}`contextvars` module in the Python standard library allows having a global `structlog` context that is local to the current execution context. -The execution context can be thread-local, concurrent code such as code using {mod}`asyncio`, or [*greenlet*](https://greenlet.readthedocs.io/). +The execution context can be thread-local if using threads, or using primitives based on {mod}`asyncio`, or [*greenlet*](https://greenlet.readthedocs.io/) respectively. For example, you may want to bind certain values like a request ID or the peer's IP address at the beginning of a web request and have them logged out along with the local contexts you build within our views. -For that `structlog` provides the `structlog.contextvars` module with a set of functions to bind variables to a context-local context. +For that `structlog` provides the {mod}`structlog.contextvars` module with a set of functions to bind variables to a context-local context. This context is safe to be used both in threaded as well as asynchronous code. The general flow is: -- Use `structlog.configure` with `structlog.contextvars.merge_contextvars` as your first processor. -- Call `structlog.contextvars.clear_contextvars` at the beginning of your request handler (or whenever you want to reset the context-local context). -- Call `structlog.contextvars.bind_contextvars` and `structlog.contextvars.unbind_contextvars` instead of your bound logger's `bind()` and `unbind()` when you want to bind and unbind key-value pairs to the context-local context. - You can also use the `structlog.contextvars.bound_contextvars` context manager/decorator. +- Use {func}`structlog.configure` with {func}`structlog.contextvars.merge_contextvars` as your first processor (part of default configuration). +- Call {func}`structlog.contextvars.clear_contextvars` at the beginning of your request handler (or whenever you want to reset the context-local context). +- Call {func}`structlog.contextvars.bind_contextvars` and {func}`structlog.contextvars.unbind_contextvars` instead of your bound logger's `bind()` and `unbind()` when you want to bind and unbind key-value pairs to the context-local context. + You can also use the {func}`structlog.contextvars.bound_contextvars` context manager / decorator. - Use `structlog` as normal. - Loggers act as they always do, but the `structlog.contextvars.merge_contextvars` processor ensures that any context-local binds get included in all of your log messages. -- If you want to access the context-local storage, you use `structlog.contextvars.get_contextvars` and `structlog.contextvars.get_merged_contextvars`. + Loggers act as they always do, but the {func}`structlog.contextvars.merge_contextvars` processor ensures that any context-local binds get included in all of your log messages. +- If you want to access the context-local storage, you use {func}`structlog.contextvars.get_contextvars` and {func}`structlog.contextvars.get_merged_contextvars`. We're sorry the word *context* means three different things in this itemization depending on ... context. @@ -80,9 +80,9 @@ We're sorry the word *context* means three different things in this itemization >>> clear_contextvars() >>> log.info("hi there") event='hi there' a=None - ``` + ## Support for `contextvars.Token` If e.g. your request handler calls a helper function that needs to temporarily override some contextvars before restoring them back to their original values, you can use the {class}`~contextvars.Token`s returned by {func}`~structlog.contextvars.bind_contextvars` along with {func}`~structlog.contextvars.reset_contextvars` to accomplish this (much like how {meth}`contextvars.ContextVar.reset` works): @@ -126,15 +126,15 @@ As you can see, `view`, `peer`, and `request_id` are present in **both** log ent While wrapped loggers are *immutable* by default, this example demonstrates how to circumvent that using a thread-local storage for request-wide context: -1. `structlog.contextvars.clear_contextvars()` ensures the thread-local storage is empty for each request. -2. `structlog.contextvars.bind_contextvars()` puts your key-value pairs into thread-local storage. -3. The `structlog.contextvars.merge_contextvars()` processor merges the thread-local context into the event dict. +1. {func}`structlog.contextvars.clear_contextvars()` ensures the thread-local storage is empty for each request. +2. {func}`structlog.contextvars.bind_contextvars()` puts your key-value pairs into thread-local storage. +3. The {func}`structlog.contextvars.merge_contextvars()` processor merges the thread-local context into the event dict. Please note that the `user` field is only present in the view because it wasn't bound into the thread-local storage. See {doc}`contextvars` for more details. ___ -`structlog.stdlib.LoggerFactory` is a totally magic-free class that just deduces the name of the caller's module and does a `logging.getLogger` with it. -It's used by `structlog.get_logger` to rid you of logging boilerplate in application code. -If you prefer to name your standard library loggers explicitly, a positional argument to `structlog.get_logger` gets passed to the factory and used as the name. +{func}`structlog.stdlib.LoggerFactory` is a totally magic-free class that just deduces the name of the caller's module and runs a {func}`logging.getLogger` with it. +It's used by {func}`structlog.get_logger` to rid you of logging boilerplate in application code. +If you prefer to name your standard library loggers explicitly, a positional argument to {func}`structlog.get_logger` gets passed to the factory and used as the name. From 3e23c2a34243d48935c5e9d9c7c55cedb1a6e664 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 8 Oct 2022 16:46:40 +0200 Subject: [PATCH 0786/1520] Wordsmith --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1702d69a..27dec150 100644 --- a/README.md +++ b/README.md @@ -30,11 +30,11 @@ `structlog` makes logging in Python **less painful**, **more powerful**, and **much faster**, by adding **structure** to your log entries and moving control to simple **functions**. -It has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio* or type hints along the way, and [while influencing the design](https://twitter.com/sirupsen/status/638330548361019392) of [structured logging packages in other ecosystems](https://github.com/sirupsen/logrus). +It has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio*, context variables, or type hints as they emerged. Its design proved influential enough to [help design](https://twitter.com/sirupsen/status/638330548361019392) structured logging [packages across ecosystems](https://github.com/sirupsen/logrus). Thanks to its highly flexible design, *you* choose whether you want `structlog` to take care of the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's `logging` module. -`structlog` comes with support for JSON, [*logfmt*](https://brandur.org/logfmt), as well as pretty console output out-of-the-box: +The output format is just as flexible and `structlog` comes with support for JSON, [*logfmt*](https://brandur.org/logfmt), as well as pretty console output out-of-the-box: ![image](https://github.com/hynek/structlog/blob/main/docs/_static/console_renderer.png?raw=true) @@ -52,11 +52,11 @@ If you prefer videos over reading, check out [Markus Holtermann](https://twitter `structlog` is written and maintained by [Hynek Schlawack](https://hynek.me/). The idea of bound loggers is inspired by previous work by [Jean-Paul Calderone](https://github.com/exarkun) and [David Reid](https://github.com/dreid). -The development is kindly supported by my employer [Variomedia AG](https://www.variomedia.de/), ``structlog`` [Tidelift subscribers](https://tidelift.com/subscription/pkg/pypi-structlog), and all my amazing [GitHub Sponsors](https://github.com/sponsors/hynek). +The development is kindly supported by my employer [Variomedia AG](https://www.variomedia.de/), `structlog`’s [Tidelift subscribers](https://tidelift.com/subscription/pkg/pypi-structlog), and all my amazing [GitHub Sponsors](https://github.com/sponsors/hynek). A full list of contributors can be found in GitHub’s [overview](https://github.com/hynek/structlog/graphs/contributors). -The `structlog` logo has been contributed by [Russell Keith-Magee](https://github.com/freakboy3742). +The logs-loving futuristic beaver logo has been contributed by [Russell Keith-Magee](https://github.com/freakboy3742). @@ -77,4 +77,4 @@ The `structlog` logo has been contributed by [Russell Keith-Magee](https://githu Available as part of the Tidelift Subscription. -The maintainers of structlog and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. [Learn more.](https://tidelift.com/subscription/pkg/pypi-structlog?utm_source=pypi-structlog&utm_medium=referral&utm_campaign=readme) +The maintainers of `structlog` and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. [Learn more.](https://tidelift.com/subscription/pkg/pypi-structlog?utm_source=pypi-structlog&utm_medium=referral&utm_campaign=readme) From 0341298815da28521bedefdb7c04a86a72db722b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Oct 2022 07:24:15 +0200 Subject: [PATCH 0787/1520] Add string interpolation to FilteringBoundLogger (#454) * Add string interpolation to FilteringBoundLogger * Add to getting started * Mention interpolation in why --- .github/workflows/ci.yml | 2 ++ CHANGELOG.md | 12 ++++++++++ docs/getting-started.md | 7 ++++-- docs/why.rst | 12 ++++++++-- readthedocs.yml | 2 +- src/structlog/_log_levels.py | 4 ++-- src/structlog/types.py | 44 +++++++++++++++++++----------------- tests/test_log_levels.py | 8 +++++++ tox.ini | 2 +- typing_examples.py | 3 +++ 10 files changed, 67 insertions(+), 29 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 118b8aa9..0e8705a1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -107,6 +107,7 @@ jobs: fail-fast: false matrix: python-version: + # mypy on 3.7 fails but there's nothing we can do about it - "3.8" - "3.9" - "3.10" @@ -128,6 +129,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: + # Keep in sync with tox.ini/docs & readthedocs.yml python-version: "3.10" - run: python -m pip install --upgrade wheel tox diff --git a/CHANGELOG.md b/CHANGELOG.md index a74fc2f0..7ff669a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,18 @@ So please make sure to **always** properly configure your applications. Please use [`importlib.metadata`](https://docs.python.org/3.10/library/importlib.metadata.html) instead (for Python 3.7: the [*importlib-metadata*](https://pypi.org/project/importlib-metadata/) PyPI package). +### Added + +- `FilteringBoundLogger` (used by default) now allows for string interpolation using positional arguments: + + ```pycon + >>> log.info("Hello %s! The answer is %d.", "World", 42, x=1) + 2022-10-07 10:04.31 [info ] Hello World! The answer is 42. x=1 + ``` + + [#454](https://github.com/hynek/structlog/pull/454) + + ### Changed - The build backend has been switched to [*Hatch*](https://hatch.pypa.io/). diff --git a/docs/getting-started.md b/docs/getting-started.md index 8545b48a..0f120d44 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -26,8 +26,8 @@ As a result, the simplest possible usage looks like this: >>> import structlog >>> log = structlog.get_logger() - >>> log.info("greeted", whom="world", more_than_a_string=[1, 2, 3]) # doctest: +SKIP - 2022-09-11 11:58:26 [info ] greeted more_than_a_string=[1, 2, 3] whom=world + >>> log.info("hello, %s!", "world", key="value!", more_than_strings=[1, 2, 3]) # doctest: +SKIP + 2022-10-07 10:41:29 [info ] hello, world! key=value! more_strings=[1, 2, 3] ``` Here, `structlog` takes full advantage of its hopefully useful default settings: @@ -35,6 +35,9 @@ Here, `structlog` takes full advantage of its hopefully useful default settings: - Output is sent to [standard out] instead of exploding into the user's face or doing nothing. - It imitates standard library {mod}`logging`'s log levels for familiarity -- even if you're not using any of your integrations. By default, no level-based filtering is done, but it comes with a very fast filtering machinery in the form of {func}`structlog.make_filtering_bound_logger()`. +- Like `logging`, positional arguments are [interpolated into the message string using %](https://docs.python.org/3/library/stdtypes.html#old-string-formatting). + That might look dated, but it's *much* faster than using {any}`str.format` and allows ``structlog`` to be used as drop-in replacement for {mod}`logging` in more cases. + If you *know* that the log entry is *always* gonna be logged out, just use [f-strings](https://docs.python.org/3/tutorial/inputoutput.html#formatted-string-literals) which are the fastest. - All keywords are formatted using {class}`structlog.dev.ConsoleRenderer`. That in turn uses `repr` to serialize all values to strings. Thus, it's easy to add support for logging of your own objects. diff --git a/docs/why.rst b/docs/why.rst index 48ea1c53..8d399203 100644 --- a/docs/why.rst +++ b/docs/why.rst @@ -31,10 +31,18 @@ You can stop writing prose and start thinking in terms of an event that happens >>> from structlog import get_logger >>> log = get_logger() >>> log.info("key_value_logging", out_of_the_box=True, effort=0) - 2020-11-18 09:17.09 [info ] key_value_logging effort=0 out_of_the_box=True + 2020-11-18 09:17:09 [info ] key_value_logging effort=0 out_of_the_box=True Each log entry is a meaningful dictionary instead of an opaque string now! +That said, ``structlog`` is not taking anything away from you. +You can still use string interpolation: + +.. code-block:: pycon + + >>> log.info("Hello, %s!", "world") + 2022-10-10 07:19:25 [info ] Hello, world! + Data Binding ============ @@ -46,7 +54,7 @@ Since log entries are dictionaries, you can start binding and re-binding key/val >>> log = log.bind(user="anonymous", some_key=23) >>> log = log.bind(user="hynek", another_key=42) >>> log.info("user.logged_in", happy=True) - 2020-11-18 09:18.28 [info ] user.logged_in another_key=42 happy=True some_key=23 user=hynek + 2020-11-18 09:18:28 [info ] user.logged_in another_key=42 happy=True some_key=23 user=hynek You can also bind key/value pairs to :doc:`context variables ` that look global, but are local to your thread or *asyncio* context (i.e. often your request). diff --git a/readthedocs.yml b/readthedocs.yml index d335c40d..f563d645 100644 --- a/readthedocs.yml +++ b/readthedocs.yml @@ -5,7 +5,7 @@ formats: all build: os: ubuntu-20.04 tools: - # Keep version in sync with tox.ini (docs and gh-actions). + # Keep version in sync with tox.ini/docs and ci.yml/docs python: "3.10" python: diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index 4c1cb5c8..4882669d 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -126,8 +126,8 @@ def make_method(level: int) -> Callable[..., Any]: name = _LEVEL_TO_NAME[level] - def meth(self: Any, event: str, **kw: Any) -> Any: - return self._proxy_to_logger(name, event, **kw) + def meth(self: Any, event: str, *args: Any, **kw: Any) -> Any: + return self._proxy_to_logger(name, event % args, **kw) meth.__name__ = name diff --git a/src/structlog/types.py b/src/structlog/types.py index adc840c7..65542dea 100644 --- a/src/structlog/types.py +++ b/src/structlog/types.py @@ -151,6 +151,8 @@ class FilteringBoundLogger(BindableLogger, Protocol): The only way to instantiate one is using `make_filtering_bound_logger`. .. versionadded:: 20.2.0 + .. versionadded:: 22.2.0 + String interpolation using positional arguments. """ def bind(self, **new_values: Any) -> FilteringBoundLogger: @@ -181,53 +183,53 @@ def new(self, **new_values: Any) -> FilteringBoundLogger: .. versionadded:: 22.1.0 """ - def debug(self, event: str, **kw: Any) -> Any: + def debug(self, event: str, *args: Any, **kw: Any) -> Any: """ - Log *event* with **kw** at **debug** level. + Log ``event % args`` with **kw** at **debug** level. """ - def info(self, event: str, **kw: Any) -> Any: + def info(self, event: str, *args: Any, **kw: Any) -> Any: """ - Log *event* with **kw** at **info** level. + Log ``event % args`` with **kw** at **info** level. """ - def warning(self, event: str, **kw: Any) -> Any: + def warning(self, event: str, *args: Any, **kw: Any) -> Any: """ - Log *event* with **kw** at **warn** level. + Log ``event % args`` with **kw** at **warn** level. """ - def warn(self, event: str, **kw: Any) -> Any: + def warn(self, event: str, *args: Any, **kw: Any) -> Any: """ - Log *event* with **kw** at **warn** level. + Log ``event % args`` with **kw** at **warn** level. """ - def error(self, event: str, **kw: Any) -> Any: + def error(self, event: str, *args: Any, **kw: Any) -> Any: """ - Log *event* with **kw** at **error** level. + Log ``event % args`` with **kw** at **error** level. """ - def err(self, event: str, **kw: Any) -> Any: + def err(self, event: str, *args: Any, **kw: Any) -> Any: """ - Log *event* with **kw** at **error** level. + Log ``event % args`` with **kw** at **error** level. """ - def fatal(self, event: str, **kw: Any) -> Any: + def fatal(self, event: str, *args: Any, **kw: Any) -> Any: """ - Log *event* with **kw** at **critical** level. + Log ``event % args`` with **kw** at **critical** level. """ - def exception(self, event: str, **kw: Any) -> Any: + def exception(self, event: str, *args: Any, **kw: Any) -> Any: """ - Log *event* with **kw** at **error** level and ensure that ``exc_info`` - is set in the event dictionary. + Log ``event % args`` with **kw** at **error** level and ensure that + ``exc_info`` is set in the event dictionary. """ - def critical(self, event: str, **kw: Any) -> Any: + def critical(self, event: str, *args: Any, **kw: Any) -> Any: """ - Log *event* with **kw** at **critical** level. + Log ``event % args`` with **kw** at **critical** level. """ - def msg(self, event: str, **kw: Any) -> Any: + def msg(self, event: str, *args: Any, **kw: Any) -> Any: """ - Log *event* with **kw** at **info** level. + Log ``event % args`` with **kw** at **info** level. """ diff --git a/tests/test_log_levels.py b/tests/test_log_levels.py index 42528876..509a485b 100644 --- a/tests/test_log_levels.py +++ b/tests/test_log_levels.py @@ -103,3 +103,11 @@ def test_pickle(self, level): bl = make_filtering_bound_logger(level) assert bl == pickle.loads(pickle.dumps(bl)) + + def test_pos_args(self, bl, cl): + """ + Positional arguments are used for string interpolation. + """ + bl.info("hello %s -- %d!", "world", 42) + + assert [("info", (), {"event": "hello world -- 42!"})] == cl.calls diff --git a/tox.ini b/tox.ini index adb22da3..f2ad31b6 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,7 @@ ignore = E203,W503,W504 # We don't run pre-commit in CI, because we use pre-commit.ci. [gh-actions] python = - 3.7: py37 # mypy on 3.7 fails but there's nothing we can do about it + 3.7: py37 3.8: py38 3.9: py39 3.10: py310 diff --git a/typing_examples.py b/typing_examples.py index 6e8b5b75..8ccdec9e 100644 --- a/typing_examples.py +++ b/typing_examples.py @@ -310,3 +310,6 @@ def typecheck_filtering_return() -> None: structlog.processors.JSONRenderer(), ] ) + +fbl: FilteringBoundLogger = structlog.get_logger() +fbl.info("Hello %s! The answer is %d.", "World", 42, x=1) From ae1cd13a74d2d4a66b6db21625f4a8fe5a26bc60 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Oct 2022 07:34:31 +0200 Subject: [PATCH 0788/1520] Clarify --- docs/why.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/why.rst b/docs/why.rst index 8d399203..83a8bfb5 100644 --- a/docs/why.rst +++ b/docs/why.rst @@ -36,7 +36,7 @@ You can stop writing prose and start thinking in terms of an event that happens Each log entry is a meaningful dictionary instead of an opaque string now! That said, ``structlog`` is not taking anything away from you. -You can still use string interpolation: +You can still use string interpolation using positional arguments: .. code-block:: pycon From ec1605229c9263455e5bcdb484e39b7edbe2c817 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Oct 2022 07:41:34 +0200 Subject: [PATCH 0789/1520] Spell and stylize Rich consistently --- CHANGELOG.md | 4 ++-- docs/development.md | 6 +++--- docs/getting-started.md | 8 ++++---- pyproject.toml | 2 +- src/structlog/dev.py | 15 +++++++-------- tests/test_dev.py | 6 +++--- 6 files changed, 20 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ff669a5..9362a5c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -191,8 +191,8 @@ So please make sure to **always** properly configure your applications. - `structlog.contextvars.bind_contextvars()` now returns a mapping of keys to `contextvars.Token`s, allowing you to reset values using the new `structlog.contextvars.reset_contextvars()`. [#339](https://github.com/hynek/structlog/pull/339) - Exception rendering in `structlog.dev.ConsoleLogger` is now configurable using the `exception_formatter` setting. - If either the [*rich*](https://github.com/Textualize/rich) or the [*better-exceptions*](https://github.com/qix-/better-exceptions) package is present, `structlog` will use them for pretty-printing tracebacks. - *rich* takes precedence over *better-exceptions* if both are present. + If either the [*Rich*](https://github.com/Textualize/rich) or the [*better-exceptions*](https://github.com/qix-/better-exceptions) package is present, `structlog` will use them for pretty-printing tracebacks. + *Rich* takes precedence over *better-exceptions* if both are present. This only works if `format_exc_info` is **absent** in the processor chain. [#330](https://github.com/hynek/structlog/pull/330), diff --git a/docs/development.md b/docs/development.md index 2bdc5966..0f82dd5b 100644 --- a/docs/development.md +++ b/docs/development.md @@ -6,10 +6,10 @@ The highlight is {class}`structlog.dev.ConsoleRenderer` that offers nicely align [^win]: Requires the [*colorama* package](https://pypi.org/project/colorama/) on Windows. -If either of the [*rich*](https://rich.readthedocs.io/) or [*better-exceptions*](https://github.com/Qix-/better-exceptions) packages is installed, it will also pretty-print exceptions with helpful contextual data. -*rich* takes precedence over *better-exceptions*, but you can configure it by passing {func}`structlog.dev.plain_traceback` or {func}`structlog.dev.better_traceback` for the `exception_formatter` parameter of {class}`~structlog.dev.ConsoleRenderer`. +If either of the [*Rich*](https://rich.readthedocs.io/) or [*better-exceptions*](https://github.com/Qix-/better-exceptions) packages is installed, it will also pretty-print exceptions with helpful contextual data. +*Rich* takes precedence over *better-exceptions*, but you can configure it by passing {func}`structlog.dev.plain_traceback` or {func}`structlog.dev.better_traceback` for the `exception_formatter` parameter of {class}`~structlog.dev.ConsoleRenderer`. -The following output is rendered using *rich*: +The following output is rendered using *Rich*: ```{figure} _static/console_renderer.png Colorful console output by ConsoleRenderer. diff --git a/docs/getting-started.md b/docs/getting-started.md index 0f120d44..bd7a71d2 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -10,8 +10,8 @@ $ pip install structlog ``` -If you want pretty exceptions in development (you know you do!), additionally install either [*rich*] or [*better-exceptions*]. -Try both to find out which one you like better -- the screenshot in the README and docs homepage is rendered by *rich*. +If you want pretty exceptions in development (you know you do!), additionally install either [*Rich*] or [*better-exceptions*]. +Try both to find out which one you like better -- the screenshot in the README and docs homepage is rendered by *Rich*. On Windows, you also have to install [*colorama*] if you want colorful output beside exceptions. @@ -42,7 +42,7 @@ Here, `structlog` takes full advantage of its hopefully useful default settings: That in turn uses `repr` to serialize all values to strings. Thus, it's easy to add support for logging of your own objects. - It's rendered in nice {doc}`colors ` (the [*colorama*] package is needed on Windows). -- If you have [*rich*] or [*better-exceptions*] installed, exceptions will be rendered in colors and with additional helpful information. +- If you have [*Rich*] or [*better-exceptions*] installed, exceptions will be rendered in colors and with additional helpful information. Please note that even in most complex logging setups the example would still look just like that thanks to {doc}`configuration`. Using the defaults, as above, is equivalent to: @@ -197,5 +197,5 @@ Now you're all set for the rest of the user's guide and can start reading about [*better-exceptions*]: https://github.com/qix-/better-exceptions [*colorama*]: https://pypi.org/project/colorama/ [recipe]: https://docs.python.org/3/howto/logging-cookbook.html#implementing-structured-logging -[*rich*]: https://github.com/Textualize/rich +[*Rich*]: https://github.com/Textualize/rich [standard out]: https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29 diff --git a/pyproject.toml b/pyproject.toml index 8eea6f7e..8f45a771 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,7 +56,7 @@ tests = [ "pytest>=6.0", "simplejson", ] -# Need twisted & rich for stubs. +# Need Twisted & Rich for stubs. # Otherwise mypy fails in tox. typing = ["mypy", "rich", "twisted"] docs = [ diff --git a/src/structlog/dev.py b/src/structlog/dev.py index b132cce8..64398106 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -165,7 +165,7 @@ def plain_traceback(sio: TextIO, exc_info: ExcInfo) -> None: To be passed into `ConsoleRenderer`'s ``exception_formatter`` argument. - Used by default if neither ``rich`` not ``better-exceptions`` are present. + Used by default if neither *Rich* not *better-exceptions* are present. .. versionadded:: 21.2 """ @@ -174,11 +174,11 @@ def plain_traceback(sio: TextIO, exc_info: ExcInfo) -> None: def rich_traceback(sio: TextIO, exc_info: ExcInfo) -> None: """ - Pretty-print *exc_info* to *sio* using the ``rich`` package. + Pretty-print *exc_info* to *sio* using the *Rich* package. To be passed into `ConsoleRenderer`'s ``exception_formatter`` argument. - Used by default if ``rich`` is installed. + Used by default if *Rich* is installed. .. versionadded:: 21.2 """ @@ -190,12 +190,11 @@ def rich_traceback(sio: TextIO, exc_info: ExcInfo) -> None: def better_traceback(sio: TextIO, exc_info: ExcInfo) -> None: """ - Pretty-print *exc_info* to *sio* using the ``better-exceptions`` package. + Pretty-print *exc_info* to *sio* using the *better-exceptions* package. To be passed into `ConsoleRenderer`'s ``exception_formatter`` argument. - Used by default if ``better-exceptions`` is installed and ``rich`` is - absent. + Used by default if *better-exceptions* is installed and *Rich* is absent. .. versionadded:: 21.2 """ @@ -215,7 +214,7 @@ class ConsoleRenderer: Render ``event_dict`` nicely aligned, possibly in colors, and ordered. If ``event_dict`` contains a true-ish ``exc_info`` key, it will be - rendered *after* the log line. If rich_ or better-exceptions_ are present, + rendered *after* the log line. If Rich_ or better-exceptions_ are present, in colors and with extra context. :param pad_event: Pad the event to this many characters. @@ -246,7 +245,7 @@ class ConsoleRenderer: .. _colorama: https://pypi.org/project/colorama/ .. _better-exceptions: https://pypi.org/project/better-exceptions/ - .. _rich: https://pypi.org/project/rich/ + .. _Rich: https://pypi.org/project/rich/ .. versionadded:: 16.0 .. versionadded:: 16.1 *colors* diff --git a/tests/test_dev.py b/tests/test_dev.py index 6e3df5b7..cb82bffd 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -484,13 +484,13 @@ def test_set_it(self): class TestRichTraceback: def test_default(self): """ - If rich is present, it's the default. + If Rich is present, it's the default. """ assert dev.default_exception_formatter is dev.rich_traceback def test_does_not_blow_up(self): """ - We trust rich to do the right thing, so we just exercise the function + We trust Rich to do the right thing, so we just exercise the function and check the first new line that we add manually is present. """ sio = StringIO() @@ -508,7 +508,7 @@ def test_does_not_blow_up(self): class TestBetterTraceback: def test_default(self): """ - If better-exceptions is present and rich is NOT present, it's the + If better-exceptions is present and Rich is NOT present, it's the default. """ assert ( From a8f3a0bcb39d3fb7e7fd903577dad8f96b69d1f5 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Oct 2022 08:56:47 +0200 Subject: [PATCH 0790/1520] MySTify why --- docs/why.md | 104 +++++++++++++++++++++++++++++++++++++++++++++ docs/why.rst | 116 --------------------------------------------------- 2 files changed, 104 insertions(+), 116 deletions(-) create mode 100644 docs/why.md delete mode 100644 docs/why.rst diff --git a/docs/why.md b/docs/why.md new file mode 100644 index 00000000..880af5c9 --- /dev/null +++ b/docs/why.md @@ -0,0 +1,104 @@ +# Why… + +## …Structured Logging? + +> I believe the widespread use of format strings in logging is based on two presumptions: +> +> - The first level consumer of a log message is a human. +> - The programmer knows what information is needed to debug an issue. +> +> I believe these presumptions are **no longer correct** in server side software. +> +> —[Paul Querna](https://paul.querna.org/articles/2011/12/26/log-for-machines-in-json/) + +Structured logging means that you don't write hard-to-parse and hard-to-keep-consistent prose in your log. +Instead, you log *events* that happen in a *context* of key / value pairs. + + +## …structlog? + +## Easier Logging + +You can stop writing prose and start thinking in terms of an event that happens in the context of key/value pairs: + +```pycon +>>> from structlog import get_logger +>>> log = get_logger() +>>> log.info("key_value_logging", out_of_the_box=True, effort=0) +2020-11-18 09:17:09 [info ] key_value_logging effort=0 out_of_the_box=True +``` + +Each log entry is a meaningful dictionary instead of an opaque string now! + +That said, `structlog` is not taking anything away from you. +You can still use string interpolation using positional arguments: + +```pycon +>>> log.info("Hello, %s!", "world") +2022-10-10 07:19:25 [info ] Hello, world! +``` + +## Data Binding + +Since log entries are dictionaries, you can start binding and re-binding key/value pairs to your loggers to ensure they are present in every following logging call: + +```pycon +>>> log = log.bind(user="anonymous", some_key=23) +>>> log = log.bind(user="hynek", another_key=42) +>>> log.info("user.logged_in", happy=True) +2020-11-18 09:18:28 [info ] user.logged_in another_key=42 happy=True some_key=23 user=hynek +``` + +You can also bind key/value pairs to {doc}`context variables ` that look global, but are local to your thread or *asyncio* context (i.e. usually your request). + + +## Powerful Pipelines + +Each log entry goes through a [processor pipeline](processors.md) that is just a chain of functions that receive a dictionary and return a new dictionary that gets fed into the next function. +That allows for simple but powerful data manipulation: + +```python +def timestamper(logger, log_method, event_dict): + """Add a timestamp to each log entry.""" + event_dict["timestamp"] = time.time() + return event_dict +``` + +There are [plenty of processors](structlog.processors) for most common tasks coming with `structlog`: + +- Collectors of [call stack information](structlog.processors.StackInfoRenderer) ("How did this log entry happen?"), +- …and [exceptions](structlog.processors.format_exc_info) ("What happened‽"). +- Flexible [timestamping](structlog.processors.TimeStamper). + + +## Formatting + +`structlog` is completely flexible about *how* the resulting log entry is emitted. +Since each log entry is a dictionary, it can be formatted to **any** format: + +- A colorful key/value format for [local development](https://www.structlog.org/en/stable/development.html), +- [JSON](https://www.structlog.org/en/stable/api.html#structlog.processors.JSONRenderer) for easy parsing, +- or some standard format you have parsers for like *nginx* or Apache *httpd*. + +Internally, formatters are processors whose return value (usually a string) is passed into loggers that are responsible for the output of your message. +`structlog` comes with multiple useful formatters out-of-the-box. + + +## Output + +`structlog` is also flexible with the final output of your log entries: + +- A **built-in** lightweight printer like in the examples above. + Easy to use and fast. +- Use the [**standard library**](standard-library.md)'s or [**Twisted**](twisted.md)'s logging modules for compatibility. + In this case `structlog` works like a wrapper that formats a string and passes them off into existing systems that won't know that `structlog` even exists. + + Or the other way round: `structlog` comes with a `logging` formatter that allows for processing third party log records. +- Don't format it to a string at all! + `structlog` passes you a dictionary and you can do with it whatever you want. + Reported use cases are sending them out via network or saving them in a database. + +## Highly Testable + +`structlog` is thoroughly tested and we see it as our duty to help you to achieve the same in *your* applications. +That's why it ships with a [test helpers](https://www.structlog.org/en/stable/testing.html) to introspect your application's logging behavior with little-to-no boilerplate. diff --git a/docs/why.rst b/docs/why.rst deleted file mode 100644 index 83a8bfb5..00000000 --- a/docs/why.rst +++ /dev/null @@ -1,116 +0,0 @@ -==== -Why… -==== - -…Structured Logging? -==================== - - I believe the widespread use of format strings in logging is based on two presumptions: - - - The first level consumer of a log message is a human. - - The programmer knows what information is needed to debug an issue. - - I believe these presumptions are **no longer correct** in server side software. - - ---`Paul Querna `_ - -Structured logging means that you don't write hard-to-parse and hard-to-keep-consistent prose in your log. -Instead, you log *events* that happen in a *context* of key/value pairs. - - -…structlog? -=========== - -Easier Logging -============== - -You can stop writing prose and start thinking in terms of an event that happens in the context of key/value pairs: - -.. code-block:: pycon - - >>> from structlog import get_logger - >>> log = get_logger() - >>> log.info("key_value_logging", out_of_the_box=True, effort=0) - 2020-11-18 09:17:09 [info ] key_value_logging effort=0 out_of_the_box=True - -Each log entry is a meaningful dictionary instead of an opaque string now! - -That said, ``structlog`` is not taking anything away from you. -You can still use string interpolation using positional arguments: - -.. code-block:: pycon - - >>> log.info("Hello, %s!", "world") - 2022-10-10 07:19:25 [info ] Hello, world! - - -Data Binding -============ - -Since log entries are dictionaries, you can start binding and re-binding key/value pairs to your loggers to ensure they are present in every following logging call: - -.. code-block:: pycon - - >>> log = log.bind(user="anonymous", some_key=23) - >>> log = log.bind(user="hynek", another_key=42) - >>> log.info("user.logged_in", happy=True) - 2020-11-18 09:18:28 [info ] user.logged_in another_key=42 happy=True some_key=23 user=hynek - -You can also bind key/value pairs to :doc:`context variables ` that look global, but are local to your thread or *asyncio* context (i.e. often your request). - - -Powerful Pipelines -================== - -Each log entry goes through a `processor pipeline `_ that is just a chain of functions that receive a dictionary and return a new dictionary that gets fed into the next function. -That allows for simple but powerful data manipulation: - -.. code-block:: python - - def timestamper(logger, log_method, event_dict): - """Add a timestamp to each log entry.""" - event_dict["timestamp"] = time.time() - return event_dict - -There are `plenty of processors `_ for most common tasks coming with ``structlog``: - -- Collectors of `call stack information `_ ("How did this log entry happen?"), -- …and `exceptions `_ ("What happened‽"). -- Unicode encoders/decoders. -- Flexible `timestamping `_. - - -Formatting -========== - -``structlog`` is completely flexible about *how* the resulting log entry is emitted. -Since each log entry is a dictionary, it can be formatted to **any** format: - -- A colorful key/value format for `local development `_, -- `JSON `_ for easy parsing, -- or some standard format you have parsers for like nginx or Apache httpd. - -Internally, formatters are processors whose return value (usually a string) is passed into loggers that are responsible for the output of your message. -``structlog`` comes with multiple useful formatters out-of-the-box. - - -Output -====== - -``structlog`` is also flexible with the final output of your log entries: - -- A **built-in** lightweight printer like in the examples above. - Easy to use and fast. -- Use the **standard library**'s or **Twisted**'s logging modules for compatibility. - In this case ``structlog`` works like a wrapper that formats a string and passes them off into existing systems that won't know that ``structlog`` even exists. - Or the other way round: ``structlog`` comes with a ``logging`` formatter that allows for processing third party log records. -- Don't format it to a string at all! - ``structlog`` passes you a dictionary and you can do with it whatever you want. - Reported use cases are sending them out via network or saving them in a database. - - -Highly Testable -=============== - -``structlog`` is thoroughly tested and we see it as our duty to help you to achieve the same in *your* applications. -That's why it ships with a `bunch of helpers `_ to introspect your application's logging behavior with little-to-no boilerplate. From 7984aa4f5eb0a036a2ad1806f2f7c110f30c02a6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Oct 2022 09:09:12 +0200 Subject: [PATCH 0791/1520] MySTify twisted --- docs/twisted.md | 111 +++++++++++++++++++++++++++++++++++++++++++++++ docs/twisted.rst | 108 --------------------------------------------- 2 files changed, 111 insertions(+), 108 deletions(-) create mode 100644 docs/twisted.md delete mode 100644 docs/twisted.rst diff --git a/docs/twisted.md b/docs/twisted.md new file mode 100644 index 00000000..f41c5745 --- /dev/null +++ b/docs/twisted.md @@ -0,0 +1,111 @@ +# Twisted + +:::{warning} +Since `sys.exc_clear` has been dropped in Python 3, there is currently no way to avoid multiple tracebacks in your log files if using `structlog` together with Twisted on Python 3. +::: + +:::{note} +`structlog` currently only supports the legacy -- but still perfectly working -- Twisted logging system found in `twisted.python.log`. +::: + + +## Concrete Bound Logger + +To make `structlog`'s behavior less magical, it ships with a Twisted-specific wrapper class that has an explicit API instead of improvising: `structlog.twisted.BoundLogger`. +It behaves exactly like the generic `structlog.BoundLogger` except: + +- it's slightly faster due to less overhead, +- has an explicit API ({func}`~structlog.twisted.BoundLogger.msg` and {func}`~structlog.twisted.BoundLogger.err`), +- hence causing less cryptic error messages if you get method names wrong. + +In order to avoid that `structlog` disturbs your CamelCase harmony, it comes with an alias for `structlog.get_logger` called `structlog.getLogger`. + + +## Processors + +`structlog` comes with two Twisted-specific processors: + +`structlog.twisted.EventAdapter` + +: This is useful if you have an existing Twisted application and just want to wrap your loggers for now. + It takes care of transforming your event dictionary into something [twisted.python.log.err](https://docs.twisted.org/en/stable/api/twisted.python.log.html#err) can digest. + + For example: + + ```python + def onError(fail): + failure = fail.trap(MoonExploded) + log.err(failure, _why="event-that-happened") + ``` + + will still work as expected. + + Needs to be put at the end of the processing chain. + It formats the event using a renderer that needs to be passed into the constructor: + + ```python + configure(processors=[EventAdapter(KeyValueRenderer()]) + ``` + + The drawback of this approach is that Twisted will format your exceptions as multi-line log entries which is painful to parse. + Therefore `structlog` comes with: + +`structlog.twisted.JSONRenderer` + +: Goes a step further and circumvents Twisted logger's Exception / Failure handling and renders it itself as JSON strings. + That gives you regular and simple-to-parse single-line JSON log entries no matter what happens. + + +## Bending Foreign Logging To Your Will + +`structlog` comes with a wrapper for Twisted's log observers to ensure the rest of your logs are in JSON too: `structlog.twisted.JSONLogObserverWrapper`. + +What it does is determining whether a log entry has been formatted by `structlog.twisted.JSONRenderer` and if not, converts the log entry to JSON with `event` being the log message and putting Twisted's `system` into a second key. + +So for example: + +``` +2013-09-15 22:02:18+0200 [-] Log opened. +``` + +becomes: + +``` +2013-09-15 22:02:18+0200 [-] {"event": "Log opened.", "system": "-"} +``` + +There is obviously some redundancy here. +Also, I'm presuming that if you write out JSON logs, you're going to let something else parse them which makes the human-readable date entries more trouble than they're worth. + +To get a clean log without timestamps and additional system fields (`[-]`), `structlog` comes with `structlog.twisted.PlainFileLogObserver` that writes only the plain message to a file and `structlog.twisted.plainJSONStdOutLogger` that composes it with the aforementioned `structlog.twisted.JSONLogObserverWrapper` and gives you a pure JSON log without any timestamps or other noise straight to [standard out]: + +```console +$ twistd -n --logger structlog.twisted.plainJSONStdOutLogger web +{"event": "Log opened.", "system": "-"} +{"event": "twistd 13.1.0 (python 2.7.3) starting up.", "system": "-"} +{"event": "reactor class: twisted...EPollReactor.", "system": "-"} +{"event": "Site starting on 8080", "system": "-"} +{"event": "Starting factory ", ...} +... +``` + +## Suggested Configuration + +```python +import structlog + +structlog.configure( + processors=[ + structlog.processors.StackInfoRenderer(), + structlog.twisted.JSONRenderer() + ], + context_class=dict, + logger_factory=structlog.twisted.LoggerFactory(), + wrapper_class=structlog.twisted.BoundLogger, + cache_logger_on_first_use=True, +) +``` + +See also {doc}`logging-best-practices`. + +[standard out]: https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29 diff --git a/docs/twisted.rst b/docs/twisted.rst deleted file mode 100644 index ace0b7a8..00000000 --- a/docs/twisted.rst +++ /dev/null @@ -1,108 +0,0 @@ -Twisted -======= - -.. warning:: - - Since ``sys.exc_clear`` has been dropped in Python 3, there is currently no way to avoid multiple tracebacks in your log files if using ``structlog`` together with Twisted on Python 3. - -.. note:: - - ``structlog`` currently only supports the legacy -- but still perfectly working -- Twisted logging system found in ``twisted.python.log``. - - -Concrete Bound Logger ---------------------- - -To make ``structlog``'s behavior less magicy, it ships with a Twisted-specific wrapper class that has an explicit API instead of improvising: `structlog.twisted.BoundLogger`. -It behaves exactly like the generic `structlog.BoundLogger` except: - -- it's slightly faster due to less overhead, -- has an explicit API (:func:`~structlog.twisted.BoundLogger.msg` and :func:`~structlog.twisted.BoundLogger.err`), -- hence causing less cryptic error messages if you get method names wrong. - -In order to avoid that ``structlog`` disturbs your CamelCase harmony, it comes with an alias for `structlog.get_logger` called `structlog.getLogger`. - - -Processors ----------- - -``structlog`` comes with two Twisted-specific processors: - -`structlog.twisted.EventAdapter` - This is useful if you have an existing Twisted application and just want to wrap your loggers for now. - It takes care of transforming your event dictionary into something `twisted.python.log.err `_ can digest. - - For example:: - - def onError(fail): - failure = fail.trap(MoonExploded) - log.err(failure, _why="event-that-happened") - - will still work as expected. - - Needs to be put at the end of the processing chain. - It formats the event using a renderer that needs to be passed into the constructor:: - - configure(processors=[EventAdapter(KeyValueRenderer()]) - - The drawback of this approach is that Twisted will format your exceptions as multi-line log entries which is painful to parse. - Therefore ``structlog`` comes with: - - -`structlog.twisted.JSONRenderer` - Goes a step further and circumvents Twisted logger's Exception/Failure handling and renders it itself as JSON strings. - That gives you regular and simple-to-parse single-line JSON log entries no matter what happens. - - -Bending Foreign Logging To Your Will ------------------------------------- - -``structlog`` comes with a wrapper for Twisted's log observers to ensure the rest of your logs are in JSON too: `structlog.twisted.JSONLogObserverWrapper`. - -What it does is determining whether a log entry has been formatted by `structlog.twisted.JSONRenderer` and if not, converts the log entry to JSON with ``event`` being the log message and putting Twisted's ``system`` into a second key. - -So for example:: - - 2013-09-15 22:02:18+0200 [-] Log opened. - -becomes:: - - 2013-09-15 22:02:18+0200 [-] {"event": "Log opened.", "system": "-"} - -There is obviously some redundancy here. -Also, I'm presuming that if you write out JSON logs, you're going to let something else parse them which makes the human-readable date entries more trouble than they're worth. - -To get a clean log without timestamps and additional system fields (``[-]``), ``structlog`` comes with `structlog.twisted.PlainFileLogObserver` that writes only the plain message to a file and `structlog.twisted.plainJSONStdOutLogger` that composes it with the aforementioned `structlog.twisted.JSONLogObserverWrapper` and gives you a pure JSON log without any timestamps or other noise straight to `standard out`_:: - - - $ twistd -n --logger structlog.twisted.plainJSONStdOutLogger web - {"event": "Log opened.", "system": "-"} - {"event": "twistd 13.1.0 (python 2.7.3) starting up.", "system": "-"} - {"event": "reactor class: twisted...EPollReactor.", "system": "-"} - {"event": "Site starting on 8080", "system": "-"} - {"event": "Starting factory ", ...} - ... - - -Suggested Configuration ------------------------ - -:: - - import structlog - - structlog.configure( - processors=[ - structlog.processors.StackInfoRenderer(), - structlog.twisted.JSONRenderer() - ], - context_class=dict, - logger_factory=structlog.twisted.LoggerFactory(), - wrapper_class=structlog.twisted.BoundLogger, - cache_logger_on_first_use=True, - ) - -See also :doc:`logging-best-practices`. - - -.. _`standard out`: https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29 From 543206b951b57e723c509d697eb5a0646035f774 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Oct 2022 09:17:32 +0200 Subject: [PATCH 0792/1520] MySTify legacy thread-local --- docs/thread-local.md | 218 ++++++++++++++++++++++++++++++++++++++++++ docs/thread-local.rst | 179 ---------------------------------- 2 files changed, 218 insertions(+), 179 deletions(-) create mode 100644 docs/thread-local.md delete mode 100644 docs/thread-local.rst diff --git a/docs/thread-local.md b/docs/thread-local.md new file mode 100644 index 00000000..1aaa3b7a --- /dev/null +++ b/docs/thread-local.md @@ -0,0 +1,218 @@ +# Legacy Thread-local Context + +:::{attention} +The `structlog.threadlocal` module is deprecated as of `structlog` 22.1.0 in favor of {doc}`contextvars`. + +The standard library {mod}`contextvars` module provides a more feature-rich superset of the thread-local APIs and works with thread-local data, async code, and greenlets. + +Therefore, as of 22.1.0, the `structlog.threadlocal` module is frozen and will be removed after May 2023. +::: + +```{eval-rst} +.. testsetup:: * + + import structlog + structlog.configure( + processors=[structlog.processors.KeyValueRenderer()], + ) +``` + +```{eval-rst} +.. testcleanup:: * + + import structlog + structlog.reset_defaults() + +``` + + +## The `merge_threadlocal` Processor + +`structlog` provides a simple set of functions that allow explicitly binding certain fields to a global (thread-local) context and merge them later using a processor into the event dict. + +The general flow of using these functions is: + +- Use {func}`structlog.configure` with {func}`structlog.threadlocal.merge_threadlocal` as your first processor. +- Call {func}`structlog.threadlocal.clear_threadlocal` at the beginning of your request handler (or whenever you want to reset the thread-local context). +- Call {func}`structlog.threadlocal.bind_threadlocal` as an alternative to your bound logger's `bind()` when you want to bind a particular variable to the thread-local context. +- Use `structlog` as normal. + Loggers act as they always do, but the {func}`structlog.threadlocal.merge_threadlocal` processor ensures that any thread-local binds get included in all of your log messages. +- If you want to access the thread-local storage, you use {func}`structlog.threadlocal.get_threadlocal` and {func}`structlog.threadlocal.get_merged_threadlocal`. + +These functions map 1:1 to the {doc}`contextvars` APIs, so please use those instead: + +- {func}`structlog.contextvars.merge_contextvars` +- {func}`structlog.contextvars.clear_contextvars` +- {func}`structlog.contextvars.bind_contextvars` +- {func}`structlog.contextvars.get_contextvars` +- {func}`structlog.contextvars.get_merged_contextvars` + + +## Thread-local Contexts + +`structlog` also provides thread-local context storage in a form that you may already know from [*Flask*](https://flask.palletsprojects.com/en/latest/design/#thread-locals) and that makes the *entire context* global to your thread or greenlet. + +This makes its behavior more difficult to reason about which is why we generally recommend to use the {func}`~structlog.contextvars.merge_contextvars` route. +Therefore, there are currently no plans to re-implement this behavior on top of context variables. + + +### Wrapped Dicts + +In order to make your context thread-local, `structlog` ships with a function that can wrap any dict-like class to make it usable for thread-local storage: {func}`structlog.threadlocal.wrap_dict`. + +Within one thread, every instance of the returned class will have a *common* instance of the wrapped dict-like class: + +```{eval-rst} +.. doctest:: + + >>> from structlog.threadlocal import wrap_dict + >>> WrappedDictClass = wrap_dict(dict) + >>> d1 = WrappedDictClass({"a": 1}) + >>> d2 = WrappedDictClass({"b": 2}) + >>> d3 = WrappedDictClass() + >>> d3["c"] = 3 + >>> d1 is d3 + False + >>> d1 == d2 == d3 == WrappedDictClass() + True + >>> d3 # doctest: +ELLIPSIS + + +``` + +To enable thread-local context use the generated class as the context class: + +```python +configure(context_class=WrappedDictClass) +``` + +:::{note} +Creation of a new `BoundLogger` initializes the logger's context as `context_class(initial_values)`, and then adds any values passed via `.bind()`. +As all instances of a wrapped dict-like class share the same data, in the case above, the new logger's context will contain all previously bound values in addition to the new ones. +::: + +`structlog.threadlocal.wrap_dict` returns always a completely *new* wrapped class: + +```{eval-rst} +.. doctest:: + + >>> from structlog.threadlocal import wrap_dict + >>> WrappedDictClass = wrap_dict(dict) + >>> AnotherWrappedDictClass = wrap_dict(dict) + >>> WrappedDictClass() != AnotherWrappedDictClass() + True + >>> WrappedDictClass.__name__ # doctest: +SKIP + WrappedDict-41e8382d-bee5-430e-ad7d-133c844695cc + >>> AnotherWrappedDictClass.__name__ # doctest: +SKIP + WrappedDict-e0fc330e-e5eb-42ee-bcec-ffd7bd09ad09 + +``` + +In order to be able to bind values temporarily to a logger, `structlog.threadlocal` comes with a [context manager](https://docs.python.org/2/library/stdtypes.html#context-manager-types): {func}`structlog.threadlocal.tmp_bind`: + +```{eval-rst} +.. testsetup:: ctx + + from structlog import PrintLogger, wrap_logger + from structlog.threadlocal import tmp_bind, wrap_dict + WrappedDictClass = wrap_dict(dict) + log = wrap_logger(PrintLogger(), context_class=WrappedDictClass) +``` + +```{eval-rst} +.. doctest:: ctx + + >>> log.bind(x=42) # doctest: +ELLIPSIS + , ...)> + >>> log.msg("event!") + x=42 event='event!' + >>> with tmp_bind(log, x=23, y="foo") as tmp_log: + ... tmp_log.msg("another event!") + x=23 y='foo' event='another event!' + >>> log.msg("one last event!") + x=42 event='one last event!' +``` + +The state before the `with` statement is saved and restored once it's left. + +If you want to detach a logger from thread-local data, there's {func}`structlog.threadlocal.as_immutable`. + + +#### Downsides & Caveats + +The convenience of having a thread-local context comes at a price though: + +:::{warning} +- If you can't rule out that your application re-uses threads, you *must* remember to **initialize your thread-local context** at the start of each request using {func}`~structlog.BoundLogger.new` (instead of {func}`~structlog.BoundLogger.bind`). + Otherwise you may start a new request with the context still filled with data from the request before. + +- **Don't** stop assigning the results of your `bind()`s and `new()`s! + + **Do**: + + ``` + log = log.new(y=23) + log = log.bind(x=42) + ``` + + **Don't**: + + ``` + log.new(y=23) + log.bind(x=42) + ``` + + Although the state is saved in a global data structure, you still need the global wrapped logger produce a real bound logger. + Otherwise each log call will result in an instantiation of a temporary BoundLogger. + + See `configuration` for more details. + +- It [doesn't play well](https://github.com/hynek/structlog/issues/296) with `os.fork` and thus `multiprocessing` (unless configured to use the `spawn` start method). +::: + + +## API + +```{eval-rst} +.. module:: structlog.threadlocal +``` + +```{eval-rst} +.. autofunction:: bind_threadlocal +``` + +```{eval-rst} +.. autofunction:: unbind_threadlocal +``` + +```{eval-rst} +.. autofunction:: bound_threadlocal +``` + +```{eval-rst} +.. autofunction:: get_threadlocal +``` + +```{eval-rst} +.. autofunction:: get_merged_threadlocal +``` + +```{eval-rst} +.. autofunction:: merge_threadlocal +``` + +```{eval-rst} +.. autofunction:: clear_threadlocal +``` + +```{eval-rst} +.. autofunction:: wrap_dict +``` + +```{eval-rst} +.. autofunction:: tmp_bind(logger, **tmp_values) +``` + +```{eval-rst} +.. autofunction:: as_immutable +``` diff --git a/docs/thread-local.rst b/docs/thread-local.rst deleted file mode 100644 index d5ed5007..00000000 --- a/docs/thread-local.rst +++ /dev/null @@ -1,179 +0,0 @@ -Legacy Thread-local Context -=========================== - -.. warning:: - The ``structlog.threadlocal`` module is deprecated as of ``structlog`` 22.1.0 in favor of :doc:`contextvars`. - - The standard library :mod:`contextvars` module provides a more feature-rich superset of the thread-local APIs and works with thread-local data, async code, and greenlets. - - Therefore, as of 22.1.0, the ``structlog.threadlocal`` is frozen and will be removed after May 2023. - -.. testsetup:: * - - import structlog - structlog.configure( - processors=[structlog.processors.KeyValueRenderer()], - ) - -.. testcleanup:: * - - import structlog - structlog.reset_defaults() - - -The ``merge_threadlocal`` Processor ------------------------------------ - -``structlog`` provides a simple set of functions that allow explicitly binding certain fields to a global (thread-local) context and merge them later using a processor into the event dict. - -The general flow of using these functions is: - -- Use `structlog.configure` with `structlog.threadlocal.merge_threadlocal` as your first processor. -- Call `structlog.threadlocal.clear_threadlocal` at the beginning of your request handler (or whenever you want to reset the thread-local context). -- Call `structlog.threadlocal.bind_threadlocal` as an alternative to your bound logger's ``bind()`` when you want to bind a particular variable to the thread-local context. -- Use ``structlog`` as normal. - Loggers act as they always do, but the `structlog.threadlocal.merge_threadlocal` processor ensures that any thread-local binds get included in all of your log messages. -- If you want to access the thread-local storage, you use `structlog.threadlocal.get_threadlocal` and `structlog.threadlocal.get_merged_threadlocal`. - -These functions map 1:1 to the :doc:`contextvars` APIs, so please use those instead: - -- `structlog.contextvars.merge_contextvars` -- `structlog.contextvars.clear_contextvars` -- `structlog.contextvars.bind_contextvars` -- `structlog.contextvars.get_contextvars` -- `structlog.contextvars.get_merged_contextvars` - - -Thread-local Contexts ---------------------- - -``structlog`` also provides thread-local context storage in a form that you may already know from `Flask `_ and that makes the *entire context* global to your thread or greenlet. - -This makes its behavior more difficult to reason about which is why we generally recommend to use the `merge_contextvars` route. -Therefore, there are currently no plans to re-implement this behavior on top of context variables. - - -Wrapped Dicts -^^^^^^^^^^^^^ - -In order to make your context thread-local, ``structlog`` ships with a function that can wrap any dict-like class to make it usable for thread-local storage: `structlog.threadlocal.wrap_dict`. - -Within one thread, every instance of the returned class will have a *common* instance of the wrapped dict-like class: - -.. doctest:: - - >>> from structlog.threadlocal import wrap_dict - >>> WrappedDictClass = wrap_dict(dict) - >>> d1 = WrappedDictClass({"a": 1}) - >>> d2 = WrappedDictClass({"b": 2}) - >>> d3 = WrappedDictClass() - >>> d3["c"] = 3 - >>> d1 is d3 - False - >>> d1 == d2 == d3 == WrappedDictClass() - True - >>> d3 # doctest: +ELLIPSIS - - - -To enable thread-local context use the generated class as the context class:: - - configure(context_class=WrappedDictClass) - -.. note:: - Creation of a new ``BoundLogger`` initializes the logger's context as ``context_class(initial_values)``, and then adds any values passed via ``.bind()``. - As all instances of a wrapped dict-like class share the same data, in the case above, the new logger's context will contain all previously bound values in addition to the new ones. - -`structlog.threadlocal.wrap_dict` returns always a completely *new* wrapped class: - -.. doctest:: - - >>> from structlog.threadlocal import wrap_dict - >>> WrappedDictClass = wrap_dict(dict) - >>> AnotherWrappedDictClass = wrap_dict(dict) - >>> WrappedDictClass() != AnotherWrappedDictClass() - True - >>> WrappedDictClass.__name__ # doctest: +SKIP - WrappedDict-41e8382d-bee5-430e-ad7d-133c844695cc - >>> AnotherWrappedDictClass.__name__ # doctest: +SKIP - WrappedDict-e0fc330e-e5eb-42ee-bcec-ffd7bd09ad09 - - -In order to be able to bind values temporarily to a logger, `structlog.threadlocal` comes with a `context manager `_: `structlog.threadlocal.tmp_bind`\ : - -.. testsetup:: ctx - - from structlog import PrintLogger, wrap_logger - from structlog.threadlocal import tmp_bind, wrap_dict - WrappedDictClass = wrap_dict(dict) - log = wrap_logger(PrintLogger(), context_class=WrappedDictClass) - -.. doctest:: ctx - - >>> log.bind(x=42) # doctest: +ELLIPSIS - , ...)> - >>> log.msg("event!") - x=42 event='event!' - >>> with tmp_bind(log, x=23, y="foo") as tmp_log: - ... tmp_log.msg("another event!") - x=23 y='foo' event='another event!' - >>> log.msg("one last event!") - x=42 event='one last event!' - -The state before the ``with`` statement is saved and restored once it's left. - -If you want to detach a logger from thread-local data, there's `structlog.threadlocal.as_immutable`. - - -Downsides & Caveats -~~~~~~~~~~~~~~~~~~~ - -The convenience of having a thread-local context comes at a price though: - -.. warning:: - - If you can't rule out that your application re-uses threads, you *must* remember to **initialize your thread-local context** at the start of each request using :func:`~structlog.BoundLogger.new` (instead of :func:`~structlog.BoundLogger.bind`). - Otherwise you may start a new request with the context still filled with data from the request before. - - **Don't** stop assigning the results of your ``bind()``\ s and ``new()``\ s! - - **Do**:: - - log = log.new(y=23) - log = log.bind(x=42) - - **Don't**:: - - log.new(y=23) - log.bind(x=42) - - Although the state is saved in a global data structure, you still need the global wrapped logger produce a real bound logger. - Otherwise each log call will result in an instantiation of a temporary BoundLogger. - - See `configuration` for more details. - - It `doesn't play well `_ with `os.fork` and thus `multiprocessing` (unless configured to use the ``spawn`` start method). - - - -API ---- - -.. module:: structlog.threadlocal - -.. autofunction:: bind_threadlocal - -.. autofunction:: unbind_threadlocal - -.. autofunction:: bound_threadlocal - -.. autofunction:: get_threadlocal - -.. autofunction:: get_merged_threadlocal - -.. autofunction:: merge_threadlocal - -.. autofunction:: clear_threadlocal - -.. autofunction:: wrap_dict - -.. autofunction:: tmp_bind(logger, **tmp_values) - -.. autofunction:: as_immutable From 37060be04ae4760f9aa8211b69e9f1c5cffd0844 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Oct 2022 09:22:14 +0200 Subject: [PATCH 0793/1520] Complete sentence --- docs/why.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/why.md b/docs/why.md index 880af5c9..916784d2 100644 --- a/docs/why.md +++ b/docs/why.md @@ -11,7 +11,7 @@ > > —[Paul Querna](https://paul.querna.org/articles/2011/12/26/log-for-machines-in-json/) -Structured logging means that you don't write hard-to-parse and hard-to-keep-consistent prose in your log. +Structured logging means that you don't write hard-to-parse and hard-to-keep-consistent prose in your log entries. Instead, you log *events* that happen in a *context* of key / value pairs. From 21c84e41615ed72d70061757c34645f7342d8118 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Oct 2022 09:36:03 +0200 Subject: [PATCH 0794/1520] MySTify index --- docs/index.md | 110 +++++++++++++++++++++++++++++++++++++++++++++++++ docs/index.rst | 107 ----------------------------------------------- docs/why.md | 6 +-- 3 files changed, 113 insertions(+), 110 deletions(-) create mode 100644 docs/index.md delete mode 100644 docs/index.rst diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..0a44e6d3 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,110 @@ +# structlog + +*Simple. Powerful. Fast. Pick three.* + +Release **{sub-ref}`release`** ([What's new?](changelog)) + +```{eval-rst} +.. include:: ../README.md + :parser: myst_parser.sphinx_ + :start-after: + :end-before: + +``` + + +## First Steps + +- If you're not sure whether `structlog` is for you, have a look at {doc}`why`. +- If you can't wait to log your first entry, start at {doc}`getting-started` and then work yourself through our tutorial. +- Once you have basic grasp of how `structlog` works, acquaint yourself with the [integrations](integration) `structlog` is shipping with. + + +## User's Guide + +### Basics + +```{toctree} +:maxdepth: 2 + +why +getting-started +loggers +configuration +processors +contextvars +examples +development +testing +types +``` + +(integration)= + +### Integration with Existing Systems + +`structlog` is both zero-config as well as highly flexible. +You can use it on its own or integrate with existing systems. +Dedicated support for the standard library and Twisted is shipped out-of-the-box. + +```{toctree} +:maxdepth: 2 + +frameworks +standard-library +twisted +``` + + +### Advanced Topics + +```{toctree} +:maxdepth: 2 + +logging-best-practices +performance +custom-wrappers +``` + + +### Deprecated Features + +```{toctree} +:maxdepth: 1 + +thread-local +``` + + +## API Reference + +```{toctree} +:maxdepth: 2 + +api +``` + + +## Project Information + +```{eval-rst} +.. include:: ../README.md + :parser: myst_parser.sphinx_ + :start-after: ## Project Information + +``` + +% stop Sphinx from complaints about orphaned docs, we link them elsewhere + +```{toctree} +:hidden: true + +license +changelog +``` + + +## Indices and tables + +- {any}`genindex` +- {any}`modindex` diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index 57e66c36..00000000 --- a/docs/index.rst +++ /dev/null @@ -1,107 +0,0 @@ -========= -structlog -========= - -*Simple. Powerful. Fast. Pick three.* - -Release |release| (`What's new? `) - -.. include:: ../README.md - :parser: myst_parser.sphinx_ - :start-after: - :end-before: - - -First Steps -=========== - -- If you're not sure whether ``structlog`` is for you, have a look at `why`. -- If you can't wait to log your first entry, start at `getting-started` and then work yourself through our tutorial. -- Once you have basic grasp of how ``structlog`` works, acquaint yourself with the `integrations <#integration-with-existing-systems>`_ ``structlog`` is shipping with. - - -User's Guide -============ - -Basics ------- - -.. toctree:: - :maxdepth: 2 - - why - getting-started - loggers - configuration - processors - contextvars - examples - development - testing - types - - -Integration with Existing Systems ---------------------------------- - -``structlog`` can be used immediately with *any* existing logger, or with the one with that it ships. -However it comes with special wrappers for the Python standard library and Twisted that are optimized for their respective underlying loggers and contain less magic. - -.. toctree:: - :maxdepth: 2 - - frameworks - standard-library - twisted - - -Advanced Topics ---------------- - -.. toctree:: - :maxdepth: 2 - - logging-best-practices - performance - custom-wrappers - - -Deprecated Features -------------------- - -.. toctree:: - :maxdepth: 1 - - thread-local - - -API Reference -============= - -.. toctree:: - :maxdepth: 2 - - api - - -Project Information -=================== - -.. include:: ../README.md - :parser: myst_parser.sphinx_ - :start-after: ## Project Information - - -.. stop Sphinx from complaints about orphaned docs, we link them elsewhere -.. toctree:: - :hidden: - - license - changelog - - -Indices and tables -================== - -- `genindex` -- `modindex` diff --git a/docs/why.md b/docs/why.md index 916784d2..ef75a5a4 100644 --- a/docs/why.md +++ b/docs/why.md @@ -1,6 +1,6 @@ -# Why… +# Why … -## …Structured Logging? +## … Structured Logging? > I believe the widespread use of format strings in logging is based on two presumptions: > @@ -15,7 +15,7 @@ Structured logging means that you don't write hard-to-parse and hard-to-keep-con Instead, you log *events* that happen in a *context* of key / value pairs. -## …structlog? +## … structlog? ## Easier Logging From dd400c92ba8ca3a16b95d543c1eebfea04036c9f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Oct 2022 09:40:37 +0200 Subject: [PATCH 0795/1520] Better word --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 0a44e6d3..694e00b4 100644 --- a/docs/index.md +++ b/docs/index.md @@ -43,7 +43,7 @@ types ### Integration with Existing Systems -`structlog` is both zero-config as well as highly flexible. +`structlog` is both zero-config as well as highly configurable. You can use it on its own or integrate with existing systems. Dedicated support for the standard library and Twisted is shipped out-of-the-box. From 9ab87b0792b2cd7a1d191e8073621c3308e4f9e8 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Oct 2022 09:43:35 +0200 Subject: [PATCH 0796/1520] Fix deflists --- docs/twisted.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/twisted.md b/docs/twisted.md index f41c5745..c03d1df9 100644 --- a/docs/twisted.md +++ b/docs/twisted.md @@ -25,7 +25,7 @@ In order to avoid that `structlog` disturbs your CamelCase harmony, it comes wit `structlog` comes with two Twisted-specific processors: -`structlog.twisted.EventAdapter` +{func}`structlog.twisted.EventAdapter` : This is useful if you have an existing Twisted application and just want to wrap your loggers for now. It takes care of transforming your event dictionary into something [twisted.python.log.err](https://docs.twisted.org/en/stable/api/twisted.python.log.html#err) can digest. @@ -50,7 +50,7 @@ In order to avoid that `structlog` disturbs your CamelCase harmony, it comes wit The drawback of this approach is that Twisted will format your exceptions as multi-line log entries which is painful to parse. Therefore `structlog` comes with: -`structlog.twisted.JSONRenderer` +{func}`structlog.twisted.JSONRenderer` : Goes a step further and circumvents Twisted logger's Exception / Failure handling and renders it itself as JSON strings. That gives you regular and simple-to-parse single-line JSON log entries no matter what happens. From ba4a745856ccfdd5b34a5bc59bcdbfdfc7ca029e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Oct 2022 09:43:57 +0200 Subject: [PATCH 0797/1520] Add missing deflist extension --- docs/conf.py | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/conf.py b/docs/conf.py index 770b49d9..d7a4b0e3 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -26,6 +26,7 @@ myst_enable_extensions = [ "colon_fence", "smartquotes", + "deflist", ] # Add any paths that contain templates here, relative to this directory. From d48371c6056728c5e091313a801722fc071d004c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Oct 2022 09:50:59 +0200 Subject: [PATCH 0798/1520] Spell / stylize Colorama consistently --- CHANGELOG.md | 10 +++++----- docs/development.md | 4 ++-- docs/getting-started.md | 12 ++++++------ src/structlog/dev.py | 20 ++++++++++---------- tests/test_dev.py | 6 +++--- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9362a5c5..ea222a00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -208,9 +208,9 @@ So please make sure to **always** properly configure your applications. Make sure to remove `format_exc_info` from your processor chain if you configure `structlog` manually. This change is not really breaking, because the old use-case will keep working as before. However if you pass `pretty_exceptions=True` (which is the default if either `rich` or `better-exceptions` is installed), a warning will be raised and the exception will be rendered without prettification. -- All use of [*colorama*](https://github.com/tartley/colorama) on non-Windows systems has been excised. +- All use of [*Colorama*](https://github.com/tartley/colorama) on non-Windows systems has been excised. Thus, colors are now enabled by default in `structlog.dev.ConsoleRenderer` on non-Windows systems. - You can keep using *colorama* to customize colors, of course. + You can keep using *Colorama* to customize colors, of course. [#345](https://github.com/hynek/structlog/pull/345) @@ -319,7 +319,7 @@ So please make sure to **always** properly configure your applications. - The logger created by `structlog.get_logger()` is not detected as an abstract method anymore, when attached to an abstract base class. [#229](https://github.com/hynek/structlog/issues/229) -- *colorama* isn't initialized lazily on Windows anymore because it breaks rendering. +- *Colorama* isn't initialized lazily on Windows anymore because it breaks rendering. [#232](https://github.com/hynek/structlog/issues/232), [#242](https://github.com/hynek/structlog/pull/242) @@ -364,9 +364,9 @@ It has been unsupported by the Python core team for a while now and its PyPI dow ### Fixed -- `structlog.dev.ConsoleRenderer` now uses no colors by default, if *colorama* is not available. +- `structlog.dev.ConsoleRenderer` now uses no colors by default, if *Colorama* is not available. [#215](https://github.com/hynek/structlog/issues/215) -- `structlog.dev.ConsoleRenderer` now initializes *colorama* lazily, to prevent accidental side-effects just by importing `structlog`. +- `structlog.dev.ConsoleRenderer` now initializes *Colorama* lazily, to prevent accidental side-effects just by importing `structlog`. [#210](https://github.com/hynek/structlog/issues/210) - A best effort has been made to make as much of `structlog` pickleable as possible to make it friendlier with `multiprocessing` and similar libraries. Some classes can only be pickled on Python 3 or using the [dill](https://pypi.org/project/dill/) library though and that is very unlikely to change. diff --git a/docs/development.md b/docs/development.md index 0f82dd5b..395f3a6e 100644 --- a/docs/development.md +++ b/docs/development.md @@ -4,7 +4,7 @@ To make development a more pleasurable experience, `structlog` comes with the {m The highlight is {class}`structlog.dev.ConsoleRenderer` that offers nicely aligned and colorful[^win] console output. -[^win]: Requires the [*colorama* package](https://pypi.org/project/colorama/) on Windows. +[^win]: Requires the [*Colorama* package](https://pypi.org/project/colorama/) on Windows. If either of the [*Rich*](https://rich.readthedocs.io/) or [*better-exceptions*](https://github.com/Qix-/better-exceptions) packages is installed, it will also pretty-print exceptions with helpful contextual data. *Rich* takes precedence over *better-exceptions*, but you can configure it by passing {func}`structlog.dev.plain_traceback` or {func}`structlog.dev.better_traceback` for the `exception_formatter` parameter of {class}`~structlog.dev.ConsoleRenderer`. @@ -24,7 +24,7 @@ It will recognize logger names, log levels, time stamps, stack infos, and `exc_i For pretty exceptions to work, {func}`~structlog.processors.format_exc_info` must be **absent** from the processors chain. ::: -`structlog`'s default configuration already uses {class}`~structlog.dev.ConsoleRenderer`, therefore if you want nice colorful output on the console, you don't have to do anything except installing *colorama* and *better-exceptions*. +`structlog`'s default configuration already uses {class}`~structlog.dev.ConsoleRenderer`, therefore if you want nice colorful output on the console, you don't have to do anything except installing *Rich* or *better-exceptions* (and *Colorama* on Windows). If you want to use it along with standard library logging, we suggest the following configuration: ```python diff --git a/docs/getting-started.md b/docs/getting-started.md index bd7a71d2..9fcc839c 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -4,7 +4,7 @@ ## Installation -`structlog` can be easily installed using: +The latest version of `structlog` is always on [PyPI](https://pypi.org/project/structlog/) and can be installed using *pip*: ```console $ pip install structlog @@ -13,7 +13,7 @@ $ pip install structlog If you want pretty exceptions in development (you know you do!), additionally install either [*Rich*] or [*better-exceptions*]. Try both to find out which one you like better -- the screenshot in the README and docs homepage is rendered by *Rich*. -On Windows, you also have to install [*colorama*] if you want colorful output beside exceptions. +On Windows, you also have to install [*Colorama*] if you want colorful output beside exceptions. ## Your First Log Entry @@ -33,7 +33,7 @@ As a result, the simplest possible usage looks like this: Here, `structlog` takes full advantage of its hopefully useful default settings: - Output is sent to [standard out] instead of exploding into the user's face or doing nothing. -- It imitates standard library {mod}`logging`'s log levels for familiarity -- even if you're not using any of your integrations. +- It imitates standard library {mod}`logging`'s log levels for familiarity -- even if you're not using any of our integrations. By default, no level-based filtering is done, but it comes with a very fast filtering machinery in the form of {func}`structlog.make_filtering_bound_logger()`. - Like `logging`, positional arguments are [interpolated into the message string using %](https://docs.python.org/3/library/stdtypes.html#old-string-formatting). That might look dated, but it's *much* faster than using {any}`str.format` and allows ``structlog`` to be used as drop-in replacement for {mod}`logging` in more cases. @@ -41,7 +41,7 @@ Here, `structlog` takes full advantage of its hopefully useful default settings: - All keywords are formatted using {class}`structlog.dev.ConsoleRenderer`. That in turn uses `repr` to serialize all values to strings. Thus, it's easy to add support for logging of your own objects. -- It's rendered in nice {doc}`colors ` (the [*colorama*] package is needed on Windows). +- It's rendered in nice {doc}`colors ` (the [*Colorama*] package is needed on Windows). - If you have [*Rich*] or [*better-exceptions*] installed, exceptions will be rendered in colors and with additional helpful information. Please note that even in most complex logging setups the example would still look just like that thanks to {doc}`configuration`. @@ -69,7 +69,7 @@ log = structlog.get_logger() ``` :::{note} -- `structlog.stdlib.recreate_defaults()` allows you to switch `structlog` to using standard library's `logging` module for output for better interoperability with just one function call. +- {func}`structlog.stdlib.recreate_defaults()` allows you to switch `structlog` to using standard library's `logging` module for output for better interoperability with just one function call. - {func}`structlog.make_filtering_bound_logger()` (re-)uses {any}`logging`'s log levels, but doesn't use `logging` at all. The exposed API is {class}`structlog.types.FilteringBoundLogger`. - For brevity and to enable doctests, all further examples in `structlog`'s documentation use the more simplistic {class}`structlog.processors.KeyValueRenderer()` without timestamps. @@ -195,7 +195,7 @@ Now you're all set for the rest of the user's guide and can start reading about [*better-exceptions*]: https://github.com/qix-/better-exceptions -[*colorama*]: https://pypi.org/project/colorama/ +[*Colorama*]: https://pypi.org/project/colorama/ [recipe]: https://docs.python.org/3/howto/logging-cookbook.html#implementing-structured-logging [*Rich*]: https://github.com/Textualize/rich [standard out]: https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29 diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 64398106..aee690e9 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -80,9 +80,9 @@ def _pad(s: str, length: int) -> str: GREEN = colorama.Fore.GREEN RED_BACK = colorama.Back.RED else: - # These are the same values as the colorama color codes. Redefining them + # These are the same values as the Colorama color codes. Redefining them # here allows users to specify that they want color without having to - # install colorama, which is only supposed to be necessary in Windows. + # install Colorama, which is only supposed to be necessary in Windows. RESET_ALL = "\033[0m" BRIGHT = "\033[1m" DIM = "\033[2m" @@ -96,7 +96,7 @@ def _pad(s: str, length: int) -> str: if _IS_WINDOWS: # pragma: no cover - # On Windows, use colors by default only if colorama is installed. + # On Windows, use colors by default only if Colorama is installed. _use_colors = colorama is not None else: # On other OSes, use colors by default. @@ -219,7 +219,7 @@ class ConsoleRenderer: :param pad_event: Pad the event to this many characters. :param colors: Use colors for a nicer output. `True` by default. On - Windows only if colorama_ is installed. + Windows only if Colorama_ is installed. :param force_colors: Force colors even for non-tty destinations. Use this option if your logs are stored in a file that is meant to be streamed to the console. Only meaningful on Windows. @@ -229,7 +229,7 @@ class ConsoleRenderer: non-ASCII output on Python 2. The ``event`` key is *never* `repr` -ed. :param level_styles: When present, use these styles for colors. This - must be a dict from level names (strings) to colorama styles. The + must be a dict from level names (strings) to Colorama styles. The default can be obtained by calling `ConsoleRenderer.get_default_level_styles` :param exception_formatter: A callable to render ``exc_infos``. If rich_ @@ -241,9 +241,9 @@ class ConsoleRenderer: :param event_key: The key to look for the main log message. Needed when you rename it e.g. using `structlog.processors.EventRenamer`. - Requires the colorama_ package if *colors* is `True` **on Windows**. + Requires the Colorama_ package if *colors* is `True` **on Windows**. - .. _colorama: https://pypi.org/project/colorama/ + .. _Colorama: https://pypi.org/project/colorama/ .. _better-exceptions: https://pypi.org/project/better-exceptions/ .. _Rich: https://pypi.org/project/rich/ @@ -253,10 +253,10 @@ class ConsoleRenderer: .. versionadded:: 18.1 *force_colors* .. versionadded:: 18.1 *level_styles* .. versionchanged:: 19.2 - ``colorama`` now initializes lazily to avoid unwanted initializations as + *Colorama now initializes lazily to avoid unwanted initializations as ``ConsoleRenderer`` is used by default. .. versionchanged:: 19.2 Can be pickled now. - .. versionchanged:: 20.1 ``colorama`` does not initialize lazily on Windows + .. versionchanged:: 20.1 *Colorama* does not initialize lazily on Windows anymore because it breaks rendering. .. versionchanged:: 21.1 It is additionally possible to set the logger name using the ``logger_name`` key in the ``event_dict``. @@ -269,7 +269,7 @@ class ConsoleRenderer: for it. .. versionchanged:: 21.2 The colors keyword now defaults to True on non-Windows systems, and either True or False in Windows depending on - whether colorama is installed. + whether *Colorama* is installed. .. versionadded:: 21.3.0 *sort_keys* .. versionadded:: 22.1 *event_key* """ diff --git a/tests/test_dev.py b/tests/test_dev.py index cb82bffd..84660aaa 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -59,17 +59,17 @@ class TestConsoleRenderer: def test_missing_colorama(self): """ ConsoleRenderer(colors=True) raises SystemError on initialization if - colorama is missing and _IS_WINDOWS is True. + Colorama is missing and _IS_WINDOWS is True. """ with pytest.raises(SystemError) as e: dev.ConsoleRenderer(colors=True) assert ( - "ConsoleRenderer with `colors=True` requires the colorama package " + "ConsoleRenderer with `colors=True` requires the Colorama package " "installed." ) in e.value.args[0] - def test_plain(self, cr, styles, unpadded): + def test_plain(self, cr, unpadded): """ Works with a plain event_dict with only the event. """ From 3e7c731369307b56f1149e177b468af86d8e51af Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Oct 2022 09:57:00 +0200 Subject: [PATCH 0799/1520] Fix missing * --- src/structlog/dev.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index aee690e9..8fec9e1e 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -253,7 +253,7 @@ class ConsoleRenderer: .. versionadded:: 18.1 *force_colors* .. versionadded:: 18.1 *level_styles* .. versionchanged:: 19.2 - *Colorama now initializes lazily to avoid unwanted initializations as + *Colorama* now initializes lazily to avoid unwanted initializations as ``ConsoleRenderer`` is used by default. .. versionchanged:: 19.2 Can be pickled now. .. versionchanged:: 20.1 *Colorama* does not initialize lazily on Windows From 30b11b9e9a603ccb38cce7866e727fd31bab9b14 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Oct 2022 10:00:00 +0200 Subject: [PATCH 0800/1520] Fix comma splice --- src/structlog/_log_levels.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index 4882669d..a4e01cd2 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -92,7 +92,7 @@ def make_filtering_bound_logger(min_level: int) -> type[FilteringBoundLogger]: Compared to using ``structlog``'s standard library integration and the `structlog.stdlib.filter_by_level` processor: - - It's faster because once the logger is built at program start, it's a + - It's faster because once the logger is built at program start; it's a static class. - For the same reason you can't change the log level once configured. Use the dynamic approach of `standard-library` instead, if you need this From 8f44a6f932bd10e45196ae3ab2d9dad34bfa7d09 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Oct 2022 10:26:34 +0200 Subject: [PATCH 0801/1520] Streamline getting started --- .../getting-started/imaginary_web.py | 18 ---- .../getting-started/imaginary_web_better.py | 23 ----- docs/getting-started.md | 91 ++++++++++++++----- 3 files changed, 66 insertions(+), 66 deletions(-) delete mode 100644 docs/code_examples/getting-started/imaginary_web.py delete mode 100644 docs/code_examples/getting-started/imaginary_web_better.py diff --git a/docs/code_examples/getting-started/imaginary_web.py b/docs/code_examples/getting-started/imaginary_web.py deleted file mode 100644 index f64bc7c9..00000000 --- a/docs/code_examples/getting-started/imaginary_web.py +++ /dev/null @@ -1,18 +0,0 @@ -from structlog import get_logger - - -log = get_logger() - - -def view(request): - user_agent = request.get("HTTP_USER_AGENT", "UNKNOWN") - peer_ip = request.client_addr - if something: - log.info("something", user_agent=user_agent, peer_ip=peer_ip) - return "something" - elif something_else: - log.info("something_else", user_agent=user_agent, peer_ip=peer_ip) - return "something_else" - else: - log.info("else", user_agent=user_agent, peer_ip=peer_ip) - return "else" diff --git a/docs/code_examples/getting-started/imaginary_web_better.py b/docs/code_examples/getting-started/imaginary_web_better.py deleted file mode 100644 index 44a33214..00000000 --- a/docs/code_examples/getting-started/imaginary_web_better.py +++ /dev/null @@ -1,23 +0,0 @@ -from structlog import get_logger - - -logger = get_logger() - - -def view(request): - log = logger.bind( - user_agent=request.get("HTTP_USER_AGENT", "UNKNOWN"), - peer_ip=request.client_addr, - ) - foo = request.get("foo") - if foo: - log = log.bind(foo=foo) - if something: - log.info("something") - return "something" - elif something_else: - log.info("something_else") - return "something_else" - else: - log.info("else") - return "else" diff --git a/docs/getting-started.md b/docs/getting-started.md index 9fcc839c..dbad32b2 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -7,7 +7,7 @@ The latest version of `structlog` is always on [PyPI](https://pypi.org/project/structlog/) and can be installed using *pip*: ```console -$ pip install structlog +$ python -m pip install structlog ``` If you want pretty exceptions in development (you know you do!), additionally install either [*Rich*] or [*better-exceptions*]. @@ -30,17 +30,16 @@ As a result, the simplest possible usage looks like this: 2022-10-07 10:41:29 [info ] hello, world! key=value! more_strings=[1, 2, 3] ``` -Here, `structlog` takes full advantage of its hopefully useful default settings: +Here, `structlog` takes advantage of its default settings: -- Output is sent to [standard out] instead of exploding into the user's face or doing nothing. -- It imitates standard library {mod}`logging`'s log levels for familiarity -- even if you're not using any of our integrations. +- Output is sent to [standard out] instead doing nothing. +- It imitates standard library {mod}`logging`'s log level names for familiarity. By default, no level-based filtering is done, but it comes with a very fast filtering machinery in the form of {func}`structlog.make_filtering_bound_logger()`. -- Like `logging`, positional arguments are [interpolated into the message string using %](https://docs.python.org/3/library/stdtypes.html#old-string-formatting). - That might look dated, but it's *much* faster than using {any}`str.format` and allows ``structlog`` to be used as drop-in replacement for {mod}`logging` in more cases. +- Like in `logging`, positional arguments are [interpolated into the message string using %](https://docs.python.org/3/library/stdtypes.html#old-string-formatting). + That might look dated, but it's *much* faster than using {any}`str.format` and allows ``structlog`` to be used as drop-in replacement for {mod}`logging`. If you *know* that the log entry is *always* gonna be logged out, just use [f-strings](https://docs.python.org/3/tutorial/inputoutput.html#formatted-string-literals) which are the fastest. - All keywords are formatted using {class}`structlog.dev.ConsoleRenderer`. That in turn uses `repr` to serialize all values to strings. - Thus, it's easy to add support for logging of your own objects. - It's rendered in nice {doc}`colors ` (the [*Colorama*] package is needed on Windows). - If you have [*Rich*] or [*better-exceptions*] installed, exceptions will be rendered in colors and with additional helpful information. @@ -86,10 +85,21 @@ So let's go a step further. ## Building a Context -Imagine a hypothetical web application that wants to log out all relevant data with just the API from above: +Imagine a hypothetical web application that wants to log out all relevant data with just the APIs that we've introduced so far: -```{literalinclude} code_examples/getting-started/imaginary_web.py -:language: python +```python +def view(request): + user_agent = request.get("HTTP_USER_AGENT", "UNKNOWN") + peer_ip = request.client_addr + if something: + log.info("something", user_agent=user_agent, peer_ip=peer_ip) + return "something" + elif something_else: + log.info("something_else", user_agent=user_agent, peer_ip=peer_ip) + return "something_else" + else: + log.info("else", user_agent=user_agent, peer_ip=peer_ip) + return "else" ``` The calls themselves are nice and straight to the point, however you're repeating yourself all over the place. @@ -110,21 +120,53 @@ And do you really want to have a logging closure in each of your views? Let's have a look at a better approach: -```{literalinclude} code_examples/getting-started/imaginary_web_better.py -:language: python +```python +def view(request): + log = logger.bind( + user_agent=request.get("HTTP_USER_AGENT", "UNKNOWN"), + peer_ip=request.client_addr, + ) + + if foo := request.get("foo"): + log = log.bind(foo=foo) + + if something: + log.info("something") + return "something" + elif something_else: + log.info("something_else") + return "something_else" + else: + log.info("else") + return "else" + ``` Suddenly your logger becomes your closure! -For `structlog`, a log entry is just a dictionary called *event dict\[ionary\]*: +--- + +To `structlog`, a log entry is just a dictionary called *event dict\[ionary\]*: - You can pre-build a part of the dictionary step by step. These pre-saved values are called the *context*. -- As soon as an *event* happens -- which is a dictionary too -- it is merged together with the *context* to an *event dict* and logged out. -- If you don't like the concept of pre-building a context: just don't! - Convenient key-value-based logging is great to have on its own. -- The recommended way of binding values is the one in these examples: creating new loggers with a new context. - If you're okay with giving up immutable local state for convenience, you can also use thread-local {doc}`context variables ` for the context. +- As soon as an *event* happens -- which are the `kwargs` of the log call -- it is merged together with the *context* to an *event dict* and logged out. +- Each logger with its context is *immutable*. + You manipulate the context by creating new loggers using `bind()` and `unbind()`. + +The last point is very clean and easy to reason about, but sometimes it's useful to store _some_ data globally. + +In our example above the peer IP comes to mind. +There's no point in extracting it in every view! +For that, `structlog` gives you thread-local context storage based on the {mod}`contextvars` module: + +```pycon +>>> structlog.contextvars.bind_contextvars(peer_ip="1.2.3.4") +>>> structlog.get_logger().info("something") +2022-10-10 10:18:05 [info ] something peer_ip=1.2.3.4 +``` + +See {doc}`contextvars` for more information and a more complete example. ## Manipulating Log Entries in Flight @@ -163,12 +205,10 @@ Now you have to tell `structlog` about your processor by {doc}`configuring ` and render your event dictionary to JSON that is picked up by a log aggregation system like ELK or Graylog, `structlog` comes with batteries included -- you just have to tell it to use its {class}`~structlog.processors.JSONRenderer`: +So assuming you want to follow [best practices](logging-best-practices.md) and render your event dictionary to JSON that is picked up by a log aggregation system like ELK or Graylog, `structlog` comes with batteries included -- you just have to tell it to use its {class}`~structlog.processors.JSONRenderer`: ```{eval-rst} .. doctest:: @@ -178,13 +218,14 @@ So assuming you want to follow {doc}`best practices ` an {"event": "hi"} ``` + ## `structlog` and Standard Library's `logging` While `structlog`'s loggers are very fast and sufficient for the majority of our users, you're not bound to them. Instead, it's been designed from day one to wrap your *existing* loggers and **add** *structure* and *incremental context building* to them. -The most prominent example of such an "existing logger" is without doubt the logging module in the standard library. -To make this common case as simple as possible, `structlog` comes with [some tools](standard-library) to help you. +The most prominent example of such an "existing logger" is certainly the logging module in the standard library. +To make this common case as simple as possible, `structlog` comes with [some tools](standard-library.md) to help you. As noted before, the fastest way to transform `structlog` into a `logging`-friendly package is calling {func}`structlog.stdlib.recreate_defaults()`. From 6cb99346b51994dc81cabdd418debd2a215b245a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Oct 2022 10:41:29 +0200 Subject: [PATCH 0802/1520] MySTify best practices --- docs/logging-best-practices.md | 96 ++++++++++++++++++++++++++++ docs/logging-best-practices.rst | 108 -------------------------------- 2 files changed, 96 insertions(+), 108 deletions(-) create mode 100644 docs/logging-best-practices.md delete mode 100644 docs/logging-best-practices.rst diff --git a/docs/logging-best-practices.md b/docs/logging-best-practices.md new file mode 100644 index 00000000..0ecbeaad --- /dev/null +++ b/docs/logging-best-practices.md @@ -0,0 +1,96 @@ +# Logging Best Practices + +Logging is not a new concept and in no way special to Python. +Logfiles have existed for decades and there's little reason to reinvent the wheel in our little world. + +Therefore let's rely on proven tools as much as possible and do only the absolutely necessary inside of Python[^unix]. + +A simple but powerful approach is to log to unbuffered [standard out](https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29 +) and let other tools take care of the rest. +That can be your terminal window while developing, it can be [*systemd*](https://en.wikipedia.org/wiki/Systemd) redirecting your log entries to [*syslogd*](https://en.wikipedia.org/wiki/Syslogd), or your [cluster manager](https://kubernetes.io/docs/concepts/cluster-administration/logging/). +It doesn't matter where or how your application is running, it just works. + +This is why the popular [*Twelve-Factor App* methodology](https://12factor.net/logs) suggests just that. + +[^unix]: This is obviously a privileged UNIX-centric view but even Windows has tools and means for log management although we won't be able to discuss them here. + + +## Canonical Log Lines + +Generally speaking, having as few log entries per request as possible is a good thing. +The less noise, the more insights. + +`structlog`'s ability to {ref}`bind data to loggers incrementally ` -- plus {doc}`loggers that are local to the current execution context ` -- can help you to minimize the output to a *single log entry*. + +At Stripe, this concept is called [Canonical Log Lines](https://brandur.org/canonical-log-lines). + + +## Pretty Printing vs. Structured Output + +Colorful and pretty printed log messages are nice during development when you locally run your code. + +However, in production you should emit structured output (like JSON) which is a lot easier to parse by log aggregators. +Since you already log in a structured way, writing JSON output with `structlog` comes naturally. +You can even generate structured exception tracebacks. +This makes analyzing errors easier, since log aggregators can render JSON much better than multiline strings with a lot escaped quotation marks. + +Here is a simple example of how you can have pretty logs during development and JSON output when your app is running in a production context: + +```{eval-rst} +.. doctest:: + + >>> import sys + >>> import structlog + >>> + >>> shared_processors = [ + ... # Processors that have nothing to do with output, + ... # e.g., add timestamps or log level names. + ... ] + >>> if sys.stderr.isatty(): + ... # Pretty printing when we run in a terminal session. + ... # Automatically prints pretty tracebacks when "rich" is installed + ... processors = shared_processors + [ + ... structlog.dev.ConsoleRenderer(), + ... ] + ... else: + ... # Print JSON when we run, e.g., in a Docker container. + ... # Also print structured tracebacks. + ... processors = shared_processors + [ + ... structlog.processors.dict_tracebacks, + ... structlog.processors.JSONRenderer(), + ... ] + >>> structlog.configure(processors) + +``` + + +## Centralized Logging + +Nowadays you usually don't want your log files in compressed archives distributed over dozens -- if not thousands -- of servers or cluster nodes. +You want them in a single location. +Parsed, indexed, and easy to search. + + +### ELK + +The ELK stack ([*Elasticsearch*], [*Logstash*], [*Kibana*]) from Elastic is a great way to store, parse, and search your logs. + +The way it works is that you have local log shippers like [*Filebeat*] that parse your log files and forward the log entries to your [*Logstash*] server. +Logstash parses the log entries and stores them in [*Elasticsearch*]. +Finally, you can view and search them in [*Kibana*]. + +If your log entries consist of a JSON dictionary, this is fairly easy and efficient. +All you have to do is to tell [*Logstash*] either that your log entries are prepended with a timestamp from {class}`~structlog.processors.TimeStamper` or the name of your timestamp field. + + +### Graylog + +[Graylog](https://www.graylog.org/) goes one step further. +It not only supports everything those above do (and then some); you can also directly log JSON entries towards it -- optionally even through an AMQP server (like [*RabbitMQ*](https://www.rabbitmq.com/)) for better reliability. +Additionally, [Graylog's Extended Log Format](https://docs.graylog.org/docs/gelf) (GELF) allows for structured data which makes it an obvious choice to use together with `structlog`. + + +[*elasticsearch*]: https://www.elastic.co/elasticsearch +[*filebeat*]: https://github.com/elastic/beats/tree/master/filebeat +[*kibana*]: https://www.elastic.co/kibana +[*logstash*]: https://www.elastic.co/logstash diff --git a/docs/logging-best-practices.rst b/docs/logging-best-practices.rst deleted file mode 100644 index 45355bb6..00000000 --- a/docs/logging-best-practices.rst +++ /dev/null @@ -1,108 +0,0 @@ -====================== -Logging Best Practices -====================== - -Logging is not a new concept and in no way special to Python. -Logfiles have existed for decades and there's little reason to reinvent the wheel in our little world. - -Therefore let's rely on proven tools as much as possible and do only the absolutely necessary inside of Python\ [*]_. - -A simple but powerful approach is to log to unbuffered `standard out`_ and let other tools take care of the rest. -That can be your terminal window while developing, it can be systemd_ redirecting your log entries to syslogd_, or your `cluster manager`_. -It doesn't matter where or how your application is running, it just works. - -This is why the popular `twelve-factor app methodology`_ suggests just that. - -.. [*] This is obviously a privileged UNIX-centric view but even Windows has tools and means for log management although we won't be able to discuss them here. - - -Canonical Log Lines -=================== - -Generally speaking, having as few log entries per request as possible is a good thing. -The less noise, the more insights. - -``structlog``'s ability to :ref:`bind data to loggers incrementally ` -- plus :doc:`loggers that are local to the current execution context ` -- can help you to minimize the output to a *single log entry*. - -At Stripe, this concept is called `Canonical Log Lines `_. - - -Pretty Printing vs. Structured Output -===================================== - -Colorful and pretty printed log messages are nice during development when you locally run your code. - -However, in production you should emit structured output (like JSON) which is a lot easier to parse by log aggregators. -Since you already log in a structured way, writing JSON output with ``structlog`` comes naturally. -You can even generate structured exception tracebacks. -This makes analyzing errors easier, since log aggregators can render JSON much better than multiline strings with a lot escaped quotation marks. - -Here is a simple example of how you can have pretty logs during development and JSON output when your app is running in a production context: - -.. doctest:: - - >>> import sys - >>> import structlog - >>> - >>> shared_processors = [ - ... # Processors that have nothing to do with output, - ... # e.g., add timestamps or log level names. - ... ] - >>> if sys.stderr.isatty(): - ... # Pretty printing when we run in a terminal session. - ... # Automatically prints pretty tracebacks when "rich" is installed - ... processors = shared_processors + [ - ... structlog.dev.ConsoleRenderer(), - ... ] - ... else: - ... # Print JSON when we run, e.g., in a Docker container. - ... # Also print structured tracebacks. - ... processors = shared_processors + [ - ... structlog.processors.dict_tracebacks, - ... structlog.processors.JSONRenderer(), - ... ] - >>> structlog.configure(processors) - - -Centralized Logging -=================== - -Nowadays you usually don't want your logfiles in compressed archives distributed over dozens -- if not thousands -- of servers or cluster nodes. -You want them in a single location. -Parsed, indexed, and easy to search. - - -ELK ---- - -The ELK stack (Elasticsearch_, Logstash_, Kibana_) from Elastic is a great way to store, parse, and search your logs. - -The way it works is that you have local log shippers like Filebeat_ that parse your log files and forward the log entries to your Logstash_ server. -Logstash parses the log entries and stores them in Elasticsearch_. -Finally, you can view and search them in Kibana_. - -If your log entries consist of a JSON dictionary, this is fairly easy and efficient. -All you have to do is to tell Logstash_ either that your log entries are prepended with a timestamp from `TimeStamper` or the name of your timestamp field. - - -Graylog -------- - -Graylog_ goes one step further. -It not only supports everything those above do (and then some); you can also directly log JSON entries towards it -- optionally even through an AMQP server (like RabbitMQ_) for better reliability. -Additionally, `Graylog's Extended Log Format`_ (GELF) allows for structured data which makes it an obvious choice to use together with ``structlog``. - - -.. _Graylog: https://www.graylog.org/ -.. _Elastic: https://www.elastic.co/ -.. _Logstash: https://www.elastic.co/logstash -.. _Kibana: https://www.elastic.co/kibana -.. _Elasticsearch: https://www.elastic.co/elasticsearch -.. _`Graylog's Extended Log Format`: https://docs.graylog.org/docs/gelf -.. _`standard out`: https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29 -.. _syslogd: https://en.wikipedia.org/wiki/Syslogd -.. _`twelve-factor app methodology`: https://12factor.net/logs -.. _systemd: https://en.wikipedia.org/wiki/Systemd -.. _`cluster manager`: https://kubernetes.io/docs/concepts/cluster-administration/logging/ -.. _Filebeat: https://github.com/elastic/beats/tree/master/filebeat -.. _RabbitMQ: https://www.rabbitmq.com/ From 1606b8f1ec0d5d815be03846190a9fe6d0f076b5 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Oct 2022 10:45:36 +0200 Subject: [PATCH 0803/1520] MySTify testing --- docs/testing.md | 82 ++++++++++++++++++++++++++++++++++++++++++++++++ docs/testing.rst | 73 ------------------------------------------ 2 files changed, 82 insertions(+), 73 deletions(-) create mode 100644 docs/testing.md delete mode 100644 docs/testing.rst diff --git a/docs/testing.md b/docs/testing.md new file mode 100644 index 00000000..e1ae5882 --- /dev/null +++ b/docs/testing.md @@ -0,0 +1,82 @@ +# Testing + +`structlog` comes with tools for testing the logging behavior of your application. + +If you need functionality similar to {meth}`unittest.TestCase.assertLogs`, or you want to capture all logs for some other reason, you can use the {func}`structlog.testing.capture_logs` context manager: + +```{eval-rst} +.. doctest:: + + >>> from structlog import get_logger + >>> from structlog.testing import capture_logs + >>> with capture_logs() as cap_logs: + ... get_logger().bind(x="y").info("hello") + >>> cap_logs + [{'x': 'y', 'event': 'hello', 'log_level': 'info'}] +``` + +Note that inside the context manager all configured processors are disabled. + +:::{note} +`capture_logs()` relies on changing the configuration. +If you have *cache_logger_on_first_use* enabled for {doc}`performance `, any cached loggers will not be affected, so it’s recommended you do not enable it during tests. +::: + +You can build your own helpers using {class}`structlog.testing.LogCapture`. +For example a [*pytest*](https://docs.pytest.org/) fixture to capture log output could look like this: + +``` +@pytest.fixture(name="log_output") +def fixture_log_output(): + return LogCapture() + +@pytest.fixture(autouse=True) +def fixture_configure_structlog(log_output): + structlog.configure( + processors=[log_output] + ) + +def test_my_stuff(log_output): + do_something() + assert log_output.entries == [...] +``` + +______________________________________________________________________ + +You can also use {class}`structlog.testing.CapturingLogger` (directly, or via {class}`~structlog.testing.CapturingLoggerFactory` that always returns the same logger) that is more low-level and great for unit tests: + +```{eval-rst} +.. doctest:: + + >>> import structlog + >>> cf = structlog.testing.CapturingLoggerFactory() + >>> structlog.configure(logger_factory=cf, processors=[structlog.processors.JSONRenderer()]) + >>> log = get_logger() + >>> log.info("test!") + >>> cf.logger.calls + [CapturedCall(method_name='info', args=('{"event": "test!"}',), kwargs={})] +``` + +```{eval-rst} +.. testcleanup:: * + + import structlog + structlog.reset_defaults() +``` + +______________________________________________________________________ + +Additionally `structlog` also ships with a logger that just returns whatever it gets passed into it: {class}`structlog.testing.ReturnLogger`. + +```{eval-rst} +.. doctest:: + + >>> from structlog import ReturnLogger + >>> ReturnLogger().info(42) == 42 + True + >>> obj = ["hi"] + >>> ReturnLogger().info(obj) is obj + True + >>> ReturnLogger().info("hello", when="again") + (('hello',), {'when': 'again'}) +``` diff --git a/docs/testing.rst b/docs/testing.rst deleted file mode 100644 index fa1d7c9c..00000000 --- a/docs/testing.rst +++ /dev/null @@ -1,73 +0,0 @@ -Testing -------- - -``structlog`` comes with tools for testing the logging behavior of your application. - -If you need functionality similar to `unittest.TestCase.assertLogs`, or you want to capture all logs for some other reason, you can use the `structlog.testing.capture_logs` context manager: - -.. doctest:: - - >>> from structlog import get_logger - >>> from structlog.testing import capture_logs - >>> with capture_logs() as cap_logs: - ... get_logger().bind(x="y").info("hello") - >>> cap_logs - [{'x': 'y', 'event': 'hello', 'log_level': 'info'}] - -Note that inside the context manager all configured processors are disabled. - -.. note:: - - ``capture_logs()`` relies on changing the configuration. - If you have *cache_logger_on_first_use* enabled for :doc:`performance `, any cached loggers will not be affected, so it’s recommended you do not enable it during tests. - -You can build your own helpers using `structlog.testing.LogCapture`. -For example a `pytest `_ fixture to capture log output could look like this:: - - @pytest.fixture(name="log_output") - def fixture_log_output(): - return LogCapture() - - @pytest.fixture(autouse=True) - def fixture_configure_structlog(log_output): - structlog.configure( - processors=[log_output] - ) - - def test_my_stuff(log_output): - do_something() - assert log_output.entries == [...] - ----- - -You can also use `structlog.testing.CapturingLogger` (directly, or via `CapturingLoggerFactory` that always returns the same logger) that is more low-level and great for unit tests: - -.. doctest:: - - >>> import structlog - >>> cf = structlog.testing.CapturingLoggerFactory() - >>> structlog.configure(logger_factory=cf, processors=[structlog.processors.JSONRenderer()]) - >>> log = get_logger() - >>> log.info("test!") - >>> cf.logger.calls - [CapturedCall(method_name='info', args=('{"event": "test!"}',), kwargs={})] - -.. testcleanup:: * - - import structlog - structlog.reset_defaults() - ----- - -Additionally ``structlog`` also ships with a logger that just returns whatever it gets passed into it: `structlog.testing.ReturnLogger`. - -.. doctest:: - - >>> from structlog import ReturnLogger - >>> ReturnLogger().info(42) == 42 - True - >>> obj = ["hi"] - >>> ReturnLogger().info(obj) is obj - True - >>> ReturnLogger().info("hello", when="again") - (('hello',), {'when': 'again'}) From a338ed11e97896753de37b1322eefecedb47dd5b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Oct 2022 10:46:49 +0200 Subject: [PATCH 0804/1520] Simplify dividers --- docs/testing.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/testing.md b/docs/testing.md index e1ae5882..662a2283 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -41,7 +41,7 @@ def test_my_stuff(log_output): assert log_output.entries == [...] ``` -______________________________________________________________________ +--- You can also use {class}`structlog.testing.CapturingLogger` (directly, or via {class}`~structlog.testing.CapturingLoggerFactory` that always returns the same logger) that is more low-level and great for unit tests: @@ -64,7 +64,7 @@ You can also use {class}`structlog.testing.CapturingLogger` (directly, or via {c structlog.reset_defaults() ``` -______________________________________________________________________ +--- Additionally `structlog` also ships with a logger that just returns whatever it gets passed into it: {class}`structlog.testing.ReturnLogger`. From 291fbdbf963262f059a3e1361bed08eb8ca87432 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Oct 2022 10:50:14 +0200 Subject: [PATCH 0805/1520] Clarify we're a Markdown shop --- .github/CONTRIBUTING.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 62d63f5b..832d0a44 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -142,24 +142,24 @@ But it's way more comfortable to run it locally and *git* catching avoidable err ## Documentation -- Use [semantic newlines] in [*reStructuredText*] and [*Markdown*](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax) files (files ending in `.rst` and `.md`): +- We use [*Markdown*] everywhere except in `docs/api.rst` and docstrings. - ```rst +- Use [semantic newlines] in [*reStructuredText*] and [*Markdown*] files (files ending in `.rst` and `.md`): + + ```markdown This is a sentence. This is another sentence. ``` - If you start a new section, add two blank lines before and one blank line after the header, except if two headers follow immediately after each other: - ```rst + ```markdown Last line of previous section. - Header of New Top Section - ------------------------- + ## Header of New Top Section - Header of New Section - ^^^^^^^^^^^^^^^^^^^^^ + ### Header of New Section First line of new section. ``` @@ -187,6 +187,7 @@ If your change is noteworthy, there needs to be a changelog entry in [`CHANGELOG * Added `structlog.func()`. * `structlog.func()` now doesn't crash the Large Hadron Collider anymore when passed the *foobar* argument. + #### Example entries ```markdown @@ -210,3 +211,4 @@ or: [*tox*]: https://tox.wiki/ [semantic newlines]: https://rhodesmill.org/brandon/2012/one-sentence-per-line/ [*reStructuredText*]: https://www.sphinx-doc.org/en/stable/usage/restructuredtext/basics.html +[*Markdown*]: https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax From 0dd5eb8c6e1c9f2212143c66cc78069cda6f45c9 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Oct 2022 10:59:49 +0200 Subject: [PATCH 0806/1520] MySTify performance --- docs/performance.md | 99 ++++++++++++++++++++++++++++++++++++++++++++ docs/performance.rst | 99 -------------------------------------------- 2 files changed, 99 insertions(+), 99 deletions(-) create mode 100644 docs/performance.md delete mode 100644 docs/performance.rst diff --git a/docs/performance.md b/docs/performance.md new file mode 100644 index 00000000..5496168c --- /dev/null +++ b/docs/performance.md @@ -0,0 +1,99 @@ +# Performance + +`structlog`'s default configuration tries to be as unsurprising to new developers as possible. +Some of the choices made come with an avoidable performance price tag -- although its impact is debatable. + +Here are a few hints how to get most out of `structlog` in production: + +1. Use a specific wrapper class instead of the generic one. + `structlog` comes with ones for the {doc}`standard-library` and for {doc}`twisted`: + + ```python + configure(wrapper_class=structlog.stdlib.BoundLogger) + ``` + + `structlog` also comes with native log levels that are based on the ones from the standard library (read: we've copy and pasted them), but don't involve `logging`'s dynamic machinery. + That makes them *much* faster with a very similar API. + You can use {func}`structlog.make_filtering_bound_logger()` to create one. + +2. Avoid (frequently) calling log methods on loggers you get back from {func}`structlog.get_logger` or {func}`structlog.wrap_logger`. + Since those functions are usually called in module scope and thus before you are able to configure them, they return a proxy that assembles the correct logger on demand. + + Create a local logger if you expect to log frequently without binding: + + ```python + logger = structlog.get_logger() + def f(): + log = logger.bind() + for i in range(1000000000): + log.info("iterated", i=i) + ``` + +3. Set the *cache_logger_on_first_use* option to `True` so the aforementioned on-demand loggers will be assembled only once and cached for future uses: + + ```python + configure(cache_logger_on_first_use=True) + ``` + + This has two drawbacks: + + 1. Later calls of {func}`~structlog.configure` don't have any effect on already cached loggers -- that shouldn't matter outside of {doc}`testing ` though. + 2. The resulting bound logger is not pickleable. + Therefore, you can't set this option if you e.g. plan on passing loggers around using `multiprocessing`. + +4. Avoid sending your log entries through the standard library if you can: its dynamic nature and flexibility make it a major bottleneck. + Instead use {class}`structlog.WriteLoggerFactory` or -- if your serializer returns bytes (e.g. [*orjson*]) -- {class}`structlog.BytesLoggerFactory`. + + You can still configure `logging` for packages that you don't control, but avoid it for your *own* log entries. + +5. Use a faster JSON serializer than the standard library. + Possible alternatives are among others are [*orjson*] or [*RapidJSON*]. + +## Example + +Here's an example for a production-ready non-*asyncio* `structlog` configuration that's as fast as it gets: + +```python +import logging +import structlog + +structlog.configure( + cache_logger_on_first_use=True, + wrapper_class=structlog.make_filtering_bound_logger(logging.INFO), + processors=[ + structlog.contextvars.merge_contextvars, + structlog.processors.add_log_level, + structlog.processors.format_exc_info, + structlog.processors.TimeStamper(fmt="iso", utc=True), + structlog.processors.JSONRenderer(serializer=orjson.dumps), + ], + logger_factory=structlog.BytesLoggerFactory(), +) +``` + +It has the following properties: + +- Caches all loggers on first use. +- Filters all log entries below the `info` log level **very** efficiently. + The `debug` method literally consists of `return None`. +- Supports {doc}`contextvars` (thread-local contexts). +- Adds the log level name. +- Renders exceptions. +- Adds an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) timestamp under the `timestamp` key in the UTC timezone. +- Renders the log entries as JSON using [*orjson*] which is faster than plain logging in `logging`. +- Uses {class}`structlog.BytesLoggerFactory` because *orjson* returns bytes. + That saves encoding ping-pong. + +Therefore a log entry might look like this: + +```json +{"event":"hello","timestamp":"2020-11-17T09:54:11.900066Z"} +``` + +--- + +If you need standard library support for external projects, you can either just use a JSON formatter like [*python-json-logger*](https://pypi.org/project/python-json-logger/), or pipe them through `structlog` as documented in {doc}`standard-library`. + +[*orjson*]: https://github.com/ijl/orjson +[*rapidjson*]: https://pypi.org/project/python-rapidjson/ +[*simplejson*]: https://simplejson.readthedocs.io/ diff --git a/docs/performance.rst b/docs/performance.rst deleted file mode 100644 index 024b871e..00000000 --- a/docs/performance.rst +++ /dev/null @@ -1,99 +0,0 @@ -Performance -=========== - -``structlog``'s default configuration tries to be as unsurprising to new developers as possible. -Some of the choices made come with an avoidable performance price tag -- although its impact is debatable. - -Here are a few hints how to get most out of ``structlog`` in production: - -#. Use a specific wrapper class instead of the generic one. - ``structlog`` comes with ones for the :doc:`standard-library` and for :doc:`twisted`:: - - configure(wrapper_class=structlog.stdlib.BoundLogger) - - ``structlog`` also comes with native log levels that are based on the ones from the standard library (read: we've copy and pasted them), but don't involve `logging`'s dynamic machinery. - That makes them *much* faster. - You can use `structlog.make_filtering_bound_logger()` to create one. - - :doc:`Writing own wrapper classes ` is straightforward too. - -#. Avoid (frequently) calling log methods on loggers you get back from :func:`structlog.wrap_logger` and :func:`structlog.get_logger`. - Since those functions are usually called in module scope and thus before you are able to configure them, they return a proxy that assembles the correct logger on demand. - - Create a local logger if you expect to log frequently without binding:: - - logger = structlog.get_logger() - def f(): - log = logger.bind() - for i in range(1000000000): - log.info("iterated", i=i) - - -#. Set the *cache_logger_on_first_use* option to `True` so the aforementioned on-demand loggers will be assembled only once and cached for future uses:: - - configure(cache_logger_on_first_use=True) - - This has two drawbacks: - - 1. Later calls of :func:`~structlog.configure` don't have any effect on already cached loggers -- that shouldn't matter outside of :doc:`testing ` though. - 2. The resulting bound logger is not pickleable. - Therefore, you can't set this option if you e.g. plan on passing loggers around using `multiprocessing`. - -#. Avoid sending your log entries through the standard library if you can: its dynamic nature and flexibility make it a major bottleneck. - Instead use `structlog.WriteLoggerFactory` or -- if your serializer returns bytes (e.g. orjson_) -- `structlog.BytesLoggerFactory`. - - You can still configure `logging` for packages that you don't control, but avoid it for your *own* log entries. - -#. Use a faster JSON serializer than the standard library. - Possible alternatives are among others are orjson_ or RapidJSON_. - - -Example -------- - - -Here's an example for a production-ready non-asyncio ``structlog`` configuration that's as fast as it gets:: - - import logging - import structlog - - structlog.configure( - cache_logger_on_first_use=True, - wrapper_class=structlog.make_filtering_bound_logger(logging.INFO), - processors=[ - structlog.contextvars.merge_contextvars, - structlog.processors.add_log_level, - structlog.processors.format_exc_info, - structlog.processors.TimeStamper(fmt="iso", utc=True), - structlog.processors.JSONRenderer(serializer=orjson.dumps), - ], - logger_factory=structlog.BytesLoggerFactory(), - ) - -It has the following properties: - -- Caches all loggers on first use. -- Filters all log entries below the ``info`` log level **very** efficiently. - The ``debug`` method literally consists of ``return None``. -- Supports :doc:`contextvars` (thread-local contexts). -- Adds the log level name. -- Renders exceptions. -- Adds an `ISO 8601 `_ timestamp under the ``timestamp`` key in the UTC timezone. -- Renders the log entries as JSON using orjson_ which is faster than plain logging in `logging`. -- Uses `structlog.BytesLoggerFactory` because orjson returns bytes. - That saves encoding ping-pong. - -Therefore a log entry might look like this: - -.. code:: json - - {"event":"hello","timestamp":"2020-11-17T09:54:11.900066Z"} - ----- - -If you need standard library support for external projects, you can either just use a JSON formatter like `python-json-logger `_, or pipe them through ``structlog`` as documented in `standard-library`. - - -.. _simplejson: https://simplejson.readthedocs.io/ -.. _orjson: https://github.com/ijl/orjson -.. _RapidJSON: https://pypi.org/project/python-rapidjson/ From 66e5012187ae7b9929e318d9b6cfc810348b71fb Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Oct 2022 11:10:08 +0200 Subject: [PATCH 0807/1520] Give _loggers a more fitting name --- ...custom-wrappers.rst => custom-wrappers.md} | 24 ++++++++++--------- src/structlog/__init__.py | 2 +- src/structlog/_config.py | 2 +- src/structlog/{_loggers.py => _output.py} | 2 +- src/structlog/threadlocal.py | 2 +- tests/{test_loggers.py => test_output.py} | 2 +- 6 files changed, 18 insertions(+), 16 deletions(-) rename docs/{custom-wrappers.rst => custom-wrappers.md} (77%) rename src/structlog/{_loggers.py => _output.py} (99%) rename tests/{test_loggers.py => test_output.py} (99%) diff --git a/docs/custom-wrappers.rst b/docs/custom-wrappers.md similarity index 77% rename from docs/custom-wrappers.rst rename to docs/custom-wrappers.md index 5e431a66..f76b0aa2 100644 --- a/docs/custom-wrappers.rst +++ b/docs/custom-wrappers.md @@ -1,36 +1,38 @@ -Custom Wrappers -=============== +# Custom Wrappers +```{eval-rst} .. testsetup:: * import structlog structlog.configure( processors=[structlog.processors.KeyValueRenderer()], ) +``` +```{eval-rst} .. testcleanup:: * import structlog structlog.reset_defaults() +``` -``structlog`` comes with a generic bound logger called `structlog.BoundLogger` that can be used to wrap any logger class you fancy. +`structlog` comes with a generic bound logger called `structlog.BoundLogger` that can be used to wrap any logger class you fancy. It does so by intercepting unknown method names and proxying them to the wrapped logger. This works fine, except that it has a performance penalty and the API of `structlog.BoundLogger` isn't clear from reading the documentation because large parts depend on the wrapped logger. An additional reason is that you may want to have semantically meaningful log method names that add meta data to log entries as it is fit (see example below). -To solve that, ``structlog`` offers you to use an own wrapper class which you can configure using `structlog.configure`. +To solve that, `structlog` offers you to use an own wrapper class which you can configure using `structlog.configure`. And to make it easier for you, it comes with the class `structlog.BoundLoggerBase` which takes care of all data binding duties so you just add your log methods if you choose to sub-class it. +(wrapper-class-example)= -.. _wrapper_class-example: - -Example -------- +## Example It's much easier to demonstrate with an example: +```{eval-rst} .. doctest:: >>> from structlog import BoundLoggerBase, PrintLogger, wrap_logger @@ -47,14 +49,14 @@ It's much easier to demonstrate with an example: >>> log = log.bind(user="fprefect") >>> log.user_error("user.forgot_towel") user='fprefect' status='user_error' event='user.forgot_towel' +``` You can observe the following: - The wrapped logger can be found in the instance variable `structlog.BoundLoggerBase._logger`. -- The helper method `structlog.BoundLoggerBase._proxy_to_logger` that is a DRY_ convenience function that runs the processor chain, handles possible `structlog.DropEvent`\ s and calls a named function on `_logger`. +- The helper method `structlog.BoundLoggerBase._proxy_to_logger` that is a [DRY] convenience function that runs the processor chain, handles possible `structlog.DropEvent`s and calls a named function on `_logger`. - You can run the chain by hand through using `structlog.BoundLoggerBase._process_event` . These two methods and one attribute are all you need to write own wrapper classes. - -.. _DRY: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself +[dry]: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 7099e27c..e30bab9f 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -29,7 +29,7 @@ ) from structlog._generic import BoundLogger from structlog._log_levels import make_filtering_bound_logger -from structlog._loggers import ( +from structlog._output import ( BytesLogger, BytesLoggerFactory, PrintLogger, diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 36b602c5..72f3c5d7 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -15,7 +15,7 @@ from typing import Any, Callable, Iterable, Sequence, Type, cast from ._log_levels import make_filtering_bound_logger -from ._loggers import PrintLoggerFactory +from ._output import PrintLoggerFactory from .contextvars import merge_contextvars from .dev import ConsoleRenderer, _use_colors, set_exc_info from .processors import StackInfoRenderer, TimeStamper, add_log_level diff --git a/src/structlog/_loggers.py b/src/structlog/_output.py similarity index 99% rename from src/structlog/_loggers.py rename to src/structlog/_output.py index e2cd6f18..76e0a689 100644 --- a/src/structlog/_loggers.py +++ b/src/structlog/_output.py @@ -4,7 +4,7 @@ # repository for complete details. """ -Logger wrapper and helper class. +Logger classes responsible for output. """ from __future__ import annotations diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index 2ecd8621..a487a1a3 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -162,7 +162,7 @@ class _ThreadLocalDictWrapper: Useful for short-lived threaded applications like requests in web app. Use :func:`wrap` to instantiate and use - :func:`structlog._loggers.BoundLogger.new` to clear the context. + :func:`structlog.BoundLogger.new` to clear the context. """ _tl: Any diff --git a/tests/test_loggers.py b/tests/test_output.py similarity index 99% rename from tests/test_loggers.py rename to tests/test_output.py index 315be5a1..7b8e986a 100644 --- a/tests/test_loggers.py +++ b/tests/test_output.py @@ -19,7 +19,7 @@ WriteLogger, WriteLoggerFactory, ) -from structlog._loggers import WRITE_LOCKS +from structlog._output import WRITE_LOCKS from .utils import stdlib_log_methods From 0dbc0deba4195ee79df97705a7eb63e02fcf1b61 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Oct 2022 11:27:05 +0200 Subject: [PATCH 0808/1520] MySTify custom wrappers --- docs/custom-wrappers.md | 28 +++++++++++++++++----------- docs/loggers.rst | 3 +-- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/docs/custom-wrappers.md b/docs/custom-wrappers.md index f76b0aa2..1a814367 100644 --- a/docs/custom-wrappers.md +++ b/docs/custom-wrappers.md @@ -17,20 +17,26 @@ ``` -`structlog` comes with a generic bound logger called `structlog.BoundLogger` that can be used to wrap any logger class you fancy. -It does so by intercepting unknown method names and proxying them to the wrapped logger. +The object that is returned by {func}`structlog.get_logger()` is called a *bound logger*, or a *wrapper class* (because it wraps the original logger that takes care of the output). +This wrapper class is [configurable](configuration.md). -This works fine, except that it has a performance penalty and the API of `structlog.BoundLogger` isn't clear from reading the documentation because large parts depend on the wrapped logger. -An additional reason is that you may want to have semantically meaningful log method names that add meta data to log entries as it is fit (see example below). +Originally, `structlog` used a generic *bound logger* called {class}`structlog.BoundLogger` by default. +It can wrap *any* logger class by intercepting unknown method names and proxying them to the wrapped logger (that is in charge of output). -To solve that, `structlog` offers you to use an own wrapper class which you can configure using `structlog.configure`. -And to make it easier for you, it comes with the class `structlog.BoundLoggerBase` which takes care of all data binding duties so you just add your log methods if you choose to sub-class it. +Nowadays, the default is a {class}`structlog.types.FilteringBoundLogger` that imitates standard library's log levels with the possibility of efficiently filtering at a certain level (inactive log methods are a plain `return None`). + +If you're integrating with {mod}`logging` or Twisted, you may was to use one of their specific *bound loggers* ({class}`structlog.stdlib.BoundLogger` and {class}`structlog.twisted.BoundLogger`, respectively). + +--- + +But you can also write your own wrapper class. +To make it easy for you, `structlog` comes with the class {class}`structlog.BoundLoggerBase` which takes care of all data binding duties so you just add your log methods if you choose to sub-class it. (wrapper-class-example)= ## Example -It's much easier to demonstrate with an example: +It's easiest to demonstrate with an example: ```{eval-rst} .. doctest:: @@ -53,10 +59,10 @@ It's much easier to demonstrate with an example: You can observe the following: -- The wrapped logger can be found in the instance variable `structlog.BoundLoggerBase._logger`. -- The helper method `structlog.BoundLoggerBase._proxy_to_logger` that is a [DRY] convenience function that runs the processor chain, handles possible `structlog.DropEvent`s and calls a named function on `_logger`. -- You can run the chain by hand through using `structlog.BoundLoggerBase._process_event` . +- The wrapped logger can be found in the instance variable {attr}`structlog.BoundLoggerBase._logger`. +- The helper method {meth}`structlog.BoundLoggerBase._proxy_to_logger` that is a [DRY] convenience function that runs the processor chain, handles possible {class}`structlog.DropEvent`s and calls a named function on `_logger`. +- You can run the chain by hand through using {meth}`structlog.BoundLoggerBase._process_event` . -These two methods and one attribute are all you need to write own wrapper classes. +These two methods and one attribute are all you need to write own *bound loggers*. [dry]: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself diff --git a/docs/loggers.rst b/docs/loggers.rst index e7622a4b..35c6ec2f 100644 --- a/docs/loggers.rst +++ b/docs/loggers.rst @@ -1,7 +1,6 @@ Loggers ======= - Bound Loggers ------------- @@ -109,7 +108,7 @@ Additionally, the following arguments are allowed too: A class to use instead of :class:`~structlog.BoundLogger` for wrapping. This is useful if you want to sub-class BoundLogger and add custom logging methods. BoundLogger's bind/new methods are sub-classing-friendly so you won't have to re-implement them. - Please refer to the :ref:`related example ` for how this may look. + Please refer to the :ref:`related example ` for how this may look. **initial_values** The values that new wrapped loggers are automatically constructed with. From 80613673a4fdccf9ad2cb9aa9ba04049de72488d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Oct 2022 16:32:49 +0200 Subject: [PATCH 0809/1520] Wordsmith --- docs/custom-wrappers.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/custom-wrappers.md b/docs/custom-wrappers.md index 1a814367..bf169045 100644 --- a/docs/custom-wrappers.md +++ b/docs/custom-wrappers.md @@ -17,19 +17,19 @@ ``` -The object that is returned by {func}`structlog.get_logger()` is called a *bound logger*, or a *wrapper class* (because it wraps the original logger that takes care of the output). +The type of the *bound loggers* that are returned by {func}`structlog.get_logger()` is called the *wrapper class*, because it wraps the original logger that takes care of the output. This wrapper class is [configurable](configuration.md). -Originally, `structlog` used a generic *bound logger* called {class}`structlog.BoundLogger` by default. -It can wrap *any* logger class by intercepting unknown method names and proxying them to the wrapped logger (that is in charge of output). +Originally, `structlog` used a generic wrapper class {class}`structlog.BoundLogger` by default. +That class still ships with `structlog` and can wrap *any* logger class by intercepting unknown method names and proxying them to the wrapped logger. -Nowadays, the default is a {class}`structlog.types.FilteringBoundLogger` that imitates standard library's log levels with the possibility of efficiently filtering at a certain level (inactive log methods are a plain `return None`). +Nowadays, the default is a {class}`structlog.types.FilteringBoundLogger` that imitates standard library's log levels with the possibility of efficiently filtering at a certain level (inactive log methods are a plain `return None` each). If you're integrating with {mod}`logging` or Twisted, you may was to use one of their specific *bound loggers* ({class}`structlog.stdlib.BoundLogger` and {class}`structlog.twisted.BoundLogger`, respectively). --- -But you can also write your own wrapper class. +On top of that all, you can also write your own wrapper classes. To make it easy for you, `structlog` comes with the class {class}`structlog.BoundLoggerBase` which takes care of all data binding duties so you just add your log methods if you choose to sub-class it. (wrapper-class-example)= From a7a825944f6256a9589a7f6cc580a874fb2c28bd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Oct 2022 17:05:26 +0200 Subject: [PATCH 0810/1520] Clarify doc strings --- docs/bound-loggers.md | 124 +++++++++++++++++++++++++++++++++++++++ docs/loggers.rst | 123 -------------------------------------- src/structlog/_output.py | 6 +- 3 files changed, 127 insertions(+), 126 deletions(-) create mode 100644 docs/bound-loggers.md delete mode 100644 docs/loggers.rst diff --git a/docs/bound-loggers.md b/docs/bound-loggers.md new file mode 100644 index 00000000..6318d25a --- /dev/null +++ b/docs/bound-loggers.md @@ -0,0 +1,124 @@ +# Bound Loggers + +The centerpiece of `structlog` that you will interact with most is called a *bound logger*. +It is what you get back from `structlog.get_logger()` and call your logging methods on. + +It consists of three parts: + +```{image} _static/BoundLogger.svg +``` + +1. A *context dictionary* that you can *bind* key/value pairs to. + This dictionary is *merged* into each log entry that is logged from *this logger specifically*. + That means that every logger has it own context, but it is possible to have global contexts using {doc}`context variables `. +2. A list of {doc}`processors ` that are called on every log entry. + Each processor receives the return value of its predecessor passed as an argument. +3. And finally a *logger* that it's wrapping. + This wrapped logger is responsible for the *output* of the log entry that has been returned by the last processor. + This *can* be standard library's {class}`logging.Logger`, but absolutely doesn't have to. + Bound loggers themselves do *not* do any I/O themselves. + +To manipulate the context dictionary, it offers to: + +- Recreate itself with (optional) *additional* context data: {func}`~structlog.BoundLogger.bind` and {func}`~structlog.BoundLogger.new`. +- Recreate itself with *less* context data: {func}`~structlog.BoundLogger.unbind`. + +In any case, the original bound logger or its context are never mutated. + +Finally, if you call *any other* method on {class}`~structlog.BoundLogger`, it will: + +1. Make a copy of the context -- now it becomes the *event dictionary*, +2. Add the keyword arguments of the method call to the event dict. +3. Add a new key `event` with the value of the first positional argument of the method call to the event dict. +4. Run the processors successively on the event dict. + Each processor receives the result of its predecessor. +5. Finally, it takes the result of the final processor and calls the method with the same name – that got called on the bound logger – on the wrapped logger[^id3]. + For flexibility, the final processor can return either a string[^id4] that is passed directly as a positional parameter, or a tuple `(args, kwargs)` that are passed as `wrapped_logger.log_method(*args, **kwargs)`. + +[^id3]: Since this is slightly magicy, `structlog` comes with concrete loggers for the `standard-library` and {doc}`twisted` that offer you explicit APIs for the supported logging methods but behave identically like the generic BoundLogger otherwise. + Of course, you are free to implement your own bound loggers too. + +[^id4]: `str`, `bytes`, or `bytearray` to be exact. + +## Creation + +You won't be instantiating bound loggers yourself. +In practice you will configure `structlog` as explained in the `next chapter ` and then just call `structlog.get_logger`. + +In some rare cases you may not want to do that. +For that times there is the `structlog.wrap_logger` function that can be used to wrap a logger without any global state (i.e. configuration): + +(proc)= + +```{eval-rst} +.. doctest:: + + >>> import structlog + >>> class CustomPrintLogger: + ... def msg(self, message): + ... print(message) + >>> def proc(logger, method_name, event_dict): + ... print("I got called with", event_dict) + ... return repr(event_dict) + >>> log = structlog.wrap_logger( + ... CustomPrintLogger(), + ... wrapper_class=structlog.BoundLogger, + ... processors=[proc], + ... ) + >>> log2 = log.bind(x=42) + >>> log == log2 + False + >>> log.msg("hello world") + I got called with {'event': 'hello world'} + {'event': 'hello world'} + >>> log2.msg("hello world") + I got called with {'x': 42, 'event': 'hello world'} + {'x': 42, 'event': 'hello world'} + >>> log3 = log2.unbind("x") + >>> log == log3 + True + >>> log3.msg("nothing bound anymore", foo="but you can structure the event too") + I got called with {'foo': 'but you can structure the event too', 'event': 'nothing bound anymore'} + {'foo': 'but you can structure the event too', 'event': 'nothing bound anymore'} +``` + +As you can see, it accepts one mandatory and a few optional arguments: + +**logger** + +: The one and only positional argument is the logger that you want to wrap and to which the log entries will be proxied. + If you wish to use a {ref}`configured logger factory `, set it to `None`. + +**processors** + +: A list of callables that can {doc}`filter, mutate, and format ` the log entry before it gets passed to the wrapped logger. + + Default is `[`{class}`~structlog.processors.StackInfoRenderer`, {func}`~structlog.processors.format_exc_info`, {class}`~structlog.processors.TimeStamper`, {class}`~structlog.dev.ConsoleRenderer``]`. + +**context_class** + +: The class to save your context in. + + Since all supported Python versions have ordered dictionaries, the default is a plain `dict`. + +Additionally, the following arguments are allowed too: + +**wrapper_class** + +: A class to use instead of {class}`~structlog.BoundLogger` for wrapping. + This is useful if you want to sub-class BoundLogger and add custom logging methods. + BoundLogger's bind/new methods are sub-classing-friendly so you won't have to re-implement them. + Please refer to the {ref}`related example ` for how this may look. + +**initial_values** + +: The values that new wrapped loggers are automatically constructed with. + Useful, for example, if you want to have the module name as part of the context. + +:::{note} +Free your mind from the preconception that log entries have to be serialized to strings eventually. +All `structlog` cares about is a *dictionary* of *keys* and *values*. +What happens to it depends on the logger you wrap and your processors alone. + +This gives you the power to log directly to databases, log aggregation servers, web services, and whatnot. +::: diff --git a/docs/loggers.rst b/docs/loggers.rst deleted file mode 100644 index 35c6ec2f..00000000 --- a/docs/loggers.rst +++ /dev/null @@ -1,123 +0,0 @@ -Loggers -======= - -Bound Loggers -------------- - -The centerpiece of ``structlog`` that you will interact with most is called a *bound logger*. -It is what you get back from `structlog.get_logger()` and call your logging methods on. - -It consists of three parts: - -.. image:: _static/BoundLogger.svg - -#. A *context dictionary* that you can *bind* key/value pairs to. - This dictionary is *merged* into each log entry that is logged from *this logger specifically*. - That means that every logger has it own context, but it is possible to have global contexts using :doc:`context variables `. -#. A list of :doc:`processors ` that are called on every log entry. - Each processor receives the return value of its predecessor passed as an argument. -#. And finally a *logger* that it's wrapping. - This wrapped logger is responsible for the *output* of the log entry that has been returned by the last processor. - This *can* be standard library's `logging.Logger`, but absolutely doesn't have to. - Bound loggers themselves do *not* do any I/O themselves. - -To manipulate the context dictionary, it offers to: - -- Recreate itself with (optional) *additional* context data: :func:`~structlog.BoundLogger.bind` and :func:`~structlog.BoundLogger.new`. -- Recreate itself with *less* context data: :func:`~structlog.BoundLogger.unbind`. - -In any case, the original bound logger or its context are never mutated. - -Finally, if you call *any other* method on :class:`~structlog.BoundLogger`, it will: - -#. Make a copy of the context -- now it becomes the *event dictionary*, -#. Add the keyword arguments of the method call to the event dict. -#. Add a new key ``event`` with the value of the first positional argument of the method call to the event dict. -#. Run the processors successively on the event dict. - Each processor receives the result of its predecessor. -#. Finally, it takes the result of the final processor and calls the method with the same name – that got called on the bound logger – on the wrapped logger\ [1]_. - For flexibility, the final processor can return either a string\ [2]_ that is passed directly as a positional parameter, or a tuple ``(args, kwargs)`` that are passed as ``wrapped_logger.log_method(*args, **kwargs)``. - - -.. [1] Since this is slightly magicy, ``structlog`` comes with concrete loggers for the `standard-library` and :doc:`twisted` that offer you explicit APIs for the supported logging methods but behave identically like the generic BoundLogger otherwise. - Of course, you are free to implement your own bound loggers too. -.. [2] `str`, `bytes`, or `bytearray` to be exact. - - -Creation --------- - -You won't be instantiating bound loggers yourself. -In practice you will configure ``structlog`` as explained in the `next chapter ` and then just call `structlog.get_logger`. - - -In some rare cases you may not want to do that. -For that times there is the `structlog.wrap_logger` function that can be used to wrap a logger without any global state (i.e. configuration): - -.. _proc: - -.. doctest:: - - >>> import structlog - >>> class CustomPrintLogger: - ... def msg(self, message): - ... print(message) - >>> def proc(logger, method_name, event_dict): - ... print("I got called with", event_dict) - ... return repr(event_dict) - >>> log = structlog.wrap_logger( - ... CustomPrintLogger(), - ... wrapper_class=structlog.BoundLogger, - ... processors=[proc], - ... ) - >>> log2 = log.bind(x=42) - >>> log == log2 - False - >>> log.msg("hello world") - I got called with {'event': 'hello world'} - {'event': 'hello world'} - >>> log2.msg("hello world") - I got called with {'x': 42, 'event': 'hello world'} - {'x': 42, 'event': 'hello world'} - >>> log3 = log2.unbind("x") - >>> log == log3 - True - >>> log3.msg("nothing bound anymore", foo="but you can structure the event too") - I got called with {'foo': 'but you can structure the event too', 'event': 'nothing bound anymore'} - {'foo': 'but you can structure the event too', 'event': 'nothing bound anymore'} - -As you can see, it accepts one mandatory and a few optional arguments: - -**logger** - The one and only positional argument is the logger that you want to wrap and to which the log entries will be proxied. - If you wish to use a :ref:`configured logger factory `, set it to `None`. - -**processors** - A list of callables that can :doc:`filter, mutate, and format ` the log entry before it gets passed to the wrapped logger. - - Default is ``[``:class:`~structlog.processors.StackInfoRenderer`, :func:`~structlog.processors.format_exc_info`, :class:`~structlog.processors.TimeStamper`, :class:`~structlog.dev.ConsoleRenderer`\ ``]``. - -**context_class** - The class to save your context in. - - Since all supported Python versions have ordered dictionaries, the default is a plain `dict`. - -Additionally, the following arguments are allowed too: - -**wrapper_class** - A class to use instead of :class:`~structlog.BoundLogger` for wrapping. - This is useful if you want to sub-class BoundLogger and add custom logging methods. - BoundLogger's bind/new methods are sub-classing-friendly so you won't have to re-implement them. - Please refer to the :ref:`related example ` for how this may look. - -**initial_values** - The values that new wrapped loggers are automatically constructed with. - Useful, for example, if you want to have the module name as part of the context. - -.. note:: - - Free your mind from the preconception that log entries have to be serialized to strings eventually. - All ``structlog`` cares about is a *dictionary* of *keys* and *values*. - What happens to it depends on the logger you wrap and your processors alone. - - This gives you the power to log directly to databases, log aggregation servers, web services, and whatnot. diff --git a/src/structlog/_output.py b/src/structlog/_output.py index 76e0a689..5b0b915e 100644 --- a/src/structlog/_output.py +++ b/src/structlog/_output.py @@ -47,7 +47,7 @@ class PrintLogger: Useful if you follow `current logging best practices `. - Also very useful for testing and examples since logging is finicky in + Also very useful for testing and examples since `logging` is finicky in doctests. .. versionchanged:: 22.1 @@ -149,10 +149,10 @@ class WriteLogger: Useful if you follow `current logging best practices `. - Also very useful for testing and examples since logging is finicky in + Also very useful for testing and examples since `logging` is finicky in doctests. - A little faster and a little less versatile than the PrintLogger. + A little faster and a little less versatile than `structlog.PrintLogger`. .. versionadded:: 22.1 """ From 7ed7a311e8367bf0ae42540311eb7e27ea3c0592 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Oct 2022 17:20:37 +0200 Subject: [PATCH 0811/1520] Streamline bound-loggers --- docs/api.rst | 2 +- docs/bound-loggers.md | 79 +++++++++++++------------------------------ docs/index.md | 2 +- 3 files changed, 26 insertions(+), 57 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 1455cd31..7cd05422 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -67,7 +67,7 @@ API Reference .. autoexception:: DropEvent .. autoclass:: BoundLoggerBase - :members: new, bind, unbind, _logger, _process_event, _proxy_to_logger + :members: new, bind, unbind, try_unbind, _logger, _process_event, _proxy_to_logger `structlog.dev` Module diff --git a/docs/bound-loggers.md b/docs/bound-loggers.md index 6318d25a..3be36a97 100644 --- a/docs/bound-loggers.md +++ b/docs/bound-loggers.md @@ -15,16 +15,24 @@ It consists of three parts: Each processor receives the return value of its predecessor passed as an argument. 3. And finally a *logger* that it's wrapping. This wrapped logger is responsible for the *output* of the log entry that has been returned by the last processor. - This *can* be standard library's {class}`logging.Logger`, but absolutely doesn't have to. - Bound loggers themselves do *not* do any I/O themselves. + This *can* be standard library's {class}`logging.Logger`, but absolutely doesn't have to: + By default it's `structlog`'s {class}`structlog.PrintLogger`. -To manipulate the context dictionary, it offers to: +:::{important} +Bound loggers themselves do *not* do any I/O themselves. -- Recreate itself with (optional) *additional* context data: {func}`~structlog.BoundLogger.bind` and {func}`~structlog.BoundLogger.new`. -- Recreate itself with *less* context data: {func}`~structlog.BoundLogger.unbind`. +All they do is managing the *context* and proxying log calls to a *wrapped logger*. +::: + +To manipulate the context dictionary, a *bound logger* offers to: + +- Recreate itself with (optional) *additional* context data: {func}`~structlog.BoundLoggerBase.bind` and {func}`~structlog.BoundLoggerBase.new`. +- Recreate itself with *less* context data: {func}`~structlog.BoundLoggerBase.unbind` and {func}`~structlog.BoundLoggerBase.try_unbind`. In any case, the original bound logger or its context are never mutated. +--- + Finally, if you call *any other* method on {class}`~structlog.BoundLogger`, it will: 1. Make a copy of the context -- now it becomes the *event dictionary*, @@ -32,21 +40,23 @@ Finally, if you call *any other* method on {class}`~structlog.BoundLogger`, it w 3. Add a new key `event` with the value of the first positional argument of the method call to the event dict. 4. Run the processors successively on the event dict. Each processor receives the result of its predecessor. -5. Finally, it takes the result of the final processor and calls the method with the same name – that got called on the bound logger – on the wrapped logger[^id3]. - For flexibility, the final processor can return either a string[^id4] that is passed directly as a positional parameter, or a tuple `(args, kwargs)` that are passed as `wrapped_logger.log_method(*args, **kwargs)`. +5. Finally, it takes the result of the final processor and calls the method with the same name – that got called on the bound logger – on the wrapped logger[^explicit]. + For flexibility, the final processor can return either a string[^str] that is passed directly as a positional parameter, or a tuple `(args, kwargs)` that are passed as `wrapped_logger.log_method(*args, **kwargs)`. -[^id3]: Since this is slightly magicy, `structlog` comes with concrete loggers for the `standard-library` and {doc}`twisted` that offer you explicit APIs for the supported logging methods but behave identically like the generic BoundLogger otherwise. +[^explicit]: Since this is slightly magical, `structlog` comes with concrete loggers for the `standard-library` and {doc}`twisted` that offer you explicit APIs for the supported logging methods but behave identically like the generic BoundLogger otherwise. Of course, you are free to implement your own bound loggers too. -[^id4]: `str`, `bytes`, or `bytearray` to be exact. +[^str]: `str`, `bytes`, or `bytearray` to be exact. + -## Creation +## Wrapping Loggers Explicitly -You won't be instantiating bound loggers yourself. -In practice you will configure `structlog` as explained in the `next chapter ` and then just call `structlog.get_logger`. +In practice, you won't be instantiating bound loggers yourself. +You will configure `structlog` as explained in the {doc}`next chapter ` and then just call {func}`structlog.get_logger`. -In some rare cases you may not want to do that. -For that times there is the `structlog.wrap_logger` function that can be used to wrap a logger without any global state (i.e. configuration): +However, in some rare cases you may not want to do that. +For example because you don't control how you get the logger that you would like to wrap (famous example: *Celery*). +For that times there is the {func}`structlog.wrap_logger` function that can be used to wrap a logger -- optionally without any global state (i.e. configuration): (proc)= @@ -81,44 +91,3 @@ For that times there is the `structlog.wrap_logger` function that can be used to I got called with {'foo': 'but you can structure the event too', 'event': 'nothing bound anymore'} {'foo': 'but you can structure the event too', 'event': 'nothing bound anymore'} ``` - -As you can see, it accepts one mandatory and a few optional arguments: - -**logger** - -: The one and only positional argument is the logger that you want to wrap and to which the log entries will be proxied. - If you wish to use a {ref}`configured logger factory `, set it to `None`. - -**processors** - -: A list of callables that can {doc}`filter, mutate, and format ` the log entry before it gets passed to the wrapped logger. - - Default is `[`{class}`~structlog.processors.StackInfoRenderer`, {func}`~structlog.processors.format_exc_info`, {class}`~structlog.processors.TimeStamper`, {class}`~structlog.dev.ConsoleRenderer``]`. - -**context_class** - -: The class to save your context in. - - Since all supported Python versions have ordered dictionaries, the default is a plain `dict`. - -Additionally, the following arguments are allowed too: - -**wrapper_class** - -: A class to use instead of {class}`~structlog.BoundLogger` for wrapping. - This is useful if you want to sub-class BoundLogger and add custom logging methods. - BoundLogger's bind/new methods are sub-classing-friendly so you won't have to re-implement them. - Please refer to the {ref}`related example ` for how this may look. - -**initial_values** - -: The values that new wrapped loggers are automatically constructed with. - Useful, for example, if you want to have the module name as part of the context. - -:::{note} -Free your mind from the preconception that log entries have to be serialized to strings eventually. -All `structlog` cares about is a *dictionary* of *keys* and *values*. -What happens to it depends on the logger you wrap and your processors alone. - -This gives you the power to log directly to databases, log aggregation servers, web services, and whatnot. -::: diff --git a/docs/index.md b/docs/index.md index 694e00b4..b3d4055b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -29,7 +29,7 @@ Release **{sub-ref}`release`** ([What's new?](changelog)) why getting-started -loggers +bound-loggers configuration processors contextvars From 0bc9c6c6de38a0206bf00bd8da4a92d794d5a5db Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Oct 2022 17:25:34 +0200 Subject: [PATCH 0812/1520] Fix links --- docs/bound-loggers.md | 2 +- docs/getting-started.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/bound-loggers.md b/docs/bound-loggers.md index 3be36a97..f22e2c4a 100644 --- a/docs/bound-loggers.md +++ b/docs/bound-loggers.md @@ -1,7 +1,7 @@ # Bound Loggers The centerpiece of `structlog` that you will interact with most is called a *bound logger*. -It is what you get back from `structlog.get_logger()` and call your logging methods on. +It is what you get back from {func}`structlog.get_logger()` and call your logging methods on. It consists of three parts: diff --git a/docs/getting-started.md b/docs/getting-started.md index dbad32b2..b36632a6 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -232,7 +232,7 @@ As noted before, the fastest way to transform `structlog` into a `logging`-frien ## Liked what you saw? -Now you're all set for the rest of the user's guide and can start reading about [bound loggers](loggers) -- the heart of `structlog`. +Now you're all set for the rest of the user's guide and can start reading about [bound loggers](bound-loggers.md) -- the heart of `structlog`. [*better-exceptions*]: https://github.com/qix-/better-exceptions From 8758d185d83541135e42202508cdb81c8549858b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Oct 2022 17:27:17 +0200 Subject: [PATCH 0813/1520] Let key / value breath --- CHANGELOG.md | 2 +- docs/bound-loggers.md | 2 +- docs/contextvars.md | 2 +- docs/why.md | 8 ++++---- tests/test_contextvars.py | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea222a00..dd951f8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -138,7 +138,7 @@ So please make sure to **always** properly configure your applications. ### Added -- Added the `structlog.threadlocal.bound_threadlocal` and `structlog.contextvars.bound_contextvars` decorator/context managers to temporarily bind key/value pairs to a thread-local and context-local context. +- Added the `structlog.threadlocal.bound_threadlocal` and `structlog.contextvars.bound_contextvars` decorator/context managers to temporarily bind key / value pairs to a thread-local and context-local context. [#371](https://github.com/hynek/structlog/pull/371) diff --git a/docs/bound-loggers.md b/docs/bound-loggers.md index f22e2c4a..e6578104 100644 --- a/docs/bound-loggers.md +++ b/docs/bound-loggers.md @@ -8,7 +8,7 @@ It consists of three parts: ```{image} _static/BoundLogger.svg ``` -1. A *context dictionary* that you can *bind* key/value pairs to. +1. A *context dictionary* that you can *bind* key / value pairs to. This dictionary is *merged* into each log entry that is logged from *this logger specifically*. That means that every logger has it own context, but it is possible to have global contexts using {doc}`context variables `. 2. A list of {doc}`processors ` that are called on every log entry. diff --git a/docs/contextvars.md b/docs/contextvars.md index d0a6a01e..9a292888 100644 --- a/docs/contextvars.md +++ b/docs/contextvars.md @@ -67,7 +67,7 @@ We're sorry the word *context* means three different things in this itemization >>> unbind_contextvars("b") >>> log.info("world") event='world' a=1 - >>> # You can also bind key/value pairs temporarily. + >>> # You can also bind key / value pairs temporarily. >>> with bound_contextvars(b=2): ... log.info("hi") event='hi' a=1 b=2 diff --git a/docs/why.md b/docs/why.md index ef75a5a4..33d82c4b 100644 --- a/docs/why.md +++ b/docs/why.md @@ -19,7 +19,7 @@ Instead, you log *events* that happen in a *context* of key / value pairs. ## Easier Logging -You can stop writing prose and start thinking in terms of an event that happens in the context of key/value pairs: +You can stop writing prose and start thinking in terms of an event that happens in the context of key / value pairs: ```pycon >>> from structlog import get_logger @@ -40,7 +40,7 @@ You can still use string interpolation using positional arguments: ## Data Binding -Since log entries are dictionaries, you can start binding and re-binding key/value pairs to your loggers to ensure they are present in every following logging call: +Since log entries are dictionaries, you can start binding and re-binding key / value pairs to your loggers to ensure they are present in every following logging call: ```pycon >>> log = log.bind(user="anonymous", some_key=23) @@ -49,7 +49,7 @@ Since log entries are dictionaries, you can start binding and re-binding key/val 2020-11-18 09:18:28 [info ] user.logged_in another_key=42 happy=True some_key=23 user=hynek ``` -You can also bind key/value pairs to {doc}`context variables ` that look global, but are local to your thread or *asyncio* context (i.e. usually your request). +You can also bind key / value pairs to {doc}`context variables ` that look global, but are local to your thread or *asyncio* context (i.e. usually your request). ## Powerful Pipelines @@ -76,7 +76,7 @@ There are [plenty of processors](structlog.processors) for most common tasks com `structlog` is completely flexible about *how* the resulting log entry is emitted. Since each log entry is a dictionary, it can be formatted to **any** format: -- A colorful key/value format for [local development](https://www.structlog.org/en/stable/development.html), +- A colorful key / value format for [local development](https://www.structlog.org/en/stable/development.html), - [JSON](https://www.structlog.org/en/stable/api.html#structlog.processors.JSONRenderer) for easy parsing, - or some standard format you have parsers for like *nginx* or Apache *httpd*. diff --git a/tests/test_contextvars.py b/tests/test_contextvars.py index 4117ef35..d2e9b048 100644 --- a/tests/test_contextvars.py +++ b/tests/test_contextvars.py @@ -211,8 +211,8 @@ async def coro2(): def test_get_only_gets_structlog_without_deleted(self): """ - get_contextvars returns only the structlog-specific key/values with the - prefix removed. Deleted keys (= Ellipsis) are ignored. + get_contextvars returns only the structlog-specific key / values with + the prefix removed. Deleted keys (= Ellipsis) are ignored. """ bind_contextvars(a=1, b=2) unbind_contextvars("b") From cfbfa9f31546a51fb57d2ac6196a11c14aabb627 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 11 Oct 2022 09:35:19 +0200 Subject: [PATCH 0814/1520] Actually, it's key-value --- CHANGELOG.md | 2 +- docs/bound-loggers.md | 2 +- docs/contextvars.md | 2 +- docs/why.md | 10 +++++----- tests/test_contextvars.py | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd951f8d..f66ba089 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -138,7 +138,7 @@ So please make sure to **always** properly configure your applications. ### Added -- Added the `structlog.threadlocal.bound_threadlocal` and `structlog.contextvars.bound_contextvars` decorator/context managers to temporarily bind key / value pairs to a thread-local and context-local context. +- Added the `structlog.threadlocal.bound_threadlocal` and `structlog.contextvars.bound_contextvars` decorator/context managers to temporarily bind key-value pairs to a thread-local and context-local context. [#371](https://github.com/hynek/structlog/pull/371) diff --git a/docs/bound-loggers.md b/docs/bound-loggers.md index e6578104..08b57f38 100644 --- a/docs/bound-loggers.md +++ b/docs/bound-loggers.md @@ -8,7 +8,7 @@ It consists of three parts: ```{image} _static/BoundLogger.svg ``` -1. A *context dictionary* that you can *bind* key / value pairs to. +1. A *context dictionary* that you can *bind* key-value pairs to. This dictionary is *merged* into each log entry that is logged from *this logger specifically*. That means that every logger has it own context, but it is possible to have global contexts using {doc}`context variables `. 2. A list of {doc}`processors ` that are called on every log entry. diff --git a/docs/contextvars.md b/docs/contextvars.md index 9a292888..b43111a5 100644 --- a/docs/contextvars.md +++ b/docs/contextvars.md @@ -67,7 +67,7 @@ We're sorry the word *context* means three different things in this itemization >>> unbind_contextvars("b") >>> log.info("world") event='world' a=1 - >>> # You can also bind key / value pairs temporarily. + >>> # You can also bind key-value pairs temporarily. >>> with bound_contextvars(b=2): ... log.info("hi") event='hi' a=1 b=2 diff --git a/docs/why.md b/docs/why.md index 33d82c4b..faf97179 100644 --- a/docs/why.md +++ b/docs/why.md @@ -12,14 +12,14 @@ > —[Paul Querna](https://paul.querna.org/articles/2011/12/26/log-for-machines-in-json/) Structured logging means that you don't write hard-to-parse and hard-to-keep-consistent prose in your log entries. -Instead, you log *events* that happen in a *context* of key / value pairs. +Instead, you log *events* that happen in a *context* of key-value pairs. ## … structlog? ## Easier Logging -You can stop writing prose and start thinking in terms of an event that happens in the context of key / value pairs: +You can stop writing prose and start thinking in terms of an event that happens in the context of key-value pairs: ```pycon >>> from structlog import get_logger @@ -40,7 +40,7 @@ You can still use string interpolation using positional arguments: ## Data Binding -Since log entries are dictionaries, you can start binding and re-binding key / value pairs to your loggers to ensure they are present in every following logging call: +Since log entries are dictionaries, you can start binding and re-binding key-value pairs to your loggers to ensure they are present in every following logging call: ```pycon >>> log = log.bind(user="anonymous", some_key=23) @@ -49,7 +49,7 @@ Since log entries are dictionaries, you can start binding and re-binding key / v 2020-11-18 09:18:28 [info ] user.logged_in another_key=42 happy=True some_key=23 user=hynek ``` -You can also bind key / value pairs to {doc}`context variables ` that look global, but are local to your thread or *asyncio* context (i.e. usually your request). +You can also bind key-value pairs to {doc}`context variables ` that look global, but are local to your thread or *asyncio* context (i.e. usually your request). ## Powerful Pipelines @@ -76,7 +76,7 @@ There are [plenty of processors](structlog.processors) for most common tasks com `structlog` is completely flexible about *how* the resulting log entry is emitted. Since each log entry is a dictionary, it can be formatted to **any** format: -- A colorful key / value format for [local development](https://www.structlog.org/en/stable/development.html), +- A colorful key-value format for [local development](https://www.structlog.org/en/stable/development.html), - [JSON](https://www.structlog.org/en/stable/api.html#structlog.processors.JSONRenderer) for easy parsing, - or some standard format you have parsers for like *nginx* or Apache *httpd*. diff --git a/tests/test_contextvars.py b/tests/test_contextvars.py index d2e9b048..12535845 100644 --- a/tests/test_contextvars.py +++ b/tests/test_contextvars.py @@ -211,7 +211,7 @@ async def coro2(): def test_get_only_gets_structlog_without_deleted(self): """ - get_contextvars returns only the structlog-specific key / values with + get_contextvars returns only the structlog-specific key-values with the prefix removed. Deleted keys (= Ellipsis) are ignored. """ bind_contextvars(a=1, b=2) From d2328168e12a42d6f8c1353025c391053f250551 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 11 Oct 2022 09:35:02 +0200 Subject: [PATCH 0815/1520] Fix header levels --- docs/why.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/why.md b/docs/why.md index faf97179..41b6b886 100644 --- a/docs/why.md +++ b/docs/why.md @@ -17,7 +17,7 @@ Instead, you log *events* that happen in a *context* of key-value pairs. ## … structlog? -## Easier Logging +### Easier Logging You can stop writing prose and start thinking in terms of an event that happens in the context of key-value pairs: @@ -38,7 +38,7 @@ You can still use string interpolation using positional arguments: 2022-10-10 07:19:25 [info ] Hello, world! ``` -## Data Binding +### Data Binding Since log entries are dictionaries, you can start binding and re-binding key-value pairs to your loggers to ensure they are present in every following logging call: @@ -52,7 +52,7 @@ Since log entries are dictionaries, you can start binding and re-binding key-val You can also bind key-value pairs to {doc}`context variables ` that look global, but are local to your thread or *asyncio* context (i.e. usually your request). -## Powerful Pipelines +### Powerful Pipelines Each log entry goes through a [processor pipeline](processors.md) that is just a chain of functions that receive a dictionary and return a new dictionary that gets fed into the next function. That allows for simple but powerful data manipulation: @@ -71,7 +71,7 @@ There are [plenty of processors](structlog.processors) for most common tasks com - Flexible [timestamping](structlog.processors.TimeStamper). -## Formatting +### Formatting `structlog` is completely flexible about *how* the resulting log entry is emitted. Since each log entry is a dictionary, it can be formatted to **any** format: @@ -84,7 +84,7 @@ Internally, formatters are processors whose return value (usually a string) is p `structlog` comes with multiple useful formatters out-of-the-box. -## Output +### Output `structlog` is also flexible with the final output of your log entries: @@ -98,7 +98,7 @@ Internally, formatters are processors whose return value (usually a string) is p `structlog` passes you a dictionary and you can do with it whatever you want. Reported use cases are sending them out via network or saving them in a database. -## Highly Testable +### Highly Testable `structlog` is thoroughly tested and we see it as our duty to help you to achieve the same in *your* applications. That's why it ships with a [test helpers](https://www.structlog.org/en/stable/testing.html) to introspect your application's logging behavior with little-to-no boilerplate. From d6752011ebbe826a35952418141c92ff6469bc1a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 13 Oct 2022 16:34:48 +0200 Subject: [PATCH 0816/1520] Improve bound logger docs --- docs/bound-loggers.md | 73 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 60 insertions(+), 13 deletions(-) diff --git a/docs/bound-loggers.md b/docs/bound-loggers.md index 08b57f38..722e9223 100644 --- a/docs/bound-loggers.md +++ b/docs/bound-loggers.md @@ -1,54 +1,101 @@ # Bound Loggers The centerpiece of `structlog` that you will interact with most is called a *bound logger*. -It is what you get back from {func}`structlog.get_logger()` and call your logging methods on. -It consists of three parts: +It's what you get back from {func}`structlog.get_logger()` and it's called a *bound logger* because you can *bind* key-value pairs to it. + +As far as `structlog` is concerned, it consists of three parts: ```{image} _static/BoundLogger.svg ``` 1. A *context dictionary* that you can *bind* key-value pairs to. This dictionary is *merged* into each log entry that is logged from *this logger specifically*. - That means that every logger has it own context, but it is possible to have global contexts using {doc}`context variables `. + + You can inspect a context of a *bound logger* by calling {func}`structlog.get_context()` on it. 2. A list of {doc}`processors ` that are called on every log entry. Each processor receives the return value of its predecessor passed as an argument. + + This list is usually set using {doc}`configuration`. 3. And finally a *logger* that it's wrapping. This wrapped logger is responsible for the *output* of the log entry that has been returned by the last processor. - This *can* be standard library's {class}`logging.Logger`, but absolutely doesn't have to: - By default it's `structlog`'s {class}`structlog.PrintLogger`. + This *can* be standard library's {class}`logging.Logger` like in the image above, but absolutely doesn't have to: + By default it's `structlog`'s {class}`~structlog.PrintLogger`. + + This wrapped logger also is usually set using {doc}`configuration`. :::{important} Bound loggers themselves do *not* do any I/O themselves. -All they do is managing the *context* and proxying log calls to a *wrapped logger*. +All they do is manage the *context* and proxy log calls to a *wrapped logger*. ::: + +## Context + To manipulate the context dictionary, a *bound logger* offers to: - Recreate itself with (optional) *additional* context data: {func}`~structlog.BoundLoggerBase.bind` and {func}`~structlog.BoundLoggerBase.new`. - Recreate itself with *less* context data: {func}`~structlog.BoundLoggerBase.unbind` and {func}`~structlog.BoundLoggerBase.try_unbind`. In any case, the original bound logger or its context are never mutated. +They always return a *copy* of the bound logger with a *new* context that reflects your changes. ---- +This part of the API is defined in the {class}`typing.Protocol` called {class}`structlog.types.BindableLogger`. +N.B. that the protocol is marked {func}`typing.runtime_checkable` which means that you can check an object for being a *bound logger* using `isinstance(obj, structlog.types.BindableLogger)`. -Finally, if you call *any other* method on {class}`~structlog.BoundLogger`, it will: -1. Make a copy of the context -- now it becomes the *event dictionary*, +## Logging + +Finally, a *bound logger* also **indirectly** exposes the logging methods of the *wrapped logger*. +By default, that's a {class}`~structlog.types.FilteringBoundLogger` that is wrapping a {class}`~structlog.PrintLogger`. +They both share the set of log methods that's present in the standard library: `debug()`, `info()`, `warning()`, `error()`, and `critical()`. + +Whenever you call one of those methods on the *bound logger*, it will: + +1. Make a copy of its context -- now it becomes the *event dictionary*, 2. Add the keyword arguments of the method call to the event dict. 3. Add a new key `event` with the value of the first positional argument of the method call to the event dict. 4. Run the processors successively on the event dict. Each processor receives the result of its predecessor. -5. Finally, it takes the result of the final processor and calls the method with the same name – that got called on the bound logger – on the wrapped logger[^explicit]. - For flexibility, the final processor can return either a string[^str] that is passed directly as a positional parameter, or a tuple `(args, kwargs)` that are passed as `wrapped_logger.log_method(*args, **kwargs)`. +5. Finally, it takes the result of the final processor and calls the method with the same name – that got called on the *bound logger* – on the wrapped logger. -[^explicit]: Since this is slightly magical, `structlog` comes with concrete loggers for the `standard-library` and {doc}`twisted` that offer you explicit APIs for the supported logging methods but behave identically like the generic BoundLogger otherwise. - Of course, you are free to implement your own bound loggers too. + For flexibility, the final processor can return either a string[^str] that is passed directly as a positional parameter, or a tuple `(args, kwargs)` that are passed as `wrapped_logger.log_method(*args, **kwargs)`. [^str]: `str`, `bytes`, or `bytearray` to be exact. +### Step-by-Step Example + +Assuming you've left the default configuration and have: + +```python +import structlog + +logger = structlog.get_logger() + +log = logger.bind(foo="bar") +``` + +Now `log` is a *bound logger* of type {class}`~structlog.types.FilteringBoundLogger` (but in the default config there's no filtering). +`log`'s context is `{"foo": "bar"}` and it's wrapped logger is a {class}`structlog.PrintLogger`. + +Now if you call `log.info("Hello, %s!", "world", number=42)` the following happens: + +1. `"world"` gets interpolated into `"Hello, %s!"`, making the event "Hello, world!". +2. The *bound logger*'s context gets copied and the key-value pairs from the `info` call are added to it. + It becomes an *event dict* and is `{"foo": "bar", "number": 42}` now. +3. The event from step 1 is added too. + The *event dict* is `{"foo": "bar", "number": 42, "event": "Hello, world!"}` now. +4. The *event dict* is fed into the [processor chain](processors.md). + In this case the processors add a timestamp and the log level name to the *event dict*. + + Before it hits the last processor, the *event dict* looks something like `{"foo": "bar", "number": 42, "event": "Hello, world!", "level": "info", "timestamp": "2022-10-13 16:29:27"}` now. + + The last processor is {class}`structlog.dev.ConsoleRenderer` and formats the *event dict* into a colorful string. +5. Finally, the *wrapped logger*'s (a {class}`~structlog.PrintLogger`) `info()` method is called with that string. + + ## Wrapping Loggers Explicitly In practice, you won't be instantiating bound loggers yourself. From 251127458a07e9956bfe22f4493ddb8a2acef9c1 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 13 Oct 2022 17:30:35 +0200 Subject: [PATCH 0817/1520] Mention JSON --- docs/bound-loggers.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/bound-loggers.md b/docs/bound-loggers.md index 722e9223..eaa8f4e5 100644 --- a/docs/bound-loggers.md +++ b/docs/bound-loggers.md @@ -92,9 +92,13 @@ Now if you call `log.info("Hello, %s!", "world", number=42)` the following happe Before it hits the last processor, the *event dict* looks something like `{"foo": "bar", "number": 42, "event": "Hello, world!", "level": "info", "timestamp": "2022-10-13 16:29:27"}` now. - The last processor is {class}`structlog.dev.ConsoleRenderer` and formats the *event dict* into a colorful string. + The last processor is {class}`structlog.dev.ConsoleRenderer` and formats the *event dict* into a colorful string[^json]. 5. Finally, the *wrapped logger*'s (a {class}`~structlog.PrintLogger`) `info()` method is called with that string. +[^json]: Until this very step, the *event dict* was a dictionary. + By replacing the last processor, you decide on the **format** of your logs. + For example, if you wanted JSON logs, you just have to replace the last processor with {class}`structlog.processors.JSONRenderer`. + ## Wrapping Loggers Explicitly From 93bbae1c02d5783cb65a8903a59059269038a484 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 14 Oct 2022 08:03:41 +0200 Subject: [PATCH 0818/1520] Proofreading --- docs/bound-loggers.md | 4 ++-- docs/getting-started.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/bound-loggers.md b/docs/bound-loggers.md index eaa8f4e5..d9de4334 100644 --- a/docs/bound-loggers.md +++ b/docs/bound-loggers.md @@ -78,7 +78,7 @@ log = logger.bind(foo="bar") ``` Now `log` is a *bound logger* of type {class}`~structlog.types.FilteringBoundLogger` (but in the default config there's no filtering). -`log`'s context is `{"foo": "bar"}` and it's wrapped logger is a {class}`structlog.PrintLogger`. +`log`'s context is `{"foo": "bar"}` and its wrapped logger is a {class}`structlog.PrintLogger`. Now if you call `log.info("Hello, %s!", "world", number=42)` the following happens: @@ -92,7 +92,7 @@ Now if you call `log.info("Hello, %s!", "world", number=42)` the following happe Before it hits the last processor, the *event dict* looks something like `{"foo": "bar", "number": 42, "event": "Hello, world!", "level": "info", "timestamp": "2022-10-13 16:29:27"}` now. - The last processor is {class}`structlog.dev.ConsoleRenderer` and formats the *event dict* into a colorful string[^json]. + The last processor is {class}`structlog.dev.ConsoleRenderer` and renders the *event dict* into a colorful string[^json]. 5. Finally, the *wrapped logger*'s (a {class}`~structlog.PrintLogger`) `info()` method is called with that string. [^json]: Until this very step, the *event dict* was a dictionary. diff --git a/docs/getting-started.md b/docs/getting-started.md index b36632a6..ea0c844b 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -39,7 +39,7 @@ Here, `structlog` takes advantage of its default settings: That might look dated, but it's *much* faster than using {any}`str.format` and allows ``structlog`` to be used as drop-in replacement for {mod}`logging`. If you *know* that the log entry is *always* gonna be logged out, just use [f-strings](https://docs.python.org/3/tutorial/inputoutput.html#formatted-string-literals) which are the fastest. - All keywords are formatted using {class}`structlog.dev.ConsoleRenderer`. - That in turn uses `repr` to serialize all values to strings. + That in turn uses {func}`repr` to serialize all values to strings. - It's rendered in nice {doc}`colors ` (the [*Colorama*] package is needed on Windows). - If you have [*Rich*] or [*better-exceptions*] installed, exceptions will be rendered in colors and with additional helpful information. From 5d73008d7a1c1290d45eeb72d349c933d03e7bb3 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 14 Oct 2022 09:53:26 +0200 Subject: [PATCH 0819/1520] Create dependabot.yml --- .github/dependabot.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..8ac6b8c4 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" From 7d046ae527b867aeea5249f91ec72a9df2a9f6d1 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 14 Oct 2022 10:25:45 +0200 Subject: [PATCH 0820/1520] Rewrite configuration --- docs/configuration.md | 107 ++++++++++++++++++++++++++++ docs/configuration.rst | 146 --------------------------------------- src/structlog/_config.py | 19 ++--- 3 files changed, 117 insertions(+), 155 deletions(-) create mode 100644 docs/configuration.md delete mode 100644 docs/configuration.rst diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 00000000..86185107 --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,107 @@ +# Configuration + +The focus of `structlog` has always been to be flexible to a fault. +The goal is that a user can use it with *any* logger of their own that is wrapped by `structlog`. + +That's the reason why there's an overwhelming amount of knobs to tweak, but +– ideally – once you find your configuration, you don't touch it ever again and, more importantly: +don't see any of it in your application code. + +--- + +Let's start at the end and introduce the ultimate convenience function that relies purely on configuration: {func}`structlog.get_logger`. + +The goal is to reduce your per-file application logging boilerplate to: + +``` +import structlog + +logger = structlog.get_logger() +``` + +To that end, you'll have to call {func}`structlog.configure` on app initialization. +You can call {func}`structlog.configure` repeatedly and only set one or more settings -- the rest will not be affected. + +If necessary, you can always reset your global configuration back to default values using {func}`structlog.reset_defaults`. +That can be handy in tests. + +At any time, you can check whether and how `structlog` is configured using {func}`structlog.is_configured` and {func}`structlog.get_config`}: + +```pycon +>>> structlog.is_configured() +False +>>> structlog.configure(logger_factory=structlog.stdlib.LoggerFactory) +>>> structlog.is_configured() +True +>>> cfg = structlog.get_config() +>>> cfg["logger_factory"] + +``` + +:::{important} +Since you'll call {func}`structlog.get_logger` in module scope, it runs at import time *before* you had a chance to configure `structlog`. +Therefore it returns a **lazy proxy** that returns a correctly configured *bound logger* on its first call to one of the context-managing methods like `bind()`. + +Thus, you must never call `new()` or `bind()` in module or class scope because , you will receive a logger configured with `structlog`'s default values. +Use {func}`~structlog.get_logger`'s `initial_values` to achieve pre-populated contexts. + +To enable you to log with the module-global logger, it will create a temporary *bound logger* **on each call**. +Therefore if you have nothing to bind but intend to do lots of log calls in a function, it makes sense performance-wise to create a local logger by calling `bind()` or `new()` without any parameters. +See also {doc}`performance`. +::: + + +## What To Configure + +You can find the details in the API documentation of {func}`structlog.configure`, but let's introduce the most important ones at a high level first. + + +### Wrapper Classes + +You've met {doc}`bound-loggers` in the last chapter. +They're the objects returned by {func}`~structlog.get_logger` and allow to bind key-value pairs into their private context. +You can configure their type using the `wrapper_class` keyword. + +Whenever you bind or unbind data to a *bound logger*, this class is instantiated with the new context and returned. + + +### Logger Factories + +We've already talked about wrapped loggers responsible for the output, but until now we haven't explained where they come from until now. +Unlike with *bound loggers*, you often need more flexibility when instantiating them. +Therefore you don't configure a class; you configure a *factory* using the `logger_factory` keyword. + +It's a callable that returns the logger that gets wrapped and returned. +In the simplest case, it's a function that returns a logger -- or just a class. +But you can also pass in an instance of a class with a `__call__` method for more complicated setups. + +These will be passed to the logger factories. +For example, if you use run `structlog.get_logger("a name")` and configure `structlog` to use the standard library {class}`~structlog.stdlib.LoggerFactory`,which has support for positional parameters, the returned logger will have the name `"a name"`. + +For the common cases of standard library logging and Twisted logging, `structlog` comes with two factories built right in: + +- {class}`structlog.stdlib.LoggerFactory` +- {class}`structlog.twisted.LoggerFactory` + +So all it takes to use standard library {mod}`logging` for output is: + +``` +>>> from structlog import get_logger, configure +>>> from structlog.stdlib import LoggerFactory +>>> configure(logger_factory=LoggerFactory()) +>>> log = get_logger() +>>> log.critical("this is too easy!") +event='this is too easy!' +``` + +By using `structlog`'s {class}`structlog.stdlib.LoggerFactory`, it is also ensured that variables like function names and line numbers are expanded correctly in your log format. +See {doc}`standard-library` for more details. + +Calling {func}`structlog.get_logger` without configuration gives you a perfectly useful {class}`structlog.PrintLogger`. +We don't believe silent loggers are a sensible default. + + +### Processors + +You will meet {doc}`processors` in the next chapter. +They are configured using the `processors` keyword that takes an {class}`~collections.abc.Iterable` of callables that act as processors. diff --git a/docs/configuration.rst b/docs/configuration.rst deleted file mode 100644 index 104a6a64..00000000 --- a/docs/configuration.rst +++ /dev/null @@ -1,146 +0,0 @@ -Configuration -============= - - -Global Defaults ---------------- - -To make logging as unintrusive and straight-forward to use as possible, ``structlog`` comes with a plethora of configuration options and convenience functions. -Let's start at the end and introduce the ultimate convenience function that relies purely on configuration: :func:`structlog.get_logger`. - -The goal is to reduce your per-file logging boilerplate to:: - - from structlog import get_logger - logger = get_logger() - -while still giving you the full power via configuration. - -To that end you'll have to call :func:`structlog.configure` on app initialization. -Thus the :ref:`example ` from the previous chapter could have been written as following: - -.. testcleanup:: * - - import structlog - structlog.reset_defaults() - -.. testsetup:: * - - import structlog - structlog.reset_defaults() - -.. testsetup:: config_wrap_logger, config_get_logger - - from structlog import PrintLogger, configure, reset_defaults, wrap_logger, get_logger - from structlog.threadlocal import wrap_dict - def proc(logger, method_name, event_dict): - print("I got called with", event_dict) - return repr(event_dict) - -.. doctest:: config_get_logger - - >>> configure(processors=[proc]) - >>> log = get_logger() - >>> log.info("hello world") - I got called with {'event': 'hello world'} - {'event': 'hello world'} - -because :class:`~structlog.PrintLogger` is the default ``LoggerFactory`` (see :ref:`logger-factories`). - -Configuration also applies to :func:`~structlog.wrap_logger` because that's what's used internally: - -.. doctest:: config_wrap_logger - - >>> configure(processors=[proc], context_class=dict) - >>> log = wrap_logger(PrintLogger()) - >>> log.info("hello world") - I got called with {'event': 'hello world'} - {'event': 'hello world'} - - ------ - -You can call :func:`structlog.configure` repeatedly and only set one or more settings -- the rest will not be affected. - -``structlog`` tries to behave in the least surprising way when it comes to handling defaults and configuration: - -#. Arguments passed to :func:`structlog.wrap_logger` *always* take the highest precedence over configuration. - That means that you can overwrite whatever you've configured for each logger respectively. -#. If you leave them on ``None``, ``structlog`` will check whether you've configured default values using :func:`structlog.configure` and uses them if so. -#. If you haven't configured or passed anything at all, the default fallback values try to be convenient and development-friendly. - -If necessary, you can always reset your global configuration back to default values using :func:`structlog.reset_defaults`. -That can be handy in tests. - -At any time, you can check whether and how ``structlog`` is configured: - -.. doctest:: - - >>> structlog.is_configured() - False - >>> class MyDict(dict): pass - >>> structlog.configure(context_class=MyDict) - >>> structlog.is_configured() - True - >>> cfg = structlog.get_config() - >>> cfg["context_class"] - - - -.. note:: - - Since you will call `structlog.get_logger` most likely in module scope, they run at import time before you had a chance to configure ``structlog``. - Therefore they return a **lazy proxy** that returns a correct wrapped logger on first ``bind()``/``new()``. - - Thus, you must never call ``new()`` or ``bind()`` in module or class scope because otherwise you will receive a logger configured with ``structlog``'s default values. - Use :func:`~structlog.get_logger`\ 's ``initial_values`` to achieve pre-populated contexts. - - To enable you to log with the module-global logger, it will create a temporary BoundLogger and relay the log calls to it on *each call*. - Therefore if you have nothing to bind but intend to do lots of log calls in a function, it makes sense performance-wise to create a local logger by calling ``bind()`` or ``new()`` without any parameters. - See also `performance`. - - -.. _logger-factories: - -Logger Factories ----------------- - -To make `structlog.get_logger` work, one needs one more option that hasn't been discussed yet: ``logger_factory``. - -It is a callable that returns the logger that gets wrapped and returned. -In the simplest case, it's a function that returns a logger -- or just a class. -But you can also pass in an instance of a class with a ``__call__`` method for more complicated setups. - -.. versionadded:: 0.4.0 - `structlog.get_logger` can optionally take positional parameters. - -These will be passed to the logger factories. -For example, if you use run ``structlog.get_logger("a name")`` and configure ``structlog`` to use the standard library :class:`~structlog.stdlib.LoggerFactory` which has support for positional parameters, the returned logger will have the name ``"a name"``. - -When writing custom logger factories, they should always accept positional parameters even if they don't use them. -That makes sure that loggers are interchangeable. - -For the common cases of standard library logging and Twisted logging, ``structlog`` comes with two factories built right in: - -- `structlog.stdlib.LoggerFactory` -- `structlog.twisted.LoggerFactory` - -So all it takes to use ``structlog`` with standard library logging is this:: - - >>> from structlog import get_logger, configure - >>> from structlog.stdlib import LoggerFactory - >>> configure(logger_factory=LoggerFactory()) - >>> log = get_logger() - >>> log.critical("this is too easy!") - event='this is too easy!' - -By using ``structlog``'s `structlog.stdlib.LoggerFactory`, it is also ensured that variables like function names and line numbers are expanded correctly in your log format. - -The :ref:`Twisted example ` shows how easy it is for Twisted. - -.. note:: - - ``LoggerFactory``-style factories always need to get passed as *instances* like in the examples above. - While neither allows for customization using parameters yet, they may do so in the future. - -Calling `structlog.get_logger` without configuration gives you a perfectly useful `structlog.PrintLogger`. -We don't believe silent loggers are a sensible default. diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 72f3c5d7..244950eb 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -196,8 +196,7 @@ def configure( Can be called several times, keeping an argument at `None` leaves it unchanged from the current setting. - After calling for the first time, `is_configured` starts returning - `True`. + After calling for the first time, `is_configured` starts returning `True`. Use `reset_defaults` to undo your changes. @@ -205,13 +204,15 @@ def configure( :param wrapper_class: Class to use for wrapping loggers instead of `structlog.BoundLogger`. See `standard-library`, :doc:`twisted`, and `custom-wrappers`. - :param context_class: Class to be used for internal context keeping. - :param logger_factory: Factory to be called to create a new - logger that shall be wrapped. - :param cache_logger_on_first_use: `wrap_logger` doesn't return an - actual wrapped logger but a proxy that assembles one when it's first - used. If this option is set to `True`, this assembled logger is - cached. See `performance`. + :param context_class: Class to be used for internal context keeping. The + default is a `dict` and since dictionaries are ordered as of Python + 3.6, there's few reasons to change this option. + :param logger_factory: Factory to be called to create a new logger that + shall be wrapped. + :param cache_logger_on_first_use: `wrap_logger` doesn't return an actual + wrapped logger but a proxy that assembles one when it's first used. If + this option is set to `True`, this assembled logger is cached. See + `performance`. .. versionadded:: 0.3.0 *cache_logger_on_first_use* From 62234264c8dfa32ace2cbc9df90380f7ef196e84 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 14 Oct 2022 10:57:40 +0200 Subject: [PATCH 0821/1520] MySTify & rewrite processors --- docs/code_examples/flask_/some_module.py | 10 -- docs/code_examples/flask_/webapp.py | 51 ------ .../processors/conditional_dropper.py | 21 --- docs/code_examples/processors/dropper.py | 5 - docs/code_examples/processors/timestamper.py | 7 - docs/code_examples/twisted_echo.py | 47 ----- docs/contextvars.md | 81 ++++++--- docs/examples.md | 74 -------- docs/index.md | 1 - docs/processors.md | 164 ++++++++++++++++++ docs/processors.rst | 146 ---------------- 11 files changed, 225 insertions(+), 382 deletions(-) delete mode 100644 docs/code_examples/flask_/some_module.py delete mode 100644 docs/code_examples/flask_/webapp.py delete mode 100644 docs/code_examples/processors/conditional_dropper.py delete mode 100644 docs/code_examples/processors/dropper.py delete mode 100644 docs/code_examples/processors/timestamper.py delete mode 100644 docs/code_examples/twisted_echo.py delete mode 100644 docs/examples.md create mode 100644 docs/processors.md delete mode 100644 docs/processors.rst diff --git a/docs/code_examples/flask_/some_module.py b/docs/code_examples/flask_/some_module.py deleted file mode 100644 index 1a032b81..00000000 --- a/docs/code_examples/flask_/some_module.py +++ /dev/null @@ -1,10 +0,0 @@ -from structlog import get_logger - - -logger = get_logger() - - -def some_function(): - # ... - logger.error("user did something", something="shot_in_foot") - # ... diff --git a/docs/code_examples/flask_/webapp.py b/docs/code_examples/flask_/webapp.py deleted file mode 100644 index 34fde75a..00000000 --- a/docs/code_examples/flask_/webapp.py +++ /dev/null @@ -1,51 +0,0 @@ -import logging -import sys -import uuid - -import flask - -from some_module import some_function - -import structlog - - -logger = structlog.get_logger() -app = flask.Flask(__name__) - - -@app.route("/login", methods=["POST", "GET"]) -def some_route(): - # You would put this into some kind of middleware or processor so it's set - # automatically for all requests in all views. - structlog.contextvars.clear_contextvars() - structlog.contextvars.bind_contextvars( - view=flask.request.path, - request_id=str(uuid.uuid4()), - peer=flask.request.access_route[0], - ) - # End of belongs-to-middleware. - - log = logger.bind() - # do something - # ... - log.info("user logged in", user="test-user") - # ... - some_function() - # ... - return "logged in!" - - -if __name__ == "__main__": - logging.basicConfig( - format="%(message)s", stream=sys.stdout, level=logging.INFO - ) - structlog.configure( - processors=[ - structlog.contextvars.merge_contextvars, # <--!!! - structlog.processors.KeyValueRenderer( - key_order=["event", "view", "peer"] - ), - ], - logger_factory=structlog.stdlib.LoggerFactory(), - ) - app.run() diff --git a/docs/code_examples/processors/conditional_dropper.py b/docs/code_examples/processors/conditional_dropper.py deleted file mode 100644 index 255504ae..00000000 --- a/docs/code_examples/processors/conditional_dropper.py +++ /dev/null @@ -1,21 +0,0 @@ -from structlog import DropEvent - - -class ConditionalDropper: - def __init__(self, peer_to_ignore): - self._peer_to_ignore = peer_to_ignore - - def __call__(self, logger, method_name, event_dict): - """ - >>> cd = ConditionalDropper("127.0.0.1") - >>> cd(None, None, {"event": "foo", "peer": "10.0.0.1"}) - {'peer': '10.0.0.1', 'event': 'foo'} - >>> cd(None, None, {"event": "foo", "peer": "127.0.0.1"}) - Traceback (most recent call last): - ... - DropEvent - """ - if event_dict.get("peer") == self._peer_to_ignore: - raise DropEvent - - return event_dict diff --git a/docs/code_examples/processors/dropper.py b/docs/code_examples/processors/dropper.py deleted file mode 100644 index 1d0a100c..00000000 --- a/docs/code_examples/processors/dropper.py +++ /dev/null @@ -1,5 +0,0 @@ -from structlog import DropEvent - - -def dropper(logger, method_name, event_dict): - raise DropEvent diff --git a/docs/code_examples/processors/timestamper.py b/docs/code_examples/processors/timestamper.py deleted file mode 100644 index 9f81f094..00000000 --- a/docs/code_examples/processors/timestamper.py +++ /dev/null @@ -1,7 +0,0 @@ -import calendar -import time - - -def timestamper(logger, log_method, event_dict): - event_dict["timestamp"] = calendar.timegm(time.gmtime()) - return event_dict diff --git a/docs/code_examples/twisted_echo.py b/docs/code_examples/twisted_echo.py deleted file mode 100644 index cf4b803b..00000000 --- a/docs/code_examples/twisted_echo.py +++ /dev/null @@ -1,47 +0,0 @@ -import sys -import uuid - -import twisted - -from twisted.internet import protocol, reactor - -import structlog - - -logger = structlog.getLogger() - - -class Counter: - i = 0 - - def inc(self): - self.i += 1 - - def __repr__(self): - return str(self.i) - - -class Echo(protocol.Protocol): - def connectionMade(self): - self._counter = Counter() - self._log = logger.new( - connection_id=str(uuid.uuid4()), - peer=self.transport.getPeer().host, - count=self._counter, - ) - - def dataReceived(self, data): - self._counter.inc() - log = self._log.bind(data=data) - self.transport.write(data) - log.msg("echoed data!") - - -if __name__ == "__main__": - structlog.configure( - processors=[structlog.twisted.EventAdapter()], - logger_factory=structlog.twisted.LoggerFactory(), - ) - twisted.python.log.startLogging(sys.stderr) - reactor.listenTCP(1234, protocol.Factory.forProtocol(Echo)) - reactor.run() diff --git a/docs/contextvars.md b/docs/contextvars.md index b43111a5..9cae5449 100644 --- a/docs/contextvars.md +++ b/docs/contextvars.md @@ -105,14 +105,70 @@ def _helper(): Let's assume you want to bind a unique request ID, the URL path, and the peer's IP to every log entry by storing it in thread-local storage that is managed by context variables: -```{literalinclude} code_examples/flask_/webapp.py -:language: python +```python +import logging +import sys +import uuid + +import flask + +from .some_module import some_function + +import structlog + +logger = structlog.get_logger() +app = flask.Flask(__name__) + +@app.route("/login", methods=["POST", "GET"]) +def some_route(): + # You would put this into some kind of middleware or processor so it's set + # automatically for all requests in all views. + structlog.contextvars.clear_contextvars() + structlog.contextvars.bind_contextvars( + view=flask.request.path, + request_id=str(uuid.uuid4()), + peer=flask.request.access_route[0], + ) + # End of belongs-to-middleware. + + log = logger.bind() + # do something + # ... + log.info("user logged in", user="test-user") + # ... + some_function() + # ... + return "logged in!" + + +if __name__ == "__main__": + logging.basicConfig( + format="%(message)s", stream=sys.stdout, level=logging.INFO + ) + structlog.configure( + processors=[ + structlog.contextvars.merge_contextvars, # <--!!! + structlog.processors.KeyValueRenderer( + key_order=["event", "view", "peer"] + ), + ], + logger_factory=structlog.stdlib.LoggerFactory(), + ) + app.run() + ``` -`some_module.py` +`some_module.py`: + +```python +from structlog import get_logger + +logger = get_logger() -```{literalinclude} code_examples/flask_/some_module.py -:language: python +def some_function(): + # ... + logger.error("user did something", something="shot_in_foot") + # ... ``` This would result among other the following lines to be printed: @@ -123,18 +179,3 @@ event='user did something' view='/login' peer='127.0.0.1' something='shot_in_foo ``` As you can see, `view`, `peer`, and `request_id` are present in **both** log entries. - -While wrapped loggers are *immutable* by default, this example demonstrates how to circumvent that using a thread-local storage for request-wide context: - -1. {func}`structlog.contextvars.clear_contextvars()` ensures the thread-local storage is empty for each request. -2. {func}`structlog.contextvars.bind_contextvars()` puts your key-value pairs into thread-local storage. -3. The {func}`structlog.contextvars.merge_contextvars()` processor merges the thread-local context into the event dict. - -Please note that the `user` field is only present in the view because it wasn't bound into the thread-local storage. -See {doc}`contextvars` for more details. - -___ - -{func}`structlog.stdlib.LoggerFactory` is a totally magic-free class that just deduces the name of the caller's module and runs a {func}`logging.getLogger` with it. -It's used by {func}`structlog.get_logger` to rid you of logging boilerplate in application code. -If you prefer to name your standard library loggers explicitly, a positional argument to {func}`structlog.get_logger` gets passed to the factory and used as the name. diff --git a/docs/examples.md b/docs/examples.md deleted file mode 100644 index ab9a2921..00000000 --- a/docs/examples.md +++ /dev/null @@ -1,74 +0,0 @@ -# Examples - -This chapter is intended to give you a taste of realistic usage of `structlog`. - -(processors-examples)= - -## Processors - -{doc}`processors` are a both simple and powerful feature of `structlog`. - -The following example demonstrates how easy it is to add timestamps, censor passwords, filter out log entries below your log level before they even get rendered, and get your output as JSON for convenient parsing. -It also demonstrates how to use `structlog.wrap_logger` that allows you to use `structlog` without any global configuration (a rather uncommon pattern, but can be useful): - -```{eval-rst} -.. doctest:: - - >>> import datetime, logging, sys - >>> from structlog import wrap_logger - >>> from structlog.processors import JSONRenderer - >>> from structlog.stdlib import filter_by_level - >>> logging.basicConfig(stream=sys.stdout, format="%(message)s") - >>> def add_timestamp(_, __, event_dict): - ... event_dict["timestamp"] = datetime.datetime.utcnow() - ... return event_dict - >>> def censor_password(_, __, event_dict): - ... pw = event_dict.get("password") - ... if pw: - ... event_dict["password"] = "*CENSORED*" - ... return event_dict - >>> log = wrap_logger( - ... logging.getLogger(__name__), - ... processors=[ - ... filter_by_level, - ... add_timestamp, - ... censor_password, - ... JSONRenderer(indent=1, sort_keys=True) - ... ] - ... ) - >>> log.info("something.filtered") - >>> log.warning("something.not_filtered", password="secret") # doctest: +ELLIPSIS - { - "event": "something.not_filtered", - "password": "*CENSORED*", - "timestamp": "datetime.datetime(..., ..., ..., ..., ...)" - } -``` - -`structlog` comes with many handy processors build right in, so check the {ref}`API documentation ` before you write your own. -For example, you probably don't want to write your own timestamper. - -(twisted-example)= - -## Twisted, and Logging Out Objects - -If you prefer to log less but with more context in each entry, you can bind everything important to your logger and log it out with each log entry. - -```{literalinclude} code_examples/twisted_echo.py -:language: python -``` - -gives you something like: - -```text -... peer='127.0.0.1' connection_id='1c6c0cb5-...' count=1 data='123\n' event='echoed data!' -... peer='127.0.0.1' connection_id='1c6c0cb5-...' count=2 data='456\n' event='echoed data!' -... peer='127.0.0.1' connection_id='1c6c0cb5-...' count=3 data='foo\n' event='echoed data!' -... peer='10.10.0.1' connection_id='85234511-...' count=1 data='cba\n' event='echoed data!' -... peer='127.0.0.1' connection_id='1c6c0cb5-...' count=4 data='bar\n' event='echoed data!' -``` - -Since Twisted's logging system is a bit peculiar, `structlog` ships with an {class}`adapter ` so it keeps behaving like you'd expect it to behave. - -I'd also like to point out the Counter class that doesn't do anything spectacular but gets bound *once* per connection to the logger and since its repr is the number itself, it's logged out correctly for each event. -This shows off the strength of keeping a dict of objects for context instead of passing around serialized strings. diff --git a/docs/index.md b/docs/index.md index b3d4055b..80902b38 100644 --- a/docs/index.md +++ b/docs/index.md @@ -33,7 +33,6 @@ bound-loggers configuration processors contextvars -examples development testing types diff --git a/docs/processors.md b/docs/processors.md new file mode 100644 index 00000000..86724d22 --- /dev/null +++ b/docs/processors.md @@ -0,0 +1,164 @@ +# Processors + +The true power of `structlog` lies in its *combinable log processors*. +A log processor is a regular callable, i.e. a function or an instance of a class with a `__call__()` method. + +(chains)= + +## Chains + +The *processor chain* is a list of processors. +Each processors receives three positional arguments: + +**logger** + +: Your wrapped logger object. + For example {class}`logging.Logger` or {class}`structlog.types.FilteringBoundLogger` (default). + +**method_name** + +: The name of the wrapped method. + If you called `log.warning("foo")`, it will be `"warning"`. + +**event_dict** + +: Current context together with the current event. + If the context was `{"a": 42}` and the event is `"foo"`, the initial `event_dict` will be `{"a":42, "event": "foo"}`. + +The return value of each processor is passed on to the next one as `event_dict` until finally the return value of the last processor gets passed into the wrapped logging method. + +:::{note} +`structlog` only looks at the return value of the **last** processor. +That means that as long as you control the next processor in the chain (i.e. the processor that will get your return value passed as an argument), you can return whatever you want. + +Returning a modified event dictionary from your processors is just a convention to make processors composable. +::: + + +### Examples + +If you set up your logger like: + +```python +structlog.configure(processors=[f1, f2, f3]) +log = structlog.get_logger().bind(x=42) +``` + +and call `log.info("some_event", y=23)`, it results in the following call chain: + +```python +wrapped_logger.info( + f3(wrapped_logger, "info", + f2(wrapped_logger, "info", + f1(wrapped_logger, "info", {"event": "some_event", "x": 42, "y": 23}) + ) + ) +) +``` + +In this case, `f3` has to make sure it returns something `wrapped_logger.info` can handle (see {ref}`adapting`). +For the example with `PrintLogger` above, this means `f3` must return a string. + +The simplest modification a processor can make is adding new values to the `event_dict`. +Parsing human-readable timestamps is tedious, not so [UNIX timestamps](https://en.wikipedia.org/wiki/UNIX_time) -- let's add one to each log entry: + +```python +import calendar +import time + +def timestamper(logger, log_method, event_dict): + event_dict["timestamp"] = calendar.timegm(time.gmtime()) + return event_dict +``` + +:::{important} +You're explicitly allowed to modify the `event_dict` parameter, because a copy has been created before calling the first processor. +::: + +Please note that `structlog` comes with such a processor built in: {class}`~structlog.processors.TimeStamper`. + + +## Filtering + +If a processor raises {class}`structlog.DropEvent`, the event is silently dropped. + +Therefore, the following processor drops every entry: + +```python +from structlog import DropEvent + +def dropper(logger, method_name, event_dict): + raise DropEvent +``` + +But we can do better than that! + +(cond-drop)= + +How about dropping only log entries that are marked as coming from a certain peer (e.g. monitoring)? + +```python +class ConditionalDropper: + def __init__(self, peer_to_ignore): + self._peer_to_ignore = peer_to_ignore + + def __call__(self, logger, method_name, event_dict): + """ + >>> cd = ConditionalDropper("127.0.0.1") + >>> cd(None, None, {"event": "foo", "peer": "10.0.0.1"}) + {'peer': '10.0.0.1', 'event': 'foo'} + >>> cd(None, None, {"event": "foo", "peer": "127.0.0.1"}) + Traceback (most recent call last): + ... + DropEvent + """ + if event_dict.get("peer") == self._peer_to_ignore: + raise DropEvent + + return event_dict +``` + +Since it's so common to filter by the log level, `structlog` comes with {func}`structlog.make_filtering_bound_logger` that filters log entries before they even enter the processor chain. +It does **not** use the standard library, but it does use its names and order of log levels. + +(adapting)= + +## Adapting and Rendering + +An important role is played by the *last* processor because its duty is to adapt the `event_dict` into something the logging methods of the *wrapped logger* understand. +With that, it's also the *only* processor that needs to know anything about the underlying system. + +It can return one of three types: + +- An Unicode string ({any}`str`), a bytes string ({any}`bytes`), or a {any}`bytearray` that is passed as the first (and only) positional argument to the underlying logger. +- A tuple of `(args, kwargs)` that are passed as `log_method(*args, **kwargs)`. +- A dictionary which is passed as `log_method(**kwargs)`. + +Therefore `return "hello world"` is a shortcut for `return (("hello world",), {})` (the example in {ref}`chains` assumes this shortcut has been taken). + +This should give you enough power to use `structlog` with any logging system while writing agnostic processors that operate on dictionaries. + +:::{versionchanged} 14.0.0 Allow final processor to return a {any}`dict`. +::: + +:::{versionchanged} 20.2.0 Allow final processor to return a {any}`bytes`. +::: + +:::{versionchanged} 21.2.0 Allow final processor to return a {any}`bytearray`. +::: + +### Examples + +The probably most useful formatter for string based loggers is {class}`structlog.processors.JSONRenderer`. +Advanced log aggregation and analysis tools like [*Logstash*](https://www.elastic.co/logstash) offer features like telling them "this is JSON, deal with it" instead of fiddling with regular expressions. + +For a list of shipped processors, check out the {ref}`API documentation `. + + +## Third-Party Packages + +`structlog` was specifically designed to be as composable and reusable as possible, so whatever you're missing: +chances are, you can solve it with a processor! +Since processors are self-contained callables, it's easy to write your own and to share them in separate packages. + +We collect those packages in our [GitHub Wiki](https://github.com/hynek/structlog/wiki/Third-Party-Extensions) and encourage you to add your package too! diff --git a/docs/processors.rst b/docs/processors.rst deleted file mode 100644 index 8d3efe89..00000000 --- a/docs/processors.rst +++ /dev/null @@ -1,146 +0,0 @@ -Processors -========== - -The true power of ``structlog`` lies in its *combinable log processors*. -A log processor is a regular callable, i.e. a function or an instance of a class with a ``__call__()`` method. - -.. _chains: - -Chains ------- - -The *processor chain* is a list of processors. -Each processors receives three positional arguments: - -**logger** - Your wrapped logger object. - For example `logging.Logger`. - -**method_name** - The name of the wrapped method. - If you called ``log.warning("foo")``, it will be ``"warning"``. - -**event_dict** - Current context together with the current event. - If the context was ``{"a": 42}`` and the event is ``"foo"``, the initial ``event_dict`` will be ``{"a":42, "event": "foo"}``. - -The return value of each processor is passed on to the next one as ``event_dict`` until finally the return value of the last processor gets passed into the wrapped logging method. - -.. note:: - - ``structlog`` only looks at the return value of the **last** processor. - That means that as long as you control the next processor in the chain (i.e. the processor that will get your return value passed as an argument), you can return whatever you want. - - Returning a modified event dictionary from your processors is just a convention to make processors composable. - - -Examples -^^^^^^^^ - -If you set up your logger like: - -.. code:: python - - from structlog import PrintLogger, wrap_logger - wrapped_logger = PrintLogger() - logger = wrap_logger(wrapped_logger, processors=[f1, f2, f3, f4]) - log = logger.new(x=42) - -and call ``log.msg("some_event", y=23)``, it results in the following call chain: - -.. code:: python - - wrapped_logger.msg( - f4(wrapped_logger, "msg", - f3(wrapped_logger, "msg", - f2(wrapped_logger, "msg", - f1(wrapped_logger, "msg", {"event": "some_event", "x": 42, "y": 23}) - ) - ) - ) - ) - -In this case, ``f4`` has to make sure it returns something ``wrapped_logger.msg`` can handle (see :ref:`adapting`). -For the example with ``PrintLogger`` above, this means ``f4`` must return a string. - -The simplest modification a processor can make is adding new values to the ``event_dict``. -Parsing human-readable timestamps is tedious, not so `UNIX timestamps `_ -- let's add one to each log entry! - -.. literalinclude:: code_examples/processors/timestamper.py - :language: python - -Please note, that ``structlog`` comes with such a processor built in: `TimeStamper`. - - -Filtering ---------- - -If a processor raises `structlog.DropEvent`, the event is silently dropped. - -Therefore, the following processor drops every entry: - -.. literalinclude:: code_examples/processors/dropper.py - :language: python - -But we can do better than that! - -.. _cond_drop: - -How about dropping only log entries that are marked as coming from a certain peer (e.g. monitoring)? - -.. literalinclude:: code_examples/processors/conditional_dropper.py - :language: python - - -Since it's so common to filter by the log level, ``structlog`` comes with `structlog.make_filtering_bound_logger` that filters log entries before they even enter the processor chain.. -It does **not** use the standard library, but it does use its names and order of log levels. -In practice, it only looks up the numeric value of the method name and compares it to the configured minimal level. -That's fast and usually good enough for applications. - - -.. _adapting: - -Adapting and Rendering ----------------------- - -An important role is played by the *last* processor because its duty is to adapt the ``event_dict`` into something the underlying logging method understands. -With that, it's also the *only* processor that needs to know anything about the underlying system. - -It can return one of three types: - -- An Unicode string (`str`), a bytes string (`bytes`), or a `bytearray` that is passed as the first (and only) positional argument to the underlying logger. -- A tuple of ``(args, kwargs)`` that are passed as ``log_method(*args, **kwargs)``. -- A dictionary which is passed as ``log_method(**kwargs)``. - -Therefore ``return "hello world"`` is a shortcut for ``return (("hello world",), {})`` (the example in `chains` assumes this shortcut has been taken). - -This should give you enough power to use ``structlog`` with any logging system while writing agnostic processors that operate on dictionaries. - -.. versionchanged:: 14.0.0 - Allow final processor to return a `dict`. - -.. versionchanged:: 20.2.0 - Allow final processor to return a `bytes`. - -.. versionchanged:: 21.2.0 - Allow final processor to return a `bytearray`. - - -Examples -^^^^^^^^ - -The probably most useful formatter for string based loggers is `structlog.processors.JSONRenderer`. -Advanced log aggregation and analysis tools like `logstash `_ offer features like telling them "this is JSON, deal with it" instead of fiddling with regular expressions. - -More examples can be found in the :ref:`examples ` chapter. -For a list of shipped processors, check out the :ref:`API documentation `. - - -Third-Party Packages --------------------- - -``structlog`` was specifically designed to be as composable and reusable as possible, so whatever you're missing: -chances are, you can solve it with a processor! -Since processors are self-contained callables, it's easy to write your own and to share them in separate packages. - -We collect those packages in our `GitHub Wiki `_ and encourage you to add your package too! From bd67c022d7051c8b861590f1c71894f2c78e541b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 14 Oct 2022 14:46:05 +0200 Subject: [PATCH 0822/1520] fix output --- docs/getting-started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index ea0c844b..673aca30 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -27,7 +27,7 @@ As a result, the simplest possible usage looks like this: >>> import structlog >>> log = structlog.get_logger() >>> log.info("hello, %s!", "world", key="value!", more_than_strings=[1, 2, 3]) # doctest: +SKIP - 2022-10-07 10:41:29 [info ] hello, world! key=value! more_strings=[1, 2, 3] + 2022-10-07 10:41:29 [info ] hello, world! key=value! more_than_strings=[1, 2, 3] ``` Here, `structlog` takes advantage of its default settings: From a2a8b37cafe103e66d67b5f437ea35b40a5af026 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 07:52:17 +0200 Subject: [PATCH 0823/1520] MySTify standard-library --- docs/standard-library.md | 542 ++++++++++++++++++++++++++++++++++++++ docs/standard-library.rst | 542 -------------------------------------- 2 files changed, 542 insertions(+), 542 deletions(-) create mode 100644 docs/standard-library.md delete mode 100644 docs/standard-library.rst diff --git a/docs/standard-library.md b/docs/standard-library.md new file mode 100644 index 00000000..3ca5aee7 --- /dev/null +++ b/docs/standard-library.md @@ -0,0 +1,542 @@ +# Standard Library Logging + +Ideally, `structlog` should be able to be used as a drop-in replacement for standard library's {mod}`logging` by wrapping it. +In other words, you should be able to replace your call to {func}`logging.getLogger` by a call to {func}`structlog.get_logger` and things should keep working as before (if `structlog` is configured right, see {ref}`stdlib-config` below). + +If you run into incompatibilities, it is a *bug* so please take the time to [report it](https://github.com/hynek/structlog/issues)! +If you're a heavy `logging` user, your [help](https://github.com/hynek/structlog/issues?q=is%3Aopen+is%3Aissue+label%3Astdlib) to ensure a better compatibility would be highly appreciated! + +:::{note} +The quickest way to get started with `structlog` and `logging` is {func}`structlog.stdlib.recreate_defaults()` that will recreate the default configuration on top of `logging` and optionally configure `logging` for you. +::: + + +## Just Enough `logging` + +If you want to use `structlog` with `logging`, you should have at least a fleeting understanding on how the standard library operates because `structlog` will *not* do any magic things in the background for you. +Most importantly you have to *configure* the `logging` system *additionally* to configuring `structlog`. + +Usually it is enough to use: + +``` +import logging +import sys + +logging.basicConfig( + format="%(message)s", + stream=sys.stdout, + level=logging.INFO, +) +``` + +This will send all log messages with the [log level](https://docs.python.org/3/library/logging.html#logging-levels) `logging.INFO` and above (that means that e.g. `logging.debug` calls are ignored) to standard out without any special formatting by the standard library. + +If you require more complex behavior, please refer to the standard library's `logging` documentation. + + +## Concrete Bound Logger + +`structlog` ships a stdlib-specific [*bound logger*](bound-loggers.md) that mirrors the log methods of standard library's {any}`logging.Logger` with correct type hints. + +If you want to take advantage of said type hints, you have to either annotate the logger coming from {func}`structlog.get_logger`, or use {func}`structlog.stdlib.get_logger()` that has the appropriate type hints. +Please note though, that it will neither configure nor verify your configuration. +It will call `structlog.get_logger()` just like if you would've called it -- the only difference are the type hints. + +See also {doc}`types`. + + +### `asyncio` + +For `asyncio` applications, you may not want your whole application to block while your processor chain is formatting your log entries. +For that use case `structlog` comes with {class}`structlog.stdlib.AsyncBoundLogger` that will do all processing in a thread pool executor. + +This means an increased computational cost per log entry but your application will never block because of logging. + +To use it, {doc}`configure ` `structlog` to use `AsyncBoundLogger` as `wrapper_class`. + + +## Processors + +`structlog` comes with a few standard library-specific processors: + +{func}`~structlog.stdlib.render_to_log_kwargs`: + +: Renders the event dictionary into keyword arguments for `logging.log` that attaches everything except the `event` field to the *extra* argument. + This is useful if you want to render your log entries entirely within `logging`. + +{func}`~structlog.stdlib.filter_by_level`: + +: Checks the log entry's log level against the configuration of standard library's logging. + Log entries below the threshold get silently dropped. + Put it at the beginning of your processing chain to avoid expensive operations from happening in the first place. + +{func}`~structlog.stdlib.add_logger_name`: + +: Adds the name of the logger to the event dictionary under the key `logger`. + +{func}`~structlog.stdlib.ExtraAdder`: + +: Add extra attributes of `logging.LogRecord` objects to the event dictionary. + + This processor can be used for adding data passed in the `extra` parameter of the `logging` module's log methods to the event dictionary. + +{func}`~structlog.stdlib.add_log_level`: + +: Adds the log level to the event dictionary under the key `level`. + +{func}`~structlog.stdlib.add_log_level_number`: + +: Adds the log level number to the event dictionary under the key `level_number`. + Log level numbers map to the log level names. + The Python stdlib uses them for filtering logic. + This adds the same numbers so users can leverage similar filtering. + Compare: + + ``` + level in ("warning", "error", "critical") + level_number >= 30 + ``` + + The mapping of names to numbers is in `structlog.stdlib._NAME_TO_LEVEL`. + +{func}`~structlog.stdlib.PositionalArgumentsFormatter`: + +: This processes and formats positional arguments (if any) passed to log methods in the same way the `logging` module would do, e.g. `logger.info("Hello, %s", name)`. + +`structlog` also comes with {class}`~structlog.stdlib.ProcessorFormatter` which is a `logging.Formatter` that enables you to format non-`structlog` log entries using `structlog` renderers *and* multiplex `structlog`’s output with different renderers (see [below](processor-formatter) for an example). + +(stdlib-config)= + +## Suggested Configurations + +:::{note} +We do appreciate that fully integrating `structlog` with standard library's `logging` is fiddly when done for the first time. + +This is the price of flexibility and unfortunately -- given the different needs of our users -- we can't make it any simpler without compromising someone's use-cases. +However, once it is set up, you can rely on not having to ever touch it again. +::: + +Depending *where* you'd like to do your formatting, you can take one of four approaches: + + +### Don't Integrate + +The most straight-forward option is to configure standard library `logging` close enough to what `structlog` is logging and leaving it at that. + +Since these are usually log entries from third parties that don't take advantage of `structlog`'s features, this is surprisingly often a perfectly adequate approach. + +For instance, if you log JSON in production, configure `logging` to use [*python-json-logger*] to make it print JSON too, and then tweak the configuration to match their outputs. + + +### Rendering Within `structlog` + +This is the simplest approach where `structlog` does all the heavy lifting and passes a fully-formatted string to `logging`. +Chances are, this is all you need. + +```{eval-rst} +.. mermaid:: + :align: center + + flowchart TD + %%{ init: {'theme': 'neutral'} }%% + User + structlog + stdlib[Standard Library\ne.g. logging.StreamHandler] + + User --> |"structlog.get_logger().info('foo')"| structlog + User --> |"logging.getLogger().info('foo')"| stdlib + structlog --> |"logging.getLogger().info(#quot;{'event': 'foo'}#quot;)"| stdlib ==> Output + + Output +``` + +A basic configuration to output structured logs in JSON format looks like this: + +```python +import structlog + +structlog.configure( + processors=[ + # If log level is too low, abort pipeline and throw away log entry. + structlog.stdlib.filter_by_level, + # Add the name of the logger to event dict. + structlog.stdlib.add_logger_name, + # Add log level to event dict. + structlog.stdlib.add_log_level, + # Perform %-style formatting. + structlog.stdlib.PositionalArgumentsFormatter(), + # Add a timestamp in ISO 8601 format. + structlog.processors.TimeStamper(fmt="iso"), + # If the "stack_info" key in the event dict is true, remove it and + # render the current stack trace in the "stack" key. + structlog.processors.StackInfoRenderer(), + # If the "exc_info" key in the event dict is either true or a + # sys.exc_info() tuple, remove "exc_info" and render the exception + # with traceback into the "exception" key. + structlog.processors.format_exc_info, + # If some value is in bytes, decode it to a unicode str. + structlog.processors.UnicodeDecoder(), + # Add callsite parameters. + structlog.processors.CallsiteParameterAdder( + { + structlog.processors.CallsiteParameter.FILENAME, + structlog.processors.CallsiteParameter.FUNC_NAME, + structlog.processors.CallsiteParameter.LINENO, + } + ), + # Render the final event dict as JSON. + structlog.processors.JSONRenderer() + ], + # `wrapper_class` is the bound logger that you get back from + # get_logger(). This one imitates the API of `logging.Logger`. + wrapper_class=structlog.stdlib.BoundLogger, + # `logger_factory` is used to create wrapped loggers that are used for + # OUTPUT. This one returns a `logging.Logger`. The final value (a JSON + # string) from the final processor (`JSONRenderer`) will be passed to + # the method of the same name as that you've called on the bound logger. + logger_factory=structlog.stdlib.LoggerFactory(), + # Effectively freeze configuration after creating the first bound + # logger. + cache_logger_on_first_use=True, +) +``` + +To make your program behave like a proper [*12 Factor App*](https://12factor.net/logs) that outputs only JSON to `stdout`, configure the `logging` module like this: + +``` +import logging +import sys + +logging.basicConfig( + format="%(message)s", + stream=sys.stdout, + level=logging.INFO, +) +``` + +In this case *only* your own logs are formatted as JSON: + +```pycon +>>> structlog.get_logger("test").warning("hello") +{"event": "hello", "logger": "test", "level": "warning", "timestamp": "2017-03-06T07:39:09.518720Z"} + +>>> logging.getLogger("test").warning("hello") +hello +``` + + +### Rendering Using `logging`-based Formatters + +You can choose to use `structlog` only for building the event dictionary and leave all formatting -- additionally to the output -- to the standard library. + +```{eval-rst} +.. mermaid:: + :align: center + + flowchart TD + %%{ init: {'theme': 'neutral'} }%% + User + structlog + stdlib[Standard Library\ne.g. logging.StreamHandler] + + User --> |"structlog.get_logger().info('foo', bar=42)"| structlog + User --> |"logging.getLogger().info('foo')"| stdlib + structlog --> |"logging.getLogger().info('foo', extra={"bar": 42})"| stdlib ==> Output + + Output + +``` + +```python +import structlog + +structlog.configure( + processors=[ + structlog.stdlib.filter_by_level, + structlog.stdlib.add_logger_name, + structlog.stdlib.add_log_level, + structlog.stdlib.PositionalArgumentsFormatter(), + structlog.processors.StackInfoRenderer(), + structlog.processors.format_exc_info, + structlog.processors.UnicodeDecoder(), + # Transform event dict into `logging.Logger` method arguments. + # "event" becomes "msg" and the rest is passed as a dict in + # "extra". IMPORTANT: This means that the standard library MUST + # render "extra" for the context to appear in log entries! See + # warning below. + structlog.stdlib.render_to_log_kwargs, + ], + logger_factory=structlog.stdlib.LoggerFactory(), + wrapper_class=structlog.stdlib.BoundLogger, + cache_logger_on_first_use=True, +) +``` + +Now you have the event dict available within each log record. +If you want all your log entries (i.e. also those not from your app/`structlog`) to be formatted as JSON, you can use the [*python-json-logger*] library: + +```python +import logging +import sys + +from pythonjsonlogger import jsonlogger + +handler = logging.StreamHandler(sys.stdout) +handler.setFormatter(jsonlogger.JsonFormatter()) +root_logger = logging.getLogger() +root_logger.addHandler(handler) +``` + +Now both `structlog` and `logging` will emit JSON logs: + +```pycon +>>> structlog.get_logger("test").warning("hello") +{"message": "hello", "logger": "test", "level": "warning"} + +>>> logging.getLogger("test").warning("hello") +{"message": "hello"} +``` + +:::{warning} +With this approach, it's the standard library `logging` formatter's duty to do something useful with the event dict. +In the above example that's `jsonlogger.JsonFormatter`. + +Keep this in mind if you only get the event name without any context, and exceptions are ostensibly swallowed. +::: + +(processor-formatter)= + +### Rendering Using `structlog`-based Formatters Within `logging` + +Finally, the most ambitious approach. +Here, you use `structlog`'s {class}`~structlog.stdlib.ProcessorFormatter` as a {any}`logging.Formatter` for both `logging` as well as `structlog` log entries. + +Consequently, the output is the duty of the standard library too. + +```{eval-rst} +.. mermaid:: + :align: center + + flowchart TD + %%{ init: {'theme': 'neutral'} }%% + User + structlog + structlog2[structlog] + stdlib["Standard Library"] + + User --> |"structlog.get_logger().info(#quot;foo#quot;, bar=42)"| structlog + User --> |"logging.getLogger().info(#quot;foo#quot;)"| stdlib + structlog --> |"logging.getLogger().info(event_dict, {#quot;extra#quot;: {#quot;_logger#quot;: logger, #quot;_name#quot;: name})"| stdlib + + stdlib --> |"structlog.stdlib.ProcessorFormatter.format(logging.Record)"| structlog2 + structlog2 --> |"Returns a string that is passed into logging handlers.\nThis flow is controlled by the logging configuration."| stdlib2 + + stdlib2[Standard Library\ne.g. logging.StreamHandler] ==> Output + +``` + +{class}`~structlog.stdlib.ProcessorFormatter` has two parts to its API: + +1. On the `structlog` side, the {doc}`processor chain ` must be configured to end with {func}`structlog.stdlib.ProcessorFormatter.wrap_for_formatter` as the renderer. + It converts the processed event dictionary into something that `ProcessorFormatter` understands. + +2. On the `logging` side, you must configure `ProcessorFormatter` as your formatter of choice. + `logging` then calls `ProcessorFormatter`'s `format()` method. + + For that, `ProcessorFormatter` wraps a processor chain that is responsible for rendering your log entries to strings. + +Thus, the simplest possible configuration looks like the following: + +```python +import logging +import structlog + +structlog.configure( + processors=[ + # Prepare event dict for `ProcessorFormatter`. + structlog.stdlib.ProcessorFormatter.wrap_for_formatter, + ], + logger_factory=structlog.stdlib.LoggerFactory(), +) + +formatter = structlog.stdlib.ProcessorFormatter( + processors=[structlog.dev.ConsoleRenderer()], +) + +handler = logging.StreamHandler() +# Use OUR `ProcessorFormatter` to format all `logging` entries. +handler.setFormatter(formatter) +root_logger = logging.getLogger() +root_logger.addHandler(handler) +root_logger.setLevel(logging.INFO) +``` + +which will allow both of these to work in other modules: + +```pycon +>>> import logging +>>> import structlog + +>>> logging.getLogger("stdlog").info("woo") +woo _from_structlog=False _record= +>>> structlog.get_logger("structlog").info("amazing", events="oh yes") +amazing _from_structlog=True _record= events=oh yes +``` + +Of course, you probably want timestamps and log levels in your output. +The `ProcessorFormatter` has a `foreign_pre_chain` argument which is responsible for adding properties to events from the standard library -- i.e. that do not originate from a `structlog` logger -- and which should in general match the `processors` argument to {func}`structlog.configure` so you get a consistent output. + +`_from_structlog` and `_record` allow your processors to determine whether the log entry is coming from `structlog`, and to extract information from `logging.LogRecord`s and add them to the event dictionary. +However, you probably don't want to have them in your log files, thus we've added the `ProcessorFormatter.remove_processors_meta` processor to do so conveniently. + +For example, to add timestamps, log levels, and traceback handling to your logs without `_from_structlog` and `_record` noise you should do: + +```python +timestamper = structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S") +shared_processors = [ + structlog.stdlib.add_log_level, + timestamper, +] + +structlog.configure( + processors=shared_processors + [ + structlog.stdlib.ProcessorFormatter.wrap_for_formatter, + ], + logger_factory=structlog.stdlib.LoggerFactory(), + cache_logger_on_first_use=True, +) + +formatter = structlog.stdlib.ProcessorFormatter( + # These run ONLY on `logging` entries that do NOT originate within + # structlog. + foreign_pre_chain=shared_processors, + # These run on ALL entries after the pre_chain is done. + processors=[ + # Remove _record & _from_structlog. + structlog.stdlib.ProcessorFormatter.remove_processors_meta, + structlog.dev.ConsoleRenderer(), + ], +) +``` + +which (given the same `logging.*` calls as in the previous example) will result in: + +```pycon +>>> logging.getLogger("stdlog").info("woo") +2021-11-15 11:41:47 [info ] woo +>>> structlog.get_logger("structlog").info("amazing", events="oh yes") +2021-11-15 11:41:47 [info ] amazing events=oh yes +``` + +This allows you to set up some sophisticated logging configurations. +For example, to use the standard library's `logging.config.dictConfig` to log colored logs to the console and plain logs to a file you could do: + +```python +import logging.config +import structlog + +timestamper = structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S") +pre_chain = [ + # Add the log level and a timestamp to the event_dict if the log entry + # is not from structlog. + structlog.stdlib.add_log_level, + # Add extra attributes of LogRecord objects to the event dictionary + # so that values passed in the extra parameter of log methods pass + # through to log output. + structlog.stdlib.ExtraAdder(), + timestamper, +] + +def extract_from_record(_, __, event_dict): + """ + Extract thread and process names and add them to the event dict. + """ + record = event_dict["_record"] + event_dict["thread_name"] = record.threadName + event_dict["process_name"] = record.processName + + return event_dict + +logging.config.dictConfig({ + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "plain": { + "()": structlog.stdlib.ProcessorFormatter, + "processors": [ + structlog.stdlib.ProcessorFormatter.remove_processors_meta, + structlog.dev.ConsoleRenderer(colors=False), + ], + "foreign_pre_chain": pre_chain, + }, + "colored": { + "()": structlog.stdlib.ProcessorFormatter, + "processors": [ + extract_from_record, + structlog.stdlib.ProcessorFormatter.remove_processors_meta, + structlog.dev.ConsoleRenderer(colors=True), + ], + "foreign_pre_chain": pre_chain, + }, + }, + "handlers": { + "default": { + "level": "DEBUG", + "class": "logging.StreamHandler", + "formatter": "colored", + }, + "file": { + "level": "DEBUG", + "class": "logging.handlers.WatchedFileHandler", + "filename": "test.log", + "formatter": "plain", + }, + }, + "loggers": { + "": { + "handlers": ["default", "file"], + "level": "DEBUG", + "propagate": True, + }, + } +}) +structlog.configure( + processors=[ + structlog.stdlib.add_log_level, + structlog.stdlib.PositionalArgumentsFormatter(), + timestamper, + structlog.processors.StackInfoRenderer(), + structlog.processors.format_exc_info, + structlog.stdlib.ProcessorFormatter.wrap_for_formatter, + ], + logger_factory=structlog.stdlib.LoggerFactory(), + wrapper_class=structlog.stdlib.BoundLogger, + cache_logger_on_first_use=True, +) +``` + +This defines two formatters: one plain and one colored. +Both are run for each log entry. +Log entries that do not originate from `structlog`, are additionally pre-processed using a cached `timestamper` and {func}`~structlog.stdlib.add_log_level`. + +Additionally, for both `logging` and `structlog` -- but only for the colorful logger -- we also extract some data from {class}`logging.LogRecord`: + +```pycon +>>> logging.getLogger().warning("bar") +2021-11-15 13:26:52 [warning ] bar process_name=MainProcess thread_name=MainThread + +>>> structlog.get_logger("structlog").warning("foo", x=42) +2021-11-15 13:26:52 [warning ] foo process_name=MainProcess thread_name=MainThread x=42 + +>>> pathlib.Path("test.log").read_text() +2021-11-15 13:26:52 [warning ] bar +2021-11-15 13:26:52 [warning ] foo x=42 +``` + +(Sadly, you have to imagine the colors in the first two outputs.) + +If you leave `foreign_pre_chain` as `None`, formatting will be left to `logging`. +Meaning: you can define a `format` for {class}`~structlog.stdlib.ProcessorFormatter` too! + + +[*python-json-logger*]: https://github.com/madzak/python-json-logger> diff --git a/docs/standard-library.rst b/docs/standard-library.rst deleted file mode 100644 index 62e6b0cc..00000000 --- a/docs/standard-library.rst +++ /dev/null @@ -1,542 +0,0 @@ -Standard Library Logging -======================== - -Ideally, ``structlog`` should be able to be used as a drop-in replacement for standard library's `logging` by wrapping it. -In other words, you should be able to replace your call to `logging.getLogger` by a call to `structlog.get_logger` and things should keep working as before (if ``structlog`` is configured right, see `stdlib-config` below). - -If you run into incompatibilities, it is a *bug* so please take the time to `report it `_! -If you're a heavy `logging` user, your `help `_ to ensure a better compatibility would be highly appreciated! - -.. note:: - - The quickest way to get started with ``structlog`` and `logging` is `structlog.stdlib.recreate_defaults()` that will recreate the default configuration on top of `logging` and optionally configure `logging` for you. - - -Just Enough ``logging`` ------------------------ - -If you want to use ``structlog`` with `logging`, you should have at least a fleeting understanding on how the standard library operates because ``structlog`` will *not* do any magic things in the background for you. -Most importantly you have to *configure* the `logging` system *additionally* to configuring ``structlog``. - -Usually it is enough to use:: - - import logging - import sys - - logging.basicConfig( - format="%(message)s", - stream=sys.stdout, - level=logging.INFO, - ) - -This will send all log messages with the `log level `_ ``logging.INFO`` and above (that means that e.g. `logging.debug` calls are ignored) to standard out without any special formatting by the standard library. - -If you require more complex behavior, please refer to the standard library's `logging` documentation. - - -Concrete Bound Logger ---------------------- - -To make ``structlog``'s behavior less magicy, it ships with a standard library-specific wrapper class that has an explicit API instead of improvising: `structlog.stdlib.BoundLogger`. -It behaves exactly like the generic `structlog.BoundLogger` except: - -- it's slightly faster due to less overhead, -- has an explicit API that mirrors the log methods of standard library's `logging.Logger`, -- it has correct type hints, -- hence causing less cryptic error messages if you get method names wrong. - ----- - -If you're using static types (e.g. with Mypy) you also may want to use `structlog.stdlib.get_logger()` that has the appropriate type hints if you're using `structlog.stdlib.BoundLogger`. -Please note though, that it will neither configure nor verify your configuration. -It will call `structlog.get_logger()` just like if you would've called it -- the only difference are the type hints. - - -``asyncio`` -^^^^^^^^^^^ - -For ``asyncio`` applications, you may not want your whole application to block while your processor chain is formatting your log entries. -For that use case ``structlog`` comes with `structlog.stdlib.AsyncBoundLogger` that will do all processing in a thread pool executor. - -This means an increased computational cost per log entry but your application will never block because of logging. - -To use it, :doc:`configure ` ``structlog`` to use `AsyncBoundLogger` as ``wrapper_class``. - - -Processors ----------- - -``structlog`` comes with a few standard library-specific processors: - -`render_to_log_kwargs`: - Renders the event dictionary into keyword arguments for `logging.log` that attaches everything except the ``event`` field to the *extra* argument. - This is useful if you want to render your log entries entirely within `logging`. - -`filter_by_level`: - Checks the log entry's log level against the configuration of standard library's logging. - Log entries below the threshold get silently dropped. - Put it at the beginning of your processing chain to avoid expensive operations from happening in the first place. - -`add_logger_name`: - Adds the name of the logger to the event dictionary under the key ``logger``. - -`ExtraAdder`: - Add extra attributes of `logging.LogRecord` objects to the event dictionary. - - This processor can be used for adding data passed in the ``extra`` parameter of the `logging` module's log methods to the event dictionary. - -:func:`~structlog.stdlib.add_log_level`: - Adds the log level to the event dictionary under the key ``level``. - -`add_log_level_number`: - Adds the log level number to the event dictionary under the key ``level_number``. - Log level numbers map to the log level names. - The Python stdlib uses them for filtering logic. - This adds the same numbers so users can leverage similar filtering. - Compare:: - - level in ("warning", "error", "critical") - level_number >= 30 - - The mapping of names to numbers is in ``structlog.stdlib._NAME_TO_LEVEL``. - -`PositionalArgumentsFormatter`: - This processes and formats positional arguments (if any) passed to log methods in the same way the ``logging`` module would do, e.g. ``logger.info("Hello, %s", name)``. - - -``structlog`` also comes with `ProcessorFormatter` which is a `logging.Formatter` that enables you to format non-``structlog`` log entries using ``structlog`` renderers *and* multiplex ``structlog``’s output with different renderers (see below for an example). - - -.. _stdlib-config: - -Suggested Configurations ------------------------- - -.. note:: - - We do appreciate that fully integrating ``structlog`` with standard library's ``logging`` is fiddly when done for the first time. - - This is the price of flexibility and unfortunately -- given the different needs of our users -- we can't make it any simpler without compromising someone's use-cases. - However, once it is set up, you can rely on not having to ever touch it again. - -Depending *where* you'd like to do your formatting, you can take one of four approaches: - - -Rendering Within ``structlog`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -This is the simplest approach where ``structlog`` does all the heavy lifting and passes a fully-formatted string to ``logging``. -Chances are, this is all you need. - -.. mermaid:: - :align: center - - flowchart TD - %%{ init: {'theme': 'neutral'} }%% - User - structlog - stdlib[Standard Library\ne.g. logging.StreamHandler] - - User --> |"structlog.get_logger().info('foo')"| structlog - User --> |"logging.getLogger().info('foo')"| stdlib - structlog --> |"logging.getLogger().info(#quot;{'event': 'foo'}#quot;)"| stdlib ==> Output - - Output - -A basic configuration to output structured logs in JSON format looks like this: - -.. code-block:: python - - import structlog - - structlog.configure( - processors=[ - # If log level is too low, abort pipeline and throw away log entry. - structlog.stdlib.filter_by_level, - # Add the name of the logger to event dict. - structlog.stdlib.add_logger_name, - # Add log level to event dict. - structlog.stdlib.add_log_level, - # Perform %-style formatting. - structlog.stdlib.PositionalArgumentsFormatter(), - # Add a timestamp in ISO 8601 format. - structlog.processors.TimeStamper(fmt="iso"), - # If the "stack_info" key in the event dict is true, remove it and - # render the current stack trace in the "stack" key. - structlog.processors.StackInfoRenderer(), - # If the "exc_info" key in the event dict is either true or a - # sys.exc_info() tuple, remove "exc_info" and render the exception - # with traceback into the "exception" key. - structlog.processors.format_exc_info, - # If some value is in bytes, decode it to a unicode str. - structlog.processors.UnicodeDecoder(), - # Add callsite parameters. - structlog.processors.CallsiteParameterAdder( - { - structlog.processors.CallsiteParameter.FILENAME, - structlog.processors.CallsiteParameter.FUNC_NAME, - structlog.processors.CallsiteParameter.LINENO, - } - ), - # Render the final event dict as JSON. - structlog.processors.JSONRenderer() - ], - # `wrapper_class` is the bound logger that you get back from - # get_logger(). This one imitates the API of `logging.Logger`. - wrapper_class=structlog.stdlib.BoundLogger, - # `logger_factory` is used to create wrapped loggers that are used for - # OUTPUT. This one returns a `logging.Logger`. The final value (a JSON - # string) from the final processor (`JSONRenderer`) will be passed to - # the method of the same name as that you've called on the bound logger. - logger_factory=structlog.stdlib.LoggerFactory(), - # Effectively freeze configuration after creating the first bound - # logger. - cache_logger_on_first_use=True, - ) - -To make your program behave like a proper `12 factor app`_ that outputs only JSON to ``stdout``, configure the `logging` module like this:: - - import logging - import sys - - logging.basicConfig( - format="%(message)s", - stream=sys.stdout, - level=logging.INFO, - ) - -In this case *only* your own logs are formatted as JSON: - -.. code-block:: pycon - - >>> structlog.get_logger("test").warning("hello") - {"event": "hello", "logger": "test", "level": "warning", "timestamp": "2017-03-06T07:39:09.518720Z"} - - >>> logging.getLogger("test").warning("hello") - hello - - -Rendering Using `logging`-based Formatters -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -You can choose to use ``structlog`` only for building the event dictionary and leave all formatting -- additionally to the output -- to the standard library. - -.. mermaid:: - :align: center - - flowchart TD - %%{ init: {'theme': 'neutral'} }%% - User - structlog - stdlib[Standard Library\ne.g. logging.StreamHandler] - - User --> |"structlog.get_logger().info('foo', bar=42)"| structlog - User --> |"logging.getLogger().info('foo')"| stdlib - structlog --> |"logging.getLogger().info('foo', extra={"bar": 42})"| stdlib ==> Output - - Output - - -.. code-block:: python - - import structlog - - structlog.configure( - processors=[ - structlog.stdlib.filter_by_level, - structlog.stdlib.add_logger_name, - structlog.stdlib.add_log_level, - structlog.stdlib.PositionalArgumentsFormatter(), - structlog.processors.StackInfoRenderer(), - structlog.processors.format_exc_info, - structlog.processors.UnicodeDecoder(), - # Transform event dict into `logging.Logger` method arguments. - # "event" becomes "msg" and the rest is passed as a dict in - # "extra". IMPORTANT: This means that the standard library MUST - # render "extra" for the context to appear in log entries! See - # warning below. - structlog.stdlib.render_to_log_kwargs, - ], - logger_factory=structlog.stdlib.LoggerFactory(), - wrapper_class=structlog.stdlib.BoundLogger, - cache_logger_on_first_use=True, - ) - -Now you have the event dict available within each log record. -If you want all your log entries (i.e. also those not from your app/``structlog``) to be formatted as JSON, you can use the python-json-logger_ library: - -.. code-block:: python - - import logging - import sys - - from pythonjsonlogger import jsonlogger - - handler = logging.StreamHandler(sys.stdout) - handler.setFormatter(jsonlogger.JsonFormatter()) - root_logger = logging.getLogger() - root_logger.addHandler(handler) - -Now both ``structlog`` and ``logging`` will emit JSON logs: - -.. code-block:: pycon - - >>> structlog.get_logger("test").warning("hello") - {"message": "hello", "logger": "test", "level": "warning"} - - >>> logging.getLogger("test").warning("hello") - {"message": "hello"} - - -.. warning:: - - With this approach, it's the standard library ``logging`` formatter's duty to do something useful with the event dict. - In the above example that's ``jsonlogger.JsonFormatter``. - - Keep this in mind if you only get the event name without any context, and exceptions are ostensibly swallowed. - -.. _processor-formatter: - -Rendering Using ``structlog``-based Formatters Within `logging` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Finally, the most ambitious approach. -Here, you use ``structlog``'s `ProcessorFormatter` as a `logging.Formatter` for both `logging` as well as ``structlog`` log entries. - -Consequently, the output is the duty of the standard library too. - -.. mermaid:: - :align: center - - flowchart TD - %%{ init: {'theme': 'neutral'} }%% - User - structlog - structlog2[structlog] - stdlib["Standard Library"] - - User --> |"structlog.get_logger().info(#quot;foo#quot;, bar=42)"| structlog - User --> |"logging.getLogger().info(#quot;foo#quot;)"| stdlib - structlog --> |"logging.getLogger().info(event_dict, {#quot;extra#quot;: {#quot;_logger#quot;: logger, #quot;_name#quot;: name})"| stdlib - - stdlib --> |"structlog.stdlib.ProcessorFormatter.format(logging.Record)"| structlog2 - structlog2 --> |"Returns a string that is passed into logging handlers.\nThis flow is controlled by the logging configuration."| stdlib2 - - stdlib2[Standard Library\ne.g. logging.StreamHandler] ==> Output - - -`ProcessorFormatter` has two parts to its API: - -#. On the ``structlog`` side, the :doc:`processor chain ` must be configured to end with `structlog.stdlib.ProcessorFormatter.wrap_for_formatter` as the renderer. - It converts the processed event dictionary into something that `ProcessorFormatter` understands. -#. On the `logging` side, you must configure `ProcessorFormatter` as your formatter of choice. - `logging` then calls `ProcessorFormatter`'s ``format()`` method. - - For that, `ProcessorFormatter` wraps a processor chain that is responsible for rendering your log entries to strings. - -Thus, the simplest possible configuration looks like the following: - -.. code-block:: python - - import logging - import structlog - - structlog.configure( - processors=[ - # Prepare event dict for `ProcessorFormatter`. - structlog.stdlib.ProcessorFormatter.wrap_for_formatter, - ], - logger_factory=structlog.stdlib.LoggerFactory(), - ) - - formatter = structlog.stdlib.ProcessorFormatter( - processors=[structlog.dev.ConsoleRenderer()], - ) - - handler = logging.StreamHandler() - # Use OUR `ProcessorFormatter` to format all `logging` entries. - handler.setFormatter(formatter) - root_logger = logging.getLogger() - root_logger.addHandler(handler) - root_logger.setLevel(logging.INFO) - -which will allow both of these to work in other modules: - -.. code-block:: pycon - - >>> import logging - >>> import structlog - - >>> logging.getLogger("stdlog").info("woo") - woo _from_structlog=False _record= - >>> structlog.get_logger("structlog").info("amazing", events="oh yes") - amazing _from_structlog=True _record= events=oh yes - -Of course, you probably want timestamps and log levels in your output. -The `ProcessorFormatter` has a ``foreign_pre_chain`` argument which is responsible for adding properties to events from the standard library -- i.e. that do not originate from a ``structlog`` logger -- and which should in general match the ``processors`` argument to `structlog.configure` so you get a consistent output. - -``_from_structlog`` and ``_record`` allow your processors to determine whether the log entry is coming from ``structlog``, and to extract information from `logging.LogRecord`\s and add them to the event dictionary. -However, you probably don't want to have them in your log files, thus we've added the `ProcessorFormatter.remove_processors_meta` processor to do so conveniently. - -For example, to add timestamps, log levels, and traceback handling to your logs without ``_from_structlog`` and ``_record`` noise you should do: - -.. code-block:: python - - timestamper = structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S") - shared_processors = [ - structlog.stdlib.add_log_level, - timestamper, - ] - - structlog.configure( - processors=shared_processors + [ - structlog.stdlib.ProcessorFormatter.wrap_for_formatter, - ], - logger_factory=structlog.stdlib.LoggerFactory(), - cache_logger_on_first_use=True, - ) - - formatter = structlog.stdlib.ProcessorFormatter( - # These run ONLY on `logging` entries that do NOT originate within - # structlog. - foreign_pre_chain=shared_processors, - # These run on ALL entries after the pre_chain is done. - processors=[ - # Remove _record & _from_structlog. - structlog.stdlib.ProcessorFormatter.remove_processors_meta, - structlog.dev.ConsoleRenderer(), - ], - ) - -which (given the same ``logging.*`` calls as in the previous example) will result in: - -.. code-block:: pycon - - >>> logging.getLogger("stdlog").info("woo") - 2021-11-15 11:41:47 [info ] woo - >>> structlog.get_logger("structlog").info("amazing", events="oh yes") - 2021-11-15 11:41:47 [info ] amazing events=oh yes - -This allows you to set up some sophisticated logging configurations. -For example, to use the standard library's `logging.config.dictConfig` to log colored logs to the console and plain logs to a file you could do: - -.. code-block:: python - - import logging.config - import structlog - - timestamper = structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S") - pre_chain = [ - # Add the log level and a timestamp to the event_dict if the log entry - # is not from structlog. - structlog.stdlib.add_log_level, - # Add extra attributes of LogRecord objects to the event dictionary - # so that values passed in the extra parameter of log methods pass - # through to log output. - structlog.stdlib.ExtraAdder(), - timestamper, - ] - - def extract_from_record(_, __, event_dict): - """ - Extract thread and process names and add them to the event dict. - """ - record = event_dict["_record"] - event_dict["thread_name"] = record.threadName - event_dict["process_name"] = record.processName - - return event_dict - - logging.config.dictConfig({ - "version": 1, - "disable_existing_loggers": False, - "formatters": { - "plain": { - "()": structlog.stdlib.ProcessorFormatter, - "processors": [ - structlog.stdlib.ProcessorFormatter.remove_processors_meta, - structlog.dev.ConsoleRenderer(colors=False), - ], - "foreign_pre_chain": pre_chain, - }, - "colored": { - "()": structlog.stdlib.ProcessorFormatter, - "processors": [ - extract_from_record, - structlog.stdlib.ProcessorFormatter.remove_processors_meta, - structlog.dev.ConsoleRenderer(colors=True), - ], - "foreign_pre_chain": pre_chain, - }, - }, - "handlers": { - "default": { - "level": "DEBUG", - "class": "logging.StreamHandler", - "formatter": "colored", - }, - "file": { - "level": "DEBUG", - "class": "logging.handlers.WatchedFileHandler", - "filename": "test.log", - "formatter": "plain", - }, - }, - "loggers": { - "": { - "handlers": ["default", "file"], - "level": "DEBUG", - "propagate": True, - }, - } - }) - structlog.configure( - processors=[ - structlog.stdlib.add_log_level, - structlog.stdlib.PositionalArgumentsFormatter(), - timestamper, - structlog.processors.StackInfoRenderer(), - structlog.processors.format_exc_info, - structlog.stdlib.ProcessorFormatter.wrap_for_formatter, - ], - logger_factory=structlog.stdlib.LoggerFactory(), - wrapper_class=structlog.stdlib.BoundLogger, - cache_logger_on_first_use=True, - ) - -This defines two formatters: one plain and one colored. -Both are run for each log entry. -Log entries that do not originate from ``structlog``, are additionally pre-processed using a cached ``timestamper`` and :func:`~structlog.stdlib.add_log_level`. - -Additionally, for both `logging` and ``structlog`` -- but only for the colorful logger -- we also extract some data from `logging.LogRecord`: - -.. code-block:: pycon - - >>> logging.getLogger().warning("bar") - 2021-11-15 13:26:52 [warning ] bar process_name=MainProcess thread_name=MainThread - - >>> structlog.get_logger("structlog").warning("foo", x=42) - 2021-11-15 13:26:52 [warning ] foo process_name=MainProcess thread_name=MainThread x=42 - - >>> pathlib.Path("test.log").read_text() - 2021-11-15 13:26:52 [warning ] bar - 2021-11-15 13:26:52 [warning ] foo x=42 - -(Sadly, you have to imagine the colors in the first two outputs.) - -If you leave ``foreign_pre_chain`` as `None`, formatting will be left to `logging`. -Meaning: you can define a ``format`` for `ProcessorFormatter` too! - - -Don't Integrate -^^^^^^^^^^^^^^^ - -The most straight-forward option is to configure standard library `logging` close enough to what ``structlog`` is logging and leaving it at that. - -Since these are usually log entries from third parties that don't take advantage of ``structlog``'s features, this is surprisingly often a perfectly adequate approach. - -For instance, if you log JSON in production, configure `logging` to use python-json-logger_ to make it print JSON too, and then tweak the configuration to match their outputs. - - -.. _`12 factor app`: https://12factor.net/logs -.. _python-json-logger: https://github.com/madzak/python-json-logger> From b1057069b469ad93a4b4ddbe0997280580709b76 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 08:04:40 +0200 Subject: [PATCH 0824/1520] Increase docs font size --- docs/_static/custom.css | 7 +++++++ docs/conf.py | 2 ++ 2 files changed, 9 insertions(+) create mode 100644 docs/_static/custom.css diff --git a/docs/_static/custom.css b/docs/_static/custom.css new file mode 100644 index 00000000..2fc0e528 --- /dev/null +++ b/docs/_static/custom.css @@ -0,0 +1,7 @@ +article p { + font-size: 19px; +} + +p.admonition-title { + font-size: 15px; +} diff --git a/docs/conf.py b/docs/conf.py index d7a4b0e3..51184bba 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -92,6 +92,8 @@ html_theme_options = {} html_logo = "_static/structlog_logo_small_transparent.png" html_static_path = ["_static"] +html_css_files = ["custom.css"] + htmlhelp_basename = "structlogdoc" _logo = ( From e736db462323a29f2a19455ac4f26e48b1e7f493 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 08:24:48 +0200 Subject: [PATCH 0825/1520] Shorten link to fit on phone displays --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 27dec150..c1a961cd 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ The logs-loving futuristic beaver logo has been contributed by [Russell Keith-Ma - **PyPI**: - **Source Code**: - **Documentation**: -- **Changelog**: +- **Changelog**: [Changelog](https://www.structlog.org/en/stable/changelog.html) - **Get Help**: please use the `structlog` tag on [StackOverflow](https://stackoverflow.com/questions/tagged/structlog) - **Third-party Extensions**: - **Supported Python Versions**: 3.7 and later From 9ef7fb0c3cc274f8336c39715f5d992a1a19d9ce Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 08:25:48 +0200 Subject: [PATCH 0826/1520] Another link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c1a961cd..4bcf3054 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ The logs-loving futuristic beaver logo has been contributed by [Russell Keith-Ma - **Documentation**: - **Changelog**: [Changelog](https://www.structlog.org/en/stable/changelog.html) - **Get Help**: please use the `structlog` tag on [StackOverflow](https://stackoverflow.com/questions/tagged/structlog) -- **Third-party Extensions**: +- **Third-party Extensions**: [Wiki page](https://github.com/hynek/structlog/wiki/Third-party-Extensions) - **Supported Python Versions**: 3.7 and later From d95e2277f19e494b39b40ba960baf7257f77b21c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 09:04:25 +0200 Subject: [PATCH 0827/1520] fix spelling --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4bcf3054..02eb4380 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ The logs-loving futuristic beaver logo has been contributed by [Russell Keith-Ma - **Source Code**: - **Documentation**: - **Changelog**: [Changelog](https://www.structlog.org/en/stable/changelog.html) -- **Get Help**: please use the `structlog` tag on [StackOverflow](https://stackoverflow.com/questions/tagged/structlog) +- **Get Help**: please use the `structlog` tag on [*Stack Overflow*](https://stackoverflow.com/questions/tagged/structlog) - **Third-party Extensions**: [Wiki page](https://github.com/hynek/structlog/wiki/Third-party-Extensions) - **Supported Python Versions**: 3.7 and later From 47eb4af969751544497c73b3f2227a3440df4505 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 09:09:00 +0200 Subject: [PATCH 0828/1520] Simplify list --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 02eb4380..eb55efe4 100644 --- a/README.md +++ b/README.md @@ -63,14 +63,14 @@ The logs-loving futuristic beaver logo has been contributed by [Russell Keith-Ma ## Project Information -- **License**: *dual* [Apache License, version 2 and MIT](https://www.structlog.org/en/latest/license.html) -- **PyPI**: -- **Source Code**: -- **Documentation**: -- **Changelog**: [Changelog](https://www.structlog.org/en/stable/changelog.html) +- **License**: *dual* [Apache License, version 2 **and** MIT](https://www.structlog.org/en/latest/license.html) - **Get Help**: please use the `structlog` tag on [*Stack Overflow*](https://stackoverflow.com/questions/tagged/structlog) -- **Third-party Extensions**: [Wiki page](https://github.com/hynek/structlog/wiki/Third-party-Extensions) - **Supported Python Versions**: 3.7 and later +- [**PyPI**](https://pypi.org/project/structlog/) +- [**Source Code**](https://github.com/hynek/structlog) +- [**Documentation**](https://www.structlog.org/) +- [**Changelog**](https://www.structlog.org/en/stable/changelog.html) +- [**Third-party Extensions**](https://github.com/hynek/structlog/wiki/Third-party-Extensions) ## `structlog` for Enterprise From a95235902728d83e281d9395c8d273b915925f38 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 09:16:47 +0200 Subject: [PATCH 0829/1520] Give lines more space to breath --- docs/_static/custom.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/_static/custom.css b/docs/_static/custom.css index 2fc0e528..3fc73fbc 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -1,7 +1,9 @@ article p { font-size: 19px; + line-height: 31px;; } p.admonition-title { font-size: 15px; + line-height: 20px;; } From 556984445a2e6c073a4db405ea5f937ef3018049 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 09:20:02 +0200 Subject: [PATCH 0830/1520] Fix ToC size --- docs/_static/custom.css | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/_static/custom.css b/docs/_static/custom.css index 3fc73fbc..8a44438a 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -1,9 +1,15 @@ article p { font-size: 19px; - line-height: 31px;; + line-height: 31px; + ; } p.admonition-title { font-size: 15px; - line-height: 20px;; + line-height: 20px; +} + +li>a { + font-size: 19px; + line-height: 31px; } From a41eb30346d5fcf8368aee8fb47f436bdd4e2676 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 09:24:00 +0200 Subject: [PATCH 0831/1520] Avoid some x-scroll --- docs/getting-started.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 673aca30..ec5c2101 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -34,7 +34,7 @@ Here, `structlog` takes advantage of its default settings: - Output is sent to [standard out] instead doing nothing. - It imitates standard library {mod}`logging`'s log level names for familiarity. - By default, no level-based filtering is done, but it comes with a very fast filtering machinery in the form of {func}`structlog.make_filtering_bound_logger()`. + By default, no level-based filtering is done, but it comes with a very fast filtering machinery in the form of {func}`~structlog.make_filtering_bound_logger()`. - Like in `logging`, positional arguments are [interpolated into the message string using %](https://docs.python.org/3/library/stdtypes.html#old-string-formatting). That might look dated, but it's *much* faster than using {any}`str.format` and allows ``structlog`` to be used as drop-in replacement for {mod}`logging`. If you *know* that the log entry is *always* gonna be logged out, just use [f-strings](https://docs.python.org/3/tutorial/inputoutput.html#formatted-string-literals) which are the fastest. @@ -69,9 +69,9 @@ log = structlog.get_logger() :::{note} - {func}`structlog.stdlib.recreate_defaults()` allows you to switch `structlog` to using standard library's `logging` module for output for better interoperability with just one function call. -- {func}`structlog.make_filtering_bound_logger()` (re-)uses {any}`logging`'s log levels, but doesn't use `logging` at all. - The exposed API is {class}`structlog.types.FilteringBoundLogger`. -- For brevity and to enable doctests, all further examples in `structlog`'s documentation use the more simplistic {class}`structlog.processors.KeyValueRenderer()` without timestamps. +- {func}`~structlog.make_filtering_bound_logger()` (re-)uses {any}`logging`'s log levels, but doesn't use `logging` at all. + The exposed API is {class}`~structlog.types.FilteringBoundLogger`. +- For brevity and to enable doctests, all further examples in `structlog`'s documentation use the more simplistic {class}`~structlog.processors.KeyValueRenderer()` without timestamps. ::: Here you go, structured logging! From bdad1e108c845c4cf97b1341d3fb4f77ae28059c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 09:25:50 +0200 Subject: [PATCH 0832/1520] Linkify --- docs/bound-loggers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/bound-loggers.md b/docs/bound-loggers.md index d9de4334..cf2736ea 100644 --- a/docs/bound-loggers.md +++ b/docs/bound-loggers.md @@ -62,7 +62,7 @@ Whenever you call one of those methods on the *bound logger*, it will: For flexibility, the final processor can return either a string[^str] that is passed directly as a positional parameter, or a tuple `(args, kwargs)` that are passed as `wrapped_logger.log_method(*args, **kwargs)`. -[^str]: `str`, `bytes`, or `bytearray` to be exact. +[^str]: {any}`str`, {any}`bytes`, or {any}`bytearray` to be exact. ### Step-by-Step Example From 47cadb89e87ace8d64ec7b347c0f308389d99c32 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 09:40:15 +0200 Subject: [PATCH 0833/1520] Rename types to typing and deprecate the old name --- CHANGELOG.md | 2 + docs/api.rst | 6 +- docs/bound-loggers.md | 8 +- docs/conf.py | 2 +- docs/custom-wrappers.md | 2 +- docs/getting-started.md | 2 +- docs/index.md | 2 +- docs/processors.md | 2 +- docs/standard-library.md | 2 +- docs/{types.md => typing.md} | 12 +- src/structlog/__init__.py | 2 + src/structlog/_base.py | 2 +- src/structlog/_config.py | 2 +- src/structlog/_frames.py | 2 +- src/structlog/_log_levels.py | 2 +- src/structlog/contextvars.py | 2 +- src/structlog/dev.py | 2 +- src/structlog/processors.py | 2 +- src/structlog/stdlib.py | 2 +- src/structlog/testing.py | 4 +- src/structlog/threadlocal.py | 4 +- src/structlog/tracebacks.py | 2 +- src/structlog/twisted.py | 2 +- src/structlog/types.py | 243 ++++------------------------------- src/structlog/typing.py | 235 +++++++++++++++++++++++++++++++++ tests/test_processors.py | 2 +- tests/test_stdlib.py | 2 +- typing_examples.py | 4 +- 28 files changed, 299 insertions(+), 257 deletions(-) rename docs/{types.md => typing.md} (59%) create mode 100644 src/structlog/typing.py diff --git a/CHANGELOG.md b/CHANGELOG.md index f66ba089..dfe8f10e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ So please make sure to **always** properly configure your applications. - Accessing package metadata as attributes on the `structlog` module is deprecated (e.g. `structlog.__version__`). Please use [`importlib.metadata`](https://docs.python.org/3.10/library/importlib.metadata.html) instead (for Python 3.7: the [*importlib-metadata*](https://pypi.org/project/importlib-metadata/) PyPI package). +- The `structlog.types` module is now deprecated in favor of the `structlog.typing` module. + It seems like the Python typing community is settling on this name. ### Added diff --git a/docs/api.rst b/docs/api.rst index 7cd05422..c5e4dfbe 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -324,10 +324,10 @@ API Reference .. autoclass:: SyntaxError_ -`structlog.types` Module ------------------------- +`structlog.typing` Module +------------------------- -.. automodule:: structlog.types +.. automodule:: structlog.typing .. autoclass:: BindableLogger diff --git a/docs/bound-loggers.md b/docs/bound-loggers.md index cf2736ea..3eaef919 100644 --- a/docs/bound-loggers.md +++ b/docs/bound-loggers.md @@ -41,14 +41,14 @@ To manipulate the context dictionary, a *bound logger* offers to: In any case, the original bound logger or its context are never mutated. They always return a *copy* of the bound logger with a *new* context that reflects your changes. -This part of the API is defined in the {class}`typing.Protocol` called {class}`structlog.types.BindableLogger`. -N.B. that the protocol is marked {func}`typing.runtime_checkable` which means that you can check an object for being a *bound logger* using `isinstance(obj, structlog.types.BindableLogger)`. +This part of the API is defined in the {class}`typing.Protocol` called {class}`structlog.typing.BindableLogger`. +N.B. that the protocol is marked {func}`typing.runtime_checkable` which means that you can check an object for being a *bound logger* using `isinstance(obj, structlog.typing.BindableLogger)`. ## Logging Finally, a *bound logger* also **indirectly** exposes the logging methods of the *wrapped logger*. -By default, that's a {class}`~structlog.types.FilteringBoundLogger` that is wrapping a {class}`~structlog.PrintLogger`. +By default, that's a {class}`~structlog.typing.FilteringBoundLogger` that is wrapping a {class}`~structlog.PrintLogger`. They both share the set of log methods that's present in the standard library: `debug()`, `info()`, `warning()`, `error()`, and `critical()`. Whenever you call one of those methods on the *bound logger*, it will: @@ -77,7 +77,7 @@ logger = structlog.get_logger() log = logger.bind(foo="bar") ``` -Now `log` is a *bound logger* of type {class}`~structlog.types.FilteringBoundLogger` (but in the default config there's no filtering). +Now `log` is a *bound logger* of type {class}`~structlog.typing.FilteringBoundLogger` (but in the default config there's no filtering). `log`'s context is `{"foo": "bar"}` and its wrapped logger is a {class}`structlog.PrintLogger`. Now if you call `log.info("Hello, %s!", "world", number=42)` the following happens: diff --git a/docs/conf.py b/docs/conf.py index 51184bba..f848d4e6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -70,7 +70,7 @@ ("py:class", "Styles"), ("py:class", "WrappedLogger"), ("py:class", "structlog.threadlocal.TLLogger"), - ("py:class", "structlog.types.EventDict"), + ("py:class", "structlog.typing.EventDict"), ] # If true, '()' will be appended to :func: etc. cross-reference text. diff --git a/docs/custom-wrappers.md b/docs/custom-wrappers.md index bf169045..5c8ff445 100644 --- a/docs/custom-wrappers.md +++ b/docs/custom-wrappers.md @@ -23,7 +23,7 @@ This wrapper class is [configurable](configuration.md). Originally, `structlog` used a generic wrapper class {class}`structlog.BoundLogger` by default. That class still ships with `structlog` and can wrap *any* logger class by intercepting unknown method names and proxying them to the wrapped logger. -Nowadays, the default is a {class}`structlog.types.FilteringBoundLogger` that imitates standard library's log levels with the possibility of efficiently filtering at a certain level (inactive log methods are a plain `return None` each). +Nowadays, the default is a {class}`structlog.typing.FilteringBoundLogger` that imitates standard library's log levels with the possibility of efficiently filtering at a certain level (inactive log methods are a plain `return None` each). If you're integrating with {mod}`logging` or Twisted, you may was to use one of their specific *bound loggers* ({class}`structlog.stdlib.BoundLogger` and {class}`structlog.twisted.BoundLogger`, respectively). diff --git a/docs/getting-started.md b/docs/getting-started.md index ec5c2101..d8761144 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -70,7 +70,7 @@ log = structlog.get_logger() :::{note} - {func}`structlog.stdlib.recreate_defaults()` allows you to switch `structlog` to using standard library's `logging` module for output for better interoperability with just one function call. - {func}`~structlog.make_filtering_bound_logger()` (re-)uses {any}`logging`'s log levels, but doesn't use `logging` at all. - The exposed API is {class}`~structlog.types.FilteringBoundLogger`. + The exposed API is {class}`~structlog.typing.FilteringBoundLogger`. - For brevity and to enable doctests, all further examples in `structlog`'s documentation use the more simplistic {class}`~structlog.processors.KeyValueRenderer()` without timestamps. ::: diff --git a/docs/index.md b/docs/index.md index 80902b38..0edd0cae 100644 --- a/docs/index.md +++ b/docs/index.md @@ -35,7 +35,7 @@ processors contextvars development testing -types +typing ``` (integration)= diff --git a/docs/processors.md b/docs/processors.md index 86724d22..443e693e 100644 --- a/docs/processors.md +++ b/docs/processors.md @@ -13,7 +13,7 @@ Each processors receives three positional arguments: **logger** : Your wrapped logger object. - For example {class}`logging.Logger` or {class}`structlog.types.FilteringBoundLogger` (default). + For example {class}`logging.Logger` or {class}`structlog.typing.FilteringBoundLogger` (default). **method_name** diff --git a/docs/standard-library.md b/docs/standard-library.md index 3ca5aee7..07f00f19 100644 --- a/docs/standard-library.md +++ b/docs/standard-library.md @@ -42,7 +42,7 @@ If you want to take advantage of said type hints, you have to either annotate th Please note though, that it will neither configure nor verify your configuration. It will call `structlog.get_logger()` just like if you would've called it -- the only difference are the type hints. -See also {doc}`types`. +See also {doc}`typing`. ### `asyncio` diff --git a/docs/types.md b/docs/typing.md similarity index 59% rename from docs/types.md rename to docs/typing.md index fd68d319..d1324c16 100644 --- a/docs/types.md +++ b/docs/typing.md @@ -1,19 +1,19 @@ # Type Hints -Static type hints -- together with a type checker like [Mypy](https://mypy.readthedocs.io/en/stable/) -- are an excellent way to make your code more robust, self-documenting, and maintainable in the long run. +Static type hints -- together with a type checker like [*Mypy*](https://mypy.readthedocs.io/en/stable/) -- are an excellent way to make your code more robust, self-documenting, and maintainable in the long run. And as of 20.2.0, `structlog` comes with type hints for all of its APIs. Since `structlog` is highly configurable and tries to give a clean facade to its users, adding types without breaking compatibility -- while remaining useful! -- was a formidable task. -______________________________________________________________________ +--- -The main problem is that `structlog.get_logger()` returns whatever you've configured the bound logger to be. -The only commonality are the binding methods like `bind()` and we've extracted them into the {class}`structlog.types.BindableLogger` {class}`~typing.Protocol`. -But using that as a return type is worse than useless, because you'd have to use `typing.cast` on every logger returned by `structlog.get_logger()`, if you wanted to actually call any logging methods. +The main problem is that `structlog.get_logger()` returns whatever you've configured the *bound logger* to be. +The only commonality are the binding methods like `bind()` and we've extracted them into the {class}`structlog.typing.BindableLogger` {class}`~typing.Protocol`. +But using that as a return type is worse than useless, because you'd have to use {func}`typing.cast` on every logger returned by `structlog.get_logger()`, if you wanted to actually call any logging methods. The second problem is that said `bind()` and its cousins are inherited from a common base class (a [big](https://www.youtube.com/watch?v=3MNVP9-hglc) [mistake](https://python-patterns.guide/gang-of-four/composition-over-inheritance/) in hindsight) and can't know what concrete class subclasses them and therefore what type they are returning. -The chosen solution is adding `structlog.stdlib.get_logger()` that just calls `structlog.get_logger()` but has the correct type hints and adding `structlog.stdlib.BoundLogger.bind` et al that also only delegate to the base class. +The chosen solution is adding {func}`structlog.stdlib.get_logger()` that just calls `structlog.get_logger()` but has the correct type hints and adding `structlog.stdlib.BoundLogger.bind` et al that also only delegate to the base class. `structlog.get_logger()` is typed as returning {any}`typing.Any` so you can use your own type annotation and stick to the old APIs, if that's what you prefer: diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index e30bab9f..2abd189d 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -15,6 +15,7 @@ threadlocal, tracebacks, types, + typing, ) from structlog._base import BoundLoggerBase, get_context from structlog._config import ( @@ -83,6 +84,7 @@ "tracebacks", "twisted", "types", + "typing", "wrap_logger", "WriteLogger", "WriteLoggerFactory", diff --git a/src/structlog/_base.py b/src/structlog/_base.py index 78ed5fba..ba736eb0 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -13,7 +13,7 @@ from structlog.exceptions import DropEvent -from .types import BindableLogger, Context, Processor, WrappedLogger +from .typing import BindableLogger, Context, Processor, WrappedLogger class BoundLoggerBase: diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 244950eb..57755ac9 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -19,7 +19,7 @@ from .contextvars import merge_contextvars from .dev import ConsoleRenderer, _use_colors, set_exc_info from .processors import StackInfoRenderer, TimeStamper, add_log_level -from .types import BindableLogger, Context, Processor, WrappedLogger +from .typing import BindableLogger, Context, Processor, WrappedLogger """ diff --git a/src/structlog/_frames.py b/src/structlog/_frames.py index 84842421..6982463d 100644 --- a/src/structlog/_frames.py +++ b/src/structlog/_frames.py @@ -11,7 +11,7 @@ from io import StringIO from types import FrameType -from .types import ExcInfo +from .typing import ExcInfo def _format_exception(exc_info: ExcInfo) -> str: diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index a4e01cd2..4acc9e4b 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -14,7 +14,7 @@ from typing import Any, Callable from ._base import BoundLoggerBase -from .types import EventDict, FilteringBoundLogger +from .typing import EventDict, FilteringBoundLogger # Adapted from the stdlib diff --git a/src/structlog/contextvars.py b/src/structlog/contextvars.py index e6c2e5cf..94340c85 100644 --- a/src/structlog/contextvars.py +++ b/src/structlog/contextvars.py @@ -24,7 +24,7 @@ import structlog -from .types import BindableLogger, EventDict, WrappedLogger +from .typing import BindableLogger, EventDict, WrappedLogger STRUCTLOG_KEY_PREFIX = "structlog_" diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 8fec9e1e..280ba5ca 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -18,7 +18,7 @@ from typing import Any, Iterable, TextIO, Type, Union from ._frames import _format_exception -from .types import EventDict, ExceptionRenderer, ExcInfo, WrappedLogger +from .typing import EventDict, ExceptionRenderer, ExcInfo, WrappedLogger if sys.version_info >= (3, 8): diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 0a89cfc3..722c115d 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -38,7 +38,7 @@ from ._log_levels import _NAME_TO_LEVEL, add_log_level from ._utils import get_processname from .tracebacks import ExceptionDictTransformer -from .types import EventDict, ExceptionTransformer, ExcInfo, WrappedLogger +from .typing import EventDict, ExceptionTransformer, ExcInfo, WrappedLogger __all__ = [ diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 2564b531..f97c274e 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -27,7 +27,7 @@ from .contextvars import merge_contextvars from .exceptions import DropEvent from .processors import StackInfoRenderer -from .types import Context, EventDict, ExcInfo, Processor, WrappedLogger +from .typing import Context, EventDict, ExcInfo, Processor, WrappedLogger __all__ = [ diff --git a/src/structlog/testing.py b/src/structlog/testing.py index a64315d0..92e25406 100644 --- a/src/structlog/testing.py +++ b/src/structlog/testing.py @@ -18,7 +18,7 @@ from ._config import configure, get_config from .exceptions import DropEvent -from .types import EventDict, WrappedLogger +from .typing import EventDict, WrappedLogger __all__ = ["LogCapture", "capture_logs"] @@ -30,7 +30,7 @@ class LogCapture: Generally you should use `structlog.testing.capture_logs`, but you can use this class if you want to capture logs with other patterns. - :ivar List[structlog.types.EventDict] entries: The captured log entries. + :ivar List[structlog.typing.EventDict] entries: The captured log entries. .. versionadded:: 20.1.0 """ diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index a487a1a3..70685eb3 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -25,7 +25,7 @@ import structlog from ._config import BoundLoggerLazyProxy -from .types import BindableLogger, Context, EventDict, WrappedLogger +from .typing import BindableLogger, Context, EventDict, WrappedLogger def _determine_threadlocal() -> type[Any]: @@ -105,7 +105,7 @@ def as_immutable(logger: TLLogger) -> TLLogger: """ Extract the context from a thread local logger into an immutable logger. - :param structlog.types.BindableLogger logger: A logger with *possibly* + :param structlog.typing.BindableLogger logger: A logger with *possibly* thread local state. :returns: :class:`~structlog.BoundLogger` with an immutable context. diff --git a/src/structlog/tracebacks.py b/src/structlog/tracebacks.py index ac250271..8c025141 100644 --- a/src/structlog/tracebacks.py +++ b/src/structlog/tracebacks.py @@ -20,7 +20,7 @@ from types import TracebackType from typing import Any, Tuple, Union -from .types import ExcInfo +from .typing import ExcInfo __all__ = [ diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index a390ba2a..b00568ec 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -26,7 +26,7 @@ from ._config import _BUILTIN_DEFAULT_PROCESSORS from ._utils import until_not_interrupted from .processors import JSONRenderer as GenericJSONRenderer -from .types import EventDict, WrappedLogger +from .typing import EventDict, WrappedLogger class BoundLogger(BoundLoggerBase): diff --git a/src/structlog/types.py b/src/structlog/types.py index 65542dea..e7cbe115 100644 --- a/src/structlog/types.py +++ b/src/structlog/types.py @@ -4,232 +4,35 @@ # repository for complete details. """ -Type information used throughout ``structlog``. - -For now, they are considered provisional. Especially `BindableLogger` will -probably change to something more elegant. +Deprecated name for :mod:`structlog.typing`. .. versionadded:: 20.2 +.. deprecated:: 22.2 """ from __future__ import annotations -import sys - -from types import TracebackType -from typing import ( - Any, - Callable, - Dict, - Mapping, - MutableMapping, - Optional, - TextIO, - Tuple, - Type, - Union, +from .typing import ( + BindableLogger, + Context, + EventDict, + ExceptionRenderer, + ExceptionTransformer, + ExcInfo, + FilteringBoundLogger, + Processor, + WrappedLogger, ) -if sys.version_info >= (3, 8): - from typing import Protocol, runtime_checkable -else: - from typing_extensions import Protocol, runtime_checkable - - -WrappedLogger = Any -""" -A logger that is wrapped by a bound logger and is ultimately responsible for -the output of the log entries. - -``structlog`` makes *no* assumptions about it. - -.. versionadded:: 20.2 -""" - - -Context = Union[Dict[str, Any], Dict[Any, Any]] -""" -A dict-like context carrier. - -.. versionadded:: 20.2 -""" - - -EventDict = MutableMapping[str, Any] -""" -An event dictionary as it is passed into processors. - -It's created by copying the configured `Context` but doesn't need to support -copy itself. - -.. versionadded:: 20.2 -""" - -Processor = Callable[ - [WrappedLogger, str, EventDict], - Union[Mapping[str, Any], str, bytes, bytearray, Tuple[Any, ...]], -] -""" -A callable that is part of the processor chain. - -See :doc:`processors`. - -.. versionadded:: 20.2 -""" - -ExcInfo = Tuple[Type[BaseException], BaseException, Optional[TracebackType]] -""" -An exception info tuple as returned by `sys.exc_info`. - -.. versionadded:: 20.2 -""" - - -ExceptionRenderer = Callable[[TextIO, ExcInfo], None] -""" -A callable that pretty-prints an `ExcInfo` into a file-like object. - -Used by `structlog.dev.ConsoleRenderer`. - -.. versionadded:: 21.2 -""" - - -@runtime_checkable -class ExceptionTransformer(Protocol): - """ - **Protocol:** A callable that transforms an `ExcInfo` into another - datastructure. - - The result should be something that your renderer can work with, e.g., a - ``str`` or a JSON-serializable ``dict``. - - Used by `structlog.processors.format_exc_info()` and - `structlog.processors.ExceptionPrettyPrinter`. - - :param exc_info: Is the exception tuple to format - - :returns: Anything that can be rendered by the last processor in your - chain, e.g., a string or a JSON-serializable structure. - - .. versionadded:: 22.1 - """ - - def __call__(self, exc_info: ExcInfo) -> Any: - ... - - -@runtime_checkable -class BindableLogger(Protocol): - """ - **Protocol**: Methods shared among all bound loggers and that are relied on - by ``structlog``. - - .. versionadded:: 20.2 - """ - - _context: Context - - def bind(self, **new_values: Any) -> BindableLogger: - ... - - def unbind(self, *keys: str) -> BindableLogger: - ... - - def try_unbind(self, *keys: str) -> BindableLogger: - ... - - def new(self, **new_values: Any) -> BindableLogger: - ... - - -class FilteringBoundLogger(BindableLogger, Protocol): - """ - **Protocol**: A `BindableLogger` that filters by a level. - - The only way to instantiate one is using `make_filtering_bound_logger`. - - .. versionadded:: 20.2.0 - .. versionadded:: 22.2.0 - String interpolation using positional arguments. - """ - - def bind(self, **new_values: Any) -> FilteringBoundLogger: - """ - Return a new logger with *new_values* added to the existing ones. - - .. versionadded:: 22.1.0 - """ - - def unbind(self, *keys: str) -> FilteringBoundLogger: - """ - Return a new logger with *keys* removed from the context. - - .. versionadded:: 22.1.0 - """ - - def try_unbind(self, *keys: str) -> FilteringBoundLogger: - """ - Like :meth:`unbind`, but best effort: missing keys are ignored. - - .. versionadded:: 22.1.0 - """ - - def new(self, **new_values: Any) -> FilteringBoundLogger: - """ - Clear context and binds *initial_values* using `bind`. - - .. versionadded:: 22.1.0 - """ - - def debug(self, event: str, *args: Any, **kw: Any) -> Any: - """ - Log ``event % args`` with **kw** at **debug** level. - """ - - def info(self, event: str, *args: Any, **kw: Any) -> Any: - """ - Log ``event % args`` with **kw** at **info** level. - """ - - def warning(self, event: str, *args: Any, **kw: Any) -> Any: - """ - Log ``event % args`` with **kw** at **warn** level. - """ - - def warn(self, event: str, *args: Any, **kw: Any) -> Any: - """ - Log ``event % args`` with **kw** at **warn** level. - """ - - def error(self, event: str, *args: Any, **kw: Any) -> Any: - """ - Log ``event % args`` with **kw** at **error** level. - """ - - def err(self, event: str, *args: Any, **kw: Any) -> Any: - """ - Log ``event % args`` with **kw** at **error** level. - """ - - def fatal(self, event: str, *args: Any, **kw: Any) -> Any: - """ - Log ``event % args`` with **kw** at **critical** level. - """ - - def exception(self, event: str, *args: Any, **kw: Any) -> Any: - """ - Log ``event % args`` with **kw** at **error** level and ensure that - ``exc_info`` is set in the event dictionary. - """ - - def critical(self, event: str, *args: Any, **kw: Any) -> Any: - """ - Log ``event % args`` with **kw** at **critical** level. - """ - - def msg(self, event: str, *args: Any, **kw: Any) -> Any: - """ - Log ``event % args`` with **kw** at **info** level. - """ +__all__ = ( + "WrappedLogger", + "Context", + "EventDict", + "Processor", + "ExcInfo", + "ExceptionRenderer", + "ExceptionTransformer", + "BindableLogger", + "FilteringBoundLogger", +) diff --git a/src/structlog/typing.py b/src/structlog/typing.py new file mode 100644 index 00000000..3cc0d33c --- /dev/null +++ b/src/structlog/typing.py @@ -0,0 +1,235 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the MIT License. See the LICENSE file in the root of this +# repository for complete details. + +""" +Type information used throughout ``structlog``. + +For now, they are considered provisional. Especially `BindableLogger` will +probably change to something more elegant. + +.. versionadded:: 22.2 +""" + +from __future__ import annotations + +import sys + +from types import TracebackType +from typing import ( + Any, + Callable, + Dict, + Mapping, + MutableMapping, + Optional, + TextIO, + Tuple, + Type, + Union, +) + + +if sys.version_info >= (3, 8): + from typing import Protocol, runtime_checkable +else: + from typing_extensions import Protocol, runtime_checkable + + +WrappedLogger = Any +""" +A logger that is wrapped by a bound logger and is ultimately responsible for +the output of the log entries. + +``structlog`` makes *no* assumptions about it. + +.. versionadded:: 20.2 +""" + + +Context = Union[Dict[str, Any], Dict[Any, Any]] +""" +A dict-like context carrier. + +.. versionadded:: 20.2 +""" + + +EventDict = MutableMapping[str, Any] +""" +An event dictionary as it is passed into processors. + +It's created by copying the configured `Context` but doesn't need to support +copy itself. + +.. versionadded:: 20.2 +""" + +Processor = Callable[ + [WrappedLogger, str, EventDict], + Union[Mapping[str, Any], str, bytes, bytearray, Tuple[Any, ...]], +] +""" +A callable that is part of the processor chain. + +See :doc:`processors`. + +.. versionadded:: 20.2 +""" + +ExcInfo = Tuple[Type[BaseException], BaseException, Optional[TracebackType]] +""" +An exception info tuple as returned by `sys.exc_info`. + +.. versionadded:: 20.2 +""" + + +ExceptionRenderer = Callable[[TextIO, ExcInfo], None] +""" +A callable that pretty-prints an `ExcInfo` into a file-like object. + +Used by `structlog.dev.ConsoleRenderer`. + +.. versionadded:: 21.2 +""" + + +@runtime_checkable +class ExceptionTransformer(Protocol): + """ + **Protocol:** A callable that transforms an `ExcInfo` into another + datastructure. + + The result should be something that your renderer can work with, e.g., a + ``str`` or a JSON-serializable ``dict``. + + Used by `structlog.processors.format_exc_info()` and + `structlog.processors.ExceptionPrettyPrinter`. + + :param exc_info: Is the exception tuple to format + + :returns: Anything that can be rendered by the last processor in your + chain, e.g., a string or a JSON-serializable structure. + + .. versionadded:: 22.1 + """ + + def __call__(self, exc_info: ExcInfo) -> Any: + ... + + +@runtime_checkable +class BindableLogger(Protocol): + """ + **Protocol**: Methods shared among all bound loggers and that are relied on + by ``structlog``. + + .. versionadded:: 20.2 + """ + + _context: Context + + def bind(self, **new_values: Any) -> BindableLogger: + ... + + def unbind(self, *keys: str) -> BindableLogger: + ... + + def try_unbind(self, *keys: str) -> BindableLogger: + ... + + def new(self, **new_values: Any) -> BindableLogger: + ... + + +class FilteringBoundLogger(BindableLogger, Protocol): + """ + **Protocol**: A `BindableLogger` that filters by a level. + + The only way to instantiate one is using `make_filtering_bound_logger`. + + .. versionadded:: 20.2.0 + .. versionadded:: 22.2.0 + String interpolation using positional arguments. + """ + + def bind(self, **new_values: Any) -> FilteringBoundLogger: + """ + Return a new logger with *new_values* added to the existing ones. + + .. versionadded:: 22.1.0 + """ + + def unbind(self, *keys: str) -> FilteringBoundLogger: + """ + Return a new logger with *keys* removed from the context. + + .. versionadded:: 22.1.0 + """ + + def try_unbind(self, *keys: str) -> FilteringBoundLogger: + """ + Like :meth:`unbind`, but best effort: missing keys are ignored. + + .. versionadded:: 22.1.0 + """ + + def new(self, **new_values: Any) -> FilteringBoundLogger: + """ + Clear context and binds *initial_values* using `bind`. + + .. versionadded:: 22.1.0 + """ + + def debug(self, event: str, *args: Any, **kw: Any) -> Any: + """ + Log ``event % args`` with **kw** at **debug** level. + """ + + def info(self, event: str, *args: Any, **kw: Any) -> Any: + """ + Log ``event % args`` with **kw** at **info** level. + """ + + def warning(self, event: str, *args: Any, **kw: Any) -> Any: + """ + Log ``event % args`` with **kw** at **warn** level. + """ + + def warn(self, event: str, *args: Any, **kw: Any) -> Any: + """ + Log ``event % args`` with **kw** at **warn** level. + """ + + def error(self, event: str, *args: Any, **kw: Any) -> Any: + """ + Log ``event % args`` with **kw** at **error** level. + """ + + def err(self, event: str, *args: Any, **kw: Any) -> Any: + """ + Log ``event % args`` with **kw** at **error** level. + """ + + def fatal(self, event: str, *args: Any, **kw: Any) -> Any: + """ + Log ``event % args`` with **kw** at **critical** level. + """ + + def exception(self, event: str, *args: Any, **kw: Any) -> Any: + """ + Log ``event % args`` with **kw** at **error** level and ensure that + ``exc_info`` is set in the event dictionary. + """ + + def critical(self, event: str, *args: Any, **kw: Any) -> Any: + """ + Log ``event % args`` with **kw** at **critical** level. + """ + + def msg(self, event: str, *args: Any, **kw: Any) -> Any: + """ + Log ``event % args`` with **kw** at **info** level. + """ diff --git a/tests/test_processors.py b/tests/test_processors.py index 63ae2dcd..b6e74e9f 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -44,7 +44,7 @@ ) from structlog.stdlib import ProcessorFormatter from structlog.threadlocal import wrap_dict -from structlog.types import EventDict +from structlog.typing import EventDict from tests.additional_frame import additional_frame diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index bd81b648..e09ee30a 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -46,7 +46,7 @@ render_to_log_kwargs, ) from structlog.testing import CapturedCall -from structlog.types import BindableLogger, EventDict +from structlog.typing import BindableLogger, EventDict from .additional_frame import additional_frame diff --git a/typing_examples.py b/typing_examples.py index 8ccdec9e..8437bf9e 100644 --- a/typing_examples.py +++ b/typing_examples.py @@ -15,7 +15,7 @@ import structlog from structlog.processors import CallsiteParameter -from structlog.types import FilteringBoundLogger +from structlog.typing import FilteringBoundLogger bl = structlog.get_logger() @@ -114,7 +114,7 @@ def bytes_dumps( timestamper = structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S") -shared_processors: List[structlog.types.Processor] = [ +shared_processors: List[structlog.typing.Processor] = [ structlog.stdlib.add_log_level, timestamper, ] From 0c9b68015f5a9b2608efd15ab3444066f9b644f5 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 10:13:27 +0200 Subject: [PATCH 0834/1520] Use italics instead of fixed font for structlog That's appropriate according to English rules and makes the text less noisy,. --- .github/CONTRIBUTING.md | 4 +-- CHANGELOG.md | 52 +++++++++++++++++----------------- README.md | 18 ++++++------ docs/bound-loggers.md | 8 +++--- docs/configuration.md | 16 +++++------ docs/contextvars.md | 6 ++-- docs/custom-wrappers.md | 6 ++-- docs/development.md | 6 ++-- docs/frameworks.md | 4 +-- docs/getting-started.md | 34 +++++++++++----------- docs/index.md | 6 ++-- docs/license.md | 2 +- docs/logging-best-practices.md | 6 ++-- docs/performance.md | 12 ++++---- docs/processors.md | 12 ++++---- docs/standard-library.md | 50 ++++++++++++++++---------------- docs/testing.md | 4 +-- docs/thread-local.md | 10 +++---- docs/twisted.md | 16 +++++------ docs/typing.md | 4 +-- docs/why.md | 19 +++++++------ src/structlog/_config.py | 6 ++-- src/structlog/_log_levels.py | 2 +- src/structlog/contextvars.py | 2 +- src/structlog/dev.py | 2 +- src/structlog/processors.py | 6 ++-- src/structlog/stdlib.py | 28 +++++++++--------- src/structlog/typing.py | 6 ++-- 28 files changed, 174 insertions(+), 173 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 832d0a44..3c956201 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,6 +1,6 @@ # How To Contribute -Thank you for considering contributing to `structlog`! +Thank you for considering contributing to *structlog*! It's people like *you* who make it such a great tool for everyone. This document intends to make contribution more accessible by codifying tribal knowledge and expectations. @@ -16,7 +16,7 @@ Please report any harm to [Hynek Schlawack] in any way you find appropriate. In case you'd like to help out but don't want to deal with GitHub, there's a great opportunity: help your fellow developers on [Stack Overflow](https://stackoverflow.com/questions/tagged/structlog)! -The official tag is `structlog` and helping out in support frees us up to improve `structlog` instead! +The official tag is `structlog` and helping out in support frees us up to improve *structlog* instead! ## Workflow diff --git a/CHANGELOG.md b/CHANGELOG.md index dfe8f10e..368d6276 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,11 +8,11 @@ The **first number** of the version is the year. The **second number** is incremented with each release, starting at 1 for each year. The **third number** is for emergencies when we need to start branches for older releases. -You shouldn't ever be afraid to upgrade `structlog` if you're using its public APIs and pay attention to `DeprecationWarning`s. +You shouldn't ever be afraid to upgrade *structlog* if you're using its public APIs and pay attention to `DeprecationWarning`s. Whenever there is a need to break compatibility, it is announced here in the changelog and raises a `DeprecationWarning` for a year (if possible) before it's finally really broken. You cannot rely on the default settings and the `structlog.dev` module. -They may be adjusted in the future to provide a better experience when starting to use `structlog`. +They may be adjusted in the future to provide a better experience when starting to use *structlog*. So please make sure to **always** properly configure your applications. @@ -21,7 +21,7 @@ So please make sure to **always** properly configure your applications. ### Deprecated -- Accessing package metadata as attributes on the `structlog` module is deprecated (e.g. `structlog.__version__`). +- Accessing package metadata as attributes on the *structlog* module is deprecated (e.g. `structlog.__version__`). Please use [`importlib.metadata`](https://docs.python.org/3.10/library/importlib.metadata.html) instead (for Python 3.7: the [*importlib-metadata*](https://pypi.org/project/importlib-metadata/) PyPI package). - The `structlog.types` module is now deprecated in favor of the `structlog.typing` module. It seems like the Python typing community is settling on this name. @@ -82,7 +82,7 @@ So please make sure to **always** properly configure your applications. - Added structured logging of tracebacks via the `structlog.tracebacks` module, and most notably the `structlog.tracebacks.ExceptionDictTransformer` which can be used with the new `structlog.processors.ExceptionRenderer` to render JSON tracebacks. [#407](https://github.com/hynek/structlog/pull/407) -- `structlog.stdlib.recreate_defaults(log_level=logging.NOTSET)` that recreates `structlog`'s defaults on top of standard library's `logging`. +- `structlog.stdlib.recreate_defaults(log_level=logging.NOTSET)` that recreates *structlog*'s defaults on top of standard library's `logging`. It optionally also configures `logging` to log to standard out at the passed log level. [#428](https://github.com/hynek/structlog/pull/428) - `structlog.processors.EventRenamer` allows you to rename the hitherto hard-coded event dict key `event` to something else. @@ -105,7 +105,7 @@ So please make sure to **always** properly configure your applications. Its behavior has not changed. [#407](https://github.com/hynek/structlog/pull/407) - The default configuration now includes the `structlog.contextvars.merge_contextvars` processor. - That means you can use [`structlog.contextvars`](https://www.structlog.org/en/stable/contextvars.html) features without configuring `structlog`. + That means you can use [`structlog.contextvars`](https://www.structlog.org/en/stable/contextvars.html) features without configuring *structlog*. ### Fixed @@ -161,7 +161,7 @@ So please make sure to **always** properly configure your applications. ### Changed -- `structlog` switched its packaging to [*flit*](https://flit.pypa.io/). +- *structlog* switched its packaging to [*flit*](https://flit.pypa.io/). Users shouldn't notice a difference, but (re-)packagers might. - `structlog.stdlib.AsyncBoundLogger` now determines the running loop when logging, not on instantiation. That has a minor performance impact, but makes it more robust when loops change (e.g. `aiohttp.web.run_app()`), or you want to use `sync_bl` *before* a loop has started. @@ -175,7 +175,7 @@ So please make sure to **always** properly configure your applications. - `structlog.stdlib.ProcessorFormatter` now has a *processors* argument that allows to define a processor chain to run over *all* log entries. Before running the chain, two additional keys are added to the event dictionary: `_record` and `_from_structlog`. - With them it's possible to extract information from `logging.LogRecord`s and differentiate between `structlog` and `logging` log entries while processing them. + With them it's possible to extract information from `logging.LogRecord`s and differentiate between *structlog* and `logging` log entries while processing them. The old *processor* (singular) parameter is now deprecated, but no plans exist to remove it. [#365](https://github.com/hynek/structlog/pull/365) @@ -193,7 +193,7 @@ So please make sure to **always** properly configure your applications. - `structlog.contextvars.bind_contextvars()` now returns a mapping of keys to `contextvars.Token`s, allowing you to reset values using the new `structlog.contextvars.reset_contextvars()`. [#339](https://github.com/hynek/structlog/pull/339) - Exception rendering in `structlog.dev.ConsoleLogger` is now configurable using the `exception_formatter` setting. - If either the [*Rich*](https://github.com/Textualize/rich) or the [*better-exceptions*](https://github.com/qix-/better-exceptions) package is present, `structlog` will use them for pretty-printing tracebacks. + If either the [*Rich*](https://github.com/Textualize/rich) or the [*better-exceptions*](https://github.com/qix-/better-exceptions) package is present, *structlog* will use them for pretty-printing tracebacks. *Rich* takes precedence over *better-exceptions* if both are present. This only works if `format_exc_info` is **absent** in the processor chain. @@ -207,7 +207,7 @@ So please make sure to **always** properly configure your applications. - To implement pretty exceptions (see Changes below), `structlog.dev.ConsoleRenderer` now formats exceptions itself. - Make sure to remove `format_exc_info` from your processor chain if you configure `structlog` manually. + Make sure to remove `format_exc_info` from your processor chain if you configure *structlog* manually. This change is not really breaking, because the old use-case will keep working as before. However if you pass `pretty_exceptions=True` (which is the default if either `rich` or `better-exceptions` is installed), a warning will be raised and the exception will be rendered without prettification. - All use of [*Colorama*](https://github.com/tartley/colorama) on non-Windows systems has been excised. @@ -218,7 +218,7 @@ So please make sure to **always** properly configure your applications. ### Fixed -- `structlog` is now importable if `sys.stdout` is `None` (e.g. when running using `pythonw`). [#313](https://github.com/hynek/structlog/issues/313) +- *structlog* is now importable if `sys.stdout` is `None` (e.g. when running using `pythonw`). [#313](https://github.com/hynek/structlog/issues/313) ## [21.1.0](https://github.com/hynek/structlog/compare/20.2.0...21.1.0) - 2021-02-18 @@ -256,8 +256,8 @@ So please make sure to **always** properly configure your applications. ### Added -- `structlog` has now type hints for all of its APIs! - Since `structlog` is highly dynamic and configurable, this led to a few concessions like a specialized `structlog.stdlib.get_logger()` whose only difference to `structlog.get_logger()` is that it has the correct type hints. +- *structlog* has now type hints for all of its APIs! + Since *structlog* is highly dynamic and configurable, this led to a few concessions like a specialized `structlog.stdlib.get_logger()` whose only difference to `structlog.get_logger()` is that it has the correct type hints. We consider them provisional for the time being – i.e. the backwards-compatibility does not apply to them in its full strength until we feel we got it right. Please feel free to provide feedback! @@ -279,7 +279,7 @@ So please make sure to **always** properly configure your applications. ### Changed -- The default bound logger (`wrapper_class`) if you don't configure `structlog` has changed. +- The default bound logger (`wrapper_class`) if you don't configure *structlog* has changed. It's mostly compatible with the old one but a few uncommon methods like `log`, `failure`, or `err` don't exist anymore. You can regain the old behavior by using `structlog.configure(wrapper_class=structlog.BoundLogger)`. @@ -306,7 +306,7 @@ So please make sure to **always** properly configure your applications. ### Added -- Added a new module `structlog.contextvars` that allows to have a global but context-local `structlog` context the same way as with `structlog.threadlocal` since 19.2.0. +- Added a new module `structlog.contextvars` that allows to have a global but context-local *structlog* context the same way as with `structlog.threadlocal` since 19.2.0. [#201](https://github.com/hynek/structlog/issues/201), [#236](https://github.com/hynek/structlog/pull/236) - Added a new module `structlog.testing` for first class testing support. @@ -333,7 +333,7 @@ So please make sure to **always** properly configure your applications. - Python 3.4 is not supported anymore. It has been unsupported by the Python core team for a while now and its PyPI downloads are negligible. - It's very unlikely that `structlog` will break under 3.4 anytime soon, but we don't test it anymore. + It's very unlikely that *structlog* will break under 3.4 anytime soon, but we don't test it anymore. ### Added @@ -368,9 +368,9 @@ It has been unsupported by the Python core team for a while now and its PyPI dow - `structlog.dev.ConsoleRenderer` now uses no colors by default, if *Colorama* is not available. [#215](https://github.com/hynek/structlog/issues/215) -- `structlog.dev.ConsoleRenderer` now initializes *Colorama* lazily, to prevent accidental side-effects just by importing `structlog`. +- `structlog.dev.ConsoleRenderer` now initializes *Colorama* lazily, to prevent accidental side-effects just by importing *structlog*. [#210](https://github.com/hynek/structlog/issues/210) -- A best effort has been made to make as much of `structlog` pickleable as possible to make it friendlier with `multiprocessing` and similar libraries. +- A best effort has been made to make as much of *structlog* pickleable as possible to make it friendlier with `multiprocessing` and similar libraries. Some classes can only be pickled on Python 3 or using the [dill](https://pypi.org/project/dill/) library though and that is very unlikely to change. So far, the configuration proxy, `structlog.processor.TimeStamper`, `structlog.BoundLogger`, `structlog.PrintLogger` and `structlog.dev.ConsoleRenderer` have been made pickleable. @@ -390,7 +390,7 @@ It has been unsupported by the Python core team for a while now and its PyPI dow - As announced in 18.1.0, `pip install -e .[dev]` now installs all development dependencies. Sorry for the inconveniences this undoubtedly will cause! -- `structlog` now tolerates passing through `dict`s to stdlib logging. +- *structlog* now tolerates passing through `dict`s to stdlib logging. [#187](https://github.com/hynek/structlog/issues/187), [#188](https://github.com/hynek/structlog/pull/188), [#189](https://github.com/hynek/structlog/pull/189) @@ -421,9 +421,9 @@ It has been unsupported by the Python core team for a while now and its PyPI dow ### Deprecated -- The meaning of the `structlog[dev]` installation target will change from "colorful output" to "dependencies to develop `structlog`" in 19.1.0. +- The meaning of the `structlog[dev]` installation target will change from "colorful output" to "dependencies to develop *structlog*" in 19.1.0. - The main reason behind this decision is that it's impossible to have a `structlog` in your normal dependencies and additionally a `structlog[dev]` for development (`pip` will report an error). + The main reason behind this decision is that it's impossible to have a *structlog* in your normal dependencies and additionally a `structlog[dev]` for development (`pip` will report an error). ### Added @@ -433,7 +433,7 @@ It has been unsupported by the Python core team for a while now and its PyPI dow - `structlog.dev.ConsoleRenderer` now accepts a *level_styles* argument for overriding the colors for individual levels, as well as to add new levels. See the docs for `ConsoleRenderer.get_default_level_styles()` for usage. [#139](https://github.com/hynek/structlog/pull/139) -- Added `structlog.is_configured()` to check whether or not `structlog` has been configured. +- Added `structlog.is_configured()` to check whether or not *structlog* has been configured. - Added `structlog.get_config()` to introspect current configuration. @@ -480,7 +480,7 @@ Special thanks go to [Fabian Büchler](https://github.com/fabianbuechler), [Gilb - Added `structlog.stdlib.render_to_log_kwargs()`. This allows you to use `logging`-based formatters to take care of rendering your entries. [#98](https://github.com/hynek/structlog/issues/98) -- Added `structlog.stdlib.ProcessorFormatter` which does the opposite: This allows you to run `structlog` processors on arbitrary `logging.LogRecords`. +- Added `structlog.stdlib.ProcessorFormatter` which does the opposite: This allows you to run *structlog* processors on arbitrary `logging.LogRecords`. [#79](https://github.com/hynek/structlog/issues/79), [#105](https://github.com/hynek/structlog/issues/105) - Added *repr_native_str* to `structlog.processors.KeyValueRenderer` and `structlog.dev.ConsoleRenderer`. @@ -493,7 +493,7 @@ Special thanks go to [Fabian Büchler](https://github.com/fabianbuechler), [Gilb ### Changed -- The default renderer now is `structlog.dev.ConsoleRenderer` if you don't configure `structlog`. +- The default renderer now is `structlog.dev.ConsoleRenderer` if you don't configure *structlog*. Colors are used if available and human-friendly timestamps are prepended. This is in line with our backwards-compatibility policy that explicitly excludes default settings. - UNIX epoch timestamps from `structlog.processors.TimeStamper` are more precise now. @@ -586,7 +586,7 @@ Special thanks go to [Fabian Büchler](https://github.com/fabianbuechler), [Gilb - Allow empty lists of processors. This is a valid use case since [#26](https://github.com/hynek/structlog/issues/26) has been merged. Before, supplying an empty list resulted in the defaults being used. -- Better support of `logging.Logger.exception` within `structlog`. +- Better support of `logging.Logger.exception` within *structlog*. [#52](https://github.com/hynek/structlog/pull/52) @@ -618,8 +618,8 @@ Special thanks go to [Fabian Büchler](https://github.com/fabianbuechler), [Gilb - Pass positional arguments to stdlib wrapped loggers that use string formatting. [#19](https://github.com/hynek/structlog/pull/19) -- `structlog` is now dually licensed under the [Apache License, Version 2](https://choosealicense.com/licenses/apache/) and the [MIT](https://choosealicense.com/licenses/mit/) license. - Therefore it is now legal to use `structlog` with [GPLv2](https://choosealicense.com/licenses/gpl-2.0/)-licensed projects. +- *structlog* is now dually licensed under the [Apache License, Version 2](https://choosealicense.com/licenses/apache/) and the [MIT](https://choosealicense.com/licenses/mit/) license. + Therefore it is now legal to use *structlog* with [GPLv2](https://choosealicense.com/licenses/gpl-2.0/)-licensed projects. [#28](https://github.com/hynek/structlog/pull/28) diff --git a/README.md b/README.md index eb55efe4..a7538998 100644 --- a/README.md +++ b/README.md @@ -28,19 +28,19 @@ -`structlog` makes logging in Python **less painful**, **more powerful**, and **much faster**, by adding **structure** to your log entries and moving control to simple **functions**. +*structlog* makes logging in Python **less painful**, **more powerful**, and **much faster**, by adding **structure** to your log entries and moving control to simple **functions**. It has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio*, context variables, or type hints as they emerged. Its design proved influential enough to [help design](https://twitter.com/sirupsen/status/638330548361019392) structured logging [packages across ecosystems](https://github.com/sirupsen/logrus). -Thanks to its highly flexible design, *you* choose whether you want `structlog` to take care of the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's `logging` module. +Thanks to its highly flexible design, *you* choose whether you want *structlog* to take care of the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's `logging` module. -The output format is just as flexible and `structlog` comes with support for JSON, [*logfmt*](https://brandur.org/logfmt), as well as pretty console output out-of-the-box: +The output format is just as flexible and *structlog* comes with support for JSON, [*logfmt*](https://brandur.org/logfmt), as well as pretty console output out-of-the-box: ![image](https://github.com/hynek/structlog/blob/main/docs/_static/console_renderer.png?raw=true) -A short explanation on *why* structured logging is good for you, and why `structlog` is the right tool for the job can be found in the [Why chapter](https://www.structlog.org/en/stable/why.html) of our documentation. +A short explanation on *why* structured logging is good for you, and why *structlog* is the right tool for the job can be found in the [Why chapter](https://www.structlog.org/en/stable/why.html) of our documentation. Once you feel inspired to try it out, check out our friendly [Getting Started tutorial](https://www.structlog.org/en/stable/getting-started.html). @@ -49,10 +49,10 @@ If you prefer videos over reading, check out [Markus Holtermann](https://twitter ## Credits -`structlog` is written and maintained by [Hynek Schlawack](https://hynek.me/). +*structlog* is written and maintained by [Hynek Schlawack](https://hynek.me/). The idea of bound loggers is inspired by previous work by [Jean-Paul Calderone](https://github.com/exarkun) and [David Reid](https://github.com/dreid). -The development is kindly supported by my employer [Variomedia AG](https://www.variomedia.de/), `structlog`’s [Tidelift subscribers](https://tidelift.com/subscription/pkg/pypi-structlog), and all my amazing [GitHub Sponsors](https://github.com/sponsors/hynek). +The development is kindly supported by my employer [Variomedia AG](https://www.variomedia.de/), *structlog*’s [Tidelift subscribers](https://tidelift.com/subscription/pkg/pypi-structlog), and all my amazing [GitHub Sponsors](https://github.com/sponsors/hynek). A full list of contributors can be found in GitHub’s [overview](https://github.com/hynek/structlog/graphs/contributors). @@ -64,7 +64,7 @@ The logs-loving futuristic beaver logo has been contributed by [Russell Keith-Ma ## Project Information - **License**: *dual* [Apache License, version 2 **and** MIT](https://www.structlog.org/en/latest/license.html) -- **Get Help**: please use the `structlog` tag on [*Stack Overflow*](https://stackoverflow.com/questions/tagged/structlog) +- **Get Help**: please use the *structlog* tag on [*Stack Overflow*](https://stackoverflow.com/questions/tagged/structlog) - **Supported Python Versions**: 3.7 and later - [**PyPI**](https://pypi.org/project/structlog/) - [**Source Code**](https://github.com/hynek/structlog) @@ -73,8 +73,8 @@ The logs-loving futuristic beaver logo has been contributed by [Russell Keith-Ma - [**Third-party Extensions**](https://github.com/hynek/structlog/wiki/Third-party-Extensions) -## `structlog` for Enterprise +## *structlog* for Enterprise Available as part of the Tidelift Subscription. -The maintainers of `structlog` and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. [Learn more.](https://tidelift.com/subscription/pkg/pypi-structlog?utm_source=pypi-structlog&utm_medium=referral&utm_campaign=readme) +The maintainers of *structlog* and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. [Learn more.](https://tidelift.com/subscription/pkg/pypi-structlog?utm_source=pypi-structlog&utm_medium=referral&utm_campaign=readme) diff --git a/docs/bound-loggers.md b/docs/bound-loggers.md index 3eaef919..0882829a 100644 --- a/docs/bound-loggers.md +++ b/docs/bound-loggers.md @@ -1,10 +1,10 @@ # Bound Loggers -The centerpiece of `structlog` that you will interact with most is called a *bound logger*. +The centerpiece of *structlog* that you will interact with most is called a *bound logger*. It's what you get back from {func}`structlog.get_logger()` and it's called a *bound logger* because you can *bind* key-value pairs to it. -As far as `structlog` is concerned, it consists of three parts: +As far as *structlog* is concerned, it consists of three parts: ```{image} _static/BoundLogger.svg ``` @@ -20,7 +20,7 @@ As far as `structlog` is concerned, it consists of three parts: 3. And finally a *logger* that it's wrapping. This wrapped logger is responsible for the *output* of the log entry that has been returned by the last processor. This *can* be standard library's {class}`logging.Logger` like in the image above, but absolutely doesn't have to: - By default it's `structlog`'s {class}`~structlog.PrintLogger`. + By default it's *structlog*'s {class}`~structlog.PrintLogger`. This wrapped logger also is usually set using {doc}`configuration`. @@ -103,7 +103,7 @@ Now if you call `log.info("Hello, %s!", "world", number=42)` the following happe ## Wrapping Loggers Explicitly In practice, you won't be instantiating bound loggers yourself. -You will configure `structlog` as explained in the {doc}`next chapter ` and then just call {func}`structlog.get_logger`. +You will configure *structlog* as explained in the {doc}`next chapter ` and then just call {func}`structlog.get_logger`. However, in some rare cases you may not want to do that. For example because you don't control how you get the logger that you would like to wrap (famous example: *Celery*). diff --git a/docs/configuration.md b/docs/configuration.md index 86185107..d40e55ff 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1,7 +1,7 @@ # Configuration -The focus of `structlog` has always been to be flexible to a fault. -The goal is that a user can use it with *any* logger of their own that is wrapped by `structlog`. +The focus of *structlog* has always been to be flexible to a fault. +The goal is that a user can use it with *any* logger of their own that is wrapped by *structlog*. That's the reason why there's an overwhelming amount of knobs to tweak, but – ideally – once you find your configuration, you don't touch it ever again and, more importantly: @@ -25,7 +25,7 @@ You can call {func}`structlog.configure` repeatedly and only set one or more set If necessary, you can always reset your global configuration back to default values using {func}`structlog.reset_defaults`. That can be handy in tests. -At any time, you can check whether and how `structlog` is configured using {func}`structlog.is_configured` and {func}`structlog.get_config`}: +At any time, you can check whether and how *structlog* is configured using {func}`structlog.is_configured` and {func}`structlog.get_config`}: ```pycon >>> structlog.is_configured() @@ -39,10 +39,10 @@ True ``` :::{important} -Since you'll call {func}`structlog.get_logger` in module scope, it runs at import time *before* you had a chance to configure `structlog`. +Since you'll call {func}`structlog.get_logger` in module scope, it runs at import time *before* you had a chance to configure *structlog*. Therefore it returns a **lazy proxy** that returns a correctly configured *bound logger* on its first call to one of the context-managing methods like `bind()`. -Thus, you must never call `new()` or `bind()` in module or class scope because , you will receive a logger configured with `structlog`'s default values. +Thus, you must never call `new()` or `bind()` in module or class scope because , you will receive a logger configured with *structlog*'s default values. Use {func}`~structlog.get_logger`'s `initial_values` to achieve pre-populated contexts. To enable you to log with the module-global logger, it will create a temporary *bound logger* **on each call**. @@ -76,9 +76,9 @@ In the simplest case, it's a function that returns a logger -- or just a class. But you can also pass in an instance of a class with a `__call__` method for more complicated setups. These will be passed to the logger factories. -For example, if you use run `structlog.get_logger("a name")` and configure `structlog` to use the standard library {class}`~structlog.stdlib.LoggerFactory`,which has support for positional parameters, the returned logger will have the name `"a name"`. +For example, if you use run `structlog.get_logger("a name")` and configure *structlog* to use the standard library {class}`~structlog.stdlib.LoggerFactory`,which has support for positional parameters, the returned logger will have the name `"a name"`. -For the common cases of standard library logging and Twisted logging, `structlog` comes with two factories built right in: +For the common cases of standard library logging and Twisted logging, *structlog* comes with two factories built right in: - {class}`structlog.stdlib.LoggerFactory` - {class}`structlog.twisted.LoggerFactory` @@ -94,7 +94,7 @@ So all it takes to use standard library {mod}`logging` for output is: event='this is too easy!' ``` -By using `structlog`'s {class}`structlog.stdlib.LoggerFactory`, it is also ensured that variables like function names and line numbers are expanded correctly in your log format. +By using *structlog*'s {class}`structlog.stdlib.LoggerFactory`, it is also ensured that variables like function names and line numbers are expanded correctly in your log format. See {doc}`standard-library` for more details. Calling {func}`structlog.get_logger` without configuration gives you a perfectly useful {class}`structlog.PrintLogger`. diff --git a/docs/contextvars.md b/docs/contextvars.md index 9cae5449..31543a50 100644 --- a/docs/contextvars.md +++ b/docs/contextvars.md @@ -15,12 +15,12 @@ structlog.reset_defaults() ``` -The {mod}`contextvars` module in the Python standard library allows having a global `structlog` context that is local to the current execution context. +The {mod}`contextvars` module in the Python standard library allows having a global *structlog* context that is local to the current execution context. The execution context can be thread-local if using threads, or using primitives based on {mod}`asyncio`, or [*greenlet*](https://greenlet.readthedocs.io/) respectively. For example, you may want to bind certain values like a request ID or the peer's IP address at the beginning of a web request and have them logged out along with the local contexts you build within our views. -For that `structlog` provides the {mod}`structlog.contextvars` module with a set of functions to bind variables to a context-local context. +For that *structlog* provides the {mod}`structlog.contextvars` module with a set of functions to bind variables to a context-local context. This context is safe to be used both in threaded as well as asynchronous code. The general flow is: @@ -29,7 +29,7 @@ The general flow is: - Call {func}`structlog.contextvars.clear_contextvars` at the beginning of your request handler (or whenever you want to reset the context-local context). - Call {func}`structlog.contextvars.bind_contextvars` and {func}`structlog.contextvars.unbind_contextvars` instead of your bound logger's `bind()` and `unbind()` when you want to bind and unbind key-value pairs to the context-local context. You can also use the {func}`structlog.contextvars.bound_contextvars` context manager / decorator. -- Use `structlog` as normal. +- Use *structlog* as normal. Loggers act as they always do, but the {func}`structlog.contextvars.merge_contextvars` processor ensures that any context-local binds get included in all of your log messages. - If you want to access the context-local storage, you use {func}`structlog.contextvars.get_contextvars` and {func}`structlog.contextvars.get_merged_contextvars`. diff --git a/docs/custom-wrappers.md b/docs/custom-wrappers.md index 5c8ff445..07263028 100644 --- a/docs/custom-wrappers.md +++ b/docs/custom-wrappers.md @@ -20,8 +20,8 @@ The type of the *bound loggers* that are returned by {func}`structlog.get_logger()` is called the *wrapper class*, because it wraps the original logger that takes care of the output. This wrapper class is [configurable](configuration.md). -Originally, `structlog` used a generic wrapper class {class}`structlog.BoundLogger` by default. -That class still ships with `structlog` and can wrap *any* logger class by intercepting unknown method names and proxying them to the wrapped logger. +Originally, *structlog* used a generic wrapper class {class}`structlog.BoundLogger` by default. +That class still ships with *structlog* and can wrap *any* logger class by intercepting unknown method names and proxying them to the wrapped logger. Nowadays, the default is a {class}`structlog.typing.FilteringBoundLogger` that imitates standard library's log levels with the possibility of efficiently filtering at a certain level (inactive log methods are a plain `return None` each). @@ -30,7 +30,7 @@ If you're integrating with {mod}`logging` or Twisted, you may was to use one of --- On top of that all, you can also write your own wrapper classes. -To make it easy for you, `structlog` comes with the class {class}`structlog.BoundLoggerBase` which takes care of all data binding duties so you just add your log methods if you choose to sub-class it. +To make it easy for you, *structlog* comes with the class {class}`structlog.BoundLoggerBase` which takes care of all data binding duties so you just add your log methods if you choose to sub-class it. (wrapper-class-example)= diff --git a/docs/development.md b/docs/development.md index 395f3a6e..81957295 100644 --- a/docs/development.md +++ b/docs/development.md @@ -1,6 +1,6 @@ # Development -To make development a more pleasurable experience, `structlog` comes with the {mod}`structlog.dev` module. +To make development a more pleasurable experience, *structlog* comes with the {mod}`structlog.dev` module. The highlight is {class}`structlog.dev.ConsoleRenderer` that offers nicely aligned and colorful[^win] console output. @@ -18,13 +18,13 @@ Colorful console output by ConsoleRenderer. You can find the code for the output above [in the repo](https://github.com/hynek/structlog/blob/main/show_off.py). To use it, just add it as a renderer to your processor chain. -It will recognize logger names, log levels, time stamps, stack infos, and `exc_info` as produced by `structlog`'s processors and render them in special ways. +It will recognize logger names, log levels, time stamps, stack infos, and `exc_info` as produced by *structlog*'s processors and render them in special ways. :::{warning} For pretty exceptions to work, {func}`~structlog.processors.format_exc_info` must be **absent** from the processors chain. ::: -`structlog`'s default configuration already uses {class}`~structlog.dev.ConsoleRenderer`, therefore if you want nice colorful output on the console, you don't have to do anything except installing *Rich* or *better-exceptions* (and *Colorama* on Windows). +*structlog*'s default configuration already uses {class}`~structlog.dev.ConsoleRenderer`, therefore if you want nice colorful output on the console, you don't have to do anything except installing *Rich* or *better-exceptions* (and *Colorama* on Windows). If you want to use it along with standard library logging, we suggest the following configuration: ```python diff --git a/docs/frameworks.md b/docs/frameworks.md index 4b2ad48e..843dd557 100644 --- a/docs/frameworks.md +++ b/docs/frameworks.md @@ -1,10 +1,10 @@ # Frameworks -To have consistent log output, it makes sense to configure `structlog` *before* any logging is done. +To have consistent log output, it makes sense to configure *structlog* *before* any logging is done. The best place to perform your configuration varies with applications and frameworks. If you use standard library's logging, it makes sense to configure them next to each other. -If you have no choice but *have* to configure on import time in module-global scope, or can't rule out for other reasons that that your {func}`structlog.configure` gets called more than once, `structlog` offers {func}`structlog.configure_once` that raises a warning if `structlog` has been configured before (no matter whether using {func}`structlog.configure` or {func}`~structlog.configure_once`) but doesn't change anything. +If you have no choice but *have* to configure on import time in module-global scope, or can't rule out for other reasons that that your {func}`structlog.configure` gets called more than once, *structlog* offers {func}`structlog.configure_once` that raises a warning if *structlog* has been configured before (no matter whether using {func}`structlog.configure` or {func}`~structlog.configure_once`) but doesn't change anything. ## Django diff --git a/docs/getting-started.md b/docs/getting-started.md index d8761144..e7a69c34 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -4,7 +4,7 @@ ## Installation -The latest version of `structlog` is always on [PyPI](https://pypi.org/project/structlog/) and can be installed using *pip*: +The latest version of *structlog* is always on [PyPI](https://pypi.org/project/structlog/) and can be installed using *pip*: ```console $ python -m pip install structlog @@ -18,7 +18,7 @@ On Windows, you also have to install [*Colorama*] if you want colorful output be ## Your First Log Entry -A lot of effort went into making `structlog` accessible without reading pages of documentation. +A lot of effort went into making *structlog* accessible without reading pages of documentation. As a result, the simplest possible usage looks like this: ```{eval-rst} @@ -30,13 +30,13 @@ As a result, the simplest possible usage looks like this: 2022-10-07 10:41:29 [info ] hello, world! key=value! more_than_strings=[1, 2, 3] ``` -Here, `structlog` takes advantage of its default settings: +Here, *structlog* takes advantage of its default settings: - Output is sent to [standard out] instead doing nothing. - It imitates standard library {mod}`logging`'s log level names for familiarity. By default, no level-based filtering is done, but it comes with a very fast filtering machinery in the form of {func}`~structlog.make_filtering_bound_logger()`. - Like in `logging`, positional arguments are [interpolated into the message string using %](https://docs.python.org/3/library/stdtypes.html#old-string-formatting). - That might look dated, but it's *much* faster than using {any}`str.format` and allows ``structlog`` to be used as drop-in replacement for {mod}`logging`. + That might look dated, but it's *much* faster than using {any}`str.format` and allows *structlog* to be used as drop-in replacement for {mod}`logging`. If you *know* that the log entry is *always* gonna be logged out, just use [f-strings](https://docs.python.org/3/tutorial/inputoutput.html#formatted-string-literals) which are the fastest. - All keywords are formatted using {class}`structlog.dev.ConsoleRenderer`. That in turn uses {func}`repr` to serialize all values to strings. @@ -68,10 +68,10 @@ log = structlog.get_logger() ``` :::{note} -- {func}`structlog.stdlib.recreate_defaults()` allows you to switch `structlog` to using standard library's `logging` module for output for better interoperability with just one function call. +- {func}`structlog.stdlib.recreate_defaults()` allows you to switch *structlog* to using standard library's `logging` module for output for better interoperability with just one function call. - {func}`~structlog.make_filtering_bound_logger()` (re-)uses {any}`logging`'s log levels, but doesn't use `logging` at all. The exposed API is {class}`~structlog.typing.FilteringBoundLogger`. -- For brevity and to enable doctests, all further examples in `structlog`'s documentation use the more simplistic {class}`~structlog.processors.KeyValueRenderer()` without timestamps. +- For brevity and to enable doctests, all further examples in *structlog*'s documentation use the more simplistic {class}`~structlog.processors.KeyValueRenderer()` without timestamps. ::: Here you go, structured logging! @@ -146,7 +146,7 @@ Suddenly your logger becomes your closure! --- -To `structlog`, a log entry is just a dictionary called *event dict\[ionary\]*: +To *structlog*, a log entry is just a dictionary called *event dict\[ionary\]*: - You can pre-build a part of the dictionary step by step. These pre-saved values are called the *context*. @@ -158,7 +158,7 @@ The last point is very clean and easy to reason about, but sometimes it's useful In our example above the peer IP comes to mind. There's no point in extracting it in every view! -For that, `structlog` gives you thread-local context storage based on the {mod}`contextvars` module: +For that, *structlog* gives you thread-local context storage based on the {mod}`contextvars` module: ```pycon >>> structlog.contextvars.bind_contextvars(peer_ip="1.2.3.4") @@ -173,7 +173,7 @@ See {doc}`contextvars` for more information and a more complete example. Now that your log events are dictionaries, it's also much easier to manipulate them than if they were plain strings. -To facilitate that, `structlog` has the concept of {doc}`processor chains `. +To facilitate that, *structlog* has the concept of {doc}`processor chains `. A processor is a callable like a function that receives the event dictionary along with two other arguments and returns a new event dictionary that may or may not differ from the one it got passed. The next processor in the chain receives that returned dictionary instead of the original one. @@ -190,7 +190,7 @@ The processor would look like this: ``` Plain Python, plain dictionaries. -Now you have to tell `structlog` about your processor by {doc}`configuring ` it: +Now you have to tell *structlog* about your processor by {doc}`configuring ` it: ```{eval-rst} .. doctest:: @@ -205,10 +205,10 @@ Now you have to tell `structlog` about your processor by {doc}`configuring ` -- plus {doc}`loggers that are local to the current execution context ` -- can help you to minimize the output to a *single log entry*. +*structlog*'s ability to {ref}`bind data to loggers incrementally ` -- plus {doc}`loggers that are local to the current execution context ` -- can help you to minimize the output to a *single log entry*. At Stripe, this concept is called [Canonical Log Lines](https://brandur.org/canonical-log-lines). @@ -30,7 +30,7 @@ At Stripe, this concept is called [Canonical Log Lines](https://brandur.org/cano Colorful and pretty printed log messages are nice during development when you locally run your code. However, in production you should emit structured output (like JSON) which is a lot easier to parse by log aggregators. -Since you already log in a structured way, writing JSON output with `structlog` comes naturally. +Since you already log in a structured way, writing JSON output with *structlog* comes naturally. You can even generate structured exception tracebacks. This makes analyzing errors easier, since log aggregators can render JSON much better than multiline strings with a lot escaped quotation marks. @@ -87,7 +87,7 @@ All you have to do is to tell [*Logstash*] either that your log entries are prep [Graylog](https://www.graylog.org/) goes one step further. It not only supports everything those above do (and then some); you can also directly log JSON entries towards it -- optionally even through an AMQP server (like [*RabbitMQ*](https://www.rabbitmq.com/)) for better reliability. -Additionally, [Graylog's Extended Log Format](https://docs.graylog.org/docs/gelf) (GELF) allows for structured data which makes it an obvious choice to use together with `structlog`. +Additionally, [Graylog's Extended Log Format](https://docs.graylog.org/docs/gelf) (GELF) allows for structured data which makes it an obvious choice to use together with *structlog*. [*elasticsearch*]: https://www.elastic.co/elasticsearch diff --git a/docs/performance.md b/docs/performance.md index 5496168c..938654a0 100644 --- a/docs/performance.md +++ b/docs/performance.md @@ -1,18 +1,18 @@ # Performance -`structlog`'s default configuration tries to be as unsurprising to new developers as possible. +*structlog*'s default configuration tries to be as unsurprising to new developers as possible. Some of the choices made come with an avoidable performance price tag -- although its impact is debatable. -Here are a few hints how to get most out of `structlog` in production: +Here are a few hints how to get most out of *structlog* in production: 1. Use a specific wrapper class instead of the generic one. - `structlog` comes with ones for the {doc}`standard-library` and for {doc}`twisted`: + *structlog* comes with ones for the {doc}`standard-library` and for {doc}`twisted`: ```python configure(wrapper_class=structlog.stdlib.BoundLogger) ``` - `structlog` also comes with native log levels that are based on the ones from the standard library (read: we've copy and pasted them), but don't involve `logging`'s dynamic machinery. + *structlog* also comes with native log levels that are based on the ones from the standard library (read: we've copy and pasted them), but don't involve `logging`'s dynamic machinery. That makes them *much* faster with a very similar API. You can use {func}`structlog.make_filtering_bound_logger()` to create one. @@ -51,7 +51,7 @@ Here are a few hints how to get most out of `structlog` in production: ## Example -Here's an example for a production-ready non-*asyncio* `structlog` configuration that's as fast as it gets: +Here's an example for a production-ready non-*asyncio* *structlog* configuration that's as fast as it gets: ```python import logging @@ -92,7 +92,7 @@ Therefore a log entry might look like this: --- -If you need standard library support for external projects, you can either just use a JSON formatter like [*python-json-logger*](https://pypi.org/project/python-json-logger/), or pipe them through `structlog` as documented in {doc}`standard-library`. +If you need standard library support for external projects, you can either just use a JSON formatter like [*python-json-logger*](https://pypi.org/project/python-json-logger/), or pipe them through *structlog* as documented in {doc}`standard-library`. [*orjson*]: https://github.com/ijl/orjson [*rapidjson*]: https://pypi.org/project/python-rapidjson/ diff --git a/docs/processors.md b/docs/processors.md index 443e693e..748d23a8 100644 --- a/docs/processors.md +++ b/docs/processors.md @@ -1,6 +1,6 @@ # Processors -The true power of `structlog` lies in its *combinable log processors*. +The true power of *structlog* lies in its *combinable log processors*. A log processor is a regular callable, i.e. a function or an instance of a class with a `__call__()` method. (chains)= @@ -28,7 +28,7 @@ Each processors receives three positional arguments: The return value of each processor is passed on to the next one as `event_dict` until finally the return value of the last processor gets passed into the wrapped logging method. :::{note} -`structlog` only looks at the return value of the **last** processor. +*structlog* only looks at the return value of the **last** processor. That means that as long as you control the next processor in the chain (i.e. the processor that will get your return value passed as an argument), you can return whatever you want. Returning a modified event dictionary from your processors is just a convention to make processors composable. @@ -75,7 +75,7 @@ def timestamper(logger, log_method, event_dict): You're explicitly allowed to modify the `event_dict` parameter, because a copy has been created before calling the first processor. ::: -Please note that `structlog` comes with such a processor built in: {class}`~structlog.processors.TimeStamper`. +Please note that *structlog* comes with such a processor built in: {class}`~structlog.processors.TimeStamper`. ## Filtering @@ -118,7 +118,7 @@ class ConditionalDropper: return event_dict ``` -Since it's so common to filter by the log level, `structlog` comes with {func}`structlog.make_filtering_bound_logger` that filters log entries before they even enter the processor chain. +Since it's so common to filter by the log level, *structlog* comes with {func}`structlog.make_filtering_bound_logger` that filters log entries before they even enter the processor chain. It does **not** use the standard library, but it does use its names and order of log levels. (adapting)= @@ -136,7 +136,7 @@ It can return one of three types: Therefore `return "hello world"` is a shortcut for `return (("hello world",), {})` (the example in {ref}`chains` assumes this shortcut has been taken). -This should give you enough power to use `structlog` with any logging system while writing agnostic processors that operate on dictionaries. +This should give you enough power to use *structlog* with any logging system while writing agnostic processors that operate on dictionaries. :::{versionchanged} 14.0.0 Allow final processor to return a {any}`dict`. ::: @@ -157,7 +157,7 @@ For a list of shipped processors, check out the {ref}`API documentation ` ## Third-Party Packages -`structlog` was specifically designed to be as composable and reusable as possible, so whatever you're missing: +*structlog* was specifically designed to be as composable and reusable as possible, so whatever you're missing: chances are, you can solve it with a processor! Since processors are self-contained callables, it's easy to write your own and to share them in separate packages. diff --git a/docs/standard-library.md b/docs/standard-library.md index 07f00f19..3970f030 100644 --- a/docs/standard-library.md +++ b/docs/standard-library.md @@ -1,20 +1,20 @@ # Standard Library Logging -Ideally, `structlog` should be able to be used as a drop-in replacement for standard library's {mod}`logging` by wrapping it. -In other words, you should be able to replace your call to {func}`logging.getLogger` by a call to {func}`structlog.get_logger` and things should keep working as before (if `structlog` is configured right, see {ref}`stdlib-config` below). +Ideally, *structlog* should be able to be used as a drop-in replacement for standard library's {mod}`logging` by wrapping it. +In other words, you should be able to replace your call to {func}`logging.getLogger` by a call to {func}`structlog.get_logger` and things should keep working as before (if *structlog* is configured right, see {ref}`stdlib-config` below). If you run into incompatibilities, it is a *bug* so please take the time to [report it](https://github.com/hynek/structlog/issues)! If you're a heavy `logging` user, your [help](https://github.com/hynek/structlog/issues?q=is%3Aopen+is%3Aissue+label%3Astdlib) to ensure a better compatibility would be highly appreciated! :::{note} -The quickest way to get started with `structlog` and `logging` is {func}`structlog.stdlib.recreate_defaults()` that will recreate the default configuration on top of `logging` and optionally configure `logging` for you. +The quickest way to get started with *structlog* and `logging` is {func}`structlog.stdlib.recreate_defaults()` that will recreate the default configuration on top of `logging` and optionally configure `logging` for you. ::: ## Just Enough `logging` -If you want to use `structlog` with `logging`, you should have at least a fleeting understanding on how the standard library operates because `structlog` will *not* do any magic things in the background for you. -Most importantly you have to *configure* the `logging` system *additionally* to configuring `structlog`. +If you want to use *structlog* with `logging`, you should have at least a fleeting understanding on how the standard library operates because *structlog* will *not* do any magic things in the background for you. +Most importantly you have to *configure* the `logging` system *additionally* to configuring *structlog*. Usually it is enough to use: @@ -36,7 +36,7 @@ If you require more complex behavior, please refer to the standard library's `lo ## Concrete Bound Logger -`structlog` ships a stdlib-specific [*bound logger*](bound-loggers.md) that mirrors the log methods of standard library's {any}`logging.Logger` with correct type hints. +*structlog* ships a stdlib-specific [*bound logger*](bound-loggers.md) that mirrors the log methods of standard library's {any}`logging.Logger` with correct type hints. If you want to take advantage of said type hints, you have to either annotate the logger coming from {func}`structlog.get_logger`, or use {func}`structlog.stdlib.get_logger()` that has the appropriate type hints. Please note though, that it will neither configure nor verify your configuration. @@ -48,16 +48,16 @@ See also {doc}`typing`. ### `asyncio` For `asyncio` applications, you may not want your whole application to block while your processor chain is formatting your log entries. -For that use case `structlog` comes with {class}`structlog.stdlib.AsyncBoundLogger` that will do all processing in a thread pool executor. +For that use case *structlog* comes with {class}`structlog.stdlib.AsyncBoundLogger` that will do all processing in a thread pool executor. This means an increased computational cost per log entry but your application will never block because of logging. -To use it, {doc}`configure ` `structlog` to use `AsyncBoundLogger` as `wrapper_class`. +To use it, {doc}`configure ` *structlog* to use `AsyncBoundLogger` as `wrapper_class`. ## Processors -`structlog` comes with a few standard library-specific processors: +*structlog* comes with a few standard library-specific processors: {func}`~structlog.stdlib.render_to_log_kwargs`: @@ -103,14 +103,14 @@ To use it, {doc}`configure ` `structlog` to use `AsyncBoundLogger : This processes and formats positional arguments (if any) passed to log methods in the same way the `logging` module would do, e.g. `logger.info("Hello, %s", name)`. -`structlog` also comes with {class}`~structlog.stdlib.ProcessorFormatter` which is a `logging.Formatter` that enables you to format non-`structlog` log entries using `structlog` renderers *and* multiplex `structlog`’s output with different renderers (see [below](processor-formatter) for an example). +*structlog* also comes with {class}`~structlog.stdlib.ProcessorFormatter` which is a `logging.Formatter` that enables you to format non-*structlog* log entries using *structlog* renderers *and* multiplex *structlog*’s output with different renderers (see [below](processor-formatter) for an example). (stdlib-config)= ## Suggested Configurations :::{note} -We do appreciate that fully integrating `structlog` with standard library's `logging` is fiddly when done for the first time. +We do appreciate that fully integrating *structlog* with standard library's `logging` is fiddly when done for the first time. This is the price of flexibility and unfortunately -- given the different needs of our users -- we can't make it any simpler without compromising someone's use-cases. However, once it is set up, you can rely on not having to ever touch it again. @@ -121,16 +121,16 @@ Depending *where* you'd like to do your formatting, you can take one of four app ### Don't Integrate -The most straight-forward option is to configure standard library `logging` close enough to what `structlog` is logging and leaving it at that. +The most straight-forward option is to configure standard library `logging` close enough to what *structlog* is logging and leaving it at that. -Since these are usually log entries from third parties that don't take advantage of `structlog`'s features, this is surprisingly often a perfectly adequate approach. +Since these are usually log entries from third parties that don't take advantage of *structlog*'s features, this is surprisingly often a perfectly adequate approach. For instance, if you log JSON in production, configure `logging` to use [*python-json-logger*] to make it print JSON too, and then tweak the configuration to match their outputs. -### Rendering Within `structlog` +### Rendering Within *structlog* -This is the simplest approach where `structlog` does all the heavy lifting and passes a fully-formatted string to `logging`. +This is the simplest approach where *structlog* does all the heavy lifting and passes a fully-formatted string to `logging`. Chances are, this is all you need. ```{eval-rst} @@ -227,7 +227,7 @@ hello ### Rendering Using `logging`-based Formatters -You can choose to use `structlog` only for building the event dictionary and leave all formatting -- additionally to the output -- to the standard library. +You can choose to use *structlog* only for building the event dictionary and leave all formatting -- additionally to the output -- to the standard library. ```{eval-rst} .. mermaid:: @@ -273,7 +273,7 @@ structlog.configure( ``` Now you have the event dict available within each log record. -If you want all your log entries (i.e. also those not from your app/`structlog`) to be formatted as JSON, you can use the [*python-json-logger*] library: +If you want all your log entries (i.e. also those not from your application / *structlog*) to be formatted as JSON, you can use the [*python-json-logger*] library: ```python import logging @@ -287,7 +287,7 @@ root_logger = logging.getLogger() root_logger.addHandler(handler) ``` -Now both `structlog` and `logging` will emit JSON logs: +Now both *structlog* and `logging` will emit JSON logs: ```pycon >>> structlog.get_logger("test").warning("hello") @@ -306,10 +306,10 @@ Keep this in mind if you only get the event name without any context, and except (processor-formatter)= -### Rendering Using `structlog`-based Formatters Within `logging` +### Rendering Using *structlog*-based Formatters Within `logging` Finally, the most ambitious approach. -Here, you use `structlog`'s {class}`~structlog.stdlib.ProcessorFormatter` as a {any}`logging.Formatter` for both `logging` as well as `structlog` log entries. +Here, you use *structlog*'s {class}`~structlog.stdlib.ProcessorFormatter` as a {any}`logging.Formatter` for both `logging` as well as *structlog* log entries. Consequently, the output is the duty of the standard library too. @@ -337,7 +337,7 @@ Consequently, the output is the duty of the standard library too. {class}`~structlog.stdlib.ProcessorFormatter` has two parts to its API: -1. On the `structlog` side, the {doc}`processor chain ` must be configured to end with {func}`structlog.stdlib.ProcessorFormatter.wrap_for_formatter` as the renderer. +1. On the *structlog* side, the {doc}`processor chain ` must be configured to end with {func}`structlog.stdlib.ProcessorFormatter.wrap_for_formatter` as the renderer. It converts the processed event dictionary into something that `ProcessorFormatter` understands. 2. On the `logging` side, you must configure `ProcessorFormatter` as your formatter of choice. @@ -384,9 +384,9 @@ amazing _from_structlog=True _record= events=oh yes ``` Of course, you probably want timestamps and log levels in your output. -The `ProcessorFormatter` has a `foreign_pre_chain` argument which is responsible for adding properties to events from the standard library -- i.e. that do not originate from a `structlog` logger -- and which should in general match the `processors` argument to {func}`structlog.configure` so you get a consistent output. +The `ProcessorFormatter` has a `foreign_pre_chain` argument which is responsible for adding properties to events from the standard library -- i.e. that do not originate from a *structlog* logger -- and which should in general match the `processors` argument to {func}`structlog.configure` so you get a consistent output. -`_from_structlog` and `_record` allow your processors to determine whether the log entry is coming from `structlog`, and to extract information from `logging.LogRecord`s and add them to the event dictionary. +`_from_structlog` and `_record` allow your processors to determine whether the log entry is coming from *structlog*, and to extract information from `logging.LogRecord`s and add them to the event dictionary. However, you probably don't want to have them in your log files, thus we've added the `ProcessorFormatter.remove_processors_meta` processor to do so conveniently. For example, to add timestamps, log levels, and traceback handling to your logs without `_from_structlog` and `_record` noise you should do: @@ -517,9 +517,9 @@ structlog.configure( This defines two formatters: one plain and one colored. Both are run for each log entry. -Log entries that do not originate from `structlog`, are additionally pre-processed using a cached `timestamper` and {func}`~structlog.stdlib.add_log_level`. +Log entries that do not originate from *structlog*, are additionally pre-processed using a cached `timestamper` and {func}`~structlog.stdlib.add_log_level`. -Additionally, for both `logging` and `structlog` -- but only for the colorful logger -- we also extract some data from {class}`logging.LogRecord`: +Additionally, for both `logging` and *structlog* -- but only for the colorful logger -- we also extract some data from {class}`logging.LogRecord`: ```pycon >>> logging.getLogger().warning("bar") diff --git a/docs/testing.md b/docs/testing.md index 662a2283..d7447426 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -1,6 +1,6 @@ # Testing -`structlog` comes with tools for testing the logging behavior of your application. +*structlog* comes with tools for testing the logging behavior of your application. If you need functionality similar to {meth}`unittest.TestCase.assertLogs`, or you want to capture all logs for some other reason, you can use the {func}`structlog.testing.capture_logs` context manager: @@ -66,7 +66,7 @@ You can also use {class}`structlog.testing.CapturingLogger` (directly, or via {c --- -Additionally `structlog` also ships with a logger that just returns whatever it gets passed into it: {class}`structlog.testing.ReturnLogger`. +Additionally *structlog* also ships with a logger that just returns whatever it gets passed into it: {class}`structlog.testing.ReturnLogger`. ```{eval-rst} .. doctest:: diff --git a/docs/thread-local.md b/docs/thread-local.md index 1aaa3b7a..f42bd384 100644 --- a/docs/thread-local.md +++ b/docs/thread-local.md @@ -1,7 +1,7 @@ # Legacy Thread-local Context :::{attention} -The `structlog.threadlocal` module is deprecated as of `structlog` 22.1.0 in favor of {doc}`contextvars`. +The `structlog.threadlocal` module is deprecated as of *structlog* 22.1.0 in favor of {doc}`contextvars`. The standard library {mod}`contextvars` module provides a more feature-rich superset of the thread-local APIs and works with thread-local data, async code, and greenlets. @@ -28,14 +28,14 @@ Therefore, as of 22.1.0, the `structlog.threadlocal` module is frozen and will b ## The `merge_threadlocal` Processor -`structlog` provides a simple set of functions that allow explicitly binding certain fields to a global (thread-local) context and merge them later using a processor into the event dict. +*structlog* provides a simple set of functions that allow explicitly binding certain fields to a global (thread-local) context and merge them later using a processor into the event dict. The general flow of using these functions is: - Use {func}`structlog.configure` with {func}`structlog.threadlocal.merge_threadlocal` as your first processor. - Call {func}`structlog.threadlocal.clear_threadlocal` at the beginning of your request handler (or whenever you want to reset the thread-local context). - Call {func}`structlog.threadlocal.bind_threadlocal` as an alternative to your bound logger's `bind()` when you want to bind a particular variable to the thread-local context. -- Use `structlog` as normal. +- Use *structlog* as normal. Loggers act as they always do, but the {func}`structlog.threadlocal.merge_threadlocal` processor ensures that any thread-local binds get included in all of your log messages. - If you want to access the thread-local storage, you use {func}`structlog.threadlocal.get_threadlocal` and {func}`structlog.threadlocal.get_merged_threadlocal`. @@ -50,7 +50,7 @@ These functions map 1:1 to the {doc}`contextvars` APIs, so please use those inst ## Thread-local Contexts -`structlog` also provides thread-local context storage in a form that you may already know from [*Flask*](https://flask.palletsprojects.com/en/latest/design/#thread-locals) and that makes the *entire context* global to your thread or greenlet. +*structlog* also provides thread-local context storage in a form that you may already know from [*Flask*](https://flask.palletsprojects.com/en/latest/design/#thread-locals) and that makes the *entire context* global to your thread or greenlet. This makes its behavior more difficult to reason about which is why we generally recommend to use the {func}`~structlog.contextvars.merge_contextvars` route. Therefore, there are currently no plans to re-implement this behavior on top of context variables. @@ -58,7 +58,7 @@ Therefore, there are currently no plans to re-implement this behavior on top of ### Wrapped Dicts -In order to make your context thread-local, `structlog` ships with a function that can wrap any dict-like class to make it usable for thread-local storage: {func}`structlog.threadlocal.wrap_dict`. +In order to make your context thread-local, *structlog* ships with a function that can wrap any dict-like class to make it usable for thread-local storage: {func}`structlog.threadlocal.wrap_dict`. Within one thread, every instance of the returned class will have a *common* instance of the wrapped dict-like class: diff --git a/docs/twisted.md b/docs/twisted.md index c03d1df9..8629a7f8 100644 --- a/docs/twisted.md +++ b/docs/twisted.md @@ -1,29 +1,29 @@ # Twisted :::{warning} -Since `sys.exc_clear` has been dropped in Python 3, there is currently no way to avoid multiple tracebacks in your log files if using `structlog` together with Twisted on Python 3. +Since `sys.exc_clear` has been dropped in Python 3, there is currently no way to avoid multiple tracebacks in your log files if using *structlog* together with Twisted on Python 3. ::: :::{note} -`structlog` currently only supports the legacy -- but still perfectly working -- Twisted logging system found in `twisted.python.log`. +*structlog* currently only supports the legacy -- but still perfectly working -- Twisted logging system found in `twisted.python.log`. ::: ## Concrete Bound Logger -To make `structlog`'s behavior less magical, it ships with a Twisted-specific wrapper class that has an explicit API instead of improvising: `structlog.twisted.BoundLogger`. +To make *structlog*'s behavior less magical, it ships with a Twisted-specific wrapper class that has an explicit API instead of improvising: `structlog.twisted.BoundLogger`. It behaves exactly like the generic `structlog.BoundLogger` except: - it's slightly faster due to less overhead, - has an explicit API ({func}`~structlog.twisted.BoundLogger.msg` and {func}`~structlog.twisted.BoundLogger.err`), - hence causing less cryptic error messages if you get method names wrong. -In order to avoid that `structlog` disturbs your CamelCase harmony, it comes with an alias for `structlog.get_logger` called `structlog.getLogger`. +In order to avoid that *structlog* disturbs your CamelCase harmony, it comes with an alias for `structlog.get_logger` called `structlog.getLogger`. ## Processors -`structlog` comes with two Twisted-specific processors: +*structlog* comes with two Twisted-specific processors: {func}`structlog.twisted.EventAdapter` @@ -48,7 +48,7 @@ In order to avoid that `structlog` disturbs your CamelCase harmony, it comes wit ``` The drawback of this approach is that Twisted will format your exceptions as multi-line log entries which is painful to parse. - Therefore `structlog` comes with: + Therefore *structlog* comes with: {func}`structlog.twisted.JSONRenderer` @@ -58,7 +58,7 @@ In order to avoid that `structlog` disturbs your CamelCase harmony, it comes wit ## Bending Foreign Logging To Your Will -`structlog` comes with a wrapper for Twisted's log observers to ensure the rest of your logs are in JSON too: `structlog.twisted.JSONLogObserverWrapper`. +*structlog* comes with a wrapper for Twisted's log observers to ensure the rest of your logs are in JSON too: `structlog.twisted.JSONLogObserverWrapper`. What it does is determining whether a log entry has been formatted by `structlog.twisted.JSONRenderer` and if not, converts the log entry to JSON with `event` being the log message and putting Twisted's `system` into a second key. @@ -77,7 +77,7 @@ becomes: There is obviously some redundancy here. Also, I'm presuming that if you write out JSON logs, you're going to let something else parse them which makes the human-readable date entries more trouble than they're worth. -To get a clean log without timestamps and additional system fields (`[-]`), `structlog` comes with `structlog.twisted.PlainFileLogObserver` that writes only the plain message to a file and `structlog.twisted.plainJSONStdOutLogger` that composes it with the aforementioned `structlog.twisted.JSONLogObserverWrapper` and gives you a pure JSON log without any timestamps or other noise straight to [standard out]: +To get a clean log without timestamps and additional system fields (`[-]`), *structlog* comes with `structlog.twisted.PlainFileLogObserver` that writes only the plain message to a file and `structlog.twisted.plainJSONStdOutLogger` that composes it with the aforementioned `structlog.twisted.JSONLogObserverWrapper` and gives you a pure JSON log without any timestamps or other noise straight to [standard out]: ```console $ twistd -n --logger structlog.twisted.plainJSONStdOutLogger web diff --git a/docs/typing.md b/docs/typing.md index d1324c16..1e6da4c8 100644 --- a/docs/typing.md +++ b/docs/typing.md @@ -1,9 +1,9 @@ # Type Hints Static type hints -- together with a type checker like [*Mypy*](https://mypy.readthedocs.io/en/stable/) -- are an excellent way to make your code more robust, self-documenting, and maintainable in the long run. -And as of 20.2.0, `structlog` comes with type hints for all of its APIs. +And as of 20.2.0, *structlog* comes with type hints for all of its APIs. -Since `structlog` is highly configurable and tries to give a clean facade to its users, adding types without breaking compatibility -- while remaining useful! -- was a formidable task. +Since *structlog* is highly configurable and tries to give a clean façade to its users, adding types without breaking compatibility -- while remaining useful! -- was a formidable task. --- diff --git a/docs/why.md b/docs/why.md index 41b6b886..f671d24d 100644 --- a/docs/why.md +++ b/docs/why.md @@ -30,7 +30,7 @@ You can stop writing prose and start thinking in terms of an event that happens Each log entry is a meaningful dictionary instead of an opaque string now! -That said, `structlog` is not taking anything away from you. +That said, *structlog* is not taking anything away from you. You can still use string interpolation using positional arguments: ```pycon @@ -64,7 +64,7 @@ def timestamper(logger, log_method, event_dict): return event_dict ``` -There are [plenty of processors](structlog.processors) for most common tasks coming with `structlog`: +There are [plenty of processors](structlog.processors) for most common tasks coming with *structlog*: - Collectors of [call stack information](structlog.processors.StackInfoRenderer) ("How did this log entry happen?"), - …and [exceptions](structlog.processors.format_exc_info) ("What happened‽"). @@ -73,7 +73,7 @@ There are [plenty of processors](structlog.processors) for most common tasks com ### Formatting -`structlog` is completely flexible about *how* the resulting log entry is emitted. +*structlog* is completely flexible about *how* the resulting log entry is emitted. Since each log entry is a dictionary, it can be formatted to **any** format: - A colorful key-value format for [local development](https://www.structlog.org/en/stable/development.html), @@ -81,24 +81,25 @@ Since each log entry is a dictionary, it can be formatted to **any** format: - or some standard format you have parsers for like *nginx* or Apache *httpd*. Internally, formatters are processors whose return value (usually a string) is passed into loggers that are responsible for the output of your message. -`structlog` comes with multiple useful formatters out-of-the-box. +*structlog* comes with multiple useful formatters out-of-the-box. ### Output -`structlog` is also flexible with the final output of your log entries: +*structlog* is also flexible with the final output of your log entries: - A **built-in** lightweight printer like in the examples above. Easy to use and fast. - Use the [**standard library**](standard-library.md)'s or [**Twisted**](twisted.md)'s logging modules for compatibility. - In this case `structlog` works like a wrapper that formats a string and passes them off into existing systems that won't know that `structlog` even exists. + In this case *structlog* works like a wrapper that formats a string and passes them off into existing systems that won't know that *structlog* even exists. - Or the other way round: `structlog` comes with a `logging` formatter that allows for processing third party log records. + Or the other way round: *structlog* comes with a `logging` formatter that allows for processing third party log records. - Don't format it to a string at all! - `structlog` passes you a dictionary and you can do with it whatever you want. + *structlog* passes you a dictionary and you can do with it whatever you want. Reported use cases are sending them out via network or saving them in a database. + ### Highly Testable -`structlog` is thoroughly tested and we see it as our duty to help you to achieve the same in *your* applications. +*structlog* is thoroughly tested and we see it as our duty to help you to achieve the same in *your* applications. That's why it ships with a [test helpers](https://www.structlog.org/en/stable/testing.html) to introspect your application's logging behavior with little-to-no boilerplate. diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 57755ac9..6946a463 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -70,9 +70,9 @@ class _Configuration: def is_configured() -> bool: """ - Return whether ``structlog`` has been configured. + Return whether *structlog* has been configured. - If `False`, ``structlog`` is running with builtin defaults. + If `False`, *structlog* is running with builtin defaults. .. versionadded: 18.1 """ @@ -85,7 +85,7 @@ def get_config() -> dict[str, Any]: .. note:: - Changes to the returned dictionary do *not* affect ``structlog``. + Changes to the returned dictionary do *not* affect *structlog*. .. versionadded: 18.1 """ diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index 4acc9e4b..0f9e8af5 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -89,7 +89,7 @@ def make_filtering_bound_logger(min_level: int) -> type[FilteringBoundLogger]: Additionally it has a ``log(self, level: int, **kw: Any)`` method to mirror `logging.Logger.log` and `structlog.stdlib.BoundLogger.log`. - Compared to using ``structlog``'s standard library integration and the + Compared to using *structlog*'s standard library integration and the `structlog.stdlib.filter_by_level` processor: - It's faster because once the logger is built at program start; it's a diff --git a/src/structlog/contextvars.py b/src/structlog/contextvars.py index 94340c85..ebb5941d 100644 --- a/src/structlog/contextvars.py +++ b/src/structlog/contextvars.py @@ -38,7 +38,7 @@ def get_contextvars() -> dict[str, Any]: """ - Return a copy of the ``structlog``-specific context-local context. + Return a copy of the *structlog*-specific context-local context. .. versionadded:: 21.2.0 """ diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 280ba5ca..9abf86fe 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -4,7 +4,7 @@ # repository for complete details. """ -Helpers that make development with ``structlog`` more pleasant. +Helpers that make development with *structlog* more pleasant. See also the narrative documentation in `development`. """ diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 722c115d..1a7116ca 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -587,11 +587,11 @@ class StackInfoRenderer: of the Python standard library logging. :param additional_ignores: By default, stack frames coming from - ``structlog`` are ignored. With this argument you can add additional + *structlog* are ignored. With this argument you can add additional names that are ignored, before the stack starts being rendered. They are matched using ``startswith()``, so they don't have to match exactly. The names are used to find the first relevant name, therefore - once a frame is found that doesn't start with ``structlog`` or one of + once a frame is found that doesn't start with *structlog* or one of *additional_ignores*, **no filtering** is applied to subsequent frames. .. versionadded:: 0.4.0 @@ -660,7 +660,7 @@ class CallsiteParameterAdder: async functions. If the event dictionary has an embedded `logging.LogRecord` object and did - not originate from `structlog` then the callsite information will be + not originate from *structlog* then the callsite information will be determined from the `logging.LogRecord` object. For event dictionaries without an embedded `logging.LogRecord` object the callsite will be determined from the stack trace, ignoring all intra-structlog calls, calls diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index f97c274e..e44f956e 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -100,7 +100,7 @@ def recreate_defaults(*, log_level: int | None = logging.NOTSET) -> None: class _FixedFindCallerLogger(logging.Logger): """ Change the behavior of `logging.Logger.findCaller` to cope with - ``structlog``'s extra frames. + *structlog*'s extra frames. """ def findCaller( @@ -382,7 +382,7 @@ def get_logger(*args: Any, **initial_values: Any) -> BoundLogger: .. warning:: - Does **not** check whether you've configured ``structlog`` correctly! + Does **not** check whether you've configured *structlog* correctly! See :doc:`standard-library` for details. @@ -561,7 +561,7 @@ class LoggerFactory: whose names *start* with one of these. For example, in pyramid applications you'll want to set it to ``["venusian", "pyramid.config"]``. This argument is - called *additional_ignores* in other APIs throughout `structlog`. + called *additional_ignores* in other APIs throughout *structlog*. """ def __init__(self, ignore_frame_names: list[str] | None = None): @@ -791,35 +791,35 @@ def render_to_log_kwargs( class ProcessorFormatter(logging.Formatter): r""" - Call ``structlog`` processors on `logging.LogRecord`\s. + Call *structlog* processors on `logging.LogRecord`\s. This is an implementation of a `logging.Formatter` that can be used to - format log entries from both ``structlog`` and `logging`. + format log entries from both *structlog* and `logging`. Its static method `wrap_for_formatter` must be the final processor in - ``structlog``'s processor chain. + *structlog*'s processor chain. Please refer to :ref:`processor-formatter` for examples. :param foreign_pre_chain: If not `None`, it is used as a processor chain that is applied to - **non**-``structlog`` log entries before the event dictionary is passed + **non**-*structlog* log entries before the event dictionary is passed to *processors*. (default: `None`) :param processors: - A chain of ``structlog`` processors that is used to process **all** log + A chain of *structlog* processors that is used to process **all** log entries. The last one must render to a `str` which then gets passed on to `logging` for output. - Compared to ``structlog``'s regular processor chains, there's a few + Compared to *structlog*'s regular processor chains, there's a few differences: - The event dictionary contains two additional keys: #. ``_record``: a `logging.LogRecord` that either was created using - `logging` APIs, **or** is a wrapped ``structlog`` log entry + `logging` APIs, **or** is a wrapped *structlog* log entry created by `wrap_for_formatter`. #. ``_from_structlog``: a `bool` that indicates whether or not - ``_record`` was created by a ``structlog`` logger. + ``_record`` was created by a *structlog* logger. Since you most likely don't want ``_record`` and ``_from_structlog`` in your log files, we've added @@ -834,14 +834,14 @@ class ProcessorFormatter(logging.Formatter): ``True`` to keep it on the `logging.LogRecord`. (default: False) :param keep_stack_info: Same as *keep_exc_info* except for ``stack_info``. (default: False) - :param logger: Logger which we want to push through the ``structlog`` + :param logger: Logger which we want to push through the *structlog* processor chain. This parameter is necessary for some of the processors like `filter_by_level`. (default: None) :param pass_foreign_args: If True, pass a foreign log record's ``args`` attribute to the ``event_dict`` under ``positional_args`` key. (default: False) :param processor: - A single ``structlog`` processor used for rendering the event + A single *structlog* processor used for rendering the event dictionary before passing it off to `logging`. Must return a `str`. The event dictionary does **not** contain ``_record`` and ``_from_structlog``. @@ -901,7 +901,7 @@ def __init__( def format(self, record: logging.LogRecord) -> str: """ - Extract ``structlog``'s `event_dict` from ``record.msg`` and format it. + Extract *structlog*'s `event_dict` from ``record.msg`` and format it. *record* has been patched by `wrap_for_formatter` first though, so the type isn't quite right. diff --git a/src/structlog/typing.py b/src/structlog/typing.py index 3cc0d33c..ca4e8c0b 100644 --- a/src/structlog/typing.py +++ b/src/structlog/typing.py @@ -4,7 +4,7 @@ # repository for complete details. """ -Type information used throughout ``structlog``. +Type information used throughout *structlog*. For now, they are considered provisional. Especially `BindableLogger` will probably change to something more elegant. @@ -42,7 +42,7 @@ A logger that is wrapped by a bound logger and is ultimately responsible for the output of the log entries. -``structlog`` makes *no* assumptions about it. +*structlog* makes *no* assumptions about it. .. versionadded:: 20.2 """ @@ -124,7 +124,7 @@ def __call__(self, exc_info: ExcInfo) -> Any: class BindableLogger(Protocol): """ **Protocol**: Methods shared among all bound loggers and that are relied on - by ``structlog``. + by *structlog*. .. versionadded:: 20.2 """ From 702786bc36e83298bf993a101e2eab3038a969e9 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 10:20:53 +0200 Subject: [PATCH 0835/1520] Refactor recipes --- docs/index.md | 6 +++--- docs/{frameworks.md => recipes.md} | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) rename docs/{frameworks.md => recipes.md} (65%) diff --git a/docs/index.md b/docs/index.md index 980a58c5..7e71efae 100644 --- a/docs/index.md +++ b/docs/index.md @@ -17,7 +17,7 @@ Release **{sub-ref}`release`** ([What's new?](changelog)) - If you're not sure whether *structlog* is for you, have a look at {doc}`why`. - If you can't wait to log your first entry, start at {doc}`getting-started` and then work yourself through our tutorial. -- Once you have basic grasp of how *structlog* works, acquaint yourself with the [integrations](integration) *structlog* is shipping with. +- Once you have basic grasp of how *structlog* works, have a look on how it [integrates](integration) best with your existing frameworks. ## User's Guide @@ -49,17 +49,17 @@ Dedicated support for the standard library and Twisted is shipped out-of-the-box ```{toctree} :maxdepth: 2 -frameworks standard-library twisted ``` -### Advanced Topics +### *structlog* in Practice ```{toctree} :maxdepth: 2 +recipes logging-best-practices performance custom-wrappers diff --git a/docs/frameworks.md b/docs/recipes.md similarity index 65% rename from docs/frameworks.md rename to docs/recipes.md index 843dd557..ae18ebc0 100644 --- a/docs/frameworks.md +++ b/docs/recipes.md @@ -1,30 +1,30 @@ -# Frameworks +# Recipes + +## Integration with Frameworks To have consistent log output, it makes sense to configure *structlog* *before* any logging is done. The best place to perform your configuration varies with applications and frameworks. If you use standard library's logging, it makes sense to configure them next to each other. -If you have no choice but *have* to configure on import time in module-global scope, or can't rule out for other reasons that that your {func}`structlog.configure` gets called more than once, *structlog* offers {func}`structlog.configure_once` that raises a warning if *structlog* has been configured before (no matter whether using {func}`structlog.configure` or {func}`~structlog.configure_once`) but doesn't change anything. - -## Django +### Django [*django-structlog*](https://pypi.org/project/django-structlog/) is a popular and well-maintained package that does all the heavy lifting. -## Flask +### Flask See Flask's [Logging docs](https://flask.palletsprojects.com/en/latest/logging/). Generally speaking: put it *before* instantiating `flask.Flask`. -## Pyramid +### Pyramid [Application constructor](https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/startup.html#the-startup-process>). -## Twisted +### Twisted The [plugin definition](https://docs.twisted.org/en/stable/core/howto/plugin.html) is the best place. If your app is not a plugin, put it into your [tac file](https://docs.twisted.org/en/stable/core/howto/application.html). From 010867d6d73e59728efdc54385c45f8bf423b0aa Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 10:29:32 +0200 Subject: [PATCH 0836/1520] Mention docs overhaul in changelog --- CHANGELOG.md | 3 +++ docs/standard-library.md | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 368d6276..af37a420 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,9 @@ So please make sure to **always** properly configure your applications. ### Changed +- The documentation has been **heavily** overhauled. + Have a look, if you haven't lately! + Especially the graphs in the [standard library chapter](https://www.structlog.org/en/latest/standard-library.html) are both surprising and useful to many. - The build backend has been switched to [*Hatch*](https://hatch.pypa.io/). diff --git a/docs/standard-library.md b/docs/standard-library.md index 3970f030..0d466047 100644 --- a/docs/standard-library.md +++ b/docs/standard-library.md @@ -6,8 +6,9 @@ In other words, you should be able to replace your call to {func}`logging.getLog If you run into incompatibilities, it is a *bug* so please take the time to [report it](https://github.com/hynek/structlog/issues)! If you're a heavy `logging` user, your [help](https://github.com/hynek/structlog/issues?q=is%3Aopen+is%3Aissue+label%3Astdlib) to ensure a better compatibility would be highly appreciated! -:::{note} -The quickest way to get started with *structlog* and `logging` is {func}`structlog.stdlib.recreate_defaults()` that will recreate the default configuration on top of `logging` and optionally configure `logging` for you. +:::{important} +The quickest way to get started with *structlog* and `logging` is {func}`structlog.stdlib.recreate_defaults()`. +It will recreate the default configuration on top of `logging` and optionally configure `logging` for you. ::: From d43a47e0eb44ed5d904e270ecca74d6b208a34e6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 11:00:09 +0200 Subject: [PATCH 0837/1520] Flatten index --- docs/index.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/docs/index.md b/docs/index.md index 7e71efae..506709ea 100644 --- a/docs/index.md +++ b/docs/index.md @@ -20,9 +20,7 @@ Release **{sub-ref}`release`** ([What's new?](changelog)) - Once you have basic grasp of how *structlog* works, have a look on how it [integrates](integration) best with your existing frameworks. -## User's Guide - -### Basics +## Basics ```{toctree} :maxdepth: 2 @@ -40,7 +38,7 @@ typing (integration)= -### Integration with Existing Systems +## Integration with Existing Systems *structlog* is both zero-config as well as highly configurable. You can use it on its own or integrate with existing systems. @@ -54,7 +52,7 @@ twisted ``` -### *structlog* in Practice +## *structlog* in Practice ```{toctree} :maxdepth: 2 @@ -66,7 +64,7 @@ custom-wrappers ``` -### Deprecated Features +## Deprecated Features ```{toctree} :maxdepth: 1 From b7bfa10ae5c9d1399c1b43db56f7aa9b3380d9e3 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 11:09:07 +0200 Subject: [PATCH 0838/1520] Separate out affordances --- docs/{development.md => console-output.md} | 2 +- docs/index.md | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) rename docs/{development.md => console-output.md} (99%) diff --git a/docs/development.md b/docs/console-output.md similarity index 99% rename from docs/development.md rename to docs/console-output.md index 81957295..eb6ddd8a 100644 --- a/docs/development.md +++ b/docs/console-output.md @@ -1,4 +1,4 @@ -# Development +# Console Output To make development a more pleasurable experience, *structlog* comes with the {mod}`structlog.dev` module. diff --git a/docs/index.md b/docs/index.md index 506709ea..63d62ce3 100644 --- a/docs/index.md +++ b/docs/index.md @@ -31,7 +31,16 @@ bound-loggers configuration processors contextvars -development +``` + + +## In-Development Affordances + +*structlog*'s focus are production systems, but it comes with **pretty console logging** and handy in-development helpers for **comfort** and **better results**. + +```{toctree} +:maxdepth: 2 +console-output testing typing ``` From c547c2675e42f48f8b6022206a6d8b08058357b3 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 11:27:09 +0200 Subject: [PATCH 0839/1520] Streamline first impression --- docs/getting-started.md | 18 ++++++++---------- docs/index.md | 11 ++++------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index e7a69c34..8f46562f 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -4,7 +4,7 @@ ## Installation -The latest version of *structlog* is always on [PyPI](https://pypi.org/project/structlog/) and can be installed using *pip*: +You can install *structlog* from [PyPI](https://pypi.org/project/structlog/) using *pip*: ```console $ python -m pip install structlog @@ -13,7 +13,7 @@ $ python -m pip install structlog If you want pretty exceptions in development (you know you do!), additionally install either [*Rich*] or [*better-exceptions*]. Try both to find out which one you like better -- the screenshot in the README and docs homepage is rendered by *Rich*. -On Windows, you also have to install [*Colorama*] if you want colorful output beside exceptions. +On **Windows**, you also have to install [*Colorama*](https://pypi.org/project/colorama/) if you want colorful output beside exceptions. ## Your First Log Entry @@ -32,16 +32,16 @@ As a result, the simplest possible usage looks like this: Here, *structlog* takes advantage of its default settings: -- Output is sent to [standard out] instead doing nothing. -- It imitates standard library {mod}`logging`'s log level names for familiarity. +- Output is sent to **[standard out](https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29)** instead doing nothing. +- It **imitates** standard library {mod}`logging`'s **log level names** for familiarity. By default, no level-based filtering is done, but it comes with a very fast filtering machinery in the form of {func}`~structlog.make_filtering_bound_logger()`. -- Like in `logging`, positional arguments are [interpolated into the message string using %](https://docs.python.org/3/library/stdtypes.html#old-string-formatting). +- Like in `logging`, **positional arguments are [interpolated into the message string using %](https://docs.python.org/3/library/stdtypes.html#old-string-formatting)**. That might look dated, but it's *much* faster than using {any}`str.format` and allows *structlog* to be used as drop-in replacement for {mod}`logging`. If you *know* that the log entry is *always* gonna be logged out, just use [f-strings](https://docs.python.org/3/tutorial/inputoutput.html#formatted-string-literals) which are the fastest. - All keywords are formatted using {class}`structlog.dev.ConsoleRenderer`. - That in turn uses {func}`repr` to serialize all values to strings. -- It's rendered in nice {doc}`colors ` (the [*Colorama*] package is needed on Windows). -- If you have [*Rich*] or [*better-exceptions*] installed, exceptions will be rendered in colors and with additional helpful information. + That in turn uses {func}`repr` to serialize **any value to a string**. +- It's rendered in **nice {doc}`colors `**. +- If you have [*Rich*] or [*better-exceptions*] installed, **exceptions** will be rendered in **colors** and with additional **helpful information**. Please note that even in most complex logging setups the example would still look just like that thanks to {doc}`configuration`. Using the defaults, as above, is equivalent to: @@ -236,7 +236,5 @@ Now you're all set for the rest of the user's guide and can start reading about [*better-exceptions*]: https://github.com/qix-/better-exceptions -[*Colorama*]: https://pypi.org/project/colorama/ [recipe]: https://docs.python.org/3/howto/logging-cookbook.html#implementing-structured-logging [*Rich*]: https://github.com/Textualize/rich -[standard out]: https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29 diff --git a/docs/index.md b/docs/index.md index 63d62ce3..8e425cd0 100644 --- a/docs/index.md +++ b/docs/index.md @@ -12,15 +12,12 @@ Release **{sub-ref}`release`** ([What's new?](changelog)) ``` +## Basics -## First Steps - -- If you're not sure whether *structlog* is for you, have a look at {doc}`why`. -- If you can't wait to log your first entry, start at {doc}`getting-started` and then work yourself through our tutorial. -- Once you have basic grasp of how *structlog* works, have a look on how it [integrates](integration) best with your existing frameworks. - +The following chapters give you the all the concepts that you need to use *structlog* productively. +If you're already convinced that you want to play with it, start with our [Getting Started tutorial](getting-started.md)! +The rest of the chapters builds gently on each other. -## Basics ```{toctree} :maxdepth: 2 From 10caab387f275748101c642fe6220178d3b8676b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 11:30:35 +0200 Subject: [PATCH 0840/1520] Better word --- docs/bound-loggers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/bound-loggers.md b/docs/bound-loggers.md index 0882829a..1493c202 100644 --- a/docs/bound-loggers.md +++ b/docs/bound-loggers.md @@ -100,7 +100,7 @@ Now if you call `log.info("Hello, %s!", "world", number=42)` the following happe For example, if you wanted JSON logs, you just have to replace the last processor with {class}`structlog.processors.JSONRenderer`. -## Wrapping Loggers Explicitly +## Wrapping Loggers Manually In practice, you won't be instantiating bound loggers yourself. You will configure *structlog* as explained in the {doc}`next chapter ` and then just call {func}`structlog.get_logger`. From 19c2ae9d4fe76cbab335b2c7bce186f459414d02 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 11:55:14 +0200 Subject: [PATCH 0841/1520] Configure level-filtering --- docs/bound-loggers.md | 44 +++++++++++++++++++++++++++++++++++++++++ docs/getting-started.md | 4 ++-- src/structlog/stdlib.py | 4 ++-- 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/docs/bound-loggers.md b/docs/bound-loggers.md index 1493c202..9f984330 100644 --- a/docs/bound-loggers.md +++ b/docs/bound-loggers.md @@ -99,6 +99,50 @@ Now if you call `log.info("Hello, %s!", "world", number=42)` the following happe By replacing the last processor, you decide on the **format** of your logs. For example, if you wanted JSON logs, you just have to replace the last processor with {class}`structlog.processors.JSONRenderer`. +(filtering)= + +## Filtering Loggers + +Filtering based on loggers could be done in a processor very easily[^stdlib], however that means unnecessary performance overhead through function calls. +We care a lot about performance and that's why *structlog*'s default logger implements level-filtering as close to the users as possible: in the *bound logger*'s logging methods. + +{func}`structlog.make_filtering_bound_logger` allows you to create a *bound logger* whose log methods with a log level beneath the configured one consist of a plain `return None`. + +Here's an example: + +```pycon +>>> import structlog +>>> logger = structlog.get_logger() +>>> logger.debug("hi!") +2022-10-15 11:39:03 [debug ] hi! +>>> import logging +>>> structlog.configure(wrapper_class=structlog.make_filtering_bound_logger(logging.INFO)) +>>> logger.debug("hi!") +# no output! +``` + +In this example, we first log out using the default logger that doesn't filter at all. +Then we change the configuration to filtering at the info level and try again: +no log output! + +Let's have a look at the `debug` method: + +```pycon +>>> import inspect +>>> print(inspect.getsource(logger.debug)) +def _nop(self: Any, event: str, **kw: Any) -> Any: + return None +``` + +This is as effective as it gets and usually as flexible as the vast majority of users need. + +:::{important} +*structlog* uses the constants from {mod}`logging`, but does **not** share any code. +Passing `20` instead of `logging.INFO` would have worked too. +::: + +[^stdlib]: And it's in fact supported for standard library logging with the {func}`structlog.stdlib.filter_by_level` processor. + ## Wrapping Loggers Manually diff --git a/docs/getting-started.md b/docs/getting-started.md index 8f46562f..ed56d75e 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -34,13 +34,13 @@ Here, *structlog* takes advantage of its default settings: - Output is sent to **[standard out](https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29)** instead doing nothing. - It **imitates** standard library {mod}`logging`'s **log level names** for familiarity. - By default, no level-based filtering is done, but it comes with a very fast filtering machinery in the form of {func}`~structlog.make_filtering_bound_logger()`. + By default, no level-based filtering is done, but it comes with a **very fast [filtering machinery](filtering)**. - Like in `logging`, **positional arguments are [interpolated into the message string using %](https://docs.python.org/3/library/stdtypes.html#old-string-formatting)**. That might look dated, but it's *much* faster than using {any}`str.format` and allows *structlog* to be used as drop-in replacement for {mod}`logging`. If you *know* that the log entry is *always* gonna be logged out, just use [f-strings](https://docs.python.org/3/tutorial/inputoutput.html#formatted-string-literals) which are the fastest. - All keywords are formatted using {class}`structlog.dev.ConsoleRenderer`. That in turn uses {func}`repr` to serialize **any value to a string**. -- It's rendered in **nice {doc}`colors `**. +- It's rendered in nice **{doc}`colors `**. - If you have [*Rich*] or [*better-exceptions*] installed, **exceptions** will be rendered in **colors** and with additional **helpful information**. Please note that even in most complex logging setups the example would still look just like that thanks to {doc}`configuration`. diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index e44f956e..c0ff55c2 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -659,8 +659,8 @@ def filter_by_level( """ if logger.isEnabledFor(_NAME_TO_LEVEL[method_name]): return event_dict - else: - raise DropEvent + + raise DropEvent def add_log_level_number( From 00962f233bdebb8ed97b5ad627d92e77916b6520 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 13:35:37 +0200 Subject: [PATCH 0842/1520] Typos --- docs/index.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/index.md b/docs/index.md index 8e425cd0..7cdc1154 100644 --- a/docs/index.md +++ b/docs/index.md @@ -14,8 +14,8 @@ Release **{sub-ref}`release`** ([What's new?](changelog)) ## Basics -The following chapters give you the all the concepts that you need to use *structlog* productively. -If you're already convinced that you want to play with it, start with our [Getting Started tutorial](getting-started.md)! +The following chapters give you all the concepts that you need to use *structlog* productively. +If you're already convinced that you want to play with it, skip ahead to our [Getting Started tutorial](getting-started.md)! The rest of the chapters builds gently on each other. @@ -33,7 +33,7 @@ contextvars ## In-Development Affordances -*structlog*'s focus are production systems, but it comes with **pretty console logging** and handy in-development helpers for **comfort** and **better results**. +*structlog*'s focus is production systems, but it comes with **pretty console logging** and handy in-development helpers both for your **comfort** and your code's **quality**. ```{toctree} :maxdepth: 2 From 99ef852fd77c8c8cedd6c8521a0bfe45fbc98e53 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 13:44:31 +0200 Subject: [PATCH 0843/1520] Tweak sizes --- docs/_static/custom.css | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/_static/custom.css b/docs/_static/custom.css index 8a44438a..df08842e 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -1,7 +1,6 @@ -article p { +div.article-container>article { font-size: 19px; line-height: 31px; - ; } p.admonition-title { @@ -9,7 +8,7 @@ p.admonition-title { line-height: 20px; } -li>a { +article>li>a { font-size: 19px; line-height: 31px; } From f1685fd83072f3734fa7bfc86bc44f965cb073d4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 14:04:11 +0200 Subject: [PATCH 0844/1520] grammar --- README.md | 2 +- docs/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a7538998..2188366b 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ It has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio*, context variables, or type hints as they emerged. Its design proved influential enough to [help design](https://twitter.com/sirupsen/status/638330548361019392) structured logging [packages across ecosystems](https://github.com/sirupsen/logrus). -Thanks to its highly flexible design, *you* choose whether you want *structlog* to take care of the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's `logging` module. +Thanks to its flexible design, *you* choose whether you want *structlog* to take care of the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's `logging` module. The output format is just as flexible and *structlog* comes with support for JSON, [*logfmt*](https://brandur.org/logfmt), as well as pretty console output out-of-the-box: diff --git a/docs/index.md b/docs/index.md index 7cdc1154..f335c48d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -16,7 +16,7 @@ Release **{sub-ref}`release`** ([What's new?](changelog)) The following chapters give you all the concepts that you need to use *structlog* productively. If you're already convinced that you want to play with it, skip ahead to our [Getting Started tutorial](getting-started.md)! -The rest of the chapters builds gently on each other. +The remaining chapters build gently on each other. ```{toctree} From 1661ca4a9a656dbc06a0a94254ac13b70421a3ef Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 14:46:39 +0200 Subject: [PATCH 0845/1520] Bring back Keith the beaver --- docs/index.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/index.md b/docs/index.md index f335c48d..1109adad 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,5 +1,11 @@ # structlog +

    + + “structlog” + +

    + *Simple. Powerful. Fast. Pick three.* Release **{sub-ref}`release`** ([What's new?](changelog)) From 13ffa4402bb8f7c003a83c3e886569f1c32f9882 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 14:52:18 +0200 Subject: [PATCH 0846/1520] Center both --- docs/index.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/index.md b/docs/index.md index 1109adad..8688f953 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,11 +2,13 @@

    - “structlog” + “structlog”

    -*Simple. Powerful. Fast. Pick three.* +

    + *Simple. Powerful. Fast. Pick three.* +

    Release **{sub-ref}`release`** ([What's new?](changelog)) From 5a21a846074db3bc849c62920caab1379ecaec87 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 14:54:54 +0200 Subject: [PATCH 0847/1520] fix quotes --- docs/index.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/index.md b/docs/index.md index 8688f953..9b6f657b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,13 +1,13 @@ # structlog -

    - - “structlog” +

    + + structlog

    -

    - *Simple. Powerful. Fast. Pick three.* +

    +*Simple. Powerful. Fast. Pick three.*

    Release **{sub-ref}`release`** ([What's new?](changelog)) From 23fcd508b20f43e5b17f0b3e4bf8b51df6144be2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 15:38:30 +0200 Subject: [PATCH 0848/1520] fix nesting --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 9b6f657b..22d4bad5 100644 --- a/docs/index.md +++ b/docs/index.md @@ -7,7 +7,7 @@

    -*Simple. Powerful. Fast. Pick three.* + Simple. Powerful. Fast. Pick three.

    Release **{sub-ref}`release`** ([What's new?](changelog)) From 269e67003a6f329348dcc74a31f9ee478dec5d6a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 15:51:47 +0200 Subject: [PATCH 0849/1520] itemize --- README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2188366b..7136c0ee 100644 --- a/README.md +++ b/README.md @@ -28,9 +28,17 @@ -*structlog* makes logging in Python **less painful**, **more powerful**, and **much faster**, by adding **structure** to your log entries and moving control to simple **functions**. +*structlog* is *the* production-ready logging solution for Python. +It's: -It has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio*, context variables, or type hints as they emerged. Its design proved influential enough to [help design](https://twitter.com/sirupsen/status/638330548361019392) structured logging [packages across ecosystems](https://github.com/sirupsen/logrus). +- **Simple**: At its core, everything is about **functions** that take and return **dictionaries** – all hidden behind familiar APIs. +- **Powerful**: Functions and dictionaries aren’t just simple, they’re also powerful. + *structlog* leaves *you* in control. +- **Fast**: *structlog* is not hamstrung by designs of yore. + It’s flexibility comes not at the price of performance. + +*structlog* has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio*, context variables, or type hints as they emerged. +Its paradigms proved influential enough to [help design](https://twitter.com/sirupsen/status/638330548361019392) structured logging [packages across ecosystems](https://github.com/sirupsen/logrus). Thanks to its flexible design, *you* choose whether you want *structlog* to take care of the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's `logging` module. From cc914c6709069bb194eb84875e64de46417329a4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 15:52:46 +0200 Subject: [PATCH 0850/1520] fix grammar --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7136c0ee..8deaa9ea 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ It's: - **Powerful**: Functions and dictionaries aren’t just simple, they’re also powerful. *structlog* leaves *you* in control. - **Fast**: *structlog* is not hamstrung by designs of yore. - It’s flexibility comes not at the price of performance. + Its flexibility comes not at the price of performance. *structlog* has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio*, context variables, or type hints as they emerged. Its paradigms proved influential enough to [help design](https://twitter.com/sirupsen/status/638330548361019392) structured logging [packages across ecosystems](https://github.com/sirupsen/logrus). From 0885cb4389f05da639c2b4b196f4221a7475c8d6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 16:02:20 +0200 Subject: [PATCH 0851/1520] stress --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8deaa9ea..3e093649 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ *structlog* is *the* production-ready logging solution for Python. It's: -- **Simple**: At its core, everything is about **functions** that take and return **dictionaries** – all hidden behind familiar APIs. +- **Simple**: At its core, everything is about **functions** that take and return **dictionaries** – all hidden behind **familiar APIs**. - **Powerful**: Functions and dictionaries aren’t just simple, they’re also powerful. *structlog* leaves *you* in control. - **Fast**: *structlog* is not hamstrung by designs of yore. From 8cae8a431bd380a81fa2d3498d7b4784fb9e0b99 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 16:07:03 +0200 Subject: [PATCH 0852/1520] Cross-reference --- docs/why.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/why.md b/docs/why.md index f671d24d..971e6de0 100644 --- a/docs/why.md +++ b/docs/why.md @@ -14,6 +14,10 @@ Structured logging means that you don't write hard-to-parse and hard-to-keep-consistent prose in your log entries. Instead, you log *events* that happen in a *context* of key-value pairs. +:::{tip} +More general advice about production-grade logging can be found in the later chapter on {doc}`logging-best-practices`. +::: + ## … structlog? From 9d451ac631c32840cb353de711233314bbe6370b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 16:10:10 +0200 Subject: [PATCH 0853/1520] Fix whitespace --- README.md | 2 +- docs/index.md | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3e093649..8b293295 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ It's: - **Simple**: At its core, everything is about **functions** that take and return **dictionaries** – all hidden behind **familiar APIs**. - **Powerful**: Functions and dictionaries aren’t just simple, they’re also powerful. - *structlog* leaves *you* in control. + *structlog* leaves *you* in control. - **Fast**: *structlog* is not hamstrung by designs of yore. Its flexibility comes not at the price of performance. diff --git a/docs/index.md b/docs/index.md index 22d4bad5..c696bf0e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -8,10 +8,12 @@

    Simple. Powerful. Fast. Pick three. -

    +

    Release **{sub-ref}`release`** ([What's new?](changelog)) +--- + ```{eval-rst} .. include:: ../README.md :parser: myst_parser.sphinx_ From 69357bceeae5e73c1fcd61abd1a838987995fc96 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 16:11:58 +0200 Subject: [PATCH 0854/1520] Shuffle --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8b293295..cc56d6a1 100644 --- a/README.md +++ b/README.md @@ -37,15 +37,16 @@ It's: - **Fast**: *structlog* is not hamstrung by designs of yore. Its flexibility comes not at the price of performance. -*structlog* has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio*, context variables, or type hints as they emerged. -Its paradigms proved influential enough to [help design](https://twitter.com/sirupsen/status/638330548361019392) structured logging [packages across ecosystems](https://github.com/sirupsen/logrus). - Thanks to its flexible design, *you* choose whether you want *structlog* to take care of the **output** of your log entries or whether you prefer to **forward** them to an existing logging system like the standard library's `logging` module. The output format is just as flexible and *structlog* comes with support for JSON, [*logfmt*](https://brandur.org/logfmt), as well as pretty console output out-of-the-box: ![image](https://github.com/hynek/structlog/blob/main/docs/_static/console_renderer.png?raw=true) +*structlog* has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio*, context variables, or type hints as they emerged. +Its paradigms proved influential enough to [help design](https://twitter.com/sirupsen/status/638330548361019392) structured logging [packages across ecosystems](https://github.com/sirupsen/logrus). + + A short explanation on *why* structured logging is good for you, and why *structlog* is the right tool for the job can be found in the [Why chapter](https://www.structlog.org/en/stable/why.html) of our documentation. From 9487a42480a454d5dae4f827c4f2f84392fdb123 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 16:30:49 +0200 Subject: [PATCH 0855/1520] Less screaming --- docs/getting-started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index ed56d75e..61565149 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -35,7 +35,7 @@ Here, *structlog* takes advantage of its default settings: - Output is sent to **[standard out](https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29)** instead doing nothing. - It **imitates** standard library {mod}`logging`'s **log level names** for familiarity. By default, no level-based filtering is done, but it comes with a **very fast [filtering machinery](filtering)**. -- Like in `logging`, **positional arguments are [interpolated into the message string using %](https://docs.python.org/3/library/stdtypes.html#old-string-formatting)**. +- Like in `logging`, positional arguments are [**interpolated into the message string using %**](https://docs.python.org/3/library/stdtypes.html#old-string-formatting). That might look dated, but it's *much* faster than using {any}`str.format` and allows *structlog* to be used as drop-in replacement for {mod}`logging`. If you *know* that the log entry is *always* gonna be logged out, just use [f-strings](https://docs.python.org/3/tutorial/inputoutput.html#formatted-string-literals) which are the fastest. - All keywords are formatted using {class}`structlog.dev.ConsoleRenderer`. From 73cb18cae95c0beec461dd9a491202d92e8eb9c7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 16:52:07 +0200 Subject: [PATCH 0856/1520] Simplify --- docs/getting-started.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 61565149..72e387f2 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -174,7 +174,7 @@ See {doc}`contextvars` for more information and a more complete example. Now that your log events are dictionaries, it's also much easier to manipulate them than if they were plain strings. To facilitate that, *structlog* has the concept of {doc}`processor chains `. -A processor is a callable like a function that receives the event dictionary along with two other arguments and returns a new event dictionary that may or may not differ from the one it got passed. +A processor is a function that receives the event dictionary along with two other arguments and returns a new event dictionary that may or may not differ from the one it got passed. The next processor in the chain receives that returned dictionary instead of the original one. Let's assume you wanted to add a timestamp to every event dict. @@ -200,6 +200,7 @@ Now you have to tell *structlog* about your processor by {doc}`configuring Date: Sat, 15 Oct 2022 16:54:23 +0200 Subject: [PATCH 0857/1520] Separate --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index cc56d6a1..2f6035bf 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,8 @@ Its paradigms proved influential enough to [help design](https://twitter.com/sir +--- + A short explanation on *why* structured logging is good for you, and why *structlog* is the right tool for the job can be found in the [Why chapter](https://www.structlog.org/en/stable/why.html) of our documentation. Once you feel inspired to try it out, check out our friendly [Getting Started tutorial](https://www.structlog.org/en/stable/getting-started.html). From 9cca82fc75aee0a80f9bc5a4b8f2f48166d600a3 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 17:31:49 +0200 Subject: [PATCH 0858/1520] Fix admonition size --- docs/_static/custom.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/_static/custom.css b/docs/_static/custom.css index df08842e..8baee250 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -3,6 +3,11 @@ div.article-container>article { line-height: 31px; } +div.admonition>p { + font-size: 19px; + line-height: 31px; +} + p.admonition-title { font-size: 15px; line-height: 20px; From 7a60163a31e0294d10006bcf2e6aa7854ab8ab5d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 17:32:37 +0200 Subject: [PATCH 0859/1520] Fix admonition titles --- docs/_static/custom.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/_static/custom.css b/docs/_static/custom.css index 8baee250..0f574466 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -9,8 +9,8 @@ div.admonition>p { } p.admonition-title { - font-size: 15px; - line-height: 20px; + font-size: 15px !important; + line-height: 20px !important; } article>li>a { From 4e1f2e1cc0ab83ad2ba8f09cb0a8f00e364005c7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 17:34:23 +0200 Subject: [PATCH 0860/1520] Not just ps --- docs/_static/custom.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_static/custom.css b/docs/_static/custom.css index 0f574466..60c3f275 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -3,7 +3,7 @@ div.article-container>article { line-height: 31px; } -div.admonition>p { +div.admonition { font-size: 19px; line-height: 31px; } From 59187e9babe640bfb1c7fee2209588e002a78f13 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 17:35:48 +0200 Subject: [PATCH 0861/1520] Remove stray word --- docs/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index d40e55ff..272ffcbb 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -76,7 +76,7 @@ In the simplest case, it's a function that returns a logger -- or just a class. But you can also pass in an instance of a class with a `__call__` method for more complicated setups. These will be passed to the logger factories. -For example, if you use run `structlog.get_logger("a name")` and configure *structlog* to use the standard library {class}`~structlog.stdlib.LoggerFactory`,which has support for positional parameters, the returned logger will have the name `"a name"`. +For example, if you use `structlog.get_logger("a name")` and configure *structlog* to use the standard library {class}`~structlog.stdlib.LoggerFactory`, which has support for positional parameters, the returned logger will have the name `"a name"`. For the common cases of standard library logging and Twisted logging, *structlog* comes with two factories built right in: From 33ccdf2e633976a57a06dceabb88383fb92c86cb Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 17:50:00 +0200 Subject: [PATCH 0862/1520] Two beavers look silly on desktop --- docs/index.md | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/docs/index.md b/docs/index.md index c696bf0e..8a799739 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,14 +1,6 @@ # structlog -

    - - structlog - -

    - -

    - Simple. Powerful. Fast. Pick three. -

    +*Simple. Powerful. Fast. Pick three.* Release **{sub-ref}`release`** ([What's new?](changelog)) From b2b8a6255acf487ced1f4ccc8cb22b2aa65781dd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 18:06:35 +0200 Subject: [PATCH 0863/1520] Move bw policy to supported versions --- .github/SECURITY.md | 17 +++++++++++++++++ CHANGELOG.md | 7 +------ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/.github/SECURITY.md b/.github/SECURITY.md index 33747b92..6a34429d 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -1,3 +1,20 @@ +# Security Policy + +## Supported Versions + +We are following [*CalVer*](https://calver.org) with generous backwards-compatibility guarantees. +Therefore we only support the latest version. + +That said, you shouldn't be afraid to upgrade *structlog* if you're using its documented public APIs and pay attention to `DeprecationWarning`s. +Whenever there is a need to break compatibility, it is announced [in the changelog](https://github.com/hynek/structlog/blob/main/CHANGELOG.md) and raises a `DeprecationWarning` for a year (if possible) before it's finally really broken. + +You **can't** rely on the default settings and the `structlog.dev` module, though. +They may be adjusted in the future to provide a better experience when starting to use *structlog*. +So please make sure to **always** properly configure your applications. + + +## Reporting a Vulnerability + To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. diff --git a/CHANGELOG.md b/CHANGELOG.md index af37a420..4309fac3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,12 +8,7 @@ The **first number** of the version is the year. The **second number** is incremented with each release, starting at 1 for each year. The **third number** is for emergencies when we need to start branches for older releases. -You shouldn't ever be afraid to upgrade *structlog* if you're using its public APIs and pay attention to `DeprecationWarning`s. -Whenever there is a need to break compatibility, it is announced here in the changelog and raises a `DeprecationWarning` for a year (if possible) before it's finally really broken. - -You cannot rely on the default settings and the `structlog.dev` module. -They may be adjusted in the future to provide a better experience when starting to use *structlog*. -So please make sure to **always** properly configure your applications. +You can find out backwards-compatibility policy [here](https://github.com/hynek/structlog/blob/main/.github/SECURITY.md). From b988def8db2938f7b8b00ea310d453c2636886f2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 18:11:31 +0200 Subject: [PATCH 0864/1520] Imply --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 2f6035bf..cc531100 100644 --- a/README.md +++ b/README.md @@ -28,8 +28,7 @@ -*structlog* is *the* production-ready logging solution for Python. -It's: +*structlog* is *the* production-ready logging solution for Python: - **Simple**: At its core, everything is about **functions** that take and return **dictionaries** – all hidden behind **familiar APIs**. - **Powerful**: Functions and dictionaries aren’t just simple, they’re also powerful. From 5561bfb9f3f4da57ccce176309c584d33ced7036 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 18:15:00 +0200 Subject: [PATCH 0865/1520] New screeenshot --- docs/_static/console_renderer.png | Bin 157406 -> 520725 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/_static/console_renderer.png b/docs/_static/console_renderer.png index 9e8095d080f02f8bc3baac018216a5003525adb0..6127770bfd4a6d5a58c583683a3624162f1d6824 100644 GIT binary patch literal 520725 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
    N|8I;#g zp4hNy{j?lY&-x%r#@38v-GOOzYL5&N+=S@v*KrTl14|1K5(zRIhY%PaU41rbmA~?D zwtN))v{zp;)PUQkh395C4nKFT++W)6w`hud*;6Rk^rv8|kmSnYidt^J& z?-+uwgsa+@V1JP0Y%@R0R38#=rlEnRDOkao^6&&~Q42NfB0;?@|8nsE~_o9K?gfF5WV&GlxxHb@fjIac@X;%|15ShY^1Fw`K`s&z+*v%N+D+Ycxj; z9tPM|g&Xn(RDN&0*i6}ZYx9}8P0+ya942?lE|!N6-S{H+Zi(yh*yl*YWK#vUJ!U`X zsA)RM((m^BUu3UE@m9osFc3!t=oMfi(vE^!3U)XWY%-od{QwMZm@9~V?-3I6rdHNn zgf|HUO8+`L0-{m-;|IhDvEv@t6S%c)`bo~OUVJVyD6jSm5lP!Ay1s;rA?zaaNMoCx z_d6QkS^*&MK@OeGtA)#8sNNzi|A<9QseaQLwhh>sTQ^1?ouw01kS>gzZZT&5x`Ugl z(4I$Rbr+F6T0CD|guYajXszMr=Pl9_KzPeI>|oXCrg`TczWi~Xa1+lx%7c4)KOzKT zO$2c}@9wr27Vz9FmDX9YFnuFbYkc#${+wg6s&@X;d5hHaQVsVcbu{Fkage{xz-U?2 zyPG+q^YX(D_Xr3Y-tewk7i9<85$hBw(@h$cwwLa3N9-HhCI0$zqv^sxM~x}sD<16! zM{C=vs}gHFKMT(mbW2~tuq}##>jOXR&p}w2G!uST$bm3GImSCxUwn4(*K?atuLOM7 zH_7vEP>{>Q>4a^2{^NkvZBxzb>H?nLqvC*YvfN(7ZhJ=4(V9QRV{SlwzIy*;P&N(& z98QXa{f&=>o7{J--_C$oMc9toLVgq%?wE_b*~+K#`qMp+#Gb*yJGyirBf7DNHOR_M-ei>LW%df(3& zkL4=|lTLN8XI8GVlx9OD$NJ`!xuxxE?JEC8!mPbjX?{b7L z;1cyuya4-EWtGX5SNpx*AL!(IMkT>datf5Lm~=e5TK$2>j~TbiC^E#;5+%k{7Gq9y zU+*YsJaz|WcDqbCQlY(BF$Jo^BJxk&%fIYaqcJa`DYRrySk`XQ8im>cS|ru(-Zv3A zeIKso@so9nVf+CtpA;JOUq>k;O72137`{mL%X9Fyr`l<#sU^uE3A9Q&H0TwRM>dFH z>d0u&m`Fq5yE{F8yA5m0z%b$@Cr|WMW<@JF&_WwlS5|rmH1)o3HfCkD&npdz6F}x1 zKVvPzx4$tGSY3$&LG}P*g6l{87b)JD?ZefPPZERR>`Y| ze{#^vxk(otGs5U;F5n{1tOV2ZjSPWc(>*B!uAMOI=mpR?Jr7S8`N!t(Uv3|9>^0H! zpd7gw&g)~ZBQr-VS=4fg($4Ppo12?M8lTO;@BIlmb>L0aIb;^egXyUWA@`35;;B1L zyj4_woiFLTgK5X1VX|36$i&eL_yY4P#uD(yhy{EM9Rt6gE5al15c5qQWfqDcC>fr^ z;r>ccEdNI?U|^S)W_m87Cj-%o&;F;|rN=Km2laqq`jTweqxVC6xtbzvOMEGuADB|} z5mXx3XN-AJA`1`~>Ml8rEz;hcz0K`ex29x-!L7;mysYn!3b**H*Xp#E2Gv%jcaEI*urlJI$XuO7&MV zY7xg)OET2ik-|~r0-IDtk7!f}&*l-vuX) zh*z!o(AhFLhIMH6bTL!WKS&!Q?K)X5JqSR0uM8is{yfi+Ok}9Wu)mIhV|p zsLEcG1Pns!BH$nn>OMcomYQf$TT6kX=0p6=KufCk#b;=rsW-DiFgQ+X8bfl)-0EiP z96Tme9B`55yzk#rX+r2F&yKA~#;U6`Lfz6{AWm5=#yz~ZCZB6UG&F)hzo`Spn|Vzb zH$#rMpo4KHwaAB%WR_wK>KG~}?tq|XNr$;j0sGr`_Q`cWNhSL6fY#(#9@ZQQ!HE8E z_x`VSEqwz8&27|(j%($f+gI1T@70mC#ME3I&F(>IX{3EpdU!?G6)o()KGVN1L+FMvCoPn_9OS+t_ZLkU(mS% z6<;D~mAp4MFIEF?lb1_SWc1&X=Uz=RS%%q^VZp>+ym&Di2voZmFOfht;$)_*CRv2D zx^*6&p55F$Yd@1r*y9d%3keCX!7P+A0L2$_7F1WOjW-Pr`JGn5s#gb6`xLn5XaF7G zMSjtMpm)9EJ{rJd@lOW7(`BK*J3t76sceqN-h7Srna?p`@{f1Ewxd~W9j@4HC`4#R z#aVU)<5Kf~JvurPuo|HmA0PJ&En=aDRd^B0w4=5yl~$BZpa*|t%K;JO-lJ#mJ!ZKC z#)F(ZoemW#w|9h0tRE{`8$C))qIOnAaFdn07((xJmFmiil9gBl+08WXq?(<-c@QCR z%SHZ+7(R>Za5kn?a+8HppzryX*Il%wF7K!kVS{pql7&V$7fp9xiY@?gatH^{Gzq{EJN4@kefOl>sW{kdR2l?^>Z0aVP(qdq)UzATQf+(5Vq`ybA zs5xXSB&{AxiCiuZQ3E1KxFF6*9)=8N;xJMy!D*XRlmvOnB9U5(auoptM^o{|a7@*t z@ATjBc>p*2D?8`$6GCi3M(VX3^S#jPQ2m=X;E{!f+NX&~@Pf3XL7JJSNXWF)Eso)!xatRZdqV0=?_u!d*NMPT*WSJ&eJj5hab!0pjj1S{c|c6B6~$8NY?fX0 z)1UnZ zYmYsVhY|zRU6t!mKYjK~9DL;>c{lTgV}jc*BKsWtj#6ti)1^rsaM`CNb;MXUchiiv zIt~K!iy?U0-k^_*ZlG(fvRqUM0fR=8#D~ztcrO8a`6L#~LeAKaj#PR@aRKoVD6HBl z&L$rjul!Y&$N4LPly*mFxBsIbnO7UMx!1A_3p?@hcCo`Yipns6Lhho}*`&)oekp3m zV`GYVc(jBNWqlLoia(vs>Y27P_{-VEKOWXm0docvACwXA{nUV z#RWE#-lq^U>2&+T=jedg>5i%{h^)7F9^im__Lk_>^u`e~QmUK=^0fM0ob@30^Uf;6TSDy9Q5~Q_niD(gbu#!9u^sT5t(Z>d)BRBF`u`n zwIuo+$7tSjy1Kw;tZ>k5d#Z1hoIJ3+SrnB}HMqGZ3++zhiScq$c=OEjmXfG6ieJZi zG{O7+G`22pdBvn?24JPp3n8~8tgPAIzT>t3X{p#d6>$#uRf#8eTv$x!O#8l$(aF9Ime?~}ftGnf0)jv$I5@kfMM?7N z>FDUX2x;;)NeM95PxJ%`)?38NMj#8y%(P(hu8?3er-P(VZu!uNU=6G5WxppK>(>98 zuBq>)PBYLQrzB|QJ!u6k)fZp+Oh7E?Q@>6}E&>l+xOhr#*VPmOU=wZ0Q5W$RVxG_1 z7U{GfBqL%y7JM~)GxRlBy35wgYBac~66FUQY`KCTkTcX;3sT?K z@gq=Fi2-x9iuXWW zR9g&rUPIO(%P~@EGEbTWK!*EP^Oi9g^H#~$xcziXlW1>mVTp}fuA8s*3;iNKZTNWx zt9@FV=LR4I&xXzRCmYU)k`QpCif&B~tQ6!unxP^;3IAZ=5E_P~1??u@B2G3-_bxI0 z68zK|uv2rCGC2dRYZiD{rTNcL=|M+;V)C7jKY#_Yu#ffTNrjba2w;PnM`@<*`B-GR zDfQNrc5Rh-!^yWif}M4vCkxdRT(_q>AgvozYnlFUNS(yJm2ezdYDVG`w$bVHHTFCQ zv)XWfqOYZ!P5mxzl!J*J3{>VVu_$p!k1G|6V9ir;)VrTP^Vrp!Q66h}UPL^HEJRPG z`U+L@i0caBWE|CMOS8%h)rs%kO$Aj9`u*`)0aNJtb?hA1+P=NQFtJTba(2n~dq~w+K-Yu4BC^n_ zw>wEX24ue=hSlD-?aDrWlyc_QA032-^%%E8@}cP<!&8K8_M3{|%Tf00QqiKLo4*(SZa)vyFdwgV-G1IaTf z%|2ZntTn*QGZ@+OuNL{5j+A-4HyH2+2ck2W1q4G@DZjjJ2e|i+Zv_xCLpZeb^lZH= zg3TB5*B8Ut1|3g|x+aj5J58PZU`Q+k(2oQpN?T5K5wqs$G6wD?J#B`y%dZ(a>#nN<5#Lde*l~0o!9fHXK0$S-z74T*ZlJo@Vf2c~ud>80zB27jvHdu|rQ12Em@L#c(v zW9G7it+Fev$Xh8g;p&zTtW zC*D9-iP=A}qJ@k}}@tWETl#;sC(7a^n?A|CLw zC1BzD_Je6W#*m?nsfrJvP813$Ob5E#20+1D2_!Oz)(Vv4#Wst{%%o6X2XfnOd0k zlr?L9F6{-Vm=F65FGmeX+mkb7XF$Eyb$I_Uwug@{bs{&g99(yU!Yijzk4#8k(ue= z`gUQe?P@MgQq=mc@{Mp%mxYw3z(A9zazmZt)j)4=rI2-d?yaFSl@Br;57ouAI3SFS zjNuHZ9E}qdNHUBEV{&qGEoFJ63>KjqfgeY+hKVf)TEwInNWBwmXoV>dU+G@T-~381p6iMq|jVO0PAf(}NZ|k-VTI6{p0;Iu(A(oTZ`WIKRt z=C`n+)U)QICC!-R-MDrRIRTP_M5>Ga6plW^>zy`tBIXoX4U0%#PpE6^(*iw3ZeCGk zCF{?o6HqVsU(NU}?BA1q^+uzlav5|tP7%i;bQ;~^4-BWR(s^s5#}v1yyC@d)0jxv~ z2q|^**Hd-ZIz*l@jKPcPf1YiLYS-G9F~x$ipkqR#7?AgnDKklIpF zimvUxFpz4Ywf3TB!oP+IO{b+%TBDTlo!61O4z&A>Y5g0i16BAZ9`f4M3}FL<$TUY$ z4@43vfBkFF^4pOm4(ynyN*F*4wr4zq0ghiY7)I4c4ds-puB_X*P2PnI@=P=bdAAr5 zg2^%8^^evx+s@*pW=XqttuTI}&VRvDf6ofI%Y_p0F;FBQzfNCL?5-sQ1&uAmkAh|t zjhh_L%7G=plrl?lYxAaJ+YOPHtaW7PB(C%@O_}bDu;6+?Cv{fGvy;YLD%Q5Fup73s z^&^~${(y~f5lUmL!=0_zft?lr0G0?z;l1zR1Zl}{*O7pK>e!yHS^)%a^aKUo-#e^? zA7-PmCn$F{-7yz^VZ`!31%B26TD}KPp0t#=1~c&=GeBt}l+B3^@O0}0_8ueKcNI4pGYk&YPz=k{`x|GCNYp}0@K+lmsu64nr7mreb@*YFJe z*HZvqBbteu>ej&h0*TLn1J64YNIty&-2VfPAC_Bo@* zEOKZ$L;;S_+MAe!-N>S-ptx9`nWdlbcc0*OaBScTzyE^>2|DHwC8NXTo>Gxg!!|+d z?7{9BYJEFPQ&4edu>W~j_@dd))GCw$(b6x|2cRK~TwY$Tf0UV=yb+2Y06Ow$4AfWp zGk_0AiJa#nWh~A>o~@Qd@ACIc>3?ISU(x}*Ur+r}O{f9sCJ8O0HEm#4^)6o8Ve|)Ft zLsX4oElQ*f4Zvr)a~r^<4j7>}QzPA#wr3mIayj!+fA10gwWj{MxzVktm7^Y;{iJ{0 zJvEwguOo9H{q;sVbFxB?EjOTLnZP1P7C=}ZfucVKYU`!M;xLS>ONS zq!gWi5HKFa0g`dw{Po-a`_=#3|5^c-4?YQ(_5Z%+7ijr# z`V$Qa@U-y4gcSxTwObk=SKRt)`EQr}w}1B6eU7F=&hxt?O^K2JDvvUjtH2f){JZ^TV4r^nfHQzJV*KaDz>XDQKiBvRl9>isX<(aE zMQ(zb{+A7)Sj)4zC0_Oq*KjR>9l4tf;9ScENAs^w0G$r#PDU%uvKbHd`{gRV>o8=vM@WTAl6m;vXf)zkDh1;}_9~=?hIJ-zCV<#Kp35b0uMQ4i5g2 z{D;!XfQzc{3wA-1 zfw)is@p$kOkOASDeJ9$ae$IQ?jm_%ijH6jaORG*e#8Ju~aff1F`;mON+sCyv&2AD0 zTgQ*Is>?wnL499|a3UeyU1ab=Qf_5@H-R>c5SCkQP8{wj&fSB9#XIgBqXMipgjCf! z4{edRbe|GfQ_((nFktP1P0mk4Krm5r5CoHkue}Xglx@13j}rhU%p1TCrYHoA)Mb!` z2~#?CvxhfaaBt4wQI0TJbf}06$ugxg!~!5&GbssOROe^?nuYxRdm;Q8@Jq+`!#Dm^ z{|x7#^15$729u-H@a*#P;kblN^hU@YQrClY#9()r=by+UarXmfb3F2-2G{{%wXN?R z?(yN%!lIxC*nDdXW4>}1W0TL%`5eN{`bUa6GUy;R`;E0q) zK^YPfQis6pRryAhgyx<=4fyIf=aotLh1lomMn zVQ?-kgR;H0MTK${w+G~?aFk-wj*bvia@k57L~(}rinH?m+a6jV@e;l}4$JI+)PP3H z?bv>amDk8yfBTEmQfCj4IK9)uH>v)|>!6{1DV0t$=M?d5`>B3oH(-wuK}*3r)Hj)r ztC7GHa2O>=)SoPoA)OmQ3T}i)RrT#(uOGVXx9Ty)I8Y%5lBJgl7j|M<8v$@B&zc*U zSFLnYM;*&639R>L2%ZZO03`KG1NvAT-w?Lpwpv3oEOrn$H~ z=VCgT7PmM-y2FllUEdaIuUAK8jvTqB0Y@8F+oYMk3hWi|0>&d7A0)siP5pu7-)`dn zx0n525uqpnh|F}NJEX> z#E@2Iz&hz;W#y>q(+NBnfDgd@7cOrDI7Ns1pKVk9R2<{A6c^5%%6Du(jrv+Y}DDXFQ{Yw29=hy0wv zgWOA*36>SPpAhVP(r=z6nNWfHmHp}UHbk3YN@Oqd9CL}2g|I_}h%iy&$QlA^|LM0^ z0_?8B?Kc4F8chr=8kU#cLBiB`hZhvuM0o3TYL6KhFyj@-QAb0CK~%kbdUKb z!0XQaW1iSA)jR+n8*&S&K4xAX=T%xLoolQzJr(@6DMpPr^%`Sush_gZdr(}QpcJHR zV8C>SP9Q7Sa)hle2x}I$8NvK3?z<%!M8&^Ec$J$n-l3jZ1%)0rzcGZQ~a5 zTRxo2r0Do2gRu22y&8$~qrrb94}#aitJkhyL!-e1>j@u#4}@r>k63Ib89|n3G#DoJ zt#ClT1mo5wu6Qzyqx_*b{o4w^85BvL$eTfS&yMs z%{_Le<8)@k?Huk_&E*5A0@@#sS7V_rYVGaA`>LD`VE76QOMIx!*1EpLCSKc{qiXh` z+dJs%R!w~giSYw;d2u2;r&||54jLJUHuH~<@&{P;_=XuzCSXX*MQGclo4iXeux7-3 zS}zQEGZd=679YW8t_Ju`8}gx$Ch$Td9UGyAPAXiYH<2%tjI0qThu>$qVuQZ)ME)v_ zxphD1qgY2Yr5OJ$HNe8cyZFNQqa=7QG56x^<88Ly2spPDGZ|Wa%NJ77f;eoxbRJNO z$;h_vCATvx7dIn(y(9pGe*P-prMY!D6)J*KA%aq5N(Uz2~CH0u?D|Plh z^e|gg^Y%`uK`^@W>UId>(>VRSq=mOE|&g|5&4034;on zczanZFaK6J=yrn}A)xhL0rRn=VAtvrED}!fxp~kKzb`e>xX)trQYr_(Z?@k(ghOgcSvkfbyLs{`rB^oOO+hHA@Kw%-#Yv+ej#QSAOKl48TI z4dL|EwB2VyZhF_is=Pr%eA<+|`qFmc(tJvhl~u>HS53_}BEK|`3SCAi3zQAW0OkfD zo3>ed|2`cE9YDmmj(Te6t$(hH52&MY+j1?@QK&$1aoDows|1oB);my;7PPWuwt}JzwR69v=h<%dl3R3UYE}<-2J87#6l( zo{wIP>b<5z3AhiWN@n2$%2>a;8RD1Vt6^P>e}uf}?6?80zI*mmv#ywc{SBC3Ydu{4 z)Q5lZFaNH(2FJj|@sI~(1PUmC7aR>1mDad-1RL-JHFW)W2{2{8I1)QuO&3x?C@g9N z@?M>w&u{gt#Q*$z1&YFZA-PHJU@nZsxs#G2_Wb$cX;zg(CbTaSTexK{sm{EO;Dp4s zoIPz6HHE`PDQZoa3&*%eN;qnxzu!DIKAsXltJ0D|PSJD=@9sZCwMO4RR}OoH^~Vt+ z9ExxGXduN*d#G}tM5(qWJ$doS4z{raN?X8#UnTzXtc!H%KUJQ8KKx%-`OpuwauIru z=_A{9j`Nn~Sh*ZvF!J;ckRO6M-Z@e)`d!wczkC1tXQmsqjbi#(Z0h+)3D%-qR> zDK=&Ag=`Y!={Ie|UgSUQV$N5w*Vc{)Wp6VlUk16`tvi+$WUuE|)<5vc3}uvjw1H}X zvOWRG>|Q*$!BG|Y*?PL|Dr+02Ztr!UJ|><4bLBNot*oD)#E$2bv;qpGUm?8^n!lUy ztvTJTnX@kH^Nriq+a{Iu^|F)2Phwa4;Js25JJCBceT%n@r^*#s?e(}u9Cn)Awivg@ zW_h2om3XVgUp#p{#mt~_ubaqlJ03Xdy_l0LTACEXn!vT}^##Tq85?*opyS6&7HArL zsTehMG)VIB0&VUiP7^xl)nb(@19SORSIFnosYOmKBnP?y3wXmu(l- zuQHI9r_5!Q%{d9Zh3XQ(=9myc8qwt%zw_guVbaCU0x`Qi*A(Gvu=z7NJ>ANX2(SR` zlpKM2avB~6uzZ+FNY2&E`d;nR_JG&U`$p$Pv7m-8N7dg&_?fMUAheuLGlOSB4$q^5 zZHc|*&(d50!Jroavpa#>$YBa_qpKC5FVbA;@0TwqEQ|#Vo~b=eFrBI0jh`_CtJon2h)up2ESTKDMb^z$Vb9DumahD5Xsa0LDK#y$C8J5%tv7Ykq$ zeD~NG{p!~?>fta)!Fy|s`}jh3!5n}Hzb41dQOZNwn&OwHg!InO}quq7V3?qg^o`ubOJ(Gr*@ma z0`A2mkA+!H)h^La@s_LHR;#wHZ)h<>venJbz-W$3u*Q!Fk*KDb$oWGpkx|?D;?ZbT zZ6& zlpc3RhLa1xCRTD4QdtxoaVb#(&hV4?y()bWGYhA|CuvM|ppRoMwKWN2S7T%W?nQml z<(-5B=Q|GmRpBIc++k8RB|8OL!~6^B5!E(%oh3WlHu1z9>0q1z=DX(|oKy(^tG%lR zeuoxd4shsy1@|A^L~kn*m1!ZA!dD~3$H|Tirdkql_qE8%a1VhCW&eHtFJB-cSHHulZ9M@JE6zGUPhUUl2+z6 zuy_)TFp2)X&;FYF0@8FZk-|FHXa0e7m0bbHrv{NnFS3dkO1lF(D#m3iyDGd!-_MD8 zYBJc5vb_SZ?*|aVlT9N;v>cs|IZ=#Vjaj2jaDP-k7>iOJ)80 z%YCA&o8T511}aD{i?gpJDZ;e6|Hc3-2ah*+gPF7di-u!-MXt za~1Bh+C`h=)WGPD5bi=(=9)@TS1Se-Lb5li($zZ0`yc^TJ=D{2o%8{O0y5T+wON5$ zibN^~Lv__8C1W{;LH@_9@7PK?COpXf7>6=%EenKJ=#RH*-*y2+v^l|a7ss`E_Wg~# zqJVr<%n4wsPuZR<$G!hvDd}_Saz;CnPtR5O{GLx%9FOtyj%(Z3A zd?0-nD4tt%55JS|IGumuntC1nsgcihZGgejk#cJ-3v^#A1$zNytCQ6CSo+n7P`9C? z996&N)-H%0`fD?d{%mN5Hqk@3cwarZ@?#hO4hjJWbMTIK3$^e9jl87jKRe$$^&j&^h~ayCyZp%}w_G_p*bAQ z$JP2CF}@v+Znq`eFwq?$Y~v!|In8J(>TASl!gnra2he7x7Eb-S;io2E&ivdG+1PM? zI*uS=A0iOY^jQ@LIo6iD;WD|k>U=2I(^Mk$&$rict&NbcU5u~8L%7NZV&}2(JmtFB zUJHdh)6jcG^Feegv}(E;`uKcd532t7BHcOe!$i7idr74O6Rq~)x^t>x{8Q2Nmymmb zcR6cy>1cf|X6+5ni>gxJGHu2*x^8N!Twk$&@&6s8A)^3=VqW8)5w}(Q?_o;`oQrK@ zRAfgVcmN!I5;XJK8(0}L=P!Yn0SmoT;=ObFSxVvdG3e`=7Om(ZJ97rV)A${&4?}V@ zM?5xHC9gbt0%XC#9-X6>B|8f7e+0oAWn)GDkBa`V#KfizirJY`}hl3DPmFlUbM(XHBh(rLIy zh3~okqUfF|55;1GOVleiK^cKI`Wog-?B-3j+(0D*hpdt&Fd1hX64G;-1Ur523B+eT z?-qE;{xpc*unc1>xujdR{Mh>t*UE}yLimx~WuKRQaR0^Qms$khXKD@vmnKZF%!6zg zja=I7|A<3j-MU}bRA4%e@&{+M9p?osT(pD#-Ae!0d3glhbx@y90X0r6UrvWT$lXzc zn~kkhlN>hoM9j+T`a^ye-q3s43Od^u1IQT76J)|I92dPdB1H(s#pkxNE#w%$vL=mV=Decqhwg?Cu+vLLR#*YrLs9tRczXrNqFB)AHF8KstN} z($cv?ROi#%hf|FJ?-8q2D-a(d9FM>HBKvp3!W6g-{%mwHV#CFi)k4QU6FQo=M%meN zP3b;)3C0Q(AhIs8vd7cS&E=orZXJE_(EVPfjQcT^Kv%|FlqSYOZs0rMw3&-|&zI^y}y^w)ngQZPSlP=%1UrFh4C8R1UL`MES)hTb1nk_~l2 zSo@rqVTqn3*3Uj)ppRaMQyh_G9CUVBnNyEgXk#Xar1<1dW(y6l5&>gr7x*+Jd8@du zced2gwB$#$rcOU;piC=|&sk+jKar#gAM$kUFHfL2Ok34_oC-*PV|4{uGe0l-lNvN6 z&K>IVbv3l1c2-xjwH2jv{B_!xIGBl7!E1)Of~v4m;(bZtsRpmn*U#QOjJ3rbx{j2i zU2cTn4QXVTIT*tpZk%ckM$p~w`?K2H9%paIZg0V}*jMjiFPcnHzTM^p`+^aRsA%Yn zgy_*FOnC(qp*&6tt3WII%$?rnMo~^q39_@?8_eU$Aj_DQ6D3j=?%8$1TOlG-BKgWxV>=DpS?GYkX(DB~J%mKdYM1O7HrAtXLkjB3z zBqD-$IwHp~!biWXZyf!)z(N`om4k&)v!I^V>KFg;lX|Lhl^sOyN>XT$Kkeg3e=uu3 zJyv(@mQ%=8k%T&=@#?sH@YFimOdRn}r{8B&-}ScmP`*yU(bi=(zapk=JXM;1Odkns zP7OX(=YQh#W_gd|15y6W{jaS+G{d_UT=8}I`?yIfvH=6eecWG zbXC9Mnk-7k@9m}LotLYBhu8eOOvdk&+~I1x9%lPmR0-c@ZQ!?|kJ{BbiujcD@(NIQ z%P!Z|mlW+vx52!?gzTTbYuV(2py~33)X&~$Q?K&4by8PHC+>Vh3sH*qq|aq`Ozfz< z!fKSw6FY+ck%+5UlM6ARVFLi`Xoc?Y_Z)KCDGh|jh^HzEZ)o5z5Kkctv#{O+;ABH= z*H$56bw$_W%M43x@`Tp0qN9%a-0C->t2B>r#VB*gmIM(ep+IQxyGoCr4GKh~%YgY` zsX@N zzHeZl&2uWoISR@j&&3*~m~Be4CelvZ2~y>4PE$L~&%$7v#;c1-I+Yu2%2TQE_K6Nww#)08daLmMf}M0nZ&wiO zjO)(*-e2;&8CLc+XQqAR1r;rIiK<*fXY3p|8#}4)0^GCmxM|Di1%X#ju8?$i9ad6r zdrr@irS^vVp{`_v17D>!-Rrt5f!uva2;Mf%8lrG&J|Mjw!Y|4Z2>$CR3 zk+bLRWNZM1TK)MEnDM9*0+tP;A?#$F=Jn(UW3?2wZIPA54;#~B?u%Wyz0Yd-_3xtVTWX^Wl_QT%gw7_FXmKs;x@`+9TRWno+Xm*j`?-MFvD>n|@F z7(*=mMOMV8zgkP)qKw}-NljgewAm)1-H^z1JwGiZw=({V|6JqsC2-&209cqPY+apc zEJ)V-Xa73Z1BJViuTQACR@QK(3wTmBLV&oY@G0VDc|Y3c3|+BvQJ}As)3H)HZC94$ z*zkPv;tZqLHleo_-WZcjmADv|$JaQ9XVw;aAA)K;E6nS4AUDu&BCdVd1`x!S23d_f zWmb#yu;bJQ)iw}$uTD{&_VI&y)mcMzr9+}1vr_zH$&*eMF~(E`P!&f@orVfw#yooW z<~Y$P&h_)Tf_5~}C(r!32{#-+6jNDAc@Afg-pPhHU0&4XztD%VOjjW^5~A7e*VL$S z`lU}V<`6o8JhcBVQ`|v*?vw=qs!9i;#8D3W~Uv|Ruga6!}m%6~O=Iq@Vzgsc<`2!6@0wXQIy6W}!lG6T}O-}%RFWFQ? zmVW>Oj{iM|Kahym(hNr?6kOSUBShTwZ=uVC_#!y2Bb%=P5ejiBdA7wD$7?E^lJgCz zi_XbPiU8eAk$1vROd%-&R#qu7$tc7SG{uZk9^19UqM5wH!DMGxh3(9vk0-EBox+w>eX@yW}5^h$oiE!#J6?>X%%;jz_BJ{{plJd4RwLf2Y% z_kN8t@4Z%jy6<5~ZFP^`0qIwq&0S*C!^$Z=DbMUu)gHo8OOI2Yf6%jsQ+;2}RFM$o zSo1s_q|lF~6)BHA(w}L%{qgkvxG0fmg9Yx;)nOJlpsV|Ty)JIVvJemxr*X|*7lGAJs5 z3C=KEo9J@2v#ODg^wOQX{7B$hPiLv2UG^>rqYGqvuj($OkQ?%wpms4iIPe_q=EsJ{ zTwdHX+tw{A{-x3J1+bv~NzG?i=*F`T;!=2%=@&$T9^2)E7rk&01=L^Z*sLu$TTtm@ ztf7&2RE@hwg6Z-uDUjf_L!n?dk+5?TArkL&Fq z*|S!8ER1`Z@~5&)&c&MjUsx{I{j~0KyGYDVbDiYtxw_%gw@;aojTgKTG48o=UESKY z{Wn6Rx(^@m`zD|UP2+i?C9vuGX|41{R!gRQgR^R;DZ2Lr1qh=Ac#M0zD{XIOlHez9 zw>Nr1UAHbcJ6J~sp-=y-=l{>bjQ=i=`yB&m0EKTRD>9AdH2&EwPG!jpmu}VKng(6- z_wRFT&+C8hr=-vim-*{R4jq3cppem031xBt7Debo<1rr)wS%IF1aBm^L&JcNb++xE#;>%~oZsGw zW9ZO*`#W_B*25od0bFZ(ttLMoa3+LHogWQkhE1}Lye5@we=w|bmwS$urO6!^_qLA_ zwmt{F%cc!TO*O`N?Bt5VIl;h0Dn5H9-*7-NRXKfp6SyV3tg^GSr}j$fPe!n_nR}r` z7QZ%DI&i7J#*+e&QPjH0au<%?Qsj4I1DVVFrx^QH_ASR?$C0yy;7FY3@VSQRmk9#B zJ`Eq=L;H3|wfx7Rp7<5{WxKvrN~9v@Gg%5V5#TIfu%mdnAE4;y&JmJ?MVwYzP(uh; zp~-yWud9?uMEWeXf!L=VCO3vG#rb{b8Q#z*pEFKe(1FeWA|v7_aO7Tuh1)YF2Dv@( zt8DVwgq{{u&9QBWcTi)yUV7P!il(9xxE`pxuM(%L5pt~-{TVR!pR(e1D*M0u8ltl* zhSfCFe@1T2T_}!|6clomvon}|f9h9_6%`8pSfBk?xVuh;g@X=8(T;wR(o!3xd;uo7rS>UQpM9iW>4RG{ z`-kRb`TSHySN1O%^=tYg@7%a zt44q4{NNak;7ZyK|h;`00+m;e-{E9S66y8_$(rsn_=< zd}m~3%kJ!4-;D3=gQIkC*4M;LqJQL<3Kf*dOazKUtUkd->5&hg(;iekL?A=-DH#7p ztn;tJZz)CGVu7y&_oLDnQf^?ZaFM|J?=1OXa3q5RNZn&`K|e+Ox?ZDq4TLiS*WhFX z?0zCsu#cNi6ZM#ow`vt}-Of^laC1Y_yzYo7KGZ?C2Ha{Ls~Zj|pSH!ri;9lH#}Fdt zA7<~`q2?~e&dg^$$4brKNxB|xtsni!q;oYP0C2my&mvO+VXU!&f|Pwi{vy|J9EV&c z(z$9DifvKKO+OIGj}%wz74#PYL)iM`1f2I0RNH;%IanRrx3BF&mRRdv(LI8BFL}2i@G1dCt$zKPW(6S|9uYkVBH? zfkr-W1}iWFycdTI@*sN9HzzH#=|TPk#C#6HSr@f)HPz}pzyUmKV2N;Jx&9wTv{HcX zq*L_S?vp;gj11NouW}F_!SsrejXqyh$P~xmWK{oxU!Au89QP3zK>0|q1~|>^YU0D$ zatYcWy*69U)x(|QM|gK0Eh zeRgispRsU_hueRib)Qa?kL<>Mqrp|Qm;c^pHD2g6EgIm}iU0ZKXAzjm2c-lB93`2f z2Is8lKUAs8>c<@OpS5DYe>qzyX^(!T6naK;XI3$?>@b?M1WuJXPLt&hSADEFA8m-K zvg0JuV6sf|s(&JFnX2pu^l~4j*e=eh3TEBxgv2+zk2F%@86Ro0RNHk7tDr|#k3eU< zIzlV|i{S(9H%`AsZ_v5w3%wC3HSeW~!B8G$AAroQ3$QZZd2*aq7 z8uU1dm_pB>>e5NC93{kVr`0TX+gBCp>}l=%FVh8_VyVfwH6&a6)6h5|)>M*7-EON^{s}=YDZ5mx^(z0ZM#&uQdi} zkKa=;q5<-9tn*-=Ujr1==4}XkO{W1538);`up72Gg;YpO$rU9LZ1xpn^3-tV-&HidPU`a*4L;= zD(JLgZGSGQ6mqlC}<)1BS##yoQ*# z$QuC(oa7IHGnwWmJ!-=iH9PUB^dBa}PIIsWEopPFdo@lBqTcWT8#?>xNBM-7F4qWr zZmM3lFnIe**=VSaJ zOA{si>@-F%(*b5Wr-nMg@aZ;C>`;;lcjY^VzcP<|7oJywE`NWqbcU4dy1V-L%=@0N zH-4;1jHRvydFx;8X`P(9pN*)ID)<7XZSuSXIHjdC7dgg~3{E(m#oTwfda8&M9wn=> zMY#m4)0i5vjkyG*F;n`6oJK@#f>ffnc&F%^TOIu48n zB|3GnCdp^N#roo+vr0?fU~AW>bs=0`L#l`)j~jy>1RE7PzDN<^PG#e$Z0c&?Xk>}- z_ji5X&_*Ly40G{I!peVo{GS47*dvf2%8{?*UZ-kznX7wod%Hn2tWIz}p{qaHwwK|E z-inW}p=m2p`E;W8#+Xb4Dc_SB6aX|C+NZo0+)(>{Xt<4meplg-_*WqJ1M8G~cJhO2+pPn}8N)rk`j@V$ z%H7d%`^SrruC+mf=6MFmUaX>*XN5Y!RhoL?rpTb_AaQR(9iE^$EPXFOze6lgX38)( z=2d`CiLIW^!lL?wdsI|OazaTDQp|UA7y&?hKCAaMzE+sL@KcQark7wt=o&y$pqFaU zDtztQ_*BK2%-JxS^WpTIWQ{SUc_Si9gkQ`P>a2J3{#5@b+FaXNYqQ%s)6)Yor`5zxr>j8qS_O_&3gJ9 z%!%K>(@x}%yO)`}e%$fmf2S_sOSFI1(2@Q8KhH(@-NSEb7vTs9%ZZ@FRnIpKsIM2} zW3}4@lfHFRK#-dNCi%LfWN~rGvL&w#JN)jiW*9O&Cw|owWZnawlF{hs=y$huR;}bc zD9xka%nrM67ip%LanRU0BkwL>J-&OPzct_Bf$u>A0dI&4X#R}S$UsiTsErPBb92*- zW`zb`aXg261UccDI=~X>+!8%)pahSb8?(c;s8C-c*)wWu9kmPu{hzL!(B2ZqGFr`{ znIAHJuPO@}mBU5YwZ=RLL5t*Dwl;(;artSl4a6;6#Ew*&iD}0p#kWxn4A#;5fZcLA zOY$OzvoT18%jmIN5=m;nyorf`M=8YRiX)+5Z( zmqW1z+9dcj#|w`lqpw{rdPLTLpw_aj@vHRrt@|`@yn%X|1E%E%&Oa|s1>``rGwH(P z$IR!~>;?O}<_pC$Kgf!22sIC+!mWNPr-m_Gc~2BKpManGa*PnQZt5dtRvPe*tjgc` z0)&K@l2CUXW-Sc}$yxgFdcG3chhdA1hl63uQdZ{Xq{{%Q zuz76|Qf(2FvZ7~0b<5<}8{ts6A}J z$K2s826dI@R*wZ8$?yeI9t0|DF@0vR_U4eiuMf** zyacT&a*3-GIR%oTpwJMdT4h(O40Ajhnl92NHgEkOPp&m;!!OX***XYax@zaw-4;dr zrrh3QE-MwOJYTrO+&0H5`38XF8@kwIFB8c7*r|7zl^-NRQ9;+tP9|MU&{eVIT)v*C z>kT?inaZ|`5=7$=q^~>kZwhGHWZS8V*msf}U8rUsoMplm4pLzK(lHAdbJ6;OV2H_A zXuEv4iP|FZJ8oQtWMFH5CH>WLd-EAkiRh2TIbo(}w@p@3&Y57*mu-TLl zRw~Y(Lf*-%#DUlAW9zns3QZmYyl{O&4?GR&;9q z(`&0~PqXIU#OQz0^ z-z*o6N+!|nRi6mN`*f4E@0`|bG*{!yLB>t#-)xg!g;JirK5I2}VfjS3gnVl*tx*Kw zqC3?i9iS;r53-h6wzB6Rq?U299AkA0z`azwOqqpfXl^K!NclBg5}mQ3Z!QV##F6a!vRvV;F(R&_J{O*2)>iAUBaj#0y{q*@lw%YB~Jg+Uh($XscYU3Q(8%w1MBDr zz;`rNW%HU2`RUUNe|B8Fk&#=ZSH)RjXalZ%YpGy`n5K1ueNzNHt4$m0lGUbFd*c1C z&$yR4{EKdtgjZNk`}(jDr@tpDj}zdORJE{2C$5wLb-id$GNRFw|LINi(<=M9hd-6e zK3~XD$+XC6US(4qh!_7 zi9mM~hi1g(CL#cg4rI!b^F^O`BhFs|QLj_(456PBp4B|my{0|WpdAmr)oDnUuaewI zyJNZgCx_N^`e%lJCIm7-P3vWLejYDb5AUxFMF4|>i;>f{^tby!K7-W32+WB zQV*5Y`;6FVv-!M_cO8CRySap76a&_942FZl;F*l$=j+!z8FlpW@%iHSWcl3K9WZNh z8W$9x7cD{5ym@`U{Gbrs_8#434mny^b>ZIN%Agy84~9b2j)bp?4E-p%@ z%E0F`Y82DpG?aG*%m#)V)#!AyffQI=^JMvZxy<~6kEf@#Jnti<;FVvkJf|zPpi6d_W2$0YIci8Qq*Eesu&tJ6;E_4^_}CW3|FNr~`Z-j3Js1;mj*9O+L)HtQ z!RG1l4Ke}q#&)WYs_SJ^K6 z@ZBG<$N0XHB_6=$t$Or7IC1e^bW^k+_JXr+`c^S(<>Ex418X#IR&gJY>oxtpNk8-E z0ff7CODLn<*6xmxDCjw~tc)sOUFB*uuz9aZ(_2*}gW(N=k@p%|XhHSngEaA0lgSm6 zVrvyBatkR5#hY#V6O7K!RH2U}=&&pb-L81V<7#DkPomzJr6+T6jvR1+1c;{hm$y}> z49d)3O;p-yb@uh&c(tnq^J?0OT0GxPsMW4{B_H~Y);7_}l&-ba0FgV&oozC$5#eek-<;>{T^ z*k3BnZ&hHj@TP|;Y4AI&U*r5QSL{jHN|&S3j4n1#RJ*K=@@OYiM{#%$Iz_>IJaP{O zg3?`(w`6ur=><`}51Q22zy3-j(je2*x6a+74AS!Fz~l921uk9+#rZeKXPWcqrlY?{ zy~UUs{pyAvN5`~}Bvm0aZTYdSjnMK@B+yPrcUe(zdpiy*3091z=iBCK74_jQ>jT$4 zKao;CZL>X)s%k@D6m#9fNu;e!EhZ6jWY0v4Vo1xcOk-sa7|wEU{6u)yRt!*H zTE}3xXvT0jdK+N5t*nOBx^IA2fwLidyKa^@d5f8@PH6A9KZIvy!ne_7 z&Z|56ZHcB~p36rdBBp6Bf8VS()tWEFuKBbge-+tD3g*as7B&@#ORWt7amV9>$^m-p zGTiSu%Cn!mz?OtmtTE{_aIXTUK zA|*bs6j^;_1^XE_XSDmf$&yD2Opc(^M|nk?t^G&ExNQyHCJuHQbZ&VaRxCjZ{m+jc%mZp_bCS4dWQfPMPr;-;;t=(9J5=CChhnS)3_3bB z(FpM*^&##{YtgWhcqCVV1J~Myj zW2}-X;$lcEJ|q%@-R26U61Na;wq6THJTwRLnfYle)rq*2HU@#8kkOx*fSFv%0S)58r zlLU!!wEU$@&0=dQ7fqh4N}M%~!4<3y^ZtRZEY?FgSz)B@^vQj(CD!9fOFq`F@_+fB z4(}^Akov4?#FdT_29Vg|`(Jw}>b6C)tlZL%>~9O5eJ$ZEu^9UTE)Hdi`Q1w| z^K?EH3>*Au1V2|YmFc7fC<;lY$$k;^WKr?Ka<{LV_8r5cT;Kj56`BJBJWo2MV*1Rh zpcwR0)%ccua>3DSg%g0@k9eDM=ue*nvW++KxnL;qUoV><41bE!%uUMv#h{SA2OU;fMnRMgeNufU=dOf6L=VZayEoe`H9N?R2z$fw!GS?MSqg z5`K&Po9)^CBK>J^)$Iya*L{sd8*GzFzc?jJ?O;U_Ul~g;Wu9GLl?OvO}>tzY&n>nJK;*< zGP1KJh9n6IXjM6!MXEI35wPjFQFCW3WV6h|0{B{d@BM^)&kO5H`+M_> zBv=Wg=;4L>?>KL?d+&ad^LOrxi=PyMx~<2(JGj1M@~i)SR;c|txA~%#ZP290ei=@y zqH%9G`{d6dzoXvibCncMKaD(1rpTn>-#j2P>o!<=2=iqz3p$bj?mOmODXRB)3>A$0 zT@Af?6JG29QbWP<>SXM?D`v-~t;WMRxGBHSe=%g!@%AC0D@N6@yeO&Nj%wX{>i>+N zcXJSNF^$N0(o;F6a-Mi~b&0&{wt;~v=o7Oju2?<`G!hAH#j6 zkvRnpcxDu}(W^P4VdOj^d)ppZ^V|`LpXp_P73m(eKOXKKYubS8hWjP>qn5FGaMtNa z?7w*($Se&~E_B`(R8?e9;kR^d1J_aAox6}SZvASWmbVG9@}_{JXAHE;HS%+g5mNPx zdWrSqMPb&Lwm=T4@WJGNTd$6&5eRB%0?M^wwW z!3r3`k2l_BR+EQ)<}|D_r_2gJl2!T&|lQo zb5#^c-MAlBv_v&}cwsy3#uWESfI0H%dt?F22K<2-6(6dr()?N5`H0Fq!5k*bg^ZX=X04C(s?n`q$gekn84^1k+tnUVwYu#-v4fSR1MTTZ zw_Ic5ZMv6&8Z3!lN9w1As4p`U`UnMQih0Bi2SSWTb2HyL?e{H-=h^RjRx)_@)6kii z$Ehi^!u*#(G&Q+WICUW@!EE2)>d4IAhrF2m-Pw{~(z&_Uv^!yH{hU~PvXm(-Rf0fZ zJ6UmuhH~z7>{HXTn`V+mNbdup?VYM0ghW(!FF$I!XML<(*t=SS6p-MuggFTjnS$>|*J4}21~^^dY%oc$ExNYHFc39aWlbnYH^eKCX0Ol&WYR>N=uPhM0G4o4 zeHABBBt%7dv;o9B5r3v9g#+)6+`&+ky>3Tln|x3vUcpYU>OE;|L5=N+dRs&vi(fW_ zXPq13A%&;+s`sKGuTW|Aj#*9fH2K zB+0o?IOlS))o-joFUEW9SU$IYO3NEn7{;eggsjVx&UOE4(i*H6L3EIgfU3kFMlT6= z#C75|6e=_dN`9*sX#CNfU1YDwHNqo2>1HzFdqor(a#|n3YI}KJ6p*8KCEFv8O;i{f%pzk^Fk232LQ6od5L8ajUeHcv)#6Uw#s*?~iy_l=zUO=TJcgH_e+&7c zqV?=Lm1=E@dI$oF$hWVNhWiNFOj*61r5ucka6Z`-}_feW6QP1(Nh%Ft4UFv zGWl&}Wg9JT^D&L?x=x!DjxF-XjyS$@(M3Mndk&}Ti_PB{F5dK_kqBPzEmOHHZ0;9% zfT}jtfsQIn&5e}vQDv*gy5^RY7)3B049pZ1gxMi{-e+BRt%VYgdT~uTRTfy|MsrO5 zc<1fGj1f_-4%9-3n49+8h@l$mHVS`cKdygZ342|K(JGpYz$LVkXLiagN~gOIU^r6( z)9vFQO(dx9;>O2y)MO zEQZ#6Eo`lf(RBm!536W*kfNE#x4cbkvKfw3z{BGewL9mUG3a)0Jb>$yX%WBeGMd{9 zbH~CzlQ*vQ)vwZ{{dgyK*pHu$0hY8OhYX9*~$nt=Nk^#bKjPFyxtY!+G>hMl>ukqFSb>crJJC z*;Z5(JoN+Ca0tuR*b1f_$%idWH)79s110k(Qd>V{#s;OodG%l#z%$rK4e~Bpq|gBC zT2Y?VRmfg14>>2hc_j&ihlcYv+mNRs_1d%xUnuM z(sGBLuKzmexo;;bDhiq$LXEsc+h0|BQgL3jb9mnUSN%0?aVupLG}&C>w!N4KMW-h{ zeElv~`(QH*agG$Vt6k4rA~mdIGk;>%^@9fh>(qTq*VBbSA^WbM&^)v9{>k5xkS{20 zO+TSu6PJLMOd4YZ^Yl0z3^VW)yZQ^1Y7^=d_Sz*c_hzh>xA?*=fF()|yL6kpKJZ*4 z!QPUcY;Xcgz0hdoF)6-dj+jwN4yS zmKX|{EQ<;BJq{FY^1&2rIGjzSXs7he)Yw`K2W>A{Kl8R_(_c7?%XoqV0y>kyFfejt zgkDRz!gf|`q#`x)x}b`JKgACRq~#qpAzigB($4h$SM5@1_i!l?XD-X7pw&0iN-GlY z!yLwK?z5e5a9Ps&E1A8pnh{IMm&XYeMW0mGBztg49ObA)(Rz=}s0d%RqoQ~xSPXd{ z`R3&15$!>}OKhH<9OW)IqGm^(m<>#3S&C8mWOP$D>XpufkPWrR!$b z(!q58<8IyMQm+C%%u6sO5gCE0zfzKTl2aE4vMOe93sC zj{(b^H}1ikNvRJ#eYL46jg4GD3{?$8@1GrZe@jP>XZ{9t$J2oU)fl3eAcB{3N}P_A z7q@PjbuW7P@upT3rP$!DKocs1$7J-6ERuv->sRL;?b~spPDL*3 z$qa(Yy>72Du?2)s>}AX{Ua_WK@hPo7At7)6D#U&P>q?3>ipajx_xNl%t_dSl)3~XilTRJpxcRX>Q}{4ofjl; zLfS{a^J2EA1wF$>I4}m>hEL6a*w%Qd<9nw?PQVfXV_@o3iJQJu9mBZ|A267wdII8> zbbX3~FqI37t9NKqI z`|s&X44=jV5yAeHgUJ`_=(aH0glQGA%X=JmFy!_Cf9B!=T#B42lG!~=;+slj&w#>W zrO}-pxO>((51r47UTRYHzW{)@gc(pHbpml{D@Rx7TfJ)gP2AkqDe(w*t)E&dbi*I6 zEk+=W^?%f>z;6eTh_iVn(?r*++>-xj?gl~KQtCWwDqX7Bn_p^rAo%#22tuW6s!xA{ zIuD%dj}emfyfyc_2s$zKrjeN5@0}hrk$X>>7bl~pG3agUNKE)@1SUf+lJ^39>Z!AZ zTb$K>WD&qWB+i_@BM#=!FRb0jCA%&J3UmLm@SGw@=%U5(RSG_Lyyny+t|^tG94=l# zl23%U@Hs5@h~0PJpkBeTUI+j1o!_%hHT5Hv^p^1;FslKu9xX{;dzN z(3`=OYOjy5;u-V*3bX%rV&5Q}(m4Jg=Q71!}%`b_i*m5w<;bb``5bVxrqd^Z`T^DMh3pMVFfB(Kx(>P$^&S(D& z>ry`*ErL;2+RetZYW?E^CSq{5FJR8V*f|hbW(WYxzO50-aO1zbXGP>>*~8Y#71%43 z>Zge1x7OT90lnXec`3MQm@xCG9JW05{%=>tRtzYX4q%W!09fxx)}Qp+lK}5k1zIa? zb#7DhANQ}}*+X+mj>KJ>>!&~phdc~ucK`ZcmmW$`jy~%J%fAUwW17Ldt9u}@I31aI zP0jVMi-Tm@2B6VV0p0nU2ySbG?pt8WQX|QQ0oJ3f^WUUN-q#p)!2uB?0L+X&QsXzL zE+Jb}!r9B+#hL&;?@@3C>;`|V)alrpM%2y5{G*k5}bEUA1fm1}%AYAUO|E_qi@rr;ot>sUm!OC0h&fwqmQ%++8q5{`n@o zH%|{-RB#I@`1RUNEdI}u{O_e8g^%MZ_P4HJ3Nv1%&E##98}LsgBH3o=0IB8$_ByEZ z|6}hf!>Y{ow?{%z5mZ1xT2V?sKsuF??vzGqOLv#3bSayLO-OflN=i3Ki*$F_yY`&X zIp_R!&TPNE*X6f84$t1t^Q^UgdH?QP(aVU+XjX!spa0;aAkR&Bl#*leNeGItal zpnOj1&;dSIFZK(qHKYvro9|=&hUUS{Ib)C2E zFyLZu`u+RidX)?~#yMQ87?I#gZvM}JqE-|%IuedPHS^p8-GEPK@V(UNi|e_&Jmd*9 zpgis5Tfpgdhoc+dJ)~&sK_$3b#P=FCsi2ije#vKg%S%zK=C!N% z+8z9CDP8S#{O1xdUk0E{(YF%JuDka(W1LvUE0j*svnIwkS!|5hR0g!Hd_Ba>$Z*RvT>?JU^*40F` zV6h#d`JxLg0W{tn48c(XeoJ#Ao@#)Fdjpq321$S;*+j|LcMi^Cw<9W0TE?H)&9>cD z|4mRL&Ibi_17x2jFkt`fZ=wa$ffsH?!wfeWaU!Uoa6_0~xz+m6pg&bLw-a8u2I{l* zV1A7sgg{Tge*FZ7nLvYBWv$p|bp(Lif;NB_sHZ213!9=slBeFYe|tOsc7IZqN7|B>MKjhni`iCFX$fbs!o-T#{!$1G8JLSu{`Bpkb z5oU5}v=6ltNHD~>cm)I^{#|leFa0>=9SzX^5Wg0_2%#X?>hB$9RQUUa`@zd~OUD6V zx}ub(+OHP+zaH~{+?0VZFc7pbT5Y%!`+=GMKa2R+y`(Aw3;yfjf8x#kTKQkw{@0oR z%aZ(!k@=7R^~>P>vi84R9l{Rhm!JO?5-4Rm3?5oN;(ivF zrVsHdDGn8nvMDSYE+!`byxIL)BANgDb@v}WN?bEq|8DqQb5cYjr9X4@y?F4poV`qk ze(rj1K~RnCVh;;=^HW||ljI6o|FGx552qsk{snhif>P{GwB@4E-~Zi@%-UW&-zm>n zi5eEE)HIUw(Ho$aqg~%47>F)N%zj5KhKn5VZP1quczSqLKi{4sYB7d@j=$r-_r#yK z1c~EtZ0S=V#XOlCKJNMYqqQ>Hzx15~F0Y z`cbC3TEwa13@OL3u$o$I^tm@hz%@@ImIr<$yp-&i$XKtd%bK4!JICe%h)k~WXm+mo z^j@ykQ&|f-7WYdesxU_}qmjY{=-qC3_YR@;K33<8>#XLzB)|t6W)lZZr}Y4lf8+U5 zf0IIU&7{jUvI(tj0rUwtjP?2c8uwHuXP7&HA*bb27lBqt*Bj8JiC`HW6+*C#?q+}s3izv#j|XUS z5q$0MK@X^T=9P9UzH)n|MH4=>PME@9{OHhG@4mrIeT@7MJJ*)z`GHOsjNm|a{2bU*@!+i0?y2EZ>Fv@d!j1QO$P0t6-7 zMy-{UM2(B})K**IwROkIXt7vhoXWFZXgxS9w92zRfR(!031 zfX#^B9pH%7y@u`Rs_m51C)y*l>++fdt}xUl_s=@7b27>@Uz|PZ;~mFct8tarQ?dMz zRYKQ^dJWK28$NM9o%rn?-UC1zHC>nEdiun2faRR`;B&n2b(y1Cri;UX&4lRr>WFb# zv11TrG8h7UK2>+EY_x;5=6dypJJj+5e+Lc_tHYAub#^+KrN?E#9cVb;ti++4JeiZ7 zsyQ<>d2Vjvyghe)Fl+P{7?aQjlX;?XZc$UkIo*ueDtEXjIS+Yd#TXLwYGI?1 zo+q?z2U^3e7m-$^3uZ0T$mmsy%LYhca*gLIKtLsgY+@_y#@!>&$FF-IOC64mQ~bzz z{lMk%F<%Y8HjWBO0eEY=jn8A2DIRv`x%CF7NG`a!{bFHEdMEGonnqyA{(;lr>?GS9 zcJpTd*_)!65BKE{&lR-Zwi8U2x>Ea!p#OH%s(2=o>5!cHEVtXAl@1+#^khqlUJ;l) z3rE=_#93N8DwK=hVkffd&5!>G17i-lBC(EZvtmkys2K{(_e^N&GnE{XgOkOmoX@j% zN5^ORJrapHw7R(l&rc^I_1j&hFVs6uNtg)bmx1i6Y1UvozGBD~uH%&>RhztUal_7N z-LhkO4!Qa}h`fc=mmsFOLON%A#jA4^`1ozyP@!b zkUFr-l}DOLL)?&;>qBWdRa%uREE{grGev2A78eW+)0hAV0Sn`B9%miVf}VuF$3nCO zK4XWgrnv5Q%k6+xD_L$^x&2Nb#57uV?b*^YC$T0L$<<9gvTj+_NDaYnTX{1FEZR}QWQ7pMonSi(kaoiA1*1TAX#gX zU{PRTBFuv!*!HAdjAC6EDk6DA34`4)$`eu4 zs+B#n0Pzl(ez|t->aE}yHOiW*V>l+OJ>PaVgsJ{u^L3r|P{-<`=kmc1_S$zXQk6{H z^dhFiJ=x<+V667{#~iCnY0~vbzynM8y8t`)e6hD9Enh|veu|R~(EF)$snGkqKLF%W za4(}8#l?usXFdHEDge2t7VkUs9xw)$m_BxhJn@%zI8RF%Ocof-(NH^Bv(+G=tK7(y zyDpa=1W+UvvAAF6FaD4V<$K!)0IUF>0BPQ;?#+iXni<778Z}TqbbELAQex9BWEGor ziAzz5)P;HZ7P>5yz(rV{H%78P+PTJX_vu-_lYMc{$?CZEc`fpOo9^XEE_)$5PN|)x z$r{tOTg_^v==d_n^ffid<6kxcYzc!n3O~GFu1^Y+zyuS_g=Wn}qF^E>_fZ47$Y{yB z$Uwo9xRR?4?Hub)^G84;$NoZK)p*w?BHlAyK5h@%Ra8J?5N<@I~FdmD#EMwzZaE8d9kYBzLz*qs1YyWJ%9P>&|@HaWZ5xbF_?U z)NZ}@s6N~6t2b{>qL@^4;2oHl1VT(^05GFyx2%GR;e3QmVqD0v+izZ`lDYZCSEY`7 zKNG!VyqG-9IAyF|tZ_d%n9urhgXXwh#omZ4FlJaXuYF@lZWEAPC170>3Q<8QTT4}Q zD<2_pu=eB9^Yi+^aoCnD&Ix8Ic;0Hv@VG_dQlbY91A#0)n3nO?WBQ8np#y zl@A766Z2nNX=%2`aI5h&m<&JW3N_5Oe^j|&WjpuERD?Yno;UzftCt)8rj;CE4sUqs z)m4mZ*RBm436ER+X7eO23gyfEtAj&QS8qUJKaYmsLAe1A3UuD0$&Vp|*yUvUFgqYt zT3TuuDN9$BYQEG5)pCdG`K8A66{ zIu3^S85`NshZgHTItC!l$Rua#GWx*L_%e7G%?+#(K`Qi=u;(tu;A2D%i9;Ivj6@&Q zV-VcBO>ms#;05gmOk&RI?N{7lNTu+|`?{rE;)L@^LqO15+$P87@hJ`jgsa6FR_<`l zt@1HIF>`P-PeR2mM8QILD>Hbh@KR>OgC}sWZwmmNF>ORWA1+~D%W)h}1em`|Z}PPJ z9&>K0sypurPj#49GXwBo$|W>56eNB4Q@BWYMWjTA9kAbViP;#AS84#DyMO#VZX>rS zU6Y-SNo=1AXgr7t@Gi!Q9}vd5f_OM418nFl^B_BL~C| zI~cxvl(*l?u56>wAd(iljbH<`uJ`ufr%!M7xlLn?IPkGixt{=WUE{QAuMgDL*3L4z zN!fk`C9F}uTSgTb_MNhZ&7ap;FK6fKigIjAxaj$ul&e|SJbT&k3YFg0&KAUrYi3a~ z{hG}I<6uz1@xIfdXrL~}GTg@mQ;~MdqWCyVQ102kPa({iM#O&Zuz*kk#x@O<;U4rI z#d|71;NujRkwn8xM2G~Ooz=XCC0mt}B|0u@Ved^U*MNVQFkV`V3wZqcC~1#G5zw){ zqcY4O9TAU|i&0ZK9sE)Z^2EbCO4c6zU*hqY+=9N|Sz@OgVzC;B+fh1!^tEfLc?_J- zYdkzmQ&Bj`rSM3x2)d%#?*oD&jL%d_eSob-srUiWOWD#Yd+xP$kR`F?cwEN1=-C4G zw6Y_F=URkjeA=SC;^Lh3n67L&x>ZG-fTpg)=r&ufHhofGN+3FsF?4v5htBJQOqi;L zjsZ3Ri(j3RbX9&wZD@K=PuO9~-5;L#UNjXCf7?;oug+VHm8yFomcrn01)uYO=dRxj z3n^`P-tg>V@t_Zy)uRG|cXZe{QbhnI$`GV!*Mn8;GJKXVJ6>~#Jl&uw@2eo;qBXpGYV!o3*%_Zylf-n*f#ZF?u zA{Z?F=bJ~#t=#BckPIqN<$=2!sJtuWH@c%DIT>Dg@Q)j`!twBj**GM z$h$P#e(AeRx>-04?F{oU)}o>gX4&fJ^?U8lKm;xJ;)PJ`s94ggSMWJ%z)*&7g~EtU zs7<3J41cvrDz~0L{T0WTEs1huE_nKe1Eys~U7! z$VF&7*WH?$T)1b12rnYAIbZT|BO#%rYiKrjU6=v~r6kj>Gh#d0W)x;W*8wtgtKw)a ze^By!N7!l=hpdj;dcuQQIAIj1m0p>T;bazzU`#Ai zYC8|)+S0N+n8H;V6fN6^t+!u`J#2568-UmGK*BfV?zpaozgA%??{$IOoN%;w^@_j$ zwdW09XHzrK=6lnVyy%4C&WjcEF*s>w$|~NcKst_r(5%)ajauV)WO1sbMhzQC|4P%n zebE-G2C5n5xuEt41`j-D88NHYtf5cT#%ZJ<0P$gF!2C`+Aecrouwm!rrh>^^$49XgUhTYx?WZ?>l&!vxPzlILyXDr5K{Z{2!N_znjK8lTLdOWFf}KRG=~7a zVJMX>0+H$;+s#e+`o~U%9CvAgyBCm-f7b*>;;G|F*ZUw|>tj52-OZqQW4HVq zbub6oBnoG*!7CvE)BMtGB`<-|So@(wrM1psU#!BL!)?*7FIyFpv>1TiKsrsW!S68x z9@WH%3Oq0Mdi)1t$f|tS((2^t8dC%xjO{ZB075H5m=5s9uwIuuK)~t#v5iunx>e~j z7?|%giGdM|tE#r+V;kGCyhDqpEX=FuUBP-|@&tp$l%2WrVgQ#)ke3V?y4rAA^G6{FwYF4UPSC0S*q{O6O-`#u{n`|TKjamqS%yvd)l&XZ>+1w(hro72mU z7FTtn8I0G=VXWpv(g101UZS(b*tO*yhDJ;Co~O2%p7 z+xShL4U<1?)*L)d&P>7OIx!o3-sCqi-`&?$Fm0$7mz^!iw%L$3wU8j_aW|0g#(hcR zn-{O8W4^w$fA#ce08Fylcz})TfhWggI&t*ScCFlOy^5wDbP80~3;k%XU30EqObNsU zd`ox4qFA^5Bg76tG7ugjRrf z=y_cn7%#2`bEA_pgbgZOm=zZDcl2bH%krr%za1frvHOxV!;qK$CD3~fH&+lT>FU9W zRC!1w0vps#oiqgk^5aobYDAmR$?@5e>NHh*(rd^uo9 zpwCdU3K`Mz-@m>hH4)?jA_hyo-@Xx%4{<}FE4NsbGU0|u1>&!BEC-)qy2rfx^jk=T z$cJu2RM6BLkzKF-!Ia$pcob?XQ1%XrJVGc8{T2@`6v11xt7*2M|HlIVU?YWqoIqAs z-1)}0Z$#w74tzQT6tp?b5J*I7&$}jI%|l874sjI#SD?8>}eUA=2IW(!X!iJyd@zcXVmX^X}4T9=eyBN;E2q0=RLG@#0a% zg&j6sSf>1vox;LU%b(Y>>$`*^7e)+k5UWR?Wza=R-@2^w;y+Hfh z9{H~itqOcnDMn!v4gc_nXHtHc|H=jMUteWG)y*6B8Xvy-j!}+wmvOP~i+RCGMFj!~ z@d5R6z{to*YIb(O+3B(1mi^PGPe+#lS*gUMM~_x225L~yu;Xh1$>=Tk;AdfRadFjc z0)m9HGIn*>)7?)+hKitp&&*;vL71VCEgczwEyW|=ng}&>0cB*WpvnU#MK}~zJy^Ey9t*Lc`#uC~`0BR;rYpL!C~J3_3u@bC>bxU^{jwOkT>9 zzbWkH6SphyVcAz4sO2mp2zd)OJ7Do%vszxdfTRRuv-%3bHhJaxwz}7C-Tl@ z**-B~qw`r?Tc@a*jucX@0kO7c#YRd%gwik%bUEdu;@ENUUaamAlU%1{cDsNq(3mJp zA{;fioRi}(pWza&u-wuz+laY{aV26JD5uFDnZ}n<| zcEF)Q{}Au^EkcLYBEfyNiCI_Z`sPdsAx@enIWJZatQZhA5WsnCqg~Gqjduf(?{j9d zBW6T`eO|^%q-7@BUtiF61HEJkPS6diApl~pIw`U9Td(KlR;FS*m&%-M$ovO}oj5aa zW!95M+Ij>v-i`Dmvlu&whC1C53^HDmEU~TI@|?Fc~ZTV@AEnNMFAtmFl~v@2gk*FEfR9ol?QARm)g) z5}2IOTEKQ9>-KuZ)vN~0ZL1p=SG$-FLI#HB@1wu7-avX_L7Dk9E&cXwD23~tthDip zp%k0GGMcQxai}*I{hGNDWU_#Unp(Rvnp1{zwS7dfwWS7#Yjkl)#Js1E1Sbem#)0iOiqLx|IE&(O5R!ZMDKtIN$^ zaC4yws`)cfJ!6%eS%WZWYwHE`c82rF-NDsS4KHTHGp42GSnnYXjVOnS?BeC4-3;%@ z$j!8eotx$dQ|sOzUQ?uu$NI5bFEMX^(#B01aJ1+h?sDry0<3DGj{ndr{P~J^Lco5| zXmO--yNUe_@WBqob(We>YxTT;TE#eRbRh)B8Kt#8F{f_t63_L9KR)yK-*5V`A1%=I z-X1A{$Y!eALzJ^BD1b(b4Yie}UDK*)=onrX?|I`32ro#bcDD4{YU$j#<>9@Pn*N?NReT|AP!3Bn0ws7;=*|8pTH&6*+NLylrY{nFpVCxd71=8z4X8Bsv>V z)bIyn1-3`_X-;q7sBx^x6+pT&^0XSyJBG0Z{lcLPgIDRDlKNm)jC5z`?jbZaxCsKV zcYB)~Qw5AjT>7|Hn>v8ZfWho@tzX9e+BgAxo2Swsdh&p|)>314#-ikdGo0$K8UQ`O zcPptqBO{T!+p4#gm-qG1!;Ebs{Cq_+yN579zrX~}3It2%0YX^1H~J&kHiPgUrP6gg zAI^_T0LV?{EDDOEqD4*xX4drpS`}i>1+o$oXX@#g3&>46{pGT3;JSi|&^N~p)ALUT zJ!x(tk_BA<_!{hJVkuGkk4go4jd{()1bxZkz6{z;zl)2D_YV#VfO85&9`4@0eH*^b zHv#uWL!J9o(TKXSd^DhX(w6qy6WN{h*s}y6V#R^Mxsv;=#6&H$!a}9>R_kI1Ovi#V zYAvuS{@A9hyx{$NjU~t|vwr>Rcm=b%(etD5xdv=t}-eZ~%2`6pbs`{K zfh&uNI`l=_Ht6WhI#1GRg!N05X_QPuouNj*z5 zAYKC%K@#8e^mL?f|630HnjMkMN+e8Lzw4oqF1xc+4i2TP$3ffTB=VO#tcSR7`1{l9 z!(6tYOxpdaZu&)?5`RQ$TcPIqBstIWxB;K3d!e$VN!wFRCo(JBvLoViFT#QAqfeSY>{>I5?ZdB~@9rk-NdK zu7BDu>duSkJd>)Kwk~6v1SWjsAyHQ!&q`B^56G^o%xpx6}v8v8wa z%EheA%%{_UDv@V3p~l^nxC`w(QLWz}8nC@)H{nk<-uu)|zppynMpssr-+&dS(r4gq z!)X4+lTjH2S*Z9$uW8{n0R(r0qa4Tf?{>AGA`(PjKzd3FQb82oennb|7%uhz_PKDs zW_sm9N|VaXrqrCAt^*@re)244TMwp5&hh$EBqdk5EY$k@`*l3Y(?i9 zQDyMCk7%V8_p=L4g2t_ijo8gL9;|vuNCegDK?Jw9?;M)?ARGtDg|`0Qes}*5PQRu& z;AjGKoMvg1_&JE^)hq4H0jh$QsI5~}O0zrev3ajBMPt#BI>Gi_M;k}IT7`{n)_lSz z^ZD?A`7*n?Nt+M$ceHV%!TP?zW6RYT6a;11I}@jCE&8#v8r8Jb=ckSOMXE5XXxrv( zRqkfCMWntI+c9wn1gx)ViiR8?1o@($4Tg5kh9W9@)+ z(%oTLvor@%NJz+LCji6V7mvh-3)qN-KO_qpaSH%^)l+;V^E(BmPTJ4ObDT(M6pVa1 z*PY0C&Nj72NtjJkja6-i{SNkBU9+n~E7LMFy<88&*n4s&37&f;Cx`ZD%LYQ;IQN>Y zd=NHe*D>52R5A6RkvC~x=rQ$|PLPm{+VjCVztOVx$lXp(0mDmH@>CzB8a!E59v=77 zV#iBTKm_00+k3Mul-4&*HboEp-J6q%BG-120~aR{o>fu%St!8+1_tvl z4XoD|fub52F<6){5uYDhIRKOW#T~aed3^H&ri8eApGVR_5X=gQy}VNpwdqwVFXYLZ zODsiAmaJhhM(XIOkTG;| zNcrmfq$CE2Gw5?T!`9LZ*2#eKwmG2KY6Jv`B&M#%qx&JJqCfD&-%q*XQc+e?W#!ri z96JVqN!c1X7qa63!w7%JW_yIFCcqu<@ zwlXNLBi=Ix%Ce6`vnI5fTtJmoysk4+NdLRq_~EgHc1Ps7m^&H05pUOiR0LB^=*YEY zXZ=8ZW8(mzdSVJt;A~kFeNgfldmts>d@oEj=*mU^rA4zf#46{&H-kbz#Utm@Pk>dB z@wVM;h$5qb8Wm_5Wz&S=%rFBm)w@bUHC&-;2_T01?#lZI{^W@TE~iJ?ld6e|*?)Q~ zFvc*6HVxRIK9+udCA~rj{6RS=TXik+4z3+gES(1XCvdhc zOb`fKz3WO|UIpEgTy%K|geXaeqx~u8p5f<|8(TDzp>QHD(Z1o+5oU`Ww++pr>b92S9m@Tfj zLDwN5uw8Q06QCn`j$kp>nVK}UFXhDjc*7_@67ZqfR!q%INGAwbAG@&L3aqUFj9WtL zz-AhAE}wkCt?}YLU6eGQZ)Ea)y{Z^w0Rfz{O|Jex}(4Gd&o70Ra|u9VqDKOWTwhT8JEf) zz*$ZKEVYhp+K=gu{W?NXKdF=tlIyYImP~X6`>qhFiWJ2#PD+KKwzjsdskO$tD{^vj z4Kpp!X&;(wFPfZ6#-ME(UWLq0#I|F3seSq^EX55Vr0OYdlSsimj9Wmth#5oZNpiMU zSgn|K$9gw__v`@9%(%0>FQEDS z{1DDKcy=^Yv!+4avJXa&NSgw(S~yDZnFMsQXl~{3iFZtayqiQMs&;9>wmDmkK4su& zDN&=w&3vnc*QdPPR<{uJnoFi5Ala>{^W|?(P9&?(IXQzgJ3)qh8y; zq$R}itt;xF&i*+p)%13Iv8+h3noaqLn&jH*64RFXcr?4^m-LLSbI%pH3ROaUJQ<1X z$K`Nv5c8Z4w~B}0YAS3ix%FRwOrPm-$@FW_YXpONazXQe!+#7A({e12O@K(<{OnM$ zsmrC9dU@Wbk>a8KR?7Q)M(0cUNus9IUfyzwfnI$Q$M!(nNI-zME$lp2PH4W>&w=L( z@10C;g&f~v*8o64Zyh#N;V%otlefc#% z*S7DjfjkeL*r`8C0stgG=ns+46RjHpe*@!GOi>#OfksB&{o=>ug2V6G`LWb#vDdVz zpi3Pp-33ZzZzZ-W54Y#9F3wz?C`IUTobLcTMzP|4-fhIW1k6a~s6QqVN8#vxd0r_> zWK>iEOC=D|%iNWr8XOpCg77fW7;{9i)(``Na3=HmYpz4;Ia#YD8i%dIo9_a-uG7+H zty-Ik2!19xn~E?I*IW5i(p)wVl8ALsMEP=dj47H?HQeHLgQ8(E<(x6!-3wST(LB4& znyTUJ?5AAAw3$gs_lmZqbel?Hrqox$huE5g~iCcNp*<4lY{nZQogL z^g-zLqxkTF(nPCo+;iH!fZDl^sDz>-W@>8c5fU~a6}h*6X*)SPdrgy$KGhJ;AuOaG zkbM;{F}U0aC$UzhcmHyUm+hWj7jXzn2$)%#wOfd{HZD>zvA+*s6-IuynR8Dg1D#hs z9kgk%H2Bi%VLmL>c$R3IEEaL|(v|1%qH9|B$1itaYR`+E`=!I0H=8FzkIKgBvpx(C zCIhE@PL!e8C7H25*Wz)FK&!#)20p-AeY`sjBC(dAtcR6x?T-U8&6aEqASP<$+6$7f z_vz`>paC{&sAg~3&d_W%%QzJ5#kb|TKO6vP@F6s~&c<6a&o{fyos34f0FE1rb$rLl z(fD|;3T#2iM%t3-LG_I6Y(JnK1^vQLa>T#nn4VOnPHox=BuXjmM}XByfqAmUeTi zjULkPTh(3TstbnqD4yOdA3iT#Os)}dK8-mQO@l=YKFx3I9GyIC>XegBMh^rkv*D$u zd-J{7)-qg30PY92#yGnK_il=`qOHqumf_$DL?t!3s=JXjL9nasb}yg@wFCku=R)pu zB#1xudQhB-o#p130wnMp6iZ#iI)^bo-Y9yy915Eu&S{YQ~UUeoQ`UZ;gBex|Bq3)P6kUX1Jy5h5-6~a=z1vC25>Z1I@qtB zg1U)M8(qbNRVpAe*6O^6yQh||)iQDl3W+we5d>iT(-nAI zabO0~c76wtY8>;AWE4eJ4vZ2O>mxaa44h zqK>%YVwM25FJ3}6z3d=fWIUs+_$?(ZiSSCWs1)QgfIXUZ2>0Y@97)`V8~Hr@?d40@ zr>E;fi8dTc1n}tFWgH+)W#fyLHj8q&2h_Jc_#{!9{Mc!N6zKwhXtHzQYmN%rb(3S$ z#wkydm>!ueOAutlAZ{-N;PrFWBJ~yfvy(#x+qJQUN#0XYAWZw%9B}^@RZV2V-~vMC zBl;AXTWqfMm1XIw{lzfoAoJ#thou=?QtAf%2n=x@9Z#5NAc$J4&{DRbM z=i2dMBf^P*8~-X@I5yCBqyv$bvttJVQWE*w6T*+T`tf;PD&r)mXbZ~_$$MH=j6l^ z;?1Yrp?%5#1(1AD;_AqlWfKPlsJmuR?XqgRH>75(rEEtrjf9Hy^g%9AbI2UG-Lt%l zu+zDs3T#v@ZtC?BM|j>fVwm$sx1x$1hZY4{;PLxFd5cIZFvt6`3!%rbx znzb*%8{Ip7OD1nVZf%+H{*LpNlF2itOtlK8s)PFwpjaikxls?0w4j>)u==2p-P9r_ z@G^D^9|X+s``?z2#_C0k9mDMb(rH0|Fq#h91EqZO?6SE?FcRs|4pc3ZC1AHbL1i73 z0}HEy2!K%F4L}6F35cK*kcvjY%38J30>j7^)1cU6e0+Ox z=lz|7xcGPm(4W_s$?OBLhpA|P`4`CdmSL5Iu&Y3OVtwhP{`G-QUovk)pz9bJx6Sqa z{iY<@WHE0zcwjjJW2fNm@-+nA{gr3n&A-G=xvnB=Gr%4Wv%X@E;m{h$2ePdcFrNbdAzV9OVInp4xzBmmcW5rYs< zyE(ugc{S29E|$oh*N_OY#*Yy0^?u=fGl7?Utf)a79c}?LfqQ|#LKG`DFRzs^X9wJy z2kqmC+BcW6?p$6bT-ns)<;1Yz8bZuiEr`0cRy&nK0PO__5|D5S453jB?R?Yz<~KL> z8wWt|afGI8^EzVAsEQ1PuLP|zkK@Ep)+*Mk86(p4Z<4;f>UMN=1e8NBSug}Me81-O zqXHH78@}^b3s106(1PF8@?&yi15tKwN#`Y51`t68g+qm}lfET!gTy+sn3Tw-?fc#(WumI_FHp5l!yB6 zRo{MsR1uD^3wng{53mIPH$&i4x(e`hyIWCQKX-XH3c%Oh(V@a~f{SoShe!ZAfY7iV2-KvxO|E78He-FhE|K%+WxOY|I+nzuC zi*LX5oey!Da3HP2p?J(sUH1I?z@jy)(6QNBV_d78BB06N^h&6G)Zu~e?a1R#-<}04W0#KZ(Zzk-YdVW;>el`Xak%Gx=XV3p0pQ~^|JkUGb3z5p{rppxjaua8 zR@}yRM7-HON)X!BKRxXU42AeTgtwwyPsjdx7coeRYRsHLlb9UDKnt>5y9KeAaRbCP zJ7$}JjR=4E%=7@vtTL>XYOA+LFqL~sn*BK~3=kzP>la$qkz3YLi2`T#J!kgO0A%?4 zYxfnY- z02G&&BTgnafLN2@cs#iPjQ z|2iUWGB`pm8bU6nW?ygk>(Tk!R}mb;citN%GuiQC@|@^=DFf2{`GdUkkQc?DaRn*` z+*rZq`kTRM8eQqcBZRQgZwY|69b+pF3_95~-r`uV^ft~R<4@OW4W3$!b^J2`2o9{x z*WCq}mQQ;XZZ9PcGbv z*}s!%`9#Z}a>3%wrAIJIB z^Xb#L3Z|V#$t#YltfrlKR-Fqy-;!-aLgPOo3umggwA=Za)jagH)-#pae^pix{H~oOzT)<_-X|l{knwCad>&a3%&xyGKM2|=&?Ga8 z2=i!asx0i!BC-zE6}~2p)8EpDgdhCf*y(@WYuqu?FeCkNKEt?c9f7S4P3m@kvbd?= z#`z@dp@S8AT6!y@FrIIodf}=Y`ErnsItMZMdZL`gPJ6JzEqgq}LHyfGOXYp99T9x? zuireQN~$t=ucd)}INXVF{K^u!KUa~xr2ubONBBEw*{^@~pE=+E%=EfPky=bRhV$t# zGgZP$6v~PE%WMy~{F0jn2Aixc=k@w={{C*~K77IX0T;ku7w#n2h7>>qgRB?rPPBHH z0+OO(ww$R2Ci9(k4@F-sRC;4g2iR|adDD|%Ihg47*L4Uzi`7%omO}F3Q1a>CO`-gU z!uRiM2tGCVJh+Atlj!4O1qRaDig4ckTnY0fU;LGo7e;=*XU8?$xBD0O0yr)!2a%Rr z_Pl?x+xK&zMV;1sF#mVICSLJN5mS7-wZ}vH_DpR zlzXXTOHgHr{5yvyhIBC&6Aj+x11rM}rRmhT_4q&g4gyhZ9y3o!ENK9vhFXK1Uv6lAjY?C0t< zq*4+{A+wK^EPwLyxAdT1;M8(E?B}dYCMdqO8kC9uoVGHl2B>u$1~LCg_xdbV^e)Lq~Of?(!{omzQ2?8i9i5zdc+qyi=+~Thj7# zm(PfTF0V#@)6bn2N_eLx=N?0P$Hl)ms#~0K4WJ__jIc+ei6Vm&`sMFiIh~z2e@W zQj6M|BqK=qa`T4HcNaybqy`Tc1zrfkuq z=@_2r@pf!NQc)3Qk9%AN0cdKSH}7wJ))*tkTm5n zj3nAli;%@kQ=w|6Ymhhi%A%2wyES~=jZ)XGYIIKzHW72gt+bq^Jo9s_`?esib5@WD zXWpM+XxQ>g6JTPqC1ABVD#HY+trRs94Ao+95Q4c8+*--m`I=ww27nR&lYR5;Z-UGD zBwlead0_aPc0>-O4ZIps_oe4PcS?yphKEH-la6Q<$b9Z-@Asen!{!;?RE_;?VJ9aB$Isy?dRvLk+|o=eBuvz z6mNaFrh|L^%>^Y7>v9O5hf;*ILnz==!S0umcQ&<_x0ScG9@=-}VV2(?vjhXdj;4y% zLt~St<5(EPJkjOq_bwnIYkXcBs%ELQov1XSu$VsDom#aWA26bGy^M%m<^7v65lauY1#ecy{Kz@4m?`GbK`EEJm6f+-_qu)bap&A;Kv+zV``9}Q$qguaf(i7XY%z)@D?o9!~tyHZLN>ybqCI>=v6+Nq0R3;pK-B z)~CDAx2v7q2XLy+c!O#~T!C~#(JBRr3){&lmSkeKVPb0$;Gd>rOSck}&8cEB8a|hq zd)q~?cKeKxT_H(V=w@bL5LZBOSm1QE(66O#yowR*KF z7g8T{*P7d2TGBJdubBnG&3!$!giln`W}`8>Nvdxp%A5(II^2hPH>I$V%>)Xqcn2~@Mr0}oB2gk$8Es9L%GaprMPK># zinP;huM5{U@zF78i#@>YihgdDhRnY*QNLW1Y7&|NH zUAowz(8JWLzLO~|6D4^=k2%UN4D`g$V-*8ygxHH%qUd(s5oxK`V1EAO;20`Fo#w2& z$s6<;YO04)S=pO@lA#N|?;d;a!VPFfdwI~n@@NoWkYOl2edkJ0??Kbmx;imW@$*9ngFDdku*9RdhG}f;#X7~*U?U8U`-zQhnK09R2Sq$shoyDtu z8@=snS$A2tU_tKnbtb-XAW7Gf(Nf z<}=&n^7kEcRrcz5y}bn+d5bv_!~$J-YW*6c*2YiUs+3a0_)VL1R1ka(X#Jvb>3p#8 z;W^$ew!2K69kLZR?wGtAd^t_G3x-bG@^#60hVmO$?ya|dG=WZbeIRe^aLrVLYCLdI z=dm^j=Pf_b+IxSI>gqa-m7a-hp>-fbwiu61o>RRud3#cQH~k^aWuc|OUPWy-=dGEI z&3mE-JdL4YUAqkYo_p!*)fNi_q)}$my|vNGy8Yh4tE`2%-T{#;)M6^3#MsaJAL_&9)p2{`Gg*SQN?!E6lf_tlpR=ckJS${H@(56S69szE?GWmjURP;Aw}MO zk1t68-};LL%UA)Kl@V3v8T0w8!>7kNI`P)O8-`m>M88iqbSb`XwMKugu3Y$-_3EzG zg5HnvoX+08+vf;y6r%ajKNp2Sx$D-X1CC^llsESZkIKJaPSFQsiv61#F4 zi6T7}X#<9^J|%#c$7yCELAK!Rf!M1%oiHBmlO1KV;i6obFxqf4t^OV%4<|D236H6vd46p?XAgJqpBf0lcN@0_Vc@`zG;AX>%FXL zTQ2!0y(hvp@9FP-xbGTyzu2IeH#F&BXs0#b*}hmE{_K4B zZs3~~=;x#iMi&otsLp+5E*m4e`}%#*UR;cE|K)u0CcZBW{5ZdX8C)Q@;zE>dQ zGN~byPZM&rx243lYf|V{fyrcHT5kHnuD)=tM3x9Qp#d|?X}^T#D0H-LFU9BeMYsoQ zPkE99S1Zn1I&1og&~SqA+wM^S=N%}^u2MIi+X`xVn;d`1)|7gqN>xv zr?kCOnnQyrH)33Ih{s|t*q)`YEu%mLYn``(+(l?7FV+x)nUQeO#M@zuArB~P*tT`A z+Ohwj>3REiy({rjwOFOEz(UPb($%uOsrp)-@SGtU6~>3NNvzsAE6ipEGR)%P_|H_h zO0JMr^x$S|J~4aA=hPn2l&Py{ZrVQzT~flhhUJ?-iHv!M>Ir)(aH_e&A7ISY{S)E3 zcAeeX`8D^tzU@TJsECzlELD15c9wYi#%u1kV#kVO;`l{BqoYz-4L7Jzi{u?5(Pl`G znGN#ih^UqBOjGKkT(h?%wdb*1Y3&klEK_EjY}gPb*noky%h!;W+f; zYizs_7=^xAQ$}jFzb2F0J=jId{n$wt(%L1X)H?QAq^2V$oHX0XCTt-~Z8UIuZVios zf|(T%m`Z&canCA9Uo&p0dx^9u%<@;W-x!i*c6!Xm)L+4zmm4iUBT{F};v3RMW7u5C zdz&EV>7}eU3mtfK2P{ zm)k#`ITTD{&nf-C3gZ89zyAAL4B|OcWs}s_S?w%tnuDvdXD}57naO5T0141eH3)kf z4(1H(MXC+m(?|*P38vKgRo2WqHrAy7z*it+My6lt^L3Owj26<6!WS+vabPM#tf=+z z@*TLe1#GAytcJ_Bfq$ab#p;3l>d+zxK}8}SyXN0e6zz$jwP7z+gdb^+N8;h;n27E< zXPcal?ZO&sw1@otya)qQ()1zva#KYiHPhLfn8?s9LQCn6FHg>!X2lZsVP%2h*ZN9@ zGh9=D+hni4!q$3arSkY3nU#c#1XC3vxY<>GAj^H56{DqG!|EkQ&i$XiUy ztBsqxuH#nPjYZTP`N-J6viNv0+nvPjz`YZQKk>=ah7UaJf{m*MQ zzp;B@m@-(1kyA9%P5&ZD4G5P5eSiYUx>fUyIYd@LVR}i<_t$-flJT-vTxJ*5A85Mt zwbw3o6EJ9N2dS~b1h_k?gln?d;KZdn_!Zl;zE@5~GCV_4;&#$2iR*g zhX-6YIZ53zoGm5^TG__iLB2|mHwT{nx%b2WZchK?FTGyAIkQ(>X@w}JPILABCx1F= zQAV4zRNEeIKk>k9mJLo0t^fSN)3+X=$^&v4QdO-6n90qtNKPc*aAkL#>Ohz2BTZK$ zKS5qQLPfKye55W0DJfThH8IG(D|<|X`4P2CS3T+DyrC|ju#OYen2EH;_2OB3bZ7Sj zFX)QnZ2Qp7e8Y`ur=YQNU8Gu>_3w=)x;RpvY){I@3)ZT*3b6#@F6wbx$A4JBtl%7fxZI9VV4TaN|+u{u;eESU|C>Y z)V5Z(IwT>-(+*NFU;QA4zN+O}b9g2m*z^D( zLKSOB*l4S0qNk){o3`qcy-0mJ8(I2n#y!n{9gB2?8P`437fEYgpn?us|{;?fo; zz7qAVpc?xm00Z?^uRtBQy4wJ@l>goQLX4aB`t?<`mj1xhzv0{zEpnQo)zroY@&lKjVO-~|JIxr0x#kvQ zCbGN#wp(NeAkj2~1%7IS z*^lE+VR-Pvy6wl;nRBg@``-6FOd$ z%4#?tk9`A4XY^LmZ6Pz5s(DP@`f>s908WMB0&Lq+b zfH~w8#X<~E?%DF*TZV$Xx>`z2)M5`*Wi-z3s7OcRPYyE}^F7+7nVcu!$SkaPh(5rFh zja7Ur2qPa0snl=do}Q1s&?@&gD?saAtS}?(k+Ir{CxLc}5YIoFEIb^7J=f5+>}v`o z$bk~;mz;^-`@f{TCKps~Y$o@M*BgC_uY^Q=ziV$Eri?oGTKN{IxM<%u7q|fzZF#AP z>#K!ZhU`rmo!qIck8ofr^(Fo9;p?CLrPtUu4rirB`J~4@>4tjY&+efo04%Xz-(E0W z`EWDV4`Ml7P&6B*{oE_eCY{XGDr_C~ZrqND<85Z;0xx?51ti`C`>}dMVkbO}Jl3my z&qnwBy7%l%U^7&|JjYBB`86TP4!&BjxkEr@Ig}N0eIA=fw2XgEuTl`Mv0HZp#1uY> zvHYvi>2GH!IRJ~BXyBvqvEO|;ppWrRlk77k3B-Oe)=)!ke?#4NoGc2=t-|z?D86Tv zNtRdaAOa(}>ll|&-_zk*VAxPJy!SN6c4*j=`e<3uH)eU69Sp0spP_Mk4{F|#IU2M) zR#n4S6Vp$q{k;;ly^&u5lX&T-gQK+$b|aY8Bp7@Wt%~=%HT%=b#xEvEfmDeGFK+cZ zeeaB&8ITEYdIazW& zP(8Ge_eiBl7nKx0W`nQfIoJbDs!>>&zNx`!tK&YmyF4>L?=1wHcNbk929&Xo{#h$*_L5~ZcKr7oFMB(k)4ElzxdRLPOXrFO?t85%l$qe8<0 z`Ds3BBAqyPSxMbNX%wn+QrI_#>e z{j22PctrihBjllO5QnHwOGHkV5&n?uRRIjc4?W^2R z%f+?^C*Di}0?+~HuqNpJ`ZnCsu-|%@s=E$>xQ*;KX8v22O9wPBNo&~d za53h^2ymD06;|33gl>#{{rfh9nzgy*0ZEYS@cvu{@%`h+oW;LUWdGsZd_8YmANZ!U z{|Ot9Q(Ldv(`8YB8GuB+>R5Qlh9Y-$nYRkZq2ocTEWfSWDK>fa>dI^BV<7OZqV4MJ z8i3BzjsM$MPd0Uz<6C(LEVOd#EEwQDwLvSt?QP$RonAb`pcW(sMW8o45GATp$!0BT zPyhElPHVd(!fnE`pR zWQEB$F27$?UqtfWmp~piZuw38e@trmP1e-gKa6D{SPk({vV#A`yu0p$!yX$_QT^|6 zuK#-VzjpoiXkULB{9kAN-*8obxw*eQ{J)yO{@uL(3T}VJ_1|T+UH>bk`75RQE2a6D zF`WP3$`_aLPse|o1@Ifl$^UQ5@Yk#VF9q}8lZ%TFf9?8Tu*L6oI{x1gnY&?a12w+03bkohXiY)~_)x{mVTW|GHZ?B-8JNJ);( zQ^tSAyu~i29<_ z`^ta|1DN9%7X0p;1|tnVUKZu1e;SC6lmPNZXEaXww=7TW9PhK{Q^tg&a+MCk`7@$P zx_yz#O6&OVC7d`jEQc*&PtLFGG*>;Cdz_?(z@s6p9Q*=2UGT%r??jL%FJU6}2=O4w zS)PlQ(fV9K@RI;N`D7d_Akr#Wce-w;xW2p?4+usghbAimkzfPfxcag~4?7H32EOT1 zT&O*4l0&!1byrmX)F^u00OEJlJ(l#h7r%N(%wPnFlPzL%b%dBK#VlgDJtm6hnqrZn zTrV{QQt|>X9!BvQiwWlKs8RMtIW%j35)G+Dj4$$9zvq}o^y&8i@sb-rJ=bt$W3F`( z%jK2D>wk{u5wIxjd+&L<4VMi1`+Qf8!*%x`apG?t7dHC=zlDrDm_9OEWfJzPDM%A3-GjS5emp|5-aqvj>PH5OKp_i7fa~Qk< z%E2k1VIp+2lx7GFCvxpxsXPPU(Y9YD_ys-4ox8nQZ0 zJrwqxJAJBk^{In^UQK`X+wW7|%s3(58&0rQ8(xB1AMg(#|MA|bo1f`31xIS0IR4nj zP>r?_8Y&=yndoH~I^Om+5lDd}st-0w67i=aeH>W4_3E78?PfK@&X!>T;A{<^ygUW6 znWRaOqvg1R+~!3xz6}+`jXsMFmBzJ;3&NYgFx%-;jYIeu4|oU8PLDfy^XA6D_R?f! zS^eorya@p9#_(^#(QpF|)KHpz}@ZLh9$h)_|F{2Qt_G?&c?X zVQ`F~-hJ9D9*do^;p2;4b`Ynk!^QaKNjGF-xy9&_r2U)s91#+hUm`C=;N5{r4y9x$ zt?uy6y#s#D;h%%qI}Lnfhk1J3ceaz)GucBV@H@RvSM`xr&6Heb@0km#?&)|eL>dC^ zton_@Ujj=(#xpy!8EM@qzq%oF7AC$P=tT9cO~MTkiVOF2L7x-X3V0v&m378Gi{%>W z6-((q@CM8K#OJgj$WdMAUlP^$BNxJ!;`-NCzvT<1zlp@~lRhvzCPL$NZyg~+eG$Vtjd#@Y+ z*tUo`qDUuYZx;cQUMnK$XCh3iBH#5klG#Hg>aUb|%KSpd9}E^#h(f$C1o4>T?CMBd ztKW8v$kdIjzQbd?e!g#auBHsTlA^3ng9jsLPb8qmX;Sp(;Q7?JbePs$HP>cJXpWc@ zZ0gtd5U{Q>Rv9^6+vu&XMNnZ<5JCA#TZ(gATp{7~V24Yp}B1i0Y>#J#Frx0+Vmi(NaDOP!bdo|v{r zq^=vowiIB<^Rt7Xm0E4S^|F3X(sY#(XeXw~axkX|xT&U<&f))9o~xE$NP(I>UbK#* zObox18SHbmXwOfPSOa#~zG1}kWQG0jD;>r+{q6z(^9jdksW)YF+K*^agnia)1E`ZX zfA_m4Uf0N05ggkyYu+|d?IeB@8z=1L`fGm&)k6dX?+CRkZCP{ZKH&Md{BfjQ?I}Kp zK4_bOVHuNs{yA|P^*E{hZJ`p^?e-hw~v9P&m(4I|95xwpM9ztG3Dg$REeNh=yuA|UlY## z^3{0xrHr@z+%E)+?9UESfk0%LoEu!RB5B?m1{}%tarM`*a$@#H$mFWtu&K+0h~A~M z-G0SDR_%)SAt52Xqoc7MO~mXIFb-qM566HLHus5>x2&RKvCX-Qd)RrID?jxn^&LZe z3!dOtl|Z>_BGJS+S;OMvv&&oW*0rL5En4wMYaI*@BkqMjJ7WsS$)W33`hvHJZ?P}t zEGk=tpRE)YhDzY~vaoJBO;?QDGUs=*BIuLqy$%*>sd%ifGpiTi)17SwHUnwKpfLpG znrE_tKJ6c7DiS=qnX7;L7)XwlEF~1U-Zg`LBF9D`^&^gMP>Z-%K@y4HCIu=|Ch@m3 zHSE5pPkc#p(Sj9A9>SV5oyyxg!!d$x9dz`?-{0L60`K4>Y<|q}&k`SD(ubeS_<;AW z-6ioessVRf>~6C+osITDqBrs#N37Ly|V)$G+J|=Pos9brD z0JTtMADs`E1qIzU@VA=Kf#8a4f_>ACnLasoR!j2I)0257(Qgkmvj13AiMIqLPb>$r zH$&X&7^p#1{l=hG@9FZv*Hm4{L1N`7Np1gtf3)9W*s1nRfXqQ5gVM#wUhU-2Zm3Tm z0eZLJB<8nH54#1?EIG`T#8+7D>bBZ8z2FC45?w}&alTqda~haB_hoB~+ksx_`pV%f zJA8r11bw4$D75f+@H;csIPDl&gJ@ojb!efrFrOX)EQTh#bah$R&p6ENU%!cc^eh?B zbobXrbpwb?8Cp7T4@MlL;i9(z3&|$;#=u8P2U)q!AK_%_Dr0PHh&2%he2%nd4Hv@J zEqMBL;I+L~7oGkyMjlzTHu>W<*CJ0hoEIf$`)F^g}PN<~9kKip*a^m(XIAJ*Zh_Ik9dDURF95ys)~_KR)3GM1Ev0M^2|9G=k43p!u>;njqgzk6+{nBYM8qo&|}XE8isK=g^{7!v(CM5uH4Y zC0^piSB6&Fm$mvMT@$0jeSPfnnvSrm;P2_%|NbEsOTt$GxDYl=iqh9YU<`nSOC*cX z`N@uM98k&5l+#sfoox*YQnQ(=<0to4x%kfOl}NqY*(C9Z+I96?+5OiEf#b0KaBS@Y zGG_N?swv`bk>fQbcMd4z(pFPq%-$ojzKdPK?4XYn}A1!AEssn|;*mz-J_uMxI zmeIx>#3JlRvl{qU13SZu4O&57

    `uFQ=(Jk~xJAy5@tQb@NGu9HYl$&d%JpoKf?)R)GsyLAT=Km~gioF$s;oZhwnQ$4_ zmALYOTrfiKw(0mH51HE zfBH_G;d9EZ+=e$K?2Y`W1gBSSq<&RK6&XNrmQIt7ec+p^#e1icsGVhb{Zk*7ZDaCm z5=ZjPJyef`5ZMA-b_ZRqY?9pZBi(}Z&@=0Pq$s%vyPm+2U+YYIxB{+tV8iyR=7}&1 z&dS3NUi{9}O77cqNqJ=+g=6ykRuyeCX5=!64XF5joxzht9iE3tK-DbS-q9QlttM_Oyc$ znDzJq4dKmMT3hR!e6h3xJNIVQxRV(g^YN%|ryK7g<=dziq%Cw;3BgQmcP9!u@&5dP zM7PDSwH%t0xF*Om?Yu@I<6vh z$MCN}`|^t`$ydHCcYG_=S&g~sS6Z{?x^`2wvd5)=%GwY^;?+4mcvFJz3)1ltNWjqb zWIR|G<&_(6S*UhGxqb^dj~xrY<;RPA#RcdthaD@9ZfQ=AZHBLh0xh^*DK1PHQs^C%IRf zPU&hy*O0Hyd>lKQIA&OT8ZzYIk!m_cEAKwVP3?u$Hth_%cBRLbZ++(NzAh(He81DX zzw`bWSFY;y<~E`ZVWS`iLJI8>t*%DM{yx$VUR`c+HcczOMN!_rQZ@0j9-OjP^8TYAs%F)T; zPBVGKroU}ZXwydo-og1v&$*DBGGwA+49;QJoj}P}Js&n9FWx@s&X`nsxU-*~7J_S@ z;2>#B!SRL(2Y1qQHD48bt;HbpLgmq4WqE&ZP+fo0CVm9yN77!0ovxYJ+KgW}en@Qs z0>KGILEUz{&RaDI|M|(;0sQ>Oao07GP2Y*bF#Tv?tSJxin|?s`xdGbZ9UcG)d1eVa z>@8R)G#m{U z(r&Gm7{-30NZ9FiYv4LK)8AmE+ww{~ag*X8Q9ncHQCuQ{vOzcf=pqOxKE>7p0h~}* z%Ab|+)Ah|nw0D-Ak2mZH0X;#m?G@j{!O?XcHT~wx3p<`b)tI~v9zWSYpV_)^wUW=t z`Tto?>3jLH((P=OT>cikLOHoQKf?zP&aQb|Xu=^r7OD~*8E$VrpZijw+sFGGVV_*J zdb4>6u_t#|Oo4M%Cy^fI(<}3ybQ$)SkLStABe)Bl5npMieNC9@RC2AKy;eq_F6hKy zoBa7gbS+*(MTKd;i(vjzVo(GriuugQ?C@#_>)MRKk)|k$^KF+-FNl@Yu%c@N&3$Y~#5-EGwS!<$Kg(~rC!V_IT zogAqh&)Ng@bai^Y#xsD6ZA;sWD;|(tp$2N}ynz==u;d9hOPL<}iPKN<%>nK4-meBR zmgbQ}Pcge$;0DcCZ!IWCv!M{X7s<<;(5&MTga}!;z-rzmNbNbIHSgQ#XSi@s$w8w* z0X>y08Y%(7*X%h&-<>^Hz+bU!y9GB77S%qakCDZn<>8>P-kNQlnWH;*zW}}-#4m6j zwY}}eJS0!<*EQb~Y{qyL8?}Dg%wYF4!Gc*WAtYQMPnn$n{S9ObBQ)!=e-Obn2wcMfUHsNUD6q99*ETk9eu*H zIKMoWp&b0!b51Gk?)(O)&X{@zBGtL}OfTfS9)}pyRM%5xX{L~3-g84358}JCLS|PX zlgp_Kh^SpiQf_zxT#OMu@v;XDB?0=!KkuzzN*&jV2Tcndf_-CQ*y~U6Sp$RX0}qr?5h@DHoX2_R(=0X=?0Jt^IHXa%DdPUBr0^+_3`JM` zm+gBGjF5G48_3M_crP&P-#9=*p{;J;^IIXtbbiYTdHym`+MpAR>41k!Dm=8+4zd$J z(JFH|cMFEx&E)kj`+VQuX1j3CUp<4o70egtzq?*92$xS2IXEcJ_U|w_tXs;LfbxUF zF#yEn>Nl8Bp>638L_n-nbG2X zlZ7u)cMV73EO_FGDhfCgq~dPxb*!yYw2hsYc30pnuA&5={ZVeTdf*l9>Fo}7qOAmG z_1U9P?|FvF3g%&{u^NgW_TBub^!&#;L9rq=wIlF1egZ52q?s)P+vF@257(5&zrWgn zrmUq>*DnZ#*0xN?PDR9MGBudHsYkJB-U4FLZqCDbD|;Nd+9$De{EjBkHl-zFCX<&Q zvl3?&^_T5&G}~(#SY#km$oJ8IE_EHuq_o34PR61^93py#NsVp8XNx>zGG4~UfU1yX zB{$B$%tnsO;dQ@0w~g1TQddLC7*7*LNt>GdX^qQj(?P>Qy(P~#i}CM{3PV^KaNsxy zGkoc{gcpCK}Qq6B+ z$B15#+HJz2TF{Zad*=H!Iu@N>&o9?mFw^e}xcI4?zUy9VPB{&1y2wa7K5Q5-hk7EF zXMXhvjg=QhTUDHSS}l$A-jwWK@|-bTlyuQ>=p$Fe71s)kSU;TJ@G~6u8*gd|K7Njx z>VD!p(M!yAO&;LeYZb<1!8d|L>-dDWM3Wwl!vWm=G_w&z|JwS-(?b-DC|A9(`&5L^ zZu+L*^;wC&Ehi_?hKMBzg2T?Xqv4%8b`r)nZlB42;V!{c>UI`+A;F-tz187BOr^9C z9plRw;#r9kJMTHF+N;9k`=ox4j51>=3}C9W$cK~I?JX>ETM3_e$v;4y+IF5Kg>M}! zJEG=~0s3SQAS>7EU(aSVW`+9L#@MY@(8Hh{<3pT@kWKO~>7a|C z%>62&rG8&5R;aqJ+d$dPZAulARt&t7F7rD6Gm9H`7 zOpu|7aaVwZ&Vale|03MiIMcy9*y=qLPo^H_r(@6Ft_VWk%y_`89rIZr<5kq3QI+vu z{&4|_KE@4xJSjo0ClxhrTg$pekQAhVNiIB2D%qZogA{WTtIs6 ztJ=sok1Yvrx{)#qm5tP3;ME@k{5(^?C%38iVAq9#I*4yyaHERhAc-#Y*%?-?``wO= zXuUfX)}y!73UnxGeRh8lm!`D_O@V1g>i!vW(XQ2(SR01H4IU&RfQXhJ$-r%fA0kq- zF8M9*q-Nnb)SkJ1aMNOE*+OO2*Vh-duRg|B^D$I)--p3iYgId~xemfM(6hP~;j{%p zMeAbjE6j@iF2i|v1%I z&&n{$N9XkhAX2gauuGY z#dH24o0~9E>Y)?!?dk;BIdg9FrcATbsC&q9&>ZI#*F{|c#bgEF*yyV`VPazv9fw;8 zIQkr(GpYBD=ty&`g%1#zb;TjIDxJO%JyE^zObqg z6FW$h?SDy-XW%e(#&9r1%kP2&n6J-#Ifx?NX{U=fS`7s(RZNXo`6NCsjOBCWiS6ih z;}0YoXydP*#JG=*-%5CgJ|?*I5hWv}I7c8pdq@cn`hZ}>xzl!#=5E_I9qEg4v-`dq zq}K)u#FRRK*2(-CWEoU<`Jqn1zMNa;v#fR=a%S}7#RyvM0sZCYCy<#I5=EALkrHYo zUBgze-TQGnxbXaekBRB_JqQtX=~f*|7`^ORx4mv;prHl8g_uWOSk!ilBz7WUJvq0J zKNx>TDw9WHcF6qRZ$DV)VrLdq069qUq7EuSC2+g+cW@J2FRbD=Fr$%)r#(P~vuj(KpBgPm| z*yfdeTcEw(f@d`Af8P$+c+dt975XXF757;Nz5BP2bp7o)s=1DChys_zH1`zwu~r@n z<2OS!4M&}pyT;1wfn42u3~tI=irs~not^3)pMs7|4(&l*FgG$oPeR@IRC_-V^H818 zT2#r_1&mGbf!I~86IA*qDrTC5yu`A0Ed=+*jxgee$Iau-7Dzr;7iv%t!nE`?s<(}q z#l6!b{o(K@7lormZWAlB?F~VgG^MuX>RNj>I*BTv?EY7&M-OlwPaYj~Y>(}kfJNyM$i;7kfZO<~pJD#%vjkU4WQEN2PFK{; z^9j#4iO!Yw-HO~5^gws#?i9sr&)HhftK*O4C((EVA4hMOay|y(6WxVBaEOAQp(c7> ztSIE>fiCIOrsAa#*0WQkql0xKD5iN6bWnNsB%e?2@hS}?I$uE#qoJ`!dQ?}!jl^D^ zRKKyZ!lMHz{i`fWB%&iS=40hWw{Q3Ldxc{ z{OP5YUIZ3v`G|gOa+qSt%_FP2CjhJR9z~4VwHSn z-xsynNftc0F%jJ1gGHBoYMdhqPp&h`ah`Q=N@vCyFX)VgDHXUz_C1* z)E;p@&g^VpOyqgwln8nyPYc8>qB@(twguHNKjH;9Jk3gDW?oQYu;RfW4>zQbTPw-o z)Ime^D39Jlm}-c?N_OXGIu1-`pV)HDB;%P)gqkduQ+l~Fd6SqB83*xwGZ&fK(Ov_Q z%=2yb^RPSVDgr2s@Uu?uNHwEgxoWg2$n?T0Gz&IBaEFY7Qh~s@A}3~@H<#L}lS5a{ z)U@JJ*LxB!J<=!&vDbI3@0@S2oK6XunLTFR@>;XxWHZH{HyMoH=;8d+2J;??w4$BT z!kJOU`#wCvS^u#ug)ojZ1%MnqPwejQW{ZzL3w&e!#f7{nrZuG~eLc}osAKy zpxf}%j;>TT%XH)e`3|C5?U+}k0cqwz`v!3j0wac>TUV6$9PeMWd2&)M5KfS;IPU6~ z<`z^fEI+&sHsrMO8?_<{X5i zBZCxDjJJMnIt<%Cb@e{aS@a6adz+AVbkgwW*TR&bzIxYI>NZ>o@jzbY`b&Ba+NkHX zUVeAVr7SMY^;&D$c>*=)%|_eKL02*(`_}vSzgFm$yOcX;yCM(w_o&4?HC}Jb#-32r zc!iuR>nu-xtzFG!AIeH(&p^GVmeNlO@A72XMhH&n?(%}sFlWF`=&H_1+?MUZ1_i~JjyxU@N6-ED z?$(ka)S6{}AHii~BJb%d{O5o4{^v9X8lO*IT{-knu6#C}GS^@)ecbslLH5L&_0*fS zG8j(~Zx3g2Rld>|m*Y}aU&+DYZV=hrK0pR-*2EHx`>(jT3RN&T*YzqtdR8#mrf;VI zS(MFKRCQg<7~I0uq1XG7;BwRXq@KfUFb41-K71$T=(jjI6%oM&pePj1lJH{4?W(^` zovpWTk~eg-ldH!>Z-TDp+y4GO8wm_FRikUXTS*j!zCtyBIZZ%87P=M+I3g`@<49{? zUuTxt17ePF1+J(Vj?6f?e1+{~+|S#{j$DF)k1#s+28@vz%!1iyT3<~D_$v*n*z+yu_CFuVcBG!H?kms{ z%}xZ0CrC8qMW5~lkqE{h`e@^EyKanDl@0g#O&#}}ifd_oKDRdtYlq8Smu#UHtE<8R zZVfw$hD*JAiEPz|pyHdm@>nUWZzqGj=ck!4+2IakZ)NbVNDVW`llvkUN$&+1V!xVS z8E_HG50X^f*$@XGF7PHDr!MYE7YmLv*?vpMkDC-e2$VA)A1npBnCf(U$-d z>C$A^tE5Lzi_800Ozs3|8iNGzMR|r! zW=7t0K^_%hi;udON}ywG#vJ78N`z?Ym1T{V_}ko8V0y*LEBTL5lu0DT=UBCEUIQ6z z_4OXpHHI_mws?5@Iy>tdMq3h8waL#g%(nC+{DF_pQvAR36)TI3Fp7{DFcU1r^5k1p z{5YwQavkal%G+UQew!7)k@u&N379V+98&i|(|HQh#_LMi4$$U_b%}4fJf79}rfiDJ z(oLU!Bu7R^xj%E)dQ@*OWJ6~$uBxR@6exR;Xg3T<7@?*`!r(*)Llg)rjFoZ^TMTk) z(G7y+RZfQs(c~_*7flzCaMwO*kj^;v$DAD%xYg%A{6TN)vN`?TepuJdUms*J5^k-* zzMfk**Oh$_QB~%gm>>1!d zfl)nrmrk!iH?Qfky{E0>;@q~xmW5Y7nrL7mkB`QC|B?JGE7FlNrs1&5F4Lwjtp-qp zRGsHO(z=L9^W2d}%w_@Z6}@sH9<83-osxJg5;jJTF4Q^c8i=&i=8KIAwuT$ zye*x=3s^3TJuo_1I8*1f@fMW3ag6sz-iII2ZVuEA@fe7bRtaZUWJL$NdA*d`AgXfb z&$}+C*q+W*8!-}0tkNjZ-Nvt+bkz=(N{p&cf3hRdFjrO^UZ4*bf!8cmJ0F)d2Bi|@ zXn^6pq~bqJuYE%lXPe>sRj-Q)GF{s#&K{gFa!ovuAUPD7!=}`9Q|zkTnou=p{Y0w! z&Uv<#Qy+xZ=lEk2piw#;92Vz}8n^RV)t(6yJuy@kdv0ZA#kR?`o*Fw4@>=b|MVM73 zs8R@~`gzd^Tyf+@U88kRR^S@8NxSa6v3@6J>Y;J&0$)3J5A}pgkyLH_Sb>g`QmCs5 z18|-%>CMzG;1=Y!Vx16Wn~PrjBBLhxocW-+>p(N9CZ&(($Yk<_bux7j zMfNM3qILrT15MtSISbSs*efPJ$ll4be%rI#l|RSSwWePhN+$NP@D~@JxG7|42F~_C z&yGVV(n;V~9eNkd=kVEXUBNPW?AMX^c$#eMp0`e-qO>Un&GBLfQx z3p&M9>U!YZ2+L*H0;;a(k)dP% z9UHrIJh6$y9#v%aMln-`7_vajaRSk0hi}A5$WTV<-=!7LC-Zs zc-d9A;s>6~!`zp56#2@@z2f_t6Tg9@e$YYuFQBy`%dXiCKm4Gf#`jnsS?uA8?jm#&Wi@i%#JC z+(|pjN_WlN%c!dpLYj=$;waYbk6D@S_%fF5gz{Gl^Z%+-NM3%ycXbTTCMQV)(hkZz zEsN@jARA7V9tjqznEvZJ`&JSx2hky>%l$p;W_R+w`G(J=1GeIi64Q^_pHX)=s882bclGvl`4RW&2P;(%7u*k|29dFXIQSri?7Jr+mbd=N+ga5>P&I0G z$3X(3*mNy_8sqrBCgX$j`V1tjC9HiQWMv-azlU=Fc-(Mr>?YOSw_?w)dhV|+*U+tJ zpNyKregbk$@GtB#h7yq%&*;WdplOGCpjjRftq&P3rzT5pczep5s1)+Bm&evuV65TR z*IShCUp~xzM2PT_Zz;)lab79+7rX4?8#1(hG`(-YL_;H0NVUKIv{&+qgEzxGX205^ zpAnh944RK1reNM@qS%Nl&wSeUu|{;PNR?@R7La{W%W z3Lr#LJ~4QE`}S>&su3U=r7}Eh;anzp)b*Vouor@>+_P*L2nJ-z{Q94Hr4TCY$sPz5 zR{V5!3q@^N1iE{bxYZP~n@>GfDm9ar3lKRR%qSQR}BAmGCc4J*77Q1x$Pku-zy>+syJRg)2?8c|&Q%Vrv z_XbqKivS)otaI-7i~4qYqIGF$X)qHipq48uWUAH;O;|~hc11arW-an%TXoU!T@_UQ z2qV{?PRmMF;ycHC1e_mL6JO<1A76i=kapYO^JPuGE97VUkwf}bufvq6R?pdwXcqQ_ zYwS?Fi)#m|45u;ufVkLM`jX+xHkR)@^X)r}{!s6Q7mvBiAhzEASMSs#Dhbio>8DvQ zXZ`Z@;ZEQ*m6d)bPy-3R!|ffvm6QoqQ{k%MfPl-&#cFOL^TQj+o*Fh?Jv=)`>vott zv&QBlFW!5((1%s-FI_+&kgA%mRZcB~wJvw%%^Ff$D@27pMR=r*HaiXOvFfU@7i#i? z2H|&?EqdJT!n&wGymPu5%8Uu0e`A|p2JTp2k*`1%jL6Ik6`F? zlw@So1_MnMjax?lV;R?i9k=EgqlV_mi62spxmXHBSGESZ6VNRI1XM>nbHe`EWjl4+ zmc7Zo6>oG=&bR7ce+tnY+tumvtzHn^fG ziXcoC5|@3LD=Y_P)$+9#;t7rl;1c}8?qcTwjz>Os-}q*!^&;mc!nCJ-$B(`)GUX8J ziIRUkD%Lf@8lz1R=@)2{FSi`j5$#v-vKp_*SE=}FPE^EExO7`A?U|?ooOfirP^B6? z+68~0*v_ipO8&>T=jd(Vk@)qH)8e=KVNfmZT+a4p4 zw{L~Nv{^)?UW(TyvtX*&USQRiGGa%TJo~_Pr|1_TIt-Ubvua0?`3ij7^!fV1=_@Yb z7=_DIn*3aLi?xXf>=&B!xKfmNVaLXRo zXp`m{1kzx~Ib9nfNu1s9(ip56!-)laJny>%ahjX6fPTB@we%Tna7DPP^&3~cT`jG! z=MMxObS<6$Q*e0&5b;YEAU&1Ol$E~=;eFZU12{|~=T`}ndrk#ZNcK9bH#Pk(W?6$)(;mX=ygJ^$tb z(gvsUlO!QK%_UA15YoQs)z_F>WYY-NO;7s^Xl!!2w}E}|J2ZwY-68HP&=r)cJ~EjT zORN9^*ZBH~6n&q<`|5>om`5Er?b@ThA^vEPV#+KZa|mNNNG+A2!h;@VV*&>ehEJ2EVVO?%_V?2^O0M<+ju0O3i8k2|)XjZ2d-(3NRhgZ4VB#F`e)1i#Sv@h zE8j$5dj8&zh}FX_DNrxY%-HIRgLnw9IL zd+ZG&D zFh7}NO1^A;bX!CJm5NW?8gR%yns?!qwv%Iax~#C<)t8Xuq9Yz%&jg*8NqV|006%0= zGt>CKQi>%uKkASU{b2G_zK^fd7eiOu3gcqf)c3TLjsaO!aQmeD=u+E<>985{6x?cKD}9dw4bS&wRa-r<0%g zy`Zzc_0R_}>)ML>^5^^o_y#+yJOJl2^91xhzJQxv0%xq*X-_PePN;0FzN77gcZxe< zqDUdD*r99Ko$q0RvG$I;2ZLQc{qzXlaQ>N~cIm$@iI_d(QUW zv+s59d;j~5-x!V|j)cLUuC#u$fsaGeygIZ*2bI|_IVV@k0j3rIhwOU?Kk8fZZti@0AjLRuNtsl3Z~yRi*#0v5(;ZrIOl<=|knB)_tlG|R z38!#FR#u=t$#3?uE_r&(nnfIttC24 zsDuqjlkumB`n)bFpXTmi#dn&M$icdv%%!l8O>-Klwmyz{#_yD9RG+jQ8xtP&G{s-` zg0*J)szIiclark2{s5-9gB(Ny6O|~kcmmhO{x9WYPdM@~$Qy~eeM=tYD?hw%2U5nh z{ga}R%jHLD@{u}MYC@1`w>rS}Qs9gCFKqCPea*C+qi#ytpL``-u{w1L>%G$P5q}U>%6~^=o|qovzru{N+{Btig~gcs88jiicLe;?a4B!9=>NAl+eiR zE>l63do4hJR8#4;e;uzR(Q8w;v-SXlEzCQ@7!{RZt(jMWI`+=EJRRYKEVNtQZSzT~;RBZcp!^RU}e z9D35jw2#L)ELJC*sEFp7iYN>vs3nv}jxi=5Sz%>oKf0gS$2KQ81|_Aiylyv_>(=-` zvjBYPs^u+>gMJWdWvV2Ec(?a%p5&Y>9Xg#gQBpIwVYv3m7yaedLJ7C~Z&w>yTxmQP zXM8fRj|}2#t^AH-b-u}RR%#DiD?3=icEVhn5o^#n@HGz#-ZZl3D9PTtX@Vveo2((WsS!_^r6;Cl9+7PENbTzd+#hFNQ)l60W7EPHa!G~V6{+!jfPm2S^ zQ(;QnuNDoHRIqva!V~7YlxEW(0*+Bh@(L()a<)<8VAF+FOC+x7BweOmY)ZE)?K7^0 zd91lkD-AdOeyV^@CUme-;wb^RLhzeUC*uIJNNAhj!+{~;VEz>UXY(4u9SYv zF*~XP)>h)%wp*VizK`L#e|t+btgTQN_K)2dr)TjUQ*v5}%5wq5{K|QDO}q7QY@4CS z-1$zb0>AU*JtR>>ezrrapQava)VO=Sp!%PiQ>nULTwTMwacv{7^RISPn}Oze=cZSn z{VdWWu|DKCCS17K4=5dVxD=XF$Pjr8Q;Gt#D$M`o;4Ps z@N#rwMU`>VLAUgTl#`}X_L^8J!_893&3)eO)t5XOZq~P3o73s>DHW>fKyARo_)WA+ z9P9(?68r0#rV+ymEykkDWV5r`@BNPm%c};Zm!WCbOrMFLbQVAv4M0a83VtpfsBOQt zJel`8__5D-;{!1p8(YB3)5C6{WLO2Q8s@r+0Kq?2md;Z}wr0498HR0)yQj;gX9MgK zO;FWd!ZP)b+U?Nvsb|J(6xwc_l3HTemL8|zcw(NN3CcPw zv?DDgni@#MU+?zL1-h%W8=X!oU~kp0`LVN*)ofylU&Y$-`nGAdW@d1PHGaD8#TZ2= z-*6U{<}OThb1;ubL$xwD0KnYAZoXGzmrDLZ_EQe^y_L2bYRX3i@LM0siBZSf+SBW@GqoyG|c zT_A*ux3lo>-J^mw6r=-y_lr6s*uaA?YDm3N%wZ2{>sfd+vcNA$Sd5ErpZK){hfsqVT+cw*oOKTa?(%E^YeS3r3{g8uXvrMK-)T%brj6eu`YZ+DuoF8?QM^eLk~> zgCgRxm11^8E>Eb})2*fv`>p2QCjF_|Gk&+a%gr6kRB+Kn7(gppPUh(r*AvsTwkU*? zRA(;t=EdEX%8$|*g@Yk2?0Qjf1 z%_uDFAWm*-Y2o)K>+0lPhidc9jn6Ny^4={iHpjQz6QD9J^QL{ZwH?iE|5X=+rvSDvTuGLZdcDr6ZblZuISre#{Sv z7mS{>3aFi~ofFj54Q9?~^K4QV#y&eywYi%P_mj-tk$dC16xePKgEMIK+&X`D(v|(| z3bmr^Tl8Lit_8Kn7B-{{$UXAt&;6I??ce{oa#A5cD#49WP2ykkTj~b*4ip3V?@Ax? zU8ih}kV;s;sDGN^U$6fT8I>fCAj16vx$-q5J$yz?$NR@x5>f6u5P=7=m=GBRJcL?A zij)NL!8-!oOqlyBm{jW0{|FWSx>iGHo!qBtoxo%L^q=1+JweLVwQQC{ja^%X$d3uR z_BqCo$jI|hSt%#sjVt^HiTvf)*HJdU!};S9{x?6RQq!xkc*tD-<+uLji~HB-Ni`?% zT@1kc%eVed>pNMNy2t3w?N@^Tr(g5vkS|&Q|2OT$|9ppUfcshHFeTeBgX3RU`q%Fb zu8Sq!pI+y0fQx^P{SV;aOgKfaf&YKHANcbfg#Yv9{^r%kzHmo*rP7K2Pxq9#Cx!g4 zUihEBj}i|D*9DAvRR5=YN|_}?_kSAc^n|$h^B)d{GW_PQ{m&mlujViGujl-ym;0Mn zr4GZ|7l6Yc_rLki|6GV*m{ZvP^#T1S&)@eHF=f^p(1n!}tf1>}z??SJ*i@BLIgzJ^^fv)uKB5Fj zGiVRa;)9WzQB`~+0tn96VI6ZFk&g)e`0ZBQ4uDnoVEUmypD^?QunT_yKjOx@U+(80 zZ~oJt+|=oflY@gv5iA%=?VwKe%XmkCn?;~mjaN71;AlAn>!(#k^>tna4C&lpxqUR8 zsL~95iWywFq1es&2U0`$&CxtOv>%SMDqtiz7JBoZ>Z4ds{j#<2kj;*Uct{RqsWW!& zT4eTAI9VX9Z6KX+n-%YGL6Ki(j*kVw>AP}skLk;Y9G|W)4s;XOlW6S@4HBo2K9uYraL*!UWCMGGP*U)}# z5H5lgyG0%w*4W%6HIJJPL6_Utn$BDn|`EEk=)=cpV?!o^zIBL z>Wc9v9D)8a{m}=9laK-AMiR6553mqE`9w5}y&Q68JV3C)W?% zkarbE#VFtS6)CP_FposVt=#>*~n*3`&_wC2JAs5b`}@oHqAy3X>#{nVWkWKR3bY{RO%}{v1h3^YmMf+jHS~SjZ(1kSI@lD9 zHi(Fb;0SjoJ6A^wu#g|V=(-pq!ZB_Iw9R;PgM-Xzkb%#nhPfy7)GiSoIddy;#9E^D z<5TLEW$!Ifr<1?sj(&Z1nFO4S^JeDeO^naPjuz9S#2uGnU^ZSrdcdh~U*4;mSbpn( zgeNX&<;l@qs#>BqOz{~gXZs40j6&KVt!Andb2c(T^p3n5LtOgvLw#9VqNY8OQW+W1JiDPrto$afG>4ba%^c!oFc~aj}R| z0-9B?`W++K3WrqS<+v>*4YF~7CPw2iH2u% zs$%&D6-7PSni#!O>+{qG4!*Nhh$!L8&gK%wa`jfCi0I;+pC9fVu%P{euW)b!C|?8L zvFEzh%uzs@K9Lz#Lt~KEwKe2umd#aX!C%^bwiI*7_dA)}6k6oo56^9gQ;@|Q`=q#B zOwz;q^g_^I-y;l90^006-_ul(56E)}EITdGUhPE<@I%A{_e6bAcxIBf9<8w5EnUyA z6*KavEK{}+8hkOPWNB;YX^VR--}(`x@*Mqjp?Sdk4f5}r0V!gIcHEq9eYR7kK9Giy zMJ1lK#q@97U`m)3Q5849ssG6R8pT-&P9!#tO`)Oui!UD0WB^NI2ms^TMS)u&i@6L4 z@cCyn_+4_zfTVc)ufkN^o(la>+vQi>ovleg-ncj{J5*rGBk%v+w)IEx0E~GQmCH-* z0=w)PXr|3aYrLYW)NUecA*j!ed9A+UF}JW#f*EQK|E}R2p;Dmpg|Vt1Y!3Tuk;!{P zr8EDDWTG?}TPUcFlDhxogA`leBJ+B^L2&cdW5s4$jx#&}v18WrJev?wF&Pb~E zPEnEfss1aO0CkyE?e#Gc{l@~vr)Uf-eEn!pW`e8UfC&Jq1AHd$9u#f6U4aD?@~+c%a8`4W`<^_ioCeMMOh46GoS*7XzS44 zw+2VZW4b(mEE0|SoXi<61rMghkKA)$)O$D2p3iO>O930ZwN-y%idMFU9H@pEX$`gx zevBUQ%a@?tSIq`$$Vf>iU*_b8As!qkn}URL7I<`vWJm5Dcy&_wFerL_x(KUBy30Z@ zg0o~B)z(mb%e2*yq=S|FXmv1PD^f74S%A-^BENwJ!!^^JwL$rdlmK^dQVSN!? z)x_R@L`sx@ffvCpkS%j9HMtubYYXf9>dry|-CI&=;ljLR=~Ga-lub%NJ#|h}aR;o= zp>+0Doki8XbD)GRMpRBwds^{xu)TE3x4P8sZw{J+@nSmn@eBLPIp)r29;-v|ISQ&6 zz=9G9BXzfEe?;*6bZMU<|0Mz--%jnKZN?R>7>;*p;D#ihg4b!%5Tb^%p`$ zwMJW1rsuu^_+Bve&(8A13E4X8olh4d{{R7gqUlg>oy)T~QoJw73@aqEA9$&Exbs|3 z^SdS_&EW~Ky1a3O{hfBPwZPUy@xhpC5ME9}MA{k`=}vxMPPCy1+pNdtiFG|ehcPLU zh1}xBr?_p)gXQg(WCt)9Ccm#t;PjD~U5M?oHX085lFazD8ur;5_EXDPW<)e_D&ghE zU9AHBlo!Z$UfeFhF$$wQEAG_7%E0=}W!Jd%X0M3a)*~Vi#ujA+PHNC?ed?lbmpu=) zfqDb2rDTBPw@Y!8XPDKLzTX~zgp6Yq2S0Z2wO$l-0fXlUuLr#l9*U1rZ}?Fjni1Ce z*H<*DdNQ+E0_O+hPSyZV^Rhn_;Th@PiP+a6nv>PDAiwqf{n;Os>LI~j`8hb0xGQHF z(u!}x0?3&6h7cPRy#cDD5dD1*#C!8D|;g{L6k1vhTi+!r7{Y9~goJ0~8d}1{d@!=(oUU-UX!Oot zH2<@|UJ4MqN!K0CT7$AncOKERY(tja&8DYY%7Ac=S3eDD>Fd1YED&ZH9(5ZgEXJVK z{@$*BTDRi|f<6295Czf#9Dgbo^W;*&>v2-X*NruAp$VDZ&DtgRevz?*h|K39i{Mj~&5%A!Cu~x~lf~In{gCfs4nxnsKgmB@>dDS%Kr(r*x0{ z>Ps!fuORNo!ewvGus$RWlc-e}C$ri)h*YPOiDx}XJ_YAON=cvP%fXjdIl!yn&4_kX z5Kt6V9feRkD(cWhn^Nu5tv=T)ok_N_H%3%4ffiuxGrCtTKIoFz{zCFf(O|mv*R(zJ z#wIOavvS3+Chu(ARknIIcfWqSY-am6Dg}C8+$h6OK+S$zP#Y{Tl1!7?>wje$6nbg= zIv46=1DT>|)B*U0R&t)Wp6aF#N2*5HUYeC19UaqE63~wIG!~8K(bt(DK71HuD`-3p z3r#p|dAh6jKOu7X@!oAWaB&v_->3V=HE(gWb~Nj$1e?KqZs!lk5=omj7qis~bhkU8 zxgR7vpk~)mHiDL+K8s_ss00P^rw2tAnd_dQ>Eqns0TFv^gX0URnlym_f#!ivo=Fc_ z2rA{?Vhh!|j+Fc6+E9)}L6Jr44x6kXwi%w49OhzYXfVP>=o$?U06)a(z8MQ_%o9S= zfo|x4r;ySHTA?R|dscVFJl3;#pWp8-hi$Tcrs<48y6=fQ!!FTcoBgJn4A*Bibk^3^ z_M;YRN+}@s^SHRm@Buj10z>_ry-;46@R_NM!Toq>fh7`aSL;0xpo6w9t z;_3z+V610}NdPf8j&f1N+Z2eo+WycmZc(vTX~c8wO6Su3^Ad5_Qefo3eAK-f(_)6h zQ}S~Z`GTC8|3^({ZLw#Q_vli~4C-&}lHbC7AjAc}WMwThg7!#wJ@!zHKVpXsQSQ9{4zPY z&eHV#Bl2V94>|x}VeecM2fDANQ3*ROpfG*^h(yS}y@|8t%FusY@Y5(Ej}?`$4$&<{ zazz!OuH(vyjEFe3+dFpdZkIW2$BW&)*|cYq^>p?TadwqWMbCL+7<;5*`P;?1i>ljZ zOXr{~-fY=2pS8Gl9}hB*Z4KV{w4csBrb2WN#*Jsg^yfRaNwk#HN?;p}gsoE%;ed>; zDUWOnS#<=7ScUY$ie-zBAG_wFhbOzPmyaXkA>M1OMSgPae6`(NmU^Yvzs85a1+8#G z9tmi_N2afs3gx+UBvWTb+fNd#wZ->3HS^maYc2^6HdRG8`)P&*dx?9k9>5~q zEI+uyW#5|{YtNUy1!CZ4tIUL(y4o1}Q{ZQc-;?57wn#T;Qy^hH-DJ(K+LniHBeBU`8CsCo zJ@I~N&JRLGoTel4GLNa)jugGij^(~y*$@w{AqfMdgG|kxia(S_X#qr27Z>5q^?FDfZ;Z2lK@R$6J#0(sr2#RY`uV%-Id?^wu9rZR}1!<+N*$tj785xy>gmS z(JiqIb%vhu)``0_RYe5c$5c=SAT45t=$eFpSnWJd zF*WIfR&V;KF!37DBn44lNRNJ?6C6}~N}4WidPmGCi)#!PcDZ?wmYbf1c(@7G*Ik*yiOpq=G-p8jb1`21s3 zjjak4Vn5wbBM-vYhX9to3<%HFGF|W#G`}zv?1T--eKHio`IcI56MURZ0H{3uY$v9z z0%(O%f`AUQp<)X+H@7RNAx6JTs1G!YMN_m{6H(4gw0FBG(tUAV78lx|3$`SlaP|hd zX{xjw_NJ$z=(vr;gWwt}PQYK=iY_zZ2vy$m3LWS920hPHP5q}I6H7kqwiSnF*H7I}DKqV!wpU~`Z}pL8%=*C| zX1?~$OY2FZ#7h**e{5rt6`Q-(Yg;nkGhY351{$;kr*ImiP{XB!caVtQ`bO&g-K}!x zALZIyl9EQCB(|t>egml~svuBggw?a8;JNzRrjNe^h~L&3oVr*pV~!GU0G46cx+`&e z{6R&3R;D2FEX2bU2TrCwR7n)mH3U&9Iz2fM&7Pe2D{ZzZa&{m(LM7O%^IUeMkXCK2p%Iq!bW9;m+-u+QJ-sDht ze{RDXp7Z9S&zi?*av$#+Zzr25eeA@g;-vhLS)nSs@kqi^|1N%>k1GHqSJ zaYs>O@m%7+R-=TOe(N>)1z}N0mAaPfW#d0E*A2%5Y>o23M$7-=2nv1N@)#Q@r-1x5 zcL>u=2a!Kc-<7S0=yw4k<`7RIRA8;#S70<6Ru1PD_(;=6MPA{@vN=GVVqO5X-t#DV z;cV5Vv%EJR@X|i1U_x!rK(QYu!oii9fF?U5>dI-?-~oa}AM?Tc4=!K6Y|vL;ki&sS zJu5hL_ioQ-wadb_(ec8O1o@p;cR25Gbe!=?ek+IcuZVNqd#NMu@G592)8;;)FLW3< zWeOF$uiac@Kc~9f|LT2_-9<1jwacd#d^WsYcqsAtt7q&MMqh>O&+0yvLJ6~N?ZN2W zdj7DS3A>y1ZL=Orj8FZz3|XFs`fDET*Hl6l!sgW&%x~xYA9qoVWelAfT>S#=_^8Iv zd)s^t+$9KTiFRF_#lEVAif0uN)@B$Lf$CSgOq@~T%qRj`(K_pfSwvNn)@aFcBlD0y zEZw4}jcZtvJUGc9YD2KUUP%$d>kdg2d-K_EuVYoZzQhx)sjTy2MLDnw+Io7{O-1c- z)L7BD`6BoqvD&YcZSD$ZLZvU~8N4J-rDq3-UF*j;DzE}+=0j7};)vp%w~*Y89derp zT7|f8JODVQYu4vr z$f;d!D7!Ydj!Aizcm3-ybnmM!)f#QgDoHn=BFSnfNBqOpUMkY0G!vJWTPiqcr(+N(cmOzhf@Focygd3aRv0!yvq4Q@&UB+MQ$rMwm}9ihY>ks2Rpsg`fwum>oHv28qW&l zM6rRI#_lyN?;>O--w}J^rahFMmPdHT?fft#e`?fJm2S@}oJ8WlhD2xXew14H(xcmv z-R+q>f12}~v}jU2$H1VOz*47`8U5XD-(VTctu8+9+C9fUb)WUMoHXw_rSP(L0!T<#LDVD<^5C#3#|TEccJ&3`i;V6IKZS4TCm9` zmZS)n?~##N-4IGrqZ}uc$JyR;49(X8Z1jS*9P0cHC~!5jw3yI&2_K!;@s~n!-{RIp z+qvy7mD9aFc5cr7xQN?aRx zxVTCK$JH|~N2a3+G~WbVHNT{Y? zx}`3Fv$-*>Gxu<@R3am6iN5qHgtZsFxNm%}k=a=DyRUiu*wUDmzjEu^r8uoEvr&xs zc*RT%9+_Jnva)~o+>V-_nb~Cy+JXnHJ01IX>bojd$~7sJc;j--t_qY2S1aHL&W0h7 zGeiJ=H&|Yf@f8ixcB7{fc4SaoDZqDon?HE|MPOVZ3)LVqj44^T0@7cBvA1@D#&w5~ zQbIWaEr`9I{$Z0g_bM3diYj}v)YEREJE1l&F}+GeuE3vZi7nrso7KzLj1ykw=~xFE z$Q-JQdJe!T;k1F9_=`Z;VrMz?mwMQ&eA+ct#mxg-i=jEryxO={=%X1&Bj#3kYq(O- zq}27L3~YreE(#?w@9GBB)o?O5p^C_kEE%PiC{4LyhIlSY_UCQhktzTQWt5>25%X%E0PET_~=3^e<7O2 z5}Tc7D=1-=kR+u9t# ze^N3$tH4dmnN9+;sPV?tR;g1j8WHWHdqa2Y_@2vnkv=3NEnxE@-TT?uwE!QM7}Uo8as{9Z1*>s2~(C;X4S z{r5i=kePkV@xyk4FUUMr=_$>PVCENfT`WAUn1FWSTnmU--*P*DH%@?v<>4Du z#7*a~e=~Ul5uN}q9R22Nr4r&j@bKcxgl$L>nyXK`%9%bsnhw#LgHL8sE|w0;8s$`v zQL36YQ>cP-vWsj>{Y&;M*GjT<$GFzXyD@Oif)dO|&QHa!U-$oK0nP6=>@hjtBEx;G zZyw-lQPHl3&zP5nD!Pl@?dLsG zhy6xer^;K1$2&V&d$3<%9w71d0I{|USobuBCE4+Bc8Y=(C#gh+6AWTQo7G@uRT`jm zqn`T_k1eY9Y-zh8psANA8Z*gG%wsq5T`WFS9ITyk$WJkDh}EG$ea?mJgYTU(SRUIJn} zf})y>W3a^+e|Kv+8a$!~2w0X4dSl%LfHS9npS~d9_ln3aGB0BM7$6g`PWwvizkvr` z1P($aZ-$%WEAHPu>kp=h%+2Tyx-p@c0g<-kZjK2~KV5t2QfrKm?eif>n!a(ymlfNd zGnhZ&t}?V4%eJjz%S_YPWCkN+Jj8m5J3%rI7&*g=XO~Nb6ul-`LR4(|!oQlRh%O1# z%A3?KZ|a{Tqya2hqulO#U)Z`m?XG2NK1cE2D3JLyk~!6o)M)QRovv=ZJ_Jr(R5wyd zxu-n+vS!s;xvzAmU2}PfF%T!?_ z-i}hYT{pM~rtQtosfj?NzoCj)>(NwIG&D5Sb%#n-$j{9iLS37I_TN3xKO+Oe5t3*Ph@U$+9oRh9wab@)ar+Mi8EO%s;uAEGb=(UOm2{int-EZl&S~g))&}yTFoZOux2j z+`UQV;k*y)QGlyPu(>1YUN+oZoj0=s#TGgXqIp$z!)Orz*f^h-boT?TY0^X{kjD53 zgx>uQt9hAI^^9tmmcAlEHH#0AsZts9zlRaZBDi~f))keSnhlMWeSq)QayH=rlyFyH z^g>_3mS`K|dIsSK1n#iP;FUxFYpN@Uxko&;69QB`7{AMJ<=~w7LO5@Uvso7iOPPLi zkQuXjUzWmrRPdnX7^08hT2j1E1D57~VhJpNY(?3Yl zw`jizzG-r#u`^S3Yk73E{Ibq6B(j78#5-Jcr9@SVn~m*NL?%D9TpKMrjPvj-kuvtMyrEZ!!Zu^qsG_NV+;dJ5R>B{bWl4K$#Wx2qW|+ zN1?R@+*lLBf{&Jf)T8B`3nVk}C1u6B1!txC9)YNgveV6wtipv7buF1Bh(lCw=N~Ke z9RSkqXM26>C)&;l?mE!$80b62(n{6UUYA&Nb4c-R*n8KNl82i z;BLMTIyT)>>&Wvw9f8#OpA8*|%_0`fV>btse=@dOMT4l_tzaK&EVLnCO8ueic(R{z zB!#f!Q8`Pm{NI@UH+a-e@}{Ux8WrCR8a?9;Y{TUw2`{GjLq4#UHN8I~xkw%IMXP3% z0?%v_8hHCTI7jpxxW~M=JI!Wi&w%Ww@Oa8w;-$gz@=1|Tmi|RhQ11{hT+E~6R84wp zf8=Fn=Iv*+g3Ua{&DoqTNO`t*GEe8#J06~18h(qm2;k_33v|eHE8zs1{Z&oz3CJ5L zJ$(uI3)2y9E>VYAk{PFYjR!VmhK%ukI6uKp<5*)hQBi$DiqovrMxL)mU#cWD?_Wbl zrrq}cMP-iEU{XjTO;2YIhNHTs@sf27P2d#|uc7C86MjNwtDr4Vv(09m5cmYjHNINf>Rxg^vtR4LYT z{Ic#!zD$-&(2Pfu>p$r6s*^8{&=rpMaYLei)g>Lezh0kFDuhY7uX$%)iDR}%aETIW znVt0nYW*?c2TP2x(Tu7W-v-E111Yqy+xbv_cO^^XrM<5qG`;A8jt9moW6{9^PAg?a zcllP_LXk^j?6)DrRW_-p3J_)y$H~W?y!?R2W@#hxLSP{I%$tvQ279~>bL|+ZaxX@9 z^`d#u<(Y#3Wfja{gT$vg_AQB)q57ax_3SlH1VS*{g<=$HW32+iVGa4${PxuwQAikJ z)Tec~AKx1!n;}t1PBfz6`kQO(Y{Po?c~8G;Vw@3MzbyHp6^O_-b6>aCf@~nwWeF;W zjJ+1_H_C`02P}q#lbNf5iDamy#(2A$?VIjj9#XgJ-cBlmgGV+fHsY<5gDS#{f>qMq znxff*4H=y$QMS)Kyt1^i!)A|l0*Y%J$OjDGUA?kfv2c`UPvX+Wg146{^SzkzU>kT6 zY?hJq2@)Efx;FPwIePZ7k~`$6r#*tasdriTpwr!N?(>k1JL(ejq%3i+q}niNqcYdF z4(P(Pw~-#hM$m?@3@4B3W0}Fo&u)t?;q_BuJla!&;3L#izzQ8AnB7? znIg{+X0946a}x~Kx2>r;k;7+Fx7>ZhsOKrOyaV*6At?i)4KLZ>-r4#Lxl#55QW$S8 zMAOOpcUC{QtH9=`r6pTtW_7EGek!Pe{HEhxa?d?c-x-Gu%eyJ`Xam#I&c}okX0F51 z=oY)S)NKUqkpiHh33>>npz$D>xC@diz_B`Z0clRQ;XuT|PTJEa{o^xG^)5-+?4d+~ zQy8N!OeiXIka2&xb@X$kX?-9sE|Y*yQ@kB$XBc%bqMeyCdPQadohI6%X**$rm#+Y7 zL40~;>f^3B^h5b?`YT;>EDPI$ghyt}lYk6*45nRLx2@>fz4P%`%z(r2_C@O<(ybtE zornAO=Hy=k7=|W)){yU9 zlzMhzzyEVtOvRqsT>;?*vMi>Q9@~G@CUIjPmKap8<(-tJfYRSL4F5tbe7_Uxcx;@N z^fr(WJarD1_~5w_=LbQ^QM9~lYj8awP~d(@&y{*;>GKg+ z+N8IACA{;te+i^J;^COlTdzzC6e~#vpW87SS^7{ScN#cCUASFqG@f((4tp{Mp@K}o&zcQo|Gt6PdWVb& z5gEZtXDA|l=R*Qo1n9L2Sg@hmcr)*=K+_7DMPjcSD7lA(bV ze7=?9*jAyrj9u1ef^sjznQ#h_i9ST<6HNb7dI&U`QITNYbAy)8j&2`=6q3q@g z3X~cI*&$9|Dg|{oohciH4qAD7SCO1KaNb3LB%+f(5K-|LAijNH39P%3sOB6id!^VJ zHeh2A11(a5Liex5uAP6&dA^GR3wlc`@}pf8FVRl|gZYvR!06iy5pC~Z2A=`R2x_t*LMCQKFk^vefs9grgxWI+* zucKSB9Sb47$d|4cv<8_N2x#8Le14y87XWgsCDHCR#9{$`J0CWkuw`y5s^I#(CB`GD zX8{U}Qn1jAIGKSSfftxDM2^KP7o=_yyECACEp8p_r4{&`>SKDLk2bQbND49R)8zp2 zRX^%V+i0%}9Ncm8eCFRsLSvl%EasIgq7@bh38JK+n=!Zw`w#7a&p;E<~UmR;V< z;jTiSfLfvYevKycbw1fabQVrsmla69hF3k@1@c_PvG1U-{D-OZpIyg)-<^yp;v8U3 z-Yt5rMGE->a1eL0*hY_Ly(LOTu$RivnJFC>>5E*uq4cFl=!1_wz zgftE-`?oj@f70&!`3FnwApRHcnFz+qMRg!Tn1oYhBH&3^_A+rieU`}atFX9BkG{Y9 z8=S#w4gn&LlZ~Mzu47|=eIcS3Cuq)`F}bZp%%p7$`wE{~BW1<>%bdyioPsF0*GdnI zii^3{eibT)u;JQmy`!D|0m73;B+_BBDLnSw+uMKR`ko`#catUJ{Yr4%m-qftAXJG0 zjf4(l643vLzUngQ2haCweyDaj-h=Unl2--maa=SocOX$^{|CyyKga*?4HVy1l76C})0h+YnZ!;OBB|oE2kep0 zvV$Ikq+DQ3@>M=I<`imW5kEmL=hH67dO0^-0S9ZwP&xo1)#<5+`kJ)FYZrL`T-qqJoyT< zMw}Pq^RSaTBq)C@mQU!uP7fdkFwQ}JD-#WJMo4vQh)#G6$-hkF7YB%bi!d6Wq*rUm z4ZYC~iu6c`NU1OAg)^N)zzNvKBN=uWHHGYW6nDEJ9HsZW>OrBf+5Ke199$eIpGG$; zk|baiHd+SdQy5}nT7}q3Hbk0to+p$aq{By-(oIwlJ#af;kW@X1>{K35jlBoJI9Tjy1(=?NC)82X(jE~}SNH@uW1 zW;jFUYgN%_uUb#N0HT25#{olW8*QoFA)KT`eMCw4%ft_O90qO6X?(xeaB1i2oC8>C z{gcNJ@e^N7#GWY-{M&9tZ;mYdv6@px>Rx)bVCC6637dWc&$GaFs*VHV+PN2ToJ1vF zyRJZQ?N-9s^vZDZRE6VI`km#Gs7fCFGG!tAky}XWvhvZ#n@%YxQjpfzoD=m}XZ1y& z3~i0;{D;MtV(*Lp*(j)&l@hfrQuhtqHeP3G&y#jAYiJI;uA%F|IKvSL#SmELw%1Z&@ZY2H;ha`}uuP%r4nk8q^Kqo)kg2pAKBH+tkbq9SXf+wE$T(slMLG;GQosZJ_8hHYQ)a4oLs4!7{FXZa?m= zODMlz-T(pAL5lGfnQP2RX z@9~qbC&QFDOZ(ayjqdH20`S_3cSMXHda06J$M@vIjZoHcxu>)mc&>b0g`;Yki`bK{ zkP-2dAY&jj*}8}h|0p|UPW!{?uT!9Kq(`*nh&AuC#{HY?8Pa*c(Ktff4xKOmS?}*D z%5YwF>aystF0>?*;926Wkr6z_qSpNB(+MvtaS*ZD!=0v3-My^T{&0N4M~nCi!)J*KD-lY)z@@f;;NSTCw%TVi$x)R z&g-Jr@rneqe^Vc#bC^5?I(efW3tR}&g!@$$kELXSjg1!lAV zL>xcV=(SE)tNF*E4ih}&99!SL!M-O!vx@Vg?#U1)qfRmPNiZ&Q+`)#k0;mFsLudrQjTvM#tpcY~VSD*!gD3R>cj&z= zal_4D@9odBG9(PS!IM@>1{t6ZWZEH(Shq4w|3EU!DzG^jk-2bj3Qm0=t#Q9JeHZMU zebUIm?IZ)jqS9b{_2jPdxS6HRN6@w8)Cm;*UyVQhN%{jyNNwe%}pm)PIRUw6bN zR;?dZFuOap{At}%G!{0#XZ#=4)8l*$3t*kF7UA6ggjqgdpuy?XPPD0#|fgjAtFx9%G(b>hm4oNWIt>#pLFN)Fy?549l&u_O;5(ckpXa2D3v zPXQ`# z0k6X>b=FG?ER{JBOGTdBj*Q=?;ftj*9_@K~RSD#VtU!`bd*SAad@e9D`dYnZ=susF z**cKl4V+sv64TAqm)X-6C#(wd>Ska^F%Ze74@A9i%On)9EnLr3L0Nr%8Hsp=>Z>Y3 zfHI^(*+Af~xKr6g$A`~8;TTq2 z-x#u<9PRdkR>&aaH-T(*CrG+D;v4vY_~L#I-1W%Y&3BrW6h00pULyE@@brOW=7%-` z1j6j()%LE}r_+`c$;hnX4he?xXNqidP1Mg4Hlj@(%U+_j_p2{(0TvrU`w; zg|-$15CR^_4?H=^S_)Q>7DqtpM-$-g2BN9Ro;JJwJ#KVQ z9*LtQO9*!Bf>%P&#;)LnhhW)UomZD2Pk{^A$5s8C?Qn`!rFuIsqS*dS_id0>airkS zyQNS}d-#i@mW62SymZdu;Qx@kJA)%E7xZHVqegXtAf1@~iZqp6dYTr&t;fk(7R&UB z9*KZaEmkK^MQE-pKEaJjBgXZ6;`fljLx++w<30i9tG)eC`xZ@R#c%kFi}?qJjUk z@4~~lcYKC{EKi~i_3=C@nLKG_K_6IEUIHrQx$|_7wm+=O0e@t=kt9CpF!%WBmRNkXI%6oFYmV1ObLui6>*J71-}N(aZc@?gTX#+0HqtfjcKdd}+9Ltt!;c^O%<1w!Ou6vFK~sm5 zU`7t!ew5LnLz+nBGOsmGVVp|7JAt5g{sa<00AgLS&g8@RGOS?tUwiQWzRMF}mB?K0 z#KLI~kkc=X2rE^q5T_p~DNyET+etkB+ne`~n@UgQODfW~CO{J6V~$U6cGza`WlPCx z@-KSBvG3L|s_%gG(dO-qsQJQK0uvK7#Ofe-P;aej`4;}=yz2rsy~@sH696Yiu_U@N z&=Iza5a&p#W9|S+wW8zpx&6%#m|vCtZOb4VJfoo4aHR^Cq*xg03ohQ^#)@Iy8xQz) zaE7kgm_0hFP~$H1{t*8}$RUytDN5W$mirwy430kbuUoD?IMe>H$l&86J~Os6s&cZ) z{nIRrm9{r!aG5B>eBST}J>P>oOe9+(N80_Y>6X#3`1i5<^5;?FXZC>XwZl?Ks$Cw2 zL-mw9Y2`92hK!heY=W`nJ~bF*S^oOsp9sZ!1WvX{$AGk zA?eiGmp%oDHOJDU25{Sh7hGS@t;`34-!&w57x`5qY|94Zp(>mt z=@y?g{fu&O_yLlW&a~~#gRR;Fmxx;_mJ2^XpuuJ1LDw8o>La2Oh2@W(aD6)MEb{E^ zlNVt+9YyEryo+wVd@g($xeP1(C$`>vON6K3q9{3hp`cWA?KdH67X;v)rh=E}y89tQ z&1BDGAF98PKeg)I@a$%|;DdiTz7Fa(hI1b;f(Zk&@khI(a8agR!e1q*~Np828k6vTc}MK(jPUzvV9 zTpL6G=)BRM?W>O`i(s~5LZ`rRLrolc>9q^6!J#}mOik3J7vbn=+n2<#$6X37Db7&N zx?CR;okvo6s!P_$d`nNWHJYLI75q>ActXP`EukkD;Pc_jJ&ty>dw45 z>Is5WKAT=n#6p;`6YxYXY-t<>xzU);o3kA$iE?U-FY#N{pjvZEyzYP_I{YQ};rWk9 z)~aM=x4q`|N%mVqOR3Pbw6$GBiX>pdMc(bI1^X2OIk_+eb%zsnDuPYZ3`p&YCq^YR zD>Ze+{ooe%#~Yy=^SQ3%OyPDFp20+@xNrU>+`?IjR<)0L?Hvu zkwtJkuUo1N6>HzF*0KdJGw}kVD}8IEW+6l47c~%M)M!x@Gos7=?9v|gf;a02uZN$G znKr<_CTiL;>^k^qptO0v?QK8FGRIyXq)^g3Ji7B4WXX&`Ad}uze8EpCwfo@XB1n5l zN4|i^?{Ltd!WcZzLuzO|DNbn@NC)3fNu0S z2qT;leP7qE41vzon=jzDOG=XBI!}y}I;zIxK09^J96xFT{W@{JqhO9uzGqDcMP12# zt5Q4a{3#qyZP)-63&Zht99jobMqO(wOazFQ$vo}TmV*Z$s}#OjIr}DNnq`0Vgel>9 zX%k>qL__?gK;8nB0l?5>VekEz?!}GOhz59~F>62=VHe$C}LCxP7p1OK8Yoj=<%a?`u5;>N+$Yc;P`1JADPKeOju4?kt& z1q36-v0Rp}6H!tc3m4VQ#339ZzKrnvwGuo}Oh+iJWdHUjf)Iy&UdQlROu86s(zuaF zaW7@O%)&Ft4p%`p#lCLE2el=;pCl*lV$JT?E~xr^yO7#)3Ow2zj|&xF6dh+j9bPe>N>E2yLq%d}*{ro&R*O zZqyOr+#5Tx;ZJam)6HvdrNI%Vk*JqHZ|KSX>brN4Xm{}x#LRehc*J)j57!%eb%Ng!|%O9vqtlLizvk^_EdphTXa_-2&1b3J3~FDAJ9D zG$JS*O?$GGJ0lD5r{?@S58z3-%gFed?q%O!J|t{pPedH zL)H^IW3&3L>PJh#1~;Jw{fVF1K@IY3xjw@M*Kc3qcW+zM2X_upLGN!*v2Q;OC9w7S zd{^SQU2FA9i~6_mK;#V4N#_`GlQVv8p184tG3e!wu{L4BUnm%*&_-AS+fXAnN2u)` zV~3P_N&n*R_qkGV%ZoCh49YF3U8a#2Ttixk0AHE^{V+ZLC$t-)>?1yWq*;O;Be}0T z_mo=&za!&5YA?a&YW{n=8yfilh)eDwt;R`iL`iP=p`wc#*R8;8{T}$FxdFUS1oys? zdi#3jkg(Yi%NwkIIYM#*7QUn~j2&e&_AD_S1~>LcS7Z|S^gLY^%-vCmK;ONFhuIj; zUDqY}Am~i+(wHtvoB=QDv^scq8k{^fBF3)br$6l2G!(b0_e0yCO{WvdxQNdG%-q%gbI%%6$SWt9xWmdCo{3Za5rOsM&~o&&VB)RT6z=6dn#`?Mgyl0lYFdGNP8cT3bt84?QBV5O2aQMm>0uM3h^SaZSRg5yMao=^gsS| zDQ8G8Yl+IBxm<4!K(b2`wH0q^h4F^r2fqdRt$RE!U;7s^eM92Gt5;`7j&+8Sv`1w& z#?-A$z+HMWoS?|k1WA98I3bgwxR1c}Ltv5V9?FF=olX4W*5ByW{o(Imz?{nEJa@vd zU`4rlz{jy>cKa?x7}Fwd(I1~F=%u$dsXldVfw%GcHK&MR3C{Qe!qL5QjWtN#;1YeS54``o#GSM;~1Py`%ij9tdV_SHVF8;%imh7Av{Qnqy#_7gF(n3`)d*x8rUv43Z)bL!AX=mhh|XDk~F zk6sI5RvoXU+Ds`Bp28;MUsDQ{B)O6)iwSH+8*SLG+u*jylN7zs5U#wrNf+B^oC4GJ z9eJsjK=8Fx5`Oi}3%hOAPn@WzLnAtlZnA!<`4=|T#>2F!gCrl`JU2k#Z%aQdK=C$aN`~r8&D;!9seM}}(4O{hNlFn0gan!8BD?g1=$7J7Vfg=b*dAEQ{UFH*X5uJuiG+Y>xuQHoPA!;}X2M&zUykba(jAAd)>T$l z=0B!C?rmP!XKt=#@?59c;61NFQxXmyXGS@IY&D?OnL}RUtC*by+r~3Cu97t0XBb#y znEov1p(ZF5php(Ll0*PX~z5hZ;<_%wSe&B#%>e=dmL7&l$5vv@HV>15>2$BV8lEk@__}k;EY) z)7j4WyKVn$$>&*P(nn>!nsfCQK{0jR2PUCK!wC{Q4@CJuTk+z>oFa~=Y3Fr=)eAse zT-gvAm#Fv_iA;Y0bit60fvM9KL!MA@7NtctdA-hcXIt0m0;J(1vsuEUpHZY`o2-pkatY>pSeqb{tIHFhCiEuM7H^O*SG48|AIu6aKLz=v39%4E8^kp6pFg`2Yo}! zMXMP#9UW4MVMu4kJUN-$uW+>Rye!#oo56FF*BuO84`;hB?W@AO@HTJWj3a?j?!Y)HHun6eYcN+U-B{XZ%9!>$CN3i!Q$`^C~TdUF1?()}_ruZEN9f>smV)*%geoW|v7h zp?3mNh?BY699YA0-qVLkd{3nZ2Yw6Edt4nEi_!qOT31;cd)B0 zhdR!d<&tl6Jgv1)mL#1mu9!Iru$V8*0Y;k#bL z-rG}ctGnSgd%<`hsrx9WH{I{rhTtg!GQc9${SzoRa7H^0t4yajB0d@AaeUv1rsjVL zgwDC|*O%1%h5qM=06+OA1vkFEdjA4VVvHvkDON0_7^^D}zb_0VPO^DV9)N~)rM+hS6X+0z4ONVq(Ry1g#NZ8T)GHJ zE6P@l-sCMe;CCyFM7n%bDcFXI+ch2?sasa(rUhl7MeF^1M9$V0nl$Bl6elqck~h5s z>VGxU1U0{F&ewC`fa8y42?u$Wf}GmodhcV^%3jzu=@}{RA|vi_-k6l(qsjUF+CoO# z;b6+RjXNWKv5NE2TeLU@3${Oh`Rx!NIn2}4$&JnVea2}>B}y}ogNx$)x$l*;1v5sy zc|kaHO&;Jg225X9J12e%@K2+!zxlxdE{v$phkJhaf_tu*t^^K4upKLFmc^Zkt?VDjd>`zt+O-}%c;Mx#z z0z2d=;yxs&*xe%2&~G+8J$3c%ocoUnvK}I1>mq8Nr z5%|M`YWH-Er=w@@ljZSJ4AJj1Km(htTb$N*1SQ9wZv7X1XA%K!{#uqO_lVEnw=R0M zj{7AKsbk&Pc$Y)3Q;kXS65|;sbx@zvMJD&>oNlM_Kg~Qj_&k@ZHvb^3?#B-46$%Em z3Lze#B%1W+C;Ihd7~Zav>R3k%)*>OsVW0`@eMyCVQ0JDAq1O3@+Xa7&oIjIueZ|{& z!S##q%FB(*9P5Ec93ML2Jv*81tIb$U7w}46HN~O|(71?Ve^jt@&+mQ~qTlQi#q?&K z5yrR##sayH)%U;iA|x~A6CFG310acDMkX1;c1FZ~fN>Od4-{O_7K7)&)H0L_gRfZ#7p7ufJ)eS3e?!@{BV1HR#1WZzq z6<$X0=DRC2ps-zUPVkRTp2?pD_p!qM{8s_oQ)VNQXRX^<!~Nc_nG&=vWT9CS8;;o#>Fk}mDP;8$K1l{N}z$3{Ixs^sGzhUH4cNk?&{ zad6_y=-V&QNG#r#r(0o0L`}0k4o&^NyM0`7lRn62PbEhr?nfvC_8${B2IVDg*~GQ! zYnhC3u~9zW5&pZ4!%Yvat7&`u7%K1?I^q@Z1VQ{zywkALHt)Rne%H;CFSAXbrqo^p zP_ER_nDdB{2K%t7;PEH9jQA55*Lh~VA~&S$&`ugH(os7S{!o)?_oCua7Pk|_X^fy1s-Y-Jw6 zR+rmPR_Lr#(v<`I{K}dAb}0HWSq-PpZG`hF*|{lNrS>Fsa(Mf)XMd@qG@l4HcJgu5 zFL>hC|IJs`!O$Got8v5mHZ3tOi?x*l1mLLal!xz<;+=TZqIg;7kxukz3yxHwvU5Bq z+qc(h&gMK|8VcA@xtjmThOU{o5}H-H4pw&s9+91J=BKCaMp})>3XrUs{G9BLHr{3S z3_4ZHYp6p9F_oLB@v=xBzKF5IoS?KLrSU;QzfriS4_ZD z=kiSMOK~SS*`lUN6gev90#!c&Ape*}(*_QttGM#hU_{hG`k~jc85P?tOL7(W$LVj13X*Ghv>f2%MOkIxng-3AV46&$$-)pDOPZ>!;v3 zi$i;r*~7?U7$?~bTe(HR`3_UBk-T;e13Q|DOzdMQj*(_B$1%)WN2U0JnNKY4tn z_?|zyHymXpAhvV|)&!3Z4b1-@r2obESVZ7J$>XP;8Q@y0rOoDaAe|23%!Oc7{G4}$n zm)w``!RCC*$N{91cLcVn3!7}O>oRO~(XB;>TyX{`d8#`Jx$9&YgKTd%5rzmKmgUS; zMy#+J9S9RHGG*krK=zkV&(oxcA5wdjV0yO?)Cys&T0ZK@-QPmq|8tK5Kd~nr7v09E zI5=X8@Kc;ZY$J_6Rm1-nA8?O2spq%2tQH0$@)UKoBeNMzr70;SwT)j}kw$T~uVu0N z;o2*o7ZE;@S@_i_-(Zs&W$do(%;s-}ydv?5PVpDs78r;E$Q3{zinkP7g5PxVUbbGc z9)JFae3q@YD;ll|2T3?4l3inwN#xyv1W}5pYMy|_u&BL?5`P+wxF}Lt7Ok6{HS3+} z*c_$fqt9EVGNlGI?j?}ks%iE3Icw?K+^Kw&W$^9(2Y!wpi+A1>;`?R$D39@uOy)?u zH~-lIBslgY&glh%kW|DjwlNvbb(7FH%J}}d8)o=`u1)lWI>L<>zLfetT#If6U(Dyt z0)vBr47ro*0@k!Yi8VRiXV1;D&}6xfgNo}IL=hNF#o6^7TDhxILRY|ra_TsC`%*_Z zlSW0mNK*IHmD*o!I>Y)duvrK?XT7i6L%r%P`@)>!Nu-`+4&ikX?_GPrtGL;(3_o}sy;VB%X;uW|6wa+bF?S@M13vfcvoyCX5 zKJUBz6em>BQ@epmU)2S2{Ha zrQcxiKGYb~`!NI8pp@;yUb=w7I)08{tM=t*Dr+iZ-SOB#XHZt8fj!_!=l@H2k2uN& zKfD~UhEgPHaxhZ{TYgtSk49p}ie0AKf#N)g^MmUXfrs`f;ii|wo!*OeA%FUtx!ulB zluAVHV0bA_0M|?YBWz4%;lCKK#!6Btgo;OuHos+yX#IIbhZDMr*TRO0eP1Pa0kPB{ zpU&}>?xGu}!(0nCt7$B6Hs^L~gR%~9w#T0gzYj>d;q(ZX@Z&}rrmOTkxqdzrfd8dE`) z7`N|v0bfE#Hiavs{@56al%2;6^3@R1CQ=zjtazyW~Ad>zF1xOnjJ z(e+LV$LI+xjDBM|p6g!t-{7SG$0{gBavviG( zcTAIo)3d-is@gvoRiXscscA3A#Z(Ma4rF)d{K*@6xH&^jER%`TzAk@!J$QbHUE2ip z0XL;<{hN(OJNltkgykNmLXtA_Kz+DH(KZ9lv&aPxJt`GlGUxX~cOxmHfWLqWH6geE zV&v-p4V&F|%S`V!akns^C)IJITL`V$W}S3)lA^|`wIJ2)j;ADR2L8f_^T3R2slI3) zVi~2^M56efUfhqoHawWrAKKtE?)1vtfj+@hg8IYj@jbKHft(V-I7JQY)-NR&;KY?8 zvst_#to^R@T3ba)v|dK@>xxI^+*Zr2<<>WhAQ3sW&nw7j-Id>Dy*|uBl`Bfl`o8zz z%=AQ0k0VPA2HaV!Qq!I)-Vf+Ev-aQ)_q-{$*=B=Qr*)xplG4qt0l3oiP@17P!^8VL zi(v|CKZ)Pe`zqjlPxIX70F=}CdB|5qH(Qh$>M8e4VJ~&GWU)3$5#ZuS1H|(wB*j!H6t=wTmjGTcvN((E@Zp@(@qkU zze^Ce%06;?(fc2pLP?G53h52ph4U4NPpU@1Emo;-hrQFM;4|DGpA*L*ZCZ`516R@r zwpL1{^ITQaPJZa4Z=FIh8^G*Gn@Jxp{2^d!s*?rMYNVrv1Y2mMKOu30;h4fZ?@=B1 zCE2|&m&`kC=Nz}@SMkSl<+iQdrOKA!T{xCq`&CucX}d3pqfWURZt@_vMu<#ivKWE~ z^gXw#EGaHC5PMMKLr6#-j98W+SboWs@X5J9r(Bl&Ej1bUoI%TDh+D*?PT5B{@>|xW z;;qz0_GDFXGASaLuN*>J>P}RlkDg`O3BMo48rjipHKtzP^kZzN#H-x6!R* z)n=dk(XN&OMI|k~HNcK4n8VD3#ueg2`{J6mdACHVo=n`f5^hjVx?K9D_Hq3_>COA1 zn>E7S7MeQ4Eh%B#HE%8Iz&oHo&zanL$}ojzD_;xDGal2>&AM|{w%ZH;O-s9`DU!BXXOe$%!6TwBc{|`|`Y)qb0VR`XTT77KdG)r>aV#pqFT=%K6 z$}QipeiE5}IR5*v1nKnrOm?PIcOwLi#lQ_M_xwlaijSk3(lN@xoBvqq0~D74bmH>a zou^Hr|3xGEKapIf)aKW$K%=)O49UnIfR5Ntml-8LU!#y^7~A6nuFA90+A|FcsD66t)vUT|_4o zWFlw8)}3;LGAU+kEL!V=hZ|>6eXsgUA6R@%X!QID4nVSRYoR8YT2^p3vHZd;p&!%j zuiP!xd*}M}^y#Y-=^VP42O-kwfzmo9K8*Ay6gX?Y zp{BhP zKiZ;y+Fn6>7%6x?Fer{{e;2*(^oi*xg{xC>G?FUpQzD|2}G{+xL?f!5spGzmtg}v__qr7krm16gUE0dk~8U(>_YlyD8HGzRwzVI?YQX&MEUZ_7x?&yuPVW99m@m^Oe|MTP52% z)e^7rRBXo0pwK3u33P+fI6%p_D*v;NCC5)=Dp4DV@o*+%)QuS4-%QuFMtXZ$F`Z-hX8_wV-&F z6n2pG&5c+|2n^g6#AwDf)U=0@K>_P@@s3lxi{LduU)0Yo(Q%@FdIi>aSCOx;OqD?d*7LJ$236P|QNOdaZu)v3STk$ykheAJ^oL=eav4Jjz);x4u`ky94sh+dzgGa3OuGy27dq+Qo@(bN5Ks9793>kI|X(s5v0Ri}BLWs~uJxxl8!Iohkpi z?C;4d$x@-bu% z4(J`<2_HY4PAw`HRf7Td&Be6!g}!>q<;Bs)%0w{M!Y|NnbZTN~rAMUhIESX%SoEi? zQO&lV2t`Ch!ag8+`PAU1?6%_2{VB&wF2es@02&iM7hCj!qR8biSZEkRIW*VWODX?W zkRPY!Ioj#j^iu49c>&n7dnMZb&F?ib2!5uYq3PzD-B4*g`NXDniJ}(1Jd6W@b5%PE z9n|oL|CoEs<@`j}iFXUzHNa2z$Uqz2hnu*l)p8uWk91@O-Ca(M&BS3-DK z+aWEKR2^-E!t1Wp&#>s)s7PFXWZnE1IH-^Y;9zVi`UfU_)HsxN!1NYj!tRZIn>Wvf z00NE@U?5@%?KZ;3Y{gcTPqPY z?qIO)QQllHQ6iw1&&P75{A<5||1qanBQ8dj&&~@g4?{8!=9vZo-v$iCP5*Uek*WNZ z3i{+UY%PN#_r(4ctq`xl!X?e<3AMs|c)lr+w|!?F#0qzvhd^EC=o03P?j%P)Qo5b5 zRq;Y4I@pqZIXTVyfgwz?CHQ)R2)ZQP#i5n;od_Q5Ed8c>{xO_^7)d@1<*hGtV|NK9 zF719cS;FS;y51)vdNfCt@%!JL*UM;^Pblk6S4GU?dkGOf)Vyg87*9%{Z&6Jl!@lSo zzw?&E_RTYXT-~AA7}%QKXKmbCFH2z|Y@GE#TcJHVr}LOCTlFl0^+1tUn{{JhB7Z;f zX1a-&t8GP}09xQ{x0(4#(Kwk4dCv|Tdx^i7j=3)hZvE@~fAbE$f0LlTN0_&aK5`am ze!?Sn4#?(w`4+@LZk&!SG}k$o+vi$Ue;17&WpUpM%41fKXhNE2bu)zD7CY7#U;~Lwsxr=$Oz~qjWd#o3=LCKbBeCVux z-oJF1y2i^eIyC1=9l~8M#6FncBa}p7Vcy#&W});*jy{3VH$1pG026-^s%Qc@s&pjf z?SQ9vqKh$-=8oZu#5avXQ=u_CeU|t3qs(}fxWv+ri&x&9%eROgL~&S`>;OZvt2aK{ zGg80lEJDU{Y3t-GtVQ*nh@};XTY0;-?aG0eV<{t$(4n#H$kYCcC*=foXx*?7(;y4s zopLxx_=hZ`#~)5mPv(d4QwEi|jlE|3I*O#^DvEF4Yh{#*;Q-&d2p=6*dfP=1eF0%s$Ly2f$x_Q#fl*qR;WI zYFad#TZUIO&i-qKe&gk}hbXP4>$=eh;`=EMJshvpfAPk@(Z)31G>hIVW^B{- zcmbEl&p<9VDdL%LVznd5;R-{`@r`|G zRbLRwt^H-EwQ1tV0+9n(i-CfMo`F zJ$;(C4Q*$|2KjIEB)Z?;ZJ|U7uw&3N!ikRh#{p7k7DprByhHLx7A+a4SijaGZsl*Z zayX0SJ1SyYe`q@dMfme6=^&zcJ#urrQss+{{lHGU@|yD5Mc;s}sB*l?AShunEfv8a zGJ)a+o>4uI1}+1IoPk;0tCX!9TGX+GhM@fIEEMQLFY+#FlYR`yzkcZf?U<^5TKL0N zj@;_7_BL9Z8YyIK4-qQ61k#+5p#@7VNK|xbn43v5>uv<}Q#P4vTd>`>q&QISkzB`Q zx*P+c>Oi{9yC;!5E4od&YX*hOrZUvS`>UPphsqTDsh=D?qZ(@ph$WoLt?xq_vD@`DEP8N^W4r_IZRnS~YR= z$qG_;3_%(RW6wRg7D{M&(Cned>otuQTV~%%boqY!n^^D_#fjDjC_dxV2Cl}PvFa2= z^|aB~98H8nSuO>d>dWd!fZDnUt^IrO_@;4fLF3m!wFTx{zJ_d(Xm_|jv-rHH9wgz*V8ZY?-dyXZl>W--wd;S2^L8}%k2hXzcsWUIEhnv0q?> z3^<~HMUCgKZ)JS|_`DN^_hGO!=dl6cTqITIe~@>?VUV`_h?IgeB%M78^kRgMv~6h* zna}AIxmd%Xp+v@e4j4l3JIwAM?Yt3?eYc4h8~$E@&o_3x=@&{`1aoY6 z@^Vut9H+w-?e6H%9Eoy1FYG_IP0{pbIP{QgT6R?~8D)%uoKTUWamh$@V`guiRG@xq zMb2NiLBRAr{g|!ne`*rt-8Bmm*Q`5(HE#vhql7^RkfYr;eQM*8(s|0SQ!gn>n{v(B z7#*9o*UzU87BAF)e^tGvd{j1_niue#U~SmeIOhR}&3WIKsmA&%2V+r^H{pJ34KFUn z#kmFS4Lk3t0n(DK-p=z$i#%4wyhoPB2p6?@&Umb_qF?wCbT98-D175u7MQeJ*la!k zFrx=7gmsA9RJW^k^}5_c|La8P#Nu9*bXkb^d=TQT`W+`&y)_+ai|#dJv{D56jpv98 zeYQ~7pHNM?k#)TyTs6^Pfp4kL?w{<8R^sumJQI96ByU1cI0sGV)vE}Hzq%hZC*5q| zrmF|ad;~={nqh`AspK2IbRMsT$OnULDcP;r_;EK4t^SGuEYqBz9vnRNjqQ%ow$KUX zT9m{ex3P^&X?CP>eHucafgRKM7QQpz?^1J@>hQlmt1`KjkLXJ@7oX66;zR!)&tG^j>khadBwm|J+$UV}vqk zkiRPx+Cjn&8|aa8>R4(FSOM2cJL_gi3Op7(mzHi#Gc88 z@IEen&JAipWUR>b4^s8CLJm31xqmYpJQ$R}?loBA4aogCOkJ1XrFo)0ohom4O_Y-7 z;q0x?dTcoN1-j}&g_Wzy`FwjZKWNx4E-R`8BPX|N zYdoY55gEp{Gy$|JdgGtUOD(R*zb33Xna!=%^Ul1a(KD;ZDK^_6oG~{xsP%RYUHaz4 zqRx)iE=c*9okDTt0$KFPQF}JyZmFr_50GcvX)&EfaaNH>`y`7paEM&V+-*3FMdo!N z)gcz#3Qh71P(P);_OlR^(y%Bu%d@m^t39Xv0%Fp=O#T5T{i8* z9?WuZ5vK24Tiy_{4x&LSelLl;d`6oWH)j&kMS$~Sq zE8=K$l4gvoSD0kd-s-~~@k6e+nw=3co$yYf8IT0zt@8(eLu}%QkJjpg(#H&t(i7Rh zK^=8Ddb5l>(P!G4M)jwRKD6tt2TYeux3*o3ZwGQ2ztkExE&_FV!40W7qn}xF447Cc zDLlr~w^hp+$X-td@vxCOBNZbptwkFd!}d$>b%aIA6Djtl+N z@Fs#@M8I19z8Xs(`kXG#%|b#vzCxyA;AMAss<`T+bf9Heh6;<7bQ3M$iame?%fN0z)ce`NQ^fYe0TtSbSTa$(6ZS~GuRBc8pq}o5f zB$7E><>UWVBQ#}`LYYyeB9hc#d&AE$m%Lnmx%|{-W;&@x5*3f4O9eRmC2^2%k*LZW zfw9k~UhF94K2!4nwWCC;qx6+S@eokr#mOW@?n#?9B%pzR=z;pKy5EIPS{8BY6MXTNv-55T~8zo#j+mEKMD%A`lRhqmEC!Kf@s91`p?T@avoUTbok zy|s$Atd8Kp%`~eUfO+y)MTKmx+eE9%hd;(rqz`c~g*P?xZm%(=`q=s$XfC`TIzU+< zIxk73QZxBV@-5YEKFo5465+7knUsc!V~<>+SY9=8NQgEeV|CXaukswnW&T`B{Sjh8 z@*wl}@Fu7ckOJYn?LM>5zs16M8;Ulu&0AsHHX^okS$O85s=HeDiJMcl?FI)151V=< zJ$qh6C~>hB@S0cXme~*Pvpj|q$l!MvIN30?`7F7H7`R<@>lXR zCG~*zDG+6)V<<(TEc1ftGL#->kYV<|8dtqPOG%F7{fEEM>m5>(7?;%!-laQK+WVfR z>am)U?58R#9Tn!P-?`Lcn*_erYu}U>4u@N?8%$4^V0eqv=TL2;xcVn0Czw@IF12;P zPsEk;SXzO9GF_bcZTEMpJ$vrS#pq|N`e(CWEv0^`2_FehM5zQkLgt$Oxw=>(qkAaC z6NcIHc*MAcZDtyE__AlO2IA;70UjCn98LS6e@J9vS4n2NsWd zsqF%9(Blz-Kvyiz%Ayi7mm&L|yu`_6uu4R_uG-nM9^o5b0j*SIiO55}WDBjH{VPOS zTh?T7dJHPwTA~X#cE#Fs2r|HMK7pS~O9#>tbrJ&3ZonJetYZ)6ohpI0ta znG9~Xc)#o$2}NdBmF|zbuK}ii$m--@Cj|PAp|^W5U4071y!Ph6efMBmw`)h`P>XGj zK==NLD?h*ew-e0sL*xQ&tI|?AhGK01P^p$INt%d3TOipiK@Uzv2Cslci7CgEnA)BU%yMHZTWCbAeZf7c8-Ue>gAXn< z-mVL}d=}DN0Wd_=cAy9vcGWU5@iyGGa&uh}qJ}O9nZn+2WcOKkjrCvn6+0SQGNlxC zZ`~VsWa*nQpZQZsChmVqc;55z1!N3FNvc&Vz~<^bQq?{ItpR*51LmSDX@Zcjio_U8 z9xUw4w}&H>bkK@g3pZef+yn%a@5OhjBoWt=n~4~ix;Pxhnxr3sncv{y@7CR6&9uAv zJ-?4c${hzS)m460C`Y5l;JXQF@7rj#PyukzQPA;){fZt8dn3j(`6jV%=sB^+N z`Z6(UP1yRIacbhc&xgpmT=pbT?P%AfKd0yX3Vwz)8TAtj$>GPQcZw-{ss7OmhL(tx zx4ek)Nj3`OpK9~;MZ&ro@)Cc+wWhG8F{-!LAcE$;61ehiUH=p6M^aod-+;=hfn)I( z3R#rhZ)A(V+j)w$!x=Y-g3;4-zJAAWvlE<@VLnQ@#a$u+TRVReED9C_bJU2;DOU;# znX*UN6yePIQLbs0_QM19plxwOxm;76PpUM(%&4%tq7pF{%^BtIP#d?zH@%A!V=^Wi z@p;#4cH$dOerM*d9Sf=`elA z5gR(Xhv?}~iA$hiI>kFUF^__xxEs)M@Mm`q7#5V2|s;PcV1q%g#3O8zt^At_5~K6^Er1WrNa9CBMlJ}l@D)p#U(-OmI zjuEY>j)@Lq$!LV*P2i6%*sYMV;4Zwv$gs=8e_%pFJ?e*`oRmF>H$@*{HVYPH*<>_Agit=;ZI#X6F#-b<- z�(=(8t^FQht+qr#9VvL*dzdn_4j&X{FHS=#NvRG<{ShF{zSKGk9U;H~&Mzih?q~Tm00~!`nEkjmLz+kN zhFU~BbA&Ib;61pB3{n^bRUJhN(DJj}4D# zP;G~_;Iy6G@EF3_YNzqe;f@a#hQ9{u<&s0qt-ENOcDg|wOQxen5DTJf+7!|u2 zX6eyobk%=6MHoqC+9sUE{SV6o;4rYrW=KnqEtxAa5u@US86~eU^^oP_8yO!1N6WsL zBDtUcJ0mI%8MvzPl2ecR@F+5dwpAIKPwm*C)%IYtr-S3b;@f2*qB|Sv+hIL(wL#9c z8Btr(bm1og!;?A7 zh;>}tn^}3>H?V9P(a^e0hllzeo58Jl!hn6oQ`R@!Ku`I~`o~vh^=NwSEC(2n{3d{Q zc@s%y_ez6oT_) zEAF@((Hu=yXX6h2Fro)z_Rg{TxfdW6OO-!qD&NEVJ)LaH(CBcnJ*tu9@>rhk@F@?3 zGNJ{usc$+;1uv6Y{28A4TlCzlQ~L`Nprs`na|k;WuLE=a8Cz z=DYh3dvnNCv20UH5`<-vLPd-N3yF z2hIEKyKKFlhpTfOLqJyI$D8xK@o*7(-N*yZuORlxbe;G6!N+NUbYja4`eihSLz)k+ z)_of#h`vkkwUbu+R&Mad)cW>X9U{|U@rbD-hRXZPHWLpze(R^zw++@NDJXOHIDZQX zKU~}67TEfe0V<5icD5V3-#WPI0fB7El}wk<$N##6z=>*~${?)Yo&5#C4u$TAzE0#e zHx2w9EJUlo&}Qc8ggO@4Xvlv~L&1KALeL3Eqfk#vriu}E8Pkj$*o}O+Q&Mw-ulHp3 z5`u$-l-vfyFRWf>V^FEhi(p%G-PW-gK#$MOSakxWd&v6hcMNF!NMVE*h-Na2P-lw4 z(4*j>B)FVxUv?&XhY@F9GKsKhd<0iywb`#lj?y4rvrASYA=*?TiKyY_(63$Pk7Tbe zaq4Bdx`w}G8FD;`Ne^QKi+hAn(P~b_!oA(OlC?Ly_fNmknTA*Tv0?2k@a1q<+0Rp3Jnx7`PuHVnoP-r&Hohb`i>+#&EIU z?8>o>lkIZmGjRT2HY#&S&Th;*!g$&R`R|i*yd`BYu&AYy3#-QNY=bu##rbif#6N*y zObn*>miM>uZwJWXJj?*}b`UUkAmx-ne2fA>@**vxv!`t=yc8%*hasQ88_zjF&-d=B z2L6-5!SHG5#%kw6Xhk1j;b#FTdKA>YG~v+8^$8pl%faa25g5+qfIVY5(B_bVcNi;7 zD5(BgoOF_1*Q8~TO4XoG*$A5G)L^?U&`gij`heT1Stz}WT}eYbg&s~dLY{gzlut6B zP&%I2;~W|&8Cx;PKxXO^SbFS{p+4b276Ub14v(HH>vDs{ z^koB=3AyGMfb_<~22rtk;sxylG{&hXSn-Ak$xvPbPOE`5F+KRT$rW}7yhi>8o1_Gt zkduAhZ7epZujUVFy};X1KFoGAl)|C&Raa^j!QWA1UosgZN*U;6eTtR*AM=LV^-{2x ziP97}-@>{^BRH@MhGa|ZJ*E+ndjx43?0T*HEPo&|aD|;@v1hX50BNZTp8JmgCrB-$ z`;~L9g1Tf=*$I-#G3xqEYqFl&g=e4_frlSp&)O3p;i?=aEIIkjm9Pg>E=u~@Z_Y0( zsLuFvOo#8?*nmxXciKbJH%wr*`ag7!BNVysJU#Im5|7leWIdgyL50H!-LYeXkne=r zvTVFUkckf)De9Bv@N#ZEoU#4lpI@?~wdu)jPa^;~eqQIaHve54OpnHr5?ZIoI<8SI zm~IB0DQ@oi3H9W=es${AE}5CW|7th}g3*WFL+d$r@#V(gY8@)TzMs;`LX7S2kc$5{ z&^qSzJ*#o`U)9zd5nDfXW-o{~uuj=Rd1=^>W{Dhmw_Pcg#Sx>|WpVlSlE&rDv)h1E zOovL_ah&M-5|Z32I#x@pO$cy9_ilFZCC166KgMap7U&COJz=q`qPt9v0`%DlW34AiCqHSi+=k&e)2OIf+*JM8fjN9Yd zbRWQ%ulWTUB7eHk+f(g2xFt)n(i2_x=!ry`l-s5W4eo(iwwcr(F73yId&C@EM3Zus zBNiM}*V4N+^W}b{gU6cy+ISyok8ojIzl0C{g<@0AfAL&5S=9SyrlAQ|D2fMYL<3wB zQz`mUkcHz-GRj4MP1u3QKfBET{-F_(f8Q1d-XmbR8Hu3c{IUgOu{4t?BovVsit*nc z&=%4{kV#Uc_F!R{!#8&PF_hvYLA1Gqbe)=-g4OX2L$AHy zTbv0N2?j2T;pO0#P>E1R-Mq#B&R7t6Uy;Fi0<>%w!vQkyu8zhJilJL5VnO^|A&}?tMJ&nghA!7=@^Tm=q zBvY5v5?+;kB#Ewdm4gdx`95i66Uhd$8ZTib$p-l+5yE=Q@@Qei>?=FlNDP`cG`1hmkHJ=Ic=$-gnGqxT z1N-OyF=YI|eFd90B<1Mq*8@K>qrS%F)UQ!LKiS#gn1K`wF`xha^zC)ufK%m;ohc9$ zYf1SY{v)#3r4J)_WkA+aVUPxPNdMF0QM_7-4Ou3HzVAd&(S5(*MhB5lyJDCtE? zC`f}S(jXupDJe)Q(nyO4h_rO0fS`1DN-C{)e(rtt+2&TjEO9w(c3Rxc9ZXWeA_h##6v46k4VRWl-{fRY|WLNt;MK&QpiX8t3Tp+&dlaM z8D?(q6NL=b2XY7S$va8A#ByjyN_c;72CNAjU zziGJ-@590aCd^@}M4!Lb5pYLAxYI&RUcDF*FN@n|9Ir=WqVwE&li- z-yg|cvk78+e?Q~pgO2zrT*Em=%eMG0{%@9y`H%~i?as!{fO0(?g794-lF3^@!mtCB zrVV1QWSSW%DNyjLC@1^9HX#vI`evqsNgCjZD)YD}neql0!5fgkr?VOHmjTk0c_4yZ zg;yGGewcia$SZ}vToABOoJgPm*ZWf24L2S61532uD3~+Ney$_&eyr&IVvZZd?|%Q> zzrVy&APA3A&mkO{sniVydo{AXU{MUb?FhK>c%iVlwees)e3^D|hg~FU8LMr#Vjs9* z(PU@=2B+CddgOg}7;3Jx5i>V2{0y!8{T_OCvjXzm{mOWh;m4(c_XRo`=4Gm-%b)CY z1hi>&y$6gw|5)$&fi+M8n1XGV+ViV~GCG++heoD5XKTKEhN8OP&RIgftWpXSGUu!z zdnvs2fiV`bGz8!t-Jdb+{M*)1S;X2I(ObOqZvUr5$Uh$MZ(p#PVa6Tm?1%;JVrx77 zu^RSq9bm~ripH;8i`c>7KXwi1`tz0kcF6|9UhgjtDJF|#m%~$QhaL1Wxj$@ogjU$@ z=Hs6w2ERG8{^@TwGI)5_8X>ZOx(k2Yj{oV4SUimuw;=PsItTxU?;jutkG>kPNB;Sw z{-;a(FxfuewL-HPd-`9IvS zpZ`b=H$>AN=Ek4HXn)+BU-;s&9~@AHH52FlShxRgzgR=e$UNkD&-}h!e?Kq&&JFvE z*O)NC3BY0F9Q3!g!_V*BpY{v9;Qx>1Xqh-eqx_d^2c?M#^Dm=-p(YCsYw3{hAcuA9 z7|agHwNPY*J}L9PQI|{@52_IZR?|>Wh6BRg5_IzX4^!e_c%mpwO=Po0f2x!C`PF#7 z#RBC10)&=e8nC-i1J`zCaZ2!CS>OM10QA{HDAt7^Afj!c-wMki4hP7D15+?&@px?{ z@@wluHU!oesbnVs1LOuxV2oUz8*+KZ zwA1pJ?({|h^sEC?jc8sSZRuw){r#+QqJV9`p}%0?TWAYq=SD`8D@XjrR`}^=VvqKNO%ak81x_zfiD^F!K!RQ#8T@b%0GRB zzx*aVoYLp$?n^aGzoW7!MXcg}BLc53V=jdm-jn`M{v6ub_%NZ=E`nJ+OfNt7i_bx| z5yflV)PlHwyH?^cCm|C!G5wOki?j{#=z(-np<)zV;+X;1N<092YbD|4ABEnZp3i?- zjCO5CE9KAaWgb*n-#4z@Nyq-4L{pq~199KrsC!%-#K=C46nJ zJQv#!D^YOd%4+nVZYw<|=CvG+a4_vkn<+ABB`pKp17hcFF;|C;DmwrfqwP1IhqS=@ zK`jhBLa7q_`bEbzExj4+^`8-5@z`S9kd&3zd`1m<#Q#WnE z-kZ;L>y}sH<3$w~_QfnIXT@Jh9}JE{u zDJ4sE9~=MjSKD)$xeMefMRgD#I5=}3V<4o!<8)Vs?eW-FkhxX=ns@)~9scFxLD{4P z5m>J8$SdWa-!2NWen99%)As=$AR7o=hMvTisH11zT3V1G&*NAA@Ivm1eplln_%GWK zl%pUmiG<)K^Z-t~GL5X7lnOel5cNT*_vI@*T<$rM_CpP80$wzmY6_E}(r_3txQ9^%;b8733**{M0U3J? zg;^`b4a*7LDLA!a;E}b!&Z5Og>=gU1JL)n=+e|m>dN~t8ouP?-#arJ7DTEWm^0mR3 z1aMeQgvq@NJc{$kAT#i(kgUo4I1G^QIp@pkiYU)qXdR!UIAPPYnS6z8+{@euYLxKg z@e9;=O%W|vhct=x(BF|o%3G+b(R6<1`u4U`iJXB2U$mB0nm0Fje~ML9IiZbG;XQy)xAOb!P$e|%^7H?*bL6V z;&`&UBE0bZ%c}=2OGmvApbh%Q{H_2|DW!~Ys3WId0heZOp>$)s}RX7?3LfGgt1I~`A8yTcJQ z4Z6ihuwy8#wW$8hMVjm;_ovz0;AlAQCg?s(MZbOOVf#>~2(BmSC zv(QxA$M>a9drH&+4#5fFA%4U~&d&iPXK74Dw;S%3jIclp#j$cePFZk zctpmpZ{f~d@$fWy2RC=f*X;P(!fe9c0P7-^%<%pv^+SiMEQr zz*s^19`wG1$1HB|!SOTj{AqUL1=^v0t?k86?Yk6O?TBM$JDg5XX@|npbS~J+RdcT3 zX0JG8(M;y`C#>kdE+Ke9Ksd^e>Q$q{NnQ-xRYZ@hvpU{#Hq61P)9cb~tq+d5Mz=Ui z|HL>@%AA~PTc0g_Px7tnB;+4HAuorcQ?q9cVef}f3o#DrWIp?-2POtRkLZBSMx`y6 z2^fqWFxIg(yK4!(&SGKU5T2SQp$OeFGj2OhG5QKvy@EhbI(mK~IlviBEHqC)SLQu_ zTSaTR)1+(P^k5kanePi7;dRb&%QixHGORB?_`b&5g;~)KiZh#JW(pOu&PJyuq9Dhnk?1TI{0rsEC?FULA*%x6j7i6xwEDKbB>& z?`cDRH`SIW9ROUxa`iV{_AL+_b)UC?Za34*6+t6b>S!iOJzUsuNRTcwf>wPYR=-RUUk(c*t|%OcW>a*_6uWq+4T zaXowCl)EGNO=s!MI_jcV7#G%$vbR0toBmQW9qSA_>_W)#l)1`NAI+H%bplEH*;iT- z05r#hV+V(|mgFb;?{dhQmsj0vVrp-`^HVOxzhx8u{3ptz``fe@1s04oVHRG__d!mw zj?dhPnDF_R!M|u|A(;b%H7m$jBcK{i@-D#bDWJ_G=LUg0%tnlM8aOd?W*kqzICNc1C3Mc`esE zf{BHJ*O|tx`knibwnc&fNr|{)u{rNZzs1q&93&*sVgq9?92Dd2Fy8t{WIXGPGkStb zc--?SmbZS+(H<>*_iHLijk7|Ii%hXmWMB(GHdnR}Qe_&7{I4N;SCXk7>X8h>RJo>n znXoe(@JL%B?763~&6;=j5%Q_gW6l%20PHws77Q{X;qca?;L@Gn^11co)~g$q1%71J zfI1@WXRjFtyQwZTt(_DoMlk(wM-G9n ziyo3XjTC3%0A})0h9@1u&O1Ms6SghFyBe38u$&ObF%6 z_2&K5qi1=E>UP{gq|kBy4m4sqN?l>Rg?&>GmE=O_`3?K}!>W=kzAQxcBo{_k10tqm z8o4)0mBcJC3l(A~P0)nEa+~*RGZg7%;#Ci7)$g^8g}r|J3UOi)Eh%tVPzw{YB6ec0 zyLYDQP%rbz2f{h-UrePD+haKu?!r62d&V-sI9CeX&RTIB3ozWZgIvJH>5|tPo3E}+ z2o(c7e&rGlnLmIg^d@c(DwgF55?Y=+q&E3Pya%cW7N$_SkIMPBU@_dQhUUkX z>8FIENbseNn?h`T@Hd8_1~BhCrB^TuO;*G@1-pvHcRj`7xe)HRG2jP;qF$W}oq~i@ zP@?L@PUG9J5MoGpoTgHA`z?+v1iz<+1i(W2p*LybE0|f5kzjvx?VZFC#Li=j?J8>L zl=o|JwYc}(?2xn9oNq~K-Q*VL{m*6Q*9T$No6rj$fxSHNhrjy6dAU&Xdk*^&mTFZQ z@DXMpM^-w26q87FOGOY`!lH9%feGKJ@#;C>SuZu!6XrjTb=8ba;2BHLwudmI0o!2TVXdXk&Iq-(<)$L_rqf2t+0Xu+ztdN z?O^}BiY>j-zFyA~0@J)GwmJuN!J_~_Co9sSqQzkq+W(Qjs#M?!?WHYEd7rF@TG&ku z=CX@Ie{xm{GOobAoQHNj@Z1AyLpGU+yJTa*J1lC|1IadI8bCygQmN9U-O$cA@H!Q> z-v70#9IL0Cf~YV~7wBL*(GJ5qCoUf2ABp8?ShCf9zD)QByk%K|;aoVN64Q3ulst zJz)P*MLTTmtX6J@A|v)(^Pe|loNr2(-XKx=Ez0E7KjhnS=D&hU*B6slXF zE^iTACG72Te%!C?d@~gk`Ee%&c2Wn?gGKj_XP3_36-iFyrIFH6B?WC7qXqgvp=d-_BC(DPBPL6lY4+mLLwVg500wq zS0+tFT)eey_V`{#Fvr-s522~eDs!v8yOt80TWL^~N4uY%vqlMYwaojZE^!PMym$YC zu;w)#Dk~zKAi43$#MSt?KA!CVCn)Q`;yd()m~pIb?l-G&aZxtbfEPDK7_pLRds)Ne zs6`QSM?S&jiz&jm0f>(rF?yF(=^4{bdvi)i&Sr(W-?OGp+kbeX4yBucvHr$`2F3`$RRe z(nSyv7Oh;$Q#!Twb>kmCXK%iLb<*}V>7XCp6b_lmS{8QpNL}_T7*3a-1wM@o@1Y#s zxl&dHmxswZ-HJ#S5?4zL^?UYjPb*&%kJ|s3Z#!^}+QF_VnqunD!0UgnV!V=}`9&6` zeQa;6(&hCIq{({rp*{8{(g^?;lu7oyV)bAkV>>YZ zF%A+n6(@YRw~&mT^h3s0g~!qPGb_XhkUKuRXfet9l-EOpB1^qRUBw=11l+PSS**)g zkGQkGUtBa%iJcdt!ElsWhs;gipup~F!g{@&%9WJV;^4|HV!12aiaCTjp>$v2=`xbT ziaKw%IprDYY$8qTD}G>Gv<@DfxL=rX#Q1iO*?W??-Z_DE^EuCV;HodDMO`8y})84Z6S4iGZ&NELe_9v+5w)aBzpPw9YqWsFY z$d~}Oc%`mdhjqrM2yWYKgjwcj1ePos%dCU>VfHOA3bZRSJ9H*ZQg4aE8s_uyY3L&1 z+P6I}6%7+}Xg0X@%0H@yznjo0G%%cmTp9ntQt!*i&nypO9TF6;;3(FzBy+j?Z%okM z8)iU**>UQXTB3S=QLn5OM&d)s?oI;H0ZZN2G-6qf7>>|*x|V{PN8^7KeNrzKsxBF! zLH?;#Cwt1DXC_kWDaVi>mst7U%gxMkhWP9EKK0Oj;_+CC?&eaY5_?MTGv*pzBzCO; zJB~XmbGo$E2I*p0O+*#Zv&K9d)mj?uE3qE?++t5baShwCK7_->=-FS^Za+o%49La< zg)ZZLD<@TlIOw&824(`0MPj)hgcJ}ybtp!w|9at zaENuGj+jC}J3htI*qb*S{jBDBgh>t2@{d7n?E)_s;_W*~0HMfv3PsCP7ztC8O|#fB z7K$>xCHGqI>9AP8bX?PB9lG6jjH8*Din7HF&V!Vs<{a7JsVw_Z0nBi1%a&9;R&gCnytV(dbn9Jd&`1LQaXm}DpgjRhJxbS$4VA{y?(WAN0VvjmSRM}^acsS}@7h*iY!L;eu8lauE;vyH!SRa6?Nk!zO?yr{+14QZQCwNzXq9GKzA1XtjPYEX0~*iA-VxC2s79Q z-jf*!tE3lirG5iqy^-q6XRoOZ@2!KnOt`nPWRa1{L|%#C^6FF&tL2_}-2#QD#4ZDY z@$H0n-p6{#dlz&Bm?waVXeY{i+%W@6)?T`&DX*L%=W7H_4(CjQn)}@|0_Fo;ii>m( zrqR8d5>K2othBsg__dc`qpQ`ZHfCkf=)pe074(%=GG2)#yX=zUF%f_r!a@at%- z(m67=KM5V9O0ZMSc58Cij}~V&AGYAT@@vWbnnH4re%O`_rWIC%?yWnSf<_GiUGhTx zpGrTb$_ghWR|BK#w(4UTcp!;PIFSCVN)w@x5q{4zl+pNwg3t>Fe9oJCg*w_OpsIb_mn9p6kZ-qFW4rHE;_DLY>lRxNXe)_Eqn>nuc|n zt@@_+u)(?c=`H-u`@go4A2VUhsnW}3G?cc-pt=e0ZG+I@*A%>C$hsFu#u@}uz;Shr z4T+rIeFs>Xvyp})s)VvV2};ji#+_7IMj`q`z-xkGISi5XfK5vSjC*SYtartR_>OpD z1fLw&@!%U~dU~(h1wI#5PF^TOySBc+-%9orxKuUzP!GQJcwyd|h%o6>Vf!Zr@&gAy zIq8&;Lslt3iH)h!!6Juo&KH)P4CTL%YhJbxQOra~%YDn?M69OK`YxHkFW z++M%OTMwnx7b#sO#?3^{fq77*e`!-=2N3whoUA!eT8V@?fAOX=1HNb?SFPBMb`_ua zAVa4owFph@B8u1hBgZPCg(Pj;Fv9~zbY9Y5bK(K9B7*~m6lReI#79~2e<$FsRLQ;m zhTU%1B?#5bKp=hgO>S*hnow*eAE%a1U#`yCrZ76|!)w`U(gxwI!@QS24 zbbvr(x@3|FN9JNB)l!UO1yA~eHTL9-iIg`N;+(i!Ap^Z^`ve&4E65c~*?fccFQ0WkEK zFjtr6HR%Kx>Y;+2jfDZxg~hUq<-BaOhVUrIPz zo}!{dddxRWQS=MP{IrL;;vgvs0FMx@oon6V+9QlN1Us_&5F7EQyvA2mFCu!Dd03I* z_f>F4COI8(CX#JuKU9ZGcALJKit-oAj*PP!I8n231c4`z*(s%9@6`y0QzK%tf;dgw zVaQ@Xxwr*A3Moi=KHa!F^xBFtV~aQ)|J=fyboQ1~dD8Tb_)B8d#FORuIgF3xbWL?M zh)T5rr*L8e7y9Ii3G_y@vtCCA1+LWjuKVEe%`e`Kuo5`82(1i9rVrH*9w_k2I5m`- z!`Q5-1T6Fvp7BPP))cMoWfr!@EWRwhwvCNvzfyg9Vs*1XN4+TUiJ_|iC*wJFa71gi zYLYbvpvwr>mRE$7h}kS@!#Ba6A49tg> zYiE7VdHiWXN1)WZ5-{v@C<{vkvQe!!+lM6+xpvOZ-)|0+o>sDr z&)l24Hsu}49vfssw-0kN7m!Nb2q!2iV3>AiA-L!V3vk}@j$0$5oMG%z*YgRpRT|3{zEQpa_ zmeQUfEH+@c0r7``bh3zPc|P~XxaL|~Sq)eJ#yJ`IHW{2C@lBaMa$HCELl+#oV7|RRKexevlq>iiN6D61<)iDq-x0#1%c9ZDdw}^94NL*N^bv3L96p5l^P_ zPkDO6ykPIbxP6gkdRsir|B9mMz-29moI>AB2Y|SnPQh8E3{wL?fUg0u!@{__+z3JaK{{v!JYG zxG5GS8C;AQbE~|JDwrx#t}HcC&ZtQOE;L>tRj zw3I)4C+u>T2hO^d~{XZ)uWE&Wqijpv?S&D!V}ZaLQjK zDnh*p(#8wv3713EVN4PyVE#E3D~lPY^|_%n_NiKqU-1?t3z*zIu1#}IY4a{1M7L7& znaEC1EFJ>L#p##eJw;5pxFEbCD%QvHu~p4(aa1rR|4DQz8XC+rj8kQF&HV!;=YBEg zIpKwh#x5Djsx<&dM9gh+yq&>p=F(q=-*XSABCr@c1S*06 zzu?Xxpzm|z52cF{&(eA&^V-P-s7r9JJ7)#61`WZ?H{o? zEp*fIs@=~X9D+*|$HptJhsPuR5nb*v;n}CgScBs6O;Jwaj^9uCS;Th+v)QFl_gbIE zJ4+U2;uxIxs(g_h!!JQC0|MJ*?&}Ux=ny-HYmID{wnT~(3AvoNJ@90#y^#I!wZgTu ztD>AIvA-~LMVeIDL>7R%*(8jlC8tu3=2LM33!n#j(}cm(U^?=G@t!(uq1EquBabel z_&ws0G@eE=gaUgZvC-n|)vus!`l0DK5%CpHojy4+qsbA~%k#pMXVlx)EA*bzsqMGr zqQBZkhJXIGf?+1FK>VV2?57w=6^N zp*TtfL|(=#c?70smcQQRE*>tjh`a@u)!EP@4rHtcl7cq^1A$f!dBn&l?n&r6I+RxE z)L^(=ScPC*)DF1c6E}+yAHEtu(|uj#2?x)iwMNZ#hatsKA*O@keVir8?Ed;H8-SMcSI)?a}cP5Ismr29? zKFwd~@;71-8oUZ<*~=?0ASu+W#$=9HYw~q6Y=3I{-Jt!%SN^;?>He)Aq9@Zk7%mvf zY=g;GL)e*G;ss=xlLo36(WAAmF(G;?Eq9NV*_$t2teSlvH&lyX4PE(77d{%XW%ie1 zhYQN7ASA4yanlvw-H0_$T;JM-W^4c;{O^0h#^U5k2>1ozgk09+3>hv=&sY`rC$q?CTM7d$5M)a zJC+}97}17@rlx{Hv1eVEb+3T!&QhnXq_GZ|1|$9yFUd?VmZ;mhj(g$cO7E(iiFgm> zd8>0vsMe;i+69q*ajGEJLJQC;3qbeJBr~F~pTQMalFWy(^BDM7*&eVlWMj7p><}2) zEP7YoaLUe~QDIe>3Ew^>qvE&H4NoPK0DkspZ_@XtPP@K#$}~Yj+NHRrH1UZHr?(jT zNp6muy!qAV&K8LWx#M`>kHg^zg{q=1oDO_xCoeCo*F#FnVVVFAE^pWnojobMRr1!? zC)EecvL}oW><$bRRint67MxP>Jw2)*+@wO2Ehb_Xo?f==ISYU9ixg{f?@dO2$4VEz zV4r3Nlva=^-Ta2xNB5BhzpsbM)yS#60rspFF?`jP7}%G^f!svN(YU2HF;yB?@WM5y z6K06p-IKSZ;h@6#m1p5OfR*!<^GtgCQLnUn-s>_)N}X+DRl(*jl>zKB zrzRrLh|v=(i>&*;@f5i2k-X&uO_u;z_0o^nBiCreOuR)kQZ0%Iba>)X&d~S`u&zGT zbo%N}*k~Q{X7kn`N9k6%k1aLYpocoXm@Kok9BGE_;jx*uW4rfqKiE}R2~01n7RVcV zbB7fT44Tv|8*gS%ng0!f@*l5xdKDINMzk!^j2r+e5KtQs8_Wb}%n)touS@#hujk%; zJBXVzRAOBcr2ytF6OVC(Gs7UqxGxk^KlPmh(z@aUV{x^o($PT8t}2B9)d+H2#}9K& zg!0-T`z42wA11dN)4`^(-H1ekBv*IQ#0p;+#~b7uJ-re$S%-v+(@??FzTi8uC&7{W zFjYLFDa|R|^!o{%snSGB+m;9u8eqH73zH`$hX^_?Yp=uJ!R{ccGxqulw0`E|CF2qM)ln)sQJ9A ztxfsG1glqWb5Wv~GzIOj+^DX;<4thxoOH@_|hqQ)RMZ zDX#*He9yrQa`Rq`Qk7(v$v{?zn<67!T6(sPCws4wtK>Ld03Ty=NJ>kFz|iGacK2gc z23AlB(|ZjX7W7~ANDLS;;`4zePPG)pncyZMPMR4H3@U|t6=^pBMQNzTq2s8GazM(t zZwGT?PeOvv{LP#2`^)IhBNEIYk)EF#0@8cMlV}%P#+EMTyl8-hsmuIIjd|EXJ=+Ef z6mtGy8=oDR5TMsHOZaQ}O3O3Uo7`gtdw-Qo?lR=V$Qro8S^+?pN5|XL;iUotkZ1zP zl8gEKZ%X}q)VdJk0%Y1f(ih)<6#DHKKR6lk!LfwNn7!Ocs6<_h=3!w@N{DTBNlt>7 zzk&!Y%i{-_xskivlC$(4ApKvzU>foPHy?dG=4J7s6w$gno7)YpFr4cSDZ>=8U+fW1&b}cv-*`@X)9fp}ye&Px%8iANH>;;om7E zUI&20pue?+kVc{wu|SmY=3|eEH`BPZr(<_8(dspJjN)KgwGQQ>qv;N%695%fkh9C|LI?Z zMgH;j9}pS(DY1vYR`vfU4)D+K1fx#c{ddC7KVSb}Zg~JwC;ZRP|7UM=LgS+$^Z#d8 z=tYIxLF|AK?_b-tf4M_Efyq=a^pEHBS4Z&Q|2{8b?|%FQ^|7CyNdF#W|3-jRQT2EH zX^!?kebWfhT~g8W;s2L~@b{lsaw^f%-}o4R^OHBAU;*-?OvwNKE&ngCL{JyFRrGf; zLDv0t9tc|u1MlPbgJFVRFsRhXhn>YSqpyNtQ@4El?iWeVl{#YPJ-NsuOD4~XVktn5 zeFiT->78-5s@bpHGOtolg0otshJZ&i>^3BV;w#C;Z2WG1p_ zlN5da?lv%iNEvQ1y<84$w8;iCWsZnFa7ZHu$j?0dJ{3;9on0LsD;5#rY^_6gcofIP zGXe_+eas0w!p2aU1=cw?{t$Q%+16m-2n_eVyuo@CS{ME|p2c__#lh$3e*E4SkIdx! zE4k!JTqz4ms20c&-*caV;WGP1p#DwRJWnsgMW$RqFm4K8fbudBh@e7%r^Cxx=7I}n zp1>XVXb+8uQ}A4kn~hPTYTX!Bw$r7}_(P<#mLPS(5A7;_>*H6k-b^Q39B5H+`p?RG1z!V^ryz$R$}sdJ1C{E8V+X2?1P12M&qI zsf{M9HvsN(x79+sCU|&W=j320C)4Eq3L zH6of%tD?s!W|DwGuKeUR5F%wLKRvSVkI!{*{B`2C;O6lUycWn}&SHblt)XFi;kBuR z=PISC+T(Xu2S^NtI4T%TAHt@QK*&e3HpgMgMR0cD!dGJKqL@OsKB zA~p9o1fMJ?m?J^pb%0>-n0-)Fk@UM%LK~(xP)2}x73$a%bnaW>Px-AAodM6{1bJ`z z0W$E$VX0Ti0W@A0?+$+40|$h}H_2obFSUTvfcjt!RbUJUtk;t&*bgIC5#j+f6ExWa zBes;eC&{(70x8vqBqcq(XbR$6mh8dH#k$9c`be@i<=#JK6Wf83K9 z1ZVz1&S^iF8P8Y+zSjP6bnS>Gfyb8@`ht~(cZF=aB1jQJB{OgAalABn`aCDYZtXm1 z$xZ@K^(25;cBXjg)Cc0(j?gP50Z03&bb(FyuRzkk>&~8w?X5Z+xZyuK1WCpfYEybTRGJt8Ay`rfQ(HAca93 zJL8Oe_>m>apnUsyjr1>(f?VuDH_fm@MK)yh<%OIxBpFW2UlKTEK^uD?x1II3{ml{t zi`DayEK*V75YLlLBJ^ZL$lxC~dE>$1lKx92xu8`kd+JNKqn?W1cPf&l`V(=1k#t<- zu9WBT|ETDwkvNInwHY-n_HCVb9pulhLB|{MI7HIr{A-|m)QakYrF3H&8z(_OA?~ux zyHM>l0Cx0ca=|pJkRnKc#)82MpRvYCRow4=?jDOu=*lFFu{^1zYwMS#$+^>Ynso$q z?qnMu;_aplBmwJ~wf>xI=P{%|f>k9Je&(hd0G!t|*M}W?lqNwu+2!(~JeJ-^lP4*3 zMw@k{FjNU2;oRqspP9NJpC_eWhSi-#>^8;`ws%eL(8MK*%3c+XwKl9t7s#eJ0KY1&HgCSevcZ3J+ret> zx&3$8mLJEn`*Db9w2M$K;3t=z_FhW1Mgyv~jF{syZ4s!lH^E@P>95%x-i|?M1Wt&Y z2m=Ix6nA5mE}=WU0F9Lwa$*FbFey^b3V;Q=d%_y5h2mwy2kkG>ivr1^h{`q<=D(zV z%vLC0b2!h9Y0-;QWgR0klI`nJC?X$J2KJEiub?x%)Iu@q#`BH99y9eUV-f{W)X%ZM zZB#_@&t=(577A_W&axUeJ+^S5kueQQ3j8NlfMWXXt}u``;N!;6irhUmZbI?zg(3ZK z73+PGKW-4Fl>xLybfmfQ`lhZ@%d zFI0QrMyXe1!Ng>wo)03wRtrvKghqhSO~OtoA-6_0vKJX1BHTpg5fcfFAMxsOFzLzF zxnK+W;Q+*oq$95nQ61ibU;e>8J_2~U9J~*{xh?r70=-O!b=VMR8TexaEhA}iWFQt` zwQXVW*LD(&K;R&t(p(n---yE3Uk9R2X@H{;7n4?vAvsR}W0^QrLPZDX$=X=i9ITx~ z#%sfhAy{_Oo`;foLBVyuxx|=Ad2SX_dzlx)=~s5PW;=NJB=xbp6PT89C)K*%!4Nf+ z9Ha{80&hL>2eXerI0tV%k!*PZRI-Q17mi~y@8SjiJA@vD(h(*>=GTPeEZ9HlV)YM>*N(?SAut95sO?E9#^ zdevCPJ!}0SA(j^UcG@kW1tDsUGkZUVk@n!`CtZ9g#iq?v~IE=IH>t?6es>1p{a4*RKOnqJo7#&Spo;Hu&Ml0)$&(h)NiE<){ z(JP1(!AmkX@>hAipj=WLcH4YE2^cO3>~;2?B|vFVXR3j%;T`w64hu9PyN(Lw=)Gv4 zA2<@6A5KwoKkbL@VYkQE%|uqNvB-(U`J(k#-8M-Jg=Fi|)X9I`&4 zaM_Bkq@Yyuk`VtV<@m3Vpavs^r&PCTBrS?)11bEX=A+Zi62uo$Xnmjxx{e(-; zx4eD_a!_I25HP*Nzl!omh4y3b4D`$wF1~(H2B~{|Q=<5|ZxF?Okv5QPS030rO5`ZdBAO&cHS^(Pm#56ad=X@48 z_16Azx5eqsCwcnpBP_VZ_a(H!YWdG!9)K0UWak=Wn&%7x<7PBj6-@Z~OU}C-JdTq{ zO+G2dX=fr6eNsA1s z(m_@gN)8)ad+Sl-gcrrX*I8YV#&Qsn3tba|LnY`HCf1K~{iIy-b?I3lnb=X-rU>>+ zBWvXLu12EE?lRc@o&XhUb&WMZq*zWHjrx!wA9K<@>H~$}4dH}|=N(|pbxo5M=67WR zKhKZR2?jvO*ss;#uneWSr*?qF(MsA&eGY*p{W7XbDa4#56|@t*sS8LV2AfZ(O-@C{ zo3!og%1|TX6;pFYc+DLI?vvonaq_i!XK@=V7llr7Ffx6JNIDK2`cXiRdj9xQe2xP+ zk_7?0dc%=Yw+4MF>-G2T2j5viz<%Y6rd)-bsj7T`(Gb#O$&GxOFKLRfqZ{{CLhHQu zk(LIW$vP``@Q`9xGXtviYQF_b3#B9XqB($l?W@h&nxYzcs@NQEr=SzWZD@wV! zJD@1FXToS40FM#j;e+c4#Q^%%(`!W1$!eYIZ;~3H(&ti(c~sWut3a$5H!VJ7)nVP- zdROSew0@^PE5k*r?E(HjmEQe!R}}2Z%fUxG$H;3!r#$f#d#( z%W@BUPN4Q1D$M3O5?*eNzwhvX1sama&+p0THPSaHKNlRW!glmPLCWO zCt7yB%03;^vaM8(F6U5eJ8z12^~h>8GM8?Cq@n~x7b+;cHS|@O|ML6VP0UQmZ3%tFes_ai$s`akiwNFnQv$=dbn(1r& z?dT@MjM>hLfq9^rC~K3Djuq#5H;*oy*o_e}H?B!MiywTk0DrS@#=Ky9^QAIgZtOL? z3Fdfp{>`h72*Dl}j7Y?wZn}F{{IX&c zlF}11F;n11zepvbP(aK`BuW(C5<*wc74rcV?vL);{ggCq#(#JLEEmLdcfgG5h6mp^ zlcXr(`YkfQ1czyA^O&9Hm!=(V7S&N@ecyP5%E7?P+Y;eJ3_M%9!!Zt1SvI90BNW~A zB0jz&`BtjTFcZc0(jc66aR#cIDe9_^N@Rn_q9Uh{X>ELwV@;T@psUXoT4XFx+iiAN zZ>tN-wJ0W7tAqoqkwk_j<>dRD2f-VX)j?rahyr=1p6;8$7urEo(3J9nJ#|}f!4wdv11M{zI_UW2i_m1fzB=&sC(`+aK)c; zft5qP?7_|BLKNz3Z2^p+J3RYkk9u;ua12NWz~F)V@n;BiM(37Px_wmJ88J!<25DsJG0uh19UdZYyEk#-3HACQ zpyX`KLuhZ48F5yH6tah4?MMl%2y2EcQ3`f}24~g0!?e?>7n?qn7xiRC_S2YwTVCii zwAVfEd~29s(*XxZ?r-oz3S4z+->QL7No$pZcovgD(aSDioXca`&oj1q#?O;lH%*n| zcCp89yMB39d$z}2;k^_!Yy!FueY?C6ZDcyq4(CVtd5LO-*~oW1Hsi)_%{}Cy^A`)L z|IjR1OR`$5jf=ROU!QUmD~#J1ecATx$*$ZrtHCMe$1~dmdP7CcV$R%ix+;~Xv@(`Y z>FA)zwFBcxxfpDk{5jkTG5JJ_9sBR?|1nbs3?UtQsFCpZ|u zj(cv%g|#`g_>^|Fc&Gk8Ta-02v*|q5s36cHoV*IEE!S2~KA@tLT(AOK_Qu`LJ0XEx z{M!pX%{@t?59{1SM@7Ras=)bS@D64$#@nhu*Q+$^X7Tp3F5jF^kUT%@tZ8ple8S~b zq|=ohm>AtLv^st3w;iwcV$$uVRQTCj+Um{3EjUe>Ivqoj4>_vL8T1A;_I4P8w+SK# z{j7+X-tWqlaSiraQkvynYqvY@Q~p?bNUB^*&oTOq3q{^tpY8W-n*uwtL5{73U>X`? z{M>Fg@pF0i{%u;aawzz5RsBxL(sN@W{!~^#|5IkBEvYnMq>e0w{?QxB*qZm%3!fK5 zTXXbc^xtL!)Ir3SWvRTzt9 zawqu?M_P?ZoMpab(vyhLWvzRJL{{=bLf>ub+bvHJ-4@9xR=S2xpp{n>Vom@}2tNrk zZ3}G0t{FiqevV|#XrkxKxD{@@8>vnY!PoPCI#k`eK?r)*=GECzf!$ZkdvY0cA{&#Z#Q^&U+`)SRGmAjQTXVpQ}?fUBF%~y?ON!Wzahv&ce+I^{OXkIxP#6u272Rs4qGJ&@0-5 zLE4aQ?rd#&!{{ibpuET{pzBE8LE}vw5o`LmZRHrM`lj7QeKp%@fcupkc%;U|BnqQS z+ws$cO)qmIh-L|az`XY^+M(;o3*&gi-{K~2$a`E&oh@P(6PmWh{^k01gAnhYd0y-) zm}(Lfo5AKdzi(m;@S4Teojc+UeGHBC#!#qMSvd3{l}x$S{U zj#PI=l4FI6{j=VKv}bu8H!W5e+t+>Gk6}?;>U4i=yc&~J%ko4uq+FBmbbBQT3#y)* z=&zhUDH?%lMEZ=4Cta>w7>26)&OQ0%c#=i~PjGU0A{AH{kiUpWoTEpf_V!6HBNc~8 z%@L`~K*v7`8C-ONoy((0ey+D$-ThHj$tX{C5${uxLyeHfyd6zSZsg6OBmK-GA+;UE{k#lW zyk&P|+S+-WX^c53v<@eV0@Kh^3a|CDcIDef!O18!E5(wm*FcScK*#iXG1+dS`%88l zaj$uxpA}eVZrp+7>%udQgm-(f$C!`wC|#ezi4@Rdua`b5qUx)Z>u9&<||v=Tfct*rY9~4|tB%Bhh~82I1wS z3w^JW*uJ1W-BRxEC){u5+7U=+%@L;o*Lc;Bw=n&}>^np{$A~b+Hzx#N2=d-266uo@ zCO&xNe`Iduo-HWUOh&|(8A+GfJLaVGqarsGzU(lxyOgPE^c*BMu1jWj%Wix0u1Iv; zeYP2CS8mk@V(G#&V#&t=eS683HW6w~2_kD-rgZi}0jrq&@%@;+Ga_I;Yj{368kehI z>j`7SK9kA-R;q=l#^nkPyK1PL*FUN&yJUO{&?N8;!T-b7TSis6y-t?g;ErJYT+EJ`hcp$4n5)moqsv3lnZQ_O z$Sa6LGdp!+yErOeH(b6Eav%Dk%b4RcjCQ3eaPU}vxPs{wvzCJ1xZd~bNplx~IYkKh z2}BGAaG0;hSCWoJGBOINS0e2vsmjyV^$lWGbZo5~c+?5$w%IJ_BMbxkWIMR;P#$99 zI{$$w2C$*u=c^SFZsJQ}_qG;=I_;ZRh5+|1F78T(eiHD!H%mj|njMh94%j1X_tYMX z&& zbPPcVLqM1N3((cID-pJ%zQ7$_ULj4!+b&Lc`Va(d6AePEyw-}gBt#XI zjc5t`mguSE%(i0|TU_F591-KGwGvc#oRjSdnr=@y0|`P=fyb0l;QrEhhyTgm3tmDa z%x5_EXAYZ0563CB!CQR*$Wurjc9Q0x=)u&^U)YyxL#7LO6Qx%^# z6}|J%np>3$wKeNt*Pm^u=R%lOK+?Ncs~gPf(#AUqXw`*BZ#ejU%O2q{^Ez!Bj3L$Q zHz(P55;WrK)}UZ6zN-Oe0iyZ0f|sJW&c~qjj1jM07N%8V?RtZECU3@q9&mvM2LfAh zMG|&hMe2~Uh^aIXuVE&)soS+y-Kv*JE~+sVg+~3Y{AgF)=MLCXG*5&T3iAMscufBQ z)GcZR`6sU;(1#qWZxYbijvBO+9mQZOyt7uX7Ni|v!*VH2J(w(eH%J@)k@P#Itj6K1 z04a)zkJ|kKa7)L(kU)N|-J~A&&cp4b*NwbcXN;6lGC2`6H$gb$H!=u0tBd@&2eCl! zlYi!o42D#Vhy%kSK)gH+G=K0rindC9e+s4;+6O&lo>&w1g9#f~Gs3f0@J)P;>KeFyj1{UbkynaThl@7EVD;N~z5=G7So-}c6u)RD}NC-BeJNwt2u z2q~QDU?Su#8BR`78ByN@ulylX%-ZF{UD=3-4klw9Mz4Y07^5K0oV7koo zTrj)kKR&u)-7UCNNGHR}wSq)O^|wD+HUJ;wA{vW~C-s3s@#84$?czcWnnS1+sdZSg zP81TCiufSV7a~3x2-D$8O+7}J*sb?HbZ0*3>Y0xIP04) z&8wihQY8(3NRV~FEAarjZG)ve50u}aY%3K1=~6EYvqqbwB(8H2$x}8v{CNc8v`YoL zS1K54tSRI#$%8vWV4+*qBaG-Y%t>59W|>w{Ss${I>?!B+^^T{=1+#9E6tma5VGrDKr=dRQ@g;m11kF`x&mc(0Y-rqEG|vpe$AJX29Zv) zUPGBDJjt4yc!%Gcha{ccbJ6J%Gj{>wG(GE6EwhZR@(`EqCLE9V@l%x_3b_+4p*d-h5D0ltK0I_D01)XrYJMl4cHPN%ypwgi{J4v z%Xl5cZV=1DQ{EQVf=OVucT;J~95`GvY9SZSVgpjhu1Uag%WZY-N!~8?fMsaF=uySY z38!q$aWd}B6GtfwYkL6gR;z29MSX_LWC(i*t26*lot0JcxCgyhMsKM_PhG0uSBs7!7&@p!o1PJUUZ-d z*(#8*=b3?OyzV1c$?%U9r)({&0-&KjyL@>1&uclwanu;h-h9kMO*4zAI_lS2R?p3T z9LROZIR4F0e=i8@E<(r@J6CCH%548cNT})~at_g=3Yy^KoCgq#8LedUrIcRqUUkBw zklUBUsFn3DBXM`Vb?Q_JvNYj&ygG*Jg$}G>UhimvRCn)AyT!%#*Pvw!;WFwuu1Fp= zM$g5V<;V;Y)d>qm;1x6u03L87^bG_?V}9 zYTt2RvuZ>HeDf%4p?D1;qAqE|b+=8i&oa0KwwKzPzzqkEd#$*ua0__OGcI(u*K58H zva1F}vNKV=R&PONrCQO(EvIt5A^4Z}D)cYgo(rZA+9_)kgYKn4kj}LiWd=bcWI0C2vA% z&#n7X;V=sp_3RV+I>WAGa!`BvcPD1+Gmtg_Yks8^Pd+ga?%+X<78Nt;n)1EaafV;i5+!aygN9OmEszA)g*yC@#s-?B6)z$y{3-w zBmA>E9=VOSbu{5;93={zD`Va_&LL6WmB8o<1|pM)Zt3B&{!N`&kjS2-4D^Nvc&?h4 zG+O=PDZ6v0iQ|*l0!JUOU4!tz?IWt*cqnr*)3Fz$n<1sP-~tw6pz^8!p-r2CF zhZ#w@O##HO&Myx=`5$k4ekQ)@eOx!a)K1#84o-1bH*q55+7Z83{$vdCG{|MV)Hng9 zqTj6i?N}PDd#_sA<@Ej;yy~fRg%O!C@~Pc*St2H4X#$*#57x)>=|fE)HozxSg<{M(Xpx{$Xg-4*HB z&8=$v?pN%Si_5^=itWJbABl!zeaGi1<9Wd04I8$t`K^D2xu_GtZJIyRjd;=lk*6zL z&|UaCkXwm3tT3RUi)IbJ;;W~j@)2_Q0j$rrzgw_0PS7&v-hbqb6PmsYkbFJbA^por zL8{H|of`2y=#Ujg=~xRMGjmin_dNV1%vI(3VCEYS_2Ucjg)uOdFbj(TW-en1%?g?# zyH}q>GS~Z0&iBY4M^Dqp#AEkq!$+x#55C;GsRrH>*+(GcfQdi`rnnv5@Dhmqd7d2!%Bu z=03g*&QDCbAOg~O9YqHTpC)_NuYxqAi<|GK41VU={LJ5#Xz0vjb9oShr|r5wt68@x z_FUSN1tC6K{Rzt?``e-sFMmm*!748k3ZvhQ-Apgu2*5tg#W2h7{iAZ>vZtYqa@M>Y zP{-Xv*kcM7Ci~K;dhZ)PS9V9Zn_UG6wSKze)&Y&pCFy9xk^0FP5~Cwd7+s*CI$W7q zbWd|=4oM=5%K7!>)@g5gY`R5duPxc<-u(#Zzpi^6UJGhggj94o@E{Q;MPqhs;^uD- z|H*o|MpSVGjm706Z;(%f*}@+eRqA^fCRd*BxHpnP$qmvtUx9$rwMAC;Ta7su=xx;7^_`u&EP z25*_9S#L7PjO5ri@K?U#$_RWp<8#k&vZ|&@f>}06=!4FUP0s+r(2zBkPluD%!{5@w zL8m~N;I|+$NSSaHmc$On{VQ;@n-TWl>joDb^&r5Fvz3 zgOni*AnW9Y8P=(t9dd1A0IBgGP@UGf=A`{L{dgvLA*v$yIMh!Ias${MxL(S0Xl$&X zh11`d>NAck0uQDyksqB6=cXJ26-G1DL4J!|iD78%q@=5tZM+*nr{p3Sss6)~<9ZA? za7N_#?JxeltOYYzL*;vHk91wLIn8e!`C$`XT-ZshOC3m%$vCqgDDgTB`nK?tnn=@J z!o{_&bHA~yMNR}vFr(l)B{v{Ml4}f!*Q4O5=CMl+B;K)X0bqtAM;tVF^Tcj0T;~P1 zm9TI)*3vzgw+91x3P#+QL@-fYCWypp7Wpu?iDRuIsOO^VrpsevZ@~IDMqQ6~zwyS# zQn)BlusUN7*j7~lp-pWT&-pF~yVi z2&1jIkf_;IT{`W95nncc@%UImsVPx~T>jTL`9@*7)FxT_{X+(ZWYNx68QLm}U>@Jq zNqbn3Z5G72#@ScK68LcKkm?Xz$>LNxM>|qyoR!rVoD7$;8>!9i=J%+m=OlrhCkeIp zs~6waa$PHBoDK!l_H&~!VR%iB`M%C4B69E+%l$$LrrdcLpW&*NO`f*I_5pE{A{WF+Tipq5B?Ny~Ue{DVsb6?g{-D=^Tt1qBIxaI;*M z#-$G!SOo)_mfQ82;|LH*#oJDF^R*6oIH*>*ZH&LyO{5b9nf3Tf zP6Asj&OLblsOQ#9X%Q^AQ%j!nh7a#?6%rA3vu*7M$qHI=X(lU8fW`B9jnIWJ!4$6Y z!fY1D83Y(8JKNPrDD_l{41KL8OwrbO4|SWs8ohbZ+H){) zn3qhoPpb8FWWKJ!WQ`xI+yB9ae_1N2&yN5A0|Ge@p~S467kWMxKB0(9>$p^9LZRf! zP!*Z*K~0jl4%L$&iG`Uc$!6_?O4H%S#i(r+*IjjnZf~|!j9VPnYksq0&%Y(3pkrF6 zrnk`^Ssdlyz2RI2TI6J83;%;`hFnU$@{j@G($QMq+7~X#YMee9o=ib6V^1#_0GNvh z_EcFw@>35)Da|NY;PJ`V9=(!e7nstc{f|D;ZJM%HnXeJ>+;&XaVRjV&_uGi8?7mt> zI2Z30kX%B%ExVTr10C?e*9M3WuQYhHQvtDh68NE1WtV}T`3Z{rP!@6p$e{j+Xu~&h=o$Wcn@-K1Ovads!WQ2?jpX}uEDc`y=qxfu(TrM*)7#(HJQIM@08JC zy`?t6spf~c}K&sJadMqTj*$+uro8e;>2` zryXdP6VfAmhA2fd^E*=>r~@B|ive#n*|laakt+!9{*BpW@dwU_uQo+z#idHc=?RX) zS_fz2*L6W8>SmhMs^TR535)#dYTM%Qc`)2Z(X0fCt@^XS;khHAg(`xtliHZxkYH8D zfErb!@Jko5b=km@@w(4AgVT3s7#1+BpAd~83{gcE`x$Du&az8onk$M06UZLK)6D095Fn2fSp~bI! zV_R5`Aw4jaCf~b%IWx<=AOYbuI{#_Jek^kpV7A>HOUTzf-J~)G^VIWn zIJIk_T~j^)gRW$ISix7Q7}K5-+qYwe+r{^%yfu$(D735Q^tfU=wSATX_Tb?uA3l^tioMW5lT%N-*47K zjR5+6JBee3LLda;B(X7MI8JY6Sqk{f+Fj zs~92d+oIYU)m^p5h50z2NymjRTw3{PygmVbP;DOt;!QBxz-KcFo&-zVnmJJ4%SjNB zgOG5yKn4{2=NJJP@ny)ZFD0nb?1nN86AGF{H;9y7Zsz{T&FRiN`m_JdR|{7o9&dc{ z(I<=1%dwl<#)i>wD+}UZ-asWd?pY@HbL1R*txD;pr=n}j0xnrDXN1SUo5Vkuf;MtJ(XN2k4)el@5jZ$`oV#S3R?J%rtScSyGAT5z{M%fMk^$$9eR69bQ(t zJ}u*Zz(h%Z5G6E?$b}cpVSjK6(wWlEd}{=64KX`>{@&=@1Fy&z&~Bbt!V9^uFJoSx zh+@G%A$IyL9G*-4*G{WC&fmZ74P(u#2$#Pga2oCq7U!jRKPHP@zpQv*XoE@p0sb!~ z)=0VMjEYJD%m_ycRIh%)LNaC!CesFjtVglX-GXR-wDO{B4*ceNcXTH81nO zW7p}7oW2UgPHRHB*@3G+S;c@XjgK>|?ZdBQ52K1crC$C(#CzA4MlDJaUQpqM1Nxbh ziq34Qfgza4GP!OgAwJwq%KVWFdNP;GU%SFfhCz6RuGL>iv_yEa*8P|o!@%zp3L<1N z%zBgC#07ug!!pTw2D}ltU<_Fq?b=FLwwk89NYh;*6KkqS_f4}hf2%LGF;isWec?yIP^(IdIqNnvF4$%WD~P z!x6%I=fMo5j;WrBr0Nhh+wz2ZX$d{V@bhybH76y~W$x7o(RR=VWYztFJ5?3>I}L?qiEr^vacm|4V5-erVMKSbvyh4H=-4i1Eu z)^g3=-Z+=6!r1nXGPTTx3!~fw1C_$-J@H-SVqW}v{BkG^{#-DRW7fCXi$K3(Z47EX z07e*880I&tV_>BL^X)=6YbL+kyUL_Dm3w^`P7_oOt~;w4M92Wmw`W#mvzz7VgWmSK z*sV1a{sBLf8k|tnrJ~&H7^WjXjl0@$oFihV|90B9Rxt>c3{XG|Olg15zAjP5W}$la zHppJWhudP5W>3dB{&E>5YCMTM1&>!+X3uqra7~w9il3!Y?p+Ud+h=O1VY6EXHoG(Q z+8@#Xk#3=5_!?tPGcB=65nyh)!l1t8C)xy)HWSdW;T{>Yg$u$H2?6dFrzq=>ebn5) zw}$@LeU?cqZ@n%LTak+x$h0w#pr2Hl175~eS~kTD%bt`Lax zzS#sp5*8ZCZY2950&fb^PPl;YHmF)-Q@i-F)+lhxq*Mc8F5_CF5*W9Z0>XnvU0@g~ z|1=ML2dH+Kukkm7)Jdnsqv1riED?7mnz&`ewL9RAnHVJI;a+iS69dDu5n{#V_llh5 zAYPH%1?zKDwZPY$ftJ%>R}l5*#iQ#ipdxPS=9dgAoEDFCS6UhOzMR<0O#6INw$oaG z{ZVfzV7_g68Wi<%v!JPlz`I`Xn0Ia(#eKV>de^)s;sgBcRl*DP8u2gG14p7b++YwT z>q0%1oYAX2xHMK4tb|tEsL#nwe=>Tur|5DRPSL~==b_tkXEMFgQ@E3vFO)$y*-gFO zowMmXqO^smIYqV|MfmMUxYmYDshKV=6-(+futS~JY`+mLvYn?r(CPo!>*-3X>7D|p zm*5ngIju>pxRQ`W@8!w=13xdgMz-wABQ0y0d`CLeec`4{ia5Mab}YvDTpW)1>fI-h zjpg+t#n#R+K8M|GaHC^z_)nN;Mrc7>bPY-8D35tx*MbwW-8_u?0Nf5G?*fX?v(D;& zXIbZK{||ti>&UXGX)!;Ke)6^vNErY;y8jq}r+%-!9sHH{i&xhpYnHC)KW3`Z8AZ_z zSB)mWZwnw?gY+{o;ALt}3w)nSWJOYI6ODpkn9T}UKQk7L{cS;K5Ycn-gMKbA4iu!g$cz@n@nmF% zD*U7P!ZRe)sb>Ui?L7NufL;;{$F3X9*L@xPQntNTl2tW96}x{#5>Jn_W|u%RIFW0~ z0!$i~fwLbQl9IRk?f^k{N4AD~u!iIJif5XmlGrJlgr|ADrmV2w$evQ{{aQP7!SeLg zx}?_aUJ9%G*61{wU0;&q)*qQ18M$Crk*WF2DEO(bRxTgqEx^1wnMmA!d`Z9EJhI#o z(gB(W##eE7FXbKhaxV@oYkPq1b3^n>EVCos{**Dh-nE=5!q*&e`J=w@aVF6a67s=X z)o`Oe6iCnWoiwp`G8;Im&P@xOKz)UsZ)6|ef&UYwqZ^AFY#|YDpN(Y52Y;5xF(l1~ z9hiaJ{Aql-9!Q#LX6Ha{eP^(#t*CcS*1F_L$k7xsllkx3i5wZLWSGwGac0}+8NBqz z%w2WADVzzUy$jF|liYD%if#O|U&|IE4OmWc+uTu|7YyNK%lV319oS}bXRn;2uSqBi z6Rl#V|7$&HH@qJqapcu#Ga~B$yNGDk&z<+~A3kxep_9w`7!REjpm8Vw5vK&DNSz|0 z6RHB>*NXfEk3M6y(CHuM+8(g%}Acm`N(uhhXaD4E;kwo zjC)eU=YumOI@7+Nx%mymA$)vt0h}{mK=tqi;MuumSAMBT)jg0N1A&1;&L}48ZN}-S zQAj}0knIh|1|3;(dfV^OhVCn-t(4eIbg5Zwdq@GV4Op9doe zmHmO+y;``a9Upt5tJ!D2xi9hkrIdyy)76i=Oqo|#JJ8PYZ`GX*nxP-zSeCrGUwO)O z^)9D@-KL8vMxl3N%$rwF8CK4Os?4Q;=8B+rt#g)unJufb?OEmdM!EVM5qCnZL*fwymOx=cy<*# z^=dCos@|^mU)4`a>U6yf;btA#$=UaGLm%(v;U!AhMk+~@3|ef0zVzCoker{XmteY!0Y!-83wTvm@0RtogZrK7^QU8nZVy`(hheVGAL!UWj_o@o7xr6Fkcbi14Np1*z*61!OK28;bnMHc{o6p~`w`lHVZBQ9>Kfr!0HLX!tpu%8CXyi<$b%Rrm) z0v6+hp++LubJSrEKmE55k?eZ8RW>&Ejc-&EKI_!?StzT2#tZ<-w#cN$$}&^%vW7Xg zfYbLs*nVs5k5}x0<-HFbj=V>rhyV2b!{?4ayUmo#&YU~`FI_`)_)IvA%yE6&Lv>Dz zJ=F8?PMX7zGj~859(~el2|O#OkRjcBU553+!#UJp;5Q&8f9xUq<3Y6aV>IH;_aA_< z2Vw}KRdF%YN_x(PRHjroF*DS*M5R>UUbe7){XZGdS{2oVys8(Qf7;|#{P$Y%sMO`{ zV*|A*fJ&Q_pv)x&NIpbA0nlZ}=4ugexXdm+@eay=x_D?%P04JH&79+NyF%6hgfhfp zY0Yi`psbza$8FPY0&4W1z>Yy-p;1Z*WO5}yIuyRhV@e(r6wesn-SWMs%$}D~?i_o= zd6sQ8O)mSW|7&?D9W4_BK5D^b5s@PZ!f1*-B#2V4WJs^K+-}W3Dj-<+Wu3VFdKDWv z#Kwc`)AJ3?tjg~~S_d9_4sLVwRWPNZH?+_ zSoLpo850O7f_*bRv5&_i325xq**IiD8;Ymj{mo}M4mme7hQThWI40weM&8O^~Jgp z21)ZU=O76*>{bhCZSK~;L)Nc!D6rY-bLdN91Q7ho{Ix-|{DZiSQ+K!!fEgg+F82N7 zH)8*_1BroXih-aWx8}3J0d+As%+Ba(xHt^>Y`^;dgTa>FXm&}CS1YvJ&42E`I!9;E^B(FG80GU4aoMalM}pA_a`(dBzUy+7ynuZ~;PHyB z&&^CaQVg2>OGcpPNiEDL4VeMTgoxEokO$LH-Gdhk&KBW~-gH^&0DdpeeJT!NN3QvH za+bp_A-HY?L2crO0_#`Zw4I3d~Jsx*bo7$ zYd07lCD_oFZzLv-u<6xLG6pc6P=kw2HfqgX<T^kPI$Kb~C1* z{->1PnAGeP(Yg}-%zyr~ZRURT(%N+d2BxSZ@d~8Wp#6AonpR~vn?_e3G*_CAwNQ7a zvL%Huh1or#qu>&Ko1;_bVjZ*rArf}&HSCNstx7R_fvS+6_vi;AUAWNXg@Iryi(oDx z0~)GDdVkxcEPcO2iNNUh!WpZj_x%b*DFms=y`_7DgOn*sf%q7mbT=3;#0^|Gtb??5aGix;EkCa# zm%V6BA8`nmc3~&|Xt!eWVCqsgy36IIatMqhi(yttzFfDu$H4!l{R=jU5!6O#6+l9j z;yn(h0N;*O;ep-L@2Qlw)+Z2609@JWrW-JLOCTeoI4{XNadpW(gs%@KRrNSDGV__Z zz8`q%f&ieOo9B^~(qCsyf&k_;7z8r%+(QA?p2%KB`=?=&&q|ObfG@e%gmlLQYlwmK zou26qE*1KIEqvICnlZLlI$F65;{xbq*59|Dx+Xakp@T-W{s}LYE6yT1E(kJt$H@_K zw-}J&kv|9kcl4e|-bMS5*LYKdB+jEq?XYTNoZ(`>RKy9j|GX1Wl*q{qC@rhoTR{7E zgYOe-fp=);&zi;{vuKe1Y%>R)dlh4%36%Fa6u-QuRerZ)$ieX5xxtsS7u@Lg8fKXB zu3!08Jl#yT%>K4FVuVdaQfaH&)oZvM-L^PsJk=}O4 z6#HCwN5u^qEF#k<=bGh}BY=cV^*v<)P^ZKFuhEK5G8{uZfpX!Uk_`x(8wR<(F+tFf z2)9F5wVoSz2~jP_Am8-rNN%Z%L2oo|S`>W_4*?;cCC`H_y?HOE*M;J#@iQSQ&G#~kb-mxo2vjKG;x;7~D>@tz0fe1rn&yAWH zx9ruJIrq%PuKp)pfIA1S%@A=+AiH${9A_cgr_`F=*uP<}h{ko3k`tfGe#baY1D<{W ztqr6Fhv+1w@^nIiq4233*+iFq0Vk&YW1gev1WOvQZHnXSmFNS@r*JV zG6Q=7Yti?REG#fZF`fg>Jk;G%d~_5G$ib&>cjEc-;LtEg(e>faxjp?kBiyS5;~Ugt z?HoChAXl2-9{eXjr24YdM6yoq$8~?%_uSq#I|=u=6%EZe>bY<~4x%dkGZijQADjL7 z3QM3iU*hQWS)wp~60QoR-d3vBCc_!RNbdbn%p@isskO#xnE77S@ znxy_l{(KbG>fIuBAtScHeR~57{4P_Lb537(PP$G`gg_%XNSG`@*$F&I4d0jat2o3y z)e&>ffLwwVK|Eez3G~2ksj|BRkjCS5T@nho+?W%&9kX}ts%=saI=wP%td?RrA@aKu z(SfOj)e_zCk3)4hoBUe8Yb)76liyBs zs_qCCf-cMhP?92Y1eZ=!85C)O^0*zyE15h`nj#3vpCHJ8ueV)gzT*wTiL z2cktVnu8+2`47gUcEk59!|{bl31ilRazS{w@3AQTmV z;g93>DUp7Kz)vBS4e8{Bc@-+JF1F8~Y`a!mJvXa>xMbkX;=;kVDE8Ncul%7j)tX~U%+$M4>L7b zdeZmLQIH7SUlwAumo3+16DAESlz)&-<4u!0D<~J`R^#9iC%$S#X6rugo&YDBa*8Gg z_F2X2YEgG2Z0WTREVMzaaYbTZZ;@1u+JgFWr7$-=K|5oonHRJcj({Vbd$yhdKWK$t zLhY?cz2XaJx;y~}-P($$_J8m1iW+M-KL9M0FdGO_^%7-6`)!@pOrM|DQwmg~&Kqt3^?DPmk&35R$4EBuD-eLE3cuBZ5>j z1feK)dNyWx4!04iduS;(P_#!3?MW2RRHVb3wEtQ~nY~=$ZmhprXt^~~jEU;imlF%? zVb3qpiyhh1nNgCjbjU_c&0@0AvN=gAg54qlgC3{*U(Xkc55 zc%a8p`Uq~tlB!u{1K-8jVb|+sZT>C`Jh|d20^Sg|88QPJv+^Kp>YY1dZpp&758Sq{TPnV+L{(kfMcKa3zg_(20w@GZVZ?STXscbnkrO%zL+T6)cNzULk+ zKZBDeXQOhV)U0~QMo=sK6m|sAOV?jT)bUs}y|(jmaL@kMK2`K-kc<5tNW0bvE5k`! z-A`1Y{?4nJmJRlR)X}BK zM_zxwiY*(#@))LfZ!bSDJS{z`bhOyGA5f8Er?=I6;l#W;SL=)oMGN!3O2Pz`r}Vzh&(@U!NK3C0Om78hidT!0K7HCbGS?&O7YF4uBexsg6&N4`G5^o-^8g|lJcTWRTqf|YB z4fBgKR(L97d5qXsQ4emcgL-uUxHvX#q_&&rcA!+Wyd^Ke(QWrMG7g~kx_S`jFD}o2 zHd;7jv<(+-AkM=R<^?}0yQmpx_!Z5o?ad*dt_5hJ^_(SVT{)$UoJ8OC6a4aW<-aBi zWOM6VffaYM62xpgnP|TM3$h2NHP=CQ9~)?3qOMZE6y>jTkD4bqwaO;VVWWg|g84w< zA9o!qC23C=g)l9_THxnH5Vkkm8E)hThtZ=9NW>we*GLe@#TCnx_2YRiTzBE>lGPX5W= zAk$5R*yZtHM#KA@D!0s)77M`BX>fmq(hx_{)l?}J4z>VwC4Z%G!v0^B&!-&zX{2^@ znbv(ct1EJNF@F`O@Dz_yiI)&`?}>s-4l$D6D?v4+7b0ScN18^UawQ#wuS;d8>dFO-hmy` z%iZwN_MA5VN}xA028TEIvD6iu`y%AvT%ocFJEWI2VNdh@N?Z7y&U)XOPPeJ%8k1^x`a*t=Y4QUAvR@B;CzS8A13Q)R!UY#P5vv7`oXfWU~cs@JOd^}y&o z06F`dlylX*Uhp@9KnLpg(lJw~4(U>u`IlDIsvkYUNwB;7+mJt%R-@a-RIe*X>s*OG zJKrl4CH(rQd=c`FsZ0!qN{!r$;5Z9f!0@7j6a>r|(zKsqr zx3+|u*ZONdstQVd9JRK&BEfWKK6hsma%=Tq(862{>%LCZ>NtDO*aCsbEME-;rzxLMU@1J?bVneDZv*Rb#u>KI~A8e*l zsoIvRR0ja-@y9dNV_wC#I&z+|0uEF?0npVd%p+F816&1?aCM#Maeq`4>)&mwH%?U+ zLs*%?H${YazpsinwC0#AnHn-^gGEe{>)z#d6&WdKg$L!<+iuV2Y&eq4*eD&uq5M$l zFw>=16;`+ro{%KL2D(bN?J4D=>uoJ_YW|5Jb`}Hq97A0)$m_!^%sX@M z4WX%3plWIcJBisScDpol!z$mKyc`aG?Hz$4%d){B5DdY4>PgOM4vMUMBwQ91%Y!*2 z3`(2WTs{fpUq71k#Z0?8@9I*OxVOF6fM(k9-sBi`GI@qTLM4M;^21Ysyo2sDzM^C? z)ra~AhK36h1v0hhadcaEste_AQH>)C3Gdgi7q1lrW|Wv~l3t*kd4DcOp0TcimrO$L z_LG?sn6fhEn~MuRU1=w81(t6fubdX5&OFQZea7C`l5T0K?z*neGIJa>Siq=p1C7~G zh8z@W+SXsCd!$^>-}BzkB;oBVDh%udXnz*@8@CNp+`Oje*XK?lt6=nEzL+CjyD~ia zP7-tx;*f%u$bOrWet4JJB(_G9f9{SMxDiAX-7?pwD8Q+z4pA#yLbh*89#evx$Adn4 zr_|{#leD!D0*Dy7Ne}#ZVnE$4{xmnx=PtrX{gbkIP0Iagjyt1f%sU9YT)%E;)Z~jG z2XrRr`q`v5qaHRjBal@kMMHT;8`IM3aS zNSxUy`PA_77I#A#mGi)J3HBk>BEeosX3i}HXO$~m&i}gV7a1ny~wfuEff-KM239*#1uXXtvyUwJg#1V?44UOoI{)YkNcwrr$NC*7 zOz>J4k)Y>u<&xb&ZW-o)6U_s@b5D5#3VKmtTa@}9YTA!V7pP|yi_hcxoC&56Q0VBy z!Lml_SdPUEGc+jo1Hvz3J<<7qh!xzb69%7*8i~qL<(~@qgar)G{9+)NBzgy&e$*8?B zu*3ORDa(Q^Dr*`oHsArm8fLC`az~j8q7;3q6a|1wsOq)g7*hU5FL#}_myoP2Le+*9 zt!{-ldVkrc61Py_4q_~lE(+b4PW098bo%?^GK2Z@MDkiusD(dEiihciVY2NqsJB8c zK)p5XI>yI*%g8=P@nu^UZ_yyqH0619BmFP=1fqk z6-q8$Gu4t)=@d8A7whnMxI{W_7-g)QRkF)q=TW~0u}9Z0Y=HrTAPFl5xbG-$(7`1Bz)o<#9TTeuBdKLEXbaszb zsfC{Z{+y*Wp;~axO7JUe^`)pz2mqFcm0@KWUAJj+Z1nagyK{@tPAhym_sm zTD0$tzTVX2Z6KuqUianDL<@_Dwz3igdaBjV zWig+q90?zgR7N<-Bbm5vOcR}kH|HIGdWO{ZPh#twKo^ok1dadWK zU^}{gsOl#NF_?uXv<6C;J)kh}lW}d^!0+qPIj-a2fE=xvpwp1*8?Dqo5Cj*UB5awQ zzZOf9{F}KC13*GB%ZrG-9Uay$J0`3iS#VC2E)xv{S*Dn|7rD4D)??0;;j}0>6yY|N zN*|EAHXCSD^nN(QauK5a-;6ynqg4jW&2#U3)=~bzV7q)i%ZW6qm%8}?FVTACUibGp zW6$3x!nEOX%a=_v)s`ddXSF-Uj)WC-rh&I4uCsrvzz)A}k@PpKICM$dty`!_FQZ!E z6Y(?50lITtwwVt_IyJ-Q1{4c=zGrA@$z~yUBuv^@4kRTT)kaNkCTcCNU`v(7>tM^` zrfNv`Vv_Sc*b7tM5D9xIzNDo)up??OG3@FHEzYlH(T)UbFqp#Bm7dKB>FQMr*YnMo z+WpK}ymQ_24_CJWs>}7I(m0g|)O*JxBX%8Z3{lgjJe3KnS#22S5>F1G?3QAbHH<2dAwKA*apmZ62i^KjJ2m z-dq};|1EgwIU%eOfs~SG2&94<06tF7h0g^@e?a9h7N?%)2bdcGCw7xa;xgId1ROX{ zo4;G$nh&=_y5f&XdikdgS-lF<=@R4M0tu{gEBw5jb;|CE#L z(F-LpH`c#K8{MwyamR$cEpQ07a+xy4D<9yPi3cU^53u13*VxiriVI?G6TD-z0vOl1 zdQil&o?K9AgW;?+ho|LBulA zcERZa*|Ed9&T9ZM#y#Y~L+zYYdw_$oKYqmp^hq02vK#MeB5!mGT$2E)mWW@y_J9i* zUmOPo_a4C$J%$u(PAQFEHdL+FKCg7)>lPQx+|su&V^L7l@Args(@T8{KuI?|X}vkKHXie@>`X~6$Zyw4dP`_-lQPdajBR_m zg5gv@s9Set+jLRy)Khn+%u>Mbw-rdi%>5)(1jEa`p!HrjYB=y7vZ~wrm3KgLs@pJc zj^mqQX5KKdsjC#0zvcZd3_WuvtPbm@AZcfjP*qMhmW1=6HyM~`3uY{`pS{gGpgK#+ za<#q-&oQIA%PU(-v~Aq-BGZ(4U_k6;aRxIyNVM>#?qoGTK>mC+KhM>KExx6tTeS1Y zO!O4-61+76OIL>F;*8#3`!1r!rm4aCntphT5y+-uxgg=(FvdrfVIfk3k!$)8!P&z7 zpnUHs4tc6tI`GW?9ZlM%It+a?NK+egKZa3X*~D@2?(RnUMQFK#0Ksk3-UWJn#X+Q|RY^|9P!U z&a@y;rJPbE^57vNhEOV(Uv0<0;OtX!1!)8eMNfbQIJQ0poVusOM_*VJED@6MrY_t- zZ))J8>96;~CveSu{l1Gjvhd+xh{@j2Ypds7CRpbbGvF5_AdV&m_&e827R7A*sFqu& z>u>_UQ|K*{#Z?2ie_o*NMuT2FP)&6r9`^`=-%iKa%$`5IT!;>RkbgeS|NT#JxKP6; zPGBVXpNt}@{L$0>?KuJ{2MqyU?^4$hp+|WP2G~D9G}aXrG+y#2pPXYIB#N0z>^yeXaw{IvbQiZ&osNtSmVW;to6qD)jJXBP>=LPd;<@u zT{Kl~q3*@U+CHW_M3-Uct_##1*xl5Rz=zDud;m%Yi*ly_|IaH#?ty@~EoPen+He%~ zcF-li7gEzF0ItlrVcdyy|dLPebj@sSpR2PKL^m zx$ODV*XoO@0cgk8v*6f{bWN25ZBFmL-_2m0irXz6*W%0ue|7~uTs}mLvj$I4VzF$? zb|>QGUV{VJv-~m?{3R;lzLqMglbW>u=hy%LEd+850%dth7dXY!GY$MNq0%? zgD#WGRZZJy@EOzVT`kJ3h@&cN7N#uz`&wukz#T7()AY;J*GdMUxxNk{QAgG@kp771 z!vjApVASYt>>3mCYVf%43InP})0FSDM)b|@m@~R@lm3n}R4x-`hEHFM2(|QW3+Dj# zRo>ndXp0R14pl#Bmi*|IzDNW9mvzpjt1xq*hO&)B7q}$fkm}W;_I7#(J>#F)xnmdm z@4^U?5N^QwF$TQgn#ny;6!69LU@sEJ)O+{hzWje*%KzhA0srj^<=F!EFOTux$3EB)FFQBG`t{kE4cYU%wGjCf zLP^toEwh4zwr2|xUc7+!bv)pg5+MzPJkVJ$0ECts;+6gJmKBV0DyKl{H~_fx=D_=f z@c^`bt;m^mA5Zi+v8}!WpXCSx`a6Iw_5W$_JENk^wrv%`049`RLNO7FBp_L!00lun zQh{Vp0m&k{ic}~DR5C~olA}n@pol10ax74CEQuxgtbIp02A_Ln7XSczdmaROvr5|-$%Q4@4vsL0{P_+fZ-aE ze$A<5pq3y%OOUF40Y?H#>u{evANbB;@|$Q!+6QouU?mG+_+k zkfNcHeXp86nn)EqfwzTM+%b4d&I1i9&&%c7J2PP_ksmt6*ICm9ib1hD@$oA1Mb&P= zk%XPgMYcEL=#VHI9O8~6L!lWVSEgU)z-tU5DO!fSypzLE648G7XT(mVXH-gFN@Az} zV-dsYQ}in zLzuLXm{=w$Moo=a>Ya%B`Q`#Rt8k93q)UBI{#>Vjy5s)oI2|^@3vYvJprG{*Bbh&+ zbzTgk3hfWnzY*uILDgL znrHtupwiMmogxL&J~8n6<4Hb%<6+dXxy#;2EdHk_`oBKt*Z+E06kqa%?a0Od+M0jA zt^Zov|61k$`W?8=kxzZFj#0ji9GzeO)qnk8@p~!Z4Zn+$^#AvN#!m8Y%;;Ffjg{jU zk@)fN{-CF^5Lc-CS!wqD`#%HypGEnb#ruD?DDBS;!dQ+V+a7&jFB0&R+~L5<_?}Jz zCZ{o|h>R6hZdx9&5Q=#EKM%(T)mRWZAA_+7Ug*eQ)_0lr3gf=>IE=^0TeHl`=8C{m z73606#hFst4Vg`yN8LFHMtFHLZHu>FfQtJsCJ)hU0xhsD#j; zP{XTGhysfp>(KwPER@tKqog^>vd}$v7jnc*wV>CGZTt-g;*ELiI(XmM9p;Q0!Jzam zV(#ujSDW{XCqth5f(itNt8<;LmhHgYF!g~DR7Nid#yHFqjKt$%XFJJC=StFrU>2RM z?|Y-bU?^PEe17^=$F;4B6IBfj!AJPAZiyW?7;s&N{?p!pCFsqZ+`Pz_dZZTm;HGz} zL%jE?s1UCJl>N&3t?(SUmCV++d2|i}>s-G=%XPC>eCuod^ENb1R);c+6wON5sj~4O z2)M-drtFBu%RR=Pv?bxMoyCewu=JmAr6oohXajwb-~QpgEZHO zi-BM0TqNO|go~`Ms00kXga^0#L3)mS`fkwe3%}Z=9_RpyDJJLPZhlyk*b`)C)LSr7 z=75bqcfB?g{5Fqcvg&CP;^}f=qv^gJs1c@SNk<0RQqO5l=c!wOWEH55LA-}XXg5tA{E zp>V@kDN&ryCy#7jia)dYX=$d1H`{qi!USwc#*n7x8MhyCXJgNzuS)NyuoJ@_t0-$_nS)>mBi~{ZCMfz7QeU+lM=!eQnH)PO2HEcj!TsmnL07%hs9t}3q z-9yDy?r}nUb@`3^?B#|WXvc@f`v}*~lr1*lX%C#f(k&l-r6+~{&dY5h z)$vdbCH1|wq?cdv7eF)IHu@~|H0XIS&bff7Em)nsA+rN-L1swW*221d8ms<6gjKnJ zf$^}yPC{vXu|5mNa^FO07I@S&uC|p9_??w{QD|bycQ;PY-i=f`*g>~n8vwXpMVBgf zioNY$FMVRk29MbIN_kVLZo{N`58}g*fI5NKWNYGc>j;gETZWvK8xMFL=XCVlIQAoE zYlvM}VJf9c$v1Dd1{fA|U9H&k}v`cFp8> z=_SF?0j6h$B`6McvPq5_&B%CoMgDL|^6~10;jN9sJI+=!S8cwpeYbNewd7_ke7*tbV6 zoTHoVlGF>{0&w#}PoBZeyba&qO8wK=;ydE%B6lJop7s$Y=s#nRQz@1#vO8g-hVs_pVg5;e1eKhU+h09X6+-~WaeRX+SzJv6$yyBoH6(ZJ+o4e*Ax2AOD=?#L@xCpXycKz<*BZEFNZ* zj%{{4Kx|b1gG*kpzu_kbHK*Y| zB{F-LQ$OoW|08=#x1WrrwivD&I{WvcDWSjgjAp33?--$!&GugUm*A6DMQ5k$fSzUo z5-uu(b^zd9h9j{w>UF>cI`)P=BQ>|sFFQ^-4dE*mm*7Ub1ot!VNdc=D^C8N1zlqli zM;Vov#krD@*TzG68RmvBRj9MstW0-t8O&GhIz+x8=TB{XDkRz73;7DKb=Y^o)hxIh z76m^+`DkFfdLfSjdGs#>T5^w(%TWdbYu!ve$Sp-c&1#~nxw*Eys|^M%FC;tf;tin2 z;lZu_;|pNPMLLg#rCKWA*M)hCMwrcxsT!pCsM^h*$GNU8 z&3^%+(YVpH4RTsO9(;OT!&yC8dWI&%I$~alDG(_vv?G))4mY1&b#+LP%ajL*D-0hBPpybp?bV zP9>RD2c>2(+?|wRDn|BA z)Gh-(rg3SiqaKt|tAE1r5F-#s9=rz!k(x3?E59z~$%~#`lL%k2wNET)Fh-`hSltZ_ zg_l~M?Q0_TQ+JW8R;$vJBF}31^a3b4L?FTKIA>2?dRZ*=rFv&zF2gxkk_lZ(Ds66M2qYJ}8psPCW)I+8M0@ndj%Q-3hu z8B(B+eZBcU&A^v^?_BU@K6M9!ZsAPA^aO&d0L{zN*L(IpU-X$eS7PT@Tkcx{Bw4lS z&VCnx324^x?HpIYu6Rpj-&Tu0Q|6GrraAs7ItELcvs_~Dfh=fTC=DbTF@W=0z>ZGm4$ zYr>3on&lqi04Bb<=-Y$AQr@gcf7YGRrm8eePs}Rxf86+X1`DdO4g7r;fps&TnGuUt z)KA8%)#83a9KWb^(bRANXz;Ze!SsmQe}k|4#+}^Rg1#i(VpPb~O^Fj}L-wFIeGJ2b zX+e?$r1F2|K(IKUSB4Q*=3hJ(ZXPLjS75*{u*Wnx zN@daKlu#?eVN3lg=;F5tS46aiGVLijIFG);ecTq`hwt8jrk#4DX#J9%Ko< z;f|1Zz-lE|2pW}*@S8hGUpd?bt11M_zYSnWImgMLye&MJbCJS&qMP#qX1#1LTW%Ar zh${dm4(hT`FkjU1I4e2&l=%4*;|JP5j~~1L%6eO)<{HC8Bo7y@6UbPex>@@g)qZb# zb17Mz? zi`@A+euof}+jXl;)1h~KZ05$_aeoy8#$4guj$V2K56k_Qlk#6TuQ+`liX;-JFtrDF z%x5v1#l(N#Fo;n5M#!w1dd^w$sc;HF%vzy0u3^#m%!1y!;yI_BNCOfunw)aUV!*ym zB^PqGga!Lqk(pQ~4NLGZ>^Da*6<@Y+Ak}y@DfmS!#=Ri^J3$hQdUe#A2 zMrJP76N>5PWBOYQ^p2Otx0RhLKdIeX7h!Z|PA1CDMmz9uJhb^$ng#dN2hCWkNUEDX z<}zrBV~{-*6c2e)@$8;VII8T`3X;vW`|6a8vLpkv9MoeKk{F}1N7H0p!d3jvltS3z zigO}$(MZ6JR`~nc4^iZ1F=>etI&GjQY8#a|({}A^+4Vwyg1Rc-ORZi#D0xdh-w3cK zdEYsN)41)M`=q>WY(bMY0(4{sO%Alm7P9Nc9~ApxFn(h60Hd6M=<58DiT>i;Vz5b( zdT7^b`3&_5#qu2#RxYP)Xk8Zua%@kw6RG*lJ9q6K$(2iLltOb9rFZ;*mxxk-BU79N!ZBU@gg@J_ zJy6sD(rH^kPw-Mlx=L~20Gp5KjBcf9R(IWpsRObc)pQYgFCalK?5?@w{)k+SdNQY; z(^hMnE8$k!2Dm_IoWNiknP(x>Q#>R_`Gb`ybzzAM+?9ZhTGeR=b<;aOxHj(B`^{~G zFjk~8Wt~cuL1v5W*YDsehjKdq$O=H6_)N z1s~s5ll8Ew(<>nzr!{64A3FBHb&)w81DTHV9SB*{>_28pb%Ts8zI|ffP=24w>zls9SpLB-n=o)jY)H4x`Ba{V)_6=(@?(T zLv{xWV55UT)w!c_T`h4Gh6ZYN>^m@cqojHzicYWq-6P!`BR+_f5e?yd^^hKZK+=)a zjP5dL+qQU_L&@|paG?%_5fcIx<*r`5wb`--uAk)WWyc|gnJ9DI#=Q!jT?FlZQz#1A zO?ViNA{jRVsGAk5u1j&G!&Jqu$MZ5f2=qN=_M2_oCK_hjAVb^; zETPD0zbs#?Q5jw0QnFqMVtZ)u+;{1RoVfVj_!Fc#B-@!NZctdUeH%gC>RL3vr4s9d zQh0Ka;zBQ8Z*})n5y#ik`obpz8xJ-}Vn^?-!s0{`Y-+^BonC3z#~cDp3^0Yw-GL{} zFJ%cpL7EH7u<<7M2WpoTlO_@Ou%+n4(-bqYYRh8_5KbsUj)zbO|J=0j(e8nqPO?d` ziFgs8#l`(`r+GW5{IFZ9#C)vJ+ZfUITQ$SJ;#P2n(0$a;xl-Pox<^k0wuS2$IDHl7 z-r;V*2@nU~3M!pf`J{zSdbzglMe=J|e=|qBcJPD3isLmavF(4+NBT#Zcl|Yl71{pu zeSJxYZC&c8nSqR8HjQvZ#B-nD{MdBv$5fRv6cco+a>pJWRlI~q>s#{_s+e)o7PSw1 zYx(2{hGf<)Ib4&>)Ti|aYTO;f9o~ch{H4ozWZ~rvg8SJ7C!s6Wc&i=eaMjqAYG+fg z;~Cw-xh=A8+|WxkF$dCycc%cKfCEIJbWPJqirvS+TYO=bgjirJrqwkeg38wYAfh!# zeqfa+b0_9X12beWpVT|yrv1Uh>Nt8Ov!O4o{E9ti(hY*?Z0CGiV<2ZGNV`en4-yip z%5QKMUuX%$Cn+bAKv+P?UD&7HtQgB-6Nst;C47KL>~epcIlr^iGfmr0_n}qsXh@6s zJCIzS({Wex&(p7TlP0}@W@vG)@V33~XFesFV4qn6m)g5kuts~}$>l<|MfC7IVc&of zl&T#7X~9Sjbw^>#Kq>t0z_ua2X-*KBIIM$chV^L6Lw)sJquHde*ns9kiT#fSxy+NJ94Kk@i6_EN>{hDL zrx>kVn@VpgR~Bt{j+tHDSMjWF^Bk%<&`jsOqOi=;ewczGcE_t!Lw09(qOJ%gNL z*RM76W4SmrgrNf$McAG($wnx*FHZ2K>7;Y4KX4}UH<37?5tn&q9VR5%*WV_Y*bvLJ zXV}=QDa|Is_@{{UD{~#|UWMb=)=SUfu#bPYDFcvA*&DHMAS9ddIEF@ri@zrT)py{G zSU=1C51D?GP4RNii^-=R!IrxP#0))0<>TAty-0Q!35>eq$#?F4C8Kmvq9}(EE+d_% z*apPnaT|Rfwx$eQ=0PTGORVa*!;Xo8q3q(T8!mhNRrzF zRutArrvu8?tNVm23LA>utbi|Opt3CXS}vg{piU6{>)ODVT%Ro$tW;eKG>^j;qBw&3 zbn#VmL_1q((!DL$oP*tKW*M3T8Or|eEC;oapV1%~)Ei*&jBJprDc ztrrVT=!j0%z8r*&+hQ_t`%&)sq-*?A1MB^ivn6jPi|QS?8Vec(U%pvdlx)WVK0SStMJ`b%0e?xlx_omVBgYIB5_AFc8XPB=opJ$Y%6ldJ|8s6&v^t9 z=>RS|W298CqBf|4YGL=(L{tdy0Dg7RqBHllX9gcI5*cP~0VyNU)il@t3QCx|2s3hZ zA?Lt^jCtt;n{MAe!+K?^Du=qx_!pw(Ft+lVKlKV3B8R0%`@C9fbQWkf&XgLD6Q#eF zeah1`OC3}s$Yrk-sT^P{8UhV&hpl$h{iFnQPmx&&r7@X6ux;bq`?oeHt(7NVFeIvMA2VqhA$K_3A0=!*zmSwzavlgZw7Q_Acymw}T#I5PEB zM%34T;po$~3Pkep%iBcrCFl|_mb@Bcrfy7STisB~#1&%ea&YmK(>rBwpZd&wP#XGp;lfHm$mfCEE@LKBAFU6)Gbd)2nebMmOK{%nYMqOjsP(?VC?< z-+n}F?yL3@(GA+}JBTtDqf2y(-j5SM4Fm{93E`|+h`%&NV?oo!>cmMzdR5svh>&nc z0xz7K#Q>5O zS%CuW`I#lSzPmLwpS)t%ylvbRY3eXw-_@Q+*`QQ&2XnO{Xh!`#J^L*K+^gtf@;ke-I4T~cS=fa$k2 zcaZs%cCP^~R;GNin{tmmunJhv9$FwAV^AgFLg)+zec#iit!n|3(j^}Fj$=BDE@7Ix z!HmLY^1$sG5Es42bxM;ClN&#r$93A}yF|PmyBP;&VHE~_tVCfnR-_A{gNymNj(Eje zuvJq?FQDRVpV-PIkkNwv8z3Cg2I@Fx!}1^G#yLDQRi|*>;gRpi_f2#!BuSE4EJY_* z3NjCnmNn#2E6%OB1NZCWsv=wh$i&6L#5@=7)+FQHlZ5LpS-w4t_DA6BQlop7fYZoZ~wRW9h&plU~7c{h}xFo4QKfq-%3|8~@Zf`I{mE z&1i~Xbe6tM7C1nO&UC+?Y)js=@Zhr&k=!BCghO2QM$H;^|G}ZX>9L{pYZ$BLAqiAw z6_8j*)zFP5scC|hU`&(?e&NZ+$a^r0p=Zszd&m4=dVo|~3!Gm~J`bf&~@Y4+ zvwMCBYI8%W5m!iN@?c;4B(xZ&F16T8;m0UDC&5W7@QvKYifuMF=er*BWkXgnd-W`x zFcj6901g9ENl~9wX&AgL6Bn5q1=qi7Lv4`YI;g_6ca>i$u2mmKxIV74o0Fz6Kj_>9 zl07}LN~TcEPg_damrpyvMS=ZenFnE+mtdLU87MOi*1`5Qc4%Q-INo*klYK>sf(BJ{ z-ip1}I^z@(>kz953$H8^!gA=Bfolg@;t}Avs0FYmvy*`b^>+>p+T9)T3TI`56K507 z6!TI{J=)x>H?c+))y&CT?Y6UY^xk&&l9arcz2#DFLs~9aj#rii;iuo2 zM+kI)o`T4y@ncjp*q2)1(%m*3K_)#wqpsP)FurxD)VdK$2!^PxZAi#l1w`?}Vm=wW zY%-ej6_b%dWHGNoNvs zG2-Np6`I3zbf4ORC0As5ZnRN3Hq^W_%bGyBjEs1cbOME%=TajG zCGB!9zS|va(Fe|S^%nAr+Z5ljx!Q%dfS9WpxSrA4e5j+$u}`#rLPy=29yEg#XK|uO z3!%l#HvoFh$vxS~-?Fa(t{{qEYAn*$M|7B`#!(Ifa*$fqo9 zY-U*;FTU?~Vcrkm!qb-puYDybt}M*X8`4fuWeOI-cT28W6Qp?5eOmd{iaO8B+pBfT zOzTCNOV0k55q24UtTQ?}$B)LTL@ei&z7I#x}Zy|Azi=Crtf7`s7 zedKYJIXEWTN{A*|yse?Dz&PPZ^Dhk;)ff-1OVSRS^A+X50gapAROsucDYvq2D^Kp9Xoy%31 z9cFIX0>hPp|LRT=#5R1f5C&Cw?|l530*4k3y7i?LzPgZPCVI2Ci=~HCyMUeNLrG^O zb}IFw)%9Wh?X_3MkSv?8=&65ZP@7ygzF5dHP%^XlI)F51XLL?nCsrLc_IIFXpDiU# zWfPyzI3N36bC4AY-bOc>>_ld~sncRH_WeP)trLdyWGU-`MsER0zjwP zIQepHqH{l6$AkVHrcL)#D^UKp_%99kIjloqHi)SNh=%Rh4GAIO04h4CBp-yO1oTm5 zm?m;~_x(n=DJN^Lj%w_X0G01X;JdyG@9dj?#Y1(V{VndhiUD=119|&N@3~jvKi(aR z9A>wuw^x`25$wg}`6&)7X#b4?$-~CevHuRg1)*pJv*_GfA^kZcbXqO75wR9Oxh{0I zwhE?9{7dwLu~F>JTuPJcN$#^9$8(yW-)?%A?MQ}O?dYkyo00$L3ZGG4ag;C|r0-e0 z^c$`kT7`Uy$w;c(=PqS8E&Y3xz(~ocA?=O#ZX+w4&07+h!$3VCMqPN*ToWYzhPI>S z12oE0;xad_RMTDc?(RC2?&LqKQ(w@K;#)cK`Z?vn)}A7p^R)ZpD;_>)(dQ=ZU#~EV zSvRc7VSD>nLG@nrK(%6AeQNM3ga>ca<6?8`Z~xr7ym79UEft>}V)A$0o7r*F+EHAI{M&F>^N6d^C(7=F(UE@5RXcZy!ojNs5glOe=QJp>SK$dt#eAa06K{-{abui@@ zoZ>69Fj+mtQ!8Gm+Ag!YQ5RI=OII=a+!@I_t355qutmi=kk%08n>o;~Jcjh$pm8?& zf~1&ixxgt?Tb9Iefdjb2U}`WBhUqJW50|8?zQRqfWUa6U42q~li;hZncO-2KhqB+O zKL;7^Y*qp7A07x!xo-+nUhqoayPF@wT%D!trDI-qEzM-gi;6xRY4j9&14!SBV0u?p zM*=HccFS=cP8^O~(x$KYkiB@$rEaF!>&GMmB7WIJuQx&i0@2(y?o2PVSE)n`zCp-1 z;{zUbi$;Kz^$Ilnx?qByFdc;F&p3gdeMxe&1e(t3myRw;%?@ln;rtmGRU*&(kMydK zZ;vg9Ja5kDPy*bS-jyN|yt}UOnF1|IH70Py5R@J83RqwZM|!_5E+~P>iVh8ZaeF0G z)Vf>r^JB^g<4=BPjiEcblCb}kriZIC>%y6=9Xrn3%3hUFGad@%sOTkGi6|ul1j#Bf z5Z}S;6)}TmAZ8cJFknuvtc>vDR%SAqJLiOFw)I_?gNqmH*k&yro2wZB$H^Fyk*1gv zvPj!C$|DMy4H7+uy2Q-RS~U)sza4gL6^wM=Gd;7=LsolEQ<x>q|vST@d z8}UCq{SO+#zphCy=)``{k~ng(dhD81)fRP0%bDDKKEuUcTCSPQg0467Kr$;}t~b3! z8}(Yfhc(%gS9yedW|(KDyD7iLaM4(V>w)G9IO@6vUKCQ2;V8!i7Hq=h9Pyd&y3FF^ z**!#_)l>RAMY@?{INthFt@j_&R`0&-!1fU)#Wk=ySFTMe43}M9cgk)ix)g9&5G+Vm zn5s?ajj5)a4pz8M5dbUpRjZgYoT6xoD8mc)S>!6DIR-*gvPmTD?L)lF`QzwV^v>mg z*ywOX`rQ^9pW(dCSK2lfUR7R3On4DWqCu*#IA_Vkxub>A^68sM1R+1^kh#x8LvR>a z(A=PjNSU#Wj7Ro>?FAW3=P14KaMh!+ReaPKF-y>u?+Fv=CG)B{-&>ndzynD$gku07 zzYtV|4*mmY{CjQz{u}T~Setx{>)8#q_s-77ogc(JX*A~=)EfiB$1FQQqY-F5&f{K9 zuj+Hck_upD`C(--7cBH}tHqr4A_GW=nBlUSz4$ZJ^vnWE9iT&n8UX7$ylc!%DB&*U zqo_N@R;jK!BM+<|V}7tD?JowP*^_MMd8{nQc=xz9_qb7a*~&t7M!D#V6tI|Q5D^Y^ z#(iD|_;^kO3ub=I0->2lS{FCz%3N?B=Ok@a+#XULALpe5|gfIb8n7xY< zSgzcBtSdD$?#JR}1@k2Rzy?6HRV%(t^xA`eu7g zc}Pk4w&Kmz&$3z(>4DjE;Ic#B{jcvO`J={kPCi zu|#M#_4W3Q>`GO773CS(XZ$ep>3#_z^|E_|B&)=%*j)8Sat?rU!gqzvIH^5@_f>Yk zM_o!=xL1)1r<{-4I7sAEbKJa{3 zPs>Zjj3xrXr>|!}^VL|m;W%GFbE?>yCqJS0^);$om(>UQZvA`8x^_EiLjgPK)-YL# zBGH`K5!yx>nvzC_98`&E4T>zdURK8rP@P^@_&$iwUe{`8W9xgTu)>eIU3ALm>2O8L zBm2y(^OO)@{XQPZn_o#eN|zGvn&d+2X^SF6=??=NjvBl9MeqpOD4i3`kTt?>&#Qlk zVia3|s{IM=mMGdI$VTbwjg46ICcvW_p^&+)m2Vb|vPEc&K!TfI%F1<`|E4B(<}eF< z8`9jfqs%8Z{a>Fw+__5y2uzEdI&s7&TFU(duJ;8UTUjjDXyd;>(SMzHMrlZ9Kio6v zxUF36_J{yOvr_JnO=Iz^GeI{J$6=r>S?gfeMp{_{!RA3&mu?KoZWe~y<_x}USCYz! zVbI%tW%>%SNhY&zo%-N@m8R*rg*UWGWDNqK4?rjbi~_$QXp%B&CE|rC$V;9-NJN-t z9{Y(-Vzt_6iPvVVgI4|`ed=BVxe)AwEcxT7D^dQ=zKz*NM%sR3)~yN8taAX)5UO7> z8WYNfRzuY($`KF~rVGu!dOR2<)lRzhOi)wa2ib2x(du(_Rf>IyDuN+ao_yLcGW-5# z@5$_E7#SUVEw-T)yn`sv^OdXVLGzR{ zA}{5N?n#;;ge|-lt!byLe7G5zrmt8Xi+J7nt|6b}u)~bT+ImVaVb_=5wQN#w_USJ< z!6lAFLJyOyh!{i`0?wOX?y-aQJyU@Y>VJLb{j3Bppn=LvKJ(#%^?NwYC%Vga9Tco8 zTWY<5-;h6^mXQm^&pMOxbV}OgAP$6f49t<(2+->7*_gcPUdL~4wgIZB)9Fh=C*JKL zr#$@hy|aI2_ZjyM8-oBiWE?hlVZ&g1C~z3MSLBcHVX#w5`tst2M-`&-4?g#ST_KMc z=ncm!%3I)vhk*)ui(|9uMQu#RArY?G)q$_T+6aY4chSS9ZMLkU_YI-k)vsO=tDxUZ zmYd=kfr`SQFlqah2kC(eKaK(?>ckr>^3Z7S}ZuF?wu z51DtgQ<+yK9IQ~6m1OXe%#rs!OGB%+p_{;L8Af)LnNg})4k&G|6CpZ|1NO#*8zzc^D9^~wp*Rx1#|9S2x$NHc;aJ=1cp( zW|n1*hMWf}la?IX6x&9=u4Bs;(@YeWy3ivY0~U4Gy-V4pZd=S!jFhCgyVsfSu(jJ} z&2daocPS8dC<}14xlI`MBZyV6G(LHtih7Xla87QWu+C?m ztIqmCv|(O*$X`DouIz5NfPwb0r{{gH2V*4MCR*dM3SnnU8R`S?dh4{erJc#W* zMBlPz#&)Gc-|lg-XFL!z_Qqt z&}kRKAmO{1U!AJKk`&HU4X-q)f%D825Cx=;q^Mg#6 z#5#UMaY>jPsgVvY%DI?t=L|}P;cy|Y<7KN+=O~!gtRHI~jsf>IgCJ~2G4KW(tMI!N zpd61n(|3~3Y-Hp5AdIfZtG6PYro|`X8}AT)G-89B^4hjPaK*7;(_G`R3R<mJxKl^tFJtbW;`7eL5pX->;~-8o;K6&D91 z+YJtGrY_ys2Vq>*X0GuMG}VjihuD-J?MC>CoW&zY#`XL%Z<*QOYU`B^9;!xN?rSp@ zoY_hmMKlyO+0xC#rwECi(dDw^wzr;d6HFhhZh*wyZYGhblz0@@GUe{^*JWH}BAzdD zD6ftZW)Gx%;nT$9trk|ohsTPyF+v@ExgJ z2d0N5>f7u91kp3ViWv0kIdWD*u)R9!tWw_A9o*6}{RPYlho)WGqN1X~17~}qY65!l z;(i)aFW~wM2lvcN*|#WmA)E_wzJ&E!?4E}=A> zUjIJYFu?iHRUREC*B+qW5;1HvKCy zp=u0@SdHloY4=G$u`r1o2fWYGGn_~9!>1s0e)DrR2_BbFAjK-P^%LyiY6}yYE2@s5 zoo=So2?Zz09-zXz^x1%_R0J4;gd%v3bg&Za%xQA5%a*`8jb)f*RFY+KzPfP>9u5YGIdkn^k+V;^weR z`n3r@;>%lO3Wyl5=O?wtVZ0{7I}=b3=ORi3Qm;)Q^|#$ze~(DSqB9T=@nw=c?QBmx z)ypNcd)@LMZNnR?P6;;ZnTY)2svk^12BM(UIN1g))Y_Z0;m>7**`3GMh>Z>oQHWMfXgtjzal+Ff&8UeoAd{p^h)sJfkjcoWWY9*$~Qi-s&fZNX9Z- zyu^Vo-Pa&dk&*ILxsFI~BeF%`4OyHtn`KJe()P3>D#F9dK8fb7f6y#D0^?c%n;&=4 zNS!u0%L@39*^)&09_Kcgd6hgVv7lIO^2;XRPVxX`Or>?@9$BFYKm*dj=Yh`nsH$^v z&x3WDg{rISk5PNszB9!nbb2A?jEkV@*r`!0*kzPL@qmIBVrnoN$?5ujinzUVBJ7~S z4B?<~Khm*Kq4ix17?>`nrp`|JNgcG=ayc)#TP@6FOH;ueOLiC z&Ru(Ic*A*dwizY!7Ua}8rPN4Xmi6~n;cg@9frH`E{mI_(4t0=fSN+HiV*SBvfn8{& zV%c#~cMVwJZ7;p;x1Lg;C<(GV(o*t&|M##K}>osDA!=ztD!Jo7|!x_R78!oFwy} zH61Wq_DOgADwhaVkC228#VZrYqi6JKAT_YkIM2tmvW;c5Y=wJfQA$D??fgC1a^_sKasM0o`Q zlj5kGV^Pa?nuR^gO@O%f*hu+P4L#=?gqh}CxI+jqAzm<(il>W*B2k5ra{OA-EMzzj zl@p~vK4}7pr1#AG;HF#B#LGa0LZy6~+BXAdDZZ`xx&)O$(kH4EKDU8g{UO1N9NAi# zm0%vb5Y?E%Q!%FrxDSS~h&55Fxxeg*sl#={5xot=h!eUBHR2jM`;`gwv`}QD zt~#O1)*gXL3gYx*wr~y$sV-U~GZYOsHJd$25p#i?)j+drMCIZ@Vf#_pRF%XzdLV_j zZ|aG5g`8`VtEe4Al&?*ij*8G4nrwG{R?gQMLR`N!W9T)%r{FH2H zYmmj|3@w9yFXv}yyuZK_DRE44%t$pjUJk&D=_J!<5pi!KeMv={O#)Iu7swFb0ny#( z4-tjG>x}>7&&(vy%De0qm8o#T5`8HKuMlww03E}CRTv8P*FTkP-60(nfX1D}mfE{} zD>FUPneI2Eg!5x}#Hi$^9tkJynMTA#5j}!Ly#w{>5_pyvda1|zxxp`Z{|qhWI-)Gy z0IC5x_ZcM(;xG-}x1V#!SGsM!K=q_u+W@5ik@3>38E$5InL1}rie(G+iDTjZf3_mZYeE1k;{^> zr%#7O(RNlzVdvaHN4sxl3D{bgBIMffQrUsrCC>Qi_;stq-8egiNU(*q^;L-%8wsmF8(I zAyL?2=2%G>LXVw#DNQQ?wA!~Vrl0=Qk$_u~JvP>uLZELFyb=UpPAxC@_+M?mG^SYT zr*50m`X~9w;&unMCW19v1SC-B2ktHWrdqh3ht3Wwy=u*Q@(FsG97$N9YLR;#5-Yp+ zf-YLrs~>oRip|Fi`_ej#IwVQ(RMh<8SN?H>GtQGiDe7o&5}BQZ>iSPPpq~&(F!Y(wF}( zT=b78Eg)Jm-Hf(?ER#PM2ByvE0_}e{OOJtAomSUeH+=4Xi^QH)?=_gb7-2|hD|NIU zpJmmgE%68^$Z8*$`|KPWO&Qb9FpGMExJw33rd2D5< z*lh^;Z@d~!PX4)2jK;{wxF(neBIQ0Jv||R0SDM_+*G0d{{Dag1YiY&iB3iX6 z28+kk%;_)jGE=skXF!q8;viVKRwYasJ$i)Z*q4I&fv_=BG|~|LDA1id8Fh2EuketX zQszba0@^=8I5Q0cM77GI48)HzwP=4zK-HbU5A>|C?2mkM>6BdoT}7oT;d`J9%qWP)H&U80{q-EmG`9f9Sp9s{?L8@6xnC&g*Ypua9snh;8fz%| zu~3yk2(3Uf1TTA1abAKkN^U?r_<=FZ2cBO7KY9G=0e>qp)LjM*r`@n;VnZm}kFfpq zi76NHKXryyaEQ*({^o0X)M9^bPIM4CzeP9NPcg`0uaU$*uA;w1_MavI_tn3jg9c?r z23I~mG#dc*{hjp8dEAy5w$+i*IwfZ~1 z{G|U5;C{OZ*?idwePU)n706sRyc8hZ%PJl_(Uxsk{aWtr{jZXUhCl?kn9=5+GX5*1 zA(N;-C|SN&0?H_z*;*=FZUt0{28I#PD_6U20L7Ov#2X|1K48h$RUB0R%>?J4&CU+` zl*Pew7HMwWEIUEMX#$wLLem+!^3d{H;0PH}g4cXx;4P~6?!Dems>P~07g7AOa|gWKmmfB(O~*V=1m zCz+XKl1wHulL$q531kF(1TZi#WGP8eWiT)(Juonc5;&NToLuAG1~4#$bt@4OMJW*x zVnru=bE|J=U|^CFDQU2(Nm|(c+wY|u(io&aX0wQYfGG>3ip8T8U?d6(N05+|ttRxN z6Cl!%8j8Rc!^Ot>M?=>ee#Syvg*8=FT<#AnD?3H~YGi(QdcKx*4qbq%r%(WBa-`hAE{Xk5xAfyH8+?D!@5&YcxW~7=|;C3$i3c=(>QSwz@>9fJk3CA90^<|o= z7p;>N^T4OKz-X`#y;RKd)vOqT>5T5(NVoK1WQ1Jv9mE$wxND<8OGDV~0J=I@$>y~{ zvo*}Ahp!1=(;}5a)@0e8_Ml{A(=GV2tSn3{5c`H+e{f@5oGWa}ga_o-pS3{t)eB&ex(Al*uL7I&!+zD`5O^3To7+I0A?0Cv=8Yqqz+QP580jM z6Knt@8uage(mqJxc=#eiYEAg%00>2>mcSo*NT-mn{pb!@1h8^DtemLyK_@%dZLoj< zz$~hMfYBv*v=CZw5EUBoyg!K8WE7(zNHZRGA2vh~U6D5#s#w@q5~VtLSwu{cNfn0B zzal?3Pi58vNV5pf=kJ*>1f&DuiT9hPqnz|nToR;1H|`p8BIv`F4rn>hXQSGO%Ir$F zq1Xk_46f{YIiS8E0EED?;C~7p6;>&JO-7|bO7WK#l2WQv3Ms=-C9eQ11zJmN3f<;~ zD(22=vLa83>f~?E1^_KtQGbN!$7}`Dix3HM6fhKA+Kif9jR4?7z1?lZ1Os-j-T`y3uKQevcG$YFGE__?lnRsI{%cc`#ItDUco z=WUDxIB7AoeP_c~GM%(Rsp*6m1v- zaNYw>1K0y3!ic*R`MHeZs^pm%n-NMwtiQR9sq1sxBOcNpVns>u;&ml&q)6wrm8p+# zj}Xe!KoPR!I`KZE5vE)oERT%sDKGvnvBLT3id|Ij$=}A!rP&T34yX?bG33UyBMOH! zv

    h7Ry|8j+&W;)-*G!yCk_Z+C?9OujLL%J_SZbM8+X#m^Dkck5i}ErJ$>2R#aQ3 zTbCSDEa5LzRzRu}ECnA+9H`us!Q|%qQuAW> zBJ^>{G4k>KqJRw}+Y9SFTZr4EjtubsG`isU)`&2iRO)_n?ZJt)6jsIAsnyFiTUm>uWW>(no3iiFxNF_DoIorma|uvCe_!lJ>1OOO;5~O;uKv!3^rXQZv?i?-%!?g8;aLq*8Z%utoAfF*6ppO{Mu|TU48ylTW{auw`X`n?67*` zu$}M+_qeUUe(I_+sWEA>e9LNfZIo-QeV{!{%p#Ye0L6Gqf}6)R{Af!(j)J!^M@MCz;3TJ@9Jre&18wlmCVp^xI3#quVg6 zabeZOr_Vqz4Tr8Zmh#U(A8DSIfazxO+2kC=gc{qlq^Mkc!eJ(87Eq8RxN+_)TFWyG_k;Wshx7>}m?WEjT^6A~*rs7x6niP{Bp^tK_M+WrxGsKxGswj@ei4 zMokYUx2p&;S>_?3-U-?00hkxDL38(uTkC)yukOxUa<=U{7$+ z`z4&@KJOub5Vj&)Ql4m6s!#QP>bn}UHF0~m{=y$*d$f64fvMtah;5_y*{tB@8kE2i9Kutsa)DY2n zw2s;$ko?Bj!)4|?f?Z1I)oR=t+4|k~X5)L2W;17No4ptCZkTYAFob98LbvP2IznWu zM{h{)T92=oq0^4VPZJ=2U3BGraQ_9r9PyMJ<5$Be#iO+f$3|~YV28ne z%R0j0mV>~(wETP7=^E$603~->K+jkFY%;ZRsPWNaWac2}vsFqH$`1v;?Uk0cv$>Eq zL^p=%-c?8HhxwF=w={;P#$Pjfj=fG#6(>t7E1D~rH9UIuUAyjk`?ayXIj0WCmR(2Q zjgP4l)v43%KP>FMw)p)iL+xVt@c4?edfTqcwf zF$+Y;VEZmUxbI`0s5~F8&M*w8`u6)!zgoXFALv}Rj_hUZ?P1g;^Kc>L#Y2}CfnDA) zGE)vg3U)$+IrcAl^HI+(`UOfsyhoIpUrISbw{m`URbO&-RjVdhj|y)2%E-2&5H3v!_8euK zO(?=0*wMdjX8q?~CC+cfumA$~((P4YeS{ziDTBB5L)ld~)08rolLMpqNW+1FhgpF^ zeWbuYUi^<23=A?c6b$y`i}CS_=0W_k6iP1-@}FsllD{ensfb8PeSB3+oXpJZoGtBL zw4Gj>KTxe$scO1t%E@w@*xS+@nc5qh(YxC^`~?EW>(2d=v^8@vB6hd^X6MZ9&PV#U z8r&c0zp@!fiT_r`#fFbmQ%;ds#NNq_n4O-Ho{^LvftZ+>*U8kJTUk{6AK)K|Bi8>Fk`p{2j?Z@rar^n>blH zxLDcS5&wnP$k^W1g^!fvUC1Nw>~<^@K*@~6Fnotzi@wm^8S^} zt!U+L_DxIF%JzdjA2j&cIXHR$R{#Gg`8UP?fYkgqBoh-8$A5zUN74Tcs^)CwBw}y- zLDPl*-$U~c;QuWA2OuxQUtRwXR{WjMf6M(~G(Q3_!@mZNAHjJVHwO$%5KKx`NYx$u z)Cbo4liJ;T09jE|PP{M;wIHzjo+3Ol+}2fXc}ws0sK%%I-7M?8rn0iKj2OFa&I^`W z*dHt)K3?4OBL8isoxzRy;-I@LBMpamH+#l{+3h^r>%4vYp4tA-B=rvpg^>{lMuT;Lim8`Hd{9>OX?^sN3T+wIO0rrrqBlva8(! zL)X#T9Qy0^s@lKMu9d4$hQr^7HdQ&bxf~^G9tR$d2)Vd1P*K$cNa+8vbbUOp(c9Us zm4i~ar&rY41iSBT156vVS-KLiG@(KPc`$&76g{YCA|}g;=!Q_Z;Nt%1mPBwanStVI zr0g9{aSBn*rhjGcFp~W2|d_Ek7a1SDTxy#bX4H@$WVN@zE`W+u>v0{$x;? z%g2!QUj+Vx+&Wso^fxCf5f?4i4H42E4CiE zp2LCz3k#DByTg~%5u6()Q5Obn^dat<|EnwiYE}oD!|7tbQ%BeHbgrS`yDvmAm-B^x zWMrhdf7g8+^ei6H01I=2;oB=J2hVm6kN8wJasr>%U<*;&K!P66`i-*oV)xAG9HYa4 z>E-3M`onQW{t4Qk3o78;?0?U8!pZCC(v_^NthS<1L$z=0-{}9}ylsL2 zm#9-^#;;})5f=|gO3Ht;kWApOTgfz+-f3JOZ5i^Bk{ zkBpH_i8V06hI@IwK0acX^>D@nm>fD&pkg7io+E?9pp8)u;@LTL*hTO~DGJ9X6fQ6h z?hkR%d$_Yvj04c8N}|@1QHF+@_ z4X0Xdt#sv5jwOT!e|w8h`2i`D=8IaXUW-Ykki`ve_k%;D zNuzcXY}=<*R_Hz8`66g{Ff@Fxw&xAy_~dxE$Lj)PL`WzAVfz_Z+y$JEB>egsapz~6 zKBn#CNO{y3-Ww1mqtg)M<@H@)b~a0$!){ugYnG$tv_JUkZi~*Lu(vMiB?uJ!`!@z> zqBl~HZW9zU3rjKQ!~Pzs=<0k#QfaW!aHg(VUZ}Y4yAZBC3%oa@g^UF&+7BKtYy?L8 zi5^!Q;(Hfu7I=N%H-}BW8P=giuy-Pg?ohu!QzCtT)PnJj zLL(~3yOd0KpRg_HcG{&>)KdPs4x%LMfQ{}PyWC{wD`j*H`kzC$`Q>Bi!qvYUD!_n% zcu@85n?u5slR#*z@(@LB)3wGvd{Xq?%{i}Ocv8}V7|rtc`x##9Xfm4>+u-A4?U2LN zEc;-y319yxVD;|lDbmVJ2g=5V?#~BIO8Eic+?P-K&9ilNiU*3GWK@K!aLDlJS*M5> z02qc|5JWQn4KKc0Y~=aT0>z;73_qRL(AM@gDn&F=&`qpAWv(ZRBrK^m=0PNrUKUro zvH!3D2u$GdZkq}wxG^29Eh-8z_~(%DDCArnX#3s2Ap6@FEBGKJaq2axE)L#HxUX*$ zJdybWtvVd(&#NjxJ!45xnJzm^RZ>V)k8tnTRsj(aJvy{pdo(-COX{hapvzTvVqPiK z0{^=6-!CCIFpz1$#RrK>6yJUl2R?kSaH^{C(S;G%bB`m}xe|d}Hnz*#?RO+k_mqD8 z&*1q+#?@cUCzaP2wY!pG`_{MX7$<<^xk1tg|((5%gE5GJAKY2=HnAV zcU_3#2*0b@>=o44@3DM-d@Qh-P@Ds>m?s-MaCw3_O$)GAm2*Ip=0QFw(66J=(Z2OYS zCsE2^QLLq~I=qk>IarldVs_Xd$112&?sW`keizwey?;F^sdD3?gS4Dla4cCCar2T#pPSXr=l_SPx}3BTmEl` z8$zuULZmMgn?Xv;x$;%LoD*+c|1vUm%-{4e99q>}ZT`8lX>=0FV8ow@W8kZYt3K*% zI`%sR7iIyk!;Qnebk>78l=msTALzL0y5Nt*wC_P`b(`5-(C)VFn-@d%_0*QwL-eBi zJz(uv>^IpP$xMbo4~Ql?HMKtgQtI;0=h|?U{>{K4epWKvjVqFjvZ5j^-}h6*0Zd9p zMlfu@$MRVYdUo+_jrV#Ajj76FJuU5uy2rxOpIWSf$)B+LIB@yRA{vwx1kJ~p9J$Tj z^>KL}BN@|OZrKb)C|^24!f(o@dTF{O?oWkHCK%DV_b{=(PN(7EAt{^clGx)&nVLGB ztT&GVm34^~thQ{H@-al__}#a597T8e7A`t)M7~S!OuXNVH@1T=**{m+fBAgH=K~7g z;g5JAkHtssM_1bUG>f&B+T=qE0`N<_lmA2|fEep^gDXS|2}_s@<;VHI6_&qg0Rgd5 zV4fYCrAZ?egZ*hf_$MZ-_|4l^$BhC`25m77}k^PW%H*frI9jAF^v0Megc*c%w0XG!qKHLhp2+Y6c ztWaUw#IQJ*(<0ebYWiGzdwGmXr&9NOL!pkk(>5m$nmA@V`N?=4=yA4$lhQ?@({k?5 zEt~fXzr#f-3fl<=a|@dW_9%(=Kxa!u_?MWUFCvQFCK<0Tz2O0=g@#7Ltn2g_1^=+t z)`NcS>GZEttoy|UxJiA#J-cURhB-!ejuL(M>*5LU7ew5hBmr~_83*+RL2FDJDy1P8 zBJ<01!ZOnSyzcX=32+(Qv1e;^Pmieo+4_HWNpM6AEQVe#2Q@Wy%}){v6mE||tJV7g zr>e26WxTSepcV=NiPSDgWg&CVD59BQ#r22C_XUrhoqzV}ffWyDxk}5z6`;YQPo)l9 zj*DL>9ADJqgYhW{HH2Y|tQ#2_Ik8yoUiH;{Wjt4mJ}pk)6Oih6O_Keyof=kdV8@7k zif%##*7y^E%{3|LQ@{|dh)_PTfMpGBvlBHnE*AUuI08~c^if_xkt9%%MBG%8ih%~Z4JI@M ze(PFT1TK+t_DUiSg?ngy2!E9i!p>tOo+DJ+iNX8kQ?YPTd0&}+1X|>$e7Gn{S$Tr_ za4j*Dc_TKz`Iafh+v(1fn&ekp`cN*t^#3V#x!ED;@byNc0xLeb9vK@})(XH@_6V4A zh#E7&)7e^Uw>!l=DK_IX&b%6pJ^SSr?lkR^jYdSvZmsf$(=CoOUUs3v69kJ4woW$pIMe$e4QN@*ajHUs%O$SZ679XBUsP2K2un*#j{|Ha`K?(kY=pJg zhOG8Liq@oO5&6tZ!l-Raan%_d6`FP!@%n|Js+)tQSDg5gmT7sP$3pAC3*^*Ivd8BxB^baqzHLcwXHDN+gxD~ zfk<&Th`LR`VKQFw>^@aN z)IT;RrAq%awRs~3ln3*~${w3iLt-ouw(oYO=e_Lo61!*cy6ca!JZ;0+57{D5)+j+k zM#B2;LLN?o+wS3Mte>J?_H%=H-_``xsegWzEG-)5P&=WN0?hfxq}T6zb+sps6hHR4 zO?__7A6?Ke%=iiSu~bR61w_bM9v82q*_JaMOLauZM(29nef?wTqFVMWFRT=GUYwzH zd?Iq1tq+Kjd@h1b|36tN-Z!U=uU8@8WU?n^b}RMFlG4KW*|ckP(wa+R5@e;4Os!Gd zk|U^L)Z!e}Wwr=l`Ho#HMc|<-X^$ia$;!O6vIu5dO@7@(J;_8C+e{|o9-hvmxGDoH zb7Otf>%I$-T*<3h6;oc$>dw(TwBmfJ=$I+oG9QOu!QVVIbNIj4B@9Gt>I>PpjE&() z3FdbLv*U8s@H2GCL;S(WD!HA29Kv%uJI#V80(@SY-84S0YUJG;4YUAeB)+Hf*Is=g zaARsha_Cci@3!$U4-D@@IhnJO<_0Xeov6?*1B6b|I{Bq~_zO5qu z;Yj@7GYQSGP-f(Tz~j@ur`LbibVwnYHNGvVl+{oV`(KBozpE_YgZxc8=aN5}LDhgm zm65r-xM0;ZQU7$cvZ7ATpceB%?wg}e#YIB{)9d`sHs1^9_-%JeVwCy(!o;5~Uh z_~v3OxuTLDv>MyenTM7}$oW=|{!V}g?UHIJG`{t*^^)F(ITUUHia*$AJ?_4+Q5hg7 zoNN|5@_FZlejzlSRs)pp!>&XjKYyDiS~{N>`$yT5WPTj~6Wqr>VY)a1`_EnqdWjgi zZwomLK3Iuc*KRiBv0wZ$`zU`x#}#mgLhG^CZgC_(m62C=bNtKV!wm+J8BMR(;R0@9 zVNuqfIDo@MVkxt~zYkSYQxlj*)7>QMx!*!o%613>R)%TB$$L6j(h{yq8}K=0;LMr~ zEKuMMWtBM)F}39H@?ssF+&91>-$Q%nLm$o<1i!Exupc?np^P^uUvKHB&suC$YABG@ zw3J}WTbKf|H!Ce5T#h&JrgQiZ%gak$;(8My?b7)W&)a+eiyW+d&+ji_zOT1CDXJsK z8yeCEPqDLZ#rZt|`Ql=or5h)v)xBr0c9#PWTyQ!#_ot^o9#5LGqXFob*Qqgew+vfK zBmlx-$y6{5$WpV@oka0qWEtZ%PHEsR%KgIUD6x3G=*hy-jqPrzjv}AsZP=wG3%=+^ zJqNOCtl@xn>U8e_`JCQPQCSJ5`PQ{1yxuC>^Q;7d{#?8;Y3ii<-x_CZGV9m+~egM~#Q2=3tC zL(BoRvq~5m5+f0EW5saMYqEDhELZE)=B$^r0DQ7;Aol<{d<1pMCL zhwJrmkKUOXqY0W3SS|6WGVMC)SK8T`#T%cn-rat$y?r-Pwv*VdHRuIce(^l~(Mm!= z0izT8S$@u{RDhm-`tnTx8_r514iH9}0Me!1J~~YL1+{o>3ct;$Ev1-v!j}*#lb;eLri5}UXkRHP37>} zf_*T5eQ4U35@$uu<-nPDNQ;>tYVv1XPGBEBerb6oW~IWt0G#^0=gE#De@Lq~V>nIL zj#-g|(S$EQvo7Z6nT<~2kdXuG>KH+ujsbK!EmYD;rNik=CUw1to^6W|2P|;#@WXUa zy1KfC3nf#LOL}p-4Y-sPccBjt?%vP7`Wdy&$b3(UE7Pm>CjP@%IB7fTUzf!++d4ZV z&>&PMnz3I&JG1KCzmV&2}tf zfQLgx33|3`Lw@T4_A2_d2&Kt-F?)4*`ODx~d?}3LdQ9`bAe!7A@QD`mlISa#Bd4dA z$JHHm_UDBQPfR4(eLAs#w}(_vP$;XYz<5naNEp~j%*ul0aXZKIK>_}je5CfCd!66j zHo!Fo1_RoCAHImgq+MSltTtLGGZtnG^vT6%ozAi-U7efB$Q^cX)UGDIP z$Y@T@rQ0MnFkXDznprA7`f)v`ljMBB4)d8huz3kulp%?2XufT>-;|Kc#VUqDZ1wRc9^_kFZkaV+$0%n$pYVk7>?aT&~3Tk-|9@No3;=7Gm>q>hBn+2-IV zH@*y4x8Y`5@P0?JTI6h)!)_LigtoQ}E!9>NJj9Hg5rNO3Bqke7KSz&*o)iY96wvs~ z`wx^)^RZV4kfyW)Hl)voW0O9b?x$I?C5R~&LlL+AFWWL906a=O4JJB^p$~Tf1X@6V zbGebWJKF3F3kVAfGj>Tx;bFd#D=qxT%N_{><|V4<_*q7p^zu3((FlP&GyN7xM_5e++q3Hupw}xowX%s zgln4Jog5^f02u_q4{i}(JLnhCZ7ud~FSf$${nIp$ebA8#rHQ*4*dP0`;Fzoy&0u5T zY(L{gD%UKeNEQ`Aa@Tb%8Bvf}RGMMB)WRVJ^sL;=AnInEzIP!pSj=y&HLg0Bqx(AR zTkbIk`?n)C(D4b(f#sz4pL>RIUr&GEJ%w69;?PGzG5e(6w==%Ei)j5=w{2HS*-T3~ za9J51WLk~tfTM*{e-`{|6@}tKo(p{8LeM1&Au}$(v(5u|@m}Bs>Eqa-?ovEVN#sX7 zU@f1`OO6ElMFI(u!Jc7sj0+MG#}{6wm5px)IM;89K?~~%A}2f-o}`E+qSZHz-z_eH zc;`q&>HpB2jYrohXd9co*Z*N&pT$5SGrBH+8M1R0v+|95dS={z zYTHL{ioN)F-CDE5mt57@tdR2jMK5dGjAjGgkL9RCr0I5LGhW5A&-tXbw{KNwuzzXo z)5d0|aIEaeuM^FOGFJTI0Y+6|&u4o~7#wD(*Nc(b*$J^{L@ckPA*a7Qd&h!(=()9% z7zfFW5}-bbqC3_+ZwygY(iA&_u`(rn{hDOi6dd8-b6?T`4OU+Y!l1ko06u1GD|vau zoF2?-Wr7`wZO93{3@9!yb3sAbgIj;!1u$R`q7YCo=uu2e_9pT5KtMx!0~u3OvL2G} zqJ`5^h4Ej?gHpTyS~}Jlzp!&6R&GP{3ky>6!G&@djXEB2e+LYb8V$?6V(DAQ?-puo zD~4YXBIUkY@a!MpQcm4oe-AP$q-KZ+c!A_K{4@2+#I-HP>D_0zdJH(AMB-dplB?;M zo|Z==w0Y<)tFiXXVtEba9}pxvfQEJpvEsN>D@Z*#Im6+mI<&lah9yd`<=vUrE+GA~ z<97eLeA-Zx>q^LbyI&}NNOeCJd}U$?0-|5;C(R5*4BMoc9xv0u{n_#^!Az*gT^}^wHkWB(w~Zw|P=F!??E0ca0+w(06ZB)c-u6QQ^0W zKW{AWD#NKOPdIsGRz8#1lbDM^wV-1@Ku=d~OH({Fe22ExVr3QD%I|a@+d)})xPzWB ze$6}|nb%f_kAWf5H@Kj6R0@L!OF4B~4I<=9M{Z9y<=|(+B{hK%o!@|8@aosdWo3BQ z)YXJOqKqPL2or$%enMl4BqS2e+Ce2;&8n;0DQEy1O>j9D1y9Ca!R@k~eHdIM0B2U7 z>3QQm7zzjqBc`SOd}AI1C4jV|is>_qy5W~Q-|Ra`!D^QyXfh#*%b7<+!QvA9cykf( z?)4@XBEing(r7544u(J5OC%~G5qX|v*9BfQCw8s%D`{n~sXPg*rQ7RXWI96^m&ZIg z@j*RjaZtv@Noo4}6HFZT_%Bh^du=K-cw-1ofi-wg6Ax{$mt54IP7U4+tW$}KMZlEBp)75S5-@lL!y1UiD>`offW3}?;HG!Y6(73;|en3^;_uNdyQL(ni63Dc% zw^-0$#XzyL>BkCR7Ko1dF&}la;C50BvS8u$UdjW}JQ@^78^7Pto`+m6~7&DPG=)jYcl0xT5Q{|FSpUEGWm59UN%9Pe>ITqa0 z84!v?QBG^wYAveuJm2hW{=B`o*VIJ)Edr27wI4H{VSuFJy8NY=zqXx&e7m%tqP; zyuv97zbGa0>;jS-EDGrxjjmo#S%hY-Pc|919oU)p+>W1@y^uU~r)~v=h=~mt3X{aZ z&OKZ|*$fY3N(1F`U__HmPE;m6gw-VxP#-TLMSu#r-(*?JB)6g%dgou zmb$$xS@dlP_jd(XAW4}U-gbX#i1AP#F}@t#ritpj&3#Np`2wToeXn`9KdHLx0l#yIv!Y72DeMtVK%}3@N{x< ziXm@<4Eu!gak@iyX?Mef(WD`lw-4-ntkK2QldR1XkCV5qv^u&M7$^{v5yio4#_+nw zIE&x0Q`A+hdVH=-9kUhxhzMDI8dT1kLKh+1WSlH@K9pAsMBOES^w?RU!`+yJJaC%j zLfR~y!dI(sf_@4M-F>wQDsuqInLzX0x?cy9RM>Z+cDP(6&a2-jJuhh(sMPS390Jp8 zJ`;v`UpnXTn3ZVCo7=IQ?tCYwBB_9#We2<2@_u>!jS_N|(wB5-3bjrPfjtCXKzkLK}UE3*e29K662UCnI0 z(=AuIyUguki_v5lNweFtInjMqov>;*PXe~Rre#BCp_T4XeIhm{=2O^8WEvvfay?U5 z+`85g`S_p~3_g?W*w~!Vk&~+{1anS$Vv-7G9Iu9!J}nZxi*88h4-D2+#qfkLf4I%$VMPZk5>Tj*cSpOSu$o?{-Ax7 z#H@LLSqXFaRoxn%?~(4HKXb2f;ypP6*MtqufVA@2?}is{P?59=qg7ouD^6jp6*g2h z2L=nm^}`Vt^@u;}^{^-7vOk-b|sNuO(DWIjlqB(mF=SX=rfUm zS~hq7#G7M$M4*a_ide%quB~Ld5P*=CVMAP;?rEJ$dxdfQv#7Wr zbEuM8xy_GDyc#i5g|x_qb#vZ77)RPkOS0jojLu)Y(6`&9l)aXqOq2~My5U%jtnA1< zIuzZ*sWW7Xel?J(z*m^C^*cy`JO(^Z_S6; zF9#RtW$e)A`W$j(rD@kx(Z@C08!!n8yO--H_G5ONUN)TZ3Fn(`TWI>(WZBX7c(_jD z`s%OGw^ok)x9@DPp*@ewod|xiF3I!kc1<&i3MDEP~vh!GYyG+Vkg`>7UjI-N33IJ^M!c>w343uOs=;6+DycQ=e^ zz+v7p>TAm%mwKv8glx%ZDSwZJnlO5KJyGTD_t!S4aWxNH`Y>q_kH}|_mH0F{RY}f= z=Lcb^)LQexiGv3yca#r3S|smhHa*CY$9j<}K~`z#{bJjGnND7NYI9aD1K@8qpyDPQ zDCu%#tinr8XpSuL}nzRxj4=$b)tF6&?w3HzP0jtyu_?T@E)V$hf zbxdqThe=(pEo@#iP9AS6uBUeAdqb&eic0}*nX1G4Td4F-N0QIYFb-nP<+1G_^nS~R}st; zY78+u1q)pKoVIdrPsF%|>@HhLQBAO5iao&d0bT{Wam2K)2thOi7eN^Hag#|j9QY9f zhtT^?#aQh(32Jnkrnk(7l z{a*c|^$qK7rCWkPw(~?kVS(J}l5w@ysQSE|O2SBI-({{^au3YU-azE~7vf=FQ^AHh zlQBUz@eg(<-e@9TWr9QOKZA!8y+M)3C87g=DC*KsSl_dySo&cnRP5I~G3RGYBaeV~ zWi>tWO`Yjdncw6o&rLpz;IUy~p*R_CjYZygSjwU`0}`=hQC$?NsRmkFj!@yPdqBqztuxJe&b8KZUrvCe9y? ze##45byQ5$$7Fl*Gf|SEA-u$R49El11l7PXug${jpG$iszhF(uRG7#>wiU_3W>pc^ zl_vp-hstZ#q^?WkbNzmqB=J%DfuPW6yRC9vkdA#11ri_#=FWcD3kGv)*@Rbsytzb| zTtVQL(|6=v1cHL4bet3Psvz(K9F-r`Hm6x}eN(z(5YYYX_h~8I^npC2NOF998vC7t zY_C{=A2sZhO`!rlv(g%tWh;5k*Po&jQA4dhjyl z=6MABw+*Cy+x(OdRaK4t%4#X?@?F7Xn()cT`*5?@kUyJ%YQ$+Oao>V8?w1o01_sjJ za4dK!y*wihlRfg$<6Db405Ab(DGv6&J!&bmAIgCF5i^1h@exUKU8nXe4U#2sa&!x8 z0}moT8#MwU*dw)$oN%EZ39hI}HEiP1o-6(&Aw|!OV^IFXf5)oG1?-wcTCFoh&mM{7 zH4}q&qH1H)e@{mFHo8I28e2j1>Bks$DT7fC_M_ABPaFeggnHGuQufz7UHXD?{@&ha zp`jucRg=VB4uQ9@DHY7r`z?phLt?mH?q!+t4al^+8;{PGi%i~k!2wpJI$p(R;>IyK-%}26MkIHz5J68rIYHzcd5Uo4C|hSujXv+_$&cKJ+kY93 zF;Hpnt zeD|i7+%GoRAR-KsA!(D)b}p(e!{<;;Mn`c5M^7-%v{{OXw|h5Rrrg|eop7All9C`V z=Hx-XUkkIH!wLjRX))^yp%}pwXA`RKX?|%?E8Fu1OkLT0UI69Tec^4PT?AB)Of+KD zM79%lsvJ_)junhKq`w$)E|YaMcAgcKrpYG9uCKLpq?yIt1e zrk+mMgjQx?WPws#epDIPv<$t5I9HxMz27t9Ll_~{(JafVLlV1mF9)CJl^X5*(OJxe zkW<4b_JX_1s)&gY8kpx+(ZN;hdJ$VG#*$xJIPa07Gkh>Xcw8k%q9!MQByv@s$n5RJ zxj#Y^z?g8Qv0jHe6@zvQ0q&b$NWVy5Gw`G^H6(l(z?Oh?!e-@%{CCNxp+#pphKEjr zx52(F!1t{!mk}ggoo~X0s}zItJPI#DASL}24gq#Dw=`#oFmbpbL_#7-F49ih^`r!C zd|gRFqAG0BtW1;=vOx|TKV`Q7K3C%Y&-Zp=ze={@gnYp-C-qSAr_`dh=)F*g7?1ZL z|MGf#N9)U`Po1QPLCgNpnU|1%gxnHbQdA_${uA2!SIZfr!;T=U>;qg7)aI!Qc~lTA zD!bQcae(&zJR}PrRb@mX@pw;QAU!*t9uQWdvZpv*$oKhg}CVSU4B$YB@R@H_UG;bTwzwUpQ#AQ*{2^ zwshy)pa(7=wSIDP$!*eUVuAH)$2li~#9kQLb!7ff>rr{gKo$izyP#@Qe*675g)m4j z7Bbpw-c;C$UOq5Pa}Ya?nqD}7-o}p?iCoi38{EQ|ATzOJ<^dZ>NqIA*Z9DC41ve(Onh%> zTXf9IwcPqT`*Ee0U-U7wwT#ujOQOsgT@4d)Xn)VeZs^h|a;_NshDvgN@Yn1tNH29y z?*7xmyPRsk3O;jPMZMBZY8r>j;RTUlknkY`c_?wSU-MRCp6lf+ z`?po3C~SrVy^cGOUS6d7vO}IjeQTZSt%?Fajc=<};=lmugU8RmnR!Je#FW#7U1L5e zmx&nHWV2cUAKx;O4n)NB>3M-n{GF8 z4`(aLrY&i*I>G?57_)+aJc90B={dDa3AkSO6$cK0+AP)Ob)p!t`5j@i()%hc=wfrH zwFD;fR}BN0^@)HwRJgaA1$%8JiP!tTqERpA4&`UtK(ClAx`fXK%{f zqRqcu|Jb^^_vrZdDOog`8SXrpb6Yxkl-)G_&Uq~SN!`4Xh>waq8e1)8sPHYGA!FXt zLpyv>LR3_e;UjdnIeU$)dSh$l-OJ;R(Rx$4IJX~YPNL3nkD`!Y2Zd@yLQyfE(Qtx* zhHi`m6%AGbHeoV5I%YW>Fb!E(F_N*dflaIJ?&XEJXQiZ6|MU73>y5=~UX;mUPlzf0`$$|e|**mLUEERLiA9Ww?`yz>dvNr0}+cEeRH|7ALFFI zUF=+WeqEx?eZ&LrhErrC#zA`hh%Undd@0$3obB}7!tCWZv-|#XahN;omP*&#^o@OV z7-fD9xfb=-ok%Te#nqW1?i*IM)$0DPiP1Hq3F?pLPWHh+KAo&FtwW$mdqA+DfFEa0 zPGq}APxH`n$*XNSWC(7%F`Sx~8CNJ5+kv$T18^9A!RR9h;+S6Z@4*htf0uBU?{JzQ zL0GOAhopSLV3E;qL}fadulZW}0;R6@`?0^=cG{sl@i!I$8o%3Pel(U`Xu(0OWpQiQJ^MjQDi}I(;CJ>m3rW{GV8+w6 z^tIv6TA0i6afxB13(voEsyC~tInNo`5jJrnTDOl1SC6x@A*`5NN0MWi@&xYOp@+){(LnI~nB$4si0x+3&l9RAz3 zI|e2=hZ|1|{nhcVX3ICc+3(d0&@LQl;#SvAU;7kO_V-OL57MHu%cQEN9=RSJd4 zdAS)D7ZPT=nu~vIOP0MK_o%p_P*bhCIa|$ zv3%guY1_OsksMV)blUw!1R0Ch?J*ZUp3eaG0LK5iCx1QE2~+2TsUid(etvOzd88Ds zwuP;J1qFqT!$UfE`LWUr`0O8}Hm!NCQ9D3)&}C81i-tEkz36E%;Io&`k@_xIi10T4a&^HQ6?$HoF7V35W1vK(Zz z1RZ6x{sq)1DJz2=%~f(|ET=#SK633t4gdZfTv$k1T3Oj(=E({`LAEJ^pv}iJ5PUp@ zl8i*&9*Pb1|KJyyud1TZ9Zw;}klo}e7KyA90@8f}#(hC$^q+=320xGw_-P0Q+FD^d z!TQLL&7JYM8>piQNf5I5xr2E*IWj}LIy>Q+j7BVqKSIt`8=%yqbzJ>fM#aDgto*pr zAFlD7&ga5*|MUb0S7-j`=l99oHLufe%XV#0goK2cC&NE|w=y1ha| zJlK-k&yApN!?d-i!LM?%eRiJdhH? z-u~$0Lc`@gw#S3%lenStTONybw-Uubg?0I6rQ#a<-yvTs+D}X8ywFk5<8Bd%`-4aq zhi!a(d~hQpBjC*zxK86&Weq?!zR6%z&npvfQw1SuoD_0BdrG_&q{I2TRIlCMQvl|< z<9fP+hmPST?(N;KxBhxCncD6Ol6ygLgvfru!NG}iLBl>hwSC`|z7s3`3lSK_5f>K+ z72tJ!eZfjQN`d@)`}>j5;DJ&hJJYT61%br+l~+w6)up-U-}>4m`HnL`J?;3w0q3v) z@=;&Rx$Ip(qJS%ORGwVb<`~gYuw$TanGA4VFVtY#OzUh$L_`JgpEavrz{Vf%JczA3 zd?Aib=%P4Y249cyN2m?}v2RN_;4uo&u>-e7oL{~m1x#Di=2dK11LW@%gu%M|VDW`XS9%p^(5kVX=Yl32a zd|VM%cXW*2a6DV^_vOd1@UQm;QU;*HZV#2PFiE4`I+?kgfrltj&$uj+^ zKyjUeT$uOC*&_xTBqkpm5GO~ElIQpK+6xrZSNbP6vBo;q#Sg19SCp%KNj@{np+yq& zHiHZV3BtbZvh?@@1u3c#v`geR&#Tk#yX{bYMtWKPB4Jz%YlXr82XR46=Czys5@=pB zf#3Sth*`{Lvt&B3;dpP)_Cu#jlr^dXDdTWf2{tOlo`^T3*IOFfL;5rMR=lTdK^avb zN@e8z4bad^-=$06d)B0~;l|ipo;b$>RLhy8AgzjzQE)%um16bLfa05I`1N^#L_a5} z2fx}wBI^R*yQap*3S8ci5vfu2EqP8GV2ExjV#Ae7bD7N5mW1Z?oO zq$EcpXzI5Eh*xt4DbR?Ci6bT@HBN{7xoZ=E=KTEp1nB5nl4dBEzGPDrskWVpnLJ=4 zBT_o;4yjJot4EWmYtQIt*a<+g{GUHjd;9t(mj{Rh1Fi}Fuc%AW{9mYxJ4CfFO+n~S zX^zKuw2=QmU059gSUfb0+2?%tr#HK^5er^nva@NTN<4UX-Bq2?wmjV+xSN=iKI=m0 z%oB%hkF)@uoi}ERXje>!1~GYjM$fyxjN;;9e4rS-6Hz1}L40xgRzB)E{D&ssgg{Y@ z)pLVoF{XQhEO0XqW}h45`~^k0FCw`j`ce4d9s(G}{Y=XA|64>kGw%iOmEkn~ zmGydmx598M$YG++LLelMOJpjq@4VX2FKm87jMO7m=<);p4PQ9wto!xG!;J{~@v9m0 z^KBJ>5ZE63jK}O@Lj-;zwY)#Cldb=77_8As32LT^JLALS_agh_1&1DP&l&0Fv$Zw} zei|AjyeANhNTcuI0VKQIlB*7P`h3x0JE)fCbtP~7%K`zX=awiW6@JEHpQxz^R1WBG zvFp--{xWBadXgs&)7P%ECxU{=UNE718AtgGn^7Me4^O@;{u|y~rj$uWq0=?$@cS-p z^GyUK1O*9zDbL{$(E;&J?(0f%S#VEtl>sZ$Rsg5R(4gLlGImlPHhA5Yl{{<%w!Olv zAOnp`|8mDb%`yUw%I^=$Ps$n=_JC?j&0iG>&tpv98)uLmq0vFLz2FPC+ib&Q(we3) z!BV~F2lJwaT0G7@M=T?PiN5f@+8y9@a&nkLUL54;o;}0qAxD>|>SJWv_sV1%k;wh* z7ubD$FQdUZB4#o*`6|-RD7bFZx(;7G6^v@9fF$b#gGl(Gjnj9F3QX^*_VQ16h(TlD z!3smcWY4Q8i%Y*&80-PEEmM_}o(@DwtwLXh-uJxrQTyu6gHy0OU15|nH@-lEVsd*o zmq0-&WKh@Y!S;Uqf4l(to)G=T`fp1ZzmQQh9SE_u>(Go6!5E45Y6$O!8TH1+PY4U4-4e@x%YwP1D~~1SK@7P*gyH{bN0Oar zYDZY83*s%J{8`_7cr+zJypEQi%FAv!>>b&{%6|O7oHJvyPD)Lsr&2xW(Mlk0xsH=3 zK-2C!k@UPS;zWajg6bJbEX$Ywf1qzD@pXY$0uEb+m-bZq^Z&C$9qkrCHoXQ6%FIfK zd~b7NSAGp3-trqtT4(NtuzmcETKZ}q%91281l@ac1s!%lX)qP-hB(;dB2Ucl=IusA zYydt=<@CY`?K>jZV&-{+6nwwdbN=AxDxx3b)0lt9*WWc|nOH#n2fB(EX6Q>>xsNrJr= zi=32IW5ow4kj@sOKq~fKXshtNJ{b;*Tg_gFNW8*YAzNBn!0`fld&M?iVTiG0yb8!E zcC2bh1S~&Hd_33;^$pGDCJ07O{3!1)+T^rY>H8hm= zsv_M=UnWa!GxYNXRV+*R5h6#obOFK(^sfv~BJdhrp2-olK8WR;x~jmEY;QFM+FL-H z-~$8x5MmcaLRoq1XRb;6#TgC0znH~JfPWNhqTO4xBeMtg6?(!X1;a;dG2*b0qPJHV z%w1gKVV^daz?N7+C}bcK#RyXLAJclc@Q8rww_6L#(h5nFC;~`V?v?F0upzV#u%}o& z>X6JnoK(|hJPs@PANT80`LT$MPQ<>txZX34AX0~A_~q%XPKSJ@3P>xod)pSo8ipvF zPK^j{UCF1UqOV9|5O4Z!5AZJhRxy(%WQF$*Y=xtU=fM06$?>V_Ewxtil`8L-mOy!E zQfL!>U^txQ*_;}{Gj5dyd+)BARM{#z&_Bg(2Hj!+#(hbeiB z&$cHRp7d+yy-Df7xE9LnrW+k>B7S13{Q5#RAS7B;@M){%0|&agNIFMzZr<)10b&R_ zZ)_VV)dK#6bw8_6^ml9m7J(Y8#!M(20%hTd{DlyBRg?`-$SPcCAVY_4TrfQu7T}2` z_cJT`KUpBd(WDVn{3YkQFENU%C6ZMc>)AGc!9bqka!16%z5=-SC1JXpAhMsM<>|}p zJUVi!DokZ7dJdIO5u$AFC%a`3TJXWjs>HNO@2;jsFv!jRbH;@ZU7LbqG8{c)B^oi~ z&aC65d#Cxyr4zj&vuB@L5&^nSB3|9PVP9ZJVj_gQduv$qQo=Aj;C5OcRmff;YgMW? zcd}S*n30KXg)q*@b;_k9`D$e%R^&8Y_b)}X>&aSywg{cjb0RmQUR~HQ4~xwb=A`Q& zs?w;B1c7=%;?C}@`ay}41ji{z86C&at7`HOW%OoVKOEA*J0aw#zY3z6vH8BP)JqWBMr?ba zAW$_*hCjJ#Lo%BxVR%extJ!0WYZ2-5#cHEZXaYwzqPV_3bb)5Iz93fMSXsUECYo$o z8LM`e5r)S1M-)OHcj;epX}@#)Vl6A);xsL7DmVR9Z2Xn4?B5j~pF>4JppNna+~LIV z!@zQN-%xe?2ZNUzBAP#f5VOFRt%H+-Pb~jXXm@+1VdcEy2zi{u{xnP9eB9aGMG_3f zrRKEh{svFU%)XlzcX70b^e%a4Sn7$Nj93BNrUn(856-9kgi%fAn6)XzGFL9l%*K2A zFxTcdXqv{N+D_u(^y@6iK6Z1r3rvTAT&msBy*9epF$7=7RrHuXgA>(>h{~5uI}~DXIRHc_Amj>c7Zlo4P0*b zAeQDhBePA#_3k5*7bM?>dfCjoOCWrp=bfs1nX--nOttUN4=M@-r@Y)}%W!^DeTd4Y z(rF9RIW-WW2=BK(a%TWX)T#ZHsDyNUOg@; zEZq3*su@29_#Zq;m$QgL$0hfI@f{^8lhZlVnbH)z1Mx|-p{_Qn3+TZu%EJWedMz3> zB;vsu+W<`BT^I+!Hf=q=;C`Q%MP?;cbrifZNtQF>zTa6*)!%WyXKBOpvoM5}j_01@ zW*fU>IPQpWrG#?{pic3Q9&8=$$Do{q$VqXI>RhiA;oiEywR*Pon2ZxR20J6zoW_f8 zr`MC&qa(FauRo<4o-UWfo@3W=B~)Sfc^|09-#>o{Ic|R#q&JqfZz8Qx#5NKQY4TPr z`2^Cxi%fRezI+^z7AJCEEoPfy`%&|^&^=%HZ=L%+QCMU&+P3@~!^^9bR?w!D1c#LI znSMSI`qyVcy&xlb@eo9G=oAh_lhvj(&1MWa6O4G#;Lf_MGe5|cNm%g^flD=q?xw7D zZ%yPtd_j|M_=3oHTQ^x;pm4n@*;?^kgRkA!tl@ohcxZ%xZ(FRG#h|+}6iWah{L&6? z$!vAf8l5jQGCNWi8g`lG6XD@LO#UfPiNyCj8`u=2%_$T#skOuoDhK<&pp~ix2RyxF zNQMweMho}cxZf;geOJXKG_9wqBgl4v*?N{=@!lKh8`D5#vLW@{uWZ(8$;shWAWe8F z13i|_0g(bsX8^Qf)OA6qq!z|amXIqX{6yc!QZJrSPTh*KE>4cuJ&)e85XaFUuUo36 zeMj+>f_#)V>+l_+vFOC27Z9N$m#0K=ES6y`gp;1Cw**mal<(vd#=JCd>_N6~4rOv) zQ)mE_sI&+RM<##hrtrY|Yl0$WWbN6W#eEi^^A=5^DJ~){CKpGug)oqq5Pk=)p!jkW zzBz1O?~;a$PP97Va!`rPrAX-Vo>UePD5dd=Hz^dcX~GNTff|zIm#df*HoZst8HqWM`F`66CW;vW5l_}TL~j{IQg_ZNRIwqY-08Ouwp-%=Gv^2sJNNqy*g*1zh@I=eq_%~H%KATBDxA^5Oz z&7e=}?hS*$E1;0VY-B0j^jgPL(xD`XvkbvwH}5{2tw`>VX*@JUf)V6P(<$h9`f>2( z?15n<5=35=R8cYG$Z2UEG4~KMnc9<)Lqt-tWuwg+qpwvS#YQ%Mm%_p2VNj`0yfqV> zJNP&bcBtmnYnn-i4UKbH%}@=MF+?Js+FE+qJHcDrC`C%pF64FavjmfSSBb zFdm%aN4vC!TkQPu124bB^M;S-tBSQAenEJE0B0ds$IqXzmf5g~1eA*0PD$Q{R;PZi zN8-QWoFWa!`b>9vfUKpV!-m(x6ewaj5`mk5aV@WlsyG~w<{6Td2v?BQgaRSharBhw|KV|d7_A`wL<|}z#&~#xp%vC zWifvwRZPiLr6#jl#vUFQsQe^rBqq^PGMy~s5Y?hR49rJP=QjT7DAHmOMzfA!Q!D}4 zokI-r5?0Z7fUQ{sB7l_Ez=6Zr|N6J`v zHdDsIA*R&3Du9+?60TUSE9Yn`Ox38@>D?kQ)815U=PjV_a2WI;9YY^Z@lJhx>rYF= zMFS+q$CK^VNy0GlfI8_{y*8#Z`PI?+E=UFKqNb3PCb;S;#@2XXm-vy0A9 zYqi{3&DKJm#eTuGi!D~B^7xIh%$?P+#uw>fiqC?_uxm_~;N?Woa2Qwb63No4bh+7+ zSR6swPkFXLY{I-3O5zKfUr_K{p6YRiSC1yhvS zXyWFvN3DiNn{${a4H6P`vjhjSH+2RJI`IA!IG2xi&OmSU^XD(9NXATS{7FTv4R(E)-WJEYVeseAL31kQ*m_PIJ_4B zDq!SFt;6CbM&7vKX9n?V!3KyB>c+!3MDF#b`+j?h`lD9B+3i!O7jTD_R~JMWL9`I> z1`UQVQ2WsFLuh=}sdh->YJ9QOP3Li^ym!6{NjE78%jCELjyToV9J9;hS<9%kgj+6# zB*z79swU7(vIJ8%NTjsiSw%&0oL^nCqLanWGLJ2x!xW4>yz8<-Qp4a&GbL#>^$^}~ zc8@gG;Z)^6IQk<2f6-w(MCdWXS`y9>bTYBJyn}0Af{z+`lG(Z!2QWoHSoKq{JC#{H(~rVtxMI$? z#~z4ej+iY5wrzGi8g%9U#Bf?6b*xE6r1On$k#k?>St);|J5hYJ=Il=z6HuvVqZ>O8 zKfRD3;If6jq_jfd3k>(BZK2=ABa3CbMR-RIf{*$MIz7IUimaaWeHrUu?!cCkuY} zyU;wBAOMtdM`x1=#igc$5wLiic>J(b)lkbFcKFg>r6L8lcXN(_9B}_mbJ?R~8d=IY zp9yIREp3b_YZ!iav++I?--giRc+RVb zz~In)XRjN?ykO6Uz^m`Z3$lj)C zy&<)rbEQvqM#$ETs{CMmIhPN^!g(+$ic;-~?A3_z6e?<;W+ZRjqGn~ekcK;%9J!mZ zJPH)Mx6%6!u3Dvt>7?9ZwM2>5x;&@DH6<&wrUUSI45jQRcy*i6UDFcW$M*K8=5ru# z_#MS`jpx^RF6Vw757Vz(Y?gKKyl>!5^`~K$Yd1CZDTt#H;J4!F^IKF)&z89N^ zKDX@G7<-4{ari^89d%Fef5~7zm^m}`xE9FVB??ng8TO@&iz*!TZPNgUx zVkj2(#!7I(#l5SPhH`h5ZJHxnR*TuL=x$8tmyS39N9GW+bw)F^bw3XcW0ytAC{|OMO43bas$Xuj2@QaN$v5hi!leX4 zCyqjq2)O@T6lWTlB2OhwI}p{DH_sumfPs{+}onE5eQ&pkfUhu|9xaHApEI>ok39;rVf!GfX`q9_kg+x8Uo|{e z3f?s@fpsqo2$7Uc`VupfO>)`Jw*y#B*|&P@ixn=|2M~F>uh2SrjyU1rX`fFHy#<0= z&5Oa@aq^F{9Z8Ah&>r7V<8hGi7D8MJO5-VA>o^QJuwpn{7{Z^oi!Vg>;sPwR(mj`of1rMB!|79vN09mIp8%X!}DDDR0TA0(>p355IgDYzi_; zKO3^`8b4I?b3bF8t_9Z^l7`M$N6Psg!5UxHk@Fo^#|?*@W~jd(3D`4@-Vh`%w|!3t zVn{5-yC*m7i=(v>aHz^E#hQNKih;U5+;!G&m-ID*?*n|)IR%X~bq8Yi5Ny>RB#E9r znas=@)( zoj-Mnv+=gIT&=uYE8mLeA`6OJPK)g{A~`wJiW*LOjrRQKq(P^bC)AB6W6 zAJDB2%Yp6Qkjj(N_g_EpuP=R|5P`*w=x4|NuZ#T$s^tnYu2!j-5?)lt!5)Owy@FMO zegOh$`txXyV`W29jdmf6D=-55{XZxt=vL~Xr5x33)Bt{uzh}GuY2o?qnR=679NHGs zBB75(G2x4v#$|)Q;1y1-8aaNvP)R;%*? z_@6(2lmd&ce$2+XIXZ%C{@_+@FE&$?x0w3BkyUl#efF!(G|grJLXOOi4(q>^DefW@pQ^MPqgGadB~B#Y2%LO=1w#)YQ6L zU5=u679De?*7w>!fO>mzNlB0m4GoQ-m&Ug7GW=G(pkiwErhAZGm8Gd;8=OTP?P8r-9w|7&n)7V1TL_>)&XkiZx+)rSgz}UaPpaA-6*F;xWS5OINAWjq%V=%TlU$bgkl#_Dx!c@b2ptUL@a&JkA zUL;ET_CI)_qEb=u_TJ2oqpv|{XJ;#^t5ZEvP=LI3 zskpgOK=c&tBZ&TD8Smk^_P&7f16kLEs?(et#LR>jD_zkeIsxx#e@cOU^0(AliyGDiX$cl*>a<`6jz=R ziEoE#h?qM~4hAP8r#DDA1e-5a49S-N zpCnELYqg*dI=Hvq<_j}Q@5r>-d6RHdAd>=eoI^1g`4>O$5zJwcJr7biQ_>(&0GP5VDyoEJ zf7wzw2s%7D+UeT%@*z5TTkM=`JnLAR(>VI@84D8%N)#F_y)P3LTxM7xG%nzwsq@J^ zC)2B?Z!y)249?3(h}$B^XHMVi>!5oQ9tGA zCnTH)&0CVnqAmu0kp`qj`&QxCAw;yPZytuA)-PW+bSPqO#NqT;wULrauhC$_XFPuL zkZdi1DW25myE&Xmsqc}yWjy7>L?Cwq!Ftk2TO+}OUYN=7T5~cxY!lS(G|XhKNxwIf zrmW{|$IHl^mmtBztbLgnuSAZuiNj*e!O4k7rCP(9Qb>;T{cF33 zyW=6f%A{tBPjqy2QGpafF#H76CKsuPUM9`6a*ybr%`Zf1=jxN1z5YK-lafpwGUDS8 zW`Ozmfpy-DEX^A)3^Y8}IF6JqKONO3MT6%@SIR+B=zt_#f={#;WHS>pqT;H(L1AG( z1Gdt#2>~PCC-);C9en8tbUR<}dD^Ucpk%G4DjvYHlB1=p?>1cwsy=`4Gl0(^Id(Y`Jq=c6K@Bw=FWN@EPh zVwKz!`+5k*cU+z)B=rtn_`O}+m2EDs7eIV%)}Zn`ns9uq&r=yIt7@DqBlxf3#t+c< z_g6tj-1!q0840qy!Bx*xR!~6xoh=xNj)9S-=elGeSv4IX1iUU}rb|@Q1Zf-;bA+2sqLt? ztg35CM%y^y<6ud!BuK;K&lpgaN(z_e7pvpak+iu5@pQRgpuac`7(Jduw()q_R073I zC!Y_j@=xyfotJq(x4iP$tW53-LI#e88KK4e=q-S3=giV)`5Kw0ov4b~Il44`y;*F0 zvDDc$1-zT_FNvUU5e=(G{i+F zZ(Xz*bnPZ|HrpS4>A4ex%fi4+h_yHyo5s7bum17#H_HE3M;>Mw{hdB|3kmEum|Hhee81gIDHuQXHW?ANT zsomY8K?NWGV+8;Wu!x;Rx0!pqM-59oDYw+uuZYx1mDqWNdq;b>MRGU;w6>js@e#U; zwQ*;p580^_drDUt2m@L3eJ{kpJqTS=l^5$^X`83n!>ZlSq+g@q1 zXA$3L74%OSjPJ|p0{|h-&K>S8hBYB2a?Yq;sEe;dOZ;JXg!fikTEI0s(&arap4#!|Pu zJh{l*=dugHJKo_eh!y?#HM#7rP^*bY_d6gCMs5npXJN@a;M|W0AKyA)nlrK-nUS%C zSB*X6D$uGR@{8IH)_;ykKz5XfW-S&@g~%>(QcOrF3?h?Glda45ncIaLaxO8_P1_>a z5eG62HAt2CBiWc^DdXj2dd*SQF)77IbF;jNX{5~99oP|xp5WkMOmy^5puiE!NNr$X zz*xx6`RBLl2;>x;Q>p?ipAO7Q4n&VYL&zXj#N?tX9I*vd*lbE4e(vd|zaucH2`Zv$HOliopKXL(a`U%4m9?5byk4$S6}Sz)i9lzlCy1 zdH2mqKYbqB6H&f}tsp>nZi_wLUfoeV^;252@p8KrLKXv~lS?}M!_zY3g9uFBvnpc= zklb(1bdBzcb9L^ot>NF6u4`z>6@0y)HCcQv<m-Ax=y=fOH3;8(Qn5 z01|v{Fq1B*DP$X_-r^eQ?Vb-hs#3I(lP85Dh1W(&ObcI6O}#!MP}oIja<^*Exs?M`!UDT=8l;DwflMQx{Uv9(DIS5Juw*7@*STY=mwMLf(H zF>oxe*YmN*jyv*5n&;^`)(+z&`>~`P0|uDGN*UGR0YGycTJd$#%uda2 z5H{HenUII(GNbwPOPMO;mWnk9^mqAi7MFy%3|-ptki@DcS;aa$goNdzb1(B1H`PGW z12{NXB}?vT(|n3lwz0uXq;{<_InUsB4V>)VF8g_2s`uc)9&1eiokS+C!ecQZ$>*>Y zw7hvw_$QM$@uvqP6BC)HdfE#70RTt27LO{!%w68bgdjDvQPG-FJnq*+##TOr)!~A~ zCLG0>m_el(VHGLbZz{Jx z(oKBzQs+G^-^Lk)x`bah?=06}0}1zdW+yt*qBmYY`W>O7ql+1MJ<>nFp!Q`4L0#|T zyzZS*Sv~x(F{+4pA0w_YmgY=erxd3mi7-@(I#(*H0X2Pnveu1*_^d3+5#4+ahOaTh zUg#t_-B`Zh5-|ZwOI7{f=^QaIFlcCL7X>QMivw6;ACJO-YEd_vGbp3?$tai^?smmEVDZe8YP>hzr z>C`$Q>?VQib3ggHx=Zl|`WyC-zeBNqj%~9T)))-}7C%XA&_9(|z_^<^D^E7%4<;TEkXfDCVL808`Fk2Nw2!!2qzz5 z(7fd(HsS#<8y+Am{Ty^Tsf-5E5}`~lZ#a%)EOpNI3vm{jRM=mk`g5r;7?HA9LeVY^y^Cks{}%lIHR8Ea6!v{TS|XWdXI=1=s+>6&oV)wLsJwp@4A3VZRbS9O z8e<69Z*+fYZ9L5lJoF0C6}GXtRku?!)1~!uo9G$EPhn_@#b(z3Is__qsC@494%W*V zg+t^~-V9t|v4>EfUv%s(jXL|&t~FnYkr)&KH`&AC@fAFjVKGXbevY`HtIKEN>`?fk zAA`f<&xz|*`*|-yz3r-Jn~rKSPTqFYMPBmm!I5cr(bF5m7&KmW4IZVG1v_~ z$-#KP=^r(CM27$Gd-(aye_T-S$ER|Sf8-j>sP4~ex*2}o8N->PR9Tpac;`gqglTg5 z6xe>q{CAZ1o|WjzLDo<1e$KDn|6kkCU(51){*pUSK2b7X^@;h@|LF>Uf2^BRLWDrC zitOIg`ad`Kf6stCnZbn=3zxm}rs$_(?@7Sa@MRShx5HZ_S_(|vO-u^jsOQ<;gGHR3 z>uF?ciFI{!=w*|?KRN6C^LGV_0wy+4;o%UAQyMj_g?!3On5B-Y(SX>nh=iyj@p+pw z3sawLh)!0;s4Ii)&?W#l>sw_-R*+S&0lZFo6Wg)E=G5D=a)4#HX=))U!_D4cUq-wW zr{D&Wf8I0=IVuU39LlebNMnkEfnmiv+mbtOpC2@mbzeaH)E`tWfiGaY=BANyQgSiV z-$^>8N|tr9Y7RSzBm9fb^T8mXm87L%Zw|K8J3#8Dtui~1)=p3?pM1W6g&9xnT76Sp zS?aIlfZ0cV$69~uEejP%97R00zP>)x>c{Nt-@$+%IVv`WTn%j*I;o%#Wyi1JP{@QkzcGdIw&Ci4=hDkwyIW3&vT%xydeK*AUFFE`)hy=H z-U*;na0Z`Lh+=C64hT4CCgS3GDYN$EzZ+#90nS9aD@)|W#K5ERIU|smdW;)D=Nsl< zUOFzdamVuU@g1YWqM(%2m<*{%NHq88Xlu)WG@(Veu3p@x$~&|DE??4nl4c+0hLx$^RKQDfFQvn zQ?*yCp(G5gc(7)SGVke1OJcUyDL0)s#~G)X;mJ}%5DswB!cP(u3GSv;=&<$_zx_Q= zMVJAGqeKWaj24tOzIQ}RU1rl}^uNhw6LUDKtLeH8*$@|EGC$Yl0S)rGiHSV+f%q``kA0q99 zFU@){3Mz9ZsQH_g!qeEy1%78ZM`qO&)z?O?={H4`AALD-fAQIZtK+xLmg$>j2d*NK zOf~wnF;;BLRGEotc9-V&?M!Z4KHk$};tMRK)iiWO`@W{G<&@|uleHl|^K3RdtYQpU#MR8&;TBHbcOKaB$O=ma=H zHjRTX5Ty+b(Q)IXWMtU}a2y~zjL%)K7~guJL8XV3os|_dkSng_{&)`eUfWbiL}ws0 zQofFDIsjKyQ**qUuZGDG4HHuuq)07^#9^kZDEt=K<*d}BDQSSkqUIduSW#Yn&>M_! zspdUMPC>!oVT>2}2?>ix&0Ss5_P+nqo~gd z#YqW<40R9JtGgEXhXo{TkdeVO#WjCzDy%>50gOt6CI^VtXQ$N1w{<`vf+z9!^mJN8 zrgK7n7%kWIn;Smrpm?`-{ zp&8+GQ6PLL-DA07UVdOwqIE5_jQysKDLo&JN8~wJ#5#QDl3p zWyJ^)qc;buXn&pQnf9y-J%Xhd0G(1gRCH@H?`V}95`elhO7m5{cu0mb@UP(q8o`nx z?teoe*)w|Zxo^_)UUwBTb%q(~vB^Q#*BBvr{G3JLZSlut)u}A1uD8PT%~0~A`%e^B z;oLgDKSb-pQJXo_f<9{{8H1h~quI<(#Vde3vOrp=VWlMl zcdc{hAz`2M!YqTTQ-b!{MUt~%b-gL{1b!r@{R2(r*Z7Uit#CD=M7s9uJx&8*lcoK% zCzrN;@`(bJRJ(moAjbN~5UucEN9e`5e= zbtI9RmY-j4$35TQWF1kNi3%3T1%hL#4o@kiiiSs=Pn={3@Z4y8I2YosvQz2B?;$)%vfglwjmZ-$S?`7rY zL$!VZXj0f`k;Nr&X0i=N741YZz;8Xx-A$b2_UJ@~E(MQID2vc_on*pY>G5J#zHjd>1;6?8MaF4Qb?PVL9Cy;6bMu;KcQl{d z%_jg4y8E8cCFIS~dMvcFXA0yML=Q~Ym5;ctx)rO>WwqI03pbLxi!?rN_m{d=u3@IO z0&iH#SXUf=MMH1gtYq$cv0og@Q-w3geaHfkCsUW(kOuTi#m zZWuk^DQPD7W6|5fF%>8^E`ioG<$D6HhO9{P3Ro@HvUFny5DE#p`Z~MLVM)}n3hB+$ z24_%viB4k$^hEZ4kk)%%dT!7-lo6dimy8@i(Hz5l5O!52MbtoXWU?>THPur^z4SK; zo}&fFZUV9>sji_M#4+BF?fYci>&T5L1qFx0w3|_nw+(`VoL>0X`^;VwWvV3-VK7nn z^78V45w!;@NMfv(1=DRP$KZVP8Fg8q3p| zwER)xtAi+VMXXk|*DL%LrS;Rp>9}|b4x4%3P6Bj3%DBFg9ZMBVCD3wtv%GjO!nbxq zD`2gSET&%rqsl@AIDYXxhq%yOh{5m&%wLSG@YVs-&wR&_13)6ZR+~qT)`z{3YrA!C zfcG8-ZxlPDOBm7my#qHWi_3l-#j*Om2E`w65P(7AB>R#?>CJGfdsUyKDZqh&rUOQ9$h81ok8_^&O`e- zEFqA!IQQoldR+~JP`2H5AJY;mK+e_ebE$pAgjS@&6FScgb{IP{@Ea`Q&Rpk|#VAF7 zFBc%dOOxJIlG<_Vb0>2$WbF5_1s)Gsn_{GG_Hpm|W64sg8zIn(@fz${I21ZPzrJ4DjjI|A?q`m$!=fB*G<+zK zTkmXqN!Zr%%kuJM-f7=<1dJ5(Z28rTb$-k$-Ri)7cGOQguho!xA=lzE90a8|?dbXi(NMeO}u8 z<^Rm*n9D^&Wv1G4%87mr}I}Hz}wx~nK<8Etamx$vPjLk)s8=M z&PCx9Jct~nJh$v=Em6#263~sChkh@rU-19h1B3+Dudj~6?a`Vjhbs(-7X=;J5Hb^o%35$1`AR0jtkvidw}9@>l`t! zKQF}trMQ;BWpCzWRTwt@D`EV<8EJQB!6&E(fI3{2O z2f*+#WUyuX-kn;5zPmEwG9wz(vKHeW+x0k;I9R*6>Ua%g#TR}B;P(PP3CMe0%EeB* zbw2q7!bEegd4E6Eb53=ia(#AZwOQ^AB=)t3gK|^|xUN?#H)I~*Z5rnoJYJ}Y937c}-qQ$1mBGVDokG5<~laSwIvr!}A42UKbKQ z-_2HbSZu*CRuedL4kk|-|7WiVP8SKw3#7DuC;}|KKAChm+>}>o*MX;F3VtN};AlMA zX-vA@)q>M$v#y&Uyw^JOXtjE^-pVBeJ>d(d1s54BXoMbb zsDD%qVxRWl?W6vDm(hChvgCNQ{dP!le0^%&Wm@274u{*b;B3)OrK42a2ZX7F>B5y^ zoUd-H|9$kE?;0smq$lw*MM*`8BHO{-c|z|VWN;EYpJ$3x>5v&(icOnIA3n+bNh5Op z!8Gp@Wc#~HCNTEp1B=~+!Q`#{JhM631_f0ec#nHM5`C)5)O(=fAeu0qy3Ao|(@+qE zaeISwv2|BS5(3?E9Q#&WohKes{Lc}H;tB~(9u7y}gL!^=kv@{<`#{L0$9aS}2CAXIS8jmDh|?YPDh+eN_qH}cEcG)T z98^@<%GL{)bNq}{gBCEh?#rJR!=_z)j|V3F&s852t$!VbftGDhN8gT3Roo^WLid5Z-&0SEd^T=z7JJ9FY7!cD|60?L z-zI#}c^`};s||aSLotf!Y2P*L!{-X!ZcZM&1H6!vt(~wO)Z(Kbid@YuDW;?w^l)@A z?B*ZbDl?AZgnc)l9mCj7tLeC8e7r9bUeTK5WOSTmmu;ld*qwr1hZx4~o=gv+{EI@k zA3p72xTKi%QV@n?5)cJK1ciD)S<;sMaG;1jXI1~g1bacIenEn^jp=jG+bbdxc6Po| zt^bz`0P8Z1EM^EfIH!fHJN(A3amvp~yytA`y$mw$V_L8~m*(bECn1OiV?2xDPMTUy ziK)Hf{m0%T(?L5fPmn-yaBTTtexJh^Srkz_Ni&mAsuh)Mur>52j;5y8d4x|J>i)bg zrfgo;ovkw+lIE|6g|8nX7#Hp0>K_e2?f1R)Aw5foM}_Cz;;@xet_>1O8%ajCjzyKJ zh}m%g{TD%THgja@ikS2KD=nF;d$A0%yqI7qoH`@Y{<)A%oQ6h59J!WtwifJq>^*)grdYE8o4u!}>@?NJF>?;f_5|&8g0}eT z;k7o7f7J`G$1Qf>VOp9d*I*xtYfHzlOw!pi8I{c%*g`?8TMEA-EB(*lKVR>VFo74J zy&qboDZ_-r?x<46)gVX_ic1?c@Xq&8aOq3slkErhwe#ich5|6hP8yO z#ZoO-5+a{1wFTr5$==DzN_-BGfLj@AlH@ZQM+ls9m8PUREC0D{#||qHZ;0!4Q<&m;By=>7-vu*-b?gzfxVgGMmVXX7P@p& zhTs4VJjWnX-{v^7^6==}E;KupEfv)FN26CEzj^CIBdQTr=2SN1L@s_qT6H{>M6*+} z13Xr0sug+R=|9j3Q?q4J=JiJp? zkFLGBg5Bw*qV!P*zqN4})y;ij65obI9X;XGZi3fI^k;8*uEqq1XYE7x@t!o<(_Ct( z&*R;22}LrWi_Vo)vv%kI#26s`xCy-cNjPMl@ZwKu`e80|eXT)G!P&{{XDi1=A60t! zu4mLKc~>xWk1WeMi-zmH*bs5gh>3s7XS<8JI_Gs*A(>3;6yVYu&*?Jd`vSg?7E;&RXn0^es6lSi zz~ej~bE@h)WUzrybn}iw+mWMgug*I;`3ngit0QnshMjp;! zqa>z{q6dr)y`9-y#ru}3dg!UE7iq29Be-tr7y7i!6h6+q^DB>|gGX{T(&v>gJL%<5 z)Q4>R8$%MIsA7^Jz%3$()@|ULd)}~GO(vDl! zHrS6F6IfUy!eI><@Yh4L+xR^B71NVdl7_&sWwa5wz8A3-&C;w0bR>UBa}u=IP0g8K zwz1x7&1Ny?k|pF9byS~GnH;8h-C?SP1L2CiS%ux>fcrW~dr?}OU}UvnXM#;?aK}g&72X|TM1ZV{nELzpp z+F7s-E)Xr3c?3X5M0HWsr8%5RMYW}5Wj}xr&UzEN_&?|D?p7#iQQP??_wO;Lf4%|+Z9};&Q3kxQhm#-{CKiInIF`zY_Or&a~=7V*lyp_Kzmrm;M8;Au}V{MV4L@`b|W#)%l1vNhs0G%P+J)n`6T zF+7__mh8MkG#SgnY%(Sh^4~v%wJwTJ;~J8cM6tW@J^W^L0&<* z9V(@_L>kZa&mTQa5+wKDoQHkqDvd6Pvvwsb8DR-;jnnbpa;;~H#9Q8On3ETCK%nH_ zKOuoPeb(2P#tgIhDfTgWtIr^yBH)m>9hTV;Zt51 zcWuWr4aoX6x2xedm@19;y?Q=26u0IXL~%^i7{u8U&gM|K?UrJ~WHzlR7uOzkxK(y=LqlOA4XJl)4WIX`ivsV7 zl1he{yQ&xcdA??o3l3suO}Y0Q#z;#F{L3C49M|IDcYs_1k?x>epOuHx?~FOr$<;?a z%dQmH9OjQTAJEl1k31eKD6VARzU!3N`{uL>xszA-6PK%2leS*TNvmK?EEhJf=AhkG zzF`_S_t-z*sV6WQW)@r2{OFc=k~t-?Cn!lln)e%Ek*MlYKw=HE4>>Wr?G$&-nZ|mt z%foa#(JbYB`SGe9+so$Zg|oDbvWQe$@-2F}g04GXN;BK^y~CdAYqIPv{UkjNb;0xz zxnK26MEi~Gmiy{1e68`$J3EB@X!fl5;!mW5=LAwWTAcL`D62!7OHeK^wI5kshOF|) zs>)A{M1v^^T&D)$X;3c3;1ITk7{z z?QC8I-M2_R5O=P6h=YmE<=cEt*G8H->a#(&4$eBof7G$-t)vgp_ROCKeXM6#%HBQB znf%C^;X@IdrFr4TJt=|Lx+gLJnAc@NG4S*4ns5NpR8ffw@j4p_Mj9Rlt3wQGI=Ix~ z`TAN%zWN-p&20KJ4!1Kc?)$DF!8dwC#j#buvXo)ACbb>I?#QU>RQ=o(ui05}5Hm0w z2ZY4}>Fhq#kz}@~{je5g6&1U6J8sKY=}s2`e0p%uYxq!_^l`J|-aO-Z3puBl>Nqs%%X^RiHuS4+1K1&ho;rRyzFx+XB;@3f+sSQx0c6=NJC9M+`&JNbf*| zTp=ZHb#NXdg9H<}+6mtVX`dU`rj9J=3MoM?B!^yFy_Q!dsqjO07>`17%Ydd*d7?G$ z89Ndky;ICHMhF6Wr-1|eUYgrVUmKs3VKh{1QSoR@`)24Et}F_ zRkUO!RvUzwSwhqgo081B^YP6A2&ISZb5NN3OZY%>z0@0#a)jb+0QaDc9Dkr|;a|0< ziS1c&y~xB5635$GA9X9QP!V_i)_9?PE_UM;fjQY4anfu_>F9m<%>_sn;Qx6~G!RXU zAwr+oi|)B4s49QfW1EX>sQS7%w(ft(xXzlph8U<#$E+7Y*rSDUKLl-K7yn~Pq+}0C zF5~oMwI_UH`uN+?%G8dazHy`~!P9%vFl!eIEKYq}u+%b99hz48x(DyqIptN@FgILW z+4E{4V2-jaYOg^AS0LNKVB5d&ud4C1wjt5li(p{+jALzuNH1zM^NC(av?e39=4bi!;v)aG^ z=f802fBC07`x{Hg$%22UF#h&Y0;KB}5T43wGxM5eZa992XkdwfG5}vN>*AJ^`-?Bw zatfEY)pKS|(G{bzW0{?s3s>6N<@-B;xBehZM8^09rAfru`@HJV=DgLiw~>2%6iW{B zNjIytuUFL_ySCMvb8&y_aLur_BP*~2AhGt(`w4557jyQ*P(;ItcOcOr}qhiqea-<-JQIip9c}M_j9tAmd;C zZb4(U_`L98QdoZR66yOVM{Gv@KOi9>6f7)gQbJqyos)o&a1k&@f2-TiTpA6oy3G}R zJ=+xCMh&8V_>I6l6;_68k4hggAy3iiH-2#87{zA~AG3dZXPnNLPf9VI`E#~Gp3vU~ zVV@_(^h!i+$2~sZo|lg&0}2wZ(NaQGnA8c_eeto~T-?m8ay{Z^ zb#~a>^O@}SEx~K;!HUvFeq;IPYEwFu-=M}FmLIV8@f{XNsJUG71UbKD?0Nb^2>TZ1 zJ^OUZ#kn*d4)Yg<;KutaD)0NYr^=Yz_pZKyhzL%l3=dTpECzatYRYCOKkKcqv>E{2>=K2R>_>o`GH>URb1bG+%JC>!$9ydF%@UOwD>Ws7YmJ!y1% z4+;OSU^cs=-9KqRcOLf5v*i-`-mt8MM2=#ElbZh)$= zftS0eNFXjKDJiMeWL($W#-?FQH7>%BiHV8TZc~J97p`D;_p@fr=Wm%j|G_J0(z%#$ zmHy%mb5c|RS`K(;yLhQNe&O@t5)~J3LQBZj6987F+q$hxL(*_bU{eE|&4=vv#xk## z9oiMKHGS(kY)>4$px^MmSmDF~)qFdrGAFZ<_ zx)V_8QO}pq%MLU|XN{jr@h#>n$Uy?*e2+9ZTxjeXCv6`g%f?@y9u~4Eqm0C0n<6my z$=YaEWG{YT668V?HpV<$$VQN1&7JCA`HF8fZ_kVW)t~;ts?_x^dg zQ~0kaL@&ifNRjc>O2a6!7$(*C`rPQ`%GcQFl$3!AYX=!wiLat8CpljRDmO*(6VU_dbn-aPBbb?DMLl~+Ng6FrmL@;Jy+JZ zJkrwCq-0|9`zn_yG%@*)1Lt~KUgbLiYA%T;Rn=L`r!q#}>udPU_=eMHd%9e|4Uk#jhaV=g;R2JniL|xV|!*NWOK)5@6v0& zMI8oj+R9s{d^F&i9F1J1; zSDiV8p+7h%aB9niU*E*m?`c0&;-RaHyz3Hjk77vv;&Z(s$aXb>GPo+6(J)cLZ6#XX z44CE5ES@|IYbMoogKsI`d~bTJZwl@dHTIO>!e_P3(Nl4zXlN_()4gA(CsI>VZ>fb(xhf6J1 z8^bpDjPhJ4i-?FQsHmV3SCL7GS_5l=jg5^Jm6chn*4mz{L2rd}Fnv_6f;M2p(n?FI z7eNa*JzM`XDe+NRV*uD`Psz;OwUyw-xqAK^tK8yw;R^96Oqw9zwV8g=Rsjt-r(yU#&KA@WRDM2?4(*x zFFGJsKV8>DRqAiFMu-sxSNB1;lR!($)Nu|*a~#*l*TH??H{Z~IQa5K*_EX~ISF)ocn2Hn_{51%M``+{-M z?TZ3FB6PJrTpx??aX$60cp>*`>|`>#^IYEKPFoe}7~0HrrW`XZG$pdIDu?oX{3thg zUjIm_Hi^{ZHBUOqwJy-Ei*M-w=2aX|pGuNw8a`J^O6jA8Rr2Z{g5PUVJ zZRb9kE~P;)d*E6FQL0TsM6XrNY-jQ#cw#JKI|@P~Sp3HO(nX70`yx(s-xfT4c^xfZ zYgCWw0x&7L9Bmuen|U6~vK1|5Sf6*>Ux{8!UQT_oOuB7+sJV1y+Mi}$aKkC@zCy@|3 zvmXagXJT6Gp&h+np)Lbje$g97ZKYF&58Hafkq%{1p`8Z)b$MUYq<*Zw5lYJNf($V; zy+9gEpStFbvN%_)a(vv@GKC4b>!8_m)S|(s;T0sbehy62l=BM`^7lW0b)iQN4iG>% z7GDiNhQ4{1-z{s&TC$;#9j}k zy&-8{r(8dW$ygg;C**E#jJ??<%!{)W!0BirZY`8y8;cwp${k5`tO}mHQKQ~;oAay> z`-yXS++&#FdDuvW)=j_$QzJT-q{OD=`LytvOVJ>^Og0EJp+{_SuJQ29d#m9G4`-x- z{PHu=7McKb^v-2QdgSo!_(zEW8vBhd(TC}3%+`03z#-vV9pMC3Tl-^Qw;t;!y(lO? z=-aV0hOh2!JMBk2NmD4wfzSx_T)N7$vV5Ns#QV={tebwL!5FK_Vuv^Y!QMh?5YuORR}_D>uUs5-2kY?IqCKr%EMKzs z<55P~MUAGEDP1H`p2MQ>A&t>D4GlkW^ah25-+(vBFhfDW?f;z^IiE2n@^F;Y4T!_- z{0h(Yu+=4$dC?mT&la5OR6~s!pgPA!oRIA~n)Z1l3<^#m-%Y1u<35Q{kr+4G9jCXy z_g%O1&senc=ae`m62rwg_K*o&qZm2aklaJw{HJ73=x_G1hqN7uv`X9=d}`F<@0(T7bqDz3y>tX@XF_ zU+~H9x$7R*d3cC`z4L^}%oJ+ndRzUVZjDD8-%kFs()}sWLW*#c)@riMq45quJ`5~+8`ctY&o5ixp(BUrW1$kaI@%|?#&M17o_|1GH z7_pFia?w1W1@Y7H{Ch+=0(t&3$c+W!$AAS&@YB%R0gO$;^f;K{LM5QT2=AH7g;bTM`u=sYrHknq(9vHw6-0y7wiu%J$|9a7G{9W!`^ z!J#3($5AK6+U&lrdM-%(DC?rxi$Z94)+K!nVR;k$A<7BQpEWp2L9vSi5*+>F`|=lF zB{(;mE%D&aok_?D&ZD8v+79m##p+|~t&vg?&ix|Y)qV+Q3j(3z{kK8HnW@bB%KW*_~MNE?0CSPVz%bI zOKZhIX-F#dhwOk1=Dg8@Z+z#h#l^i>sTH4SI>Lg`+wM2uL5jP~#LJ3(O;KcP#WSBs zH%?BBdS`|R>~oZ@bOvj_4fS%ASp;mLf`}6Jw41ybX6rJ(QY~}?yX4!RR4(R_7kH=k zmBtLx&fZ7H#N=PqvQ~*b`Q?&PQ^)Hkf+gAM=I0spo9#T7_1*(ryYNGfg~kJAHkc)9 zbyn6zYs)tr5NHOj(P%@f{As^q1p+prIVCJ0FGi1wKrvBVC=|0ZUvXH83rRdAxvNfT zpZsbg@gR!f5pu*y0XDJ%yZ9AS?grTUTI8mgzEz0XBiSnJ1&c2I%;W?blpQF0EN^pX z1pL)=>{$ncu=eL|=sa^|9*eIGnnH9@@K?Kp-ZVw1vyt0xyXHgSuu0?@xRaBe-EO+_ zAtiYq?L*=03-vGC*k6f`2l;Imx{I~?5ZL6LWa0^vOm+eQsxf8D0w8 zi(`zH)tB0D`I+A5DQlDYN7w$0;qn~VN6`UpSFQb7pSMKfbLZ)dY*3&ux9L7MyF(_a zs)v&0->$VOxMoC-V>^8`)2W#UZqau*FeRPAO|{kjtJ;rQt_;CNCiZRV9zkF*52v42 z1QW!f(ScskV}BvTJ4C{512_G#6|@e-90f=zHA!Hm|5Lg<{t7Std3Vd>h$;~;UBFI} z$?^|PiAt}tXbDeP0xY@u-DBn-iaT$E>D5(K^(?gGgUR!^sM#0qS-=rduwwi6BENoE zVndFU@jIgXU}%~=0hLYM=7d>LT|Y*=`3EAZYd(iNqh!{+S}Q5f%r@r>KVN@gmVpK; zGOUx%7fAv<-oX!-c`H3hT>@Z7tp$>#>j+@OVwjfp0O4Yn33DG;aTwjDsEHGpPeX8t z_5aVeoae`8XUqTil4BqJ3vc27U*j#fr4`zUfml0tFiX?X4o@m4x2Ikb$CePHrlTo) zBilvF^$gEMZ11>s4L_#1gsL6auh;?uNaoZfveFtECo?PjBGe8n6t3k%sya*K$#i=Z%HYKe{ImWh@S7v^yZEfs=%UVQIspj0VXozi#+2u)qMmuP?f8vo|UiHw!F3 zJjQpwHGDpHN60>M$1&OQ(2^(NN*}-Og))$}5Ik8}p{a|~Kh^a{ z(Ex_xzQuXs4!b63@-t&dzQkhV6J1vsVMq^zeV9=o@vOS)Sy?>E)+SYG_MLQm)(8B| zTbdMlU6O@lo{PJL?583ax46A%@tV#z!Et+fK5-{$eBzdr8?%1%wYU_M+=uE5L4Ob* z(3|RY5+nNuvULUbArjKr`wUDFUInDdeTaa@1>`%MpsZHZG%n$wk)+cC@y<>oNR^>r zyoubrd`r)gf`Uef@VBR>N@Vm88{^^fd}N@98W%5^lr*uDPp-r&=eu0dQC5u9lIBO+ zi05oVAL<&Q6*ZC zGK8j!A9Y{|(>GjO{c`Z-t`69F_BaXr=pVI}Z6f>84IvSt5B>K{rsOmTr znbdR@lM^g^~w#&yp-!y-7$la-Wl@k zE^o>0DC5qzEVZxO{9@%DeiTtiGGaYlXU!0XAA@b;s*)}Gm zo-r0s@FMwbz$AICd$A@Zyt6UMA0|U6e6y2HnYTNp?ay(0yQpvLX1Ypp0~-2-yF~7u z4j(sW-z0zuyv}_{)+hJw-HB~FEmF3f4P{xU) zytucv*sT|ZE_cVi0#T??b90RV)-lK1Yt!d{Tw0NwRG-uD3-5NI9gs7!5gng8ybT;B z@wjBRwFK`FT~!XE#j}aFBRNApy&PdrFJo8xZnvrn$@5;LOUX9`fpI4ojU5=aMK2S$ zk~@SV4T*La`;vX1+Mnt@{H_)q`4IyT_z z_iYa12AE$RGlq011OD;WC!a0>R-O+5BpewQNFK&HC^Il}8Bd4puVL`u_1}@vbvY*? zE65;)-WbZGjosFK7BW>13Yed5t-(-Gk^!ZTRz!*P5L&J1&%1n+XS*~(62nZS&t@`9 z;}D_<#7G^?w&)h#gx*^vT~!`w@)vIY6q@=mgvM<6_Re$9!<)SN>c?u7uNIJOt_Kb; z=uHq(Qc`AsQb&$gqu>L9ykQks@>}@;e@i_!N+Xl^zg|tA3u==t3VWEJS@_A>5=P7d zwv(s!4cn{>tk(5k4TD%?C61b_J3@$q=N*G*8@o+Cw$6JwED9Ct-6w8?QcSIeujbQGf|c4by9@G>~7oLC6blH4|?LiO)^pQY1RcHg|pIfMiFGShdMMvOmK_|8qwE$>xyvu z$(f?5v`mycolDZ6+A&o_?Sh1SM{_~7|?_nun znErXr-g1zGwq5ZcdisvHiZAuv88g|ZtkI-EfdO`91;fX+1plWxHc%0wZS^OtDS=Zf zZPKocZBQH6&;+OJt?3j@qi{#zB;-9al2YIhBhXPtbCcD68~+v;ke$OMFt=IPdj0F|{@V9rTkjt>;#>?&o@^K&MsTQMsh zxc+Q4nM=&-Y?{W%Gm2-`;up*}21CFUf70$oV*I}60zR0I%zkfjtK6j(c6K8cS4;^*oj05?{yk8B4=vMAP_U6F znR5$!#Wt$*i9Afkc+(2aG2kvQ7_dbXWxNkB+v!l=Ni$#CEXmRSVYYB@~REl9>^vw>5W!m5;E0h7Wd}-_?Ro-f!_6f+L;ohuc4g=U-yQ- zb+0x@9@3E(Do*0us62XIe2!7XYB%XcH@@lzgvPn;kmDUvuPkl+(m0S) zTL%V>{s|~GcFF$%WI2_rOmE^)WvRmXw2nfAS z0>kSHb%#5^2MeQ@osuOVZHn&9P?_tdv0Odk1GK9lm}!g z6lhXHf|+{piL*z{ZpdJE$y$D~O93BjE}?)hHrt$TCM(qLf!zhcj_w_vjlDM=5UMx~%-QJv z#3rALTtckgFBO}#pMy^d^nTTQx_0AMJO~qp%SSKOy$?tDZf6PR(EuZiRS9-)hbL)l z6>YSVS=6_5lH1|XKg!ZGJQ7nXH6-aE`)1w1`?UPN3v15%>&jTmP|w$N958UOv6_=C zh0kcXvi<6|dnu@5TOkI3U8Aexjgg3^CXPA-4$%;#%|i7~wJd#~MqC6u3)|2|kR4#x z7&kJEosh{?xw0}fMM}rEbXBPMz|F0tGE!1e@ihvU-F^AWV`}VIX0sF5^V>end}REj ztZe;v+JDh&$e+Ule=OD2%thIvzhcO}1-dVt%DA3$=k|_8fVoSAp<+ekTAKvBr`^cE zbYXhql}}s#F&cA;>+TeLI>yoB5j%hFBe*VWR&iaoZr^Gi>eWNvILzvYyNyK0#ci;B zlKG#DY4?&NYjf7MG_otM%}HvW^&!+haSL%$@XK)0_kGm8WXQG6mlPTL>vY(Dh(e=4 z4BeLMnZyfWmM6E2X3_RqI)WvAkqXR1Yaz`ASVIhha?ZG>8b(rw?51N%;}| zKR!OtI9mE-NvzXgb1w%*N)ecds}O3A4GL;$YW4Ir`Lw_I!xJ-6u36qV3Vz51k|Ylr^s?4jFABODyrWnzi3B4&ZYw&yleev_pQrZ1qvB zD=DxeRp)U^1z39v#M32uvrhdqI7wx9Yvi1wT3ddP$eea#J(Q5adac#_( zxClMlQ{=2KuAqyizaxP1bl<>^%j$?s5d~+1J058$G0D6o zMd$i}Ym1jlMMWR04apkP21`|FfD`0xSy`czb!4&Q;UEsQ$zqCM&9ESq^1i5opo$TT$`|c}k|D*OWX1P(sx&%r2Rv6jgoJ0E+dunq~TPj#BC=tw=nSFI-tyvUVuKv3t zO)J)mn7Xcht9DEIQ{2fb$c>A%jLddL zJQ6d3k0s$LIsw)``VHTT;1-NAGVnrJn{4g6pi=dj(TC_%Sl_a`8WGILRv)QT3(TFv zT{wMDbt7owt#NqV7j-0DR`0uhlVbvfRAas2n+E<{W5wfl=pnkg_g}|VBzHl)KqLA~ zY=h&qeG88eU-~vRtdwC)btUgvBNI)eiv|CZX~to&SO@wWJlz>%NT=R{sTi_4x|ITm zZ|JS6SG@gmnxG1DCun??d7p3a^b-vLvjjj3GP+rCkVqfusXCKLG*;lgCQNJiYsrWu8|4$Lg-_WEh z2#D{p;$!$Kmv+xs$BX4;{tmFb^=DuPSiga&67TGGhqoc?1(S1LEeyjJ4pwR&J2jiF za9i5EFbUHI$O?jhI7MY*3iP+n{HJ^6FBpoJWMVH~-YN~lWY+S(`#N{dH`=WO4V*ge zoVxCA|J_&85>HgN^kQgEX|k9>xKq6uxXaGU>MJ{B4$cEusr*Zn@K&^7g1T}bH6-+l zma=zK`dGTWT=^g7F0iPM>!3f>8Kyp`93IlmmmQD6jHI%J5coVXaigy!Mb;b5P|QOB zOL;MW#!t>exbc?!<1+s9hs=2-)u#fPcKCt;_BJ7}hpY3(yqD+4h$3KX`pxw~+5fFP z<)1DWpeDe0W8EErf`Vc?Q>Jf#c(c(CNm2F@z&bt8V{{ln|Nf=&= z_hGw{;pkOWRcqZYiwx@npb@A1Aup+DX=OmM`zlHQ#0$#&0Srfpo)6Y!JS(Y)_45dp z|0JZY!fNar30Lzs{xn`SbqmPhA}nkiT*iv6zf0 zI5~a5=lAZ?_id0gHby6>pis26{chkGm&6TpKHzkhzhv{c#RDE;k!VcUc3+k4&E1xq z9A5+ip6!}+&;6V{8wCZVU>I7FfLHx)0F@D@qM|xFM(N2C_z6V&|FVWiW!Pr0nxXXe z_g_AKkr$8NPG<W`@F_R}&4Up-6Ee8Sg-D!qi;FXYTnCvrGU7VRrLHTPiv_ zN8pCh!Vs~>DCtA3xe0-48a4h(MuIGh_#R9ZF2eS7Po$$%RK%w2JtQ?{Wr1;egYuSH z`ngIF=9`*$6w|RNQmP=~Hh-uGG3c_x(_>GDr~8**S?3;w55d055lqnN!(?oXfO_Asp5(H=Zs5K%Tlnckw~wd{1iL$)FM3Ohb_r^* zM;~oGR>R@ri4c|^S6FR(zAAdXXYpZ}`*E;w0O7#@JWH`K;}Za*I65?xv*K}Kx@5w= ze;LC=7Af`WdVsFGCLUZIhT1XXI=B&*#!#58r0w zH}u^Rv44))J#fr!Sohb~KDP*lsqlOYRLn0a8Kg`NkE#N?4nHi{A%&=P^y0$Xs*fxz zEot$2H7Qkm>0uhc1`jtyHe%i(*dyp2<^WF0HWa8p(ZcU`e3m) z=ylo(`uPQz4sA=~nWstUxnGz`ud>@)l7wV_EkuYb+T`$FjtWdEC~CV9)vR&OjP=;_ z=iX0$y{QF}MLSzOHk>L6?%h`7C-D6`zWvJ$;|M$`{0&#W_&w3u+1YiK{qc|CE#Uvo z>**2scg=unT7;AQo=64T%K}M^guw<=rLbm3$;oeXFH5WTb<>pk1*xC?$B&#gS@a5u zlS~W8(?()_j5jz(_$8+m?8ZEnAiWo^Cd;BP0^Z8PWW3{0(VKA9^-sj}dovF=| zZS6v=02n-N+Arxn@G)>RZuy$|e+b%pg! z@(XuZTWg+pH5)5Twq7T*S|1?@=WcpX^^mNd#s9rrnb1Mrw--FmA+|nI6okp5g}G;LTbg7kOL9kUG^^=d2vpZ7<#S3^(RS$!cU;{1(+xVv^&v)?nwDt=FKRJs>9QP-P zsl@PFXTbtiHgfU;GKIW(?20Pg7Oj@*Q{}xDf!(lO%Sabp zUGnNmn|N)E`s@^9$}-g=)nwe}{+)@=DzRoAx4fgc?U%j@*YpOp#02Kq6W2pwVY3O} z7a=(Z3-0HWmDw)k_Ze#udOX!%9?o2X7#wY9Ufp@bDYs%?o{KhF5D;SuD_hCh0umCe z#H?JS2hO?y5$VI2OFKiGi;-d8L7n;wy(fLhbL3p^6?-=g-t1(!w+sR9gR>451W3=95Lf{Z3a9lki|GUWN0@KwZ; z0)LmWm;d$jGEc8UHse3v+kV!e|23_$`g2;<>^P`42p#-JzJO#tfwpl|T!drI(vbFl zQ2mNcN!d7^1p+zWvAO+2K6yYz#HW72%*@eu6hqkC^B{#mn^E!v>RLmr`f{X9A4M8zz;Y;|1q5%0No5X;`20}&FK?) z?4UmQw(nUKEYl*;lgv7#b1-hi!XEVX&z9rg73eEqeiir`uvWGXF;kOgXTF`rfJMwY zVUd7atw#)oZ221+F(-XbxNHD0$pf}qqAXQtHz{Rl^0`m3)4-}`Sg(7MiAM$|0;XS* z+${yUqfo}u%}qn5Y<4aUz&{2(40{_t8Q!KFu7(o~5@dYSg%v!cG*8+&UFg@%hgae+ z4dNzs=uKs&_j=h(lh3FM<8uL}ZZO6C>1$7xDKU?X>{aov@q~#LBwGu|&OYa# zGbMOk$URUYN{e+CDbw~@#pVz~w0wVy9lHwR?GTpPlehnBTO;6n(h4x*G)$d_A`dK_ z6jhZkqSlv*kX^UKn7`&+o^ZuVC_gTJ99sEin zpF#@7#qMJS4jFA0chEp-Z}9`W+F4jlt@%Xt+ zx?OIh8R|RsGzGXi}Fp(4zne%BF_6j+(?E_ zor>Gx1~fp2ii{$nr)SHZG&7@UErk+tzR;#9H@8?C?L@loUO+t%b6J!90)70WF8zHZ zp+%r1$p{P}*%h?1IwrY&3&+~-eY2OBHcm!gv)oWgH&TA~h0d<}osG*Mun*4P4Ujh! z8Hv0O)AjaV*K`tjdD4?<+r+WH{IaJq`0O062*fvkc^xFoQJ>N66^Odsw| z=OcuqwW_4(8n8FuV+h&M$OsY#uw5lQmSh{t)aDck*KPK`v+|$bzA$JhF>rPTYwHT- z{0N{zwsv<<`=QVkx;f|pxys4d=&R6%v#J@L#q_IIl=AX&0}T+66CN#!-^vhB^vDel zl7ZkhefAM=2^i&`C;#w1J^3Ll%|(L+FE2*~f-}TlT{D*cVR3a3JP-59mP8vga@7e< z7_JP${8f>;Ka|zK6N}zSv3uU}X{#8q$U4-li^Dw1&H&vGGVr}u(O~qU-ynZ$p;doG z=T`b>yzsB$3@97?tiybl&PYu0kQfD2;%sNy+S(2!*_P+otrlgB`lF4zMH(gCLvalg zVOLvRPL0#G%l=z^?|O9%=A4?2&glQ4>#f70?4rI=rKP1iRC4I<2Bo_hy1P51rB%9f z$e|l#=#cJiL}KWcJmd2`@AaMcJJR43S z!pWL4Ihike(4#fU=p68FXGr;p|A5i#Y5k_7p=3XdeJuSFNKI0C+{A{vQy?iB?$!G& z=^o+H;?@&~M_`ZE9oq7Lj&8CQRSa<>UFRVQ$(a{8YOI~p%(?2k{lPyFM=tp_ZgQx3 z-BA2AsAf6M@=x^b;`^d(ihy4x-~8ka=~-AngwOZyc6U99yEMF4mPVx1IA5^-glx9L zg?NqgKR*uDDEhc(?I^MU*189dBPk)d@0RYc3g7<-l2cBZl4tFZBmLv`G4cQ2ym^BE z!TRPiMpUDa!h7@Og;o0$?gRcnQefz0Jl)P7ohf!u7$hzP`Ao^y&Q6{DxB4>-;WrtP zS=W`4+3?3=yvM;bsKNgaYP*OJ&S>r+1br}DlF4tZ%V+fTp0mvkpRX$4Z%vGQ#6B70bR9(P@I{d~FS?wjFpnH|+*&?V zZa|i`_YBuu7ViD4lvb>AJ36g$E7})yX{f&5^Es-un|uc+B=m87U%~F35UL{- zCwA}nnF_h0X}g}+Cu@6x8ogw!2fe^Y259lD`#flZ+(YXwwmw3NRwHq6ams!aNH7?# z&f$+7{4iMx&s$fq_r?KO2+wh<4br-8z=gtT=6TYqNr!#LhP9&;LqT~>O@$EFc8*( z_wiU>IFV*|Vy9O{9e;-sTr0DAU?d{j%IR8KSDpbm>#vS){4MMEzsLF+n@v_MiG@~N zmi_P0|JOYJ`=LXPZ49bO!v8-L{J-vE`v`l(Z$4Ru|KB&fqmm<(Zz-zzA1b}zh-q=W zh21`Y{MyHGa4_Jz7V2Np$s~TBs3(lGwEDIDKhzum1doOxWaNDRw9o?o7mTQS?W-qR zFf>BUSnQQUR_aF#2L}xmUCGAp7RPO^x6`Ws3<4jnz`a&Ne)yla4q(52+|1>&`94Sh zY#*>0sy4jVu>@0$Dk-TwL66%dKpq~2)1&BGVPOb}IDCdxRp;`gaCa2r6XON3cYK;b zP@+$Wr>XIBAhQ%P9cQ-ivq4=wLBY92-jimvdGDNNkDxi|aT|n>f)ZaE;99uv?}G>| z2j561t401hVFfBU@tmM4<-8m@?SDv&8`~8C)wfB3tQi7Tunhv9_>BaT&TiYY0 z<=+Zpc}GQ3hbPCNTcxZUw1g4;Lmo$UwsssRY~an-5-)4 zUIC(EUC60(m`na-irJeN0k_nq7Nsb&J3n!67i>BmsdeJMZfQuz2Uv{FN4Y+iFUXNb zs5QZm+HSJPN`A*w5zJ+Bo+Neh@<94i##9w~U{D20KJ2sk+lCAsq{MIKkKLkUD4SYgPoQ<6UaVp$ld%$^ z&j4-0Aw+)Etd5Z{GlD?KpdI!Y?&YPi^JD3<-H%VH{qx2KJ1{KGkZxe+?+6EDsN^QAwi zIGy4T@5wI2_+hG<=~p}@;d5F|#=#B=>OGoY|84>m#_VLwPPY##shYeXC=!m#DHJh} z5U6>&zU!9?Q`NUhMP>SPvxOVFT|1hcA9PcfOgyJ!IQ(a`dx`kO`)igwE zF+;f;C@b$;M<35DS)P$$Gk8AJ@Un{NM-0BJ=)ff0!swg&GhE55CT9Q^xY|0nY=F+{ z?wJ-hnZ4`LY?W(rb@ANk3f@0+*5e8w*+}I<-AyBX!#<@kHTh}xINz<~fiRA_V<> z-IHx?n$~Ifm+*f2k3dQ3Kj-qdgokss6HxS82f2N0FQ3RAb$$&9$Rr~MViFtW_38hFmsvdw!u~;*`4pqrX>y@MBXNd^B+pe&^X!N(l4A?5Z zzTwab=CGhn%}h-e@ANhk+#2ITsKtVu|IE}S&gYrSEj?q?B2dt@$n~*9-c8jkeS+?d z7f13`QP2#cPps8wF_2;YGSaYknlp@y zxN@>LWYfOJ$W&n=XJ|PpPg@93Ns_KHeHG$sAZsi})z2nRFMY-%{AD6NgDw2Knb~X+ zrPG|1MNtjha4}WX*3b3jAL$4qbj)A4-=-4{*V>rc+@@d7u2g%=#>Eu2`kzucbDwPg zY+)SPb%_flWT~wymhNc%NE*u#<$xIbupCMB$oql*(_ARbm~<;B!BRXf3Q?15@QIiMH11gQLbMZL=~*`u2pkFs2A^q$08Gs)!Kp4PIh!j2|nAt7*JRLv+l?Mcn zmesBgOuSBF`7YxNPN1;K{YT`Ozxkw)`fZn48y60ydSc(e)dVj3T#%8ssaQK<(VDc{ zl-a61l+BII1u8@s2|6bQwwv+lb1dS~1;0+Tey?oZm_}3}PxrlHnj0Xi|J_^a-Vqf9IYMUPj(7rk-%i7VgfFC1)74oFR(7c!KQMx)#Q?e& z95ZtQd|4JFiBDwji)%!oICZ_&UbI=MGpEb5J;xh?S06eif?Y)Ud}MS(yOwEqrY*x~ zdTJTt@d+xF73&pS;VTe2u;g{bFg{K`dr~Amj01}bQ=>KV3};gZet7uDE~VQX8cP0g z-#4Z1@OvymHH~)N*H@B5)k^N_kp>uC02o`>(cG(y&XHrN$remOh5?v(EPw3TLvK=Q z=g<%q`>dY6eRR)Gaqmad@sDW(SonvAe`%~Ej^*Y z0YY;-pX2MOx}^S8G&^dYNb(`2qU+Ffl_O2B&q-F33zg5K>55+_+-~I0m((G4Q*CXc zP5ijdarFug+4`8UT7rkhkfn(d;y(UtT|MOsFPBhe?{mHxG3QD1DoKV8HAaK<@dKg>E*l@jg)C>;+iz(09U2rn=83xV&C=j#=+VYE8Dt>VCYyIRXQRl2(naqCT8`=Djb}A`n3q58b zRp}DCoNsS}e+tTHo5CR`kPx-pjj9i88M;@Uz_lVbLcrb2C??o7#WSaeCfty$AVG6Z z*R0ghO+=GqSdaN(ux_;TTPg51TZ=d{!Q5y`EGpk^#0|cCKj%^m6JU*4npdo)W%Xo$ zN{i!3?gv9yPESEorlsI2!&afK3>7|c_YICEZkdwBfj|d#yuKjq7%75-~f0oXi}+eiHXP@4rW{ z;ZpL`BEZzd8Da3XjqH`FID7cn%Q)Zj*j4z_3`4|Ab7x?y{bK4b?fBnGwB7#a#I;jb zF}O!q(B|e?X>vI_c9X zY3J}2O(MWJ>e*&O!4ZV@Di+ws_S|&n=v;yNn<&g~<>c>#@KN&C!yKzZaL%Vp{t0ah zW18vtxv}m9+(lOgz1G1^ijq2cERjLhROhZmUnAhSnlQ>)xfv3F?w1x~=L9zbFBg}r zk=B(P?T(WwUYrL)#fbtuOs&{7;p@udn{!l}SoZOePYwMG3pLZt-$Fj$mr1cv%e=xAKGv=`~r8$ePF#u(HP2q5L=~2ICLlvT!S>D`l%2gTE$6>S#5hE^r z??Ot^0fFtqbjlWVQs+F3*g02tTkgcS;JV%XYd6SIBWz^te-aGsjA!oah_4TCwItVB z9?n=8%n2qz;`($Vxrq^m75;iwf620eAn@nb9z!3sq=uphJeHE}Tq?|QY={>%8;eA_ zpKqu#{*SUl2|kyk`o>K5jh0X@X$)--)0U66dhRIx`)D+Fi?)AuJyAAmg$4n8J*R!Q z+*Vb{&p-#ade>gDHj|_v>lr-(bpx3thA8(-iFmWF`fgOrq=)x(7U-*~6dQHv<0(l~ zSulmktC zJ|~Tg%e|FPb}?yrOI^uxSYhX==^%4v)F%{d-Ta>Zm9tT8SOt2W{DI%>SQUp#n{_j( zhv^F?S!mZVvQ1CEN~rs_dj%h@ZLe~W-XFao_i()5prgPr z*8~jMj}60&IgX!1nwVNEFBv&28hCiz8rQ6S$YeJWX?u~x%KkBjA;P)Jc*chZ|5KX*R--&CtzFk7I zT`@ZLXwi9*@leNg5On>1qEq|n*vI%uPK!g+IhJs6k-BQ!qp`ZCJOXFw@ReMA_>!)B z7W^e9otB;m;D^>&Mm`>`JRf4c>b=gn<|5_D;BQpVICbU0@~atQ^=+74?1|l_1<;@5 zu_|-4E!MSRkkbvF-O~F?{RtU7_u$|0qiZQd>z9%?YVNh0WtnlyCQ@+Yu(U`OD6dWr zBoz^2!4A-ig~P0QocwDl#3zHQ)6S8-w}$@<#0C zZTH4`FMfOrvZVScoDuE0>h-v++&|X`7=uqB!Muyd*(YNgnS#p)OXQTxmG35VWq2z5 zlhr?JpXobU@%x{Dmt%cxK2`jG*@{(P8?MaJ=X#OL|_IdewJE+!_pZtN=e^u)D> zWNOK0JVk>(hN$IEtY$Uvh^s_Jq`K*8$&j3`k8f&q+{Wu$4+&0xdf5EvxF%HckNU#2 zgeG|Cv$5I_S|o7_lV>K2b_f4(q;?S=a`H2yTFDRWlC2z!8Ki&L3I@N*c zGpr9Y9lutBixAZFkcLB@{FlashfoR|LG1Rb6Tl+w+FPGjy*e54#}2$hcy*Ozt|#in zV})O@n+PcYRoe0J$qWm1uaC~kF;}pLtc~NXh$%y*2Py)z~W;;xguccf_4#dX!LR;7@ znWXcG(nh0$mjk_M_L}b6JH{6-=Xk(a#=CH-RG$F)I7gN-AzP>hc@m+Li`ONC-86lg z9p35*bsgZe(B#m|U(0j+g{@d8j@E8i&CS)KO)zCZrG>HmJI`o+wHZ7MJ@I|tx?#UD z8T4q*)pi_fF8JibToG`&tAqTqlET#Bg@u}WX|a3bp!=^88hoy33_o}d-Q6Ij#Fz=0 zYVdnIZSn5D<3B^zfD*x2b8692p4y>lkViVk$|9y}WM;(^IMC7;RvT^R(t;b*ys+jG z*-lCDesHm}G{US#VTWoU7|e7YE=D}%)jze}5A3L6oKBHG8IA=#)r55o#)?gCE50s; z)~Z#DSaGFV!lF4dQuwezUh539nzekz*P7FNhGdoAO5M}^U5qq(guIu}6y_~Ga)g)3 zv0;DCoCQDZp}qc({0RtO8Bi$uHnCwdGCsonJPi%SEukwyoLVelWyXVpNwd4$&(&9y zDFr=uUD-ch%zvT&E8$>aJoeX7$n5b>Ib2U|@7dl0o2uF~>B$NHKGQbqP|98YxiVnM%eafG@IGJTk73=5q&vyPhqxaZc1mDGw zYYwgSe3^i|S1J9w^V5lK&_(an(|Ac8Yqs!6BsF`Fd5;*^G{|I2juiHCiRKDIf%j9t= zK&H4uZ)|R!QCEJ7g;mpC=exAVX5z?xQ_a^fT2RV9{yqIYAu@hoKw8aRp;S`+yc1Gq z@9gUiupno=nn7ZE1rJAee#)y0#$Q{rLrJ1U+GW`cC#z8)lwFZmuQl#)XxO-&uFp*J<0cqQ_XoH8z7ylUfe z)%_9l7}~K03F1*UBp8z|2pt5_&Hm~qk4>oyl5dXxLLBPS$Q-;*Xt6247k0aqy;N zW`hglX+ndzeC?VAF=sgGW}?Fx9F-?n?eom6?2ZO^%zCYt9`T}c$%=2bkWHjL1j$8! zirK(;_UNpU?XZkCOo2WN{S~sHRec6KCxw^jb_jneXFWMSu|)F*8&H_{AwK@;XHxTx zWs%gylcLAIuco5l@qNpz$%eH(Y=NF0ycPf;6Ip4rfSnByqBzIcA#PE>Ju-_%BI}yM zqy3}8$mh;xorBHNPc>?uQY50IG4`!{Cd1kFT^7vb4wYB!FAtq%&4cF;QiPZZUkW}# zZh)u>Uy1?*o2T+SPGMCPhK}q0?_srI6%!Y`BZD2&7GuQ*dJRG`m`5ymw;Ljy<}7B% zefZGgndrtD@{GCpWyQ|BDM8GK8WYe_UgA@Y+5D=;{cP_@8C7S7;r-fcQG@P)WLyuS zmeX3N1SUiNxa0tnLryoPa(bY`CcY&tmF!=`(g24DSB_Ajm^vKy@wj?K(0Gx7%${x4 zWm1OaIxZUqGgZpfosOXh^vtMfT58}>XSiGz^qtf9RLGi9FQAXDj96bWG7SO{;*fnJ zO|eoT((mQE>HMY~n~+x&hO*osl-+d9(4^m?10#B@Nk4D{U7D%72h~g{s{LmE@=4Gw zU&#YePKVxLF#2u>5(m>kb>zA>?Cviq>GsE4I(7*9Y~6Clj2QGlaFPeu!QW9@N?P68 zx>O%D5~qKniJF>o!XglK@kLpn)$7zyPC=n)d|XMu=b}jYkPIyu;oR#+>ihJ_HJ4jF zEH3e@1tkGkuQqQcEh3Wk74LY5WK5fPY9RDa4p#NAgF+CVAb(a{`$K7s@n-nknQiu> z618^>+9ouiUdM!=fcS;wSV|W}86sk{sz{e|M{*S-=W< zWY4r^H38QQhiOs|D1jIwh3izMgv@Nda=*7>8Q4)bvUWecJHFI zcvwRGoD<;T;g3*-m2a`GZ+u<6F5Mxl@#!|bzvtACQByeyp>vl-!kAgW2XGR(?Zexw zwam=Cxwg=dke2b+F$z0>oE!pjXgh>z=x72M*Dfcu>BEwl6)`+!*SPbDDCniR+)gCg z!$+%*t5xk{JkZ3=0(@cRzFu!A>)~!`zwq+X*I%2k<;k_=h&7N#mt4Xx(Hx_;yAQ7Q{26DhVA&!3b)E650B@X zo4Bq!?iJDcUGUZIQ1D1tf;KT+r0nAhcAJ+KRK{z8MgR*%PPYYBtcS6iF-d&a zPq5S&yMpm-GD{lS4qA07xPMlvA9sWSTpMX8Z)=Jt{V|;WI6zUjb8Dp9VgzNd1^ew5 zb%V1f98G^@{jMaoM~$)_vGSy{QK?tjYFFKsOwK2bxu#ltspbrn9w6d8?w?fBvb>h5 zd|9n!W1%VZNUCS{w(o1K*nro#KNvlO_y#;mNjB;_xv@MCQ&;@?FmBL?hrd%43R;j9V0?3lYKk8AZpUZ4zTb5`W{p| zSq@<4B=aeGP_ZD>Zn-TTGly12zT=PhNZ82?u)3{Ox34TXt(?0#w95d#TYsCgW3H7|)*|d3 zU!iw!)gK|Ac$^gWNsmqN8|`I>lZkxU_JySdJ9m&J9JxhvgKa$SmYmQUZ(qL8*^O>P z4s!v{-2?J%5vcNGz#f^UAthN2!+GpA5;F4Sf@u3E;Su�(vAP?=<7B)Ew?02*S>guN#~en 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 <9X7&XtsLY^Sc*?jr{3G1q}}cqU79*Lb$8s?Rx0 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 Date: Sat, 15 Oct 2022 18:18:06 +0200 Subject: [PATCH 0866/1520] Make it a link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cc531100..3fcf3797 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Thanks to its flexible design, *you* choose whether you want *structlog* to take The output format is just as flexible and *structlog* comes with support for JSON, [*logfmt*](https://brandur.org/logfmt), as well as pretty console output out-of-the-box: -![image](https://github.com/hynek/structlog/blob/main/docs/_static/console_renderer.png?raw=true) +[![image](https://github.com/hynek/structlog/blob/main/docs/_static/console_renderer.png?raw=true)](https://github.com/hynek/structlog/blob/main/docs/_static/console_renderer.png?raw=true) *structlog* has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio*, context variables, or type hints as they emerged. Its paradigms proved influential enough to [help design](https://twitter.com/sirupsen/status/638330548361019392) structured logging [packages across ecosystems](https://github.com/sirupsen/logrus). From 045157315e389234da3b78a13d04f4b6209e66bb Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 18:39:26 +0200 Subject: [PATCH 0867/1520] Cut a few words --- docs/bound-loggers.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/bound-loggers.md b/docs/bound-loggers.md index 9f984330..d2ce88a8 100644 --- a/docs/bound-loggers.md +++ b/docs/bound-loggers.md @@ -33,7 +33,7 @@ All they do is manage the *context* and proxy log calls to a *wrapped logger*. ## Context -To manipulate the context dictionary, a *bound logger* offers to: +To manipulate the context dictionary, a *bound logger* can: - Recreate itself with (optional) *additional* context data: {func}`~structlog.BoundLoggerBase.bind` and {func}`~structlog.BoundLoggerBase.new`. - Recreate itself with *less* context data: {func}`~structlog.BoundLoggerBase.unbind` and {func}`~structlog.BoundLoggerBase.try_unbind`. @@ -42,7 +42,7 @@ In any case, the original bound logger or its context are never mutated. They always return a *copy* of the bound logger with a *new* context that reflects your changes. This part of the API is defined in the {class}`typing.Protocol` called {class}`structlog.typing.BindableLogger`. -N.B. that the protocol is marked {func}`typing.runtime_checkable` which means that you can check an object for being a *bound logger* using `isinstance(obj, structlog.typing.BindableLogger)`. +The protocol is marked {func}`typing.runtime_checkable` which means that you can check an object for being a *bound logger* using `isinstance(obj, structlog.typing.BindableLogger)`. ## Logging From bf545fb1d9f3b260698be6bf01f39a0aaed68baf Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 18:42:22 +0200 Subject: [PATCH 0868/1520] Better word --- docs/bound-loggers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/bound-loggers.md b/docs/bound-loggers.md index d2ce88a8..89da7862 100644 --- a/docs/bound-loggers.md +++ b/docs/bound-loggers.md @@ -45,7 +45,7 @@ This part of the API is defined in the {class}`typing.Protocol` called {class}`s The protocol is marked {func}`typing.runtime_checkable` which means that you can check an object for being a *bound logger* using `isinstance(obj, structlog.typing.BindableLogger)`. -## Logging +## Output Finally, a *bound logger* also **indirectly** exposes the logging methods of the *wrapped logger*. By default, that's a {class}`~structlog.typing.FilteringBoundLogger` that is wrapping a {class}`~structlog.PrintLogger`. From 5c6a3335f36009870adb0643b606c5499dd77c54 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 18:45:39 +0200 Subject: [PATCH 0869/1520] Words --- docs/bound-loggers.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/bound-loggers.md b/docs/bound-loggers.md index 89da7862..f7985e3c 100644 --- a/docs/bound-loggers.md +++ b/docs/bound-loggers.md @@ -99,11 +99,12 @@ Now if you call `log.info("Hello, %s!", "world", number=42)` the following happe By replacing the last processor, you decide on the **format** of your logs. For example, if you wanted JSON logs, you just have to replace the last processor with {class}`structlog.processors.JSONRenderer`. + (filtering)= -## Filtering Loggers +## Filtering by Log Levels -Filtering based on loggers could be done in a processor very easily[^stdlib], however that means unnecessary performance overhead through function calls. +Filtering based on log levels can be done in a processor very easily[^stdlib], however that means unnecessary performance overhead through function calls. We care a lot about performance and that's why *structlog*'s default logger implements level-filtering as close to the users as possible: in the *bound logger*'s logging methods. {func}`structlog.make_filtering_bound_logger` allows you to create a *bound logger* whose log methods with a log level beneath the configured one consist of a plain `return None`. From 0c8b79b57236a1af546b39d560b7dfb50404a993 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 18:53:18 +0200 Subject: [PATCH 0870/1520] Clarify earliness --- docs/bound-loggers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/bound-loggers.md b/docs/bound-loggers.md index f7985e3c..0a6c3593 100644 --- a/docs/bound-loggers.md +++ b/docs/bound-loggers.md @@ -105,7 +105,7 @@ Now if you call `log.info("Hello, %s!", "world", number=42)` the following happe ## Filtering by Log Levels Filtering based on log levels can be done in a processor very easily[^stdlib], however that means unnecessary performance overhead through function calls. -We care a lot about performance and that's why *structlog*'s default logger implements level-filtering as close to the users as possible: in the *bound logger*'s logging methods. +We care a lot about performance and that's why *structlog*'s default *bound logger* class implements level-filtering as close to the users as possible: in the *bound logger*'s logging methods *before* even creating an *event dict* and starting the processor chain. {func}`structlog.make_filtering_bound_logger` allows you to create a *bound logger* whose log methods with a log level beneath the configured one consist of a plain `return None`. From b44daaea3f31e2fe57185d38d27b05f345239e88 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 19:06:15 +0200 Subject: [PATCH 0871/1520] Move why out of basics --- docs/index.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/index.md b/docs/index.md index 8a799739..7f6a56ed 100644 --- a/docs/index.md +++ b/docs/index.md @@ -14,9 +14,18 @@ Release **{sub-ref}`release`** ([What's new?](changelog)) ``` +If you’d like more information on why structured logging in general and *structlog* in particular are good ideas, we’ve prepared a [summary](why.md) just for you. + +```{toctree} +:hidden: true + +why +``` + + ## Basics -The following chapters give you all the concepts that you need to use *structlog* productively. +The following chapters teach you all you need to use *structlog* productively. If you're already convinced that you want to play with it, skip ahead to our [Getting Started tutorial](getting-started.md)! The remaining chapters build gently on each other. @@ -24,7 +33,6 @@ The remaining chapters build gently on each other. ```{toctree} :maxdepth: 2 -why getting-started bound-loggers configuration From 5abd86c7acce2b8deb3db8e8d5855ad109889b1d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 19:15:41 +0200 Subject: [PATCH 0872/1520] Advice --- docs/index.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/index.md b/docs/index.md index 7f6a56ed..4c3a062b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -25,9 +25,8 @@ why ## Basics -The following chapters teach you all you need to use *structlog* productively. -If you're already convinced that you want to play with it, skip ahead to our [Getting Started tutorial](getting-started.md)! -The remaining chapters build gently on each other. +The first chapters teach you all you need to use *structlog* productively. +They build gently on each other, so ideally, read them in order. ```{toctree} From 70e72ba8c0e016b96bf221420a3e69f6611d8405 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 19:17:33 +0200 Subject: [PATCH 0873/1520] Better transition --- docs/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.md b/docs/index.md index 4c3a062b..702368d5 100644 --- a/docs/index.md +++ b/docs/index.md @@ -15,6 +15,7 @@ Release **{sub-ref}`release`** ([What's new?](changelog)) ``` If you’d like more information on why structured logging in general and *structlog* in particular are good ideas, we’ve prepared a [summary](why.md) just for you. +Otherwise, let’s dive right in! ```{toctree} :hidden: true From 30c214a1d7d7bb6e684263405a5af7af292f0345 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 19:25:33 +0200 Subject: [PATCH 0874/1520] Fold custom wrappers into recipes --- docs/custom-wrappers.md | 68 --------------------------------------- docs/index.md | 4 ++- docs/recipes.md | 70 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 69 deletions(-) delete mode 100644 docs/custom-wrappers.md diff --git a/docs/custom-wrappers.md b/docs/custom-wrappers.md deleted file mode 100644 index 07263028..00000000 --- a/docs/custom-wrappers.md +++ /dev/null @@ -1,68 +0,0 @@ -# Custom Wrappers - -```{eval-rst} -.. testsetup:: * - - import structlog - structlog.configure( - processors=[structlog.processors.KeyValueRenderer()], - ) -``` - -```{eval-rst} -.. testcleanup:: * - - import structlog - structlog.reset_defaults() - -``` - -The type of the *bound loggers* that are returned by {func}`structlog.get_logger()` is called the *wrapper class*, because it wraps the original logger that takes care of the output. -This wrapper class is [configurable](configuration.md). - -Originally, *structlog* used a generic wrapper class {class}`structlog.BoundLogger` by default. -That class still ships with *structlog* and can wrap *any* logger class by intercepting unknown method names and proxying them to the wrapped logger. - -Nowadays, the default is a {class}`structlog.typing.FilteringBoundLogger` that imitates standard library's log levels with the possibility of efficiently filtering at a certain level (inactive log methods are a plain `return None` each). - -If you're integrating with {mod}`logging` or Twisted, you may was to use one of their specific *bound loggers* ({class}`structlog.stdlib.BoundLogger` and {class}`structlog.twisted.BoundLogger`, respectively). - ---- - -On top of that all, you can also write your own wrapper classes. -To make it easy for you, *structlog* comes with the class {class}`structlog.BoundLoggerBase` which takes care of all data binding duties so you just add your log methods if you choose to sub-class it. - -(wrapper-class-example)= - -## Example - -It's easiest to demonstrate with an example: - -```{eval-rst} -.. doctest:: - - >>> from structlog import BoundLoggerBase, PrintLogger, wrap_logger - >>> class SemanticLogger(BoundLoggerBase): - ... def info(self, event, **kw): - ... if not "status" in kw: - ... return self._proxy_to_logger("info", event, status="ok", **kw) - ... else: - ... return self._proxy_to_logger("info", event, **kw) - ... - ... def user_error(self, event, **kw): - ... self.info(event, status="user_error", **kw) - >>> log = wrap_logger(PrintLogger(), wrapper_class=SemanticLogger) - >>> log = log.bind(user="fprefect") - >>> log.user_error("user.forgot_towel") - user='fprefect' status='user_error' event='user.forgot_towel' -``` - -You can observe the following: - -- The wrapped logger can be found in the instance variable {attr}`structlog.BoundLoggerBase._logger`. -- The helper method {meth}`structlog.BoundLoggerBase._proxy_to_logger` that is a [DRY] convenience function that runs the processor chain, handles possible {class}`structlog.DropEvent`s and calls a named function on `_logger`. -- You can run the chain by hand through using {meth}`structlog.BoundLoggerBase._process_event` . - -These two methods and one attribute are all you need to write own *bound loggers*. - -[dry]: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself diff --git a/docs/index.md b/docs/index.md index 702368d5..0eaca51b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -70,13 +70,15 @@ twisted ## *structlog* in Practice +The following chapters deal with consideration of using *structlog* in the real world. + + ```{toctree} :maxdepth: 2 recipes logging-best-practices performance -custom-wrappers ``` diff --git a/docs/recipes.md b/docs/recipes.md index ae18ebc0..74299931 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -28,3 +28,73 @@ Generally speaking: put it *before* instantiating `flask.Flask`. The [plugin definition](https://docs.twisted.org/en/stable/core/howto/plugin.html) is the best place. If your app is not a plugin, put it into your [tac file](https://docs.twisted.org/en/stable/core/howto/application.html). + + +## Custom Wrappers + +```{eval-rst} +.. testsetup:: * + + import structlog + structlog.configure( + processors=[structlog.processors.KeyValueRenderer()], + ) +``` + +```{eval-rst} +.. testcleanup:: * + + import structlog + structlog.reset_defaults() + +``` + +The type of the *bound loggers* that are returned by {func}`structlog.get_logger()` is called the *wrapper class*, because it wraps the original logger that takes care of the output. +This wrapper class is [configurable](configuration.md). + +Originally, *structlog* used a generic wrapper class {class}`structlog.BoundLogger` by default. +That class still ships with *structlog* and can wrap *any* logger class by intercepting unknown method names and proxying them to the wrapped logger. + +Nowadays, the default is a {class}`structlog.typing.FilteringBoundLogger` that imitates standard library’s log levels with the possibility of efficiently filtering at a certain level (inactive log methods are a plain `return None` each). + +If you’re integrating with {mod}`logging` or Twisted, you may was to use one of their specific *bound loggers* ({class}`structlog.stdlib.BoundLogger` and {class}`structlog.twisted.BoundLogger`, respectively). + +— + +On top of that all, you can also write your own wrapper classes. +To make it easy for you, *structlog* comes with the class {class}`structlog.BoundLoggerBase` which takes care of all data binding duties so you just add your log methods if you choose to sub-class it. + +(wrapper-class-example)= + +### Example + +It’s easiest to demonstrate with an example: + +```{eval-rst} +.. doctest:: + + >>> from structlog import BoundLoggerBase, PrintLogger, wrap_logger + >>> class SemanticLogger(BoundLoggerBase): + ... def info(self, event, **kw): + ... if not “status” in kw: + ... return self._proxy_to_logger(“info”, event, status=“ok”, **kw) + ... else: + ... return self._proxy_to_logger(“info”, event, **kw) + ... + ... def user_error(self, event, **kw): + ... self.info(event, status=“user_error”, **kw) + >>> log = wrap_logger(PrintLogger(), wrapper_class=SemanticLogger) + >>> log = log.bind(user=“fprefect”) + >>> log.user_error(“user.forgot_towel”) + user=‘fprefect’ status=‘user_error’ event=‘user.forgot_towel’ +``` + +You can observe the following: + +- The wrapped logger can be found in the instance variable {attr}`structlog.BoundLoggerBase._logger`. +- The helper method {meth}`structlog.BoundLoggerBase._proxy_to_logger` that is a [DRY] convenience function that runs the processor chain, handles possible {class}`structlog.DropEvent`s and calls a named function on `_logger`. +- You can run the chain by hand through using {meth}`structlog.BoundLoggerBase._process_event` . + +These two methods and one attribute are all you need to write own *bound loggers*. + +[dry]: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself From 9de183ca763ca3f188a64de8c839bba40630088a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 20:48:59 +0200 Subject: [PATCH 0875/1520] Grammar --- docs/index.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/index.md b/docs/index.md index 0eaca51b..c4e0a548 100644 --- a/docs/index.md +++ b/docs/index.md @@ -15,6 +15,7 @@ Release **{sub-ref}`release`** ([What's new?](changelog)) ``` If you’d like more information on why structured logging in general and *structlog* in particular are good ideas, we’ve prepared a [summary](why.md) just for you. + Otherwise, let’s dive right in! ```{toctree} @@ -70,7 +71,7 @@ twisted ## *structlog* in Practice -The following chapters deal with consideration of using *structlog* in the real world. +The following chapters deal with considerations of using *structlog* in the real world. ```{toctree} @@ -109,7 +110,7 @@ api ``` -% stop Sphinx from complaints about orphaned docs, we link them elsewhere +% stop Sphinx from complaining about orphaned docs, we link them elsewhere ```{toctree} :hidden: true From d328a630210c93711326f21b9c2856863fe9fb2b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 21:19:01 +0200 Subject: [PATCH 0876/1520] Simplify --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index c4e0a548..68be3413 100644 --- a/docs/index.md +++ b/docs/index.md @@ -42,7 +42,7 @@ contextvars ``` -## In-Development Affordances +## Development Affordances *structlog*'s focus is production systems, but it comes with **pretty console logging** and handy in-development helpers both for your **comfort** and your code's **quality**. From 8a41bc9d79062fcec3ae8329fc8dab1aa3323a93 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 21:24:11 +0200 Subject: [PATCH 0877/1520] Add missing ref --- docs/recipes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/recipes.md b/docs/recipes.md index 74299931..8600602a 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -29,6 +29,7 @@ Generally speaking: put it *before* instantiating `flask.Flask`. The [plugin definition](https://docs.twisted.org/en/stable/core/howto/plugin.html) is the best place. If your app is not a plugin, put it into your [tac file](https://docs.twisted.org/en/stable/core/howto/application.html). +(custom-wrappers)= ## Custom Wrappers From 40b31ca790763f828fe76422406a66421891fbd4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 15 Oct 2022 21:29:48 +0200 Subject: [PATCH 0878/1520] Fix quotes --- docs/recipes.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/recipes.md b/docs/recipes.md index 8600602a..5a9742e6 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -77,17 +77,17 @@ It’s easiest to demonstrate with an example: >>> from structlog import BoundLoggerBase, PrintLogger, wrap_logger >>> class SemanticLogger(BoundLoggerBase): ... def info(self, event, **kw): - ... if not “status” in kw: - ... return self._proxy_to_logger(“info”, event, status=“ok”, **kw) + ... if not "status" in kw: + ... return self._proxy_to_logger("info", event, status="ok", **kw) ... else: - ... return self._proxy_to_logger(“info”, event, **kw) + ... return self._proxy_to_logger("info", event, **kw) ... ... def user_error(self, event, **kw): - ... self.info(event, status=“user_error”, **kw) + ... self.info(event, status="user_error", **kw) >>> log = wrap_logger(PrintLogger(), wrapper_class=SemanticLogger) - >>> log = log.bind(user=“fprefect”) - >>> log.user_error(“user.forgot_towel”) - user=‘fprefect’ status=‘user_error’ event=‘user.forgot_towel’ + >>> log = log.bind(user="fprefect") + >>> log.user_error("user.forgot_towel") + user='fprefect' status='user_error' event='user.forgot_towel' ``` You can observe the following: From 447e784090413d9ef495a04984e6e4ca7e78fb33 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 16 Oct 2022 05:58:01 +0200 Subject: [PATCH 0879/1520] make more readable --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 68be3413..9eab6a7d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -14,7 +14,7 @@ Release **{sub-ref}`release`** ([What's new?](changelog)) ``` -If you’d like more information on why structured logging in general and *structlog* in particular are good ideas, we’ve prepared a [summary](why.md) just for you. +If you’d like more information on why structured logging in general – and *structlog* in particular – are good ideas, we’ve prepared a [summary](why.md) just for you. Otherwise, let’s dive right in! From 57046664de4ded2fac764e839f94f1fe36760c8d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 17 Oct 2022 06:04:27 +0200 Subject: [PATCH 0880/1520] Oxipng --- docs/_static/console_renderer.png | Bin 520725 -> 291528 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/_static/console_renderer.png b/docs/_static/console_renderer.png index 6127770bfd4a6d5a58c583683a3624162f1d6824..a8b4bc8ace6a74765ff91771b0309b186d44c061 100644 GIT binary patch literal 291528 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≦~2s2mK!fQYJ7bgz0Lb;MGV!04qxlF#ZIGkup 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ΞEcy5LWoYFA+~HhR;5slk$0-kmyOayrp`B`Fv4a zn9)h|ardhj5~bv;--LwMi3aRmmm@mD=iM0%tHO8ZeV4|*d@nOPh{BJ~x2aA>=X2%( z)}zz*i}e7@nE}<)bam~@Ph@G)iiisPwSIOfQ69KcT0zvZjUUl-(y-ErN%H)7NoDLO zbh}^pu;S;p^Gk>Jw8?t&(MQa~qiU2cW*Rc=?;3d`2QgYXW54*_bVE4&wzdiE?sC#o z;lOJ?w- z@#fzGm{@HU^;(HOArb)2K{LXddIo2Nwf`p|bTh|U!;4`K5f3`P!)6evHTrQ<;9+Q) zSQcZ%`}4_zvY2?MlvPw(>+BV zwVX(V%I2b-NP1q|2pY9hXjG?Z%dqfQ-f(sBJBYaWyRK^pU0mjVg~YN<4Pi=&Wmc?p2 zA`JooFfZ_xbNI%~MDPxc&1_JV%~=$DwBW@Ljn|D)LH_#&QNZrrJj#FS9*Qmjxrpzg zLsepgeM}L8awa-5Mnft%VR_nuT9|{iok?5NOKD_AMI`d_?UG6TpJbfgj=FWsDdJXs z?*lvINKg>9shF>rxEZ_0WFS~N#!4}2@#i2_=Sm=AkjTtaJW1Rw!s<|HKh`&B3h7_O zizKWtL+$0|)jhdp%oUoH^wu<@xtU+-osf_rh;^DLTb)}x3I%r=#}Vk04h1+5LKY#f zX_#Lc(Rnh{Iv}t?Q_WF5*mWOZV(~v=H@4vFemsE92LK*9ed$Q8>_fI(d}89FjPa02 z8pis-9X^D}THIK|wjsNns52wOQE8O+t)7=TBz?^n_o9I^F;xbw4m1}`VqaQXNy%ln zOOW1MNw`}GmIgU|5u2qcq{GF-OCHCHDM8#%Ov`}fg42#EgcAMd&MBOV_Ghmo&i~xG z%-pcF!TDyivQm-3w(~WVsP_ceJyJFoyc(CNb^;1EIIl800P|Ox)pwU4ziYC`s&@m1>5geR>~M+#wK20^QbJWt#h^0rK&D0hHa7GHyB)9G*r&$7KteAOuj{hL$3drU z)(gxEOKy6J&W+>@%$U#)KDXM2g&*BQG5(#EYsa3S(g!hFus|VDXVf_gdHJ# za&YY_0|wBo1Qa03%G`Rg1R1-T6!z_a-i5<-DaYjZC}-ov0RBx95G7`ezN-4G$PxQ? zVVML6fX}_A++XV>XRWF{U~Qu2783eE4Tmq{{!JS%_2(;$qYD}GU$>GORbO0OZYCgR zlamVtg#^p0CvMwNz3sid*M@KK3>CPYl!wQRi3vgsJpP!P%KjpV%P<;Wj)aznwBL!Z zd{vzaWTE0&wph~41-qL+Me<9h*nlFJ7CcKy8YYv}O%*mIHjG!!s!75iJnb2++#i9~ zOncXFUI3$tzM}q=aZ*h;g;VS&x<4*_@p~j$R{!NW@5)MqNUWBPhom|EH#hjdlzhNf zD~~HHe|LMK?O=mdgE+pLmRqI=k~Pnl3Qz|15rg;WFz|Cf0^)en^&um`G-gJvGT6k1 zTtqz7AKel72fj{HYfY@SSNFLwvq5l3ncvsOW#^X;l;V+IPw&Hynqs{^N5GVS&%wb# zLj#X$63;!8Nlyv02n;{iq|6}W3lzfdRKE)w;7@M!Lm*o!@sH;5J|Ly%pZEiz&0l^n z{wO)H8z7ELr&lfagXmp5Xx+DLZ;LSXwbwqGr+Pz)hB;*F#%WzG@kN+|ceEah-nP}g zxV6{}KvyenFRs}kkdj=I`j=aWkINrTrA)!5;Ho_ze~>h7w4!dzhwHB5s1ix#a1u-q znxFmirIk!($u_J0S#mfzF2ORxdv9&+7lCWoib}S!N-l2h1yZ-um9~rwvb16sCr<-929|o=IbxJ?jjaP4yL4dM;oVP`LhU%{YQi!#17wYH3btFQD7kNe zh3fPOGhp2y%8L+KYs%FlU^VJK3EUk7NULzok{?<-dmnzRlpojudne*cSA{B>lh<7L zyQsmYZ>8CDHPo+sCwr~O0756d(XmE3Z9H+z&PhktICtu9knsru!5mS3Q5#BN^)M1H z&XaVia_~JB+TCt@dd#9GGE&96PDcm~{9##}czJW)HF&~z7UuwS%~iQRDkU@vS)vwU zf1%^|6Hl$hNEM-0tn=@N>%E$}-M=M&qBfPHNFf=fUkz{7p@ ze&A@n1`WRIAfVM33k&Ph$FeBv__}6P0+x6YlzYSez7h#42e(pgwb!0Y2F9dzZx)XB z|J0W0)uAL8W{qODl4#M&!%Xa7C1B6Be&ukqHSy^5gP4Dh+`oZJbOi_L={Kk+Y~!X{pGnqt~@P{4>qS#ER};) z>X;QGJtG-9Pv_4Okd0Rj=KfX%4vwo^esc$~K!m}JglT_VmV(R7wPZSGe(I7LO~leD z`1|{Jn{QTI4xLrlSV=2D^_-lXKG)u}AyTYzQq%p$|C|Z9Ro2M-2(QP9fss*$C-6Vl zw4dHlTgr!`_(8`f%Pp6?V zDQOVtkOm16g`vZd5D=uh8|jb~B!?747#iu27#iu89E73Hjqm&WzTY|jz+oxNg^QVI z?&p5?zV@~Eb=`{o5b?@Rwb;xU51HSBI&1wWd;#S+^}lorUC(mpY?zD8ongfGBJ%KXG~cSF{pGQQWMX0Pn5@0}HtA z?<(;aaML$m+A^GQ1rUvXz&bH|ODHDA)p15rD(zNN082_t6wOA@4DU1q)I1Hbw_R5R zg_&~DH(WwO*KyGqnN`CQe%4$(3@rd&=5C< z=qM`6#XoI@FvcKiLP)YAy5*#{yM#1Ta_EMVM4*icdwl^c{1|`BQ7h{|H%{$q>Da95 z-Azm7v~;)AT|S~V)XerBqFP09PY({gWoPFi7zEZ#{M62I8(Ic?0yl=gEP_l7Pvxh@ zHZ?av2B!U_3$r6cN*ClcCJ=p)r#e3C(o6mX)3g!!k={*Si4%x_QNZ-z0IH-E%E+N> zVNuZk#l@Rq6)DiefpUBQ8q$PW(fq@HUi?3IjxhT6&b#RDF?j_z8}+i%0r|rxeOKC*aK+YSYk}Tx=R|fs`B#}Q)#j5`5Qui%j^`1n(#T<5 z+P8yez4u+b%a{Jr5?2j~g$-Jz7dlIy2+21&cgW(Y;BTMB5^kYrI#B8E{7=swGgc%^ z6SId`Ff+VoS0*77^+wg^Qm)7SiEmwUykB@1{i~Xe9AOwd3g-*L}(xHP9i2HJPL&PH%@HDj=@!8 zc}L%ue0K&c3s76AGGtBXZ~3M!RC+#wy*%4QqCi9o?+rLN0PTmsdUgA4oFZJGO>)plZVcn=U zv$6SF93u_+B~AD~rI~@hG?#LYL5G>({J|aukY?qowSytH&PH@}^dqE@wz&J*0i!&9 ziqV5-9*H?>%9~~kNFn);PPUI_vx?q9ZOOj)!6`{dOsN`tt{Q*x>Vx;c`)#A-v-_E% zQq^Fb>9;r1J)hr|nNj(b?|g=bXg)OU^@Mv-7{4 z7akrCI7x$mu5_6fFG$-zF!;v7V7xwt<^-f$x(qWlQL_ygLE;O2WKgAY0{Ac1mhZ#BdF$sT>!@oA3v z3bSlZXFVm=ez;T}IhAZsl?N%H2jxqcXrFY>PWT5owxH*e2*tD5%}WRKC!OZ`_@?b` z_sU>Za5j2T3s>|!XWzqRg}fL)Ej3sFvNEm|BL?SY1Cn^3FcgjKwH6M>m24T{zYTg( zG(3+kP$>K^V$3N1AZ$EJ;>1VyjPMKKY?8Lj)vkMnRZMd<=VV`^;34dKYC4#hsa{AV zvWHGg9w`)Y6A|`)-IM(OWsp49Q!lj3GHH&J?ry~g$<|lCYHsWgsOLuzAO(i@54Cx~ zO~BHJpmp&!7ffrEzHj@@XaFf)fE(RtyLq9u5)~rBIF#iMG!SPJF>dl6Wp*WhCBLC5 z7z<^a1T7_4;d}KmSTW|mM01zV{6MyHRkJM8@r{NTTkY7ZyAvm@i_IuY{=V#TwfrOkyznqU6?0_$XtgGJ zF=*wB&pJ8;U(!8fXV`{*Bn{+`OELE76?~R$;Z2~K)Ii65k5L2Q(;yz47m(Ktj=B92 z4QJ$!mw)N5%RkD2g-adoYRLG>J-|A+OI+Pe#OO^RB|HDrLo2HJ^3tm(@nyxEDzXC* z1()!{kFmj$2{6dBuxV`XmMwfMKOQe;MZjPU&Ug4HyWJK>TfX@o^~TCV%)Pl?+p)?? znma?fKdGoTANIZiKePK<#rGjsraL`@Kc(mke?_%Kp@bOA^tv_P0U`AhFD%#Jy05o) zSErlxnnUh;zW9svNd6T>2mKaTnsRb-;^(3LA%AVC;+CLZos;ADS>0*A@dK$MV=f+c z8JBxT22zNCae8y1*)wyM3MH16Fm*n&gP2nh|joOTgI+ zoPeoDGow!Yonz8x@>2MtLkIyrCZ$nQS{@7;MjR%Vy^C{YFm!Jp zJ-;q|WH}e3&MKIQi_@P_c4sjUt}Aq#uO!a9mhY9q?~}dez{SHuHiN11W-Sy=fM=S; z#)Cbjmx~-=iXq>OXd7y770tK}CHX><=+9EF&L6+JoyWQZWt?U-t2&wAN@Qd(dHA37 zq2llEs?pddJwifEKK4f}?q2#PKI8afONO}5U5y_j;5VqysUh>6j{|4*t2 zdgcrf2DJh178FgUaF4QW$!z%ZGqYWu;^$NOLGvq19ibe|uOK^ndvu)tDWzy6udnfV zjYz#8o!>6#!Cferls&%uer&sVvinNzOF5;E_?yfkb3pwgQ0Wi_{)&^rl@BN= zt=-;&D%3~F@Aa~GhQ1KluprciJiamg&W@}jEP+!Br@1^H5j?hf^EwlRgKT}SL*Bv zWigWf#&co28Nqr>=6hsczQJ)0xcp7j<3*iT!=moIT;12kI8%4|`^ShJBr`_04J|Rq zEuR0ixx1Bn@zxW5Md_5pe!C;F0Nf<8QBRx#DkSUSi1lG5-h=|lFf&p*y;zmjDS%4f^qhw{N z-iiqxiPU3|tw|a*kNge$qP14e#o>W!Bt8qHsJhs~tTgqv4$~l~&u59nQ2mUGsq_%H zu@dSBE@@jNbY$e{X#RFVGm z@QZ)H`40uYPY(h8AU*ouC3Sk<(=R}+{hZP8o0)={X)d?0FoP)d+r*T5kvy-Zg(rQ1 zC4(8SAOg||#AZ-ur`l%$>xDFdr;=CW-#fp-VZ3YtV_A|CC9ox9o4k!y7z+pzOmJo| z&E!nM2IwrCea#HvvHjSO87$)r9}wUEv#VJEF6&R>6$!(59$1O^Xj_C`s9X_&UsmaO0t4tH&WL-Zw&hu?-Y)1B- z&d_+%;rfo>rN=)5@#&)v$3rhZg(gez9D*qasi&X6!W1+j3-DPiog)m~TqbNZx1g*J zNm?g$+Qpz=OuKk4l6Yu)n_bi;!Ms#G-qbr`6(bLR(Sp0Ro-x(c{CRLiax-EdgEG9E z1sxPkh$i6n%+0&ZI;~X?Z2zT2@(~1!TA~vw9gS3F`6ZE)Iv5Y#kxwEp?PX$So|r`N z7&Tg?%TxUP)%%Iv9M)mUNG=^z-F=82o0i*``otWtK1csBWt7(p7_6OD%_`FPPM#V! z4<4L*sC1mUw#}0h<*Y33J48%#>BVi|cKUhEYpQYdAswur=AC~#g(2%0l`0($lD1w( z{V}X~`iI83`KVDi)D8Nl8s2@o;|E4C>+#-?O*7z*kB^@ese1?B0_B(ZL_}0(d(WwZ zgLuf_+pId+Pa-NYa`&qm8x7B&yqwT}4Eq1yiJ z3wWS86(D%jWDJxYIC=PtKK2s-qOhE@YVV?)R+sP3EYzgVZPW-<^sa|g%GPG^Yiuc5i|V_)@*Za50=^R4^8 zp{2U5x!vf8>wS6jL*Y_AN?=-17xG4mxkt($1jHbG`+sO7=>g4o#%up@CwhxkT_#j| zhU{vdLL?WmRMQf)!Ano&i`}AV{Iu`(zEvnP)mmZn=HB=iqx`$7Z#1!yf?jvzMCh2> z!H2}>VJ3l&H@CYt|Cc|jB5aW#?A(Rro`Cq1o?V&?ItkO9l#e}&0FFL+wuQS59mqi- zlDS@)Q8D01cWI{-GN=CB^&ePj^H1G|-W^sh{$V@DR`uuXaD|}jw!rj@$b&Ijzzp!U z6&}g?HLGhCN{j@zqtZ9nBalMq^5p#k1D#|#g^bgG=Dr7FbgVKfK;-zISFNTCK{M;6 zEc?jMQR$ce@E&to>xfo!qi&7)oiCJ3wN-E{>2!GEllGrQ9}k!37rpZ7jZ_qZ>-7J# z$SNK-C{OkM`*U?`_xtDVCb#c|8OP)$)nG?+Py&XfL&|NL9cT=Z zd(QF$?a9jVMCr?Lag2w_m3Y59!TOVvlTTq2lO(^WFDg;rw!)&96pGaQx4o5Y)wVY5 zvUjXk08wjZ-#2$%+k2vqe0%Kf+&%ceTl`46;IVfqli$t2;2`q(ijC4D|DnI($mC=p zENqeX-v+Py-wpox*Wc8Xl%mUr!FL}UDsa7gy-j7xjrwFG#KU7Ba372z0EYYei3&=d z;4&Tz!;vRsPTE>pu2tp+gFDeMDXQ(s>7%<_ZD!)dpaQ~472eN?V4ZIT4ZD^Wzk0N7 z^G|p$yJ`!H;rdqs6-3yQ!r3u5yL`IuE`ADES+rkbRYg|uMt@lFF)*c$AVJpkIdFC* zXba?Jy7`N`?%j-6dvOS-tt}VX~D=tqpnVepF!KwA>j!^h5f=k5D3d(!@tZF1et4 zbsqi#a$7Jh8KL(%s{@f|J)Si5lYry7CwUBo{TZwwFZq9BQ9>IxV{>ETqwR4FlYixF&n7jR$t*5=&p6mz)x;^ zsE&v2%$NVYQ~a$0i#^4ND{tasoU{keCa{+swrHs)lOF{1h!~dBJ$3yT`4c}ygUFA~ z*5{4?lrh;TDf=sM60)U8;e}|x!aD1&RBAanl4yX-Qv5AJuKkPs?eExHFrSDraj2XQ zA>fuMfCaAxr5f1W%su2|Yjy96s=#lAQ;I**<$8l`>T{=xn-IU5HGra0#?;R!a zX0aaHEO`Ct8tbtSSPfierkxVb3)mIuD8Lxh#n4OH8&2s$Faaqt44p(2WaUvoBb0O{HwgZ$b`)V zpKk*!IPBZjA8uB!uHMD{7baQo0XLUG4nMso!{SdyNWfh6m%7*=2Z@HJrl#}az!ihl zl$^9tOI0|bD{Aoi_F#!&E>kz6w~l!mYCoD=modo@3B%@QwJgT3BF&4fuG8+Y?K zQ8t!U)@zj|c#0!x9o4*}ira;*BDaiv2=AC>*g&sl^{Xg@_^SA-vm#h&ePC_kZm;01Iq7m=#sT~k&L9k4#qkWYNt5!=uP4|#5F0g4tX97hVJo=0Ud@DOil zuJ0bmw@TdR7$hk)mj4UFbb~gbYe7L5A3RSh;ivf{h`g~eWOj||zVWu++^hq%Zk=Jh zR>A4@Yvff7rQC*!KeDcUG}xx|fHTs+OY~!!gh%xfrtiq5jJ^S79UKK}h*{_QojYN~ zZh#QK&0hj1fKYD5B_jI!k+(Abq*<%_W9_$Z+ocS35d+#IKTNx67A53ras>m|@}vdk1*ma!Ib}ZIKl)TlCrX zB_Hn_v|ZZuj7Dw>($DU^bZpHz5w=T@{uW_%-VgmvwH4a>4s^XJaYv9sAAQVdwDu;> zLZhb)K=sIQnk4b4`09({6LG)+m%)^~;~D)|!=Gc?Icnwb{`R_B&v3{?(^Dc|m%)6C z0F9+Xt)N^-6O-S7huXE0=FFRAPgiC(ZeKcxEPbU@jFFg}EG}V&_gjqkaE^+UG@xet zwL^38?Z^0>o$B#o1<0=9yJ8Vp(jzgWu-A@(=DB3O&PF4&yBG0sS|iY?DF% zU*wYAbGTy4HM+*0xCp#2%3xOzA3_k~x1Rk7o%S*rU{lBdg#cx+Ulf=qE>FOJa)yC`GB(lM$EyLz{pp`cvKV6qJ-cR9S@DZNN7ti%QX$ag>;} zSvr_q#T@uWCC+0WHpabw0U>#si$bN(nI~d-tFLnazq3;0?8HRyml3L05LLrZtMdM` z#+NZs;uh{=qEqF+L|X%BjGy?#g>M%#Vb{Tm7TZ zje_$;y&k}ytyZNMNbxX;hGeW}*g4PW!39A~$-re&noUzJ%w;=NXUC^TgG25YqP0_p z?66`Yg?a@n$RuJ_>*Y&pH++0d7Bva4vjd>JJ>U(9RhS^@9LS)tArlA;Z`Y&L zPTS~vBk6TF!JEl(XOg>fu>BFH@GNlPV5Aj0muPTdRADqs0-a1>H%al22fu+@FNlf7 zn*ivw2khyd^SRu%JsTowJPF?s-m8ue3QzF6v?HOT+bfWOOLz5s>Y`cXIc_m%*gq>%{+JsI-q4=X>X;ubZ0_H_ul2#aS)K zYOFZ~z%+TPag6c#-X4l*SH!6xKcT`C1S{S8t%;We>uFp4{k`0#E}q-?J& zbcPBOIQz zWoBX`=0@|Ri}>K;VzP(cbz;({_@+qLDUaB`voh3Vzoeo&gLuJ?C;XYUKBNCKtJR@l_5ySj0LgWD`3RMZFU zZT#52gxhBE&HviI(3rY&2V&&9StHV zD0i6Vb9jDfI1Dh!|GG+(2)Gg$;P>Q~lk-pD$2tM8WMOANaU!(CP#l-4r?T`6_zs=V zUolHbW#7I{rk|P~YTLX!%DoLKL@Xt;P?Dqv=3sSm(b4lMnqFa_huoU*i0lu|>HT2XuWC2f- zrR3v-Nd%|aV|fQ#*(t0^1bHflI>dS9wq0lL{NL=|fufnzC5DvDiUXz%QwkR-*LtP_ zoozQ=t>6M3U&ya)j7plZcWX1NIX=Cml?aybk+}qiRFeql?MdAR{S!w>?s;xyHP;rj zH5m#$o5vBEt4nTqTeUVl62R)s{f(7!=s}YR=;_FcaC#>mGg`P<8r)rVWuesrqbCdu z!a1Az+CP0=w3vS77RT)p-_~xl(uRhHzYRy_)PSkO(i;aorRQMU8)adpFO&JcY=%8f zf}yk3Gha!?*?lnNYe%vLn{HJJ%)hddZ#-Z`F8q0DAu)dH|7%J8?+aL+{4@!qFx1xe zcO3_WfG=vb_meBX&4W4*PtUdg;jAo($DrO2dTpbb)1}a`z7Xj*pGUzJk#QI`jyEUQ zH{D3K7kn4-uX^?BZn;S1Eg{~|pM1ZG6>Is3=1&)j#yf9(3}Kvh84;U8^xyiv5^jaz zbZHtKvcN{lM(QwF17};zjR!zCgTsK$5g9jLn1MfeuQE9>T;T(fT_u%=MSJgC59r&F z==Glm@Z91LM)C+a&*}Y1grHf5S*h>0bkc0D5;oj5&;s;>1VM(vGm~51<*J%=#YO~n zW9L@TqG%RyRq)fVzehHGA?{*p5fkH+jN{jSl<{Kbrg%Ph>90c#80N|4GlGz{Z746K zzWJD6xxN9Vxv8w$+n*J`F2&?FKP~Ys6yLDW_^2!zf!^SK3v-1lTgQF(>JS`*1-}`Q`3l}yHsLRj05nEj25k_;t!46StE;Pn0UDR$6(DQ+ z?|a(5dp8HH;&xyyz-JT*49Gf&W&2Z`$BHz0jT!~P?D12&u_Vwe{h9*ws�ID%LhCws0+Br5 zP_;6qd2xITYt|h3OG^>Yyx(qp8ooZHCsKXBIsAYrZ((Ry@>Up!tXn8C4r~;B>Mnde zgi6OC3l4i49Z?uRfLNfoSDz z$@271P{penoEfq|CK30%sTbxV{PnO{RD*c}@0tP^)`dDKRn%iOl64T-pT*tI5r)=R z&iEG%Xn&lFBuM^>hl|UgYN|(6+Mdd!MzxOXIS%wDzX0Y@xB|{zyattMs!hNZD@^&f zD+C{mMc^bDSv9BYUHkU!_~aA5@1ME(PPfIsq&jh}5iH~nVtCRu6h=K3k zgKmka#pVup1o$3;$@HA3IX`-Op2xmvp`fB#5hn<21fB?;%qIaFxlBu_0yx}wOg-#3 zKQ$>WPtRP4CV;vi`u-c5LM$Is+Up@)AGzw@)!2bqtgWsgKMUGkS6dd%dpZo_@xDQ>XN=Cj zH#(ewQvI2F-woW@;YWQ(?^m3hoH6ex)J{ALAe z8KNxmF0E#5LIL)tZ00YSZfc*dJqlv)-!am_7YDZozVwW1(BQI{CR_ zzkJbj*7CVw3bv7K@(RN$ln?lVS`2*E&aZ~zS_50B0^ZW&x^3f${U68WpDsQ>uxX5z z{U<&zU{8htd(m>9U?51A7UtO27CbBt-=|&MNDd8=M|2+75$Zg}s+Iwha7MU*mr8-f z7lNrv-dN?LcQF;p-S{+u9LzcvPicYez$=Di*q%|7oAtzycg%vFN2t~MA^ja<>kg>huU;mmP)7L{jJ*0?^CQbQu81akRd*;;E z{&B3?4>#DsfR8oKJKdG6@r?o(Nvu_9@vXTPIP5@MLq?-Xw)9L{!Dsd|&QNB7?y2D<=edMo6{JZVR)e~U1Z`Fe!RCb0-vKv=MFA7WQMNT$CcBUbzbS=G^ zu)%w;{0sXLzb9WisCRR{s%Fu<83$3F*1m!9K3Vf;d<~KfE;Ka5uoZ_!+g^6bQC;(a zaP|;#2G8TVnR|8n#tY||!$iA36&WF_w{8!9@ouqE%Qa_TFBL4ws|XhO8Wt0LykXn3 zz6v*{A_N(5sK@etxVN#?Zip$mjVTXsWL$+yfb$cyML(dnir7iR!3@_*%+o(}&cj9^ zXMjgB;lgQ1Y{SAaLKN(t5vCpl4Tgfd!qZaMNjC)tx-0$hCG2#^eDL0Aey5*iej3(x z$F{Jmpc1iig75R0NFQNFikDOv{jmDKUqIl;u-D&tvkCl)dxGcSrh%_dpEFL-kLz;j z>1q5ZZ9!wFmuS7LW~lFs{K*goS`Ky`45(0Ijf}D__R415EtcZ_*%mo&f03a@{dz!i zXl~!tZtl|xVgEBOH0~Eb5^QH@=j3bTJSZe4CU!rYY3LOiS}hjl#z2}QYD-COK zZ{mdPPdD3nFaPo^Tx7qWs4T^}WAmR+GS@!mql(hIE~(aDnwfJL+;jIDMyq`X&L#_& zU#|N3P*u2l4@k}2k5;49!5!lNKSyIQ6fqQy4QK>T;?uNPUX~3H7@h?NC$)T)Sdab5 za{c)$%6lR&o7?ap3tQlHfcon9rjP1H9o?kxC6TnT@j@JHGSlx_Ve z)O7#QS76N^-RPz(8kPfEsA(ZHGc$3vKqsu8EqMi;z~QLv(wF6ibsorV;8F<;p4|ba zp}*Qx0>eVDbacp0sYbv?V_qx;gN3=%|8^A`+V7lIXxCbo_V2pk(Gt(nI6Wsk=L_x~ zk&PW^(wpa(H&q9B@H%8LL+#;{;JgmKN3{-%k`_sz`UJ}h*dw9oIH10ivcQ$(sa|~c zckYuH3}mQ~0d%zA2g}QUb}X%6uxaz zK_v(6l9aoiQd$38#634$f4{j71);2$9IO;&wNmX2twYn3SDNsU*htKR^EF_-BHufc zpy`$8Bd>|$CkUdWpW;~&_5J&6tE+F`yaDaunwpyazP^&uQvX@_&dyG0Nr{T8DiBV{ z$;r_@c+lC^rIgBxBblSv#zBppnVBgrE)IJ9KMgpjZRSmYkf{&Q2_oeL~rinN!gi-WST6xwcux@uuwk9Q2g0^qL05^$k_^-yi&*-%qzNoi(?3kMQ06+nuTTy_;ztDfy4s z^A$IzyLef=(C^WKp<-s|GgDKk7p0cWkTE#a{DwY~x6KERlh|*0ROe#5Sl3esU4{Ps z5YKgVo7$jY70QUtY0%K_e&Mh%HEp}2BQi2Szqefvjzs~ij;5xj6tDt$!=toA_T?Uc zCqQW42HMtu&vX8s>95D)cyD$qu$`f09N<8spsd-fXc=xE9u&&fkJe5L;GwboC|GEE z5%3(@CF;8t=$qmMW=>bJVvfK41j4X z-0wNqB(%&=KTIrK?fM9}GSTWX8-+z~OE({_tw;9Qx2JS_G<}~=dVzPqbM(wZqC-750&gR8^get)xc!u7f(P6snFFb>^ z;C+t99vlVeD$k~*uyz6T1tCe@RTgirvCf=}gXh@^( z)l7yuZLF<6YAF3RPl`_Nm#rVO|{Dx5>Z*g#to1@H-n##%?@j>t5 z>#Gazpqc!Ee~;!hXS;8{i$tctBNm99X(912LL5i@feB>hoCXZd=!Q?%J7mjsvt+`8 zF>f!(j~iSe=|6*|l0Sw>1Y}BA=8xahkn+h$UJ$arEmD@lhRL@U(3HXD{41*cWxr0Q)$yhca+0 ztpD%z8Nu_LhUX&vMe%C84XqSJKvMG0wuqS6 z*2}yOH3Iy;Rsl|bnQ5{wQzir}WAp-qAEfC2sX zF6V61lLQ6^@~H8o9Fss>WEQ5Ux4vA*tO9Cy6qhqtkL7)M?FTov3+m{4Eslotm7lSp zAX?1-!6)KWIX)Bu32KM|GZ3Wj3Gt&kfT!v4m@rGqR_|E;HvN2-vnyqLW3kWOn*V&p zcQ3+|fhR7Gm=%1(l6@{K!5E?HX!IbN>l^;Jo}=ZVWsSQ7ja8f5f9c$S^OUm>0-Ryk zvQUxsIX!K}C4B>qqF`e+nh^RlG(JD9^WsJOP6#;hXdo5;8=Uf)nE3IPS}(J=oH(s6 zQy+80Fcsozx^dEXZsuz7$J1*$r5!2T@*7p8<=_5pFFrOK7h>lmkrEho5l*bJaO0+$ zHgadXyJaEFxjW76Cic&%@9e@6ks-~sN=GM*ZJlmFH8X8fU?7xaNDiOEn_EPrUX><@ z!7@ZqaB#p@^ac0@gf8<_P9!^@DKor%39C~4gBtLw0h6O>ts{g*Y^gv z6CNysnW%cZ+3rkqW62P|MzpbOpx$JB)_9~7lo5QF5c6K3tWv$hqT>B1L;ls0*jPES-pRFen zi0wbT$m>%04s=uCq!G!p-!x@k!gPVD`#}A*Se^^%o2br0_gI zyKDArwdqRqn$<{J!~EPpxK%*-FDgx<;kmH6u2+#nN%W1{o+~?(ujTUkRQI@ z6X)Ao<3+Kw^x0W1-(U?6D(#6T*(U3x4+ruE3tem{f0>iTAVp4mCr}gpF)1xBHvy+o zcGoATiL*bt_tKNaxfw{7_5-%pF|54w;ig$h6w4;OfHC$e&B^IOHs2E;dWx{OrXyj>J^K29$ z-7{XGudbF8fjan%p$5V1hm_k@RCxQZ_Af2Q&hszK($a(l#2L~Fa1|#JQ7w6Q0~qcG z93YWNu}Q%WrRVKE96wk6irQ&0!T2RAR(6BuBqbV56$EqNu`txNGqZgvhy-Obj@K@H&RJn!*6h@EjiHYrPuQMiiFK^%m7WPv(vWp52(yl| zx^4fF{u?imLq9m2Ihr$~3}@pi{!t;Ki34QvhsKDar> z-m|CW2ERXS>@0H>*Bkp-TnCrn@#jk`)%>z{_w*3Jtn|I~xt>$RiZ&UlbR3X{qgF{i zrLpn-ib z&9D{A5BGwwIvkt}@130FmcrUrT7VyaiFn>$nKN@Ia1e+Awh2%K0zZkvXMKUI*J0V# zlKd*#F#& zad&EcZKq$bx1!YZ1_>=v^lvpMt_k@H4{5dKbStmS4?Ns_svS0lGpbemqQ;f`)6Wib zWKlNf2kXxgy$iw<%q1in_ne|?ekQkbR|i@>yi33K?qYa0J2vtmI}G*(Uv-rFx%)dY zrh$1_ivtV|4HpSexN8EAtRg}21_dDoVlSXhPJ|)baGw!B)h915AOiL|KECaNf0U~1Hzm3^I32aO${DZU1Sn8|8Mfn~A@;1!^73S$ht`W&EsTuBwcCZ{umj^FS*nPcb%m9C2%CX;X4>uvGR)r}l@Om#9^C zyu15B{Tph9!@$S@X?5(>k z*{EmW7`~XiuT0&!duiVtTX$vfg_XStNSXxGW%()_gT(j#5Yxv@v-2|T*MDAoL){fq z^>k_$2Z!-RF=tWGK)G7_K&6_G=*}@hKs_#FqOQNW-UVih6k37(=l)p@q?#^)PGKUs zOQmgF!96^@8b`oRZAsx?{TPuE-rm|;s->o)qoL!ef5jeQ4g8)|kl-l1b<)CYj(0FH z`1^^dwJ_^7Wyag72YP+xchb?X%DLv*RYL#WLaprDyRWN1?C8(SvLwKT|9pC%byGa{ z>gq9zK+rT(li-^>-rP+rO&7i{Kc;=g7T+Ba9$8_@pwdAv&i?6liID2w^#U~t9v+Q^ zz}(2+*Xlzoko})sTs&n(n{RlJ$;%}4jROBO+!b|V8(J(u*PSN!Tx`^?9cI2z>r4N=`Zb_o!?nm zIqD{YgH0e>S|$bt@-Kd+&df{_N$CcUzpXJyWe)lI)4?67LeYu$UB)>*J*N;`K|UvC zWNM1!`}Z%->tUm#R#{@q`LJ@2BdlD+x>1wC$ilkj|~t<$LG4bZ}jy|tv4?FQ}kA% zHPq=0QHE{f#hlpXE~oF<@-F0~c^nT8E!^dqE{`CuD{>)nmiN+*7n_Ro`}y(D_dKh2thwlKGsyg2|c%3@#ucX<23{JAocz2vZv zK-JtKI2#%kpl{nwU}^6GN6Y(Ow5lEa7srJj7v zVU&1{O1~!iGHjhlNM`v}^VV4z?@spUy8}jVb&2bjnm=21Qi0su^(uuY+H5-cofR3; zBudk8u@95VvQ(Wc++6D5DJ~)Q}eY~!B+c)-XrWbYen`RUdp~4QS z1r=avc-uLk9@Cf^PG4cCXJn*tn|!v-JOCWnd$CHJ_fjE#uBR1UVBYGmDBJc#=wGNm zGtd`h<1*|Nl)=?lFnN7}L=2D+?6<@wG>KtZs>u0}%GI%wlk>g)sv_%syzHFi`Efwp z+i*fx=;73Qn6l>L<#O=Rm?aqYs4MJ_-I(={ODRc{MzenadDyr>{0rekL-RZHu&b}m z4c8@;ql~z~U9V40#hesOT`^K|)0f6hqvy7j2i}42n7c|hJuY%mVZvs2sPrB?C2;PX z%q#bz8lK5sQ(A|LKI81iRWh~6mGdUJL;42w5#_bP z@^$`rmVk8(Vg5)i-b()7$foOebun#;yGd;?e_F-zdrG7xgAumL$w}F)(E}$n@LypX zKVPeufRW`hakTz>JGkE<*4FH&d%8O5adEAF|Jju{)`?(mUa)h^{yp4@_ICpiDEfdv zZ~<#ZB+rFR4x&p zxv~2(^?X*!K?gTX>75)`O|WmK)C=E;^4z|!-}4=>w;vH44^C&8>zI{Z-MqaollmOe z@l(5ujxR{02*wyjPCDJ;+TQH%geir zzVmPG5XR=$ZM*Vwy2fpI+`9J!qTs|D2GVnMah{#bk=(A}rc1-#T&*pc>@+yNfkuP+ znsyl9M1>V8G}osnFK;qLf{QS263pD&j|FF$|CB2r!~6a6dlV!X8vp5&x$|C|O6{YU z(?8;QxVYXtHWBEa0w;DLX70o;Qtx>)UW>6|RB7&}-KkdcvD{&+Z9 zQyh1+k7xJ0v3Ohdg@xk39Ur!!DXE?L8I+l781lcCy_pN>Ez=p+??WW-$A*bwD6^b% z3PBNlo6z7AcDW$0c&+LHW@aHQI5#hZ|LM5Hbi0U<&!0C%idE<5&R;*s$wK;5CGN*> zpYf+!7e>R$^lI$0UOaq}uJ)j=tWo^BY}wgqp%IQlt4w0{S@4-DDT6dQY?L8^atsTD z4C3Q8@Nxa_s^V&CSwDn59~QnoHnmw*vZ)_`9Z!QnPtIf&`Zsc6BSTj7Ns;1V^$Kgz zWV4XQ%g_26TeIIBnkAZ2nH`%mfAw>&JkCo0n%YXez!0=+thg$tHIO9QIb9@S`zsz~AOAEZ~E`E0|pqZU$Z{!^V^+IeRSwS~(DP7k#x2GH zLgnL6?{v>ExCibhP_afv2U!I1Z73UMz13+Mv*#{Op~ZG<#j_~%WAIj|rPc<&7|4sw z9C6QvL+hY1RX{C`zl)R4tn===M3}wh?XQ#<7IweIJJYNNQMHqKNG|~!l}@b{z4!{8 zDp_@(B34RIUW}su>vaGc@miM|a2V&`Cx2+_Zi9ZP>bcWnvya!~-osM*b`_jVJEPfR z()a`eEeU~ET zk4LOeIAS;@ii*O7P0v4@`6P*>&ey_DJ}u_bcTrUc4KOfAugjwyy zjx@-xr=s+w_4RsqPa@>NmlG8DZG$ooeEaUV+0?`ABx)D|!wZXA#FsPmLhN^D=ib6b zs(tkXbq4n}yXFPt6#H}3o*CS84Jqu(OA5DQ8i~U!a9C}UtQTL4c(^K?bb$YB2nr>) z`g;fFgf%raX+F)(%gdv3EIibVhbuGY>j>emNM2Gy&Nczsb$nY8kj>?OJ$#j6Bp~Ie z^7e&sD{#0z{PCrV_Guo!xMCJM4~d1jIhV28Xq~4#_^bqM_2$g`D?_%~=#fBZ%K?Sm* zq2UmLX*oNRbRWNOOx(z75iE?kA-WR|*Vf2-nJLsR#C2wB{g``-(r;P+Ui^OIbTJs` zRUUL9O|)%?w75`?e0J%Whs4M8S;5ql{!ccl111PbSjOT@Pxt%#EY?CgD|wOsWRdLt z2$ip19}u6~nV>bA=5Hkd{+dCY{7BjPeDlALlKHs`o6w#LjCCTX^a(6ut#j+Is8A)He+Z(2eaHjaw`Ins zN8q;NJA-ECKrSpyFe~zy|2%q}tULZY97KQ%D+m0^R3_p$wyr2J-N)$}r0lHWx&45I z)>1;#J$cja@+{qGXX0`2-rJEh`BdArht#MjD9yyaJD^*nb;taE@)-`ZRwkH6hILNi z-?{^6o;@$GJ87;zuvWX3JxS{W{a+1>wb2|XYp}r{(Y-E>{Y%1wG|^nwXr&=Pw=b*e8x5vgVH zQP)afYvH8rRO7e4^O?S8QHI|u{u*)Ks-8z#CF8=bNeBA=m)x{`Nz=vVYl?+jqO~6) z(082H)zI)_WQcM!{PU)`&^=Ok*h6tx*ylL zDq5KIwDCDpJaJ05J0Fh+1CbnM3RBK{0-D}CwK8Z)9C-josJ_R#vdF2Ov}rKzBFwqs z4Bc}L4#%$g3oUHJ4Gg_I`kizjq?F{=hsKx+aK=?EkTe#$9~+ilz6SY-S9AxGA#I9e z_8|i!+R~{(kl1m)+v{C*wfo8n3_tXk!Vid$KI1sW^XIM)MC7^T>LX{7_Suqx@8xVK~F_Z*W67_i^o zsZ&Nji%!blD`~u@0pr4IF##VUT_18+g-~;c7M9gA@tBRxl{IP+5SY6U`j7^x0@Fy@ zaHV6pFg{W99rRG#`I9>o+0UUDhmW41ulA8{ZlXng^gh{J!>6HD${5^`TZQRaxRLY&Tj z-eo%N>d;Rs`PnBY{y{HyO`RMI3K5*qM9RPvXb)aYBeA6djBq7n*K#?0vZ03~3niB%Hn!Iret zVUkEmDIl?=L0M5(5V!GKY8RcNH1=EbDI_(o=5K{rh7dpd1A@RhYMqhn&v=FLV_$Sy zNe#}3Pk@a@wNTA;M@wtlYF8W$A zPZYj%;m3~{8TFs8z%1Edod+JO#EW<=cJh#kLo*fX;5cNF1%(TA;=3P{T0G?-gVPzE zR0$WVl{y3hsUQ>94tPI>8`Q~7E~*3f-&Ffn;ic7$u1)6~b5tYjy2d5@Q|oDY1SQ7R zF~4Y~F>zZ=%!*P%sK2wT8=YG`lou;S8>L;%Fr`{R0L4n4^SMv9_CbaNA05eJV14 zNtS9pZx$j+Ng=fJ^mt_A^`4cV%TYf*Hg!hd(U4dz2RWnV8}w7GaF>##E}hgvWAWm` zm$N#b_N}{B4IZw%dSFe3$Xms__L#q(yF5?N)w+KR{o(^EJPB^V?%S*x1$ZBmu7Lr2 zjuIi>_V%BQu`;>vW|he|MpjOs(f8ubgCvTFiuY@6770Jj$(BFno+YIp2mP%$&Pay_ zFgG)U+PxxoKL^ z&dZP7{T%fK1OU?7&xauuRAgKqU?~gVYfs9c2yJ{WWpTNA{mhcgFw{bY1p zU>HBDKZwhFr+@JtV;c#AD2A|K)#xLY=Gdq?y zJOE|EHB9Xs7{7Uy2t!3&mLgGBuGLkAC??o_FMq11X-RWy>C@BXC^uw#9XWnurowqd z^GseoGV~!6Q`jc*rd>Z)Vt71^go{Vg9<8`{rR1X8t+dh2fByJb@iwW`b8y%J0D&>C z?mcHO#aJNDvObe1JfGornH_cTRk|z;w&I|Qbpg|Mc+M$!G{imj+F0*w+HqY}AjjX3 z#Z@SNh@%!8PoW@)`~Jj3j>#m4%Ot22Op)OZ{`2Ib7!;llXV4+F?|v2f?sM&VSnJSV zSopF*3Cn3N9wUK~@IFENsnPswSuWIuZ{G7~fLf7hJ2L#JW?Z*=@1bDaw;VrPNnf0> zv@O=A#~zy^sz9)fPE;}}bt#ZxchNE`u0BAk`IwiGE2j3o<5|VJpaXQ{)_9!?#!zw<+dt4VN=q{gMY-c-G@ z;1;&^t5p5=OjO``J+MtGfC9BR4zLB=H~rDS#)3*GEh8lHc?zG~U+%}ieQizvq?>SsmAr~7DPmlTgTz~89 zf~NI&z`33oBxg&MGX8b9=Idhz%D1ROW{!7B(PSacm`f8@3eAL813x*7jsGPgsMw<=6N zSTy%wBBvzK9VLiPVi6}PQ3%b5IKRH=G z^NU&++?QN>Sr%}v4f1d zFBD7_;_*oW7ih)3yuBWV<)9r(dVYHBpCx=$Q>>n&ux01-6-;S>~hN4iwxN-1iwrHDDGb78-I)s^2p@X9}lWlPoS_9v+@B zgMue60P#?`Q3cex!xy-ZB+n@}?F29s(eKap|HxruYrjlmDQ!IV&&?)4*|dAIVfS2# z`U$Y=W$Fd}Mol;6tS1)WTGdW`*sxn4&8fo#@>qPv-WbYol{bjv_3iDq@hwv`?aO>6 zJfJz{t_$fzCb}nHZnU2$bLVZ8a2^yo`ox2ljX4qNOp((iQ_MRBhu}};BKf_0YG~-Q zn3($Muc!6=8R=hBw4qDY)oDy`9p_(jds=%4mF|6{0}pZ|-tE=x6y38>3B}Qs@x|e! z_b%UBB2mm5$dp}=>|lLXq*~aNUSmfdUYA4TWD=Xf9W38wb?E*;@ESGHFo`@xn8R%b zHtvgFXE~AW`Qz+~h-ijQP@hpHBOcBvo-FaasH+l0M9r_u*B9ro?Y%tuOJiv&14u!( z#`7ben6=UxGBmv$DE;h5i0`>#|3P`i4y*Gbw` zwY7Wa0-T(Ig`Z+N7+1>uJ@!wZdHGM9(N!sF+t_NPBhZj}0$KvVD`sNta-H^qr<{3P zR+W)Fx9DlUWPzalFsm=%IaSkzX5Zd3zXU&1k$b&ZsZ_UsgJ#_toZ>nDOzJaGU2yR6 zO|k}fQ!|B^xcXl1_YP4zDMMykyz2(f(@zZAhsSY=!+ObvDxeJ?(jSQXkU@h@I>W@g zj^vKj(=N&Yh_7=mr2$O;!hCppYnBY@pYRiJiY#3G;!R%p^2)evV({&>)%EJ2!s0z` zD31+3TI_C#O!OP}V(2lI@Dl7cQRsQUSkOWj?%<0(mBcs(&>$N|2AlNuc7=j4+G=n+4Rb4e>DbqbXWpPfzQXWATsIGAuqVYflnU zU49~BEenTDk-_G9#3Bg%Qlpl@cVIte&cP><$~ede27i9dHl5?Ce3$f|->=zOX`_Tq zd#4_(jltv5HPs*!PJdxQ1f-;OU?4cw&!4qH2IgQKnu47N3Qb%$uP~6HbYVOGC%6ss zgW!gpx~q4@KX0^@|E{mCxT*pQ6>OJD`^h^nmXH7L8*W34rr0h1(~R8G^=9B=Fb$i! z{7}NZbW2OD%oHUzM)x+|i@zFUMOuiE57;n87cDBiow{xrS62*O6#NKkJV(b$O=Dp~ z2^$_@-r;Tl>Ewvfq~+!&kg#=f(r)ovA9;`#omr+;QH9yYY5pf?#~=4NL(qO@=wdQb z9Z$&wt-SmsgEItoB9r3~8SK3jH#|HOCIE^uu#p&rbR-1HY)KQ(o>T0d9A~-j)8FI+ z=r?xqWrRsUWR#-9lD8s-;LEeGN6Wp*U?vu|IS-jUWcev-|NPKAq|twIIAg%0qHZ4a z*F51d@`<2qKOGltOvC`bFaD`}Xs5?D=UrYfMF7K5p3^3;JBhWj1XECoX`QJ;RC5l_ zk7u?O(?Mh2FArZUMjokq4CP$!gF7vz9k9XrJF)>QNWcnnTx?rDK+NYf;Jo2srvh>c z#amZ1n5nI8>38~(L_a#SPceNqpFE;^yGIrC_cEfqIHp_?CVaRB!HGDp0^mIz~d|2&P?%D(yW zoow|g%%9mYE#!M6RWpx-h0}0!|HL)s>t&RL)s~ha@tup4eS%MjpE@()Q9ac)Rri*N<$X4T-4c=L~;gFVJG_VM-q8&Q~jD z2qp9z^MMkj&%2)1^-eXAI$k8d0}QL7aKw0#mkj^H;4L2}AR6|@zJnXwnvOoHb}OE{ z%?1(p)*kmH)qI{De?0KgRv=A8tzK7oa=$^{y;tR24?r~weIR=S9Ry~ep*=GC8&w-8 zrYS=InFA;-_FR%8B(b8KXpVr|kBF*Qhx^|@cQ^3~e||IQ&=~nD3s^y5$(oqtZff7} z5M?I*Y}J!#0{BS38T7idbz?d3>!ofYc@C_SE@j9s69w4WvEOBm+qk*$Q`&BnLlaAA8)=blkW6Vaof%_?^9K|Tk!^s^~l@?yn3I~H`$_|LFKVS1c+mE;#7V+lIq^s z2{>TZZa2b;gy-|}=!-CZQ_W4l?XjGl(Qqzc_`sD?tHyKtdj;@!by);kB`*d(Vwx3L zK=n`&P*RE@JO3muiuri_SLe{@^2!r5mS+VjGUAEZJaRB9$rAH@+L2-ORquK3ko!6S zRQva~UAwBPPulYkBkDZsEjuJ(eYns5J%}-&wuD(5QJs=%g9 zL#!=Bjq&6{>Ndm?LiZpPN?;Fn+uf)QlJ$e&7xw2VrZ` zWfe&NEF3IsIzAyU5GFCWzlYJm_vf~Oy7KkRfK|a}h&=Yq&ZeEp#2g&XwLTI{`feJC z&gLfJd)m>O#zz}p!+aqTC@3f&2+AIQIOi6|r`9j`Tj?Vx!kDM!TG6P%RVXl`AUvn| zljkM$_h+HuGRtm-0CbbleV5g7Y)HL0)%Rd_=9(GJS{5zQ?EB_~&$ER#NhaES=&+DW zhp%sprw46fk(y<9zN{j$lY~SUk~;2XA~_P+reul>pCT_0{(N;|Ct7}8`-qi`J^GZT zcXIM)cc`EvGgJer+lh^;Q4wr`mTYD^C&Sd+a_$}F>DqX}SFNo7Dg$e=zAa52VCa2A zeJJKfHHk#ZAX<2G;YAoIr1i$crJ;Ok@3`trzI$Vidbjwf{3?y7k_AJ3k6tV2U?6*3 zY=}HQFezu~WaZ6T1Ypr5@g>0o=A48U`fk&VAlQ;PC?H$^L9&ACkZ^xR;ZzdceQ;;f zKIsG~69*a4@$l-LU%R;hO3c|~ImpB!sB+hKc49P(U)O;lSFSeAVxOZG>(Z}J6 zP^ePYlW(lf7bgxo-;MS39Rl@GC*i={?k5Z;;IbscHpbo=j7Em zPD*+3TISSqn;{-s=7aiL(ju?1&$Cwvy* z3}8o=eY=Zd2Y_OxDvy^DndW($<38#KPgxa+d>Frt-ex8;;NTb3|9`k7tLGf&S3;lKGEVR2;b`r@Cu zni(85E`x&3{m!0!{04L9oM`KmPLAezwq%s&27e4w*f~E21`Fu8g3RYLhz8d)Q(on4 z^K=w!%AQ`j;25+kyOIq%+Tz^6)&U_QX&hM|FG&*xBtZO zaQlMJRe@d^Fm2Aa}umbBkex}unCyqdBP4%dgFKB9- zO+BX|lmP*e?tR@iT$L-JX#TQ%6VxyB>j_(U2AD^-dLY{A6fxLs z8-9K5$FAq|d=ZaIX8Cz59<}Hv-2-48Ft)3h_YcSa^Ww#>=XA-iY5Ut5&6(4kvo@TjXAJ76Cpu4}g81DW$Aw{g z`xw1xstx+?q*lz-Z>vdoA3epd0*wAuN^%}fi{`gzX*$&0Q&rznEYe@!0mt_w4M zb)vwdgdY*>w5~Fp3utDRSml8YMHHG!Qc4{3Ep*sSM!l2WgwEs?iw(0sdW@Y3 zs7^@tZ$AAP)V{UDyITa3$iE*kdS+(yrE;~Fii(*2r?*K#0ulY0wQc2tVgI^mk**Aa zE|DUT0EWp5)mz&>esy-R8W4bFwq@r$2x3Yb(4$mTF6ROBZ4%xW#JGcWJytn3z&#W>?Zu%~zKovAY|N7xz+W*ugga zxVMTR7El+8FfKoxLR!?mN!9jV*4Cy*N1M2~JS89i4O2OCU6^tE!L^@ezwr7f@6S>g zs)()15kFF$vYX=|jd+(qw}piXIxH{{;WVV?;(q!LhzJ=$wty`RY@0;YaZp@GJg|9G zn;H8b=o__kP*{eo$ej@+OS^gx?C5S*W71=p-ZhiQ(V^NXt`H>-qAkhmy-a9B=B!3 zb=`K_=ryniwK72uod0uB$_k?`jozj2Y9899sotXPui?hICU>~jJymW3oX~WI++$|> zAA1@2sQA?T3q2MruK`^&x%jA!6QymzgL4Xsr`)G_UpjwH2sf&0URSS;elm6O%}362 zmK0};WNDA;pg^>=^#sKLG8+)+SnB^(E}T=O0?@jf@k6epJU8r?=-~K%R`fi*j20Iy zNA>Fwn=Po=NKTnqS?NLFiysG!IzVhal#OM${g>xK+*%XA#7)_wqQ_wbT}{Q{nLv%l zn%_c2$J6R_I3@?M3_z7Ye664O^aO(%tDU^@Bb1J)1mlPw=yFyEh|4(enPPQKR7v4S8c@$O*ns#*KDGR2?)i$McBnn>D3;RcW#3cEXgI;x2;DTz_e zY2=Cm^wx)$Q-E3RJOgsfk}&nYUL=7InaJfO-dT!d(86-3`moIpPeU=aeb#?BjWKt( zJ|EidN6GHX0c0(wi7RoGHG=gedSQ1R>3LL3N6vt| zGzNvm#o;zmw`&RAsxMr?eB=+1N1aXGaN%m0kp}c()C&}&0KEAI(sOC{GC(uXGh6~B zxB49OwqNHIOTVbaeWqCN!Uusc4CLTQD9~JBTQ&Di*CB9fYKZYeEHK^d-x95J{LwK? zeRpmAuLTw`xtgwD`#ZzQqfT))sC1!udiq2Vpm;+ID2+wXEC~sna|)2c835Ad$Oz%W z+SoW8>EM;A;~A^I|2a$64b})3QOzr3$!|<`e$nU!kKrh^eNUS8i|%M-fR=xz!_Bi^ zEXLykf+PNT@{}{BSwZkA@S>-}I&W0mW&j_U>%C-`xLu;=t5?}CeWOb36PF%=r{eAp zmLKnw=<1DuT%go?!*0#spQlkWR$?Xei(GI>q{qq++I&FKk^#kPQDl$>vbGb*XGm;5 zebv#|e;aAhc0|OeNcyfsFVh@2*hiEWW?3ZP=D~zSL}!gUyanJ{Ttohh^EnZg!yxep z(8FEll3m(u+M_{t?)KrO4v7Sj6{<@Pd0_Hj0~l;=zXjE+ zu>~+60L_7IX2iF4g8*7Nh$}HYgBXK_g~I;X(pFAs#Dd-L`~>x%l)WoZ_($^E@P2_j`v2l9dLzv5ik z^7E^)TdU$z0m6J*ttqev>=yci9hB#apSo)xf~mw$yoT}ci4O-Jog~g94Z3283U?z4v3H1RsZ~W%Y=IIV3Zv)dZ!kN zewfiqMN#fCp#UQzH&{@8@ck%jnh_$=Y;qgk`V$-ldt-ZT1^9@Ih?8=|6{zA;X`+!? zgt+k|0*cv`q5b-aqzS$An$2P@Y|Ct*d+AcKMv?b+k@aTgicM>>csOT1{S{U&f_BKH zpSu%uGVg2?R56WEk&s;l|AsI0>QzvvuCA}1`cE~XQT68`VduL8Vmr|66GsQR z=$JTsu*D#bsR?-6MEXrtA6o8u!1ee!=ylh|i!%9f$<@1UW7`>uf3nm{dmU*L~>!Q-A~hn<;>R{!u= zD)K*nJKsE^c}?f)-TC<)lz%F+lh6mO%$px3uNmx| zjL-hsHUeeMVdnk^$RAsb+fPM`hgxi^vVMDWF$(j?yNiml@gBH4 z{QUwhQ>nG~y1lathb!_C$bYo@fBy989I{khK`6!~1l7^Bl4a;9 zAG&ekZ`%Fw@z(3v>X9Ck9-L_1_h0uMhWpiV{BuZ1Z9l}De(wt(d6RYg`1e15mhJkl zoeg;FhH3x%fB#>8q3x+Jwn=9~YM|(KQU1jK;-4=Kpz0!v<8zorrPZF`dw}uX4JSUW zu~H&iQ?rod@An|A;J8BR7sx`fIU+dQ3$0AH7TSy!3>2C&`qS@Zq$q9Wr0kL>CyTb` zXYaH`8Oe+dZVOZAethKqwt7TtAucywxOGM*B;To^sc zs`TloIe8K01r$j($45sD{~Q?jDY>GX3^j3le0HLBeUR9H$!W}UP_xUy&fe@()!4|| z7@O;tdMn-k>m?M+3t~NRfT^o<2TF4gpWNL^Q37`_>gwtMIpfizN2{+q9UM546`n2M zN5#2En;LoHLnAh-?v&$2UiNJZ)PtXOGE-9{x=lN% z4b~7zPzOiHs14+^^el=P)LX9%x&M3C+PGLT8yXwm<$iQ*b2I!316q6^amYsv+Zw(6 zuLzx-624p`DERpI3WdNGV1C|6taxmX7_|_O75iNU@M-T7!HJt~%%!HLHouq*sKu$N zs>-{zG8fS}ixqFsQSTzu&d+V|A*Q>3k zC(J%4D!yvE9G!zYZuj@^($;s2C6hLup1Kz-jS?Dl<~(VZ)hx;QI5Aeg=FnOt< zbV9MN9v;lI?*~_pa-?pwUu!EXkADB2;zOF3`*p8=hs@U4SW+5hd9HGGb@dd#&;J7U zPV~u>Dr4s0UFNG|T8K1XJajtJM~M!C75RTlI`wHc(Xp3dE$}^MyN?M>6)LxjuGJ(; zAaA>uy1PT|HCdBo&|kcGQS}hEi-&`=`Q+JY__*@0e%ZGI!phvQr}Z3Uwy$4L9{DJB zs+{>4`Qf9qkBp2Q9lhpBi|$>HT}B5(uyp7XRCa#?q`pQkxdIgp?V-r+XtC!e+5<=>7DX(@dd{&vTWy6f|KkKHU@zWRAlaWSt5dh*p}Y9t`m9~n+{69xg;{k!>vw4iv|1@KPujTU9puSU$QN#GjjNPE$Y110b<%h-UoGkYRU)S#y z8C>={L0uyUt7Z~s{iUs!g{udvwRUhVgO-_-li3O<*tFN?_^V57e}puzA48 z@rHe^o(WxVLpd*YoHAfnJLlQi2Z@i06|+TUn$slwyP6gZSN2_3O}M#EGXf!9sZN#&<)3oZ{8L65Rz= z2CA0H(fu`H9zGz`*kA~ef1Ag`$$6Tc%kAG#!I^{#MSWn#jZ^(W1$-)wAVKJb>{Gr@ zY3ZV>XySp(&N<24a_{lq^DVQnsWy}QH5K}<*B7nY8#&ch#R?xbC&Ep<$JUdz^)gNJ zNB#Z$#vJoyAHBUx_$nNalvXV4fv6w8oi}2!AuTO(X_(XRGs6Ztu(mUbZ~C1+zrOhi z-{tF+&`g5_@|)fA?fyqEq-e-(8rE~5dpBIUv{UOX;^>!=XlvSc&?^^ptOd&BjnQBIb`q~rAjepNLU&Fk=-nm=Y~sAg}EvF z3&4dm(r+E$mDsirdY+zIDlaz@Wak+J<88P2?UNFDWst9qiet`kH_VxEft5XHvq~WJ z`QFpP$5#b(Ld$lMk-?u@8a$(Gxl{J}L(asnHf`gup5{J}mV1Yf-35;>H%06faQe9f zo`#BEy#~SIWi&L>n-we9d9rJL7)WPgv)c*n*pqS*6rf@A&kN8J62^@OGV1l4-c-yx z%lS7D-V!**f8L8e(@d2JP5bl}ghtg-q4!@6KsEU9Gg8#j^5ZMr5EmAvrlDa4UubCP z_^p!Cx>zhs(Sn>U>FiI`IxcXqwpQ`8mI{99^lBpN2`nW$8$XFi%1i$BZ{gCEl+StX znJPm;lkSLv_oNYbnGBa+5ctCmvt|io633|aYXs+YVq;Pz&$l6hS20U=Xn1SkHTbVN z6ID!UAiS-ZbA*tKnGR=87vC%99(WKJjOq8sasVhHI$VCw2}kmi45<9iEw%fTa zvOxre);YZOF`hf!vuAY?WmCQIA?Q-u9S&^LAL0A_G+eMXuw#EDHS%aDEs7+1q@eg& zg=y)(D_}o2{RpII{A5+;k4ss&(5N#GXk~pQmlt48D&{9Da)-NtlF!j8t*e5b3~B z=bUjayT|y;3;`t@#X>52QeU5)h3lQ#F(L{7n~OCgqGzLG+H~pf-VJ?t5KF_EBC(Gw#|s4vjdKED72dG!;KEsZg*L^RSqU^WaYm@Xvh>L^uk;q~l)4mD0Mm zC=Jka%2?6&txg#-<1|ievM>T0Dq2+I#Wx+kpItwF;tPhU562ag^9qqg09VhtBMJv1+VaiCT zVJ&*n_i)z>#9zdXvY6)h4>2W!5Olw*RZb4XbD1Mlyx7AVA{Jp`Y4N>4-BhEkIU0wZ zt_LYO86scccwody7aSX!SH#o=U(WyK=JwEKh*rJ0$ahQqTjf4~4?JL>pOof&EZlN5 z`@zu#;dR6UedcG@`oj?s#v+{(S!&M}Cmr*DvlZ~mQSVHxLk6-#6iv{>`MXbEq_7hx zNl67|i!yU?Buj35F1UR2Ys%ymG3rYb|Eaz|DFFq;nMNvC2C-ppm%wKQ3#Dw)vvZ}q z33WSog<%uPqpkO$OT4UFWk3|Ju3A!Fo|K_@v|r!CgPkw!q$LF~-j(hj&d1{A&mb9-?XZ$T zT=nXmWmGiKhd*~gtE=U92SZ78&$Ee%b(c=BPe(Crox=FuZG6e!r1`Q*D5&T6@+K+S zLLQxN8BASMPKangYn_?ti4^(rwi8Kx-F=hs;BgQl{Y=yN(hh}%?~7-XPeaUp4eg(O zrtHH9NvT&%Wwf=M4kVbZ1!u@R^DX-SbDHSYSjnhPOk5Sp=kKz!EBQbIdS40DAY%m* z7$J2Jy!0O=mT@^_Uhwj*an@ahj{p3T8>IoJ8UJwCC>V1tD=I1)MWi2cW?kLh;gd3B zpJAJ!)T9q3W8W);mrmnubl&)0yoY_Er89}oek{c+uzykP&pLs3aB~gG5~95dqf#4t zBqsKB&Jb^CGiPQdfiTG1XXkV8JmXhq48N=E(_!Bc-tHu|Uz_5^-?AEjwn^E3B z=1^9kVDLSI-lUHr^zg-CJ&5$*i{UgWu%GZ3IltL~lMv#)nw&B;Boi6-Vy~>Y*x>x2?QZvo6BR$J zZU^yGpJ4>+yToOvA=W(3)l^ro5fmgg;^0Q!X{D2c)H?pyas^hT`0g-f=0a43T)qwH zFD&4;$?%_?Rz_7Sn4B0Ldf83+Wf?QUsv|*qJq;MDt=jim_z{OG2Rpi zOX$q(0ulYgaqX8c5hiO`g_=mim+{P)6eJBmV@B}s`OoB?Bo=ir7r6j=@qxti@0e5i z%y&nb@3I>_v$HEZ*#7lPrbNRYKM^sb4XaX#!=!r<8WW#R;eTv9d%V*dM;b*trTX#I zjHor|rdd@&&i(WY?BH>JeCYXp9I4s*SdLCNys@!JA;};J;yy2Ic>Zd)g*S6S$i=iY zgbl2weN7?#^TorB{9Qu4vCBBHoV;%LuB`WvJz#FJ;o8PYxYVQKGkh&&qgA1|iWPG6 zF%18o><#>UW;WmK$*Q8`M7zf-*2UKkT4P>0Obx(#ma+yjzxWe#vc>hQSx8Bra9B*X zxbIAqoYGOK)EgY#ybr$~{;o_)x-TndifvTSs-&&`{)A}?CPnV?oZR>a>)6E}&{_^a zb90}v6M(Z{j$0^|4ZTe}?L)@L6@9(cC&=u5Kycjp__1Cn5P=Z#EnyZf(~cu0Wn@hA zG9J8vIeekD=K%7lMT_W|L~IB5^u6vB*l znZJp3Uo%JhKZ_|35Os)4Dl1=h1TOk2s6!x}=@>*z%sBH&avy-dD~rUJHJ+*{N`K5j zHQhgpM=cE(b?apjFbH?-h9k1u{0z zW2snDBIJE=I-eYuj0v{t?)qOVey>|!$LsEKn0<8=^!b_=6E{x$IgdV##w^v!(WC&*^CBy|2r5(a=pGbYSo` z@!>cLeN|FgdT_5J!smaY1(H!9kT8@<5;UXB;!zgb*xC}}c*#0|S&55;LnvLdLeV#_ zuxwR7U{53X=S0L_+~U^TNh*B$H(=jpM!}gH{qz2&zrFQ=;9ott@rOF1}DbreG; zoc@lG6L)hH!~g6B)*CJw$i>11Wm=fM^n`{N{(=4rE^rgJe(Z0h!`PC;* zX|q4iZNy@C?s(Gs_ouTW3f>r{eCT_Tg7sHNsP^c<+lN^^9~+9?a-M{mHPuDU9SL1s zM~m}nUQKDAy6)zD>|AR;IG`|j`s;UgSPYw1^n~CwqW5i~;QELXmf*)Q1_Q+!r8JQ?C%tf!8}Zm*&YwYiJVI&P<8d=kV3jAA(l>@4kX; zhL$qC)&T<}c<l4k&zjMOwGgakYJ0knm22rkcael93JwACIdw{C&Xc?iWtxdXYceh35zxxPa>;B%@PzgK|q)NCYZXR@+ z_ahJ<`%FNFC*00)pqa{R*hXdj1AcTg4uMV zVc*u))}k~`i6PsYEbs{_{kpX;H8HM(0%GUZl0LRmpHPl0C+h5HQzmAA%)ijCxY*@P ziPzKXnZbvc`EVdPVyrvnAY_s~oR?$>mhGMbeAd8@uzAr6ufr5x-`Y8#TA%Jx+hm zKv-cO{R^rTj%~(>T3_$jkQH=ZZkXj$ADrtWKsau?TErU;M(vh|h+prs_P~*K@gdT2 ziaF9QE}ug})*XQM|Jz4)5?f#~D((&@N=W_ZZrn$HVz}uLh2#%JRJC2mvH5%(4iD$S zU_nKjJuUG+_hR_pd+`xa;|qaO;bm)U{>&F0Xo`3$f*kg+8Z zkCxzvR&C2?BqRjJXCCN(G7g+#64>YO?Rt(<5Tqs}9ga)V3W}-o_cODHerJOL^*WZ8 zc|!IxeEsAv8m~@N3CD{i3>}`{ZpUa06j|Pn_4w4JIzpyF^yh_<^aUX(##P0`#dAvJ zI4;`O5ENM5{{yW&18F@j@398$QFA+kY$UB^pZB)60dMrZ;`@?MuJ+d$Sh05$WJhM-#`wM`xTJ0PwJngML;4fb;*oR704Q zv&)eeD|GC6xg#EeQO(S^xoi{~kf|z6%*@yt6F+}xa>wfL{OhwI2=#Mr1JJTEEd6ue z+}lL!rjTe9Y`P!$JmlF;s@Pzb*W{}$Dq7{poYw@IntlLOBf#or1!_ntkY#0vudCwW z`JPlCBGV|j$R#)IT+-aAK5Ti4e0!UAVZuwuR%cz0GF=(SA=M9I-)Ejw!tGAKK_9cT z4HBYJt?XV`PBus^+nGxHRKQP+l;=`~?X~mNQ>Kdmtr+q%e)&E(Ks>oJpS9f1<*@JZwrZ7?ghJQ8r*uusDCA-(Co{ zwYS%x*ga(a>ZoKxZ@pmQ<}=*JJK&vLu5-^6Xq0PALZ76M*W^<#3XiQ|`5vHvTAw-E%QC%E`CvdWPQ@tq1-Z>{mx<36)^hz?mG4 zfIZpuXAgjb_!xWo#DtpqD9Qe36((5S698}*FMV#4BwgG6NhMG&8O{NUyr#{V1uH-Q zw@X$4`{aE}2ps&;ilwQhcJR{u$?JQdQI`1si2LiPD7*d-7)44#5CoBw4g~?}P6=t0 z5`h7vQ#yw(kq!x!?i#uokS?Vgq`OlX>TJB9=YD=?o%8qmx>)L>X0Gen`@6sKiKv*^ z*wcWh6l`+5z~Rc88jm{R1LVg9jPcUVn8M`(aFd0994!S(Ks=D!6F?fX0;)pHZ`%hihUwU*=xZF7piF{xE z|NEdrv^Emaf)*T|ou3c3-g7NZNk|A*z|7#sz@mzY`TkuPig2WRTHnwRZ?f7Ozouz$ zL--{q98A7$5_%=jKx;x30*Rcwn?SuhwFi>L;7sY%4W0w0D_~5KiM%`COu7H;zC`+< z4c!Lrk2!UK&9bq`dt{T<-u`M<6_mbwETKVl+8eikSHPbQn!}L+110ClAUE}un9Eat zK*E9g@16OsDbA$bpPw-7p8*z9$bnK!=j-5($VqIdvZaz6O3DS53AB8@84dn zhZ|hyfx$$*>!BGq{j~5QGjM1Fn*xUY9GGbkbxml2R_Xsa&Y6&dDv$wB{5efXI#rB) zo92&mZL_lGS)LFPI8jn8qw?0yQg-5Zjzs0Hx)->BzDrPv?aGbY*4fBP*9VZfI{D z*FW!$Ow{Y@ctCXjcqcnSPXa-XlKCRy|0m?2J}^Z)P(r)TRy!wR(fYUy-ehvaB*fyat$K3Q_hLy! zJ9%pR7p$q8g;i;mjvfaAde5#8IjLFbX__w-36?FtfOiTS3#KX0nmp@@2U3sQC{rjX zDS1I^|Id3y;Tk!0t2Ssu$1f9vcS?Y{*Z`0S~VTf#&e(^XRp^bMVyP8G|rK&*YB zvv;G*l%)_gCg^^WceDeN^v^^uBn;5dWz#F|4MGaAMm9%sht!!{pB17ofF{Fq046~k z`kyc@=AgqWz-Q5ul*0JtHh-}VfzVMKn=pu6JAO)_jtRzHrNv|ngS{hzjHEMy0fZZ9 z>)o|H=GeUJR>m|Fbiu4@{C%xB>bkd9s#`}O|+iHSqN{0!vugF^a1?*R`U)p zHsuf6zYa-gfPDV^xvf;K-FT4N3XpjyC@5rg(qH8bfKD}@%}j#}8$94iIPlS#e1{H- z@=8##(y&wk4y$9jlruwW?kqSSQfZ zgIC&i)N;nebiBI8v3i1dCZ)B^u{wP8l!W5A;pBL8rvJr;%)`FMMe+NOgY!$8 zny#yS|Dvz{zFr971?dpi2WcCVz_T_=hS1QQ;F}IZ2d~q@h}*ic)Z1CWXR2f$``-_o zi_$`9%i%}yo&A2hs|k@?Fezp>w#m8*kz)qPjs1si z?)abEgM@T&Hq#Zs0r5a=qO_L&`&luA#S_J^7BaIX&^-s4wbj*tMdbf}(dS*o(VP4u z(0hSuEly7~|90#oDP#W^u7bo4uHJh0=|fSS>p(X0DksZ1m*$zXk<{wjJr`Z@`k;b8 z?h+MQ{W@=@+kCSU3Ee3LqY0FUELiWb|N9#MFZ@d-Dtdb?Nf6nEf~OAb(vBq$043=T zM5e#9vbHk5^Tt8-LTZ5gxSw%b71p2E1NX`m+}=aKzNAYHFH! zP{EK{?e4-mWqbN#5+c0K9qf;hMoa-p$Bp0ZV&vE*waKHWD8`Qj%^?S9;t&wiZhBh# zWFP0OaQd*b}{KY2C(NfV;$ef-lqwKph;o#s#ymw$K4^wvSC?)HZL zwd+zIBf8CmbQ0`)?ZBr54IM;k#deXdWE{@5x|p-4Ijpd5Zyd$;`f_w%Gj&x|_*QjO z`o+cG%60JkZ9YP|cvB~~u3J{rotReSbHC>chx*@hj~M`5kX`+V`wqK^ga@5q(@C7J zJ=`Ce9U+j;DkysiJ-+>BIqxN?fF5c>WWDj59e^33!E=8^|7hsxJk7A$fFYMJ%QrMa zFPisO&irivGa%(Qukl->V_$8x-PTm8aZQcIJhkn*t=(_^PhhNv;rtVy+HXQ~1y_T427 zg8Pk@C3S0OGq%8m$_wG*0$5|eohEei)t+B}XuLY=8xT6~k5v}oe;T>IwidLrIPfjZ zv$(A6CDPkI>zX-+JIrJV^2Ib{QV{!qC!%;i@^$BAbP|6V!H52xS3!xdae2;gs_fdz zP;l36sMT!zJM?GtmpO6_5by+$zF$CZ2LhpM@1~9{UYKeW9($Zg6wW1muc)BSKHla> zrxm9AK9B4@d3m66k$w|)v(~;gJvn`}aa5jHKAiW4(Eo!rHT0)2Nk5sRhCLN9{AfIA z9Gfb9s7Zd4cIXeAZmu74LYZC_-fr5~oe;IXywYi_TklJO@H^12and3sazU-%|KM>y zoplI5(tm0@+W5ms95KD@3Ivs2o)dMt*hx7C(*GL%GRqUijRXm|y{)JoAQs2#M0(S` zu#lET>WTvV+4}8(!m_1>MT+avr?EoK5BDQ#l+zd<;NSq)y8?jLtF7guq7rLoYImX5 zfcg+;5lg73;4S0d*5W+Q1E6R52!Evd_rNNlfZdc%#^*RLF3zY(j6^^Dk!UF37{4Z< z6&C)!`3MjQS`UCq(qB9~pzx*>$U@#O7<0UQ_;9V&i9-pv0@7+v*U5gZ2duKU=EoAj(`GTYg6r1{Wh@El)C6I_Gu{>)0h zP|eE*lnHO5WOv`uJ`6v0B+wFySr(J%9T+ez0M}ZkU0f^o=Du3)(UJYVOuXqpG0?Dy z`Xz^aMnQTQIm72G5l5Hi0#)=(V$S2(HrzgZrDYFL4WmqHLnlLcd?nBo4|> zfm^4d-wZ+4rbyn{Fv~%X^92Q8(hA?$*ch@jbsn~=tA|HTWu+{+GdbzK$eCJSEKE%N z64<7w%8wsEm`Kd$-q%Jth4cmX#5=Tg9B;SrNgJ1n#uG|F83)~J?6Q*KiBoJ5?d;zdziXvab-y$z0rk0Qjx+g7I|8pa#w z`1!4eu?8nL#zu70B(5bcI-7T|c)0oE@s}80G)rWBVRA6X@beM!MUHs1pw-~~!k*$M zKqgg9W_Y3AJiI9{DY0n_!U>I4y@<|F15M^(R0~CrC1MZJqElL?HW14+5Llv@- zM0?J_AYBX3xfM&lDQdqLUtCe)0BTO4>nMc~sEy(40&1=E^OXDg1_p~QEj}4tgM%uP z=)FjmaXzYdYC~Z0k^N(N@s~9AF%+cjDSE){@k$lZPSEcZ^7Gdh|Aj3C>3PYqpc}Rj zn@}YG*X$(u$7C0c{d7-FBmJ~QKJZiKb&L>kc8Qk_DZdw0Z@+4t#V#z@c(=qdl|Hpe zy~%gr9d(7-^SguxqW{iPmG{X6#>oO0WGH+zpwFv*E)6iW{j9Ze26Q{Kbp-sugC1I1TKf8Fsi~AabJX-J zYiq39m9o+D`Gtk@EljAWa!9}{H?PF3PR;k!hUU9Lp^Wo8vADGP=85@((tDtLTwnt`w zymMR}jH$!FyoS(XNbvoKR&~e5-$2cVuLTh+K|DNu%^VTca{ui8rf4e1*!Yv=!iEi#h7opqWEG~m5h_&uQO&X%2(nUw6azbDd1PzwnS>{nlLqZi<#2h=J%;UBk z2UfYbxUEVbmZOuCpWC$vb9knOl}Uf146G-KPfYAS2|2vehXA^rf0ql;)f>djg1v0p zw4A}N?t8z`@Y$Ku^ex%@KHC+DWnJgrEz(`pdB1=yGtwOS8T{N?59T!&(ZF!L_Ko+V z&?IocP+IINYxT4${fheUHCiZ`sc9rLfTb{M{G}o9Q?UW6cr6#RW=R|$AVnu)fkq`A zu2H#x^XA4z6ki(i%Y|-wfKdDA>Oj1W1EPfTJXFUdvuTx;T$i}vlU>${V!l8-<-*>v z{Z-nnnE1O`Sm1ewnh$B5r-mrqhG7K3lP3wnq$&wu!L%5%QmNGInybdfxiGoqD=8C0 z?ymL!M2GJn&~bi)2ZdQ45uIO#?{hL{vhceU>=6?9{FaG+oQx*eezwq8w?#<_V%)Sy zZ03n#7w^sQ8wG-Wt>23%5$BwbE9t6Kplv;gU<>dhips)LE{j#=pfB19TQThB-GP^b z=M!*fg;8N7n1K4l^N2D2{Shdq9tC$88aPh@_=zVFlG#oIR(A4BfH42$?~}zCoh~da zjQ#nPj#j$?{~uhvL7^VJx}qXBAI1D?r4XbIiOXQl zET8FXn1hT=umAE19uu^rGH>$pSJinqUl{C;F!𻫋P@;l{lPE#@F#DowS}0FM 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 xa$N=j5m__L73l(ETJNKz$qjjGq3 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

  • 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
    N|8I;#g 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

    v%Ej*A%)()JdV|<@y2@I=`JSMO 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�OV8&P(`LPYJMruxbezuMR2_;Onqtr@PnVJ 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\Ii(FZW9xC4?x2KC!>pfLb7}jVS&J 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 literal 291528 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≦~2s2mK!fQYJ7bgz0Lb;MGV!04qxlF#ZIGkup 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ΞEcy5LWoYFA+~HhR;5slk$0-kmyOayrp`B`Fv4a zn9)h|ardhj5~bv;--LwMi3aRmmm@mD=iM0%tHO8ZeV4|*d@nOPh{BJ~x2aA>=X2%( z)}zz*i}e7@nE}<)bam~@Ph@G)iiisPwSIOfQ69KcT0zvZjUUl-(y-ErN%H)7NoDLO zbh}^pu;S;p^Gk>Jw8?t&(MQa~qiU2cW*Rc=?;3d`2QgYXW54*_bVE4&wzdiE?sC#o z;lOJ?w- z@#fzGm{@HU^;(HOArb)2K{LXddIo2Nwf`p|bTh|U!;4`K5f3`P!)6evHTrQ<;9+Q) zSQcZ%`}4_zvY2?MlvPw(>+BV zwVX(V%I2b-NP1q|2pY9hXjG?Z%dqfQ-f(sBJBYaWyRK^pU0mjVg~YN<4Pi=&Wmc?p2 zA`JooFfZ_xbNI%~MDPxc&1_JV%~=$DwBW@Ljn|D)LH_#&QNZrrJj#FS9*Qmjxrpzg zLsepgeM}L8awa-5Mnft%VR_nuT9|{iok?5NOKD_AMI`d_?UG6TpJbfgj=FWsDdJXs z?*lvINKg>9shF>rxEZ_0WFS~N#!4}2@#i2_=Sm=AkjTtaJW1Rw!s<|HKh`&B3h7_O zizKWtL+$0|)jhdp%oUoH^wu<@xtU+-osf_rh;^DLTb)}x3I%r=#}Vk04h1+5LKY#f zX_#Lc(Rnh{Iv}t?Q_WF5*mWOZV(~v=H@4vFemsE92LK*9ed$Q8>_fI(d}89FjPa02 z8pis-9X^D}THIK|wjsNns52wOQE8O+t)7=TBz?^n_o9I^F;xbw4m1}`VqaQXNy%ln zOOW1MNw`}GmIgU|5u2qcq{GF-OCHCHDM8#%Ov`}fg42#EgcAMd&MBOV_Ghmo&i~xG z%-pcF!TDyivQm-3w(~WVsP_ceJyJFoyc(CNb^;1EIIl800P|Ox)pwU4ziYC`s&@m1>5geR>~M+#wK20^QbJWt#h^0rK&D0hHa7GHyB)9G*r&$7KteAOuj{hL$3drU z)(gxEOKy6J&W+>@%$U#)KDXM2g&*BQG5(#EYsa3S(g!hFus|VDXVf_gdHJ# za&YY_0|wBo1Qa03%G`Rg1R1-T6!z_a-i5<-DaYjZC}-ov0RBx95G7`ezN-4G$PxQ? zVVML6fX}_A++XV>XRWF{U~Qu2783eE4Tmq{{!JS%_2(;$qYD}GU$>GORbO0OZYCgR zlamVtg#^p0CvMwNz3sid*M@KK3>CPYl!wQRi3vgsJpP!P%KjpV%P<;Wj)aznwBL!Z zd{vzaWTE0&wph~41-qL+Me<9h*nlFJ7CcKy8YYv}O%*mIHjG!!s!75iJnb2++#i9~ zOncXFUI3$tzM}q=aZ*h;g;VS&x<4*_@p~j$R{!NW@5)MqNUWBPhom|EH#hjdlzhNf zD~~HHe|LMK?O=mdgE+pLmRqI=k~Pnl3Qz|15rg;WFz|Cf0^)en^&um`G-gJvGT6k1 zTtqz7AKel72fj{HYfY@SSNFLwvq5l3ncvsOW#^X;l;V+IPw&Hynqs{^N5GVS&%wb# zLj#X$63;!8Nlyv02n;{iq|6}W3lzfdRKE)w;7@M!Lm*o!@sH;5J|Ly%pZEiz&0l^n z{wO)H8z7ELr&lfagXmp5Xx+DLZ;LSXwbwqGr+Pz)hB;*F#%WzG@kN+|ceEah-nP}g zxV6{}KvyenFRs}kkdj=I`j=aWkINrTrA)!5;Ho_ze~>h7w4!dzhwHB5s1ix#a1u-q znxFmirIk!($u_J0S#mfzF2ORxdv9&+7lCWoib}S!N-l2h1yZ-um9~rwvb16sCr<-929|o=IbxJ?jjaP4yL4dM;oVP`LhU%{YQi!#17wYH3btFQD7kNe zh3fPOGhp2y%8L+KYs%FlU^VJK3EUk7NULzok{?<-dmnzRlpojudne*cSA{B>lh<7L zyQsmYZ>8CDHPo+sCwr~O0756d(XmE3Z9H+z&PhktICtu9knsru!5mS3Q5#BN^)M1H z&XaVia_~JB+TCt@dd#9GGE&96PDcm~{9##}czJW)HF&~z7UuwS%~iQRDkU@vS)vwU zf1%^|6Hl$hNEM-0tn=@N>%E$}-M=M&qBfPHNFf=fUkz{7p@ ze&A@n1`WRIAfVM33k&Ph$FeBv__}6P0+x6YlzYSez7h#42e(pgwb!0Y2F9dzZx)XB z|J0W0)uAL8W{qODl4#M&!%Xa7C1B6Be&ukqHSy^5gP4Dh+`oZJbOi_L={Kk+Y~!X{pGnqt~@P{4>qS#ER};) z>X;QGJtG-9Pv_4Okd0Rj=KfX%4vwo^esc$~K!m}JglT_VmV(R7wPZSGe(I7LO~leD z`1|{Jn{QTI4xLrlSV=2D^_-lXKG)u}AyTYzQq%p$|C|Z9Ro2M-2(QP9fss*$C-6Vl zw4dHlTgr!`_(8`f%Pp6?V zDQOVtkOm16g`vZd5D=uh8|jb~B!?747#iu27#iu89E73Hjqm&WzTY|jz+oxNg^QVI z?&p5?zV@~Eb=`{o5b?@Rwb;xU51HSBI&1wWd;#S+^}lorUC(mpY?zD8ongfGBJ%KXG~cSF{pGQQWMX0Pn5@0}HtA z?<(;aaML$m+A^GQ1rUvXz&bH|ODHDA)p15rD(zNN082_t6wOA@4DU1q)I1Hbw_R5R zg_&~DH(WwO*KyGqnN`CQe%4$(3@rd&=5C< z=qM`6#XoI@FvcKiLP)YAy5*#{yM#1Ta_EMVM4*icdwl^c{1|`BQ7h{|H%{$q>Da95 z-Azm7v~;)AT|S~V)XerBqFP09PY({gWoPFi7zEZ#{M62I8(Ic?0yl=gEP_l7Pvxh@ zHZ?av2B!U_3$r6cN*ClcCJ=p)r#e3C(o6mX)3g!!k={*Si4%x_QNZ-z0IH-E%E+N> zVNuZk#l@Rq6)DiefpUBQ8q$PW(fq@HUi?3IjxhT6&b#RDF?j_z8}+i%0r|rxeOKC*aK+YSYk}Tx=R|fs`B#}Q)#j5`5Qui%j^`1n(#T<5 z+P8yez4u+b%a{Jr5?2j~g$-Jz7dlIy2+21&cgW(Y;BTMB5^kYrI#B8E{7=swGgc%^ z6SId`Ff+VoS0*77^+wg^Qm)7SiEmwUykB@1{i~Xe9AOwd3g-*L}(xHP9i2HJPL&PH%@HDj=@!8 zc}L%ue0K&c3s76AGGtBXZ~3M!RC+#wy*%4QqCi9o?+rLN0PTmsdUgA4oFZJGO>)plZVcn=U zv$6SF93u_+B~AD~rI~@hG?#LYL5G>({J|aukY?qowSytH&PH@}^dqE@wz&J*0i!&9 ziqV5-9*H?>%9~~kNFn);PPUI_vx?q9ZOOj)!6`{dOsN`tt{Q*x>Vx;c`)#A-v-_E% zQq^Fb>9;r1J)hr|nNj(b?|g=bXg)OU^@Mv-7{4 z7akrCI7x$mu5_6fFG$-zF!;v7V7xwt<^-f$x(qWlQL_ygLE;O2WKgAY0{Ac1mhZ#BdF$sT>!@oA3v z3bSlZXFVm=ez;T}IhAZsl?N%H2jxqcXrFY>PWT5owxH*e2*tD5%}WRKC!OZ`_@?b` z_sU>Za5j2T3s>|!XWzqRg}fL)Ej3sFvNEm|BL?SY1Cn^3FcgjKwH6M>m24T{zYTg( zG(3+kP$>K^V$3N1AZ$EJ;>1VyjPMKKY?8Lj)vkMnRZMd<=VV`^;34dKYC4#hsa{AV zvWHGg9w`)Y6A|`)-IM(OWsp49Q!lj3GHH&J?ry~g$<|lCYHsWgsOLuzAO(i@54Cx~ zO~BHJpmp&!7ffrEzHj@@XaFf)fE(RtyLq9u5)~rBIF#iMG!SPJF>dl6Wp*WhCBLC5 z7z<^a1T7_4;d}KmSTW|mM01zV{6MyHRkJM8@r{NTTkY7ZyAvm@i_IuY{=V#TwfrOkyznqU6?0_$XtgGJ zF=*wB&pJ8;U(!8fXV`{*Bn{+`OELE76?~R$;Z2~K)Ii65k5L2Q(;yz47m(Ktj=B92 z4QJ$!mw)N5%RkD2g-adoYRLG>J-|A+OI+Pe#OO^RB|HDrLo2HJ^3tm(@nyxEDzXC* z1()!{kFmj$2{6dBuxV`XmMwfMKOQe;MZjPU&Ug4HyWJK>TfX@o^~TCV%)Pl?+p)?? znma?fKdGoTANIZiKePK<#rGjsraL`@Kc(mke?_%Kp@bOA^tv_P0U`AhFD%#Jy05o) zSErlxnnUh;zW9svNd6T>2mKaTnsRb-;^(3LA%AVC;+CLZos;ADS>0*A@dK$MV=f+c z8JBxT22zNCae8y1*)wyM3MH16Fm*n&gP2nh|joOTgI+ zoPeoDGow!Yonz8x@>2MtLkIyrCZ$nQS{@7;MjR%Vy^C{YFm!Jp zJ-;q|WH}e3&MKIQi_@P_c4sjUt}Aq#uO!a9mhY9q?~}dez{SHuHiN11W-Sy=fM=S; z#)Cbjmx~-=iXq>OXd7y770tK}CHX><=+9EF&L6+JoyWQZWt?U-t2&wAN@Qd(dHA37 zq2llEs?pddJwifEKK4f}?q2#PKI8afONO}5U5y_j;5VqysUh>6j{|4*t2 zdgcrf2DJh178FgUaF4QW$!z%ZGqYWu;^$NOLGvq19ibe|uOK^ndvu)tDWzy6udnfV zjYz#8o!>6#!Cferls&%uer&sVvinNzOF5;E_?yfkb3pwgQ0Wi_{)&^rl@BN= zt=-;&D%3~F@Aa~GhQ1KluprciJiamg&W@}jEP+!Br@1^H5j?hf^EwlRgKT}SL*Bv zWigWf#&co28Nqr>=6hsczQJ)0xcp7j<3*iT!=moIT;12kI8%4|`^ShJBr`_04J|Rq zEuR0ixx1Bn@zxW5Md_5pe!C;F0Nf<8QBRx#DkSUSi1lG5-h=|lFf&p*y;zmjDS%4f^qhw{N z-iiqxiPU3|tw|a*kNge$qP14e#o>W!Bt8qHsJhs~tTgqv4$~l~&u59nQ2mUGsq_%H zu@dSBE@@jNbY$e{X#RFVGm z@QZ)H`40uYPY(h8AU*ouC3Sk<(=R}+{hZP8o0)={X)d?0FoP)d+r*T5kvy-Zg(rQ1 zC4(8SAOg||#AZ-ur`l%$>xDFdr;=CW-#fp-VZ3YtV_A|CC9ox9o4k!y7z+pzOmJo| z&E!nM2IwrCea#HvvHjSO87$)r9}wUEv#VJEF6&R>6$!(59$1O^Xj_C`s9X_&UsmaO0t4tH&WL-Zw&hu?-Y)1B- z&d_+%;rfo>rN=)5@#&)v$3rhZg(gez9D*qasi&X6!W1+j3-DPiog)m~TqbNZx1g*J zNm?g$+Qpz=OuKk4l6Yu)n_bi;!Ms#G-qbr`6(bLR(Sp0Ro-x(c{CRLiax-EdgEG9E z1sxPkh$i6n%+0&ZI;~X?Z2zT2@(~1!TA~vw9gS3F`6ZE)Iv5Y#kxwEp?PX$So|r`N z7&Tg?%TxUP)%%Iv9M)mUNG=^z-F=82o0i*``otWtK1csBWt7(p7_6OD%_`FPPM#V! z4<4L*sC1mUw#}0h<*Y33J48%#>BVi|cKUhEYpQYdAswur=AC~#g(2%0l`0($lD1w( z{V}X~`iI83`KVDi)D8Nl8s2@o;|E4C>+#-?O*7z*kB^@ese1?B0_B(ZL_}0(d(WwZ zgLuf_+pId+Pa-NYa`&qm8x7B&yqwT}4Eq1yiJ z3wWS86(D%jWDJxYIC=PtKK2s-qOhE@YVV?)R+sP3EYzgVZPW-<^sa|g%GPG^Yiuc5i|V_)@*Za50=^R4^8 zp{2U5x!vf8>wS6jL*Y_AN?=-17xG4mxkt($1jHbG`+sO7=>g4o#%up@CwhxkT_#j| zhU{vdLL?WmRMQf)!Ano&i`}AV{Iu`(zEvnP)mmZn=HB=iqx`$7Z#1!yf?jvzMCh2> z!H2}>VJ3l&H@CYt|Cc|jB5aW#?A(Rro`Cq1o?V&?ItkO9l#e}&0FFL+wuQS59mqi- zlDS@)Q8D01cWI{-GN=CB^&ePj^H1G|-W^sh{$V@DR`uuXaD|}jw!rj@$b&Ijzzp!U z6&}g?HLGhCN{j@zqtZ9nBalMq^5p#k1D#|#g^bgG=Dr7FbgVKfK;-zISFNTCK{M;6 zEc?jMQR$ce@E&to>xfo!qi&7)oiCJ3wN-E{>2!GEllGrQ9}k!37rpZ7jZ_qZ>-7J# z$SNK-C{OkM`*U?`_xtDVCb#c|8OP)$)nG?+Py&XfL&|NL9cT=Z zd(QF$?a9jVMCr?Lag2w_m3Y59!TOVvlTTq2lO(^WFDg;rw!)&96pGaQx4o5Y)wVY5 zvUjXk08wjZ-#2$%+k2vqe0%Kf+&%ceTl`46;IVfqli$t2;2`q(ijC4D|DnI($mC=p zENqeX-v+Py-wpox*Wc8Xl%mUr!FL}UDsa7gy-j7xjrwFG#KU7Ba372z0EYYei3&=d z;4&Tz!;vRsPTE>pu2tp+gFDeMDXQ(s>7%<_ZD!)dpaQ~472eN?V4ZIT4ZD^Wzk0N7 z^G|p$yJ`!H;rdqs6-3yQ!r3u5yL`IuE`ADES+rkbRYg|uMt@lFF)*c$AVJpkIdFC* zXba?Jy7`N`?%j-6dvOS-tt}VX~D=tqpnVepF!KwA>j!^h5f=k5D3d(!@tZF1et4 zbsqi#a$7Jh8KL(%s{@f|J)Si5lYry7CwUBo{TZwwFZq9BQ9>IxV{>ETqwR4FlYixF&n7jR$t*5=&p6mz)x;^ zsE&v2%$NVYQ~a$0i#^4ND{tasoU{keCa{+swrHs)lOF{1h!~dBJ$3yT`4c}ygUFA~ z*5{4?lrh;TDf=sM60)U8;e}|x!aD1&RBAanl4yX-Qv5AJuKkPs?eExHFrSDraj2XQ zA>fuMfCaAxr5f1W%su2|Yjy96s=#lAQ;I**<$8l`>T{=xn-IU5HGra0#?;R!a zX0aaHEO`Ct8tbtSSPfierkxVb3)mIuD8Lxh#n4OH8&2s$Faaqt44p(2WaUvoBb0O{HwgZ$b`)V zpKk*!IPBZjA8uB!uHMD{7baQo0XLUG4nMso!{SdyNWfh6m%7*=2Z@HJrl#}az!ihl zl$^9tOI0|bD{Aoi_F#!&E>kz6w~l!mYCoD=modo@3B%@QwJgT3BF&4fuG8+Y?K zQ8t!U)@zj|c#0!x9o4*}ira;*BDaiv2=AC>*g&sl^{Xg@_^SA-vm#h&ePC_kZm;01Iq7m=#sT~k&L9k4#qkWYNt5!=uP4|#5F0g4tX97hVJo=0Ud@DOil zuJ0bmw@TdR7$hk)mj4UFbb~gbYe7L5A3RSh;ivf{h`g~eWOj||zVWu++^hq%Zk=Jh zR>A4@Yvff7rQC*!KeDcUG}xx|fHTs+OY~!!gh%xfrtiq5jJ^S79UKK}h*{_QojYN~ zZh#QK&0hj1fKYD5B_jI!k+(Abq*<%_W9_$Z+ocS35d+#IKTNx67A53ras>m|@}vdk1*ma!Ib}ZIKl)TlCrX zB_Hn_v|ZZuj7Dw>($DU^bZpHz5w=T@{uW_%-VgmvwH4a>4s^XJaYv9sAAQVdwDu;> zLZhb)K=sIQnk4b4`09({6LG)+m%)^~;~D)|!=Gc?Icnwb{`R_B&v3{?(^Dc|m%)6C z0F9+Xt)N^-6O-S7huXE0=FFRAPgiC(ZeKcxEPbU@jFFg}EG}V&_gjqkaE^+UG@xet zwL^38?Z^0>o$B#o1<0=9yJ8Vp(jzgWu-A@(=DB3O&PF4&yBG0sS|iY?DF% zU*wYAbGTy4HM+*0xCp#2%3xOzA3_k~x1Rk7o%S*rU{lBdg#cx+Ulf=qE>FOJa)yC`GB(lM$EyLz{pp`cvKV6qJ-cR9S@DZNN7ti%QX$ag>;} zSvr_q#T@uWCC+0WHpabw0U>#si$bN(nI~d-tFLnazq3;0?8HRyml3L05LLrZtMdM` z#+NZs;uh{=qEqF+L|X%BjGy?#g>M%#Vb{Tm7TZ zje_$;y&k}ytyZNMNbxX;hGeW}*g4PW!39A~$-re&noUzJ%w;=NXUC^TgG25YqP0_p z?66`Yg?a@n$RuJ_>*Y&pH++0d7Bva4vjd>JJ>U(9RhS^@9LS)tArlA;Z`Y&L zPTS~vBk6TF!JEl(XOg>fu>BFH@GNlPV5Aj0muPTdRADqs0-a1>H%al22fu+@FNlf7 zn*ivw2khyd^SRu%JsTowJPF?s-m8ue3QzF6v?HOT+bfWOOLz5s>Y`cXIc_m%*gq>%{+JsI-q4=X>X;ubZ0_H_ul2#aS)K zYOFZ~z%+TPag6c#-X4l*SH!6xKcT`C1S{S8t%;We>uFp4{k`0#E}q-?J& zbcPBOIQz zWoBX`=0@|Ri}>K;VzP(cbz;({_@+qLDUaB`voh3Vzoeo&gLuJ?C;XYUKBNCKtJR@l_5ySj0LgWD`3RMZFU zZT#52gxhBE&HviI(3rY&2V&&9StHV zD0i6Vb9jDfI1Dh!|GG+(2)Gg$;P>Q~lk-pD$2tM8WMOANaU!(CP#l-4r?T`6_zs=V zUolHbW#7I{rk|P~YTLX!%DoLKL@Xt;P?Dqv=3sSm(b4lMnqFa_huoU*i0lu|>HT2XuWC2f- zrR3v-Nd%|aV|fQ#*(t0^1bHflI>dS9wq0lL{NL=|fufnzC5DvDiUXz%QwkR-*LtP_ zoozQ=t>6M3U&ya)j7plZcWX1NIX=Cml?aybk+}qiRFeql?MdAR{S!w>?s;xyHP;rj zH5m#$o5vBEt4nTqTeUVl62R)s{f(7!=s}YR=;_FcaC#>mGg`P<8r)rVWuesrqbCdu z!a1Az+CP0=w3vS77RT)p-_~xl(uRhHzYRy_)PSkO(i;aorRQMU8)adpFO&JcY=%8f zf}yk3Gha!?*?lnNYe%vLn{HJJ%)hddZ#-Z`F8q0DAu)dH|7%J8?+aL+{4@!qFx1xe zcO3_WfG=vb_meBX&4W4*PtUdg;jAo($DrO2dTpbb)1}a`z7Xj*pGUzJk#QI`jyEUQ zH{D3K7kn4-uX^?BZn;S1Eg{~|pM1ZG6>Is3=1&)j#yf9(3}Kvh84;U8^xyiv5^jaz zbZHtKvcN{lM(QwF17};zjR!zCgTsK$5g9jLn1MfeuQE9>T;T(fT_u%=MSJgC59r&F z==Glm@Z91LM)C+a&*}Y1grHf5S*h>0bkc0D5;oj5&;s;>1VM(vGm~51<*J%=#YO~n zW9L@TqG%RyRq)fVzehHGA?{*p5fkH+jN{jSl<{Kbrg%Ph>90c#80N|4GlGz{Z746K zzWJD6xxN9Vxv8w$+n*J`F2&?FKP~Ys6yLDW_^2!zf!^SK3v-1lTgQF(>JS`*1-}`Q`3l}yHsLRj05nEj25k_;t!46StE;Pn0UDR$6(DQ+ z?|a(5dp8HH;&xyyz-JT*49Gf&W&2Z`$BHz0jT!~P?D12&u_Vwe{h9*ws�ID%LhCws0+Br5 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𻫋P@;l{lPE#@F#DowS}0FM z*xdx&_&&XTbfJ5uS*T}>Jb1};Mzk+gQQh_9$iLrd*$jba>$z~>(0?$5oi_JaOy{x;`ZL!?rOmAS{yv4r|mLu z;EA@Xa2tX#dT>yR4z>QXH%CB7v#a&)|6D3PJ$<7MF)3;9NsrN%Z)$4 z@FnlpueX&=*OUznw}mx-Y#ZvmnyXF|)_yfAtiiQd}Uxb~`n5 zDSEti?P9y{tyO$$Qg!2?JTUL%bZsotB@-WCzeOX=WTtMhHRR_fNQ8}iYP!37dy*-3 z4b_~Wtg5=!emnAHZ0x>+!xMUjp!4&PhlGpvwK;Gi0s{Zl4FEg>5{V0-1_o+7P#}34 zDT3JWe<kINzob#HqDvAVgrTx@U&-k&2w>@}RGLaTS0{s?%Tw=D%?=e~NyP7w=4 zg$3D5iM@?#?TwccAT|vSrhPxZZiCjtYMp~ajn(TH%pZ{WN?=LL%YB!ZUBV`(C+wyR z)*Qy#EMKZDQ~BH-7mkdDqKj*67VRGBHp6d@2NHnb#zjA;)baX##T7dcWsi@KJSHzy zeq#)9nR4Vlvcg*9J^J%_|HCh&j5prWx9LZcrrQHvV>ge>CFg2>2Yda2PW)lYcdp;7 zRHJ#3T+K8rdUP1(M@~v?k{8W5f8p|d9?kVWdofEA{FO-koBBk7w9z!nY%^mnRE25P z(<-Xew7t>2C(Mw>VNbNAvjgO%%7Gb?+mCy}17AcMsG#Cj`YcWEzhq?77~TSNtEbtj z*~&jXx8e&lS$TCkk-b1JN90gM4YD{-_@Yn>KF2c#RQio_?0W;qEU9HWHn*<3cG7qO z9)=uAqwBrBJw4HUDyk9rC@EOB4}gabHhIU23$--QG+Z|0b^2cOgBaJ+W$hz& z*qz>+?6IG&L)ObHx_0-*zwx_oAdkvOi7WaGk9>R4raf4lKQvbF|WOq9i~W0aA$oqptc&!Aj~XimwjdY_i4Y08lsE}{5Km8GLbVf+FxudO&BGg*`K$a zuNe^K({fqTHs1`bFzssc-u~fV>xP5Sb~nyWJ{N*saC{}!6A^hVpU|rL_LT3bklAne zoNX^*4)QD+>yW3bt2@V>L;hw=BmVE`*&pAq8t-W#+h39$^OS$ON4pys`eZOJ8O7wO z5KlL1tT2|n8DXHH<}aO|r-FEE=N^-KrQb>L?!|tYnBZBpHVj)0UiThGe7dfAC^7S^ z_4`|B?r`C{M5KqzBCd`|G)hHBx)TaS?D-Ri^Ip6JlE`ybR0ZviX;(hwDQx0+HnOs^ zA?-thgDsutsdD7Nyo@rxgZ(qY2V*5WSInm)?N{ z*V7F&%SJ?LkONItEu$3z^N~L3(c$*99s(IVF-)C)G*mfTW@|OIxc2DO)O`&^GCju; zOi++ol;1r}O#|WXZc$OLAX;Ba%cG$vQ(7M2viM^XUc{oO^VXXRqW#vfazl)t5*%|` zH2w)NJ)LE71XmWVIt&IRg2Th^**8-6J&Q4$-o!=I#po`gEv@C+qj-CpWi(^l%q)64&^l*3OvoNOqN%rAEAop!n zlWuH0eHu0)N{4y!LqbFV1Jg&sU%}w8l@HFrF*61IPKy(6I#)?o)(M(p(R4%wv;O8e=y76O%Zj34W!2mFeVAlNn2gS8s&#RtiVt zEEa+cK`_$se z=dA6D+DKhWHkA2zB;t5`m=+tdg8DCPm@oXWo4=hprT$Bnlb}uq;Eu- z9qIT7wK#-KDZmM-H(_FQlwFucLd~d%pYSiOAs~AEJRNa%lxp}uzzGqGc!d<$TWBl z%BcMORpAR>8$fL2$%KnoARLV-+VJC}qeq5^E4)PutdC3!CMH^AVl3{XOABkH2(A-C ztxY8Tcbg0xANPI9R#$5`F_p>5Wqk73n3p>pwZM>SW^Wb~t0sXc&*Rn$JW&J(VkP{* zg=L@J)WPr!v+g>1k~HTrXsD3Q@w)abSR9Xm?hB}@y=}eEU-I2srA?=B%yMi=TpW1y zj8~1~dzNaHq(k*hk>`M`bl!OHtB-k0c$7`Er8*|y5Y*O#EJwlw;d-$ZIV=SaY{~UX z+Mj*GIQKh2>#~TPN|^;UIxMA7$VSaH#R~d@hy6@xfa0b==J;v)M@B5Dp+Mk8AT`9q zQH;xk5T3HqA93W%&j81^i`7u2Cz-liA~qNW0!J1Y)n^yiPcQv&<>)!aKuIs}bBvA} zA>sK%$*POrX1tTN6H?KhjeOLP8rEpc6cZ)rHR7x$6C1Eu4 z*BT7S7%Yz%r=MpcK^0Zf0*X|VQL=C2d6=2ym&Ba-{|rs&r-ai>T)%bsL-Bdl(Cs2A zCPsdB_0RU!O?Iy7D5rOBHX0f$MR~bbMO|Hsm9zwhqQ(~=){=n~YetpYGkd9yso`PE z_;}HYL46s=nQzh59|?hE?61|j^%OD^e*je_=liG+-b7vnm{E8yFNkNY`YiGWRckiqTvd)w&$HjHXtM33YgdJWer zi{fy7-L175mkd5XHU-(!P7++k%e#(q=6?fq+pAYJk{!MoWuBf? zzK5wtGENHIWRZ)023)NPWWTTnDk>61VjsZ6j536a0xBr7eZhcp20nd)7K3u#A?3;Ah{FLHHL$S$(LDk-w7m8hf9dl>mbpc+^ODpWLn}Ll&o)#Xj z!RacgF%D`1?}@SOjT6naUxD;N?*$;*2qnA2uToNs*w}~jx$<&eiSZpiX{?4cIk$T=Qp{Ko)Mh6IjpQNOUP$u<&P?T9ElT@+D?bn|6D(CS^ z>EfTAXqWIQdZ0-=Ve^qJ_9aNVekUJ)@obCwl7mn(j-+tJ`X2poZfWy#5;a&g@rdcF zFP7ad-8*j{zs;8QG(O`VDa?I*=qqs}BqBncgU54^(3aW$yzFpNxAJQU1k`FTKn8{oovVdASwa!=M+rSod^`6qReN4?r2ov2#N( zoZZut`TMoDN>r38UP<81X%!$qsTMkPc65}Lf&LX4Nw}GwFVMtc+4W`Bxj3Aroq=9IXL%v6q9Y;?48QS*-PFE6z(3bMdQT{ewz#{ zMu49C8(FeGQx;QqvSv`0#{NPTpHbz3~)vK_Ecvic#l2i%lXueX_tXX2c28|m>fC535 zPVZwy6}a2YcE+@$=;RaUGq)yUP_aD(|FOQ5)`MDdB=#YpkqlJz$nT7+g^)e<* zoT|rJPshi~4$r58f-o5#FGuQfny{aSY#_h;X*DzZC8?)#xzmhZ<_QCx870~x&jyf* zHxn`RAG0uCF7v*g;S{`iJWH^bh+3&gT!> z*gre(4qN3q)z}PCCi}vg$4l<_d}KglsWo&SnGhIAdCd0g*DRat#9U)O_mtiK({Rj= zQ*J9O(G6FsJ-5$Ym!Ib+USk&c?|NE0);yVGC^Vo#v*3Kt)1&o^Tae>@;d4Gld)#+8 zj{UiPDMSe`HC*LfvEJSH7u*()&<0AM@PeXpcA_myE#j1TC%86L-6{k_j6`?x5uwC& z`u2Sn$SUuX-*mQt2E?PRju>K;;#DG~fHjE`j1==&7U>>ly`1+-FVGTc*P^({jG7M| z#tpxkDXz4NOG?^2hy%g{pGq^rsP4!cCTdW{+rfNM)vJhdFTx^NovHepn4xG=u0wfc zwYSbhHomxg_wxw$V*FND~?HDU+!n15&-aSbMx_l;mE z$?(0p$Kiw2$fzA4vks}VIsPF#y^Cy`gAf_ErkWSUSzy9tTtHX+DOr*}Ah^(OTY~NL_ahFb zTR5fke%>wkCavArB=k&u4h}Vnh&uS#uxV)+Hd~OOM}w(V0PB&-h2aq4vdU^9^#wG> zIlbFXnT-%}s5>g>X=4AD;h*_B@)VJLcoX_VUsji<(*j6P@qSl0E9pasY6gfHTHcODtg~~~@-IH+1oW%mF`!BN3b;&P;LiY$CbgF5&|Pi2 zGShU!Kz#hppbLEb6-*yqE0T`(_WfyX}t-<>?d^~ z{^zS)KKquj^QWE3DL}-B{$3`)u1w37033MhrW^!9S!aK9<(A8Q{!Hz1q`O--_g<_w zfq2mDtMQ3{wi7Xf0DX2=O^ug++MlD<(;8b__hZFwtp-tqtk9YFWij-mDygF*1ByoS zS;668QSx%b^2XP9N$krvKJiBftkB|T`OhZV5=ZH{g`CV0!`En+sl}dWRnrr{ZCuGn z>{D4TUI_)r$#IWXLsM23qt5SD zJfL8sYEcY^4p`QPXU zGn=$m(j13DluKGd$rfqwL$#sICciMEE*oqNc6B>^MwfO?~@;b zh;iCAvg^@nf-giQZia~Ipdy_5%g+VgCr0|Opw{wdL>xb>k}b8{BHxQJNWWtlorr47 z{l0!$KheX58T+W+QY)$Kjn|X29|K(v(=AQczh4)fa^94GAZE*j!+$TzNlK!GqY>^q zU~tvnoU%Q8))=Eb6uVqhSKYi=l9H13)tV(b)L_jjCq%L+Fs9$r1Asl(FrQt81tZlpvoXf6;!IXRVxpMGx5-J-OYHB*(f=0 zfr$%0AtQ{{>b22Fx(uAATM&JSfeM7Br9XBk;rmjYquhzCPNz?o=igvLd45-Gv1zme-`=01X|C z)H*}>oe6WFi9SjQi%xt?O;~9yN47z$R1X9!Rycbh3`_ zVlW`IXq(i7NIobS@wuREimJ-7{4B)th&>awxZY+5vPu#XB@~9w)wIkBr`-P>&n6i| z9-A?4klpS9QOb+eCm>o(;ovN-W@~E1nDaEBegWYm|I?=>v0e=r113`m?1xg{=ic{8 zb&qIPWN=CDdo9AaDLbuI?4YYs)-_?XRQ2mU3a-|o<7ozGY(Romafpq zO`8+=74(G804!_uwdWk+u74<93#U1Egz zn;31pa(l2ePL2$M{qLp>Btqd}FuLWq|0R{U1$|R-=+lx*+=?ny;Q+M{9nYKlAao3{ zj7_+A<-wY`ZJ*w)V3T*nuSc^4c$n{<@`ZgcL`w!A&JX2@4!@;YTD9! zSAEwsNLn*Yv~yKbdODgQ)N?>NQ#G!N)q56B%e?zX|rZ!V6K0V-$4@|LUVqg01*UIQdwr>k*dvehW z1vX*^8AwP-+_57+0tdrSLQ)D!TV(PkPGVv{l1N{r%VnsWu}>*TFKXToeL4yQaEV|s zpxH42V?xdSL_|7{ne+k3wj#0w&=^DKRgYwbhKFfb`E`);{nZiE_a8q7*|5B6Kb1>f z5$q=h4ma*u(dJURcL7{);%tDM2jo}N>=r~1bt_D8l9mIX=nYm~U+;S>Bb%IXU%d^r z+qAUdSW&nseBgRk1bg{UenJrXtHM;uBOjcNs%SZ#Kg7X`CQ(=att!OTU*&4nfjFf@ z!#=G7Gv8dNg&Lz2>wtM}NBJ4Fu3Kg2)!9Y|ff3e0m$)8LE!U`1ZeYY%quGf6IySaj zSYy+2kie;cKEfB-dBOKIBQE{U<@Z2NAkRdrlURC9tM+;$H=;rMYb~n$3 zD#e+iqN59-0^O)4FDbxFd}mn;$mtw7?n8xM;H!vzra)=mtQsJ4Vg?0DYf*2svSHV% z?~+ve5m1B0$B_{k`EPqDo^M+YiHmo>b5Bq6=|9x`n(S!pU0fUw)S(QlV6ed8U_qRP z!f*X{yVKmdGoT`i^&x@cNNsgx!|I|BfM%uygHL`Zg7lxHk28JpdPpX@zVh~~EkjrP zpjjokpa~`PMRt)wCCr|P?M#0M9Douz3i$WS_4|lo{1P@T^(DvAt!b}Lrzd(!Jj+)I zb_JTZ&siDhf}~NnS;3kmm&uomW8}y&qEk|GbfH4XUaqK&MV-rZ_tQGG2X{7)oJai9 zor$dpCVnOcIqr|I({s?ZJXh_L$zll$M3B;%55VmXp5nm_j63B(74@*TaY@QV+9-zi z2fKo&=hYAY`xGS$`wzH80GBuWJB}R&P^L4A0Mc1dG~T5Dg^9gaZs^bTl`2oThx8sT zy;q?AQf>{1B~BTm-ZJ@|SkN*6r005r1>(bYM~C!F>}sNS5xofQywp^?FTY`VR0QXE z*Igy7x-e>bd?}|_^PTxg`4i!fyMFjhfL&7CJYVr{%4eT zo*Q_te_Wnag;(%SH@j|(rsXdM2^)@eqY~q8TWVyEObCgJ*j|5Ah~nnPP93f4$e@=d z%78oPZQv!X&2_p|1?8>F{yo`ri{a0Sd>BUhlLTZMgGxqO@9rVx5kBQ>9Zol#2W>_s zCQn7ZW~qHP{Mpe1+FL<2#G66S{_>tkaMZwzVAncNYuuEF&upTiIpPo)l`j|J#^dRwdOBnoY^sRC@ zuw)0r3nk6LswB2RFzYYfL?@ z1SzrSftX-V`FaX1rfViJk>mJIWFq;d?X7Sr)^7{f&!^mARF1NlAf zxe?ZKp0Y2*L5H|ej`W>`_pZ8-30umMzjaajSdnqan40EFB6-h8iDEtb&;H+1jxz=5 zDSlKeY;3UqcW3L~T83DOl44`XktnB+0if5qP()T1ojE~vi(qg2tNf#!?*dNG>G+FB zq&^cxTYz9toWeiCqE{jv0k8|l7n<&*Ih%W&d_KW#BBU2ENuHk+q2^xQ{YJach>`=N(4CiI0M2N^BL(~F@CBVM{K%O>-t z=94QLo*&*iF^vJlbs!on@DGm}w3jc+DC>gc!Fgo|Pnr9}(E|>d`5h76DZ{@_6~pm~ zV`E}z^C%jhWOrQ6C^vt(2qXONd3y}d&y41e^31Ff__*M6rP{qA0iBY)+12pQ5R$3E zNXK!zeq{}6e9Kz9WoZr^tci$3=pqu{87&_0XpPu|^{3ZsJ9---e@SxO< zZ|L<3M(o5@oN0w5*3uCFWF9Xl<_+WkB@S6Lc%+#*dXzp4oiVN+U_nF z>FdD2^DO8Icj@JFWYsqR`9XTmRq0WcNSm)5+{mvwj;Cy_ddK=|BOmMoQlcPJGyzC~*J~@{ zEz0L0eJdAqsS&}8HXzP^t*Gc!>!XyRa`f|21w6-7wwZ3Ks?s$5v>#Ke=OqVat|6qXe) z0`8pGS2vQH2}3Y#P6vj%^{U}FA7a;KKK*?A9x{`VWKMq6Y-StWBeVA|^_!JdAWHE{ zq@U`8$0t>1XU@64yz`z8D+&ClhU?3NRUDZxARS_Jh0vCg3Ou$0?jq*n%YY5%RU!Jl6H~*i6lc+4(u* z%=@Np+-UiLJv`bk0=H~r^2G5CiLUCegO-oww1|_c7Y@~fX5=qKdJ)r<-{c=B2oe99 zovf?RKQG^vM>QUb&El#ab;Vxm8py?b*vl5`F#LU7k-@bNVO*xJYe*sLzGavW=P}(P zKU4!|$kCXFl7>>@M_$KJup#0*v!r(gL@h2th=WuqzBBtY2IS>2m6J}&;`#z&Gif+b z;0i_xJ(VR53}78i2nTT;vpXTY^cr&}QUP#Hw~*?YIBZk%06jC<=fXWMFyl(v?tb8xN&{ zgkBnTClw8i;WgqEz|$N^0Thh}-vKcVtRA{xFu>WyG!{FZg+s~EdJpNx=I6bEJJb`1 zrz$zezfY{4nt@wgEn&eo9C6VmdSk{5wcaZ?UZS`5xV>%}R3VKHD|qfXY=h9&G0Aa# z?LY4=YJv3L#HngB>(4MfDQyMV_MBqrwDIOCQ$@Ref}rD}>6ko+teeI*5me)FM5aXcm^eQrzms9pua z6Z5g5$sfC zpm5o*zf9aWYd)HGyM?=|gYFoU*O`@lTim(pOLv_6&ohRJUw>3wnEA7s!1v-=UrM9! zG|~CR(Xo-H-<6-&?uGhnY3dW+$k`~8=!?x5Z{3LF0T1k1$4 z$42(sK>V%eUpnHUAW=BK_=;_Nl-Y$y4q_!e7Vq+3N;I_hPmP?9_(oAr7BJAa(OQz$ zc;x@{h)PNQ z&Ef1fGSunVr^d9OYGy8rS^8Vnetsn*BTJtH+OY)cY|%Q8C@CY=gCh<0&j3jlSJQd_ zcer*ifk6h)N6mOot)&Y*T4et^uTXcPF=IV@#`of{^U8(y%ZBB7^eKqozse47F834S;{KPUF;&mj(N4<;dm}K# z4SVS6@i8%DX=n{Ns2{P^WM?mL=5h~N@0+Gh$pM#!0in#1AzaTty4N??7>u8lUSod# z^uu?fmLCUaS6Mh4$EXNFiq6b+xUx~_8ZAu+s~VdGQwEi(-uT*Qb`>U4^o)|tZM8&{ z0$k?{z6UQK%6rq~D<$Od9-K~ql9B|Qs6D+QiPP>^d!x{a*6>V&*`K|T&5@o?o&5R? zYhT#+sxMak4dMG+N8i#?(t3?rvjVyoy3Yq)wJhah625(R(IA+En_Wu)qqtMliLB@M zu0EPNi#vOVUva<@i4`HSV5q8~I==&dm@F~~Jpvsp5W~sTUX7JFOLbxy5}T-LK~R87 zq>C#m7a`L#tPK!$Uf0h3&V#ujAT5w_k>tJ!cHOhE16~u4h#TO} zo5S?-C)_?Us~NBp%Yx^Kjljzrj#*cJ`uI(w8qAGYAD z?JB;)rA0(6OCW!CR^)}R1=m8EHT(bgRq~X-q^$8Qvi40-W@aR-usiE~nJ*6;hiiY; z0mJGgz#zK-xM!5IJCj#o5n4VhP5D_aW{1kvhq3Pb^z}oT zMx%TtAn~9r5v)c!DQZaXOXoY+V}I3BxC!#Jny;r-0Qdi+I0+9y8dHXjj!vF3JToIt z+j{p>A)JJnIGCky^bjl>ni~!I&-dlVMQv@_2n(!SYv4gy^#IF~QfGNvpP9)`Eq=rV z;yT^J@-j+7-zL6o^EHo`0u2=e!ih&h@`+Lc2)1sMhl8Hq;(h)0jq-o%5+*SJ3h;~1 zBu9Zj1J!s??LdNnVjdqK{8X3&7JYG-9~=gPlaUdD_*^9x*ls5Vo_6fJz z%2n|nUTbV2R;~yu1ue0}iYfD9(es>ZvUYKGMzsofCnEVZUTc;mZXJOXLe}TBs>#hG zwl(I!GpP}+?X(SF9RF%#Qy+?>JpQBA{{u8bHIB$Q6O<_)QI2`K$9-dL1a0gl;Ol9f zlv@%43jThdT1_I6?{3Z`o0p%9F>O~Q zrA)zix4H%>X+a7rfP1fqWPIXPhQD7*Pv0d#Z?DA{{pszCWmKeD0Art)CG!z@NePdr z{B3&SHaKHKYGXyQf=;>3sjg3e7M9XTpr+z8O3 zLEjj-zQP^WaSJlN4u0GRbs)%?uRt0Iv|1|JIR0IipU}5dZAhQ;#5SP2goo?^WWr`$ zoh8K0ctsV|CkdcGbel#+Ls|$Q|AW}Zup%26vRiwQ)WXJIYH_@FGa$;FANRszk6(F~ z`ySm^I$=KG_Q>UanmJ3qNjI{MX^WY+aP3prBc0`@F@*jUDuOj>Tqc)X44-5h`J8go z$l)jlCh#1sWIEEWr1#v5eH}n4JU)S{9s9nc^*b#&doi1)o-|W(0Bc+W?Vsemp+tS+ zpd=n^ZAC?#BVr)5<^&W$W##jpxFJq9fjq#{ZE#uzK*E_R0|ME~qnDlyO{7M#XgNfaA$X)@YB~=qy21_* zSINHt2z~F}%?q}z1$ZTzRjs1s5k+wD7a4P!W*xftt8G|_XQfxFbVK%9V>xgi>ElG(e*H1Q_pQV zoHs3B{MHZkY^xBa*Wiq^^$`rmybK9fKS=p@{jV`~@9^}`Kwg0bznACr?u-X0n+`7b z@w=*SXKeBN$NzMa;oQf~`jT*oxQNE0TU&3t);?>+o|*TiL?@=1`nYp(G7{d_2F?Ik zQd+5lhYteOt3m8nXKSil-qQ_RU1$rgWvdm$+Xt<1qVicV$_`OfW@N@l;xPW5%-xj0 zww&|O^ZIl#)l1-fV+hXHeAR4;bbGzj7CbbU)h%1j{O)Z<`_IcAS+u<>(6S8`N@3!^ zH?{G(n(e8RFrsRG;y%Sg5vvP45gf;)Q1i!LB3@iX#0)%i8VWS+hf>>5LKx{fuVW|U zMjdT_^XGA5eDGg7OFRC-C@)es@^Rg9b2FtfWn;n2FmXssnsiGeb8uZ{Y;Z28!FBII zqstyqvMk8Lc-|ZFrt2tdwfib|C{W;v?QE}w{?{??!uhfy%zaIkE4g~wF}Em4I4iJ^5%AXZ{(4^(VW z0ogfp#~k?C9pKtEFK|zPj^$!VUlybCNdJBauJ+}as>1bs1d13w6Xwt# zzAsFQuhh-nE546gDn2PHveAgVK`;>#14ofqn6T&hM*|AL-9_psC@i!zpcqOwejf!> zef#!!fc%2%$IyV0J-L7*6Cp2n>84_ zk~O(nyaeBdR-Fu6O$Uu9LguuF2Eo|ipM4WRQLc9-#OC=!WrsVmOvDD(xylLn-t)C{ zUO^#<|J>o+kfPs|<;~UhI*M5OYAj4DxC{*mDQ#iJvXr8GB2>)W+?=5c6kNu}###_S zVFu--_oK3__h`tNYS)1 ztrdU2boZAJaDK0@t_Jv1(Al>JvK=NSCN?%Ufcy)dGhmSd(@DT7B_JRGLr&m7Woc#g z;NPG9fBruQjdZa+fmc~?@>Pm_N=ixsg=QPwIF0VqB7Aa$71tr6-rEPob+HZ=j3#Zr z&>O$Gy46`;Y%fE+4}U!o4i{!)(0lL|_zO`bDVQAnf0%mfuqwA`eOo~~r3EBJ8fg%a z2I=k&=|)1S1&DO2ba$t;APWHj>1NR>-3^QSCZ2uH@4K%3-$wR!&GpWAjAuOKe#VA} zal;9R=jYRVI{yAO&l=9ztF5W2X>IibZyNBB+uPf}dj}HOZGjly6-5TpizrD+(NiD( z{#06c*Gm_aKGz#gep|N|?i4p$VpG%p5W?%~h9K)v>9JQ6uS~hX5B`B2kL&1OZMIxY zrfD-V{p@raZ`ISM{CVwo7h6(>*;#UV!n1PZVQg$HkUl6l0CL2q7(iIjM+*yjk!ySR zlxPa9UkN0(&%^OTeCQ}5Ld0{y!?QKGHFrOF({oi7`|CU0>@x~VO<}=L%aGQ$r@JZ5 z7tYttaV^0c07)SVO(?7v^1d6JZC)prp=){guLC*2>*9tUju^b6ae74xdMfbd>@lCt zdq_NCC@muKJT`Y15V_@kq%RIVH$LBQZ+_2=fp}Tdk;W&8YiTKvEzmz_L)X#Y?~$`M z&&kCFv)E_9rN5?U@sk$_Pct_MgEEH21I+Gf_4OQg2e$&hX9I3d3m@xp6#fmhVV(jGS-e@!jeD6Hgi9dsB8%v!S1v zS&>Z9N3Q>@UM(qxoveaBf5U!l8a8WmpSKZ9iR}05g8^Afu(8kh?Z{^=97pD<1fs8W zn9bTNb_6Ck9_4#=x(&$0>z&&X;4^yXGhnDAO7gAjb+_Z7SMHSdPvt+sp{UtkKxxDf zO#QkFM5HYL2n-AaFu~&DV!%pVLQCU?1X#C^pdvkEKETy8W@P# z4YLmWY&?N2U6q+RS6cO`3w8<^on)$9->1HO``GsF_x~WGtdoDkZV(WI2Ixe+td9d# zX7-L|J(e79W^bT~&N!ZmvpBkYBI$tkYv5p&z7QlA4xeIZA&q_^ATP9#*x+ z=RLCsyb4q15y>wlY*IsGrtX5R2N#vP#^W!$%)ePoZd51NXZb58IX*pI?14?42ljkT zbwovfO-+$Rt3`^97ek>&0h&q9=!|RY>pAK12oIQKr-nL=ASOmCF(1WaasG6rPG%XD zckPL17_=8cauu5FP$_xB8}#Z~SYg3}yBPOb*X3m?%mG*d;LvPHtncJoKWxXT|Z;55 z!OWiMfy5KoZ-w!=xj?1BqL{T+yTItrO@@>6M~&gjr^`ELusWwZx4toPJV{B9g-ZX1 zXDMK)V*04-*Tcm1$Ut2^_DL!GG6Cn&#RbT$*3|glkAjepkQRIt=i+arq~4k5aW-73 zf75Sptn`! zU#XI)sH^9CAl1-;palpNy+(=paU5~15aFR9U|xRE|EU5zk9faf=4=G(LrkQh)mT_q zrZ05d+_(kGsF=fGQ+wxMzTg^s2C75zhdnh*7d~<#)`zF#hgRDqX)^guNkr7`>}4Z7 zII^>p&!Ma?#Dk}KcfPO(8SG* z&;0UB*;!U*>a1`%qX=uifFdgxEv_vl1)ubZl1YW zSyUWslYK;D8}w0X9)xp$9Tq=36dM($t@FtS zDon05z$=7$UR_;LALdyT5E1D$svIxon(M!HaBzqS(bLyI8cYbQeCi_a_nb2GY_|Qg zF(A{1N+p9-4=DOO9|v9F>39FsbHt<2^zjFW(~Z!-Pa8xF;p9t=2yggKUmY91X_G{j zg2K)+_8G(?{@#^cyDtYD1~udA;=Af(HXB{9IH5r6&{7Z4SM9$25;fYB5}Z6u8qOMt z9I?xV&AB#AMpu5_M-JL*GUzn8kG^}qDSbw8$um=izWCzB=s@{wmFZ`1m0!<6!W1dE zL@8+T4wtY-$T?ouPN;GN@j8Sr;6Tf?o$;mrL&Q`#8Ro4dXNL!XUhdV~KSWHSk(Trr z6#+wTNjC+*%abkc_pgD~DIB?4dXgdT?SblXrTBeVy9XaNZ5I%2Jbeay%x^DAUjYUy zNLE>+d-X~&>GMBKABk~ncefB_Db5eJ7=sT__yZqX-v)*3Z+{}uB-$lrv2MfVysSQu zcW7L;o>t{x3!GTk_t5v2F;d9*_g5D+QEh$-GLsQDMSi5AkWsiD)SVmbxLQkD?_HAC zm06ECatIK(5V{U`r+f`1gua!m1A`&(^;U#S$#%&(lA>c6abq0Gv_oJ8PRre>gocDh^0jKM_deb zhPT66@*a)=qxiN)%uO~xT-G^;Gh1bJ!GN=`Id*RWQh(tlQV&JX*grfJ_I&b-lLZ*g#Ot$ zh&V5-a-`IuvZUGHzxWcTB(l;ivoykKqjYeUvskw5`v;#WH$yaIJMXB{q`uy&_?enr zhAC>Fh|o=-QqQa_BUAQtcXu(xREF#TZ@ ze9g(3(~sPtK+6#K^i$#GFQDQqBo2S(vj)iR2NszyWzdvIDBN>y0uKYok9g3JaKzq7 zxD!VwQd%kA*!y~ipU+XWmSa>bpVx6XALe z8jK3G_|-`%@y$jI>9-G-+|M>EIAw=>n`=63|LxVH!BrMM#Q?+%(B!+}dSXj8EW*Rp|*EkmGKc~Bgho=~bE5K1!UM3l? z-$bML^gsr8M68n;gR?m1oXVy35rWO)x!MFkC0;r@9>LXOt|O%d9{So%wP%e zZe)(qF#RK8A!iJNm3QkMgy1$UmYx0=v*=Vu=|tryp;$olAfu3h?@;+IAAH}qzvm3`7Ij_<#K8`{J=R?7`HPo9T3~37U4|fr#Jk%)S zSUNah^CLKJ{=!1`K!cSPFREog1@2GybJDFohnuh$AP`qnlSmyQIJIbRwqe#zav9F? zR7FrDAfDDV=jB{(o^ssd{n`gCez2v0DV%hil22h6;^ufiGUi&AMJ1CtaY}!(uFKhy zG1ONx4V#~?3DR7W+49?PE(}Z;t?KxM?WofBGP0d8VRp8|Oy82uNAh+fWb*ujsw!Uv zI*JKI5dl!eXmWLHWefveGBVmoc7O%fT3Zmqbcm?Qb@M53`^|c22iSfUjeM)1&>woD z5?{+J@ZaJ^?CiK?e(4Gl#&4Y`!9gRIWUPjGL`nCf@^UrH2hbB7?E2zLvG;b*D7q3S z8#?KgE<*xQ=byZlzIe_bfOux#5kpZ&$tSv4?#^rQGc>oW#q`h0HS%55ap3h2-JvkF z0-j>RYGQcxk2b7;lP6cQI!L5xOhVY(vq|)Gf@U>WxYoADAAQOloLe`9znhkQrA!7r znozE&^lkF(B!<5ll?P+D@7Ph4v+(gL4~dO5bM%U!Kq46h*>7x9ocxh|tJJ|2=XA1K zu0Z!6I>b!l`6gxv?|yse@;DF*5!!we@5Hb7pF_*l;76~ZR!~eFg;AUf8-U`%9kTLy zeGslEeazs^#>K5Z)lsmOx*77-$h`vb2@9!0BadIHvp>w%s6)1^WjQ5|9bMXg*ya*p z5qxaa)YNncE~tSPhb3Vk$bfh$H{?sfqgA-3=_=blWuQspT6O)PMp2O zf2;e$CEvvZ1az=d;nATNYDPaNA;A?0jfmiS>g+CCRsB*SZq7R{FpTq8IuYLIFclS* zB><3UE!>cWH+y-?S5^pqN^GN*UwV427Pn`9c8;O15v0-)3|zJp3q~ z63v0})2E7u$y@?}A9JRFX;Ih+SfY)NMB1-?#|`=>RtIO$zH^ZN`Hf##`RSj*jhF7f zF9SX)rE*=#4+)8PEMVLy#W8%u6jPd}T*pZsDa#P&}~4UNckviF_wF^x!MHZBOsvMqeXnp@fO=6ar^ ze6o(;ZeG_|VwmR1+>xwmBfsAW2=8F|$+}#k(ng$7^z@9UTRJ=T*;6je%+){an4eKJ z=*06UMh!s_Ew}R@iHm#d{QUf6RFK9CR(@JB_^U@i9}#s`s}XDi{D|QBpMH4$bL{6D zN7@3}52uthKw?nX7mz$?KQcR8T5`_N*87cJ)#X4HkFNL8#~I*pS?dS*1hLUn{Vh9& zrOnXzAY3*a5OKX}7kb>TG#+tta{fVL({7Q68z8S@Yv&m3xBp!Ene7|Y%oG8~gE<}v ziM2ZR=QrWHrpeiYDiOA>|4@DQFWgU|R2+Psq1v+&! zD)jR4s=jr@A#8J;zmpgpzF1kR8~2r!*U8_M=r$;Anhb*deEdFvOo-N0PFCp-$1u!@ z#qX=|veXZbWuH(h%X?&P%=&O82o{==mQoOVRY4%#&O9~cU=yw=7T4|U!b(d!(b1=) zQ{1@MJQdL3*CNrnqm++PbvL9oqTZL%bLCpf?Td>PxtFFrX>)4lpmI~2#S^y9GtP52 zi-}(GIq}qqXU(ac-)@?Sok4`j4L$F|iU<)F+3~cvWU#{2)ZWbHYf4gjj%m1DvJ{}P zK)DVHZ63hl;E)H@AWb+p<>FBlz+yDrj#qIM8F*0RdG!HfGKp`-yM3n=8;`cdlHO!d~*mda$@xd*~4|0m4y z?UJ&M(y~bmt8+F$rv|m4#?!F<+{$v`KQrjx&fx51h3r)d2vnVb{gNXm5GRcwD0JW4 z01Jhu+<)i+E{_l++uwvUZ8<2f0p;=8H?XNg+FM)il7Gpp*4hG5jD#2aJ6g?Qh>d|6BEZ(N{i3ynF~`z`lr$JwkTo zBfWg`M6w|7??<;Xk9)|B%jR+iRh({>+(ouTFbrnh!~f#bl_wmn5P>6t4$<`Uli-;w z=gzExx0i3JT$y>Ph+L+s%PeNxYG2zf4(C=z)kae>?}XI&O{LGIlVwE2QdSBp4Sm*b zO}n7I`(Egwd^_&t79t)6o2eY(MUlrr#}Gx~AM=pXJU#|2Jri#ef?*3fZ)K@Y1r5DG z^An?6?~)_SKy%bmQIDLEvVJ2Q6$lo-d-FA~(8O9opR&2oSG=^9gEgF6R4l3x(@~X$ z{f=N9O}jvTg8EIx9ZkcRI-#CDCj~)@5yvs&Pe(-$L|^`*MWG#%P5R8EiL@^CW=FTj za5JP}k{VT!FR~(f#!w?7jqcbQCe4TmigqrX*dWStT@@5{K5AbZEN7 zZn#ZUZmVl+76`w|!2ZpZp^X1eltMo4<9{y*QPJmEX`h+#fiI1rI1S`CM`EHXdktnM1T2cI6-uOB_AtBk+^d1JYLWPvGGNDU9Q#FoloeRp& zPKbsB4hzQGniC;m3y14^NPhlnJG=XqLaY7+4@9u@TMa!2JY3z%%ZKUl*Y6}06!jI+ zXHZ_ zQ?gDhCYSyQ2dzy>KD9~?OuIr)P^(q22@3+${wPeVsJc0>7~n0eGDvWRY+jkl{FPqU z|C%|uR+2k|PJ?mA$DGOSC*F}`BG+Pc-L$QtZ)yKDuzy$q9(lhq7txNe_I>SC5ce2V zz=0M^T_fkiXMvg~Vk74&&6p*XrgB@JCX&=Be|lXgi}}Q7CGPO+MPpFaxTPhG0_y4Z=fDsW}m^!@hE-AqOk^nZB!6z*~r?9aalP~3sY;c;+bMh!r0{* z{L1FSk>r6QGxebW zos7aN`SwtJMj}J8x8XoITDe!m=@-3~AxaOeB6y_%2O;uZ9`0{-2LxU08iwMq2$)wuK;p5>w`BGWglgV&( z!El97d#e<&DeTpPw!{n9^Y*z(x*J|}|FGZR8-8?x|70%7t5E5-qrRR)lZha1yt0zI zf0t5vR`r3&w=*!%u)STOq2()RH|b4Fdq6C@Gb>3~zZgme=z*i7bv0 zrL(diDd|F9PGfdxC^ZpIpvKd4=KQ`y zNMy&Z;x_;?N=r$Ms!b%@0?>xa-7O%tpos&g?Y1CzlLx5i=rq3V0J$wv+yGtb8evg( z|NS?})Da$c1~!GKSOEHRHOvWS8U!)K|63hvXh^n{1_mH-r2IN`UenBHpjR6U3{IiX z)X>}i>Dt{fHdX+w-%E9>ZBGlIIosKyE}Ca7`=+WcF)P7>uZ0#J*4C^!Gc@0#Kc(E0 z^R`x9nerCliyI_LN4J)WE`I7u5YaXn6M3+dfGKkXBdAp=MRBH6S~X*8a(FUTh?V0L zgIB_|Bxz-A+7X(q_6rKd(~=Bx8)qRfujf)Py+=-9T`*D&V~LC}hWLc|xDr_6f1=xo zD7k$^*)*~d%?n392IXrk!|}tYe&O z-?u1*(Yf8Dsy?AEHJr}O2DnD}^z`VA1aAq2wjp_^*MqwsH>Eq`rNtyf7c0E=!QLbZ z(qFT3qn4Q`GK3PyXnr8G-2~*ogge&^}!K^=6H?HXbQ< z$ebSFJjOXL#$lqiwk0lKRS4{&Mi&=jqAB{qR=ocQ=V9pra2~zgI>v7d^-3lnchxOI zv&T;C@*N%bAIrvT=ax)v;VHIn1kI$X8XA&FsDAOY`r3F}&T#LEE}8u}W_ZbR5naaO zu=?uRvv$r*>wZD|*s}Yk$%j(t16p zebQG!p{D6NJ?n&FB5y2lo?7)*QVmZi&(}m$hZdB-^~$A1xb;~Rs>GRsTVPj2G+oiQ zVHoTBDVf&me8)MQ-5T+lO|-=_i2CLu!k1h6;Cm}H*cEW%@2(9M4@znCzojS*-X>|>=030+_|^-GgLcEX3URv?1IG! zeWv*8RHs%ZwzX}%@>LV`N!96lq;a0)_Jw*a;TaWY7TU zy8-DfI)rU_u{i<$V``Ll+^M_{YDSRl;zA$>`4R_zco2WGA7CLoQ5b?0=Rns{X2!sK zIam-?oQsK#Z8;(iUNX;iC}>RqU}Edh8F^jP5U2i{I-913b&PFf*t1M%z10l&@+0sn z8h635u(BhA>E8C&|L(HIVT=gHC76U6gx%cSd>x^pQ}iT!?VzVkU`gf>*1ILw2O^lF za9NFhhEjU#7`rn5cdV8J-IUA=nyd8=@3=MXCX)aXXi^_lWA^Mm@mOIz5WiCBW3-&5 z*J<71Z%Lt6{+uoAz3U4MD|O(&cez_TXxR{klm5XP5*qX93U_d>Iavox!eN@gbhnou zH`%acfi8jNmDQTq>TZRUGL!Tcd59;y#;8qQlaK)Y>#+ZV4cTqb6x9Nwba}rKBTFt5 zuO6P^I|9hSd)}d`veRqd+v|3sqN9@95I-7nQ6pjj8BDo6`Qi9cTJk`!F+-}%XeBkQ z=Oxp0yqy#Iw$|9E?1>3vz@Lg&x%ESsZhO25Bg5A-o}&ILXxxQQ;WhTvIElZ6MM#kc zJ?3Meci0lApbkr`lq*lY;N~8e1Tq}%6Ac74O*nq8*i&F&1Au|!X7*YM8owV{ugEMc zEmOKMGBTP9(&O*u#J+wWX*_|OYJP_cLj zoXBQeU}`Vd2kwz5+-OP>R`AuVc=Df)Rx5m4yJGli^k!K2epB^C9!tMrrH}BS)#=Vf z%deH{m;Ef{9_o@&HeKVeZI@bULcxKIV`kmSdF}k`{D@A|}eZk+|YVD+cs8c7cjK8>6?6FEV zH9bqnhrq_?+0-;ICH%w`&?R556)h)sv~w~{$Tf?`C4x0k9lKIAPg`qM!MxLKz5-{G zD?{tHw@QhR+P^qc6t@*~kKiJvy`(c0@lnh}W4ac}IN{*L2*M741QZ4-x=yb1_r!ue zHM`+y-ll0(paq-@UOYmwOl%srmhcGL{k&4Rq8~@jJ~m*mYYBK_*KUoST3HP!gH4mb zE-L;q@b0}-Y$Gi>4*kOQB)gw>Nu`ldVYRgz_RfB z5hbkpKyV%$RJw6602_zkk_46uV9kt)!SNOIk9!JOBcY-G|5zgg8`_3?fMUOIX<@nt zvR`dS{f!fCKC&7#va_>;Mc1navF@+Dz(kC~;_q5=%J&LPIb%wp34{cB?vTNRcr^Xr z*ViJ+DJ3&1{-Z{aJ@8ggz9l1TT3pk87@bnHD=S}4>v?$yh36{D%I2r1*Y~D> z3ht5ZXh06kAOoGEWizOzBROw-1t(S{3=XfdZS3PFxSPhdF6u{friaEn>|# zL9ad#?25|k^%07j`fK|;KLX3UBS~?WsHlYjb_!%c9*ryPgc&mJIUFXCD7-D=u-US~ zTKSibdQERQJ|lfjBGUX&@ZFCtzl*h zKY#m{&M@pew=xWLzR7)x$z){L@c!i1#hLKv-Fa{-?;(4eBe^tB#)DoTT%4V?xU7X& zw}R>Qn~U9PiIb_g*ayQdO`z{@u1#Ql{U5qO@K;%LIdsiR9|VNBL(hbO`awAu0#3E+H_POJquU~BH zgr@{l79OMp@;kRuoC>S_u#+RjqBxu#AF;+7{yOjRZqa)WL9H zAp7wrXWla&O*D<44ewDUWa{w~K0SZi%n->!;F3%Q!8-Xt1!+4E*kiB=}c>wA^> z(ErW@Ev#PNxDR7UeMY^*-mmAbw^5E#8D-(eZ`NA#5DVoZXaN&7dM?tLtWAua%OvW9 zg?w4^49$XKA^o-@9;YBbB1#p)nvr^z#!mI;I&ZBth#B04>gwudq*(1ayIygQ`6=eA zs$cJHzX6_J-2YTwS_yyGKA=FNa+r9-L!c_Qb8Wo=&B%!|Yr-qr#}^mGxneKo@s$Nl zU+jV{O*S^=N3W9@z=M1B=NVEp4siCAx{1ln{16x%g$b;z)>Ysfe-9k{o>kd-brtq- zs8@Z4q!f2W*`M5AY66e8B7)4&b84z0wX0{r`_f{by9NOHR=v?4gmL*HCS7IJMpf1S zw_-Np|5~X@q?lsq99liqRV!EiP>KOSM9N3;LvgO%u%3SIgJ*a9ZVT@q><=%Q`aAFJT_jgDarxmFkt$Y!jw^_( zHqu3|R`a@I((hP`p!Hrew%Ly-#K8*zVgsqg3TIz9_)%$D76ONhDHZtPAO>^ zA}xx>BE*0Ie6IzwIid>C-Y=f}uR!R;U0rLafQprZdZ_f<`pa|{h?!yi*U)8`v-I@s z0nTjJKc)&eOf}7L$xe*;7nNOFDH zv9kOfWwi2vL{VUe@cKhGj`tallSpg6Q_I_H;BIdVfgkkyO53$i>C5Y^=kilBzIxv{ ztQcqgs0$yL$j6dfOS#}uM<^6s&&}LtxMwg`ph_$aw`(Q`ZJ~_t z=H@1QlqES%`&U!57qv0IbWytue_2IY#S}#aqa?0GI8xf$#MY)Bk{rPJkQLLxLe|Lf z^*9WS-W3BuRJ`E177;6%!K>cyZ$9n^(lXkAO;2}tLG^PW3!iqG!UFYW41(+zruaz) zK6zvP z&)StlQ#u(`J8quVEL38&N=nIOtF=C@3x1^^D7-rXTc;E%S=1);Jw=suDXW~$1GAlc z3Qa;n#GeR(NG3FluZ&AQ6*rNKooW-$e(VIHL*O&Z#~s*PcE2y*J2x-*8tN1X{YdAn zNL8c%y8^&m?&4?4eKFU*m~RzYp;BUDnt54YJ6<_{abKePMnJ2*6%fD=qYf58AE$Ll zTA4|!YyShDEU_?s3nuX5#U;hvmnmfC;>LfI40Jt(M9x>CL;YxdPlJ&zOyl3|>wyl{ z!_!mj=zTbYKc^@ISzeksfcCdjSYOox`dsh7quF~9g3T1;R;e5ZBmslKZ?~Lr>kT9Thwx(# z#l>}xXX3816095Yumb%<%fXy`U2gFqrIh!ZqI=)=!9n*R;8Zr9q<>s^3I}iT|6q16 zW3_aPi?p3v<8D)1Z$^K*>Y3$MyFSz;>CaJcm|Eo)JU5~}H-Xz;0T;%4B87)BKR^5E=&r5JNLZM{$f$_bmNf*OYV=1mK)}2x;KRYe9P)HG0hj4?%TAgp8Uz8n>eE|qga)fnnkEB*e};rJ`AbC2 zDNo*MF>-X1dsVKSnVf1j`xHG%00`P7e#w--yE}PPe!guN*XYj|XVf{7AE=}|Bc&(p z((d}ixtJBTwtC}X%8L+s8u4@5Q~j*ovVV~jsl5L zVg9y~|3);3{6I|w3t10#gzSon{qL{t=aPcfj{vxsPQP`K zIZHsw{a9dyJgocQM;@M}*16WP(VV?Cuwtx4L^K!?(T9oNPH^Sz<>l?+(H;co@F+;% zp_Y6QEF6B&N%DyUocynEMvcy5)1Rps_C(;DG$2rVNbs`|h*$)3rx0CZSH=Gd&n}Ud zlB$(pOlrNr&(Eng{Y=hRWAI>;{lMVk-A_+t8H2P@JP!K+uj3 z$EIkgmcITQPNSDMnHnE$Uqkxucgw7Tkd~w(*&ZPypksfx%-9-(MQf3}8yHJq6FJ1P z^NaDNu57+L^RQSEgzTwIQ^ylqoM;q{$e!^?KOtz0*D2eu5>mFKd6yd|_hb17>ul%i z=Zg#*(?YHdNso$hS3^0bzfA??rqu;q2BJPpnBC)ZG`@3^4ND-k!NwBd-4R?w%}XwQ zR_uN%uN27AW4C;Zaa-bl=g+P6fb8_sQsg70D9d zD6R1hOY&oHTP34<1jDC{RY7)vCbr}jM>g4Mj@E6Yi0b}_m~SHJFI%v1aF`*$4vmJm zEC?z0?j=zk>Cz_$ia zt|LP72`s9lV;c1!K9$%zi)E|}eoqttN|*oGU;Xe1;`nzdf9N|hBDZZ%GTO*qKcS}M zQnx{)!SV)kPy$yBrlcx=a)`sy$xwXPtkXgoIU$(wo%eGAjRHnfWaV11l~(o3`|N;m zK#3;}uSslyFdhxGY7bW+=_zCP8BhGo+rKXhAJayE_+H~&_$BP*l!wV3GJEC_=NDJi z31(+{pyeNx7*%y8I*?99-r(;U<7sXjb$QF*vmD;hK7E>ZuEQCg#Z672ycu}L1G8K` zjq0^GNdFjLkj_KT%ghEuI)ZI7+p@I;=L-qT!f#kM21R*%+^#Z>sNkjLQ4iuFSjVgn z{e;^&4kP9G$(ZE5yu8pM=H})_%#9B=7uLw#|Gf;e5DJ>}D^*e9@*NOQg8WCe%04WuZ)hs z{SGalY~=CkeFs&&Mt1iK zbaZKVDN=s4Csj0DSlOa>7QPB6B^0jG?9xQH`ur`WHUfWwK2RYouQKQ=cqEoeOL6m2 zcs6LT0~$gu!gmQ5&mhu^I*L9~b|1t<*nql%R>(=~j2@n;Rw}DmO>`CNRVq*oU7yK& zQaFsp7{#h-Bwz%Yb9{UJeG;Z}Kth^%yfDa{es*z8j75#+7arrm?6anP(pSL2!6w-1|iLN41YhG8iYvQxsW;JkV~hlhF~0k>kAAq z%g7r&j^3H#oaTb0AlvaU&O4!A(Oex+SC6iO?1vx0*{04JP%RSD5_iY~6BC|Nx5FvV z@0cF)AiGx$LH-RqjEwC}9n;fgmBkzZ(890T`z z1_z0}s8OOS4{7g~0% zB1=XD0}xvlpCZ@Hu)FnCKnH9FIp$XeT?cD-YBG|su$tn$LI1!I(*@#+aEUxXm7a2% zYaCsisivF>9m?R;e>kt_r2^p9qeY@CGxNp8TPX;6W_eMZPH7az?rpoJf^zsat+G;; zd(BweveIpUHG|bF#S(_L@hOHvm`1P75%g0>)~rAl6db0EN1N8J9{P#Tg*Y_o*mHa| z0sF!ypA)nGP6dFyze9A)-9FC=c^lLO>Y-ozcS!2uWcEIr?kTBcoE!sPlj_mh70E zq8Fj>dU-Rd^%#<9@P2EZ>q=+nRy7RtFn~`fkApc`9HMrm(JQyl?RD5hdiip+7NCX%9Lsef zxpv7P>*@8`*`I=2+AQ%Oj+pc^x1P6re~bX1rp$#~#MpaW@bwt1-qPHf{xO;rr}VOI zUyA_k+gX<|%?|gH)_cE;^J-{87b;v&POcaA@!b&sP8a%w`C*9r_y{^g{+R%PaR%cI zVTj%)vWRQ6wTz-7p;FNQmGIfWR%YBUDyE^^!fw_s8gVbof~@Z@*jsZuZboNntd7=} zqR7_Sh@r>fRe=PMSH(r4A5@2@LA#-&6Pkd%ZP)p-8GH8cADQK*qA}eiB{c6W4%LQc zCkzY_MG;98jq%gyT0jUlw~t(=>y-l~9^^EY>aG4NX7Gg;H-D2CEWfOK2^!pLjnZPC2gLHo;nhahvsr zCOxV;iE|l~s`8h7?o;(_Xm)RD=u%F)ui%DRoCIMoctgJ``YR9V?JAC%x*AD~i4%Gl z)jDDxquTJ&*GK=wK57)bb@4fYX9&H0=%B|rqL7t4)2=a*1==eNo8wNL0B&iMN>Ff4 za&vDl{{NjZGB{(9DA=x9=+@wO@4M@{OK%JIE>9)s-M}7`*^4ZJ@+y3@ExY3bRXBYw zZtmgXp+8^gX|v0koGD*gNu^;)(eSo#>+C3J=i*|x)9LHy&u4NigF-Om1%2TuNSZrW zKLwL>o$J;fbZ!UFQ5XLrSe|UAwq`cgj-72}R^`>@r3%s>7%|a2`O_Bg2zE1?FP}i# zdf1L3PEYh3m@^X4{(l#6kr+JT?Y^LC`YEkS_1m1j zyA#@T$!lpERB8V0u}S41BG9k(q{K$=*e#_`9}HVgn@+bAf&O_^V#x-rv_CXSY}Rk` zJegwSk?Y%-_NLJH>>OKmI#j05SH!l*VZdaOyT{QZPH9{V$tDj{5KabTM_ub$J3fYX z(=SdaGy`5t6zx;ipB2YmgKEwI5+xJpCJ|&|%57BPqw9Hp`P$KO+dG}C=9M2=I+hP3 z1x-=mrC0}wI0C3&;D(Q1ngA9(sudzxk0gL&6V`8TZ*x8cE%jQAxE?X`mnd*YyZ!Bx z($&?ix(#%knVnVim;CypgD^2AycXFZf|nIhjW2a_ZG!Sp^Kq`{|Y ztS{+9({#H9%J71MU@z~85e;dnyY@7GFk7C5y`B!Ye$ximt7>??%PK$XG?-qx4flh? z%W5w!P6-68L!&1LJN!;hf5v5Il97{duB~y{;3*OA?WA&ea;{@pPJnt*p|Mu=kMTY~ z2ZtH2QA*t3{3~IdXV0!2z%tlWe&zBjh?oOB#DDmH zIK^Q~SWD@3`0G8yK~DlvNEY;#?LlJa{ptH}POol3A1+Rb>I#3q7!!~9Fs{^j^uwZ- zo4OuIF{Tkf(Q+f;oyf1Ge$odJU$$&Bgj&Qa_~M8lr8wIoQ*mI^>)PFWkG3{DWS3>` zN@&~ecg#q>bM|fSg7k+iyQ1Q7OAUwd6D`CRMAa27{_UV@;+G$@GfxyZ;$x|_mHEP( z{MoqavLBn;hnlO;ERCg8CJ(_=M$YPji?MpIyHT)S6wJ7~tB-%r>Mo60CCl+J5UsPD zi`cC(v1n(<+_7WUDof&EEh`jVe)^S3k$&8E<*kxZG}@QAV$d@Jg>5cK%!1~s@76;> z!^WnVKOMW+1Z38>GkL7bVNq`*HFZip1=!M}jpJXR%{9`vpE^HnivNFKD1gdiycGt7 znuUc0$BIfM53d)$`@V^vj%B`e6)LK{FQ`Ai=i$Bc^lr{i5P?lGpnf~6BM}iv8`jki zg_gdU96BgG&%BW|&Hndg(dm=8ERDuayQ(Q+vj1o`bay?d1TXQ0M6H+dLxpy9^eA@h zK%NcRcTsuy2$BI1ubAJ3dlBTQa&!fZiqF5t0;T^O==ebE{Gc-=?ZUl^v`fk-+ZS`n zZk7-=`yLFw80c`{GafeM#bxQ3VTBk~;`FcIuOirnyWT@y`MPbBz1WfI)YSgF*VJ%i zpDMr%WK-Nhd$@#iq?^9hwnzD_VM9btcp%c3*9FxMRoS)IU0zIw?QIHSJxUp8%$3 zU&2detgiZiE9dWdb`(HeR}ASJHf&N44SEs1DW^n8j-;ptS}yQzffn>j2E8!55#OWZ zLlv=alLp8LlpIKt@|w7^Gwj8@Te-ZM9I)+2Vr<%BXDQc+nr4B$eS9jH zM--)ng@qlApHdK2AIZsq!MBkSMI_2NA?H&-B&Yf}G)=I7Y5HTnySE*aDl+fKk7qNA zAhoT;NJ>fy^rXur5;Y)47c3X0NO7^V`|E}5v#ZL;sv1%^HXR<4*w`k~8pz0~wGpoE z>_m*c8!b@IjJ|0F>5)mO+|bTTc*?GKoDW3tjsXD?k$R9Re2$7bn0vTS|f5T zKTXH{DbHbSmlWcrol7DaLfYL4pw$3v^ej=D#ouY{9k;UJQDA;o(51l?A{}Tbd;YsC z6jU_gv>t4sgk~Hctz{-$=C4k~gTNnLau_yJS#Vo`LV7wofzI@4dAX`r<;u-VUmtcd z#GEsmUX0ub5XVq}1z5EYkI^nH7T?s-BG7#4DPLp=m{H3ZBviI((YS^~k(bzu7iK$u5L2hE1#Xz2;yyn#?wNYGq0e_Jr&1>xvvmx$`t)b0svd$F3kck@FXNvZ);(PXKlA#f#0Cp6$sz?8pE z|2JI;u^f^FMB*#5I;WzU)pxOTLB3QsBPUd0Dv`uLB_>eNDFsZEI|xH;%t8y>Q9(gF zMp2NT^BxQ1V^C7T>fCYrNnj}gj#Hkyq-QAzr+60w9^UsT5G)N%&Ezhm2PP93w}XH* zpC9w`#xB|1Z84P%rx2Mw zRYU2(IQicd^6c`)H9n4r;Q6broU9u4373V1mWr%O%?iCBOLzm}K}+KN@KP2OnJAMl zyH!1}F6@9%qcqTe?U%ZbTEsBZjw>wY;IGPB77Bk(Wt*>S0+eWvGU~A8edLPUs?BZu zR+iA$lH6@YRp_6BT=r5R5Eq+$NZ;sWt zEH4u-4vp*aJyhsJl4^seVCS*C-mwE4x3rE?`rzMok&=^hMa$7CT+#dgf+)cZ)xbDnXy9#Hsw%){DX{4M8d<<*~563MH&er$2)P|;!b%0tcZFRFVhXK^_~(J6mGyJ{doLR!cZpGQHA{} zH99LN`Xp=|R6^Z$IVQ=!CT5|KX4%(Z4kDR`MyK`YB8fo&ke_U;W5Mn`m1dt;yyhg( zW#ttVz^irusQ;e?tC?umh}Zi^D(`NzaTqrN=~e0@TJS?*|h%fPE}f&a{Lml7j!whkv;2dhl#@ zU-_&NM(BM@gzbA@Sg&qIVuCXem2^2yi4h)s;5}jOrRP*W&THKJ37KVplcJuZQKaxo z$_H#uJAPaQk$lJ#XhDuMv9mUe63k?^sfkR+YUEVXr#!nK!=X|^B7di|=n67EWnKKu zGB*_|QVA>h%568$8?0ORt(i{O7?I?7x}e6(1=cS67H;+E2EvXG9h(c<^7io1Z|hwdn|-3BjT)NpKf~Bbe$; zu0^Mi8<5~>2ws7!fkYSeqm~6UXQB4tZjpFrX124v4b}$gZN>_~>+K&I>TszI5M)*t zaos>(1->&tA0*EZu%4SoI8goNO( z_7*g3Y*r?w0G2w?HRTP1pE68hHc$oiiuXF;Evxvgc0~bQ7Vu1ZdV7z9^Ou242`9~F zV8K)y0R~YK8~dBjlasCco0k_E8DL?r!w;b4PH<*t9497P^bLLjOGp#p4A-xru^OP> zi#qOKRae_hOyF$qd=(82Ycfzh>R4IXI6j^%%&+V2CJqh`Zu)gAH|S!ekRceC4*8z5 zqMeeWLUy|7`(eg!fB!DGzP`D}N<_#(FNN?nZlti1!}&HMB7&IBC^EC`&}?G4BgAx2 z=>Fz}p*1>m01S{;HlExZqFL!(UB&+Q0FxkpFqCq4pUn_rUht!Q=JMuXPKG1VoDrJQ;}i1 zUb8+``BRUxBj7qveR*UwBvfR=(2G`#Fo@sJ?!hbh$VD|P@vPu%pLzP?C@tn|zgy`J zk<_QHc2O$97Oj(+^=GM8lKr^RPw{a-bC-d!w-QfA)2PcDm|&kCXI(r_Kx{F=Zs?yv zuxLZFAQ;boi`3Q9>1~Rztk=#Y(b++GraNoJ&V<{EvWTt88DzGEiS!kzG0jyE}g0s3eEWA^OdNjOq?I`YbqgEYW={O&pL`>0ijj7o*3AYHEJ}1u+4$);ApdsXp!bpuuzZY;>%1QSwFCI1M~}LYyUx8z*bQZG zP8XCZfBgNLMZPsW<9L6yjiDtSFXTBLdo{!lxjD@ul7dSw{Mbq-2sk*CoMVQy;DJ9K zYjxqX*G=hn<48Fuc+&r3F+=mY3c45QltiH=@1yYySwAv zsQ3Nc&-;5n{6GEA2gEaT4m;Lbd+oK?x~`*8af8fXL9RV#maH_LLv8&c=M$b+3rTVT zAGTiu+#LA@D2mOnhLKq1Z2-r4+zD?-Sll!>;rVBAlHkd*H>V#v)D&*Vd3Klg#$OL% zYaa+HYs7_ix%MQKEs5%wZ|syfnji$K7t_P8!oJFYCl7xj+(ZD(5xCx#yB;(IQfdpD zIVWX1u^-0MBbD_gBwqKfFBOtf5`{849%tDGCYOC^$hrt8Q?b4Hxm)86{UB-8@j=NU zjSjrwi3a~3=S=Y)=gsSgHYw|t2OV{*wxS*undlauo`0B@Ks{NB4&5VKDUqfOWQ1aI zRkBQIUL>f&Tsd>X@Fe79Lanf@od}b1SB^|~ zv5kt)SFKBL+4DY)+IQ}eY{$(Pp?=JOWy2Z~NH_RGHWGyD=Y-X@!_o#zS$gyk$hp|!rOEZ zuTM6DIdCy`75iO)r>HC7Ct*7`0sabewksl+5GCK_WpwANAUsj4{ALtya{qRjJzz#dAW<CrdfI96oT<@?Y|}ecT-cI=pcHR%j`5pFe5t+ zn5&%xrdO?^I~QH*D^1Rq&zh|#I~PkwKV|*;klqhK(Dq={alZYL)InJbI&iFS~YLY}!Ne*>eJR$eROpPBqnR5D|sp0mw z_aGi)46Pr6^cy&YF)ET+%AH&43V#8*jehGiF8rUlxdoQ;lcM5O27WrJ;KhO?HRvljMK)$LH5rc|KYS-y{K);z8#ga{TuI?#yFN{GW-Lk;(&bF? zPKlE0*#m9c-c%WxvW0_1g3wpiJC;IpD+PQO& zXU!bM--Tf5?GbeE3C8=fcj{-Z3-a^F0h1J#Z+mEmFE}70zi;>ki-K>YkEM$>?3TQ) z%+cVCpve0b3p&?S0M2Rn2yW<@`pi|e=26G+zyOVlk! znR&9*AP_4iA|fKgyY!maz=bdfHX7&`&iWUm;cu&y)zx#FI5{{TVWp)BiDv-PR;?)j zX7a|qF~6D?7m(=%B#Ef=b8~~p@fE-eZ%TbBj0#Fb^VMKm!_v7G6+>MtGN6^9e&Lyp zf_Qo@z&c{JRU|-r;L*>LgDT}!pkiagRjRSl?bG@`2Y-s#y7T8xAz}2Prr^l9xV((V z%!3_KPb)fW?e`Xb{*7g)PFFmI*15gyoFZFol2KWS@d~D4)20(sLg}k)`d9TkfUeSxT zmAj=TOB&i48FxXpGMFAd`eBrk8n@{^2K;iYQE=Qe@PRS<^L*D}Yj#fHm!|-bMNNVL6`fvfzly(9zD*w57?RHXXP9u70 zPQl45H0CZk0lge3!R@C4TMlJ`6iAHChmRlG>d}#CWKN8 z90%ULV}%p%Uis6n&O=2bKkahguZ?;x!tSEW=Lnj8JX_B8KJy(O7S#Q= zfgof)J9=Tsf=>wR>FwPZM}Wg$iRd=OGlBC?IRQ|Qz6CZKl>80{yKR)yKp^{x)F9+MV^KoT{pmO#EPAx56&k3y#UzIm7~Gzf>6!dw1hpB7x=dCZqezA+v>TXB8&Pg z0R{@5tA>mg(`Egu8{<&f;*G0Xpib5LPP0`g^=NY(@k{jK7A0mKDaBf12OETbAKQ|~ zyL9GtjX@`Y*1N3Fp|FPUSC`w7QI}ed=ZF~A!itAN)d2nI3u=a7#-o=%#y@QqtNvVZQhzkyBK3wMR)+v1BLw z82!aJa4ND$x+Fov?V}wtj~y*kKVDl~+pHlRP5W?O=_Z#A58dJ|T9AlE59;w^n~VMl z8PZTb45lWR$|L*Oue4>uEFg~><9Mb4xh>gt${uAqHi3%kKMK&88*T%*s^t4;lRw5x zOlU94feJkvkQW&=s-s>k3eXsgHQiDjrE&@j50h^ckeMa2*k)6cd|+%Wk4Zm8-cF0$ zgI#(NSu?|!a6%_J#%&bRUe<_-F#JWQViG!NH8v zK=hx=s%yUpxv(j>jHqHe*y`_uJ7j0c?BZ+VK~`eE(X;j{0|6awMf8QBcbAa4_Q`e1 z9iby<;ana^G2-=Qp-+FLW0-aeLnx2kGo855aLQ)t?`45_lA92JK`sGy$|j&Fq(Jh$|~SeIE;`=wG^#5q3SA zput!CpPyt?#|pZ_|7ic`)H?^s56Byt-lxd(><_a5_;tqUkdTlmImZK817g<5Q{O6g zVU3*(om#sRtcFu=-n!g71k)#)8a7-{6sS)hZmf?lb*iYloQ%%fJcs6#$vj zl;KYdyad4en}Gv($W6c)#XZvDayFKTv%GrY8V_Yhv+Rz5Gq8jP*}Yrx}Gr zK!8T~9b|NwbHCkBVh%)>B@0=5fH9@$ZkJIS^w;V#ISgcFWB@SUpJ@dCpMzlh=UwcA zh(5OwB{R6L5FWW1b<`nYcehk7NKQJ_7S1ZgU{y$p*q=^JtYaG7X3`kA9yRLT_V}d# z-iet=v`yK{+uM6fQu`UV*_5bc&jzlCAI$lnUt(=_;v-5y01Q+lb?+Wft(#JzJDA|$*m&0={>}6&BUzqF|J2!Br)wI?X=xdMktPk4&@5UfV zzY_73=reIu2s_pJ68tF?2Ed^l0W7W%E?F_TceSb3yPUSjFX*BHxbRDb8M+!Y--Xz= zitiwG`AT<2bB6s#)Kj&zLYMX7!fYiC|NoJqpDxCpnOl_os zc~-f2-otEs`4kC7n0Eot`aP>h-4-I zZF5KM%n?Bx6_sdcx{lo$893nj`|VqVeJW$$N~r=h#*Vfr-u7XQ1E_v!GcXGAo`xYd37h&988q4S?&8aEDpZb>rf%Vd&f`r z)0z=G3S0nM>=pcC$ODADX!4iu?@7Gi+PY7Vu6aN;Pw)D$NUIX-dJxCl zmGM6|y_DQV&l#-6V|SG<%w6UMQ_4P#vMml&nn7&$Qqt0dy_>>? zX?oP@8aOC#a{4oju{tVUygla8Ru-S1a+pctI?e91V50Yug}G+hDufB^-^S2l#`xv-d;n%c5xcub6u`Hh)d zc%Y(Rp)v_;yxT*=R+0zPExbl*-6yU|ItXl4NoQ7O^=iNS%U^}KX;>x#~%`~@={Y9u3j?U=a|SVEDR=wM7XYQu-?r0)ZKY# zKYwyEE4w0!Q-<*K)Y9?%tNgNk;zg>DjO(%*v1mPgxWJOpO>@B@g7}?dl9(g1GD)9q zCYW>{3Lvo+N**PJOzFt-1oa2;aFLs>+$TEDtrbIU2N@F`Gq}PBCz>9vMA5sPqc2Yn z5fIx(a$YM*Z^z|C+XQm}wqI(|fT1Dr+Ek*tF-~N?iMRR*ObNyYHBR(bz`F3cH<*~c)yb!I=J%>LQt}=^ z+L=G$c0N1s@VFhMNWx?Oh*#xpHGzY|TSY}vQx?cE9`g&F>umiY`&^7&gyUeYQWpTw~ne+kGm zI59tMZ20hjF^)dBz}48K`}G@@24c?omC@Lt--Unx0{~fkZUia8}$wDroDAULZ8;L2lnf7IXs~^4jy=%L1 z2RFxa>jl~7*Bb!Fi6cTF7XbjlbnV;p@UW^u(5bLLT1qUWQWVEWj76jL&T_Nl`I|Tn z)H+@(o`l`^`h~Y0(G6yZ4cxqIet7Yad#FCYAH_)8{1k4JUe2MeR6?wwvFA;zq49ed zB348Q+(u~!loS`n1$Ge;+r*hyb?NEj(E9ps!#`L)NpQ6y2v~IsoPI0|NeG2NyhZw^ zadyIfEVrS)$lJR(-M<&}09efCou6Q*irfBbIku~tn z&Wfba%v4H5TK`9Oi~-UFFIk+};R^la`#61&V{-i=d@kk?bF=XR_Xv0;I;Q97_+CU@ z4jUuS*~3Woy~F7me&Skp3e0Uu$;qkB_JwU_#^?^P0Q~&~fUJ1?<)40A*8phZgzxKL zer4-&N^Q>g3Fz_O732kAHK~Vbg2KILUxx;SiS5LR-%hf8Deq$u@x@XBD&e&G zN<{^@Ipj1Fc`N#i>%D#TbhqZEgJk4l;_IH7#O*Bu{Kt)>F-YU(r?-UBzxy{?8tN-Gr7|oq-kVt5$@-$qaJTj=s~ItG`mSa5(;XS*OSp20%+01C#XdgMn{6kE z?MJmv3SNfaz!;V8ZiQJQJ6*_bMGr+Q0`A;HhVQmZi-v-+(#_FJ2?HcIng{RMi_yo! zf_FK0!&uo4RIKk{+{np?3hs2S{`=jizJ?#fV;<-`Z2}B-#@SPU*ld}@_B`|?@eZBK zGY@SI_y2S($@xelp|6>i-YwUa$E}|VB%mtu&r(bSb`w^jDX|?|COUQwf9tAER^_+G zm03E?v8DhZ6^DP*<5uz>N@a2l5~;8m7eN59Of^C|6T*XegW`*Sd(5{C|bwliw`$N?Uew(>thU{U5u!?5BIv%_jxkQQhDi( z_JoE;qz0hiJ-HAjO3VH8j z(vqXV$m=){O=n|UFzh|2pg7yd#GKSU?+gyUXQTJB^f{cXyLUQ}zDcCBqa#u)vOVc$ zcf7aU%{^_^Sa*3e4(voYFWhHA0}S^K8QYu@z>Q;U_;+uBgQK9TIvhg&((1c6I$@r! zdHpPi0!5htFsC#`NR`eVNTUmzNQC)~e{eSfLi(u{vKxj&z$5- z@6tVDgMOC2Rm`>p-i)#`B@J32H=$1%^`EV860=XC9dNS0)Dkl?b25?Fj4K$3|CRmJ z)djjcX9~M)ujWOrDJCB!g2Zz|qxVul08{S31Oz@p+~m+Zl1aHud1h}GeoyK9ugM`V z0mu{R3?Qtq_Ue8GAii@%#sA~@0C|520&ZAf)5JIQ5^yKgVl}{KvNJO1U7yH&ee~pe z>^P924Io3Pwl^~L?5o=c*W-#AcggKmx^TxxllSk_L2nL;4Z2yHi#6A=s^;+_H5!_X zo*I(S+>hXHlLj-ZcKP(<=&ernQfm1_7M3_0P4Td=oKYA??SJQ-P9fRNL(->qebA2bI$YpBd>vHSBM}vRUeiooYku)I1My>qY(V zQX7uJt5Y@p5b3ISmB)P*X%!L&>BSi+EpTT(FX(% zGI49M8y(q=t$&AG+k1Pt)#=fb6sEjOS6;^_CI){=z|tsw>t6b%b`HuKM8VvoQbQ*r zU-FReSQ|LqTdWuUfUUx5Gka~lrf&b51tQQa5nmlct#Wb@$?#WmZfM`|(G9t$YixT_ zk56{z{hXajKGRJAR?V>3*xYvwo|8BLhy1-cDpl@06fnbVIy+%@`;ezrRcW+%Y|Q(a zpWsEg{c8+Bd0C;svpxx5kzP_63+2xqS6XAVYkHn;J>0zdV8;Xg>RZ&OKW_r5i3i?j zS>tc~EWc;44*vGm0Bls08PCqvWXh0yhN3z^>TCd!l%PG9NHMuFfO2A6#+@+=b}0Ce zr=2~~vw6um`ASI-RL>#1d6Y?l5c^VI_|a!EZ>B+{=j-xkQ}+7{=!k`7(h={?pRFfj z0O;>stIspiF&xvWTH;NSbQ-`{l&`KIhgMwPKK0hJRWP8~N_PmjFPLkqt zeKfCQh5pk!IsDMe1|Z zEnaeqy@l5ouLlUx@Y*I^S0l~9(mBNPRW{$@XVFRAsZr#$utrIsfb-cSo_vwvBAtAu zhp-b(ajA~_ZI60sQ+C_BA=rpVH zcRKIgr*;f_-}>VX@vH~n!pM;Xupwl#APe>I%HBPw6c1I`;Ll8gz`=^M6EidOCJ66@ zJey{x06CDR5+fk7S&HL7mgI5S?G=tM@$va{m>(W*vWbPX;eyQO3hCFc!ID9w-iS6u zOd=99eyz@qG5B_tat-5=6d^di&F2Jo}RR z+`KBHS{|UoL2R-`)QW+3!6*mz<#?!6Vdye*!d0K9;gh|a?p$=n2WdLZZ;0ZDb~!D3 z=_$QS-x21k77kEJgi?s532V>;kK+i3=E0YMlf!LtazPbHsMEM(nc-w%!3BJ5%+-G| z4-;}dG8`RpKjvnvc0in2;_0BPmDPon^JQgs?Ed%avzn!z%V4p<9p8R9mRy4IJHjKH z&N*l!0I=&#c;Wf&W43H!j_WfgR%PTDsKWvVH0(ZY71C+xBj!VwigJ!oq8S! zuxx;va*LV)?97t@!#OTCI3XNn0eRuS<3%H+TmjdM-$ZK_ zHFACcej#w-)DZJKaAfJGEw_R52y?_Nq$zh9IQ-T;R`EXynqb1I0IsuUlInX6Se^Uc zV5&3*dqqf2C=fAuSBmum3*&R;%A+vM0yb7E{6^MJ%+HuUrpWt$3%t5KrvbVLJjtj; z5KUSKdEvNX(4K=Dt1(5GPko9bllqT3wU*un>4(Gak9<5N14ec32f`SQ1KKf;(W z`nvY|n|qEdLcnAAfHf}af4@l20_InePggDT!ITlfs1`~CEeCh+y zeIkgka*otFR{k7*d`j*;-wN!;T1qr4r0Dj^@8*iU6tRVh7!;ngBHlWv4sWySkUR=M z{K*scWxfxGq0SGwi;Xigx6|H(Es&d>1UfHMebS82LCgTK} z@q3TtD6a8zYnPKKGTNr<`w2`-^FpGOLRlqvcXFY1_$02Fo^{)Cse2!i>1tx;YBtPN z{++!V^dfVYGxMRqQS(O9Avk>ip=muHyHHg=$D@MzaUkZ!cQoy3J8*&f*2GNGc0z(d z##5Z1kN%mXjTobTQDGQaqhM2r&Y{r?J7ZA_1epWK((#>85KvW~X@AF9H%ciUH+|{=AHG!g>k>@T>F5*6C zXiv$Wz14cv5IitIsZ~5<8^d(kxn$Tpc$HnYPdPp&pE<2rdjc#|oucAi<4XUid+ATn zBOo&?eW}0zo{b^kK35<8O8H$bPRe=(MC{fXR zjTw^qKa=?EEkJYzlww{3d!e~*y*@lE!m!tE7~?0{h*ApxI51+`jOsy!`z!&l4CAP~ z5*&3+i$Vx)jxC*PtJN8^Vq3M&&rB${d>jdC*@7OHFurS-d73r(EFu>0d3ALq)C%!D z7ZjnOuB<|1Z<;OSkK-Jt30^wyc(fI_YN~Kedw5i>bL-1ZLK;Yh8a^c{cGu^G{Nbkq z*Yrq(v)W;!3t{m{I~skAB@Oc9SseKlD&(Hgc?5?85L${pY|pl9TmT7S=@V>H`Lm1G2eT> z2)(u5)W5sC;J6y?D&;MFCX&I5r}nBX>kYHnRc?E`@Wa1ZUysa^M#j&tBk0sFUvRVG zN}jZoB~`46Cqgt(Nfp#G_exGrqq94=6O*u@*tbqKpTIo6Yr}^xT{oxd(Eg^a{fr+z z9n(0~R5abIP<&XIuW4dmbkVZ7NVqkEGfZ)7uR=!mu1U+>c~*A4YJNq6N7MWFe^T4r z64vQsBA)+Bya4&H$zud1!yk?v4(Z@#i8cr-Iq3C2p%em<;wfr zRxdB7hIHIb{}~}6mqivxx;5N}Hx?Ea>SO}VJ;+>KTvA#H z?dcBAbonAA`!LqXgyj@4cD`sp{S@O z4ZB}gmw(%O(V+tuUw7J6W`odRpK8uYz?_|2;AM)a4Ad+!kSe2I1hit@6uiSH#wl-vS4&QC6R--I|Y+1K<7gRGF>j=&hA|mx8L@I z;TQwMp(T~s%goGquljoS-|5|>w>>2(+^@j<^IR`Exe0i3Bbxc&CuhKua^z&6D4={H zf3@>eIVeq2uD9Z90>VkFlnoI$u0q&Hd6JXsU8aGN9m5$ZAz8bn1YLKQ$+|rR+w8ddN=+82!gJZjz&m>l6&x3xQ?WG_)PWa7a;=Spa*)B zn7)=bS!wn47Za0zE}bdf*PN?e86u6{hIYvg>jCewjk2=o3Jxr%39;V)Tt3=3Z6AEt zvs3Bq?aIOea%#4We*OB|GXCw;>9qRB$d!wgJbowbmJQ^=eZHq*Cnr6L)4b-ljIQ=C z_=@(8MVm89Yp6225fzI+3?{2-x{@jxPzGNQRy--KTgp>1~#>~aayKnWd?E_5Gq9F0l zSLbZRGRv;qCXL?a_!Ily>FE;Zm%GEmV|k2$+DPjSzu^3_qF;=qrH{_-nCt{>GZjN6 z1N6Dd;Stf8;h`xhpg3m z$6@>|v%;mSW^K)ezj|0rES={Cg@6D$&$V-C(sh9GL32aH=Hw(xLcNSUr0f#`Efcq^ zbR*@xQbeO=`lQT#Dz68^|MNq+0|vW%Yr(esiCON`(j*01E~29y<(nB|G(vp$*@zC0 zF1vhgk^t8dgM}7O5k3dQW&VYM%T=mzxq_oszZwJ^4?Ufu7n>hFO$*7tTL==rxr)lk zy)MY1?o(mTv{6UUIe?g1tFzxXJPfE$i1q)jJtu$L(5F^x(}q`USLjh^(ky*F<+MA8 z4{WHb5W-3UfMO?eBOPu{gt_Ui&+0qYXv4&U3tsD$QND8rG?Ovwaq1XNoXEkqWW)RB zvqW!;L??N~*X#J5x8-|0|tguOsEj#1vdWk}fXa zJZKt1cX?23PLPwDU;_xrb>5vi~j6q7s&TU)J&%ysCK z2&(0}Snl9n(cUI93NI(4@TRfZ^-xzAThH}bFll0zV@VA!@1R1?w2!8#n9jVn=3!{*IaQcGt(Q>$By9be<`5W(qH zKK5gDFkpTVbd7uvk)1+XXYr1ilaptl=uC5=e+_zxiFsmJbxkT`(95-w~w14I7xG zAYd34v^4MAC^O%Y{=dgTY8^`N;cb=%SqRO}>PUm>5M$(}AM8gtpOcZ0#;#atbg0PF zbvZS$&f26qua)+O62!JH#~fBDT9zW9+ZFUuko=A{hp3q%q=SPlQ=;_JK=pe8aGz?n zlSX=a1@_@#A66NUj*lcUPkF!iT74{jWl}|#sOq!c3dwPpXzh^&fQYFQ6`s_%nSk@RL)`v$AGb`R!Wy<=s+^dtqwyz92(>#rd zuczfyRqLb^-F*G(|LU70*3&}R5FxQ)}f2p~*5ck{&6FZPv!MRkcwT+5h zhXm`r#Kic>eVk40_Aeqk`IU4Lp}Eo}!^4Nc!NzX`0-$@(=`gU+kmc!?X8lnsB=K49 za2B@D3h|SM{__8|wYI7Nt<~Y-Wkf5{Saot(^1)m^vQd5rwc+U#dccO%v6)gsOkyyn zYAN+GQTeB&kOmVNrB^ZNDq9ORb<`v+q#nmei*52E_ZLTtw@yf;eGG83-X;OF^1}JJ zn2ac7(P!6f(dGr&ItdAvwT&);{{mkQMcrPoy|WaNoiU65J9oR_n)UVPxx3%EYCq)R z`Bye}Xn^9dpvsNqvxG1lrw20+&*I~D%6%tIohE>B9SZmL9o@ef{pY_>*of^P^0IGj zfoj40CaGD5M>%sonG#LSPor751*Gioa$qWMaMi8FC9~H#*Le_*kpCJlFh!A+Yfv7Q ziOnm-+&hhfim#mp96Rgh$Mt*>_G2R>N^`r*v=PQmr^~0OwGwc%aV|ZKHTTQ0^6cef zY>JEKA|0M~!sD&W?u~+ez3q`wF``@hUB-iy%S!^~?@>5%2_Hwmy7UFAEwlTX`UrmI zSdE&#ciud!o?lb@7di}D}l#`^iu&}!onwkr1&~g0CsG_k& z@*Of}D>w$W! z`}1~6@;DL#F0PQ|XLmaS3(zN`q)?Sotc9UJQLRu;(+*WsPO=o5seB4xcjMyA8mTG7 z{P|~6wAw@OF1`DC;ALKBQ7fK`G{tQ{Shs4`cfuZc%-n|M9`$aK>9O;h9%g^9uw$Q4 z{k%GUBZ4pE8z%#r#S?ZLd%MNfdh}?>#RNu7Q41;0G~XJmf|6N-XrLFf5~@cQ&(=h- z{@3yWW}u)Pest{ZJ)gJ=oaYHF}IIM@ib`nw%^%#m7b+ z^rC-VW&6mstW0a4L6sS+tuR$ySF9`JYqPR#CGVY6U>FxgM94WgU(`gQ*VRq)+sX4^ zVYjL^G!M=1s&AqC>I@C7F>M8k?&Pn1alZF5UHohe;8xrtA@M>o!o;|EIi2I!q(=(# z2FQOUcI;1kbeeqXY6UTWNi%^$_NDV(&+hIQnc4E}t@^%KRP#p#Uyv7+Ow4Pqk0C+jY%yCl+ukbDrV$-Rd=pThzkm0K{5`qI)-Y+47M;2} zF=p-r$@UC@Lrt(aD6-bnE2Jc!B~4-B^yuv-ld?0W2%5l!22AaAWNbFG!l}xVw{nZ6 ze8MzaDcV+VB>*=C{*Ag!{q#n>EoR#T<>{jS%C}zyhpL*KL!I3Cx6PIsTi3mvCN=v% zwX#G$8klEsBt)7yClwc%#i>+>350Q5+{-2>JjU7qOLtF2Gl3&^H`weL)LhC~bOEDHgi1-g*8kZ~#Fd!-|v?E18on0JqH6K?qAgJk@SDmCj9Yx_vX) zyW;pL5G4kI>U_k!9hnvJ(nXgr6y2LyN9S(kI91$=?d_;+hL|*WRa%*<)DxdP`hJf2 zLqpHd9mYY#!bF6u5yVsRyR{Raqpa16NJY!L%g3&kWzT4{fA%SmaNaM0U)PjxXWUri zido&Q{B=qKeVrUoBVFdnb0bx?RPx!}Ik z-D4W5jdalPaIx*`Ebgi%!^~i{GNR_SW<#Af$z~!6Mu(a^wZ^B^M+dcKHUxR_VHGtx zH22b02g zoUgV+&Eua^%r$5)V_VUVxf0&mm&H4n+}*x8+-2iJhIzVWOO%0udHEUTNnMLh^^m#_ zoYM@i_vhzBH2r8w4{w{OSc=c8?oSOTIh~E|hrdp3Kpbr&*T7mw6o8xPYIdTpIEhX}$>`IB*2S7Wjt)%j5 z^qc8dp%x)$OmEB5zW2+;_S=9jfeLmMn&FkFOU39~cch7lS>tiY%Bcokna0rmlTLx_JAL+?>2D*EW~ zud)t806h1na(@k4AD?*0L-x+VI42L-Pfs14oKEZNUKGdGfYj8dp0DmyaXwVsHfl`? zo0ET^?yw_0u-cd>Z?YLH0Fm80`d<6Gr0+|2VPV>X??%>dB8iN>T*05(`6}0Iw)=#NKJof99)R- z4PHNWZ*mqOqp@}LvRDvp-~#w4!47Z>>K zr9Spe4%9xOX3@Kj8Mdn`Gzc9Wc$i3?3ma91uYDAMfqz1=vdC?GJw0zw*KP_N>YZ(#X!&dP$`NY~;!|dwAX`F&h8j%XsJC+#U z2aHkf@GLbKnc1Fxh54%_8x3?!=S{d|M%pB2U*+wyG5j#e2KZaBLqWG;^M)HvAs=1BNKHkUiQE z^gCWMVqL=hh`07={6!%x3t3)Ab{`6LwrbyP4Hp%OC2tqZ>Rs4*vDqn6e|BVJSiX|+ zIg497i>tUX3nAeL6^^;E=YP9cwpQauavY-m+LVN{w<;>zY&`3ym5uM0>rz_+c@zCj zQdi{H^t4_NnK7{%GKC{cGlfkpfYR0GkZj~oDUyScBYg@1{Jee?HYu|r) z95I;~`_gvm!%{+B{eJDe-*)=T-Y{Y;)o7Haf8^vnI{FwBL1gZJ6>iUi$4`z<8bxm- z$~k9({aaT(Q4VRAwX|B?YVM&NTFT97ZzCGzA?MYx#5_*Awg{n4xbtwl?^?TDHT+wG zbfjoyU+r1kmLhnCMgD=Te;X6^Y13=wP4NM=S1I{(* zQD?VY_!!^8hl@ECjK8b;ZD3B-qq**d$sBz>6MFO%Krh7-|J^ZuQGADeP$9@~E4$$? z5Pw|@FVdY(W3v`B%68d#K?aherLuvoA|)qJ3sZu`KS!Ug&aHw-Q7$HHI%c8)>iwm1@3OQQB1SFgepMB0VUd8aPYeyLv?j$RnUH8 zjonrz zeFlajQONm#vJ}(q!iajR&7iB9Y1~sK#L*FNT z+m#1dj{J#JqeOPR6x&$d8TUIRAx*-~xPe?2ow`%A^J#~@I(<%0unUBLA%=5cRcfZs z`ue`82pmK1+Akv+b*_ytz*$2YpJ7-kO^IkF*X-tMek})t|$QpOZpZ;;2z=Lzp zV{_HnzA)_b+#%w%0?`_@h!cBgEMu)(Wo5u@13o%ktcH#D#IfADR5QZ#d`>P{s+&$Fhm`<&r~9m&Paf0FD}uoz7~^f3&_}e z^tV6v-)mfo=)|9ss;OoS{&Q1q723_oc~*FZSXz>?EaQm)b$n`BeYC$`%ywZxB4yT; zgial@b3PyZKT}Cll#-kh<@d<65 zm!5ldK~brWPTEYAiag|Lq6P9H_w0~WH5E~$lhb2@{YbdDbGHkqms4z7DDsklg#ELB zD}Qc_+t-(?Eba32`CrXzRstA&!>X66(=Q#AZS*-wIMuRbmvQU2D99c5}i7Nb*Jnd~h7Ui*U_4-fPRTj>5%G$5W& zNYCOND&^$l0-x)oesS2HN5KxDy%3mIl<-|M)05%il5&@a{E9XGppe{7B%?k4h+ZL9 z*z!qjDcTy8R%xs6D5b5lJIifyo#BtlsU6V0hVD4$rHe4){*^^{t}IRcFCF@$5guX}r_b*lt8S)+0NU@?uq$`%yA6B_dm>FJ|QZi^V35E$c^ zn~fVN39mtUk!PQ=7$0}=n(4D?DNPhy=D(0D@Ho?4jU*M+7W-O?o&G>~;I~1v^>z)f zu6(+5qAxA>k20}n=*Mx}7G#P^Vg9|f8wo%1PolU~4dZz7a<8zg45-c3+DCqqb=%&A zFsEixQdcV%0cgSpGs56d8{73`%WQY_AxbpNAw)j1tArKVK}9mZwbULC>Yct@9P7=l znp#g0nttx^dvG4Ldc^hA#0356ov;>T^m9eG6$SLpVuG|J+`*_ZRH!|bcS#D zb@`ubs?n*w%8SS|PvxFq(Q&_Z$ca-vtCWnYEL{?q70yQ<8t9>>st1AWUrDd4RynS( z4;guE@V84;^rGbU{8g-?9XZ9c3YA2xVEIhye?p+f@3#(iE`q9FtU)ue{@lEgK~7-S z3tckur4v?j3NJ&0F)a+KZO*SE6u`{%XUbcs+?o$GJApBe5mGokcE z*!f~hLiYV@bL}YPVk-i@4Uy0-p$io(V3}cP^yeF!2tr)Vsr!jf>UcXlcb~HsYAsTH zGM0x4zTY9`Oi7r-`76aIbg1>3T9$QD?aHT4ithjHJhNc07$fS0ej)DB;QYJvH-T}% zPfR>3ggY+y@yr~b!dFi|lPP^+1JpJ_E*ECZtP)UY3zDCPtNm52p0vDIz-8xIwaZRh zbxlibuiWDUr75cwlz@zqg#4?92s&s2_vdWtuzD?>q299zyIO51mEjqQabfOhoi@wl zG$2vJ#gfh~o!(Zf%u#c6$dJc4tk~V1T!-q6p9fC9cusXs^yA0A4};B=1KB4zpN+fA zc27)Y9@$|#2qdWW9dc^TSSwOWXA{undL~dEMyiW=o{k58mOYOha@X8dWUI19yInW& z&+xol9G?6BEO7zZ-6`phegKDI&8**9Nl7vHKlbW?(^?hdpAo^mk(AtTT$if-8@QW1 zmzvQ{GM4+t-QBZp!cn9FE8V(;jU zOA^TN*O(QW0ieeTl?#KliU`Euk8jFKO2bVbG45?ska_t>?MJ@pQY@-?HjMaTC(P;6-U0)PwKcw+A#{0qx^KLF65JO0{?U6G?vk!3hK%&f`RL4y;A?xqOLR+Tgg>5O z#rG4s<(?Phr@sON=YBYFtXU1$n|!)hn4`Yn(ob@>XFRO4w7gDunum$ZsAAId#6J$6 zg}o4QInvl@t80P!>D#orZfly&_hcWTluuB-92f&O!IK0RXCBMLzImx|%*+pj;!3Gm ziLr2-8cgRm=C z8Gp<2qHv4Yw%f-TL}f9veO?)9%1aq1Nlb61HN2B`Kma z$ixzq8G>c2_OErKB7p}sb@8&%^sm{sv~eO3JK;RRqnrGc&`XzW8lB`uG}D4cm#U{1 z5mru)1LNif+&TYPD_csH9N%iA(A!u1!ZqfyCl*tXP*^ecOqG1 zsH%A1b_b3@`|vQ+=>7M%e6-yMmDP+g_k=XuGNFuO0kXC7LrOfnfl;k@UqXfI2FqWGd0UQtXOyM`y;Iul07k);N|-EAQ(%G znlM?g`p(=eWOVx4=jbezW2>kU4qv*A8E&x<{8s02@@uz59Yf8BSex?x4EG&W^W0(8 z`{G(lzXIDcs(QTwXNo7WwcA=4nC2Q83!-Zp1z&%+C(8Wzi2CZEaIzoWzcNcTh}h_m zK^z}aeJXflfaWlYy&=nb?iq#8Px6MA0PQj&>8T;#7jvKC*t@Gx?9iZ#tyuQE-5z}G zyin{ zYQ~kg<2P@}KbRi*{c*0Io8BXWIth_ae<>l_7Ou{K_ z?DJoi%V>&Ow;W!%ym_LO!0K%iJAY4)$d@K;T1$iB|8Vt{VQqcO*OWqWcZcFupt!ph zDNeEA#i6*n6_*w$THFcl1oz?+N};$r6u0;AlY8&~Js%)Xa*~{!J$uiZHEYkT-TM2k zb|;Xvu<--!``%{odpLyEevbt(v$ z{hWgOyw?76MbHxZrA0pZH(sIjPsChJ#&aAT%lQ}Q`^NmU z>X4qKL0%CDcd;qboO!)_YN-D7k!1^qQTZDz-__pl-v9&|)=$389(i+DqfwgIp!LJD zvc%KV=?wfvpFMl6Y-%^lr}eAyZCb>ix!FxL&b#r^(ebDO!Bx#KzO0c`P?+3fzl*7N z&ST!r{vBTk9pBb0ge-CL|HMR%M6$SDSOTU`sD@tpZ;~0SMfSI9JNS>)$;m*4R1_r( ziDk8)@N%0#Q<@8IGCm5qO;!4-@LTK#JVQi(O}yV5DbZ-P=>z?a+DG7j?D^0s&ku;DQ*BnS$jSwE*A&_*_S3vtG z?|%E@0>D=H;q~>)pbs~Ix1D6D6~)DVM=IzDb2$sZX3^%Rh{tsQPmlKbt)eizdRYEb8xv_*raeD`$s2T>)+J90wmwP1ldLwI{pI2k`MB z4By&ZjlQEyjaQ2E4qaIOiAow;)-{yj`{{3IZ-TFQd;acScD7t6Bxq8{qMkCv#?t~^ zs1`*=mLn#nfR{bE6Zmq67WsT@XxB1K7fe}h$1hKqaK4NDA3n$ zp)t`y9@p%ZPr3pRb9df1*A7AyKVZj?fk?|Pd9CF9?sVRPluSAoqp;J79Xe7n!+FZr zaCv$KCM67bDk8$edm%LP^YSvT-^2rV{PF2L(DQSougpQ#8Jmh{Cg>K|0~og zK{~puw5+h-e=O*N5ns3Iva^!&d;Pghz!LJGj|av`Wb<~a<^7R$wnJ_;mL|mCdT&hy z=S>tveAGBxN8|NjH(NC3v1#k#=99cYo&Qrf!mCH1id$zQHS$aL+m^BcK;KmxpfeEB z95~-ly)-|zL;KBJrQ&<^@%_c2Wn*B?+dDwW21v{RJ%~<+Q_@Cj&ksXwZhBeSMlN0i zm;l-# zta$LV7HDQ;)8O&9*_T>C=>}sYuTWFl@vD+-|9D*axsp<+-dR2H4<U@9X6++F_;s2!xKS#t9HQD^mW&*wTNnU&W#skmR=oSw>_pA*p2bps#u zrDGI&G&Yt+O1AWKZcbAzQCS}PTnCC0bSDD5DIiFZjs*!uOyKLVGux^2^QZk+K==CZ zOMU)u7|g)`YUTm}4c=c*KL3%T{IAN6683+@cvyq~71l+FLGb@pKs~?ZtRC_C-(N>O zSo+_Gz`bVuPn|TF4I8Zgyg&(x`p;uPKK7472Y6}_`uaaF{C{7;@Shjr!4;8!V8pOZ z$ER_znKNl9A9g;kO4iuG@GDxJc;Zmt%~G%E>9o$r+xs|Mu80`P*sD zk8Sh*UnZ=(jC^}i%JOGV?ZmN~2B8>MyO*qu+--{3M8TEu3>QOnoPRlE1UH-)yF0ze=X{2QD*hnzwjQXU^A->v4WAOQKJncYEvG zq8%T)aQ)!w>g&lsmVjuq`wsI5`qtG}y5wWd31gjsb?ZZR<1ZpF9c}hd|3G1622vJ9 zUmA0=OowA!5_F?UV4&i`{EE}PpK%07^*)2!rsx9D^i^}-i#-x9_pOn?{ZN~QbrXJ| zI{0N8%}f!}KkK_5L;J2a$NRVf_Zvcu`TdxCB}Yo&LxbW2Za@mqSE=1UhqrxK3HCR= zGp3CO&C~m9>_O%nSA2RZFquzC5z)*spA{`*l`ZgIY~@>H+K~ z4r)EF^gn9e%9C~1Z<=6?6Xl#{E=o7mf=z#8?_EA&JD-tOD&g;HF3#JEbfVUtgF!gI#0*+~xn9=7?FP8~3m z8#d@k?V+B`r)Qg$M(+vAymoRzE{^hS<3fZD3_|A!8tONZX21JMCxDw{Uf!e)6F5Is5$`YGtY^{p^5F*S&BCd2*$ zRT9eeVmSj)(=y^z+MjXX0~mhvY({V*nK4y@ws&3LbHseqbR^l=WT|`gzPh?2b)apx zFnh;K#{=Pp*b1>N)@PJ?Bb=IRmEu4ZhBn?NKpF)GMhvo*U(RA`Q3!2I_qaQ(H*wvt zadi9lT3hhU7m9r<^74$_8m=PInE}LaC^i3HpH$Ev;%w(&=;y9$XV(zKh?`;mmB#^n zga+vGs{EEtG&4$$CO(r)-whS*YXbOYYmW}pUMT*_1wH)nf&%jWNzjsq(yIfabip~1>Nyk zyoP=##@V{OdZn;wTvoPjZvKImwmLErN{h|!ZYls{Ag*jECYgbFmPXzdp z9&ZMr_b$)BaA%)crv(*q_Er4b7sk}?ci%-oHnu{R!bXxk@49VDOG}RoEnQqR0=VG( zfR`lgKfcM1i@Rc=EaEQO)k$)tF;qhQ%aE#82cc7VB`)p+NF@Ib0s;I@S`zax%{lje zW9AUrwt}pin_T%p7ztDPv7O)J@_0AOE7$6b`}>F=-1rY|EIqx$y)!`MBvixb3{NdZ**_3{`MP#&Iqe)9MWW@AEoZ7k#+60zl;_1EuZpyBZ_-*BfQ!~w zEv(xD3IU{7P)t^v3c|inYQw+5Ro*Y_A84)r3NlmbHS{XEP_R#;uc*bvlg3j{c$}_4 zy-D*f9*3@smZkeBb?3#snNFrn`gEaADUAJD%9=kWCg!y;Ds>t7Sbc8B*5yx}r>C$9 znTxQ?w32AG&&2|GlLeL%EielB2r)?VqwwG5Nzb^$|6F|4ap)SZl$e)x?wZM=i!(REYY1W?(7C+wr$er ztgY907vG-(v*_;1LD(N+>eJ?JQ79WmpsxO8a?JAmfT^Y(lpb=zNKDTQob&TzV$GfnX=*Y zS|da2HPGK_a8QnJK5sOg1hW;MImkmbwMPnw}9`|Gqe=^<-^b(>Vf7L}gv`_PPqg+%ivUfYklc0NMynphsG_)^lJ z2wlj&t#z^j+C-;S z$7sP`1@UOj=Qv9%)toUZ>4_*`2lLl6`aS*Mxg$f!>_hxpP|I)K{@}sbY`xZ zID8?jF(!sVZ79i0+z}2{Y&GEKb@x2Xl~)^KK%O2kFPGv(m3_~Kb_9=6Meb~&&D&as ztqxkYwgD#|pVn+1A61u@#?{AcZ4ah*cC1qz(3ZQp+~u;fUnZubJV|`vqRj!?EUao3 z6cw?3s4)Y!LTQ71FDe>;djX|megiX8+t72fq$sOp+3yb68;_`>dG_9E+ccB6`y(nwnI(-NH0psR;UVM6g9Kqz4g)SgBiWrjH1cA9mK5NYizs_l8IN^P_X_ zc$O5cw!9i4e&-lz&##lBw`x;4@-a)r*3|a&Q(x75R*H93lMbxy`R=078FP|WF~UA7?3tBblD5LUi*wDs{barB#xkc2-&(lmuGx`z_nL*b z{A5rfoc5!1?6w{*UQ_jt_P3uBQQNo!LR0xA!+ui)spgCyJk-2ghixCqy*@^Hq`Hnt zR(R+x$^ZK}spn^T&o=Y4FqgdX?OIn{e1>B{Bd5mfMajgk^ewpZm!t}X{?}fC>G3Rq zH9^@r`*4WeKP1~qd$6wNsa3>Kar#VD&w!o!g{{Z-pRTEF=Du_fF&&haFedN>5`a>% z)@)V9Xaoe_KQgb}8`d#ESG7rf92u|a{qkH1Ag_Aghfi|x(4Fbwl0d@D;js!_(I0zo zr6f8~4q~gQPMF`$n)R~7ojaXV1h4#_=-mx^X*YL_vf)wi6-z>85b0yY2Bth1RsCP{c4HzGJGE5OSRWKfPl<@@rNd;NrHJu z1%}+^w2zygKc_nl=6rY0Vg7x2nYu2q)dBu>3Wvjmy2>b2^PMs}_Px`Ul=7!Fbe^_W_D*Ynf38vhH{&uL_VQRb2_Z))f;| zR2gTUq302}{bXj=EI2kRY}MG;H}JXnJJ8~?mDXiant;D=<<+Ee@*9K5a1jv^V0*43 z-x{#L4k+&0TaGLi(2ze%ps|ib33G_Vx>@vfoGUQNq z?>ATii-*~Z7aT8I(a{)}bQJb`fVQ>{$s1ysaqh!D@P*7z6FyQpSXuOZ$0$&O?({e3 zRH+$hQP!}zyG|!;jor`;4GDLNs#j4a^8{@lzg#U7 zyx+?DX2eaCLPCl?A!Dp2CRV51>HkA0(PHYtCrF)RvvTvIEYD{?YdG+W0UMd0 z4_pY(K>Yx@U?(LeDq;(8H;Hq{FxenJ90Y-d4LpAPTF!Ztm2n?}V*C&xHvKtK;fZ{( zJyNGSUxcpV>DxE7N!|79A0ntdhB@~ z+ppm1Az^rMUv1oy=fGfzI=RPsqkiblLlEINi)D(yeKBifeyU=U0*yn0jBk8!8>ie^ zOYOhxcSRq#Ho0E9%xYffe5wU(q_Zsrbd<2YA?C%ezmKELkRt@tcw37)eSD;`vGgmi zq?4E?q7&`0&W5RQ;eL9&qS7_~)$pl{GVJqf3EXyr(PU#phd!W=ld|lN;82QeUEAU! zyRl?m9%DZp0(mO)#-BlIvX%x9jstO(9w_X~b#HG_L1lD8g1@X3E($NA%XPLq)0Exg zV?uWtE+mY*T~8UPdgUi37O=fylTeT_-J$sFERq(DhDt+bIs495Q)~nE4pYU*XQeZ} zkb{8hH12E}&k}J>XQwGXK9 zW<1DN8|I4$Y`imRI^y@1S`5~2S8P!6`>NOo#~6;A*h1pOgs5s!0_Q!D43Ne;W#DK( zSH|=g4Ry+(UWG!}fm6+Up|2HQ_jeGc=*Qluj15$;{A*KjVA@NXDRN9<q znCt27ODXxkk5wCIF-MG^hZ0Ymt3^%~G4e2QSJ!7L2j#mW)?_)VoQw>_v>+vj(Nso1 zRNRYrlKxYZ38<+7<<=BO^~QK7ai1TKBiOXNzh)!h1P}2L9y2heWpelv!jI zwL8f}3(>%^p`104eJFTngl*B`V49=oXU+Achp{&Qh%?~{_g@PU>c=mU0i)Rb%PQ{Mu)JXS06-alYr29L@4&&x zNZ34k`I8<*5N*BeixNT|Xsp`-Q6u0(&Vx}6GUa>SEy_2~#>50;>=3_iz0`tiFgi2y ze%ldFN>Y3WcY$P{xT(7O4Iy#0+xybewUdtt2n{Sl&+a(M4w zweg&>zFt#SR5Vghuyl1LmH0k+`<#(30aSJ6;aS=4(}Xa{q4_3GJVbS40J`W3I$5{j=04T+CAO^U5N*$=5nyH}rRNtZg@}-= zQn`LaOn&vQzXSjNn)nU(;-~(_?`UX9PwuG*E9?Um;oN=Ak(7C1U#88w6VQdKbfCzM z*j|#^J46qrrRr)Dj_50iX(ceIxV)J(kp8MxwzjH%SJa)nIGIo7L+du~zkdd4gjvWk zGS|v?%|Qn+{|pSBjR^+#YwQB6A7aIMk?6%PlhF0|i~OeB#Prl31Dl9!WHDkx@*6P=6y+n(yRuA`%_{}aiKI|tXF zxT-4sRl3QLd>kAQm2^oeHBe$@sVA(#ereCp$8I!@o50Y6>d_Hu;BE($Z!s~+t*opB zKvz{&RZEMPhsX5~&hZ(dPEBotP_w+O0BTeSFJkuoebM$yna?G0fh0|b5S~5M9+hxW z(yY^}LZyN}p1z<0!W$@Jg}T3HdleNX6Anmer!5R#7FP;ay0aeDof5W;(g#be!<=p8 z$S+5a*TvDgiexe#z<;jfUHA2B-{}o&w!e}a^tU7n>S2<X*hsF3#`*G;##qiN3&sOb1?k z>Ew!n7B#v+&)h;Mz(-5?felLsF>tgSr6*wwrV4$;DAx!lN%t07F1wR~ZR zUOt?Bv+6VP0e8xGZnjUbYndIjt6}kefRYZGL|+@9MJ_KGHg!VtyEG=pGQs`z!s!5X zB2Y{U4`1ddzn#kfr6tp2{mKB~_Q#~1BV|pQ4)l%t-`lO^gxbBBo0-kd8j}${Yb?bA ztuHT$C6t?RAmRa~?UovsfBPKPqiKT-{MTb*Fob6wPY3cE*wePQbO5)K48*1$k2gm^ zz$xibM4z33fjy=*s+4XE8yY7(XH_=KyR1mLGh^4dDoK3QQnnfAuWuB-tlOxJu^@75 z8U7HR-LM5mz1PHH5ZZ$=pu+;VnKN&KAiqPVhG^8)rEB7vO_5V6dN;U456G=Gm~0N` z4wnPgZm}Dy|5ld#0|V*q&yTGx6(TnwXC<|9;Ls2=baco&U-4^Za%5gcMymifLtU@P z6J%r6#Za)SfzuG}&!0be+{#q6wV{WN%gXyN?a$#zU%)fQY^nBKV)fH_Z5E}V`Dty?XH9C*Z-=#FD-Xq!3`InuwjQyt%Z{r5NLPe;%n7*!$EjJGDH*)d(A4j;9O{L*qSYLhLHm>xH^uG8u;y?LwnIIGi&53 z#E3Ac%d$k`tt5k?eto@y93nkl#1I+f`uWn{f9F7&EaGZP#^9d;pp^cm{3m28s*qnf z57djXjN2Ud%iRf>YVXQ`4g#Zc{-)%zof-7Oci%n-2O%;@7~Vezgfb^6O~DDflU8Ol z(;9H)B_+1cW=||Tnv6LSfgbo>ybuD5zvk#mPgi4^G&e^B1cR_3$xeFfDF!j-rm^Cm z1JIUM^_YpAw!$K3%k!NbF~Pdm=5V{pvWT=TvKxJ(a6L}r!yJhBBSQVXzRx~Kz#4fu zF^haFB3VvWDUzVJ62L?<=nU8vY`Tx^DaIo%aulztkz~8!X#&BgherS*QudPy%MU3e zS91_t%lVs0sLss}^1&0tXX1}6xZ`)(!_8qMg4-iJqY`v{5D`bPk6l&c zW46I(bl1%hwt>lEMCk;9+o|R3UXk7dAd=Y9HYB(DUhk8_I`RnZD3|nZJ#R8fqIJcH)~wxVayWOH8@DBa%P3c<+^{sgIb(EL!DfcF#gpc2d)96F{8MJtFdoTwCQL~KQt$H=j_ znn1Phf?^(ov?Qx`3L{!+W^1=kYs>aIkF5=_yZ zJR<*N$1Bv!SZh0(;#5?>XkG+hi#~!Io*e zlX0@XH1}kD11_(?=$N#BAE98+5Pa6*f}Het%~8(NdNdMiIpQXh7xL`9rlucsIlOpX z1#UJ3hB+sn+(A)0(y6x1_e2`c36G<;9CtuZ+Dplc!y13gjb0>ap*$qDRkCwJ2IVEz7jG~w2JHz z#;ja)(S~#)hmg==ypf z8vqECL+JgmGAoV+*Pkn@3RX3u+pz0lb`ET$L7jrAXieWh(;9@yT1&p-8f~14{7Y3E(uOdts#^eC21}nFKjRFPqp0Fi2Hm3dNpvbIn#nwM1l>Vg zh|I`*k*Tp$#}wxxfngk&L+1+?NHRc@DhFWk{ty;GKj8NGcCo{WLc&n9TuhP>l0vCx zK?dMi1OqfZO@xTVzmIOH1t@~gwVx;^jTehDEkFn;+6B@oLyDB+V`H4Ryg8GgqHiNC zDF3mJ$fcXwc1<5So*TWQEg@0mNMmLx!NO57^xIpI{5I9Jbb}}*0@1(4+UV^MKWTui zI)A1ZoSw-zTn0D;2?4*T!~y6=l+a$_d*?HhLoer$2fYqRA`eH6QWXB?y#L2AD#GOS zRYEhVLc${yU|he*P?5oBB*#y*xZ-hb*8st? z8@d9;@I5Q9Pj9b!?u2+)W%0H9{n~x z158(U`W>b}mvm}#;Z8<5K+y?Y~M`QtD_4ib&8;0L3G5v(|LEfbf*hm(vZ6S zBhzKo)vd&|tY7K+>q0*z>RMMq8`d=>Pb1?4Rld1PAn(!?%?4b&giWZUl1am?hdT8G zX6I`O34?JrE2USJUDdk4#}vuTQ}>MArPPO{eP zhR!qm;f>(y9^ci&XQSJN!t(pm+EE|J3oWoeRrws(J|j-!=b4ss-7i8heQVX0Gb#Rn zx%?SSUw3-}wEX@bj)6QUEDUZtDExHY#?fLLQH+t1syp*Fe+5GZ4Hdg2S7o#_AFPDu zWVFWFU*K{|^+P((EDAr>yYF)Vd5BD_uTY}<;5=?uP2o^d#vHoU5fy>Ret`$zRlX;@ zdl}|%@aBfp`+0Qp#wDkptk1ym^pvHxj#ks(U%)Oa0gEn}-^7B!->RN6obIe8x2BCR zJRT_IU>Z*WGHqr97CTH%K|VRIFI;#T{cha3ZU#Hx@XEqsBW0~ZPj5$1*Z$P?e zA7n!_PNKfSLHg@jr>7;OxqgIGphIW-5YGW4{+%$G`RS*5eSg@X8xyM63er<4u7E3_Ry8|UhO z905otj}TZVsaU_e3Ub-I(*Z`oE9eE3cW1BTDr!Hnjrw3ZD9~{&)~bc@EjmPevVL-A z*i157u6QT)HL+VCo)2pSKfdReow!mzZCXX98X+~21RT8kSZu1yYbomCXur2iNcFFO zBROS{;+k3D%2YoSq(9Cy5moR$5byRqr>g#5nScmrDyBeib_m7Uq)+wr$m`62nA^vx z?RDnHOO}7=ssif3_%^jcq#{~79asCWSN~a;UadwHHk%(7a?Nh%#vDgz|IeBvBoR)g zRryYEv-*0WJCwif?HLX1T%fF0le}Cw{nJ}OH~v$%>??CrW)Ifz@DD-I4SnQDuFFb_ z&sLLZTm?@(enP?v7b+lu7Gg(5h_ zvbBwmPoZixQC4n>*Yfk*5V_khP5Vu6&PI?<2y~Et~V! z?X$JHkNR}e>vQ%ue^q>zp>SI|DE>;e36z=*tlVBvYs&-&AHTRS5}-kOE%C%)C%@}o ze&zXU@fb1JBg06oRxy8s!uE`xBG+uVPQHf3w|}ufuz&C^)7Jghli?e*;|P4KS4pm7 z?fo`w4J6YTd}dzc{+k2hwvcbC#QHp(bjnRroA;HQ!5H9)6yD`wNlG-)`0iEy_`yy^ zPkaZL5Sh`5g_$xU^ao&`eDDiib|k-H#dH$5-C?Sj1@bEr62&q|obm)B5ie>%F9f=7 zz(zc}NC3|8ix){0k;+m}RZX+}xj-wQ%j07Hlsb z#sx9t4V-siIZ(T*7EuQ%N!~sa|3H4%S^#bfv}&Uz?Hpjgs6(G0x(=&EDls4M-s(Bs zV|CR523DQM*5md@y!gn>vwo5X0t1cO0dgWSGa&FI^KUa9yqi%UiAIazGjOZ|S1)9` zHy|PzuTy_6sytkeb4O;9oTz#CrXXqo4|Bfb7%R;mw50JaFVYC9l$0b54fP}>m-zc%Z93TYjpqKO3bebqxncK*51t%ex9Q{tbOsY$o+2XmAHSSm188S%tuukm zh%dwr4ddg~PdNo-4kSgh!ThHr=bO9w20B%oL=fE(6-{#b4dI4tVJZ+u`>@jV#-Vcv zq?Md-m*wu-#|hP_$)UL8leL$P+`h&qke#+JDBzILZ6cyQ0TMJZKV$2oz`IF)hF(^O ziL^wktA3R$HWB+8$J7&izF@re8j0S+{p_4G?{$q%UxIRT&u%kjV!d5Oq+8^t)JNa)C zOUc)69A(H6=<)6wBT@c;5q}HstnHL8HX4&6kdr!iC`yKb1z!0%-zW6(3v`))tI=ru zov?&%&WD`3^ESz|AKfxByj;k6ZBLLD`am641ptjuq_O3PW_07eIwOt(lo^C!K#;^@ z!=kH=I0Gc^Z673r7#xbMt-Ah)msmJJxktMYd)nd+g*~(NvHLBQz2r7Ro29Y8IitQ0 zBxk_I48yq6lS`SA4R4awl}nNau=KBX&Q);Zq<1^nHeM{cUK1xKWV&i4%^@2Pg@~t8 zD2S~3UUvYT$mS_`CxU=v_n!9|k@P9IrJBevAkLN1f_fZ_|pwJNsCY7{O73R#$ zp`Zw3#IemS(N{O8+&Uwq-O%{&-_SYO<0}DU(e3aXsE)Iv&Bw#SqD;c8t9hHO#mo|o zJq3Hj7znODw5OpOMJO^U^?7>OuxsRQY#b1LCK=N<-#nN7p4UOM3(YX}t=EQLUO<6{ zn}FygK}sxWgaaH!Fp}BBYoFUr4Ho;o+T@h7^(^hvJuRsD2l;r3E`A1T%k> z#Vk3Uq`|ipBJbdkTe+}Xl(N6)bG^!5u(%Zu7)RdkobGPwQ0mao4~0eklW7{-*=*$s zt2R<2DQwxT*9-SWTPQZxEd`%tq8;Hu=V+&gKDp{;LjmBfRoN$j`|(xJ7w3QgNR)*l zvq=Y#7+}|yu6!|S3qwbAH25nj^Srsf)p)3kgqyB2tP;0ot5DL9NA!s#0+|97tZ$dI zjOT-I^@=~i0pZTj4W0c)KIMYv>aB$Qyd1gSMh9CP`SXcnkmT04+Hy9J)93C!E9ox{ zO;zu&;CnFdfz+pB=M0A6*h!Epe0N&Fs8EEv!7NKv4WMlgc|QLX))+O z`N5}8!h)uy6Q^B)Df#A!Xpn#UwXj|?~&g8sDo@4&P!aMn$`fLe_w}6Mk1nD){ej`}3X>36Q z*)*3)|K1OS!9!_mjReo?Yvk=W+}>NSmcvLk9VwCCTt%#;d}=RloOM0@3-mHqvZBX2 zhxft^pM>|EWKw@7A$g9ZQ161aqXE4mY*fL>06pUqga3l(kUVW-Rf3QHo5#B~Xe@YX z4+xlw8soJFddU9I;y_7EiPZ(lI`)cNezRakCJRrK~eb6)nDvzPueGh z6+)1(j?0UJRgAMwU-_Q%u=_i5zxg>pb?kZVS7Sw^Jv|ShcW~ZwtLESB-~esP-Lp0Y zpd4hrx%!}mhdE#Cx&x5EeE)iVDHt3Rt%FceTDERkfA0eTtibK}s%e{psD%%X#V^10d=TOfMTbEY2~hN&fdS+3Dbq0!!ackG z2BdlNlv+_!>oy}bp>;-qf|R8gVSj6u!hjrXeLjTdHZj3Gp#_;QV&|S3QYi30ijTX< zC=>}UV&8_6=3uZYl_cp3Qhu3ULwUd&V_k-`a&3=?+)f}*;IzSD6ou?cHp81JAfvgW zAPcLc*F!~&lX2xz4fuf3XCELWWg(OKP*+F8k*x}73sH%uX3WrkcQe`8eR^wDhTMp} zF9C7@Qn=59Kk_{I08_#vFYm+3q`*{P&<%Aw5KI@Ep-?*5?g$$mHnFT=dimc-Bb(m=EM9bU{D&^+)U@Qu;%>33|NT1bRD6J?6k^#W zK&aFytEz^?#a-X-BOML_@;|E!(FYerZ@=wKRu8A0oSV9v_NxYDw|||$*0>5Lw!lh& zzUi;7E;D28oE*QjW^41bdyLcVOzn!hU3JHbQFB*U;Ua!6FK-Z@o2H?kfNMZV=;njh zDR(G%X_ee3=2fwnRdZ_})nw438lZKlqo^=D-bQ6`_+Xcl8Q_lP{JyKCEAi%HqpxET zSYiw)+jGnEjAw!Pgt8${<^ZP;U~#U~9v@VM>$Cd9 za`>SueHbX`+fT@zd7HgZ_IG#3AgOHA-H{Q~>+#|bK>y`)K~4dy?&vx2a`hS|qdR=9 zbgeMCw=H)MrtQe6KPr1fRI{o!z&bXTRTA+1)&ilmNfGV_+~xph{qd+glNz zl${-SFU_;xN^&_jhwnabeAD=Q0qEtN=Z4r2^`_Lg7s~L1z_Q$JjK7BYaZc}LO9LBZ zo)y*W;lfb2sF8Ql1SwC2CovTv!l(#E)otq=Ufo$TD_)QR3(lqxz_8V?u9{Kh)Z3hA zN-n=?E!TqXUH(cxC58QdGbww!)Q&nyyj26VvX*rYMn#7(ACy8KiTBtdqggOeM(Q;I zu5HS?p?*o$AD1`{;BK3NRx8HYdMDf=tdo1u4kQ@LNcgcD-c}XBQ+xzga0Fj=L51ov z>iRUv#Tc&WjFdb9e$q%1xh-^IKt_u=7?bnW5Pr2|KjlXeKaqb&AE04@8DIIawGMg7 z!mnP2kbc4QHb5aNBsIU?Fr4gaQ|BGkM$xz7^UZzTDgexju7d-QH7}zI@|$ zWY-Cs3I7)a8hXMAr15_0i+sJBcDcwI=f%5u1JnsOTc|2#&~1`;Yzm^xdE<|JXN1N; zyFLAMx{e4qdP~3nbk)=l$*{8g4rRIC;#;ylJ_o3tK4=n_E%i1dt_fvMPOpLC|JetH zF`JMVYxqFL`aXawZ?na9(}V!A@ZEIZThy*vAl>@C8!A?uR|AYcCVQNgVH=`cQHqOh?gcauQEH6--rb94FSB?33^U}tCg*>xJT zx!J}tGAMojT6h0g&%m7=p&wyNKyzCQ35lvR5g22{&+yx#!r70OXRSjzW(+)e(X>Q$ z;bu~v8Np|0rv)HYU%z@sCDdo)orelc?Tj;!nIxmMupVn z+T>Yn^D{eL8&luhNvzt~;=}tWWov5bNs*i~ANo)r+gXjHG5R4p50BhnNfEu~cyE&?8QIX8)d(P7X{TPkJLSIl zY*G(+bTrs;v);J)l$c7~Gw`WDpkx6;Ld@JH+xhpw;kX8{=!5<;0LMD>A$HJbtdD#; zC#mB`DW|IN#PMlrim)Pp@zd>>-!1juj1j{&E%;uwlYrjI%_D(;bc{qAW{omAkclds z1f(;#5DU%uYpx&kvAFV@TK!X#r`me0=~{Yqa>>*zEYXP_gF?>k0J`_T$|SdtU}Qnv z9)NxaL((QRB^T7Ga_Z`g)-idP%tG-*0OCn^`+7YJ%RWY=r1Ez)W;lhRn19HL>$osf zI-860W}A?1`0lhG;KTeMJr}gZb9I2sb2`sgVBpTntL^OVQ{yMn9nf{qs@-ljU0b%b z^;PM&np#>x6N{9>!fZfK8RX|UP}ts)d_4z8LmW_R9(6;%2c*KdNcam}{?w6D4M94} zk8x98nsQdeSyr?JP3}3J+5a`IYgx)zS`^d%?|kkjA*n}J7gf5E3old2R4m9WQqFH7 z<5`2S;X>TvfNO1G21pFd&8Q%CyQk?wmf?HfE@2?0@=A55;j%_IroD%#Qg~dLQk#rY z;qL<(bdK2NuZT0-^=>aWo=AbBSwR`dZcK#j?izPjNGuX~JkYiuv|P&r!T%|M+x&7p zSgo~A>c_^&ntHx{< zQ5*$NVh3O${pP9yK4?F!LNj3Erov{oHJPKF9wA1gzzrRlr{5UBJIt0 z^N{cVrQ?6r1D?B}R$`;TEhSRoVazuu;x-xY6kJcb3KBoaCM8KGv$4%Y`e2p=6!hG! zC=hQM>z$OoKF-ks_MO>;hOFSq2E3_Q0pIh%o=b7)%#^R#u#2`Z%+7xLB0tsf>Pfqb z1PB3M6%>T3@xa34<6*B2_{)sqLwLBqwmTztnC+TYMf3a^Lnn|SQiH4fpw9FI(UQ7= z(=%-4uT)8Ct#eTsrb|iqx((l-3>f?rmg-bsfHdcj*vks((EHidF^j)?vI1O*0ewY< z{MZ9|=uBmISgb&4B21xLpwp*5%H(_?NT_Z76s9NMd%46rf`tAGo)PgQJgD_jmzjl3 z;yaS8*Plsr)1D>w#xr|7Jk`3fhpWc+r^on9?fVayo13A4zQ9g;y29_zWbq2Yv=sk% zGNTWgOkxra(*ZKc!2C(3yIK2KNlDk!!!eg#R7d59yr<5_W%85LPxOq^t{VxmZ&SUb zq_7Hx_x38|`=GcG!0PXoR)l1jXm#nmMF$9ceY}ONTL?hGxlFk$AM#yqA7= zsN=^}Z1_$ZzCdvde|+zytRUnk_v2okJAflggfNi3;#5C_ZlS#1de*?#FkSE zXO1=TIG3T9u7?=)C`mQt4HGv=3h3C_CV!CyfKR#dO=xFHpBoZq^5l0FS`;U_4ZY*& zk-5JLy;`@qYNY_B-+od6Dw*4`)ERfJ!vFpcQ9%4{`_xWw%x)3IBLZV4i%b94_y5a5 zisV1O<0A+i86J2fylpAmFFt^!hHR& zSn?&cbO+gwaK&;FLcBh~F@drnEoL#%I)9@mc6O=?>e%9mh1VM7<9{zeYV~zAyX!`t zJdjtWlH-K|(g!3d46Ho?I}bt2u-Lv8a`McfnbjepnxqQ%{nNlA1@9BhgBkqSNc z@)dddpVXU^mV*qT)H z-*`mk8JNu30bKiI!lSzA0bc@)@&6`oYuP9$@(mYOvt-riSJ6YmZdGAl7UaIx;=|7P zem1ty)I_OEB%(`%!9nWrrw>SfVY<~DiKmsUNM1V<-ys{CJ?_{52-Qfn7RXlSdr($0 zY{7F4y!?ljEQW{}y5pAXsKOo7JrVT*x?G&ywQ)2IK}zx}UMLuxuXOnfJTdkI#y;<> zI6M-6L4Jsd!H)3=C*0F>fU1G`vp8FLydO##VoOsb&N+r)EKBn>A7DBrqU#=ie&iKI z?bI?Pk4nR(voL&?4|t2G1U2W==<;DE(rmr!AI}RR{RUKywRwmCj%JJt$tT9aolQU0 z;wz~6W{VCvQk80UWp5UL*vYET1Zf=zXy$5t1xsYsGFbJJ?fxHoZy6R<_r{GPAth1* zN|y*oDN>TsDIHP+D&^1}Ln+-Yl9Eae(g+OQAkEN7cMP4w+32Is^FP;hKAn&6yFS2N zv-hmM*IM^l>yF?3TVd%R6YrP1In<0QyB>`i8cPJ(nc$uXtWsVboqTLKoXCeXVT`^9 zL4KPvJaHa77VNAcT-MJmACT`wk`|^$jb%!$A5ZYG@olwc?NtDAxywsMl;LmR`qb4$ z)jA9u%MWwaPm`MA)b<|^?&BjE+~5owA7;m;PLmSl4$3|0iY6d3+_LxPWdWS*fYvsC zC2lQF5Z-45x0rVC^AD&}n$m;N#7pNPwtYNR@?j~vti^@;iu3I znt5eDSs?4AIeUmSchK%d05^p77iDY~`|L&HwGEutUdqH_B6zb;H#SBYghZtkJg z1~fEPZ8Do4cAS))Dn6ya8b{~c@skf}cG8PKd?j%92CRws192>3eSIB`fn(yD%0;>} zr33)pOI-7)5cC0!1nAWwJAJh<3>RHTIj zB4CPGk6_YABkBiMo^3#8WBsK)z6kn@d}{ZvSK)l;+mQY9Bi>*$Td7K2DqFE);Pj0u zzNvi3zzetcApL(NQf=15W^X=Fu!KP8E*nll`(3Ns-72!UjFb!86AzLChz<#W2+d(E z0>RncqZ}H>Ms{}zZOjS+p*Wg6I;^7)0=(HRp6kHjqQFBd34r5UzZJcM!C(!h5WMwq zeHUs5-@!xgFBTP&G5UIsmVQtmSGhK}0PRSelxv27hinW>28R<1UXeekYZA)ht6m9U znRIK8X0_%YkV9;uVB>q3Eqir16gXXXGU#$ua3V)QZkIjb>lK>z_?Gs1MW|@0BEQZdb;1)T0oKn*&JCEhbwhyUb{>C z)H5B?^dWV5CkOv?{nI2Mk?R1}GR^Nu8@{Q+xY_1S{Xq&q-ZO{u@c>vY913wY1##49 zzj#9<)vz01{T=DYoJP@W!#W|6kB@_vwf;b?f!TUI*C6Zgkp7y?SYMySh=&33p@aj- z2*y3n$Yp}n3Eh76b#JvT)PX0+FTe)}_khgVpX;S`6WAoex5Ci-!XlR}Y<-&D@G+c$kU{QW)qOHyEI^}QUB;*@xCN#`foEcAh`DFnzz=izzyK2H1& ztAUb_WOH$eUU)mUwIxIdw_5JyOLVOVYuG{3+47Pc+J*eLQQcqrEdl9%zqCOd4<$a5 z&uh84rFK`w;-*Y^4nYI2f#?x2@kAri^a^GUR(Pt*)*NiCOV5C&vNx%-hD181uyT`- za`Xx;hB2w1l3N-UDC1Y{?2NpB&#d@TP0iNXncwtw1Ks_q+bdSiaC-V?8sTcgfyfee z^c)Ekp~Y`L%Z-99)^;&(PUvR14el1vMwi<%N;YRzGOBY)ea2pwYIjNOIZ#}|W#)U) z8V0SXY#*dG{t@qe`G#3&T6uf`2o_Df8=rV!bG>Y_?vEb>3L}1aqd+RbsyP#BiW^u3 zsW=Q%c6?8hR#Mk?y|ccbUv6#9wRX5jN@)V=Ju*_7t!)*iCflKY84?n^SrNtAUpSGP z^I#x13^`N04rFT}H5b8=-!Wy@E)-~rZeMet8ZkOP^fL{-{qXiJ^cQPcg`TB9vq$*j zqp!nm=D~Xg0;gW4hkn4((d~7E>E7mEKsv9AS`;Xe2KnF>>8IMKRVPmM48()_erC*I zi-f_JNoQ|8r16W3S*B@b1LFcydb;2(}|inm>rhe z`2A;mAa)yXOQRY9WChYI85r?@=@|*!-50yKt@T-MC*=@Gkb973qy1tcUJtIsyE-6M z@%Aj`z~~kbO%qcri3TRqxCjUJ2Y&ziZ1O~)EC_2geTq#9A0-37|Lcu6fYsg3P4F;} zvkR9kIq2?Npr19oA2tW{u{Gjo563sYF~*g@ zd?*_)L|?#Yg-BHBjJ2_roG*dsu48e3OXsuSI>qx(wU~&QGA|IyPi`l76l=6&%(N~5 zk;Q$>HvW>?y)f4M#>fd;GUd^0-03Q5$s`=@y>08p4--gWgR@vi*OZ({& zUC4fyxuT*ES6)(*xnTMS%F?t@=qJvKijUabKw5h<{5j38BW{F``GefTii@+I^7V3q z5a?O&fyMV6IX>$jA(Y12fERmlsy%hwTbT32NOGQTpYR|(Wq10;(D{Ydi(kI&STa1n z6^(VTZ+iR>-#(9}!QkwAa}&b?(11V;i&Y@6wZf zv>hM0SbTP%^*gqm$PU5lq*8Mxzhxe&^WUK>f^vrE`biWLx-8luH{sd>^UfF)j9mk? z3qcNP2K=Ch!nFj=DVDR-MwQn~O9VIRXvpA&5@3+RH?m{jISs36+}q9oH5rw!0QQE( zzGFGg9qO*d#GBaF2XYGHJ|fF6X}Xc0<;BIneS7hB>zQzwm*+#&NFddzVcN3eGhuQ| zRWBW|-(U%Mkx5&YEG(EmdlCu-;M`s>2`oGHgTKC+zA-Qef8aj>_c@1tj?Cp?q5KJk zKQ|1;qsTW)1pKGrW-gpS02`<2cvx9oAz{t#8K6bZuX$bQ84ypPTAIIYZ4ww5xd*P; zuC&rZ$qfj&Ul8AbbVudw;w=8hojIa0x%4*wQWuC*+diO7c)1S5M~aT!X5B_n_emi| z#XI`|));WPy~F`|Gz;^i(!U#Mg&g;cufD;`_al(0y$AXbWi2ODpm_Z>^?4fW7VG!t z?uS{b>K8VLv8vCx(?0vGp*)gJ%{U2kd_`MxV=%1vr*2O7v{*Bw*6R>+#83Dqp1QwhN>~mIpN4>#A=}u1&AEnoad(qL85N@y-SvwUVvg*N z1OQKxl>W)@sd~P}S@jnod=GZ}npn;4-E8ZJyR0NTWQim+ONkO89B$@l5e~-ESd^u9 zS;us0Cd=Kg<(~PWQeJGua&~=g#0zURLj`+o6h8U~;1Z`L zuv7ic;I3Ba!}k-JfJ9*F{{+A@F+v1C6xHV?qB8Gclgho8%(Gwlr1as#dQftk&`qFn zj?7(CvyJX*82~KM9?A`C4T&F!(l>nZ>0JQ(y=z+!sT=|W$%x^<<}L%Og2RVN7TT7( z{GU4oCW&rxQ6qGM?}GvVT1x*K-nFEUuw-2UR9OsFi;gxs!!oX+Q^%Q4i+7_5bE?XQ zuaA4i1*B&{W!DTiTiv^P*P~^gFU?)o?lJ)o7!FQOMSeAnxQ0>cG>>8h*uDbi5ti4t zmvIM{pPJ!&H=$Pa#WjNaZMxYx0^Z-K?Pb$O)4<>?VFHkX+ye`X8VC1tGdFE%Z8&#V zmxQ?ZY#=n%Y3vnWZEg#`=p{T1I$u+3i@r3o3E(K0EQtn)N6Z@GrsnZ5(UU=~*g56) z3IX#VzQTs@hC|ok0v!q0CcM7$fEO_B|061ruP#gnr#~NeAN#YrR1%c?lko2ETx0^7cDBC7aqSf3XKeDQ zpq7@UjJJUvln*SMRL*72J(7P*4xobg#oUf@ew`;u(c=H~qNnIDD$gHEa!*qAqnVOY z%DBn?NxHTH6(3JL-u`V4MRfo7*Y~YeFNwXtewED*u3|tI=ZXNyQ?eqle%g*PP(ZhnOEfd znb%%>`#OX=Y!Ua^a6U`uu;Ch(Fx0b={%~;Si!q|#d`QnV<6*Ozem#AXejP?zK8`P{ zcnb_*iSqzQ{psnVs!+oHI@m0o)B315LO9UKoA zo0?8m`n|vBuF!{?D4Cl_sHpAV={rdO_%ue%J|qhnp|$r52jyQ6K%d9eQ_sp7Vbg#0UhaOOXuKT6VEkjS7g`OH4f3^ z*1ur5e$b@r(~ok3Mu{^fc-dqN=QhBD^XQD}WHaBw#%R5LkJ50!-Uavd7h^2`pHIdB z%Y&QOXBA+oX!(wEhS0mW2(vYm$7)F!`G{U?RSUKHS#)chJpttrd&DapwjgOADmTn! z3(|re+=mY!csPn!y@HJR+>yiBbQIqxeG&q$1*T8Fz|O%N4%ajuE(Am->@!m!2mn1FD$~-M4~FE#fjf= zOFD-`O#t%CAgHINgM$W)%rdezy-{-cpoY(;J?5ij!1K461J<7x7Dl?d-Z;BZ`Iaw& zRpX|nQ}XJf%Ci=M$D_Q9Jq6C2o?wCW#t2}2AQJ51>S96-xg;+8d1Xn*?XFL zP*D0^QQDyhXuY?0p8XL8pSyTC(9Tlo8&Xb0Mg5&SlrO1;Bf_2h6`j`z8OhZ-5rL-wioo~qpejg2QZcwcMmAM~f=Pt5pz4}nI%gIIaN8tm6cM;&g7QQq2a zmoy1;4*h4GZq2nWEZCl9B&dZ}q@8@~8 zl$4wWgGt23b|ie1iKUq>4h}9xSpYjR#h*@6$MW*K@}mSXe4a`C8a8N+sOSa85>c^n zt0R&|K5bZ8`6Qqa#Ydb@*PuQQGQ8bDO8P@aRmA61H&yO2Y;0~$zh>u)a_pb?i~Re3 zn)r#y6wK+vHkSI<;82MGl*V9U_RY=3Yo6N5Qo!VFzf~Cw9sN|k09H`=5WgwnIzR&x z^qHM=uZkRP(5x_chilHa4vdA1dn>#YV46i#u-;OQQ}%k)x7cAOv4SGza?&IddHdvn zzMkI2(O8i$AQ9I-#l_Xo-JexO0H5KW1bxxz=C4O)s6chDjxtWp?HR`auUZYH*y(G9{x|QVGT@|e#J|+CYP2^bw7-iOPV2u+ zv9bV-%%2M=ECheKWj~8twiQzi091}*1RHac_g8JAK4_zOvj4r;2L|vw{!_&M{tSio zGxVP`%7JSGaA0oyQ`W#Yyl=nD;V-h?-=EKQ|9p#r;(5dU`>Xi){O5iDxB9=;5Dfg= z46L<(8FJAN|7|zw`M<5Z^*`1B_w51J&40@OuebmI>YV>uJutNYXLZgWc|rjM^RK|7 z{IA^qJ2yP>Oo1QRZp~oWP?+6sM4WJ#Y4ESc8N7<%NQv(0?Ol_?xszh|Kq4Rb-0Qd) z`OP!vn`^JO7h3YP53~m9jl(VErRY78p<<4_JgcavxH#UPs`sdpRkXI=IXhT&*&6=_ zIol5=ezftOPzHy2%@!+S}#Y7V8Ng4JWUE(%pw>3LQ-E6xyDq-a_LDqq%O| znh@Sby}KaqvMzDhfj?HzoS{-#-}@Zp;r?fL4GNgQgD(}vQp69c<8`hx zhT@}qTgE8p1m+eqtq!$iY6EF%PFyh|&X*%Y&6@+%w%T?p{L#Kvfu9%#G_0 z3GVBfCsn@bxLd}fU9A7A+&o$~Y;Je1)@8Ryuc~)ULqh{g@K04K>ChMOBUiyY6ugS% zdb+y0CMG6zc_Skl^H>HCLAZf)=W{=ocPGlclY}om);L_#f;PGO)yYx!D~g-X7qO)H zF$HmK-LcUFNC(YFEH{3n3erIKe2wpiWCnf7wwV0c^nuT2){@r=;FP|+g#3{;S>DxE zaET}YvF-=eyE{#b!%Pbhiw$v5`eg3aDzB@TM>{}tv!3f=8|Q$4tV9}(Zqmy3iq%n* z&bw#e9?LV*y%WSoOSVtQ8Aqf@#3aB@Oh74IE~}tW>wc8aBH+B0Xndc_4rzYbm&~Ws zb$+z@XVIr!2Ut;mj6sx!%e!J9bv#@GJAd0JJv;yQfZIz}nUi!4l1)eIXNb=O?uof% zHzM)+V0|a)VpSh0a(DWlrzTljQbKT$l>|LeuWtA z-VeduR^S1=-CYmZK%xmBPm0B!Mg`~?dBXy>ZcSWzQr2bpgbjsdw$q6l_Q5=w-= z>4^9g18_A;Ieyh)GnIe$?%f}9bJ`l<#g$d>xinvTc{@2dT^v-%GOB?2{tHTEk(u?dmn)-%@)MrTs=ZCLoSHaZEVzex>66jku z%&zSbs3?wd%gf8T**0^qOyb@oo}M_Jz8i((S7F3EBd2z#ozVo)J91W5R$TY*DKp%| zVF$s4W}ACIajUDTHP3Sabtf%@tz9C-)S?2g#?zs`kZ>vtl(iV=t#M-!`=w68L4ofs zyVmlVgJ0M91B~y0m5hxuO8z{g6TauuvFLVn1YeA)0K<2|Qw%KSbr3lv7^5o~GKpTU@HP^ia6R>JO@eXdO1D z=Y8`nfqgQ(R+Eg+e`HF9_Kp?mR>%X?{lCi+7~i%?jEyw(x@Xovj3?o(CrX1kK;``N zWtJ~#inac8S6YJmGcyPam#XNNYT(>TL?3W^Wn^tF;0&GI>}g^3+qet8Za5HGPy47X zm#^mJywOnQMm&N=nMD3o@SCMKFsnOW&N$j^{U*y{x9RFYe^9!Kle(`CD&;IzyQ2zm{)C z7yG(k3hjD)r`av8%YB+p8xki)CPQY;URYDrex_%(t5A=&d*_bVQ~twsm217Ldd@?R ztI?qiz5E0CYTy_DSnXrCXRU@NE?c%Ev)WTbO!PpS40{7h? zSZNfBNOop6W=}59!B?S4FnH@sxA4MQBX{cz!dVm_Z55gtYNMA@#mgzglftMpvn|*P zXCffDPf*2JeCqd_`rD5={u+lG+*31=!!v^GD7R^6;jz)fncR@ak6ot&#>G1^HxN8m z4D#2z;;WSYNAJ@UMiMk2YIavGN2%9aOB~d$yK~&z6xP|VnHbaxOf%Aj*DOf!l|!MG_jNf#xJC;Qu2h0%kQ3s zhJG6-VtE0JYFm^Ni)&WljAU7|mCna*ZauS%Y_I{rWHL`JO0c09?8!5z)K@Zi&KNO z)U3h=!;(TyGdnGbZ?yt}t%K70L^5JwfwssG$Z*W-IClHyV02t486}Il+kp`N>1q&8 z#GM2_vTY7}`YG|LICXl=hc)Y;gJ?G+nXfkekxY(vb&b2I6qbnT9q79#q-sN!dWLTg zU0R{q)#x*bLm)yHi;mA_&{c!=&HmHrCSU1zLExz+SH)D@(f~0SWJ?qdKAM z>+3@Th`H|b{ec0qkYw!?QCuvnBmfQ1eZa-BnmZCA+mpvQuBPT*cn?&@UV`Vz`)n{- zX-9rV?E#hdcH-LY;*=+DL1r(TQ;KEkB5L* xa$N=j5m__L73l(ETJNKz$qjjGq3 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

  • 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

    FL13agw)41Xw39Y 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

    XY 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 literal 311775 zcmeFYWl&sO*EI?O0s(?+XdHq=0wFX`u*NO8G=Y#1ym5zMK?04t1t(~L;1&q(F2UX1 z{oCX`=RJAO`_-+wKX29TDhhTtz4lsj%{k_nW6d3?qyTx0{sbKX0pYQH}>cAUF9+i@#EJ`n5fS z=$rWt)P4}}=wLNlUu*G8YtpDPQEw*X3-u?pm7(<(R!Jn7NkUy_J&ZGT#i39qtalL8({7?k; zU$a1i|M}tnf78FLfeaZ%{nIZ0AGFe!ly}y<&3@oHOGw#hkS#Gsn`nySUFyVrwEXAw zW)-QyRmil_QfP9D&7Tk7u6Bkbv^{im>*RguqbHv~4>r1A>A#$<(vH6w(1pTxPtKM` z`Ins5=C{u0_n~g*M?USFGd0n_{(DFvozL33&ZSo4>%n6b(so?93nC|)g*k6W_Wb$%F{CGn&d#vo@s*BWpW)HWO}J?AFVN7YSp6te zq1Fk8`p19I9sxn*0qri7ITSAB(N+@R(Mai>!axM_nn$bItG{YoOd0e^U0kiNwLV&Z z=CG@nU7~11_Rn`eB1^iBuw%n_9aoPcWt{X*IX%Rh`Oa z$awN<{)lC%_Z{WxfN`eOM>daO1P^^)$u%zf(BgoaF1LyaXU+46zi$3HyJ+f@0*dlE zea29Dk4ROab?cjuAE0 z0LmsZVgMSlh#nQ95&|9GBRmNzLX|qT?UXk@hACrXj8hBn_z!FKj^}vge#ze|(LW!m`_d|i4y{pKd z@f*F=m}0Emq7j)4u4jm#*62d(X)g4S-fWMkx#%Rs@ko);pQ5E1seh#N2@BAUiB94& zu_%>~kblS!VM}G~fEZ{beQL>TX`^h;o8wYvgN1T-p-_*vJ3cc!%;x2~dXuwRX>ge` zT#1zTLZ7_RiI`j=CqP;nw?12uSWJVJ7^Po;EeH-GS~61zC@nJ6m*xFw!4la zsdtU-nEkGdnIfpu64FD|WMH7d3L}V*V!TvU3-sQZ51a+{^3m7hw`2qQ-JHpO25)nhn^UvB&g43kQ7YiTLUj%|hFQ z=SCNt&)<(LTvSRo;O{nSy~W;kY{d7WJda!#c>nzaDeeO8ILaR$bpPiANM-qRED-t5 zav6^R50A#Wd(h|4WaAxS;gyu6k`W6TFD-sKmHX?}I+&b>H-)dSe~=yLcE7Znxta02 zyQ#64kdRoEamOO(8)5az`1b8tiQ^u$xZibSh`t(nAt2Y$*XMv5U_{A6c_Acld%kq( zMfv%Rnvqe;e5#^%#C@XLHb)V4QTHoSYwlWVWD|<)GWPZBY&ny$AK{p-m?>QCBSNL) z#b!49G-*`&1PzC!8?IDHTAb%NxRh3I@M(~m`}o0<;FzztWS*(fe)qcWPYQSO>i+R3 z;-Afm%UfNIeT>r#uluyPZjB1Dx0`P92VB%tt3oB{>EkaG>5)utEF1NZE6g`eF7Poh z)ZEh}A`|W8Z!GK8PKrK3J#SXH|79*J*s?h}T~YPKB$eHW7Fe&zgA~ln#%8ZrTyhwW z55vR9e|)B-shK;Kk(bvsWKYiTAXk=JM-rsy zRRLHhSab5{9@Ik``5~%KLMGRKife)!_VP0Q_z%PshT3wooCe1-W7h(c)bJwb2BL+9 zluaW>>5>LmJ4=Q0nfX4eDxcB&>oEgLA3+>&ken3Gk^-pG4%;ThO%&PxlZ*ZBmoS{? z3q2+h?sxoq=3TCA3>;rYBM$Eg+@CKr5Yx`Ck-*A&!%GihFrWQq6tlU}=}{9ZWk;Yu zie~|cgi+|`_;tNtTtjw+#Z=H|Vh+>OsYcJn_FtEmE;^|27*?&J9@l|N^GVLZY03-T z($dldH_F{}`t6~p&?LKM**k?5>`g1a)7bZqxxep>S9W@3z<+*vX@c#3dkz^sOFs)H z?RCKJf(o+GJbr3Lcz2P@iFR=QmSX(u`eu*2e}!6!)ytz z`1tGGi|vd?)CUl;ST;33hn^?u^+Q{NM(kPzxoo_4N(%aAc7hhD#~M2l3jD8&{~b17 z8H2cOUKx$;SJLyj7sB1K96ZzQUC}JuW-E5d6BC-R$L+3mDz|pCa&x6B+3D!SuaAcn zD;|S(X6tpXuaElWXCeJ5f{)L_6B0}X&EN0yI_@T+J$_v7M)}fembKw(xAy5?hS_+L z(9zy^S?lm!>_dFX5WK=#d%{A)UsXBl9bc)~XlYyRt*vP+jVdsUI-dFGy?lF+{uBj$ zh{8>TVE5O??VL?b$NXg3%-UzUUDjqjcHCbTg#j`$c-E7&Edlms+-Lf3=V3`t7f*zi zThfNgj8)yc^vz(3+A>uoKghLB2xoq|b1YN*I^JZeQB0s?U^dyMb{&=sT?5@pl^fp3 zdkSru)Vn=RSPOR@_!@pDS1weYIRV{Edz|8TP~UKAKsic*2Kq`s&dYj_j1E3365_f^ zXw^cJ;w^1KaYFSHXQiCHy}6xD9S$2Nn_>E!BC_L=LVK@Pj&ga^1VjGF%)cED84h}- zVBPCUPwEf9^u4s7U;l|MOi*54zRUEg9ZrsK)o_umfk;BS7#I++UlmFr=(0Z6pTs*n z!ksMWs$SMltnWtcEqMLGY2urKO}so3WV3%<-;-@~bF*dPr~gd<@^WY7Vp+csSAkBA z-PZ*ng(R@S#9E?NgSFz9UnOt-omS(GTT%pFTga^H7SxnBW?lEnJt*zGP4wMQqR$Vz zIa;xWujkczoBc4{m*>8^xcHBlUD_3IO&MqAi$ZK{6m5~w(No+dKP6+j+JS6*7>Chv zTQW19>O)_Zz5lxTjzr`kaj@yicl`Q5f$_7Q44qg`iv&}5S!~b#AS{Xjf%eDPY=eb? z-Mz|%p_@ak>U&=RLwDIH^K~-mBwWrp=j2slzWO@OY+ptF`m~~*!c7=PhoogAnrIL@ zfvc6^N%^VRMKwqAM4|IdWV-r8{~oBU$Y&x$U5k)(#m()>|4U?VXfAPLfeKBxV!bjl zAfZ9fdY26al)T(r97@mYl6H!B@7{fKHTm#ifH}J9X>lm?{|HYdNMbueW+cwrm)uc>=~cZG0T)#{-{5Dd27Y{SY{7Y z&%#1zpOvHd$XMiK{j3<700!5htz@1{Wz{ZU@zzcw>J=({nT~}k(hKj?>G%`>yL49X3lsP}Oy-u+jzd!tTK4uxsS&Yrh;tL&NlytNlR;W#IC%(N96ScutARc2r8YFGVF^ zn>C>73O7!fzwEF{BQ_kj3eh>Q2Yf}ml5XFcV&j&S%YwIqD1KT?jVxBMdE}yOtU%o_TVVXp90UCQ@kjV^ zsMFHGU|fXNFMa?iTzwV zaf*fl`%t|4*cP^D73hcaqV-u+I)JI{ijtdiie;7~vK*Vf-^_nJ>~B767D9%1Z9&VA zLA9~bUtLZZInHW4MvnTmu#CGNy?b|J-({Ytc_z%|^ztR6sY65#Pr zHtp{?a~@ZP?~8$eRQ@E4=_+tGZJThi)}P8#urpSeIB?PNRZxf$%m-wbuTVw7lPJsL zErILx`l2F*$|8%Yip?jVslNkWFfinP4rHarv-DXrwT@e-=-Ak?X677L-S1mN=T}tY zIx<`4UMMNqEq}{`zCGPmKdv^IR4LvBfc-0yB00bIFR|hvbhYB#OuCs96WcZBF}P-> zx@|Hh&x=o=c5AwC^lmE(Q@rsxqcRf?hnZNqAMPas=+*zp9SyW%HDj0+dtIBo$-Uoj zRfo+gpOA?zR9PLkG4CH;DhP{2cCC5D@b6jXf=}mB)b00rG zX=!WQ++CP7PA#{igt~0dzjg)kgpcyauG5FpuEm>>^CiWxnj9-+Ki})8UfxLzsow@< z1=&8F=RxZ8x^+u62_M2pko%8Y;2kP@itPqs_Tvm86os1nr$0P;?dkooUKUAr^jdrJ zd>AWe+gs+&eOlYvmUoJWH{AAzEwVUt-+YaweWnz}Goo`zM(y`KP+gvBQ&)Fc&7z4* zQ3uTNFGIw^zOTCg=rN0BQ#gkVR8)C#XF9bGg_eyYBdR}Lc&k@$&gRAoV(SG*Z@2XC zIMH&?9p*pG);VXp2ww01tf@D`k;>0j%U5@yw^0eZpbX^)E&5Y>3~Xz>e*Jbsh!t8l zF+vf;u4igTY0gn&EVC3kU+xXLFHBD3Nok&e&-0McRToI{E!}ptBvKd5#+}q+>rFB^ zkISrzPp&32YPT2c8L4T6pyjuB$o0!~1S>763dyPlSRWUbO8Tvx?8KKp`Q=`9G8m4AM3{ zfDDsr*_b9)pQv5(VUVWxvR~**4jCEw!`SiGxZ+uzv$L}YF1Y4mHL=)fUJCm8Iu6@y zgC7Wv_l*D>l|5UC(XlkSy_!dQD7?=Q@*`YjW8*cAS+D7!`=U5*bd;S05{l1SPj#MG zMjcyXG_`L|rA|W%ELPTDaHhNK*bIdAykXVXupYDP+C|>KC%EnHlBtPSuX$vIrr->5EeVhOjGU`HqH~G7FHZ%x}E7f>v=8TIA!^I zWZG_J1lt(QGQ$D0c47g1QkA3 z9%**N42ud6H>jBd@|^t@At9mjOip&TWLf)Ip^lmvIhMZ@Knb|Vg^vfsY(n&r;ZGHk zoLYTec6N5wa38Jqmf6YM+uLjJEHBeu&7fXIdJ*!rcBt-4G4t6e9W!zedo?xn;xVp! zt|e=5!&J|^x`S$P$;NaV{Mnj+s*MlVmJYoR5xCttv7rfCJpTrvtajTzog!>Mth5+S zyiQM8#T(A4d_2qLDva>}a*7S2523KA)<11~90UcbbDkMm_gevp(7F2Sh+S=PcG#bH{h}9RHzp8 z_VkSKXJHPU%g^W5)m;M{U1PUlGx`7mWQEEd_kENF_SkiGKB&U1vcl1`XAW~v+?fp5 zNF{3`ESogPmaIl9cm5>afwy$LGlROKVwsx3J~#d>R6i(6ljIC za}u%Dx%DjI0F;QEf+fEgACXOaV*aLdr)>Z32d)?Gg%FcV=Z4t(O?xqMy&5M%1!kvP zUZ30l<;HaKK`*e#Zn$0*oz(sq++X-9f0kcRFtVeeq%?1zIxwJga5AoMcFM%Wq+Foa z=uy8~^EyW%ep(nP1j+d~RW(zIPTI(@$0oQn^M?{G4b;m;L43}_ zD`z`gLxiqU$^o71>$4$kqY8|RLvX2 zy<%S+6oZSK;`%Qz2IyIt`?o4dyO(Gndm;smZ@^mL_rw7~nWvU-clDS;U_!OHr$??= zNcei+C*XXJ5_xTT`9l!^#8%>(nsJ>s_+a!$j|K}TfkNwo2_MV<{Pt>(`)YJ#1Xwou z18;9}fX1d5G$;_FuY>IZ`jO$KJQk`Cvrl(R+!WJm9bfAyt}W91tO=IDAmrv8p>Nz1 zd@H%+Nc*xtW0dy+lEmaBSBRP6<*|e39027KjlSM)iFG`uoN7;Ii#uDQ?_=iyadvoQ$3HWaXX4V6kzs>V_Wn{_5ChR)S z|3IAa0Dw39>gH{SB;b+7?zP+kBSC%bz5U_bI?%U}AeCfU1(w$*2adm2bB*olh&Vk~;%8kK^BhzgIB77o(6Z1%!W#L?VN|ZE ziK&K(uLpR=n~=yG*i<9Ed;ea}4SGs+Qe62&MnIr~ z9lN}3_sZZG%Qv522g+;qQFL_l2uhFhruT)yx94IH9z4*6&H({$F~-8q9y34x=Hhh9 zs&z~XAa0vNf;Y#*hE^@Dt!iI?C_6h>_woYZjz>YUJM?6?;mWdvr!9mGGQWPfZgT$+5A&zlICsos;2PM1_Y0GumJMxY zG()SplQA93LXM|TCE1~Mx%oLz*Y!02mNBQJUY^$e{{H+cRV5{=Q%MySm1uO3#dOu+ zZXH94Q*#z~R7}jT!gnQ_XdvD+%cZsmA&b1|i4lTI)0sN=#8ITvdSVVvx%u2li^`3$ zurOzT9kcZ^qmm-^Hz%7|YZoZU9mzQgw_FS-Lt3gB#a85Xfk8G^w~0WWf^x-1-%ho@ zo7L5?viigeB&xookQDTGy}%#gD?KI$*jT4vs?6^-SC*CIM0ii~FtlH84(qt?waJss zoXh_U3V_wqE5nf>EN|_O@>J%fLIhn;13HatG$HmE7xO;Y+hdb}<~wC3;I#jxic=B} z+Bk84^6bsW39`ti@_8y=84ybMk=?rD##?PbOijMLcHOJjU?$The*j^3996CfrC3of z%AC~-dj7nUuFJ1Ry&##O zojwd%sq?EnRRmFcv?f?8nhF^Qj+4NTSf>7ZRX6hF|!k+*IW+V}i1d}L1paK+; zSwJC|Fu{xu|s=^ZmO^LF3Oc3J=TBg{vSN_d57XhgH+6SI^3>JNrw zIWC5T&cACve_n&Sq{jG@fM8iA`HQUMQPJU%y1fd6BB$iM)WK0?ff%a&R)F;G!q6H+ zD0zPVpvlBD$`7g!XuvajLtz$JGvxv8V{M@8anbwOncYG3)mrA-D6=?bk*| znMBP8cC4D;e&D=H#Ai?l$Vlsh&LG+ok0diPGe?X=UFDNV{rvop;ksy!aosZZ*ozE` zNnd7dYa}Dm_e_Dr{B zT*l4KnFilk+sT%B-|JW3=C#Y+00&w5kAq~&C(|I-!1AExra{xro0*m#d##@ZpsDD_ zo1S8Y^hUT`Q# zL`4y>F*@+J0gld4ZaPW>TlNmt;<6B;D{kgzV@`Qam{pcw*Q-e2F z5dWfnLvo|cE^r41@uw3*ft$9r-paY_*9U(-*93m>Ce&m2}Cv$HHGpj@|H`2AlC| zvPn${_QG*j_hPqpuO;%Jl~`X2Ncinr+Y==j;3so#MrmX^C}_+XXy{V8m- z6nV0$jUG4OFOlI%8pZNvCvWOBzFP9;g%E1oKWQD4!vf4Z~np|H6utuXR07eye4 zqc@W~^6-s`2p6M2gahXgbX;7or^$hImG<3axXsMW{bD6Hs}v|K)4Ln=&Bh9s> zMoK?bOktgU!d&Oj%~qNF3mHB=@KSirYyrN#NJF^$%xJ!&-zb7zQE=mcVwpntsq#!s z%?bHXj{N9oH#6TNEM@cjtr^>+c*pZDL9S-tG>=ncUg`$=H7s;xTI=jVI2n%=Z08qL zZ*8a6aq^OtVUOZp69;6WfeGvR^#-%zgdgFTiM4wTIv(c>sMZeG0Eg0k#_;mxSiTt> zBV$;XWR5~|QAf&SvX^o~SKDRGPryU9x0hR4nVI6#~pmtvpZ-zbl@9qm-k#q0%J*)j26Q+}*lf zoG*p001{(ZdOA%!uWk16-kiRum{@%kR^0UsJ48k z1<>vd-6eL*l>2WK>(tArJe7}Ht*(aqNIu;DhCf`N_zQ!r%I>Pq_7LFQ(}k0}_E~a~Hs>~LkmA-ai=9%P&E*L3PCc4%iJo7H1LQevcK&8BHQC~y z%hIYbBO+8zYWn_s|MTUWp&)W$PuH$}`e*yRX;bLHo2Vg@8B1d)CnvX)=m_2!4K_QsHywT3qxqKq zG)9Fj&!aUdKaG4;sLtZBHaMtELP6o6h=2oXy+J8jYRtAXTq2wESn~K|?2Jr&kXrsI zoZr#WaRv_o8B)^LT`ciZVWwfnL;4>WLWARgcDA?ernT}%r#Xob(BRC8smT+LYil>K zg(3PgSv{_r0|I8`u7+CG# z?X5?9h^?({{Tu=n*jxM|WE6s}Xzse@U;hlYn>6)L*-ys{7KN#@67lcygTd=J4}nH7 zI!ETT6?mv3S?}3%;p?g(U_V(QNXCFTxJP=7em}B{$IeyF`1!l=7AP_t= zW?3orGEtDlQ51&!XOr5!8FF>m9j7bm>vueW?y5gq*3jT!3o$XVG?lL{T`M+<_ESI) zfTpHqKy?4w3^vde_h&y_6Yl-6f3(W|c^6yMNvm=so&> z*+%!Vsi|qe{AKOS=g${zKB|5lHP!RP;NjtMt@yoXZ`PYXFNErZ*1o)I{(j~Yb^c`^ zIzIPt&&q9W=RY@7qyPauLiUA9j84K-YDC1uwYNkspM<1X{yyMAhWL-p)xJzjKJW;` zqa>Q!yCnOj~eEM!LF{9WadX3X(du|@9)z9`%KGgZG-4MNkMLoH26Oxmc zmylCXIK4S7DJl6@Q9)$p;_}Nqkc5=<(TU3q<%$ijm3`1P1qmf3wydmd$?eu%#{3*M z0>U_j09tpW;O?)B&%}3?AsNLn&Al8#p^ToF(wA1g^Jw>W{Jky65Ituw#lvR1k<`~W zcVj%LOO=#54U3g%-Wekk6B7aM`R~gn&!*Pa*7#>@RK8Ym;QEO!=r`iGTl-e>33^~h z$()N7c*H6 zd!rSFU8SlC*+ENjLJzMSzhDE!Le1^_$H;K#9Ul0>H&zU<3=t%Va|)L}&NIY0BrjTl z#T&pYMdkxY@xV51Ly01Fll<88j78fs{lTTkU8E}?aqy@f;Y+AKKzzuGOtTg&E&EIw z18iXa&6;Xw5hYmqy>w!-?QGp%y=Ncq8mR9`LsgmEJ_ll3>$*RBo}ZVBbS&t;I=j1( z5`VO{baZL-!6n%|{}&^}Cm~v45?4JT3lANS!PAm!$*cb5@uzp<9=}f0+(wQ+xfyS> z9Gc%m9==(5@>Qm2`P#kJDQ$t#FQb^x7e^G0+P4`Oz5U?l6rk~%V-V~S5fD^G$T~Q@ z46-n4@MdRh${3Q~mnr(Kq`o^%huiP!Kvg zgaCg0L8gQVzMAtSMfiR;eiwVJ$bjZW7s7TtAt?};dasA;G&$BexNE8=T$jTX;R|$;Hg{@{~ zF9EygJx!H`EZFri0V4u?1Pp?V0bwk%FBc(dy{@jV{^jgc57nwLk7wciqSSuv{OmdE z5x`_(m|kZy7OQ3aXWC&A5x{&tmP;up#2}$!`LbI1md*qbvQ!Z<*Fj0Ru?gUeAc>E# zk!VY&TVKF71n>cgs4ZE>I2;P#GqgR*`&%E5rWv+jqC@m)!W!BHoi$fIF9T1nYq9+@ zCUP|=^~-cReVUb>K2j}bFCX6h@?;%lQcKc7hy3MSVXi;xIf4P#(fJ`d4xAR^B(oaL z|L{@)gbH3>UWB_4;mFn1_mg$bwm(Xelaqf{V^Ru%-s&0L-QGk*N58ujAc^+5cq2bv ztRFhQlKJ-}iqKx83c|8^ne)%~*3Asd8*oJJ?6 zeqI>F9`viiwn~NhM^=>RkZAYrm8-XnAvd!~3jr;chATdS#VAR0lp(cDI+w+;3Ys$ODh%;5kV&;MB$gu2#RU)LG7+{K6>CV z6bJA~gQGVdSlM?Ib2Bp*OkwN9M~SXL6cQ*o6}Pmyy?soTpP7~Q%Hb6Qo!vr{%bP|` zN@+Pc-(zq4=4z^viblp&Z998=rswuS7U}8fRNjowO-)U!h{pC^49*3DNuEDg^P+t! z7x(c-1)L6B4qi3-dGC{cv_zOoM>Kx4=`3;6b(gN3jG%Znkb&@> zkDbjPrXDOc1Q`XRQ{jf*n%aD9=*9XI^>>9NOwQUPM16oaIe zR(u4p5k`?8dNFbM3+&4^31wwmKiab|uon!y0iZ|J_d%izrn&bB-!tsrTld#nGJ*2p zuf;;O98A2Vp0npa$85&E4~O{ivY!gt-I7GQr1lDdT&(VlYv&X=l!X4=uUGG4BZXe^ zF#jDLN?@DVXci4-lp;Wc_+|YGlQg}h3I9%vTo`DRd?(=h_&Pa~WOQ`&VXw~xZ`}Fv z*v?d?4$)!8TO1?*!$X@JLyyQ%=_0@8j&Rx=Lz-AuA#9-9Fg|bf`H(?I%g3j^f$)i) z%d+Qj%CfGGj@ct*tfTSfs4c$>GhFHM-o8EsiB%u4#6kx*Bgj6R>~HiP%z)UsKcc2v z^rLOQLj8?C_sGBq3h5zvO8K(hl8KD`iJOw4+u%?fHz%;@>X(<^oW+k#?0;FmKTXVT z(Ng8)=()hR z49iwoxhHrFETv+Xu1jtYjXz7RaAy=#G5cAj|BpRQ&CQSBt}D6jSm5L1M;p#4VMq@T z4SlO;XJz8su1IeX*`SK%Airg%yh{j`z=f#T;1V@RU_b~D7&f|G3hyE>n z59+w#c#)nZ8iX-MRa^jxjyQ6x`QvYQVH)oRI^9^BwOw5J{AhVSI=bt$b+%#!Yka!mhr7;s>1kr>nDOnqfyfG{(XEH5EuJ0UeE-Hig ztFMQNucfPrtRdjT=$62>LYnR!f?KP2r<$SGt>ON5 z#>G0v%zTE!mLtiMX~Czr^`ZiIS16uGD2-aoDW7jzY(0aV>PR4Hei^QVJE-Jb)Uzpk z_A-5`!W_V&B6TV))6O-3BQplzot#DQP}y$RgiMC*Aj#bY0Sd_=^V zh4mOfmsfieHu2eBoM*Mo zN|0`&2l-y4(_ReF*wzL7{|W#APGIEOIqRM;TUIUT5b!RHZK}?>OyKVN2u%DSh1hnr zC%mpsK%?(7(5-OK8@6X^&vvT=wg~z#3Q$f%PMXRw*ZLB;&BC~Z&SoR4e>#8O;KFp zc{!)kiVW%9NF8;B*l+0Z*piR8-pc--#K%PIxEB*KMijU+ z%<#aM79C>$)dz>4syOrxi;wccLbw+8)Gy=Nw^H*!NkdX4JP88uxmbYeR7J|-*t$Q+qmZGBG8%J+MuvR}4 zUY+ehaO1=w5Y)@(I)C%4kBgX%ag3~0XGcxt697GaZGzn17%`qH9f=vH8?1wYR7AX5 zEJ3Hs19;$8wvzP1y4QqeCh&a@-p=*7vfjXc;gODJ)FwOjB{CwHnA5!Il>8XAxR zw9W^Q8a&yBx){R&aNa!o1SF`gplzVg4)b{XpE=tUJ2NUft%|9^*jS-N?nMt4*oce z@!|NJ&m=CXu7%?deEB#Szd)41=*#6$jy}RVXmI7kL%lC9Vpw6Q-wMg8h<$YmK0fpI z|LU8BkL&|WG&j;{jbDF(#U z@vEZDb^~-fwK@C>;3Dfk7IIM}bxj*E2%X zbLZYHNbRuOpYIz?6%${L6U)hUHMuRIwGVqCp_;EatoD#f6g{(MV+1k1DWWo^%GMFl z{&_%v+l))`!h5Ss9uXsXRICqWFKfMMZH(^=8IF*D4IRjUeb-@kvyOC&Vpe}68C{J`GSY)nDN1Jv1EP?7Bcz zV2^+wAO4Bnz}3-N9@qWYkG4`Xe3r~Nga7Cx5^t^8(FXl@(I+_YxWgpv#VV3YNQUHA3bfWdgzNejlYQj*#%Pa5Q{Hu&p1G@$Qx%reR}BL)Dj2kA%+iJ40ld{84j<} ze?9&{3Eb7!7qc~9Oq((_?-Yc#fR^l*1m)5tws--yUPKnBu5AvtnUR;1ivqfMc?sY> zjhPhqo-0aVB2?3bLMKK}pl# zBslwJ%Bn~gsG{Cz+dO67Dg)5+^A(krb^PIGl}?v{=frVM)KkLzw*a62tNvW*Fk0

    v%Ej*A%)()JdV|<@y2@I=`JSMO zAD$F@>TTFW0s6YBH3Kqj;{oGH(_B19b=-HNReg@6Vu@vao{aQ#BLFVh?W{6j%Uk&L zDUAg%ouWZvczXTfg_?=eX(RY2V3wopkc0TSg%7e0=WE{0xM{FV2{*So?ciaK8=(&``z5`DpX=IKrE-r=@X&KZwh%Q>Qf(!%?9D&Cw$|I3{X*2dHx5e&}Du6_9 zubxcF@T*pxri!c#-IGQZ=lTgE(V)zj7}19C)1$R0>-FHsxMYB4KmFR;s#0mGrma5JDCkUzh(>p zXW|*@hgcv+ppl%>$fiNK$j>1*qfn>P@Nt2SZy53*mg0e0P4)8fGGJBG%71pz%+xf> z`PCpP5J~2JnDRImvFHbGQ0A0zjMgL5gXFv0GxRfGTB%optxdN=Ot}3a&HSRhz25xJ z*T(PmtvxlL&T8uK-&Fchfo{yQoG5y6`#Xddy92!F=o_Lw9H`L+7%L|@&0?jo474=7 z$AFyIHa<4cyK7kN+p32$rsM<6Jwx>1TA37J0UNYkw_Os}P*haZexqOSqIUnZzOa29{C9(@n-Tu8)Wd%~-qi@K1u z;pawSb9iggT)pK&oPgcBlGM>RBk6ucH+B}5t>=ATU+2IS<`<+(Eob;9OW$GeT^!r> zil)H*G5`{rQC2%$W8a+yGrIjtf;yJk(*N2)N-liuMVFoBN5>K(d>F;qV55!-7>M)o z$1Us;WL+t%uC0khrp*dw>OIQ2l`4+D z{CWP&St`&)ol82AAFVBExOM9FSd{*GVecB-9+R0l_7DfP{%p!Q(#m;z>cZa0b3jn~ zEqnm8ddBE73D6~#XZ)rkxk{faq8}Xd+OBE}jXoC?)Z^shD$&o6a~jIjuLB-ydm@az zy7uO!cI)*jWuz{~iAlDM9Kq}J;z;4RqtSc~K)=R7KPT@*(#1fri&LR{{LT63y_+@M z_Q4t|-LsALb&)~&AKa|0tl|PkezZTwny>70vZJUdgAb-G%7HKQZ2}|& z8{sEfO-rC&ZXK{U4k7E^94lderqO{D+b)V39(5+58~}v(;ThaXQ2h(I21xt^?)ebUy6%P|8?<$anW!pM$)-ZGcn~1sZvau|`j8VJaS?N0M{_V+u|Ns6fcc=@To4>8VF zVBUSq^mhM3pFHCZ>VMWb%MMC&#VTULT1E6Wk-|RwMuL4Id)6R|xK`o5&|%|FT_iE` z9}rPTH}+4CqO}k0gy;2gvga!sy8nq2 z6i%jZjE#+d6wzpDY4M@t$^=(bREYTPbU83eeLEkVv8n}x^h7@Fhs!?KASZGa>kL!LdOUezc6biRaw#8mM;b8sqBN#!D}D2K5r4U+=?rm@k~b zQi^)L$o6PezFza;@|y-&CdcB!grNK7_rP`}KibDZK|!o*R=`6Rd~<~Jf{#@~9`G5S zI4q!zM=HHtsCh$}ljE;9Z=2t$X%~TRatHJulm~n58S4U+pIS&|_qSYch#DqWEP1UB}%Q{H~|w z%kB;%!W;wk7*kb4Aw@X~B7j;8wnU1EiZbF>2s9}7l={a02;!6+Zg(eg4|Yf-b#B$E z$ecUT`Sr);O5g;yQyq_zHP7qtOtmP;H(2JakP09&TkeY>-Aml&l;5PaLgzl*#RvC4 z!S4ff_M!QKd7nS>CGxrQYoauGG%)t4SCDbN4=$YGp=NJ$~7sQ9)&A~{j9DYoN)C)6T?E_#KZRuiFTWo2=`ZNnr$OD7TS>h3;xVI>Wm z3jt3YyLkl}z6=ZvjSUXQM3dvS@OQA1bwh~a2yFy#35ypHj)p9l)c zeDCt#kj(HF9Oi!gI@o2<5`e2-GGN^l1M}U*sIm3(Hp_QvZEXec_#D#_=%4)fc3?x& z5er~zU)bW}!o;j_-~|+UhOIUBTdZ%>Cg!fozrcL`gXZfAN(w%XaKGy!=Xrlh$AMhr6qtE9{i~pckm5x0{M>3!>o(L$e~Hj z=P(n7%!lz_34Ceun-ATed8U+7<~o5;D&V!9n%(3RRvk9&fEE{J$(h~nF#c63F+?c zhHoG5^?l#*jc@$^`5fc^;~3ZTJp0*u?X~8bbFOG14BE@Xsk;L0+GKtgSj$i}zd4za zdx>Y=I2!mWrgV|T0p@lA4~~@cWXL+eE-g_0Bw0G zIK3U^vl}<*8}f+f_~F94g_Z!#;{AyM`cL%P38nbBu-Lt?m<*JI#*g>%orPbis*b6N zLR*~7nd{}uW#2x2{223UIce^ix?`$SdjZ8Bd+485jBU`!uww2P4#_~vDQcWAE}D}A zsWG`~%r7mXVI=Ol`u(+gV!?3e-Cmx_z}I^b>vYEYRk~R1T@4+)sl!|h3g40^deR%d ztUEEU`Yofgk`EN)wCFa9b3YQMkPgk#Hdkw=C{l&Vtae9q$Rdod^gWuxDeSyjLHW1C z380vzjtDgMoG_BO=eS?#4?ZU)#q9(>dH&tP^dw`n+>JG5-Gk!b^h+sN!5bRiNPbAs(THc2r2PYPiimPd73% zGvmoqR$0jx0)RxZhD^*whRE?qCuUt;sNzb({?HeLl-6b3E!#e>U(+5l2BY&L+z+pO9C zGFuBLfFiGYl+ahTt=hH+lIRKsFNy3Z`vP~SZOV?JV+%9$8PnE&Kiiv zop+Jill|J_2z?$a8w%FV(w9Yzdl%R^B zd8oy(j|B8br)W`}Xn{j2m{S2s00NqdCL4UN?8Z#W{IU8+@-Xj{=j5F7#|_$B8BT+Vi9WN4l}V7;l6hiw2rLf;LXPXLKY zUjLJ(ZDTzrVacDn4h&Sr?S^0YU8b!hlXPf;cZ|!Nd)EsXMh<6!-9$Y1m*^n5V43wz zB}Ywqt6N@@GaUm{^n|49j2uCc1!vL=LJ-4CS0Kay;%Y$AxY6ceht@ zJA)xc8^f8tEysSy7~fFP+M%jQES?9d1zPX>|9833pR$W}%WgedjMcK~U4ov4RT_3a zk#en(lT|$w9jE-yQV$;V8`FJm88S8>>WqJuPqO!}Kwx2g)WCwkb2S4*q`)cX0gb0( z#G6u_O3;?AvS+0NvR+Rl)H~Dvq+=ABl+@H_ouKEHnD46}y!V@V`UMx)BsPqmfuVfu ze!!mU0bE3tVdFpkp7Y^HzX({xf1(k{QmjJpRtu2=C|2|zeK#_Q>?HA;4o8ki@Y12h z5U+8+V6Wg*h4R|W3%C8dn~8B!1D@@bU7MZ&KlKOr%v$gMY~iqf?($tf@+VX*nfF)-wa`#BW%z@&xC|DO6>A`A zQGp=G6-OL+fVv&4CEo@RKC&pqXi=5hb$0s`?{^>&^#v~pt?=)r3 z1JW6gE?X2lzMUilSvWwS{Q@KfHhGY#mAPNoy+vw0Pc|*GL1YtBzpXjML|tuVh5!Nh z>$h`xe zQ3yw-n=Wa-17%MNrPV8oP$iu)UuVn-t;12ZsOi8<@8PcAsY;{$?8Ls_EBBNG9-SF9rW z%KG}59bfv!^YeoNtGt8+LMmNcT0&M(ZwQ0;1H>RKYWd)=%b6$2ngvKTm~C4txRyWJBqHPF6rVVhG#3F!$LjdU8$vT?Z5c_g`U>YpCM<)5Cf zF?OJN8K?`bQORI}TztpQ>)aj~O7+9%_NM@CXUpG3%_VwJPEHkWVqU~adO~32z+HjH zXV?*5OaYmoZhKCuvE|aID4>DZ)Ay1Efr>~p%Ll_gU zhJrq7y!~bFPvIU|g*+#@z=04z(HRx{8@HN$Q%i3mC$J>C+uiN>r{~tmP4QgTe>!sM zMZP54`>l>mqB9j0T$N|p+vb4EQDJCoWTfuI&T0ZL-v32}DpPxYERRl3_8f`&0Xh0b zyJn?TN=&wk28x~*nhp!O9r2*;Bcy823lLmuu##Ga(8gM#3tIvQPZWjR08~Oc<4nqy z(&ZGCCJnwuBHg9EEo&#Qj$!IPnq(pV7Mf&0v8tg>-ugiEwKBn<&ylZFKUqRZ&cY(s zIH-4IvgNDqmVzzszx`}wW#zIZ+Hs+BW|v?+0r$hgJHTU_Y*8>V$r>euFx1%J3lV$C z%0`NeDk)I_VvPsj%x40{u}Ob2UG0aRk3is&!;>pa{)kL4ARU0JdfH)weGJRU4WRZ+ z^t$_s0l)NkJ@-9;fORXSl8TH^R?d54mf!-u{<6ai^hRBi<nw$>AbK1HO4$S?RLV!wgUTn42pW=h+7)PQ!V*rSMo>x3J^WI_; z*S{b@Y%^bVO z0xjpHYcEFF@tU4>1sVW#aA9!!01b5g?4MKx>0?N(6}(hmi>7AA^I0HiMBhHt0a#a~ zgMonotgj<0JyyW7^Ac9M!<|Gj2YS$>k$#3j( z0ZW||3uN-Aj3ASLndMn0L=R%Tz$f#R&Mr5H=gA)-8MSg>JnIHz z^QpdDgpp{gA!ETNIcpeQ8t3QeMX_MYx6KCAb8%tg*)Fp;U%RTo=>tV@V-aKEJ8SE4 zm=ov?g5d95WxiRkV2n$d8Hk>9;^UHGY?$91mhX2x2A=?6 z;08@>EREMCrvi#jPL&OM22xKzpGp@ERkA{OjiQd`ZGkulC%mwh=tGZhqtLp@Em>!3 zRLRx9!N078U3@+#c{J_0>Ewzm97&qVH0y^Le=&<^0yq6a7ZRLDcKA~|mG(dW6B~7_VJFSzzIvE#}awxrVEY zGG(xn_x;;xfGYh^{AoLu;!FRa^YV<;zL<4}Hz;!>ZH@ICM#pa)m>@$1@%XcnV~1>x zQLp3iKQ(d2sJ1@niD?!CY@DrMwV9PSSu-L<(4$6`7;r(W<`kMzr|@7v(w;Tbj;Ae_ zm-%2vlwdl29c7NtP!{UCnVZen`S>Y2lMH2d26-iuR+T)nZUY2m zCuj}stY^nWN{K`ww}7(OY1Nf>u4PdG?;`m9VSIEK@z>At~4|By5dVkYo{g@@<8gvZK z;C)MQ*@NO2m-qcJC2k}AS0!O!3{_<>yhdm|CsQo1V=4 z1T159pmNvE!(&kW4Fks~b2;$7yyIIM-&7fpHv#rc$4QHKd2sTUiM@U4u;U}_kFwzV zJeDrQ7riZ2bPsqY)c;}aHvwqvYDC`HN_X)HGnRxO*%o^&po{=gH9>7j-qN)urb{lx zsO$7?^5B^l?_7h8Lj!4!^NMUJDpOGWrGEH7VM<0u#uxwM8wzwp9q??5wOPXrT*8Xi zaWkk?=Ndft^pZh;X$l`E{QmvA?>kA!Ame0UYc;Dnj-KLH=D0OBfd?BD;LLHxBOxKt z9O_=}BTOgzCwTdR;5GD3JS=Y&Bh|djpzn*o6ul}6hBv6 zrr#o9lslbp^=7veQhU%Zm5v<6Cdi7d(kP$e7AX@kYb6uW-3FGif4K(gsY`0v!M z-a-$lE`8UEDcg1hS&*ZRzx+fK{9uMTf$XkK{sn41z%xP>vX;t_w^WC_eEn>q({(yE zHjGL#NWmk2yoB-%zuJgn5etaa3$$EZ`0aJ70S#nxNkF#n z6A1Gy2+%v*+mZSnoLQvReE|*`>K*F9ENF-P!+sl%oYbpVuOfMbUx{{N{eYfdn`Lth zg|RdQ2R%5hx&vLowAzoB3-6BCheSF>?*R~`1QJQ^v9(M0UC%(`Z#+Ct4uqqn@A>5!e#VHjegSjGTNG zA;4i*7nv54d!55tMR=%D>^!MRT8oJP3Ewn$jYXwd;zui16&581$_vvgX=P6>y>2Qh zO@KoBt_>zy$wC!tC`Bp`9(IvYNbpaU;vUH8!!qCb5jJ;v)(X4d7(5^lH|d<+@I9W} zgqkmOiQZmDVj5h#T%;JT*)=~O+TzpQCo=B&08rHc3a9nl^^4r>FCRg{k1K`D2<^C8 z0+hg_d{8(#da95PT1;1AVZczJK;xqTl8|RFkb`k1#kb8A8dpq7wUiEcIMf$jytA-C z->J#-4YF3Bl>gtHaTu~*fs2|qrEY!TC@>Wq(`?(Y;1hafh0B3;={$WbLH#UyqvIrw1Y@CmYq=0Xc zkxE^mm6N_Y57{fu4r;1y-vObcFpkrM&Sa-ii}$LBM0I9(0qI@%FxqPMx>=_rPs+@Y z_A@9!fjE#KNQb{E5@;aHf8z-l+OgH&U+4bK(50L~47&dr@X%{Ta-NHk+97VsM}7YM zZ1^0|iVVVsn-PUZlKzd_zYP@w%-P(}_iLYL4IYn&;zh09AMQbA=&qDh;}01L z)r%`dHz@aQS>77Yd437s)vZpN^DHygz#gz3@TZ6~Rd)GF90wqMe|e~xwKaw`itx}L z5T*R#hys%V+`If9rc<=QgT!yy(BCAh&&_=X$l$*kDcS~F(hAcSrNP=OEAhJc4j-BY z5GgZ2KT0GIh0bd_eG3ovgAMpY+MeC6L`xD!16bv42T#|af+dGt_a?%SN#a7 zenr{|&20MK>iTV(gx=MiFRiSsq?QgmZGcsXh$&t0=X;CYK-}Q_Ap?PcMMv3R2AtaW z@81g)w1SrTayLzC?C!3WH?zz4D9|MQ&;1<|8Ww|;>hWC);zA*L%*cOS7~4;Bdv8k8 z*9I{+OY*ykBW)pPg!3CuCS9KD$aBEG@4zmlBh6{>3=BAb|ewLX8Zv*Am{0E#;y2D3KZ$0`{{g$ z_i;BDgATwIl$)QAhs#95?=1h6&$J&xu?7cM;dhRva5vIXjoB!DBESKKQD}iVNOCfy zySEpYpNwD)s{<5)-+tdW#Fad8pZv+!vh`;SkHDIbR?05&@Ni-L1U}5&;~VaQG*K{!tlHRrAlWNX z*=})yE2LIhyP!IpPd9~H)x#24wO5Q9B^jOkQ9pj&=n3coL&vEWEJ0aw5}faZ0X(Ca zuRsml5-n{mvLJ;tECW4zEKTQM{nZ9hc}R%_bhD23NRHuYaM#Vajshj@BGr?8{aXz8 zw%|rmDoe=5#{FE1dM_`!B(BGzA*ned7n48gH36*la#sKT0bu;u6Tl$U5CQDr+hXmn z2TCm3u|7v@vTr<6C|6cxwB{P_>of5R>MSZL0l-$YC;LtGCncH(umQ^)r@A+6At4BS zW+ETWe%Gj=c1Fe=f2WsbV#Z&N;V>$~eM87HYQHMgn)P~p9;7FKD7?GrqnH#R?%B z^73D?{92;%kMP*UQibSo1`6XQ@nPPTUUkm5GsYJi*7SoaU5PejEXaie8pK{2WDT)j zj`qhWL)W~X_lqcnIy0aA0=1MGPKvZ-kX;)$D?mfiY?jGsPn|Sz-9ZiIa(l7%91k6y zRWKCRExsVg{E28}NF%-tZikL7``Au!^@wf?YpSc$0@^}RJ&A*6%LAl_)AB;FS%d+S zoi2JP9)`bA{tks2AWsWj(?A!8)zqpT`$oaa7W9(qkl*emfhKG9Hp;H zB5O}+$YrmpOBJVwA!Kl%pgb(fKC8}Qw!GYo=hkiiI)J z(u*-x3hPrDD1qw-_x+K#m6?naXFeei`b~V=$xG@Rq?BT=X^EEc_~v|D1zAcy!oXX6 zFD0gB+A`FO+a(_rzrEt~L~-;WZ9v2cb~Ao0Mr;5D3!&_p?95E?dy6)}107sLpvvn5 z!Y|Svzjt*24HR~z(23LvTAW-f#BqQYzu3@bi^Yf9s1S_d(rwjAmNLM%-n1pQEsUPs zf+Zyz}{$yvMNjXIne*{xAt6#m$BNU0g+)qNh#@yJF@TvC!_ zJ+pZyU%gmV$XnQ(0)gR~*Q-#L7rrBp%=?nK3!4S?_8<5eugi|nHP}3Pf(|^k4wB(e zuZg$5e8N4+`w($WAsffjyV1^r-2-);`QXhY)Dx59539tZOo=Pn2(TPs)fXeDkeot@ z(PcFii4Qi>p)D#zgVixtV@~PwjXg8QZ404?Zf}3!rAB(nT&uiNsrnezeAg%AyS!I9 zGNt{MvR?&R{4UARk(4arJzZO`-6c`Jj|$yhsXelx#Gda$vsLf`4d-{JyVZw13>vfL z-V4BdHk?H0OB3c#ZYl7AD;{*r+=HDHwXzny|3#f2PNtPjrdv3=ct!#Z-CjbDmZHQC5ql;> z$1Jh8Nk7vo;UA$sD?Tsfo&E)HjdlB=Q%fx=f~f2=Bg35FxbcQda%x8Zj5z}rzh;-k zWaQaF+tPgqr{Vnis;WxfmDe*R{+3@mIP+5O&Ean(3nu)|T4xXxM&(TO;fk8(K;RC)NV^3Ax_Ttqid>bC) zXcli@%;KhH6UgLQ@N;l1u!J61rEZ>yJbn}Koo(u}40kh$-Ix2*^RgYLqf*qP+KsH| z?fu*P*$zG*W~j+PY=LFoG3?wUqD97`pyO9 zrFu>5mOVW^hsW31AQaDEJif~M{v8#O=^e5qg?IDP9&q<&*PF4$SMrtQkB1XAfaj8h z&>+oqxZom}sgco(YFn}2VkE2~{6u1lXobL#>mf5@tGPCR=NiQ2bX%i88u2X(rELQ# zW(SYooPGa%`O{DKT#^&mY!8SDycQheJ+4lD>^XfDc8PwU(Y#4+0z?lNf$(wG@~!y4 zn^32V0R7unOQJIM>iYuy$sJ#jcRTlKQty>^qkC*Cu%amr^q^|h>LJ*@t?(AY4Bi*S z8tUwbQ=32Rjv2C=QpF5>=6>ff?@V}ctVDRyaztn)h~crUk6w4h?7-)8Kc71f1lYid zuhD9u($dZChMnJT3R32OXFR4zb;B<+?RtqZxfD02TWR#Dlnd(`d!F__ZYbxz$iVn* z<;{SjD`K%vf<&%u%XxK@7L0jtf43Z7R)UD}YR9x`w#|iS7E>(FF4!YiC^(UVb@3W`J0&BG=9QGaQ zFXVUS6BDbS({mjCsxyvsC}H8{G2h_kXx!hayQ)hPXuUO!ubg?tRF3v$lh+;_K3fU6 zVE{t|yZPabOuzIWrU@84C@}Bi)lfyB?rg!6-0M7_x*fQIKPgnky8o%&Zg&kVuHdm7 z7`}2&dhd^a1)}6e1eTwl9|Z_19E~Lk?-C&sP8I0ZN{QC1zh7iK*f`w2IASIm*Rt=k z-SgOZjpR$wQG0oLc^o*eA4f!$eb=C@_i@%Yx{)*Lt{(i-z2>1p-P_WQe0mCA^UICw z>*~hqMAN|JD>?0JKLs`It;qy=x8}`LDq zDbn_I)MpQLQgkoXQ*$`1dp^uKj>mbh;6m7lfe7u#GN;%2U|I>x5g6ab^N#_L>9FkK zw)ibr6H+LBs|H6ubaa3(K;>n>`On3Z0yHrX;OII0UdpHp zc%8^jC1l>DvkadEh63g}RDI~;xtXRC!v015nkfFtg5`e_I?Cjrxw&k^vQ z^T*{R+-+`(ovV4sFV0o(srT*eE!(44V+GntshoOn2k2&n-Fq0G+xu)jvaYRfT9;i* ziwVGA!@sBZK>=$iZ%OL=LLey3N2B1&?{Q~9{0iD{FbI$0P?ZrN9w^Y_+BJf0vI5@Y zIjC<*fU$os=Lg4>7W@050n!J*2=3&sFIR-F8ZY}N%(-xk;lKH3vJh@oGX8{5R@bf7 z!MbSr+*a^*#e@m(!+W9a2FJ(8@W}{l-;3adYxwT&E;x4AyMO0q{F&I5Lyu2h>nve3 zX93&Z`PAjvKv5#3fja>{(rMw{bG#dSQzNf(Xo-;XfLw*->Ew0S6E5-715FP8NB6$} z__0Jmav{a2+rWRiJ3|CC!NPUti(v;~(o!cF((n{G%Dq8<@}vXUYd#wgIMYH$M;EiU zwgv>J7reZ@houj<|31nx!~bPE^M4!G{GX;XdSIFU`{)11KlJ}G-s}|+KRiT6{y8=_ zX5!gYW!J|!9_zt!y~^GA{=?tjY&u5++aD8B52lA0n_F9RH^wZaJ4WY!#+evTA}7+q zoH(lxJN3(tzAkTW-8>EkX`@ZKt@E!cKj0DYle*l`LWftHO3 z@5%woOUf9!Ztfs^H;qF+YW$^>5Oq60gqHwhv)ORP4)u<+}k&+M04kX7s=S*2Mn~e zUw9r^vWo2#R1lqWj({{2J6D3se6$0pZBsi+@1p)VbJ5VVb0#4G{tEhV7wv#UKFvE;W^dKy658QWw9t?S=qOaORbAjZ-^NATN!* zwT?hzsbig-octzFn~=VTW}nd1JY*cNty;W<2J3Mz9kO=JIO=?*;IjxxN&fX|!h~cZce=T`ErIDJ9=gM=wP^T^IbE8-JR`lfmd~nor{Xto z@o-%?>w3Apfv^a=Hl2Zwi44G8g@ar<4|;Gr9|Yy_Y^2gzHyUQ85|TcGgZO5CpvG_@1XP;snunnKNyc?E>m&q{r}29iM|ZdOmsdiNEx1?G zBUECy?P45Q7@+DuD{QzltGhn@xiPS@w{)?VT6q4M^d=cT&nMEy$H!qOlVq-1NZB90 z?^8|1B8w(WSC1GUHhKEE`FNiQa3MUN#5zdfAGz?i}jy$5{LB4}1 zxg?xsdDz8q9&y^m#Vt0bLKN`1rCXPR6pD?T!Mz1@zKs;Te5d7ku`)C~Y^ONO`T%rE zK^0JfTmIah2^IE+8otnA!M!ul3JE}3C44BtPgoDOvOb9eu*NfYjS)}wIGrfgYxaF- zW+pSNo9%^9pyRAR4erKP&ktaa7#FVmO1*Wsv=Bc&IS~g*0(hZP@IsTnK*5@Q^z5q3 zc)L*AO(76qC8#jFA_72*dI?LspJ85D&jlQb;0+44_rn>uTbXx)r~#rQBO@7CD(;Io zsc;4KliC6xO`HN-NgTEY-U<@&VC^-7$F0y1J^TIU=y_UXAk2~Za^-P0L&Lt9(O7;0 z%=?J#nBGJI>oxFd;6VSA_N3qG?bWxYLx(H1-^XT(YtVYziAvG>mIzDTmo^f^*Yj&4 zeD$P*5^Iba*$|zYFr1A#aXZ--F=(dzW~$E3uAe9SY(M$PLrYhelgaVySnp*0V(G)6 za=nVSia_zM>(Sxiw3Xd+@X692FA4bcE$8RwTdjlwz2r@e8Kg2P5OApIyKsFxJKEc& z#l-ym0|QaHxb&86fENk~pPiP}5x@WlY6c0fq%e1V*Bw_{6=)lkL}1fIXB!(2KK+gu%68%WTs3IkOGIX%@S1iGYBB zDH2NvDDTN=NDVqrV+i0k*^oGk85&YdX2SdNwXY(_YCrIg(OgOaeyIbfmWU4=)4l>; zi(FQdVPrXre{5`Qj=2IJ?ED%y?EKqF{G%-WE5Q$r{NwNvQ6a~F;9sLqNdT-AGTNl& zMG*XOFu8AU$ ztC4gmwpFV)xK~rp0^F7qD={=WE-v#JtpsUJG@y{+Mjvv#7gkpG0#))<6u%RYIjI&P zB!FfWEhsE28&)tM9Ua}wW(T@-$ryhh5WE=NEa0!y2p0wdQJ#ejur4Vtc_b3zhjSM( zmI@GOMUs|>#7C5H!W2hG^Oc9q_M>qkE{nmLuE=nasOKf6rLQekoti!`YtbsJshJym zV~O;DKnXCzUmTE5CPZKn66P4)d->@pU&lilO#(c;4FsQ7GW&(=akPQ8Z(j9QZ&C%d zqc2F`C_qc_4wbd$`gg_Pj~11ypti4fivM5B5rF){VY@^1|GWX9+z@foYrKR%wv^Oh z8v=Ovz^y{d(eElISKhrGG9*Aby`Es}Y~f*Zk2zizaGCMw5bj;qr=^K>Qyc01 zU1M`~9Gt`t#8=KX%tZ*QIM#>D-KvYEQ}NXO08O!YnhuZz@-NJ#CVh5YTF^UCOjfT8 z6(*&nrLDWoxy%6c4!#Zku}6V}rT_Xc{J+;24A^=BhDxZ1;t&%TSd4MjM8BY>ez;;e z;oe}<_e=%bwhPK%Aqe#bT`2QH5x(p$`fqf)IyzPke;;$HFl1tM^n@WCdCdS^s1+!Z zAZ&aOUL#%Ty864QcXd{(s;cxYnidv}0Tc``#6#v*#mp_FoZSr-&-QPH_@u6Hlc_xK zj8E@aZmz9)7SD8z!{&t8+xJYqpIge}s(r{AK#?p+4myYzu()#wJ@<$w^SrYfyYs5A zvg*cbyyKC)zAd#lxT+++y@^pi;7efiv^Q+Wdmel#hzNjda7j{wXDdZ4krXWOeDahX zF$mHHZ#IE#ZFhBQ3HN(nhMR^0|6-KY_rT!>=uVb7S`_T;O6E^ofcCS*>&}x0NQmZL zZD*Wzr=x$U74}>lt*rp`r^J5kjYg54PdI=!_A-foCWE+$Lb(HkuqdlbyEC=Eo*+ES zTFutc0f#LD{!?J8-vfqU2$-P-A?u-IV(9e)%>y0i*nPI^GC@^<3?p?s^r!}G*d9X& zlkprn@MH&`s2Wu^WCcq@&%}fB07A4>qz>KPjY3=rco@ATDbc%@<-4 z5~yPnpw@)f5(!RuA(Cg*V;vx*FP|SQl^FlTH@l279k_9TTsk^4{}njzssh3b;GSXcD(#+A~^hJaC%QV8lBX)xu*Jggi#PdAqg|7GZB3if1 zbYV=N@T%p0hJ;esW#4{xAHS}?=09z?&b)Ctj66+Uk+T%)+Us@M>I9p#zcoPB0$;|R@2*XFdb-G?^Y3!{;#!><<{7lvDBhi9j$h&x^r$7ywMy|ho` z`B{!QR;47IKj#~=@!Do+6?ne3xvBb4=H%HX{r-)G*xd_bbYaON#_?&-mOXOBn=BVr0Wrr->-Yi)6I5MjdBCf}2f8 zd%#rx@F)%!_Jl^{OL52DXMm;Sd^jSb7O?hTL}YUCo`$0}%7bi?!@H5F+nQ7{?|-?+XwI+^5V5)qcNQ(7A`^$b=P z=yL)(<{ktsr^p*`QX^J-sxjgQA#Z*I$K4^~OaEdH274Dv0RzjEg*D{fY^z?HRCjD+ zM*HJ+g-TnpN9~=RXPP8uxMG!n4y67p2DF>?Z$$VnRRCKRzQCd%86>;>8RE%4sNYvq zj1JoSDKZA27D(1q5IW~!lV?bO?~6%%f9luaJ$*?BPAIPgDpYQ*A?lCP-gVHBY<)^O z+Ts5AqORqm4aaHk`(I1m4d^@DxOYuWo=lK9=C@e|(Ij3`$sssb*IGt$pEKG*`+gq1 zu-wxXPKg^Jwlk3;pvwpC*f|s5DYPVRW{Cets>i z=AWNG(Q2NQWFy7B89WTInh>hIp&hlQcoq3l+#**iSJ2uOG8kWwcY(cZH)}s4Ym6Mb zC5?9W>VpUM8Xc91xnk+UWmMoB6^OWitU30fg0f94P)Otjqf>E-(K8f#T3pEBtfhqq zH6Atm!$HG^0pq*az8Yxa`23>=nVG68D8o%t$1^Hb35mc59nD)FHf8EQN?JJB#~c_y zQ}FqB?_MxxceOk>@q2??`fLJw=D{p#VlE*KD3A6A!7dIBn&jy~z>zKse{$IEVNFOx zr_2;+O*O##;)h=9t4lA;J+2~4s7QyJ;#a)-w)tAH3eGB}Ps^`_Rzr1bhb!{ow_{6m zBiME*vK~N#$T+KXJQ)OR|Emj8B&&2F%U^>fRDEdudcSampht>%8u=*`pMA7Z*4EA! z%<3WUdS_Op8|6Lx%S~_s95VJ_zsny+-B1s;QInwT-KaoY79PYiYugdvJZ&KL)d)>W zNy#5qlM1aLV_{}iy)=#kbtReom?01h!M6{Jw7Hq+C;VU(Vx@~|i60sfQBOOTPE9>8 z0w^O1tu&ya-Q8R-@clN;ke;Sd>v;VbFX{TYjQWJDA*9AJ&q1(iZwN|?h9MSzOA8@G zi{_i4Ej0YDSb@=x#7-fi{HrZTy|g1eTwiI`vibX}yxnILDh6TM{3l!RjQ4xms+s5yrRU+rhFTO}(OAv+p;8Dol zu52P4dfHkIWc%_4t7~gXp=_3uFQ~TEEG+WUDGB!eZUxVynu*!jg7*YT2*n#i$Z$6t za~ysgtKF>A*`WFm4@oF*!gj!^eS0C#@Y}6ekig->q80|VQhQ|)yGDMQ`crVmM0N^y z_|PsCcX@|1J2Ue0Yk^V2C!ORFvR^ptErcPBfcfAKW1CI|yynx(r`@~N&cMzrcKe4b z5W41gp-8RkC6V*b_?#0|Qv-E>~vTg`p$Gg<1>h9morc~`wh89nQKJU!jyn)gu z2%s6`1=2R!pX^lU%-#5A-5z7i5_p+kkwodsZeWPfXXgb3H`!dwBor1uo#Xnx7<)sK zwL*g79qau{Qq`ZrD1&X}Vae<(DJza?8Y3(ASSE%nkrdVh^{X36reQg*lhlT7~k&fK<|mteNW<;znpR7rw|VRLuUTh%s7 zn3MJ--@Sfu`=`?%Q;hTN++9s9hNA4d|9jBsqlE1gNH~yZX-2;(ETesbD;^lZLe2Mdq+2*+Y#vvlFcV1Hu7#Qf5u`87#@ z-C$JXSIZDVx)7!jx9gA9$B8LiuVuc4AzC)7UW8(ktTb3&E=ThZeVQg;|Aq531)i&A z@^^f%yd^apo~bdHnei&SV@$v>a&CsU1+{g12Q5Y6ex_~5xPsDH25J@7uYb5kB|pNP zV$17MYUAkj%T#}h_C>{j%r7pwCLv5$lZ5s}$lP7+lMz#FGJ*y+F(GwShCKcv@v4c$ zCT_Kg)5MNzvwN=Pf8yP+HLy^Qj!v^6?R=@=6+Ax2t+9uDv$EycPoTX25kgfVr~i2lhdEq+b*F6dfq zq7ks;RV4OoZz~}OwRc6+DK8Fc+10OSU*k0j8582faXmSWeViG84Xn^@+T)d8JcW{pXnJ;k&IuJWa zROpqhcq~Y@m$`qqxjfPNIq#7@MN(2);+h}UE9-34v_RXH3<}t1a05u!oweEedg~8Q zxhx2KPE8k3gc*nXCIMgDnjT+_rQQ=pBGiyw6XlDpy#*Y7i>Ym_7mv_Nluv4iK?hyM zT~hqtuT!BIsO`V)2_x zcilo`FQg?pR9hCbbViq;8ete7I%7I}6|rO;Rzc@+?y~KX8_Wa-$yCKDHwFJj{iP8n z_{>GpS6f78HHG_of0d=7QZp|nj=FNgb?y%GuS8b~>JhpFGJ}XWFC5Mp|2!BI|0?do zfK1v%ix0Tp&tjt;544ZgK0~>;n4jiH@+fy;`)at`B&SvA<~l3nVjxH`$^8x9QjGw0 zDbdc;ZPb}y1u_dmhhG&X2p%BwugP}r=;&As@+|v7fRm*6;sEr-#|b)`-vjJomHUWK z@3kGXvJGzqHV%<_*--|PVFR#d1s6c`Lr=M71hA{wU(tPh2v-rzqZv-)0Nmck(ZNCQ z=+hJr+(4h-6a}8eJ~_=(+%RJY)pxo_bJlj*Ks{Fdjx zWRkTxv*VBNHF#P?o$p9*@^r{0(#isUGIAp|X_6F%9=a#z0*Zz-z&FW!=5O*=?a9S1 z0Q~=j>tuk{rWe{$?wEYuxv&`25w6 zHu>><$7qD7PSeK0KIZ|i#4xk=6Rm;L&v#oH80L6~`*|&~BKD>!EJ#Hg0^2jzxvu{2 zCd7(`M?(mxK)sBadEB!okoBGiX)7%!Cnx*r(Z{!u1~S&E0Y7_s_60|n1dJzLPA5!9 zdFi1x?FR!Gn@*wv4~Aq5BR8ESH_s$pZ<;Q30S+N1Cbk|y@+I9BmvVFs`K7R`9RbE- zlH#X7m|)cD_<*^QKb_NFLWEB^OQ;rBMqTO{QljsO1@ov%)}?%D{o4?QVv~sX3-Ao` z%Hl^W!?a25Be`I1O1r*`(qBhJqx8m&JFMjMOaJRn^PYre$fiM@RM zsC>1-i*`1%?YCCZY?)04O~6Q-T1{UOJ1b>#a2Jxuw{i2|DrG9~A51v#KMfM9@GQj3 zfiwm5{Q7Kup0eu@lblT)Dv07431z&GYwS9I+j2A_2qNG`lnw7 zxJYb74ZvpFI&goIHv=Rs)=or3q$f)+MaiwWT1;sdP}Vn(miEuDfc%ul{NqQo4Cc0j zdlrH(9}-7iHdo8bEshmfGHG^8p>f^&?y;b?f6{WXB(JR<0j*F}Qv+JyH#$VeTPTuu zE}yCnTU{edS>FhCcx~#Fqz*^!2#M_^QK`0{QEEN4&X%n#ymv_01B4M>+&(W3f1pT4 z$&yAmN7W-9hD&-tfbWRaHc&ZCur+iQ4ae9RSEa13t`c|R*af>RNRb5Nhvw+${`MrNKZwJimS@L>S{TkFYnUkH$qYC!TwX;vTt-aMuf9o zcIp3Oi;~W9Z%2Jhrl1hG*|ECDAljAy@{lt!cRk;a@81vayv+(oN8n8@y?O8;dO@(TS4hvw%#;}e0?j~|=SyqrGT93SM=f-PhkNWyU^U}%xZpVX-N@|Ap9T1`Oo zOWefyzVG%~SKwODG19y&J9z%9MM3jiuhQ60%O@)Eg|QG}?i~cm;!%O^CM-YD7z77! zvaVV3F(?_ErahvcN9UHk#p8xV@&tzXO~#qOdu73jw`9{z{Mw^SX!CrF!*~!e6QgU@ zI13}29%i=rGGmzKeDfA9&$p}$YZael-`}zj9E^2a zO*Fl{hB`N5O!w|hb4nK*?9Vp`8>0QzTC=Nm*8TmUjjt@-C~4RbAch}PQwuv5;oFP5 z13m$P!o#G4@NFuy*TI!j>G2Zc`I+Uy`p5or-@cGl1CN+2k{=wCUv9Dg)U+3U*Ul_M zO4LN|v+F-wu%0{~v@`@%vJXaf2vNlR1h5fwj#+G2RI>^l5txL>;0@u+vXE$=-ZG9K z>Z|cT%XA$Vu=vgTa$H$KA&sc@_ZncK-kV4`E~o?st@7w70;|RiShB-Z_oDi zm55%%Z7UNuWX*Fl>W75>6KJ|Ct<3xpQBWgGZ?>glj!V%KGgd~VsZ{mU6Z98QM5Dbh z=5WFrUB#6=mwj$(jFCr`89W}zL2}fHZi`9zv2pwIw zc1)e`NkZ5oHRiYY_gf7O<9g+~hL>L~tj8!=n{zFs{@_1QA72b_R$?^yrckZ!s2YMt zOlYDG^_5>f9QT5`HZEjkU5D7+?BT)hPY)m5OeOg5k+5(x<=hWe{S5tCLa?+4BZHEv zdkU=*^>NlIe`vDt=%T$Fz69n-X~Q#-U}%eP`DelD91o>N{s4+ufKbkSzqb`vVI@ub2nXUCwz<$Kpie-rfyNkeh_uDG6c4 zqH6UpgOg4N({K4(zJCf?xCIu}?~!*-9svU*W1bwEBrxJ0wxpn@?l``puU7|T=!%z6 zML{7qY3OjD*fnU|*Dy5#YG>t&Tng_>#dVCF;6{bJnHl{uW2M;o7v=o6!RL*`!-`;} zMziS)f#z*6fqf@mkUev;y3O(ixD&gTU3^bZZ|yA?wy`H#12t}seG0<9#%z(4cL&o%6RZT$K|CS~rk z$o1fTPB+C(z52s-nx2ICm&&A_@2;v{N(UZEhETP`q2*ZixPip3?M?4$LQn~1-A?Zj zOGz1J6a!S@b4^ra%i@bb36w3Si_U=2# z7Jun>kqL<-Nik9@Rq-T3*|3HEZC`rVzeMQhm6?whx zo7=zzifXJiVnU`GIA&!|gTfFOw;sKYK=RYioO7!#xkYAV zWXRhcVCH3Wnvbo^U<0#`ArA}CjqX|H=?}2iW!dhmUb+W-1r;&A3OKdIFqfB?zaeo# zmE>0HYv)Zd5S`pGY#F*s*lLJqG);u9^q>rp{QBXyqeTFuI^S&kZMpHxK}Uo-Bc*`~ zqFrs*Zg~ybCJA$S95!FAyg-j*uh_-`I8caN9DK5Q0nD(RRt{$Sv|WstxhNcRpGH6S z9;oUH^(zk>!0l?_*Ka}WqUn-22?iaCO_;ul3SIyO4%kdMB#A#<>sJ9eG?G21FOfsC z(i6;(&)sUO+iC|6ZtQ%_>Wx;0ualt)bh3YTTG#$#BHU_&F*RLO#IUdXHiebCjaNwG zq4K5ZPbuoFrK>-UbSQw$W~;`0M%W0TmDd*~D?c57N|>6^do<4-_oSy@dT>i#OqNgP zK_zvM=@w`U^n!aY7rz`j_l@N*ny&soe7$!(*8TfFUMOVC2$!vpklAHKl)XaB-ej+Y ztb{0Bwydb^vdi9NuZ*bdJtOn7eb38%zwh_>{2ss8ANN3AUa#l#bw1DYIFIuN!!NJn z6zs&!{VJ7+KyGc&V2$rM`*mu<2Hne?KJG*@CY?osoq#H^s7ncnno>RPfwId7z~QoF>VYSUQgsV zyKtF$dHQvZfn7R&(w2nX2(rHUw!9(8{2|-u!pghwVq;=pTPx&K6W5)cey;L9VaHLl z#%U_SUTX5OT4ebnT=H#WsfNYR4G~C}u`iJdK5KCLI|7uS}b=nS2M1{?se-(gk@Opr3@FfymU)LXNx4;g%WHt``{f(mXj;!b4 zU~s@~J!KRDF_9xR0d6CQ8U86o^@{NU4$avz$}mhTN^0AM{1Rd%W=BW$?Z6ii$Vzez zlqTV#X0%7d4f~X zT{nzA-et_XZ1QU{{#j*bdg`lc=wnez1g@ouCdsssoX>S1Od|^YE!4?;m#_YrJDhf& zgS&a2!&|Q!0NITrg@xE#`5TV~vk`9sfnzwHA`E!@`VTM~H4~D=vGhMOP`_h$! zW*wGn3>b0O&@cjZ8&KE=@9=f`#eSHQD3}b44BjIO2){hi{_;V*m zHt2P43;RJ?==`W7X(hd@;vc!$FUwELd#OC|zto>3;@oU2Zo0pI7x}_;z09Ar8f{8i zI1-B~cZN4eb8|v?B}za3jOc`I;Y^G`PLzZKjIZV6EazD@QtsShd$Uzk_Lp9%9euk8 zoxE*E3l2Ik@li#*@n72_dv)wQ^Lsf=ms615L*Zq2BJN^iNy%_`ZAOeYPmR%$^Ao3{ zzP0yn-$MKt9O{lIN4*5@#Q2+m`V9Zns>S~3jkhGL9V-Xp2{LU#0<)|1DWoW;D{8Te zj6P|H^jbyNOq-lKbxn&)EsZ;m)^T&T8J45-b+fYtra!A)X5zpL15*6)!vI!pAFBhY za1nFI!6*&Vcnh83A!}Z%U*&o}O-?!WlYY_Ou4dggt|H#^!pF{v>}!}lyYmq?hu!|Q z^h1MTZ(bj}gWhYe9sCF-RdwH}nLe?~n`Znisig7PxCht7towVu$yw9kgqUBxe4x~O z7rAi<>2&Fu~Ww)9bQ$n=D#X~sUkjq*gX_NCHKptSDm9muygH9UkM~D2))-+kIA06D`jpBp!UuKGR3PqHyQuk7 zr%Gw*qSf7Tr(ydWRq3xhisxK93dyCXVApl%+dM*6Jm}v<+qZO(e2RCrAxBY}-Sp+x zpG@p!6m!y(Jtx;@@XIH&JT|k4YU>_uLqdi)n@C5#``PzS>HAfp8PNXaMu?pJ(|^l*ak1WO>@C?n$P7`z_(+ZTJOB*H!0-vf;rF^Dvu!OKVyGkHN_18+VJ#5TKT(~ zspqF_4Jw!E1|S6)tsCMe6y}om3Jqr0(tQGy7OmmTir}*I%6W2Rh+u8{(DAOoST@#2 zlG~FDue@0hvw@3Y^*q7Gqhax@(?pgXWS^8S^; zdd2bl5)>mbPfcR5MUvV8s>7qr_{#dn7K~E(n2>c_&J=8fDmer(ncQee{>RVzN{ih) zY%iizqZ!u|K;Nrf$GFM0D@Dvj<*HWtSZ=MIVz{LmgGu>sfyOW`dS}xI4PK`DkY>#s z9=td$r0yacNLGG0Of`j8?5Z;)$_o}+bS2EHcf#zk3fPm)xjQ2e!qiYto-Pxk&A#UT zeND~AgNBjwtd|+?@DLO_sBvnc?m514t{);up~W@b(Aa+wB6nmc0jF}@{!u ziWgy}imY&N6rSYRy-};af3LzO-iroBOuv=jAo%3iGhcxRdSe6Z{;Y?&kL$5YhmbbC zET3(WW;|P$KOB1AcIqqRdZSVrI4-mPvv0WUnzB+B;>;b@IUB=^GkQ4i@lw+wZ9c3KxH~Z(cwVPmKns3EdcZ`Mi(S+ zsmVjx`S~|)GVt;7h2sfFt4!6c@~_8tRvx#pEb%SLr) z-vfswk2S0Pdw@e~@G!C6iNGP~WYqRs8>>2rAIezcVp6A&p=>=25pnwRM6!rxyX@6T zkFBKQE5}7V8f(Gr{J|=_ql4gZh`Z;*C7n6U9{Q&V||=|qrYK`l5RA}S!g-tkk>Qmidd2to%qCO=!^RLL=0!nc!^ zl2pbsJT30M5#f&bba+BX@c%zx44lJYVzS)Fvc zSLVY&0Ox)3*nVN?%8JdGzYFse7GZWdhH=aR1!mHLkW^i z%{BJG zBQh>LiP!MzcSA%C@7e_sy_q5od0 zq|>FkNJeJ#c|w}3=MaCPU12i84VX=sHQHT5GWosfV^0}gkedvmK{e>X>acftDnlPF zMPzl_>#g1Uu+y3tCf(WC?(j;?TXBjpH#fbSWBfutItW;P?XShQ!(-?R4loeX-=#`1tselD~im`Qy&`*Ldn*9NxdLAo4(S z&}a#2=_rQ}4y0|ddOb;H^-uj;q>=9FyK3)2fw~2#m2!on9_Nke%^s%txW_#r&b{92 zL@Kpbt~Nefk05NaoTQ^{76Kb0+9BY*rYN}PQTV=sH-`S(z=6&%WAuuUtfi8b`hIW1 zfDIhjKvjgZjn$az$t>}QAj?*UG_vtiBy;-hqCiebfP3G?A?0=bMj|-^x%kON#T6MX zwMT71=F&)~!GB5t=IPgwwpbJPkcW@i(5=Tjb$p!_^9ZB(Z#=1Vjy=Th2vY+LoaTif zSj2Gz?T2YEqt!2FD%WgYZlw7Pm)Z|~ZJbjS6TS_yVT-<+S(yHwclC8i>Y9@Znu`~) z*A@CpGcvA-&v{@#rL92aQDH1{zpf^2(od2ZJ?z>mtf#O6$XX{jQJ(;fmYkB(> zinAloira4X=u1<`Fur{G@}$V^vp%jb{$@qX8$Qlr5xwVXFL1APCEkLf9J>e=;|<+i z&O&2nC)oT6sOlM^Ne&ys7aBFsl+(~qf zO#e6hH+~q=@09^@;iKuWuau;9^BkR)w>XLrTI3f7=kxFRzX)+qs!fzWqhU;WXYS_} z#M@8elkgdQPu^)92N<1byRk;$h7N^vVJKOTZv{;h#(wQhXgMC)NxgGkYuxW1l}=7) zlmCpcCf^HP-;I{RHF|Eu<-p6Fg)u_*&r4>gE<(}1`VSJBxm;ROV!ZhYi~ror+}yKD zl2!!FRxSiSp)@7@_Vp*o1DX71MiQ3j(J}M#W_MHMWhKGF=!=Oeq@<+pwullx4HPBg zd0)lQ&g*oM2ipyYy1U1x`frh-|3)6bnu5tg^k{MCcH3;9p{qt_v+sBF+s!Mg)*-SzQg6yw(vAQ8BOeIA;r!trxa(SCpf1r^oHACDV3 zNb7RG1latj;3J_IHB}^ku{Fcf4K#p%2|(tPzm4Zi-C66uUiN-WBM0AJufLVJD?jP_ z&e*dJQ<>G)njZfx}l2LX18?ff4uz{YGTmJC##%uiJLBb}_)8sXz4m zVHcF*q)~4O)@3=vglIna6lAf^vj|?1jX2=fPB<49TDg@mw>JCfA)vtLu{zf`8fg>A z<+NUJ*SG4>a!yFkTHf9^Pg5N+*chefY$XXPgBDw?gDr$3E*tq$qvHjuoV z&dYHXmQp30p!WBSMj`189Qjw$NhXX}Hk=i#qPk>Gwf0IFh^hl$YJWAnp#+Eeb{CjY z?Bbg?^kL*ch&V#qeg!HjQglRy8USc@<08~o+&0?SW9F}XDkKMw(;5iGke==?2OI&5 z-_fC5msCaQNC#Nx44Wz#ltx?ft`Fik&}RDglWecz%-X*X!pAVCP+<$so;1HN#eR&r zr0DaO7x8%+t9WVk7RqpXkDdJYdr$Kngl|$2zsvZP5;9yip6_K>y0+{|(T3UJr zChIC3*US6llQ1B5^P?&^zQ1j@rtVK&c*zkd+qGlIRT!==dlC2N^N@jHM(uZ7MxBeA z8N+hIiQTwpA;*l7YQL5wCdAn<`2+Qcc$&aptG0?EUtc?=fY6EJ{q)YG)wAuK&aVk? ziEblAs6%-fdcPvPX08v$jy-c0Z2a)@DofqilwPc{m%zS>3c?hdUn3v+QGT&;c454B}e3>0{6 z&)=Qhc(XHZc}#4CH*4GJ;9qQf<$Tc}q(1V(7RjwS{?9D$S@tnBb^OWJ`oD>FAOhBJ zH$64QU?It5#Bs!N?V2E^NqaP>VhEJvEq}-2R*1!SSA!1^J>?B!O_Y<6WJiCli;>J5 zAMUOzR(%mvS{#k&l7AIoBM1{WN6(B-bdf%Yjg1Y4{^c`3wz$V+`eAIZv}j9)3VU16 zi06Xb%?U*UDRHmkWyHD;f<5os88ltyMZcys!=hbS>i_=z@~-kFXmsp$qJ%JsEwCka zk8#kHW9ZvCOV&Lk8S*MBLf7ct-t?d{F&eUdUUUTn(qA>&ZZ(sl&BKm9<>o@+blN4T zYJV=}$8?1w64f!|u|5%m7k@BKl7J-gcuLoOMF11dy$L@GpuNlN=2b5@|8ZGfp+xD6 zOx~Z&`tyoCT9lg|MJIWQ`Kn@DCpJDoLufvM9Mh+26|KN`&`?-+Esx$%eH*+LYpya9 z_<{0{RM+?~-YQfPik;i@y6_lRBudN3=+-y;nUrbo-mmW2E6*nhuaG22YVPx0t=APU z^K0Ub>ufgGN4~I`RGECNFen}U`I_5T92u^khD=81a5**??@);Rwzu^O=RQXly&Wtx zYc$9Em7n<==XURnOaf@q`U@5^yULuCqsglkwij87hwA0uY1gh}1$38)L(EC*WpPSr zE)+yG$sd8j+12d`(2^?=Gej`hGjcrG`YDv%P!1xLp3z1ZXdIx~6gt?H!7lUc?hM~& z2OdEf@9gr%Lo6^C1=c9b`kfRK) z268F%fTlWZ_T(*>x1`zY@fOP|^p4^Bfw;=y@o#05%>tKq&V!P0=u@bl8=A3=MrTr> z2;~K@LJ>orQw#g1J(gSNkG`zj&RtB&)PpAn6TRpJ2a1aqr}J`Hp3@^8Zb94N>>P1? z)c&8S2?{=qviXfAsMApQQfPvl;_7 zFO%-62|1+R`sa#zIz3XjjAcd%dZzgr`Dk}m)r|=S9ODePW4RTN;tjl+6&ksoiG$9$aFLarU9Mp74AxoU zC1bx^;O0v~Nr^Aaz4ohEDO=2WPFXIbae58A=>m`(={d>`byJ`kwzRdS#5=pVxCkUh z4rIERhzJduY{}4%PT1r<3QHB|X}N9^f%8O~Rp~M<8edqJY38>X*7dLPnBaw zdV2heJKUw)%~j9N7ur&ym?GTNkyzo?cOMvS z!H&n4t7;8o&nf&jF2vcVSM|?HM{M0QA3vc&bG7f`0B@yYwDZL7$YrrTfw$45gYEJ) zEf&A?cy~eyp5J{%go-_E)r}W@{6RNIbh*U){)j`PS1X>{?Kz54M<#KmU?rm&QW^l- z@R`>mX_9$@NG9j|n_Wi+D>b|rPJcI&Up$!ehz(%w?{ zAiD>gN~H#}e>$YCXJDebq&S%9_m7Fw5|Iv3aD|cs@e@aN4iy~y`3K_|H4G&LnTUbJ zJSK_V8$k|y|IWz=CQr)H)yHg^i7Y3goo}?ScK^Y2v26MlvF;n7qk|Fc1v!%X_k#01DQkSfMMOUfWi>T4W^zl%iZ&}EI0S@c0>AnqhS~v+WG_zkLM1C zl@2(s+J=F={`don#iLo(qx+Y!L;8JJc7{sEE33ygSyg`x67xTC=idSLsDj7FB{*Cz z*@q3Xer1z?Em`7eCJkd9Mi>4?bD)t6FaL^qnwXHVHT=QhPGQ4Y>ppJ|M6TB7=0kIz z?tsWbGhj3YnSqy9=Pl4=qd0ds0IvCaD~Qri3nU|b3G_UVk&Ji32gI^Zz%ZMjb3O$aE56*>=e z1;+Z;IRkR7leY&o;O>flS(wV-M0}j75WS+FEj3AXGe*Bi`B`VWn|40H8Bla`p)~%* zgJ8CfEQRF%;q^NiUK@p(oA1618ThkKTp(`tyviq9d!njAC-**NdfvEwRLpKzbEtOH z7isdQ^-STd2rt4jXAOZA5;lDDW^gTy`8^dMJtx8!<|g)PW|Lbs-<8bMA$TQMb`n}L zzx*0J&;QJeZy#I9MpcBDlQm3CT~Y?p_xDyZSD|HKp?c zcJ{R}G{7xPX-r%MQ+r7c{vO}FC*|Gq{r%{bLl59MHG{&Mw55s%;S0m@OiHS?R48L( z;~5}^+f7R=fA+|gm6dIOagKnAP^)GPJOw62+WH&ao;B&+{A&;Kx1b_8?Z>y}b1r#p z$-Gij+RS1Uxyat0HeA|iA+*1aYbow2AM@4*dO~HT{;cWVimwNbpHkz{^qcs4%bJ-o zsn$}WZb3hXe|=v^G3h6|HU?0Z%$|TEZ>g4pwe0w4Pk;P2TPORi0|whUNwKLiQ`t0+ zfv`nC_70fIjI%p{oGhZh(LlqD{lK49{P>YS>lve2VE^rT9H?cqU>$X${){%>WhyL- z@_eDUv+7fSsb}Ue#PLcHx&(A`Wz=@N>vt}?nNh<9S$x~#%JK;u}r|?4MURzt+ z3!;P8AU`4{DCQ{Sx#F-xPJn@Z&bUvYN1TP);A`;sPpK*N z?TXzaT&*ee_{`ynbcFbfk9(_61grPSYGbWW@)d8n$fmVdNXI6LyrB#5hsm&v9)t1p z3-s^SvdyJW`4@05;>lo!qrot#Z8^V|2ToF|)&V^|z1ulH$5f-(<4JNWA{M>;`Df*3Ub7Qb~e2hGF%sFTaY+f|)+eL$m8o zIm!5|iSRStyi?4(D};_YpFeB<+1m$r4oiIvI)#{7ZeN@LLX$E{W(g^MIv^6Tv9TR4 zd9k0iq5y?qBIUzi-s-p{tz|cO+qc3bBQdGmTXZd@{LOG7^RWY6CgCqNPgS9l!F1ca zYvZn<#%Fq>kJ(gPCR-gXrtQCVUU*~11AMpmmV-TB?6B*WUn7;eV9xdXfDjJ;NXgvW zfZV-Vf5Y20fF7d^k!*gyS?^W<=oW>wh@^+MLOrhu%gzWQSbi!d@)E2xt#ZKbUzHqDmse zDm2{N>MtrKssG7SMgpc&zJ*B^A2E>8^OM9c4t2VBAblg4WB_O`_x3tY)+FEDoe7<C&t!?z_jUc2?g@ zE)6glYbN4kXk=qu!1{6S>{I6J!F8*Q1qX6o4~=Mw`96M^sQ!ax=;=Lo@chP^Gb4c$ zLGdJOI>KJtg*3Hh{3Y%mPu0vWO%!524s$UfKjh!5C|vx}{@T{<(W#miMw;cXiz4$A zUq#j7!ZF92-(Dmqg0$R)>PO3OT8W5%UDiRUZOh^5{9RTxs|`KpWWSA zUdIC%Nulb0mf)}NJ)h^;D|MozDdy-_9tNSnGsz|xvAw^p@WT^>!|L*%A5trah2cx# zA2BLD|GrLt{eS=O|F8Pj|A=-G{`-%?fBnxl|9#JxpE^~V`uC6j$9=&UF$zfkabbR= zTRd-q;VQYTU@XaWA1M33Y63DdGfOc0<@Cb*4QaecE8#?2IvN@U*s`0Oo3`T(pFax> z*Q*T-57U8$(2bc*_k(}^iNCg4#DgZ|hr0T6YcQ*5$%P}wsmVd{K|gTovczGh(%8{zqyJN6xj) zl%G#r91){rBvl z8C#jovo7G_%g^FKlr`EH`je_N4*T|}G-6k$)ueuvr$y{NBcAL%RqjsRh0YEco8Cj3 z0-rK_yt?0KiC(U@-#eNX@cmfbV=kGAEF0W3VNJ!7>qB}2!^jyl+tThNxOQ}O^cTfW zHU=gFyD1J*n?!JlRO*khGJbP@YPuyX5hQct0MptmDXs4Emu3#$sed74>W%#whh7)` zE-OnutZ+A3IYj%3t80g+w?b}KfEp<2#vY75q-P`K2Xdv=Bz6yh*v{laZz{jsFJQ1n z)REnqz}sPUxYK$L=QI%gwR~sJ@QXPN{P+aaOY9~?Ly(lSzW&G2Lx%a`Ug4O$FCTA^DN#%kwM`Eco==oe=glSzO0scD%O5Ef}0@J%D?DhYGxJ>st{>rL_iXbUG+P% zF3_{H%hLjjj(vSE!OdY;H4TExw4vn4qIXmg@?Sw%ib%MMFAH5z=0H0Gw z2A=~TTmHPR_uD_O0etMG{pJODq?N)I44|&&9oh87vR@haBs72nho8`&XaiXb)9qgV z5gQwuHl(4a$8FO8p|o@;IwnS|gk&eb{;5VkEKdh|HZy+w*dtP#BULt(#lcjHJNBB^ zhq>r8ec;5SVrG{9s>yi0KZ`AgeXXavTNqeQ>nRVx5<&n(i(T{{Dk$I=lZx}MjN@X- z;h@r`6 zw6wLYE)Wo?T)z}@BTsSq59kGV0-~*_*7pc})65PGPiSrI<(F1hcL>9G?dMA8lGCUX z1jjzPo7JYDCx5^Rg8Bu)N&ak^f8=k@RIKmAHp8!$e>;^DaEmE?N;FFbl=Kq>;$PN* z>^}aBED_KhQ{@)_Q&r%@2wHi(DcA-e>oZeIjG3DBpEn+} z>aB-$5jgDkQh!5%KrXms1=6Ng$&S;_dzQ4ZvRwG2gyvOA58gGWh&apAzU2OedoX0k zjQ?8xdCMkF5NwNu>#xTR1J0q@iXFn4-ki&%P!9%c=oZfw6nzw_x`wlI+;yp3r3R`2 z=}Na`>J`7?dE=EIg|Nlzy#Lw_|C}xGyWBEAk9xW~l1;1I5<(NzV1S>JI~P&AEBRyH zdN4qt{$9Mv(m*!VZ_GCA0!B<13^<9??ah8=!WRP#Bg~UrfG7D2>I{T)yY@>@ z#;gFG5X7d!w<|wIoSdD%;~P4)D~s-!gJq04i2Nk8)fxG4ulVTy&@m%OV;%i zoJ`oP&yVmBWKL&&Sus!P@9TL8A;RV9(~p|BH7p&txwxX%iQ(;{+uBW)3lnW-5Pib2 zDD>5sulVKMocS;&DE#0R6B`~F8v1ni1?k2%1WuQP@Gx`lM9llyc5@|8Q}q|k#?d>f zzB9{l_F(dz-N~BiB{HW~{meysXQ8NrCu&c;7}WXh5p<-C?hLVLCMVV#-W{|%aZaow zJ41?OnZd&P_aO_vCAHebW3VzJhK;RcnS7TcEx`qMSYBIKH>Ww{m!~%fGgFcm+Av;w zv^mNoQIaZu!~9UZ~}0V1zGZ&v$WM=zUNuoIWg&RfJcH%o7h zp=GPV5Ij4U>7ZQ$T97Pw6a_3+{7!^P633-VYyp|M8RF{MpmoNp#~**Ibv; z#n3ro1zVols#ed9D5K4-e&)?~E~(A^<-NJ$p`xx1UW-I(1Hy#O`I9eWEsP|s=n zUfoOlrDOYVydsus|48TU{kGriDy^mG2lfBXY)w7^BWZ8N&Dx{iGIR86LFqF;3LldX z6}dBR-Q*NHNvwU$aQ;It8xE#WW|ybzJPKe6mO(ay!o@ak3Y*9H*X&h5hn9iXl`nNNy~V9G`9Usm=hH`cjGSH^DsU zJU91Ihv$$1ql%SE5%sIQN~`-ntgCRc$9|-Etc4QoSCGGWHWQI$^4pJDDxU&v@WK#( zuGEY1$v1fkI&uz0b4CWw>sA*o6q!}cduZ!4`e|X~A=-Mp@}Dd8oeYXTU5Ojgbs|sC z4_CT=DY_r|eOVu)-?)2_+RIT~kVz$c?!V4IJcLZD`uCjSZ{M!R6>dlf!5b==?$Vhe zY0%{Y?6zN3Bvd)|$A&T<9+jM2T$`RgpezD!*y#!Q`$u6T-#lp3z4VsM3efH68?X1n zje2|gc%w}Fji>50yz)nP2|gubUM%e7L{{05yF+;&Ke9Lo;t2_@8YK_g^FH;c^%tLU zQ3EmouCn*O=1o=A!*%V4;OFkXrGE2@jMIKd4!5mu>MbU*ghIh`Kg41@ zw&F_?;)Yrit;b%Mgs&Oa>^2Rcr;ZO;sZ}t?Au}~T3hX$CE>?mT>};B@m66u}*)UXb z{ARDM;`F{e?tRy6_v?$oTk`j`n&-2Dpr3o2R_odbCK^i>ObujfuJ41T8`17@DQxiL z#68;z*fxE=y^{xb5GPqOwzjzm&d`-r=)#CMxh%nH_v#!oHG!4U(C6V7+NQ_O&LDG& zT5dO(eRJ^*9^x`paCsmj+t&!iUDHuf`h?c*Zhqd{q};KCSzc-)Qi`C(J+J+4*9LNm z4SMAMG^6tgqNqct_IO+8B2v`z(GW9@Q$yHIU)BS()aoQi(k^Oq!K62}%;}B4$<--c z8jAcjG$hA;?bEsc3b3~(TCqUK?`{`{gs#FV?*QW2_lB5#njYk)78drFcop~%QQ>gq zl}%k34No~X_ZC}&ND5{%qH{1t)uvOxIKV=2AwD^o!KGbYN~-={vl@&CVacM_`;f7*@*WPcY^EfF-de_|Ph7?Q!*~dMkt4YP#+p49^xe*R3F?TUo7+3Gda9-b zWi{x$$`Lgc2yuf_$$~#ixL3p+wkpRdn++=0n~k@B-NiwfjvxQQt71 z;IMFaAKL+wWtmyE&TcLC&-KbNe$T&b30TQM!=N^y*FX6!=464KDE*E8N7~kO-v_Fm z@|Wcc;O?V`A`=t2oU`WiAiX>mdUPxQ#!=Uy@OadKbcANc0H=CijwF~p?Jlx`tepTj z(39gR>^~c5IN_9&3uB0(b<0)9QXu~lRV$dM>Ws;zj(k~{t&C1K8z6k2l!KDplVaXB zp=NUA{*cf2_b7{G{E8Yhx|TP5=;qBs2j$T0yg}b9jvHyj?5{+e2ZW*_I@)w6hsJ~0 zZG56VDgk0a8#?0p^9{z6NlAw-KSqj#a_8Ha_#B7?wV>^x%`WGjfX<6*{++?R=W&JR z60AQ^;hRr0!9`vB6mZl-0PoX@v!*Iq zBPGSO`66;dBAXr2t>C87d!uHO@Z!;*z;jl|+smwZn>TJ$;$ADUM-!KcAK27g)6-tq ztB#I^2b3S`j`Eod(2aWgc9zRwYop^Qd8>xOo97*vgY0C-p3iwzSNsXNWWfB+aB!Dx zsm%0=*SME@|2U(H(zm(A%-j4A#oxswCT?ep*B`fsFs9g#og8QFO*2-vbXeYB9UAh` zRwqLQ`P+EHLW~7gh_>9!lkcLVBba@bH=U_MkN^_GPkZ68gVbkl0$1`eh>(sPA2At3 zjr-li=A5cn&O5NzC$Mrn_+5JN_HPC0)8y!RT}0AIAIL7zx{xr4bA--u;^IHZ*Uue$ z0~5jtFEDKn;mo8jlWyanCzA6MBG;{gh6<0!@L>N6Qw9T20H4809vG71j>f-urD|{N zK@u}-CZNQN#disksc8yGKnFS8z0V4g8yu84%=a+-i5LA&!=PRG;cm6Xcukh5(Om8M z7-Gh!DLzwo(AV2vT^ySvj8_WlW$^qa_C?TA>!`=rMS%$UJX)XkFNACN@7L^0 zL=xJ!p=0y57313B2UfjyCvdCRS{RQwY+e!(WbxT$vU#nTOa@OUgHsICIQUie74OVhw0f9xToiDT@ck9eFFF9wO`*2Q8%_-WNho)c~^5YMhhOG~?}o3x-;UAa`bK5v57$>?fVB_Oc3-VE_ea_UltkOI|l`-pq4eg?O@F z17hqtWl*hRq!i5|i>$%8r3edc4*Nj$Yz7P+bIAV90sjZTlXfU%;y@59L7vSR%lG-= z_a!$0o$Hqbfr`2QJTfOWHT8Dh+CEMBOr#QC`7Rr}AAZ(U|6!);+YQg$;^OZ>n1f>c zTRov;MlKt@iSx&MJuY$C zwUP;UoW0b=uWd{-2AbxOED|BMcRsEe$z#b4>Ae|o8Q;zen%A9f)}lcc88Qwm8nn~9 zvQfK{J6T=wWyO-CVL&SGk1K)(^JapQH+9KPhdbO=ZH#gbZOncvJb%96)A5DmA@r@ebum%6@3Zi#bm`k9A^izaJv!HK((q%~Sf)p&Vz^=Xa~ zU7AFOAGQmk2kwrWq*?(v?@p_DW!V&hIB8gFmq@?fUQ%{z(uhM z`lz2r!O>frSl%`3!gA$5@7Nd9N*|IPg-~j+2`J@95okFN9DvNmr!jVw%XZEHBh{@- zi0C!H@G7t&^4DFdWzUuog)u>$T&}%20cp&vyHz)6YsL5V^+|>1fBYC39&v#S24N$$ zf1Femq--BBNkv-~qsUlgNs$}xKWnBOZ*yy#mz5Wm?Vt%p|`#7~val zi(M4Fd55%RxOFslwQK^UK~_HqD#Sayu}OqD(`+3z7}iVYKrjw z;Hi9W?R#0xc?OKHYD)}#y?;Y~ry}L+y7}ZNkI_@EmzpH;GvyX`M#acM@L7e z-5Dq*+1vV%NeZv{owH_oWV8qY>*XyD3XNsOC0+|n0+9gu0RNd|RkJ);yUMpn8E!Xy z(=CY{?P5i*m!`QmsKbc<*ZQ7(S<*Z0ev3wMXY z7``)ysd+n17&gIKPv5@V$cQ!flI|4T5U|v^&hRv{KXPNEXx1aV_;`<^%o78Edan76 znCP2SR7Ta}E-eT0JK$i+z0w1pG8$5+!eXj{55OWEacrR{zA^6kxeC*@`PT&tNfjKA zjZ0i6yaa84jDu%O+Hxp_f_om2JcptPul>L!7=+xf4>l^H?=7ZxgWtb>tD9%RhhZkC z&SLxVn&|mRmol8XtaClV%A>dz9A0{x`Irhz-J{qN zQ_Xa^jDH@L@+d=ej9Bvu_xNGm$u2?m-Gn^ZkesFg1FT=(i3s!b4-Y0804tS$uIF{? zeOFWxOuLgrQfZA34i35i6y-7f99&@z`KY2Zu)DL$L5Kb^oDOB@6ZU>XpbUtuiOPsP zxTYQq0a9e{7YtFQY-gu9f?5`!L%jS?8S^TZuC`R5=*7&7ii+?M>6XXG-t?^tzeC$C zWtWzn=U*aB)RG5GtgUa)br=l#z6~ItH=*aL>=ZLBa<)LW8RBAM;4yl#jomNLguzGL zu;_Et!QSS2Sc@kvEQ7o%?bd~WPDqfyZMJT1LLBqg^?XOQDjUYYZ9S!U=EJeWUj@K0zr#m;1l=8&FfSTtG`Cut$a*Y7T^R zn}VVD;1Hxkary7xGw-=SiF$W<|EU@j;Kj96gEx6s@&kVNbWKee<4cGPmVgL?Q%=g$noy<|eQhi39#)oE-)&P2nd9)aMEosWCsezKLBih%;s z%@~v3i)7Ar;QH_q(NSHW?+N_tmZjMk&Z5$igUR`0`EXEK|BHxl91R$x*;-je&OMY- zy#Sots&CfeQ6>Y$LpfSe?Yd6J&rOm+eFehfU@mOIBiMrST%|p+g3;>1Y~VLD%=Zxd zWFX$m%w!dR|NcE2y+^pq2?K6BLk+0;fOEyIN%Q8=Wf65zkd|MpJnx(O^RvsPDS;IH z#FUc}$A;iTAEA;WeuL2J?MYSkp) z@#MfKP{qio`(2(7dQ`Mb4)d*#?6uEukdgbT zaP9XYOl>H?=|kK7)^&{2cgx?oGfAXBNz4^hM^?=A?_M^%nPXRRP&0R8A@g{z8|Z(1 zKor_G$peVx!CXz}&g7fJFTDyZh;XE`59Oj`msLgb2JthYNC7C*FJRHm=sE*!ze@JFIlw5Np0l zL==#0GW#WsTZe`GsuO+XWA*nq2?J#V*bwhoB6RUDUfvpAs~GwXrJo%Q`Z1+e6O>2VI4O67&)cFLBNHc)SoHM;>WI>bym6aAti)lu!XUsx0720X%%Ku`?n4^tde*uymSASho1J~cb%n}k3rhK16 zZ!R8E(>SBXm+|2G&^FH@k&&L>gy}V3nw_Zk>pPU?j-&{c)myXPOA-_mY{i#Z7j3m* zCdKrJEs1`YZPE=hH@fc* zLh5=w#uJf`)E`pQ+Pu4MX>(1v>?PxI!L86u=pXyCjvw5GBGLPJ^IiVhdK0yu`E0v` zHWs8uU%(M#FWEEV9dvX?9H8O%KVc0j7h|ZAEi3Z`zbN^MVGe~=*!4nKa*Ga21Du-L z+6hz7c6Dt4^qy0w1f>Ve(H-r0Q1G~yMaaV4eeWF5{~^V`Oia|qdB@JA)Lu>eY3C)O z2O^Fvb7FNx9GxB|1#{<%Df3T6!2KPmgf-`jYdjb8Fp_}5YvHzfR8*9ic{dv-nYNu7 z7>d5lgHhWR!9(cT{7;O5-xvq$tmQL>y=P#%{bf%k)t}uR$AdQnm8) z>}tt^0NT9K{Ynsxc7!6onZ|PIt8ysBtq!L9(1vz4+1LTaW@%brL-OoY+|2U%@1gePtvGNdqo`7L2$W3>?;;Pz%G+ z*eZ_JZLQkTE^%K>f9^i@DtvGJM9gOFU@S|k?D|%7nTRt6eo@Sa-s$Fq9|^JO2n+jq z4wx$gM6JjQ{nCVsZlA3GGu6aH7|pasWPtVM@k3`41kw-?q^bJQni`4z@o{@N7p6}P zUf=*&6>}>n$)6?DzQCuo&VwAXAM=4M^}Yf|NiqxYEzbZ7p){9<-|n#iB)IE_eK1ux zdvjg3`1R`xG#+OM{Q-vo#w9gLECgOw?-$Vnx2#yU!+T`Z)WR?@dX-}d=-=6lRf&wf zL%MI60zB0sfrW$Oe_&=-v$*s+A&?OjZ|})!ib;36Q^Ih?rp|_?99=WTbmK%^u9{!H z`hqHlMt&cM?=WM~8tD!hy1PY@20^71hHg+ghm;NhNd+7PrIDef zK|*@y5Rh*8j`6y$>$;z3ed~RHz5H-3SU8;L5qoa?wm~`^zwUl{RceKal}~q_1cQiJ z`8pQHO^g5q40`$NSU9nq@ffe=gQSTFW%=WPY>69&*N2g|&8W4N<3>|!nn$q&ZqA@!}eTIdrP}`_pL_&gXrJ=9GrN8rDVdg*C>L2)*OJs4e zlh~b8vP}w`mmjUI{#qjN?;qsY^x`qpR}EH)(D{s(=KS;Z=h0rh>$h`QuYVE+I zpw&-s_D{(E2Z6S#*k(b$eqbmr{>%&~x~yCcQ4KZM{re;S`tYj&PL9?db^nj0`Qx+Y zZ6}@)lao$@=}R7d+=?GY$hEW#re?_(mJ6gbwRC@N;kSNQjR+5q$NQhp|IbJMd8~iF z`%B&Q-*5k2F7(fwE-YrVNLz5eVML97DNNISH92lumnnKcYRl91aPmv(xMz~oxFw4f z^vOb%WKq@s5k&XtpBMl0*Zz;c`+o)8{rkXw@R-&h#ss8ag*~T-n?~iMH@*SUqwhZ4 z;vT=>xjx}S|MF|*==9d2K1Pe}Z`6)Yf2DfxFS+@op0Ho`o>8*l`Y9|Uui~nB=_|xgi9AP<1jeY{{rP``h%H;O!$SDPte4UrzG!A@p z99|u$_uaQ05vZ;DMM-Vs67{8bf`s#{-#QHTDB`RY$!c@;$@h!Ue~$T|KZJp?JMO)4 zTvWEX-6WvG-1Qz2u09pabl2UzEg<22HAw)AG=h$co7B+oT|m_US)u8KEa?ZwhNH_x zNB5(HsROL?ZO=^sUaMuMOo@~8okrO{1MlprBN40X8xnRR73_w5n2_Jt9v{ zt!SsM<+@Ov8+^zoFt4pY@>U)rE2K(EXt-oQ|9V^_Q69rp=M9W%Vc}&gSUvTL&&-Xp(C;OE{V9PVGEw=UZ;!g8kB3;Kg!9+0Qo0(P{eOjWBm@azIUA?vP~)hMf&>Y zWD*N(ZKLtS-&3 zthP)rEMT4@HjPfp)&y$x&bS-2tFw~|rMiyFLzk(MgZPs##PePo zl?S8vZe((bvG=uD1~dK&)xV;+gmh+O7E9)ah~^qvJDuM&Oh7~}F+4qYNH6m?ECZGX zNkk4OxN~O!@K0`%7}ryglNWXygE7+LvNAZRo)k4TWk;3;F}QKl(Lf;YfzDEVfhK^b z=I1|qkiOIzc+)xd{p(Z(%n^wA@2_KIl+N9T;4}rp%uopeT3XsP zz_QulXzN2J4X85icLq}R$T;x}2-KwGn0+|3@WVc28kN<@gfHDj5{>2-7pr`&G7sl` z@PN#&dCr&qF%96CLwiN6|Au=ZL5zRi>wj$+?&mgH*Rvy??aWD^>7F7ocz{MTc)64={#@tr6rs)q z9QhN2rGCC$Ixfzci>bp*3od&he@$i{lPq#hEJyX}W4V812SDTw7_aY#rF%jh(|5_b~#Nf(xaG93wCrz4lb*=_)Gg%3*kj%>{wm- zJ?~sXu7ut3P-SZSo-Jo3E0SiPwEBDi{a#SsD-o)lC?}&&WC}UAPTl=)#LuQ%JozSf zQYS&*guY^|jEr(souH?3Ak%!@GH0<1O5KlZkYi(Gmo*lUkz5pjPdgW4WwC&wsE)KW z2FO4iQS9XSx~8Tyz{nQ44Xti%CD9Ss^J8MOvatc}O8UC%;dyQ6#J^NN24j)W;5v%T z*5Bs*07O_Tejzhst8od+F=M(n3KMKoR#72ZZmYO8DtmJqw|H-E z*EcRU_K#g$#Qa|ifKtZELg2CC$R90kQVi}GeT9^aG3cY4=zJ4wGumtDj{5tSZy!O>3(s7U)dHj^Qo7IebD*bDk z)RUf^pA&P~CqUsHO9_{pn*_&rVPQe21I(e3&;J&_6!W?SIt)R32IF(tHN=b@9BKjL zQR9&Jj3Oebqh%&`Ut_byZXNrMGrrl4T9UhLo zirRZ@6;uVPVU&epZW)ADdJkhMSaFo)WM{8cu{Ek8z7GW#pNYdvqUyTzm=rt)n z#YbH7WyPAIwfR>i11g z3WSJq;Gp$;5IV@Hnp0fv0aP&}J(lr5HwI(-se<}erNI2jH$&L9j|?-w=46JqOgEA^ z0{D5M8XU9)T6cc&15)mjG1>T|;7dDH&9;V=lvLIkRx|lr`XSTp_xaWKQkm>Rq@+o)^z6VKH>nqh7pQff-lje!JSjq1bu#keli3vPSl z5yws2)rB>6L^-g;AyGm?)x!S6enxDN=QY_d;7>=vO*{;g05>FJ$N%NosO~Np z>LP@feE2|0LM}G;aOC9!+_qXcS$s%H$nH)pNp`tugJG;ZQ)i2EuM8ys4kV7fGuGW= z&lRkUjDYZ<9gYRpP3Tob%HB%<73uDqDggcpzhAP!WJ{s+XiVm+tR(eP#`A`6 zoRO>+OTJFs{fv60qPj;~&jfuFp0w}L*+PzDzzsn*>5M5tA|3p{lYB2j61A|i{9KmlO3&2g$BzHJVmgLms!!Dpg5Jtecsn~UuuB_$;v85pPlGN<|e zYc4?PQq*;wWaah3Fo3i`CH>iMzfDR~9l7<7vBXl*EXerzx!C?na@}k1j>g6Q-L##N z(gXmn_U)K-IdhgN1yFjqEq<-&lwr%Aki2gZrNYy%O(xZ z{WABFh)Qalgp=euP3L6s9yGTI0ewzG&E}OoSi0Q5 z<}@NAn%I=S%q%6Nr->67rU`Ify> z#885Py``ZPoF|!-p)F5jfr1z$J!glJkD>t^cd1Po5&GF+S zNkN>lfaC_=nGC)%&)E@qa(_HQANS4La3P1q;r==0W;TK>Ffg!8m9hRR*b~g|sPRD7 zn#i1*c=pY3`+Xg_4JzcVa)^;SAwShuKJOY3KlPLsxcXQTu5iDwE$>QuI+s!y*|9&D zLjJJbI&FA6q9i~4#xN;a^K~Lzam~_O<)|7y&-#L)vRmMC{{VL1>P=XgX~Xxi;#6=? zoyT+mqrcapzC+_lfngM8(*mOPnFA!tOiisjP+xqxWw|XNHZK#$Krl_jnHg8Xuq^Wk z%ij;Rw@ID1`UU%Mb9GLcQX2OIwo0c4Nn5M)4lT)=k!h5X8Cs#Q&CO`f@>Lr?7^5BU zA1jN5kv!2Y6}g&D=D}0ruJ`fjeBeOStuS%a+EDihVRQH7_HA35eu1-mk zRv(u}mnf#`U^?6ZLB8B}6kZ7^7wu4&+xFO_vWG_nBetaN+^npxVT;$PlVG_MZe()C z%iZ-4cZDfk6O7fbSVk+uSbLqHb}1ByP+We0lc;W`z!+DHpGHB$Hfb0JV#Khzz2C{0 zP!`H?m@vZ@^BUmm*3sE1;;SAecK@_k7KGm$o}bs++8Wx&#>yHd#xCMJedERrLip4_ zy?DQz96=e(u0TtyfN=TuF0M`;G=*gio5y@fhT@7){#!R;?kvei@?%C0@i8GhML1FL zQRwZUyp~{0zh2qLTfFZnuDU8uYGa6ARKVN`;oHOz#!eRP3GsI+vwqEo9j?iwV?CK= z*MqCvXmc;}f?N%gYa;w_FV+gzh(-Lq(}$&+H|sj(x-N2{GEEw>AN>uzS8SA}uJ(+O zozI@E-VNQBvkr9%k5Nky-2f3~R|oznn@!ZbC^(o{N|xnIF?V8Cc?ZVFi$Ii<3!)rtpM>g5YDd9%BX15=|CfJ_i zBb_U1bQ9FZ`lx+h_#EUbVJY?U&FQ#!u0gb_u^jTdS+xPSz8zJ#(*vf+b-P|WS^7+$ci$PEN*D`@U&&M8it`2 z@rXW`m2Exg#2iJwd@u~i6oR>xE-x?fGqaPD+Jn;~_5dAsn^b}(bm%G9)YUXsvtj4? z%>M3fE-3!2{%F8M#>F&C``1;%g9)b%D5zH|7I$auCXTIKLbIJ!C~8=ArAnmB#>aQ2Uzv27&so+O;RQ3X=uWhT|L|OY52JC%;#X2s zP7eJtX1a8OyYF*B`qp7wTBVfhSy$&AzW5yjegQVum*gYclWM+4TR1Bs9FSlp=7-Hg z`2^3WYCgBHL+*dAnrNWuOL%qZ6H!{0``ehxU}%W7wle6Us94eEH@^|%{h3pE4@i!q zP3jx~dw4XbYU&485(zWc7xEoaMmr%E=P&F6%XXq~Gfq1^A#35!7OvNd)LqswG{;G8 zxTt|<$K+!;2$0_#t~|Eqo*?f#%im*(*!`@UjCuAh<;wOzEMjBng7_tl+lB}&o1dP3 zVeY_nU}u*=;>s9T$0ck7By}HA>9qCV_dC>fl4d9u>eXD&7g#F)DdBGHf|;c=o}lSi zd3<7K0*w&pKv#0G9WRGmv*9EXYSV~?33WxmTnAG6<9lsT5vEx#`qnjz0> zg--+$V9`@Ko6UUST+ugNDs|AD(6V=dL~%QRC68~!OTv8kK&dnQ{g7=K^5k*hmHm;_$C?2jyXlFzA$CG z$Q%+4mCr8?w*hA9Ca_%ql;!oFb#JR~duXP?+h(CXT9B7l8c2Z_pt)Cxbi$?lp{$T_ z<7${p!hkbi9ao}m$rcEzfvrpdh^hGQ)YloW$Slw0dou);ZkvWl05myf8VFlF{M&Y5 z^(vDuMs?BpDlZRchd#?c4a5xE8!l8&`cS9iM%Hii?qFo$*%y5pPrqj}k{VaL1$)Ri z#gZ=$RC*|DWE(EhRsC$Gc~oT#d>bPP9016nONSgmRAv$Rh{}1>;CFio^PSCS5X-8c*@NRC&my zSTbfoI#VlN6ligI8b*oos@X^u>#q_27=$}R>fAWCOS=8!QY3a`rgBnaS$>U!WcBXq z0F7Qk68DqL7PO1Fr*FH!ZCmoPhmvHse?HpdV?486LxG6+t4W5aJ?BaHM=#l6tJ4kq zat#7HAd3c`!`Y$2`o8h(c#7NQJ&*>yhP6&}Tf<=5tSO}*Ke|*}8?j2G1?HwTF~}l= zku5Er#@>82bSgyK;VfCOP;q5m%&q~`|D3Yl!f$c;YJO|hXsSY2zyNvy7+L3@b624G z22Nloo6L~8Ua4W5zhmFg%~@K`H-lippho(kD;~(qMY3FwahG=VV|7L$Rk3poUDFLg zXB{UVgmC-Cw-coD`kbC3Tr}|;9=K$v69V_O`JH>92{%-TLc|jDiWr8?L=VA)_`V?1< z-=?8!;Q8krzw^;x?E!*%bjnoMQQ}+B+1u-D?Xy)2BtopWkH|02d(7G~P@S*-&T$FN z%vh8moNiDrztkLqvB&xqMv{^Eexiz<(=Muo@8#Yy zHlIfycO;91gsgF1*P@SlS1==Oo^Y?~ItnfU0>$B_4wLB3hdPcGB06Koy`#4kd_u&i zM7;be{S)bK{?2&b9Vp7W>|eN>IB#e$^(jSm%C%8km~1&nC@q^m(jTA6N3j@NNtjY< zvCj@ZR;a)6sP0oxDknN)SjTqnBi^N5&$|-P-4yA_Y^-b@PxvYq){IO9{_cfTN|a;( zMz^OWAK5km#y3__=5e<-03tcsMRgW!INZcehD;Q~_8G8@n3x!C5@S=-GO`4*SFCU} zx3$<}Gu|==LiW1^c2{sdH++G(JBe!nUz`x`l4uNwloP#;!b_gD@-{Ry%o~3q^Dy&} zrU9HoP0KINcZk9-`qL*3ZYo<}>f_Cf5TrYSf%MR;n)WA4o_dbS~tk*m>dhWv6Srpc80GL%QR)? z!%9c>qQ+pW@8-{!lVglJ>4`}J&CyyVLpF&?b3PHLITR;b~5{rtJ^^Nz)S zytx4Drw-z8tJ+_!*zu>`l!-X0yky4>($`hdxeNEYTjj3f{rTLLzAtE;dyzt!1%hrw zw9j3X3TY;0zr7sa31sNA!rN96!0c)@c@tyHvm^F4SQ+OCFX74%-BgJC!p)1O;ND~> zCL+qo$9NnzI67LOH_i>|2o|;F0|ZZH(6XkcS?b-n+s@K_O&Q+A77E73kdDC{+%AjP zC8o$lo9C%x7~RqzTA7=_2Hl4?eSO?|p2c2Jffoivmq5AA2qu5F;z5!PhvZQ_xhK?d z5?yPjD-(Fj->6^zivG&TrlI@sEcmgTWp7n`CxQ%Aryu%Y2Q~zR0c53hM3q%PjYe)X zH7ZQZ4W}bbow*i<3RvF>C7{)N>kp(`irmE24v{-z?pr?;i08T0z!M)T|6BEEHATqM zzj4VBryn^loIRH1^WPe8Wr*CXfY&2+re`FOLi!oUUy<;;4y-F4nCt3xp`@@`?FH6LYVILR{#3+*_@aRE8yyr8f!ZU-32#O`pUPcrNQ zEFxIbI8&g=&5KF0*ImOxulMZPGZhu#k2~n~)VzUJ z(y@=0saJ6EJ=Xmg$d>A6dCw)@x6f*6Bil+iwT0(?m0L&D&cO)D2dN3a(Rk60Q+EdpryRs z>bMX+<)1z7-~Zb!OV6C2;9x(Ss@ql;aG(7qEn{Khx28~Np)m1s2v^C(Axoz<>-49q zSC9DsB(x54OHoOR?wjpfzzOJ23mR}#ZuRx`g8nU+EfLaE4j$Q~&p7kUbw7DX&Xs9> zci1ei3##wL!<9q&eiE_EY%wV_Wfv99-7^t;k#BlDh;txSTsQwH!}^N# zX^i-jPfu!nKtysQwL6$EzBjzKz9|(nF0hyB$U$MSaW<(J^|VD z3creq$}Y)XT{AjVV`5<$29>rGs&_^2-o1XPtINjD9sz94F;(XYkM>D=8z^POAdyIY z?Righ$JoPX#2eJ_Z^uVQ{`NC$@Dl2H{2UDEy7@l<6;~WAERbe3*G=NZvJ-GZ5cT`K z9^#~^E^dHbCWO;8zX?^A?WKR3W}y)iRzcNmyX$J=RJ{2PMw@Wy>6Rd(4IFFA)u(zH z=Z_>({&i!&O*P|;R{q3kfJsi5)Do2ZavR2(`5y|A2|%H%pJ0NoCIqXF&&%}0vcyJg zZoWo^`_X#3>>Ebf%C4^yk4_vllu0qo=At+up^eWEoglp-?j z(^U{Rbm~pZ!YF8hZEF--UVOQLGmM^;2z2trYCz}h?E{Q$1Sv8jMnJmPlU(no;=F$!RDVHx1RLxLdN>9oi^M?=S;IGj@;+Pcx@?r_l2N=A)^jxf)E(b_xp?Qo z`4_V@ueaw<>ODo%;=`j}vz!n_$&Md)iPLr!+DOw)j1yTN@8#)cEAar6N9l01HI0v} zw9parBw9*P@V(bLV6%K2Gh63gKCyG|{qFY?+2QWDCPvZWDx!azGWXDx){kq$#V)W| z$}I0BQLW7P2#0J-L@=}e@tbe^JPxWH5QVoSxWu@TTz%~uCx=uv!Hf@5g)FCE)@r|9d@-VVB#6r& zFr+_DbW{8?wGLYeS9kfh$93oUGjSJRI>@X3pNlRZV>Y-sEPO|Q(>UFEe;3}D*i;ba z|9OYer0(YdlX`*$KEEYj@Bjb}__$rih+?LLpuy&3>rP`tF9$fc1Cmk9bWfW<~E+{st781*>M!!)YP=@Ii+KJ z`0FRq6I3!8(|d2Dlmm`}Z+6CFZnd^6^hAgN5`bC?a^&F1FIh6>kW6$is>bb@i;+() zoGBL+)3uetB9Q4ldiCM^ixCfh?&7zWT`iQ!!vazUvgI}t54sxb09^9m z6!Z`XU`Y<`<6&hr?@|Ub;m5>w^v!2TyjTeW0AWUof7Ig$VkEDz=b#}%6^&6Y#4qle zeK0!cFQ@9I9~|qq-!fJ2bz)zh<@)d>`sk>8{k{P%a9DgO6zZ^*0_D!Cgl2lOttU70 z8O(w${;msa%8>3h2H5ANSXg38inTBSh<-*g0s-gIzc`2~Vh1THTi=6fI_Id{C{_eQ zCdFS?H(_{3|1$0|bT=l7&?&CY{8|v>S5mk<{?hgfzK(^mY%!6{4^VnjfuKAcrFfAy zerx9{h%Bwi#C`)%9~^yNHt%>d>$~B?PrI9_Fa?1^%Lbjp3Wm{!r1Drxx=ff$>7j|j z`Bx4tQECpPaE4{rQ3?pYgJHA0TV)~rni#JKv4R-$29@tJt7~)p7|GF2Y+5r56Z1Rw zKtZ?Uk+aM_!D|2yG{?aC{rf{6V+aL>b}JB8Kw&M)1XO`j`4hOFRTV$KM&5Ej_od7Y zZ}HALs$rM`TqgQM!z5NcDSXKKYCGalS#Sxc=)7sF7cws&3I^pl;C@$@cWf@(`#Xi`@`1?iab!nk%#`P!v+q_{$64cKq#vfp?FwwAbNJ&{ zsmE?TYx**hZ;(D?&p3hgsrYR%DAUONxcUQA({MqXyRNNt1-EXyw>kilV z(ZV)?>l>p3G*q+aoTe$#xOxE?gRz=SDSqT2CwXul!OOPOm9gmMSb+fKU{mqS_-E)< zZf$LEho`{yC+x~=N@0l^883wifL6k&DM`ZHTmOWd$^3G6xPS1MCuk1xdLn7xZI4)=+g$)M#If8jxB zX*v216HAG1LMq}GW1FE9z2H?3br9o>Kd6Cp?A&@_Rk}Cedd+|J+!Qei`~sAEL%$0* zLjP#efxbgp6t(JgAvFCgTblHz6`gYpiF2%i^_5A73F;IyGx9-vt<``Y*+RxOHA!*l zf0C}!2I@V!+X3tfzzwd5QFnKAD5da_Zvj(&v4Vk8zC`Z_?PP<00%sf!HMm%^L_T#&eME=);HIZ>GnOXXs?gf#+ zg8dx?Zz+PDBcOHg_tfV!d3Z(Ps2T^PZEOT*EPLR`qKkNvKQQq#FR<-pPG&=wXo$kgnIt7~jY>?xf908CS zk2-S#Z~5q`-V`~dKFInRMnOy1)W^|d*7&&AJ|V7rSt=4A=d~3)T*Io zoXOzQqmXFL7wdAKFsz`wP(qvCsycj!XX6VtB!OLw6$nC&S769Kg@YM|Y_MbH{D-bVzLAgtTNC?)(-v(iN{oG)ufih#Q_zZwm z=^zS9O2elI8(`5lHa0?^_khuZHt6{)q^YT?W}B*(7WuLXKp6aw#lL?2`aY>K-8}ZJ zVmVP`Imyn%4ov1P1bv~*c{!-4Fmr#_Dw4Pd%LE8rVes(OZTvQ{4`22O zX_7rK`4esipixUIL7=eNV1Y&ER3$}w=QcXuwymG8bFbrs?06fppp;i@ZCMDWPPCnA z^i2Ux`hU*$x6I$Tc%)!d!*xQ852nOq5X@-z^i6EwuNl+Ah2HZmBXle&B}GrZMD;)# z>g0^FHkh!;Ig2S2&qJz{@Q{aGF~P+?GVU~wV*sud1srSwLTv>sm(M`2ZB#QHV=DbZr_Qy7i2|YR*t#l zi*C_?u7?chV-ew4oJ{(1u(OBQ8FTLvwMT`8!Pvn_MLr=17neqa_^K4JS-aZ+B^KtF zSx`BxrXL9u^w=!`s;rt{3UzO6WF)xi+ZobwkJo+6xUK&7?c3G*hK0w3@GK2#%O@_y z*!XW?f&tF&YBfh3uS`?j)_6dSvQ_K%jN`ABZ5P|FZy95R9e)Z5xP>Wt3*qyt1h(HJ z(0?Zq)>?lsYE;s(3#syZ0Ay*vfB1W0OR+Rmh;G97*%GSAd9uVfN?{}vv@EJm0t0JZ zvEo&r7G8~)szh~b!7KETnktZ1Z4(7UJXHwPNAf$50w-`mtql{Y6Ihkx2T(F$d&y;I zf-E%zb`MmKEjtKmRkE92HRXjJXfCn+DIfvFt{Ksl7PVCTpt(yKjbMpFii7u~&%g)= z^H54^8yi`L)?=ckf&o0A4H@ymu$qvF7e;0R+GUF}32{xs%91aN2(j zAWG4(A33^bx%^mPKkQ8Q2B-n*w$5vsbN9qFwV4o=SB)H)@q-Fo*Ne|T@6*%E#8<^$ z`R2?Tc3#cg!NYsLqr!)lb))V8uqIy7zOs}GHhP8h`WN``AbShf&sRXA+k2&JXlKRM zuAA6yuNz5QQ3eXa^nl-4$*Fm)8Larh`ePtUI!Y2bn`eti0fX7e!FgaL7$1n+&3(I8 z=iJ}l?+(QTX2#|6-1EO8!3bp_QU;Bmm=tW|_3-}uo}m=BxU?V#`d1+6bXvR*>KBVk zs@#z9-SPKFWnlFemo~)Kw->q}uaE@iW-*D9814o!m~khK61Q}$_9~pyZ~^V&aVU=) z+ZU2maps^r7GkR*o=hohzTFx__H6g?^|9iQ6c;o;3A zxUu~hfVe{JGpL;yG_FB>FL2`YMk_I!k`)c{T*SQ#rJGA2v7A3L|7X|6|{+` zBm}mI0eU~b%G$oPKGHz=ael0%vh#by37jBGnfv&Nq0XrX)YYjY=y7Bi&Px$}xJtRw z??1y@P2@KFE>2dmSpae@)ajG$2)pEeAqu}Tl)Tsf1^XePV-%GuE2(9O3QIj742?KB z@;Qsv&2)b0ysXRv8KE8LF}~scW{8rdxGH#;oW~E1YOUsmXk>Hu^g@Uv0cpzRm&;lA zDP59?q|mn>JqM3NlCc#U1?E}o!kbU#_QVaL6UkRSatdk55%_C@Ana^hdGG?SB&*-T z$X6bZRyg7ftQ8c_(-zbtx5?%|cIk(JSp-e!e8Wd2ciCl^6GwWz*Ix}HL^_cG%eihc z0d8?84+N+M7JZ?hmOLkn*WEy^5;fI5g5$XfSXKykpRNMXGV0(a8eUMecX9O4x;QjjjyDBhKO*}59z_FSOQW^+8?s1r@_Y{q}fnxpE z9a+@aU6xV7D%zI=O?JlFZ1>=5xsB?)_JHO6crX3Pm(M?zv@`DW?YJ%QLcjt8_eu_i zy(>97G9y!VCeGBng*GpjYy~NBzuX3PA2{V6fO2ps)5H z10@}Suf!Q@9j=40N!Ul~45P?{?34$`*TUDtoejNEtPX<=C`z2uGodzKifF;j)4~V} zla;<&@vr+T)5s}+KF&L((IikOjW7??Xr`G)SwB8~sKEz9yc(r|i+b=!jYItRBzAwBvL8rB81v8=%W&QIj4= z7+E(6b`V&uZ9@=EMny#tc@RiLEkFkq!BZp{mG54$%QmAq7Dh-*>m|Z9xpksmE(BtP z8%!rBlbghC=SOJ|49U`^FHKELR+P?82LYbKRG^OU(%ztf#4ZQjJOz2J3ovDM0X+ar z2Ndmt)!iC5g_)Rwmisc*o|G9Qs1^X3sL#i41&&K()>WR1jSNcPn4$e`RAtIc#hJ-O;DdJ3C&wK^1*W zxUyLqV4#~%SoU;T*vxL-iDXurr`6hL^uS{NebNhhZrq1?Cp24d>OxlHhM&iA9k`Fn zlc@(?8d+~hLy6zO79)P_Js<8!e5vUJyMspPb26ngTu_&HAVzWc&EXo7{;svB1g9Dy- zC)vylpO@~T0|bkmhFhQvDY2R8J*UK?l=A!1yXx(e)%5I3%1dBy#R>fS|CJrxH+r~B~Fp@m%N&K zuHX1y0YT>P-GltbI`^C5jJ3JvgB3c8q8b;ga+0RtvO(!(4nz%OsP8w$5{8N@^j3Sy zk)t}hJ3^zFhvkaByh0yBYrU4@Rwx9|slEf3g*}FjlUc>ZHsV%pD=OhmM^j8@h;Wzd zdX#B|iEZxnd-M#RxhELdk=)AVA*0?e+SuFM&6je&2L`GVe>Z!)rE7Z9=ht|TqTTDQ(*qyw7 z)-949sY>fv1`zMJ1)gB72>3LrJI7wjYgPv7py$32z}5#bUJO3c-dtKz08{vceJe;~ z?(3>*Y6})FWLVYO$+%N&3=9EaOp2Uq81RS$IRlLl?#DEWFTwu5A5U19c0$#28&-ya zxYz*eU2Cg67{EA>UL&EV?mZ&PZfOevL+!0ASYR?ZAWD&ORF)Bl;*^}FZ6|K&g9e)+*~=|QYiS1 zI5}NmM^vi!gyFVFzx2XXb)_!kZBb#xQXa2YxOo>o@DxAWG~Akyqwnf^29GkYuDg4` z>Z?v~S!RTBH9N#{>sY+O2D(@s7BBiVU>e%X)1WNk>sv3}8K0`stfInc?C4kI({g+L zQ$UoYp8`pn8Rt|);$yc%7RyqPum@)dy5 zDRV$}{I0;5PRWLE{UWbMOt!p;jOFpP22mqw>OTB?i)xY7DyR8+QcV?)S4%;xs3>R~An!o^LY7BX$7QvtD4MBjyg z>}WT908DCBl{fu(cq2=P5H1h;Z41Y>-!fbI1Bdc60`I)+^;2~$?H>3Bf z9`dS_^4;QVdB00&6=vB;qZ*hj&C-$fLWO0EO*%iQIX6BBMzJKiDBcZ>dr^;(jGcin z<`jRsn)0aYnm~_pv{x>36w)xagHVd&KjYd`Mea&mKBbf0~NF%LqkYAw$=_q z=vQV?&|dQ3Mm+B(+rnsRi$||?S2iZX?hRqgQJnyS4r0SHw5Y~Y`1~{PV&$9@z;zYB z5a<91s_S=K7}r9Psw)b4r`)wECf}w%yzjdKu7iAa%Mu`j%Os2DHm;TiRHC^lDHQO+ zLRhN^ts+X9NnAVwOoAu@O8p$bN;wP&^j86IO%AB;4}h`ORiH?hyOQmn1sD&|$WfCL3h6Gbt{dX+V+%9wrZ)O*eXOTZ=q@IHtN|^Zztq12lbI#Q!q?&tm*lG31 zR+`^e+grxYiZLnr_*{n`l9NJ<9L!(;T*7B{{~!w1NDtY`F2pRT5MTT~ah0>@O~%MN zz@k0xGj|U}1J7)ytLn!rh!I|ib8h0znbV9Iyr$|~+P5RX90V)=jIbDt%&xb|9N?cQt<4RArX&ZdY$ zBahI7!JMVPDPfmrOdKb(j=#SYtsGDnOiWArzJlM9A+4=V2!{GT>m%D@req?fhWV$*qNB^5eSqo%D~C?yISAnRK(|y6$u({#q&DGnW2x;z${#mJ7O-t6FU%`vC8^ z=KrH|hmsIIi?Xrk`p#cxP#zuBSbO1fMZxoUX=TW6gMw^mGgAA>6LNpO_kgZ#;6r(% zs#Rac)10tiDl&&vkoBQ4RAe4D0M&QyoyvMUMpj?)zs`aQpNF?Dh%z7BQ|I>SvernB(9w96%ptpIrwhX$4WjZq!-$M^3w)QgMK#@#yMoYY>33@tv}y`N-XeMTgg zAa#;b+n1T2D`Z!_0Ponwb4UokPs?st6K@#PC_DY6941+`GU?#q|6B6uU_^Vv-UIiC zx%DS|UGYf|>N9Hs0@$0?+otd*wmz`NpaG+4*P8v$y`HUmO|x!+Xdg zl}aPIplYm9y#xr)Uy}QLUb>&F-W)D&nj-?XDyQB7bT>LmQU_3y!DJ0uXGbaWU%DWH z^rQ;1O6<5UotXW2)uVmNrm=Z?AU4lzr$z|OU4yFbw_E2^2VuAF*UtJyf)b=A?TBe^ z;H|nM9>?1Xr;2n|G`Mq`a;`)pmCTm+KnIE6cjmXGRQ9n1fZTz3RqENhoaDnf=hL9V z6C)PfC55S?pNe?2vsFF0EA_JubESIrCVZi--8HbbxdvpHUtYNzPrC7Enmgrvezj2U zY2WC5d8>DHy8gwo(91xr(YkHV#-m36+yAOo4FJVN%D_AzwDuD{3;kO3%;_`Fqi|e5 z=;_AOr-dS@?%pN}!@@5SvVq5#FR30_TMHx@uU zQy@<_*i}8E%G(}&=^Ndw1DIHUp+&f)GhI7hnhEh1nUFC2#E%~szIIe%JnJvC6*?ID zee;HPe<_!7+`vMc1N^vTn)r_flQb;xbwI%Nvui5P!F)aTED-IAR|DlKyK^G|0Ta(D z2Lirjludd%I&lqXi>$2NHfPbSBZ0}KYZ%m|b^7Y<##vH-=~n`b@Y_m*#Y%2B&}vPu z=Zd(2Ru$l&qP!XfSu`#nh;cm?1=FJ_FbF*2m${nw5#V#Z!K4jFY;0qxSFl;sMb=yq zO<)c6i$^tOSN7*xvcri5hu7$G=8AkeBV#isChY%kGk}lBg0Dw_q-6B?ND|Psa{zT) zYOxStY=7(v<(50Fcmbr^Yd+z!(EO&;C9$Ko`D&Y)m7Qw+c#}<^*b?t}kzDexJqgJ3 zy1ljE@NlWN@hsBll`aclQ89}-)2W_5a?(#~VtxNW6>;w`B9GVdF98w9Xy->TxlBV- zYFNeIlP=5yxW&XcjjMTIj(?&D)d}WDdU~U$SAdx!+a(<=)a$v`i@*>(%8*}`qdBY} z=v*9Tg!XMl1n#_?=DE{FLy=6{U3r%&ZdLSRCA{gpi2#1(i0qf^P9y`bTxOy;dA#tg z`R5Jf>rr31?Ia1g1QUqm2)oXCfzc@X?=f;p(P16q;>2Mk!vSn5?|bnY-}@D zsTkxe%f+FTri;k4^doQ-|DqQGQc59!IyV^1&Isc~10i$j5CYn)JL%wa{(Su<0!9aL zw=@!7LEvPB0*=IBwPfyK0KpFhgNWLCdSqaT3kF8hC}Y6fCK^vfZE+EIcn z=4&uJ#^Ph-0Ro<9(>E|Kn`b1B6_eYZLbQYoKabi?ek`36q8w>|2kDE_7-I}`ocChG`+kET zysTHi0h;y{O{~%??jxy41+R&t1m6E0Z2x#6CdR^E{d@5VY01lL_t_gVjuQP! zj?a0rCihtHXoA3EtrCZg_# z-@ci;IsE2rpd!6X-wSN84CwNnHWb;Opc%LOLA}%^QyD)Y>4x8AeTTT6b9+^V1u6_l z1p4}}ZKO}492>O%A{C$;T>CLdAaxvxmvQ^fYviE#YeB0L(_a5}mrU`RjcbvM*XDAo z5dN7rK4=-p;OoY=q#g=fx|cUT-6I`krM`y23ITu~z=WWtpr9b?vKl)vF|oMg0TT50 z(sXo9v*jSkqCMhzfIYW$;-VDt`0KLm!U$-3r3Q2(X_=ZK6`d!rb1F({Pn92Qax&7lI`T=L_j%0#(IY7RN=G? zaxg#HGR{SRe5fWsDqKFTxEvA}(d`5WW4)293;t#i_ZU9@$a}@u>?K`q+bTP9;Hz{% z*pf4%usFv5nsTe@SoM$0mN%l};z>*FUCsWiTR6Ku@#ONZZ@<&)=w*?_6*(c^PYapPCx-UXw2%I)F7}L86K&T2}FAMazxX zK}*ur0{4iRA6FK474LYje)u_Mxh3&X%f{l@^T?j)lkp=og+*m~dCo5=CO*wpZ{HFj zLj#bde;!L>rwV!}2$3TMj}ZYN4sd{6tKGCxt_BNl@cSKpvb@Wv{>NYnQ~8|LZ6&7) z;ukMo5RBMZl~)iij?K)-Z7dY~QjtJJMW1;~{_^E4n>GP|G(m?0_)LJ`MwP006B34N zV!<6i%k&;}dPEZx zM8bHS&04;}-W28gvf6fiJn(iv1|-lCf=NP}jB&pfjYRNGw zrO_V3I-rZTjP@8GpFmmMdnVqweS@W`16M$|_I0S%nqYVqWAfWkv z_i6O`k<=8*(H*~Aad&_N1b9Bd-T{?MrSbRsvF@7Q&x6`=VN=i4p9_JhS3s~ce|Mdgw8a~OKnk5K%bg)QbNb64+d0*+?%4#CZqJr$FrVM^LQj#8<2ZhJq4!rkC zohaVc`deRkCMO^c!EGqvn#(aKju&czZpMR(V~a&}73PLjE*?Nj^*|W2&N{OrK<(=3 z@PnOE3;QqD&bB_3nAzaJ`fY|m)_$Q8#y#c=T6qP!@b-48nAljFUALzDH~t7Pp5cY< ze1m%R!6y=Kmyvu>R3J#(TYawrhAiT2pZ(7IxI3Czrc)iXKalqCO%;=zj0Rxr7H~W* zIOQc$gIM~;}dvQl?F2Y+u2a7m=JmFsPBX%0HTEg z(uY!WN~LO!kHGr9M(;zeqr7^?F%X2nYuhM+x@FmciR_t}&x}nUvSRxC1D)_n*fZOR zYnVW4{7iAmJB1}_|K^nt?RY^|ml-`79hXYRkU{*fxU)HoP9F-Rig7123PKpdf;+Jn z_<7Ar26co~rXNN(I9K1`5Bbtb+Sv_b(8(9ODUT?02JdK$1_nb1FI#=m& zH9@4H17FI!uw*VbB0qI!pHJPW&Jz}4;%9z43Wk#`|H%4E_ra%dSNjA z3NARBRW$cSyaZ`hM1w+9Dx`k~ViHHj77pmt*^-3EWoGUxk3Xl=jgk1J;t$vQhB%n5 z4#o?j(?z}9prVC@MSoj`-|qwoMaiFXXj6>3xkFoiMfcK4CeZA5fg&At1fsE}@M6lI zg5Js25Ta+y@zlfUVp3?+pB;o9gJX(*sQT{(VZn(M5*9WXrlqBQ;0=uI|N2P?jNc2$ zRn_w^Rk*%37p+&0 zlClCOc|B{zE)A1}2%B44?tq0G{1IaM~F%P&Coxy#ZFZ=4`^HO=m ztN$zxpj4ho2sBRnrqP9XlkQl}Qio;Ju!xwYm!dOfi#&)%Y!+wx#wazD~Zmq|GR zi-Fbf%jcCVmR#PSz2wjAb*X;r4e=3~?1G=K2OZ|N!3Wu5{%qjV>Yla!(N(TGufo%I z&|r^p2iZQfBO|(WCUI2p^zHb_PG5~JF7CVCfgGn|#M_w)$piAjM|pG<$t*AqwbEKjDE9KTSlkRIR)z^o30}j!zVp82Gm18>x#(qq7hW*jw`fHv zm8UP7*Xv?Am?=}yVkDCdEX!$Yv@yr^T?+{*se<#lhYwJ8{9PF2#`*7|0c(K`89#xb6dw&dcGevraF?)Q+hQpnFh0q?0YI@`Wy=Yu2a+(0tkdC>lQn z10ym%`pO9V@=&1hq;ySPpRU;ZijV7ZZ)Q|+S#CL8Ep`rHF_YhmCK+CmX)6@+qudB^ zy~ta81@}xZ65jgv^2AJRX@V(7Tk7QDUG1^13(Am)(9rC&AV`)y@bD|rjF)`826~V9 zc!E>W!t;1|SfTQ17zTJ7$B}Pi@RSjuGZ^%9ZX#Mi3=qfX(gLKUq$@O;*RkO|-qd$j z?Y%9Bcjp$$%1`j8{tBu;7Dj{-36EEGe*K_vbPkt25}$Gpxht>K3rX~&)@48+n`gK+ zvP`}r!g1Qr+Q*3bUPlo1#@j=UOY%P_!!Kc__wOMW zg=o*yd^w5GIc-^AO1y)%t1GG0G3vGG{%P}7P`dkV#Bm{+a0kF*`o9<9PGR7 zT+K1w*Eb2R2Z!myKQI4L6kEt_lP4vCk7HE2XQ8=;+ zpybKK4_3&+!Q@&Gd#sq6?QB)e&qA2B@1jo(3L+Jf1M^dsoQ_3>lb5y1Sc-Vwn3OM> zi=(YhgBR^PBkF8ciehi#fA6?Q#d_o2|Jzy{eO?u)>mU7dLp zxD-}L*3Cvg$SpTMFynbt1^2K-hVa9UNG%NZ`yE-x*JRD(KIP9(5N>dEEku&77>?K- zB`s3Mw_H?SB|6D+@TTLAB#7msd7x*zy~vt&vOzD+b|PZuZ!J$(CQTYltB!O@U=+gC^s<8o7q)_*rF;|6 zVpNqQ_q#;NOuc=U#u2p|?QB(Rt09!D?b;I0`+EwnO(OF;NMk+d@G|BAwyW(@9;uD2 zq2hu9s9&ErD$nbK;bHas zRN^Z7&D0S}=JdBws$8Kx=L_?eA#yU6KKIZCj!Tg{SAa@lS7m@S@u$f9fIMz|1?hAw z!N=`DRtv&0lpR6rxnSzv#Kgo_BmF_!U8~~zO%Rx#>bn^Zsqy2;wP`g5lZEai%Tq~B4ph{CsD5eKHJ{iPbF-VX(W?p3H_bWCR9;+5M$)C4RRF&Xla0Xj&5h1|D^HqNo$F{Z3(pP-AmIa;R!J@ z)F(pVFNEG12Kof_w4wDXUohc1^4}$LHONba4T5p=l}6aR4VYO}ffE#Mv(1}= zF-A@?HXP>uMo+7VZ|@fKI?edpbaVit&ry*)v@$J27=+G#_tH054g;N2T7YKjW7$Xz z-DuX0mVg&qJ<4uPbKPJm!rdiWw1@5W)?PDO3jwdkLb!X~Lo&B3P**omn z=U=qifcmPU4)7#nwu+_)H+YdDNrqm1_Wu)&Q_(PmqBHRV6LWg>uC1|eNOTO#R{P-T_SqoSWAHk^^6f@WqK7(q?b!W?(+le!aB`|vQdw@1;0kcUbN_< z!XZD?_@e^2LswxBF>xh`>U9H!uNLE&&+O+DpI=0 z(WdjAx+vI@T;@?0uNe(nUz8u{IqI;43PYI4iu+x__x{$P3^7HoRw?ifjRDzGB?{8- zg74H4GBSqN)nPEY4k0-K)XT0ggC;kotDd$#U1iW9Xa4((R|4_lD$B~|Bk!>vKRQj< zH#T;{I6>ID*6DzCtpfem-ZtW@HjYoTn0Nm6XQ!t{-3!&0*f4#-?mu)N*nXU(U&yTd zuJ3n-!;kTD{c!Zhcy~$F1Lc9aZ7^O*f!IwYir!vMpX)n#Sprv#3B{uv#5hP3zL_Wa2wzlE*mZSR(fr!CAgxb-U`%KKXRW5d^fgsXvvz2N6%Me6I=6uBUAduFfW;fbe*}m3)`)wDStgrr) zpR}=tH&!j1IxiO}Tg0z{T+Zg13l1^)z zDfIL~L%B^LJHj>E7V9{i5O|Qy(Jvp-oecQXR}z2P`&nOX%E!;Y6ny&4P@9#g5)7)- zS_Am_VCgMjT_8`35HH8+4B`}>V*HWE+M^A5ta;LgOu<>XhH0*NjbDxrn}XA#R1%5SnhTA7L(%3fmnKyqd1D2z6&xx>MD-Q@!QeTduA1L%?NBxXEHS;+&sT_}o7NPt=sXgL@|?>0zP zY|4xz%`=;>BxumWD}}CNP&EW{S{kOE(;|*^c2G@arto6$W9V4ln}j(?+Q|=Qx1^*9 zQLzgxO^9&R7~e~!sRnii{}8hd zv_CV^4@=0Hu&^*Jx_o#Zyi~h}hOFYdku@^nEHj>;YghNyh$9Ud{e$FRn1T8oUePl( zN%Cq#y#xS+#Vgk{zKSSmA8)K%7K^^9rj>ZE|yydAD7oU{jRRn;QC90LNkB1baR{$D?4FAIA#A1 zl(5GN*!V!GKu4UaSl{Bkzps}!;?JAL{a7HYZ)7`EO5=;DWn*XmVgm}noF&dhzbm^o z-2XcN{^^OOQ&K>Wh;*Cvo2xA@5gq#zZ=*w;zrGPgPtJ*0@`VO`rQXZq;}89= z$FFne5&W@!np$4@>M*sUv$KJYrB=i{`E(>hY-sOjh?=^FNH_Yh(==FG=BSSRJT6dA z*XJgm1?A>E7PGLPDE5s#hgVq;WvI-e14BQTy-1`X5p}*)T)0evZHF694V*???B+{gFZcUz1G zo9{F83u~P!k6uel_EB@9B(f#T9m#V6jkfIey^;|C(Y%ck=JljGJrd-U9NSN~JDZ)s zguXjl26)Y6W2`_Pze=HCfcT3@>dTQl_epYjtVC<^t%c78QrVOMqlvtn_&Pd&X!{qL zmY!q>RdPR`1+Ww?D9>4-Z-Q`6Cmr-}*0o^(8YP{6JqY|g#VbQu;zkJ9Xn(BO9Pt#R zTY$(IBQuhd<3oxT8F*{fLG~vOQe5)wAVK6^i?LcD6a5<;GXA%Dckd)dP(&#q@71dq zU^3(L9l&xF#!%@1`Bw|>&jInW*Kp-HyY`^KZXbKB*B;`85=wbBUM*uP$LN247boc* zdtpQ>1SL?ruSBmJNE^$~Lx+bKeLFCxb@Vgrkz;P2u8*1~`!I20=sBiBR|+~^|D7Q_ zEAfcMT2l*A-Dl$%OLR(fJS88RIb@%S8TdN&8kKj5efk`pt5J+?rmCALy+d`EqMs5k z)PB*DGeF9}f_T=K`RkPX9`GBDfdMF+VoxD?QCdZtU~sy|%_RtxGCLw8CFNP2{_&%t z4vbd((>nPZ1lavhjYBGW#K`O0v{z!F6xsc%sm*t{SL_={!@>tvrzT+5?x)$?|Dp@% zummN;$|M_x3!M@zSQ8vdnSV!Dct2)hBe-;#3@x+eSQFkahh74M%9n8?-FQ0>oXI9cDzTSBI`QaT=PH0|pA@TAlX4Ou{i z&BwTc&3j|vC@=PB?dw4Jpviqgn5?rpZX|Pj#Wo#i2dXW{v42N$5=DM1`v8UQD6B*; z_Djd%dC%Ue5weI2$0=D4*Yuvy)w@^UeIeb{F}Jk7Q7GeGPzMrI3SsDNxAhy059 z{EEXnp{9TiE(G_+r!d@{1ccQ~gjzswdki1P20_^7=g(JF3=l3)j=9a%qCx#vHj+-^ zwmZLwEuHMWA_rQ97vk&1+^ApU2ELvD8$J)J`X369OjbN!zoxU9n4T^`oB%Ufav=|x z=QDH>8XDTTE^ow@E$-Om0fr3e4})N8oyMF0qL&|7i8v3^nwUN5?B_aC?c&HXI_!|> zLrYh-mZ7q(wJIr z55)WDnG1R=nB^z5mWMgeH7=_&K=03^e8c|w)O+C)Y#-*T%u7CB97enT4XKjBMVo@ z#4Jg2hR_hP8E4F<#wy8VgJu__IM=Jmx9aO6eBy|d4pS+Cz3mTQ3r?{Lv?K*>Am~zD-Q21Iv=szKhK42y8H9vVyS6qr zjrTwlkG8Nv=XlsxU?9^fmH6Nq?Sl0eQkN>}9T>e?!6Zzr6efW<@FNW^6SKBsAn1ER1V6KuKGN<>v^}O~Y`) zcjZ&HAAGF2I(o|9ll9c*Ba$;KwazE)qxvJJRSTqbY1;_y5s_TYXU#5Kc*S0SCj7ua zNy|zjpCg&ZN6S_~^zrZCw)=tBs};esSc|4Q+L0&qMKjGhmn8>3^g6N#hthfw(eXSU zSBcDiy53Ff%T{ytB8tak4Nf|Q1zV%vISr;`^A%yMaUOJ)4xP765-KW@Bb;eNjrd!X zDw%_^$(LR}H{IjubkzIo|d1NrpfLQkhQ0u^N_-VWSi`QYWs|S$_Wh0jH zABO_rBn=|&F`hqU{g3&BrRiYl4CF7~p6X@RCJ()bPe=$Hx8h+HhpasU1$#BK8GsKK zhZVO4H{WI2xjm8#cp6^mOk1TR!>h|OF{0ElnN%n>t6J_q>JiDDzeT~qETBLDB}Al4 z#F4be{He&AE%`u{LF|rTAJYGpC#WZvzLX_T@_8v~vBXoS_7*@63_^Q$*n_jappSrG zwM{ra8~O7QNZcd@z^69tt3bsf|7_2A2DuFBvbI@mGv?vrt8xPq+9p4J1?hCKCNR5Q zp#hM}*$oZa@$vB<%CfRS*L~M`82~wF;O2g*lpzGWq%Wze;)==0V8g@1lQuWcL&L)Q z;xDJw`dx&FM-#*?#D2~jG~1i2FZM56tSDD>C1;y+Dx-2O(Xe+_Kpr} z^1i$MM9jmI*Ptb}2l0LYNji!Rx3^acn4H zy-nyS`Q48l^pvrCO4hizPZ<>`!*C{S-SSt)gW_Fe-p*xZvSFG3e(VhK{xIO3@>&sa zJIlS#3UzV4v4Il|I=Q}~}i(3idbBeiG@DXXTRznJnG^Rz(5S)pA=i zq51f55}W7e(8b}LLt07Z+qLRBAR!dDxxS1mQFZYWiZf$9;xlMhKM&=9Tr~f~?aw8r z!Kj@PJ4PlxGnF67>{o0F&9F6$|F&bn zC4znr?5^75LikNCKHnz@q~hzSW!aoNT}@MJ(_1$}5qOw$4kEdyT}ws@fNR(~Dbf zY&7UiC0|li`}Y!&rKMb~<;@hOo0IpTL>B7xq!)a-y3)0EZF(d=={~Ce=K<0KA1rdU zTfHk<@phqcd54;sdId?n?*PTz%d$N{rNYDzZ+5|~?6@v4?D=-0^MOuEkcq zw;>t}p?P24D-w6r*t{aCZoMFHAA5>pjfIOJ=S48PuIjtwI4gJaE3_W)OV;^`lj=OBau?8b}71k?zJ9#JP#_6n!@#MZsO)Cm6Tc+Gk7+n z+t=0XN&_7J;D_1*N}5x%!JygjG{?!XjMo4stJaU|ZJmF6!?f>DmgPd$MvsQ_#6Ql3 zf6&LQ?eV@_7@V_hk^fl@VQwgI$Gu5!`r#2oH#DM>(Y;>F?w+r@4u+8+k*eBO05Yx( zk5pZq?EW*9g*}q=%x84!Ju?S<>ep3SIb{hia>14hfgFrQJqaG^5%;ct#nr{7!VLs{ z>Go}>a=rpmGV6MaA<{QUvL7T$Z2(&K@dsv#Nf=Tx_3ITaJt$8_v=S4h%}!#Xk?T16E4 zp;yG<2ow%BT&!DHcy5IHMTyMroSC;a>x_=dBR_W z@R>eMK*K^i-qXJad!J`*xxM5`I{e(^MDmwIUtF2LDv*Bs+5oGXM?56Gu)qJdd?hG2 zxH?%>RJ6oESC`ZV+P6c>xs?_R+beAR#0q*va;mSr&H!7Ktpd*o9|yesL7xn9d~=^E zlCcI)LgQo`5DY?S=~=*lH)9Uur;fVbk?5PSrEqI{)*h3@TEzhFdy5&oJlx1zN=ssc zbARNq*0ijm719DkD=8V0M!I?kV=+B=59UaZ@qV~%?JA3_*jM-lMv&#%{1Iksk~O!m zkP;v@`_JKiH@w=Td0%lVPaeLL&!Y9%Xvga`VR_`ipamd1hn8*5j=5ms8*!?ID@4Ot z_j`` zrdO`-u#x!%d9jDeWF|8@2^~4xfUcaKPy4hTWmB~uB(AcRt*#ptL^E**hjF_y%nFz> zk;fd?v{@0$qr8oBF1~qrS$`iFF?c2Xutt(o##dN}*ez9#D&|0168pv$wNVGK2@9M~|@p zFxvwNvF9-4tX&Q`M`xSCkUXld4cHl;LK|=oP^{6)tG-G{$EUCGRG)f^m^{o1tsV z=_Re{#T*FKwDB!iByH6a5GZV%x*L82o4=^iSZG&Y`=Wd=(fvr@6R`)F1B@ zM4W^&cIU|KnyS52 ze((}eylnH){Q%8bF68ZUq3LQjCvhYmbAJ)G*{}ZB>Qz2p<=~~bxbpHe5H1arN2r)D zjXytsh%zdQ-9x2rosI$hv-G_XqqdyncAV4*ylYh7dvmR6vudvUpD!~?y%3m-Z5w{R zyt&rD;Y&}>Hln-B0_Z&EhFU)WspuHtc~eL)hcJ7*DP04qfiUTnn#oWC#i|gDNDb-K z&+jB;L^y8-dC1KyziV*>(yBOV#{xB8R3^UGq&Y;){z@%gT9~o>BI7|YGg?u%c2bkm zuCtw#?Fx7zYxh%Pw_74qEk6a|WWCrRZjbrB866Tv!_Yv>5W~7rZ>e#AlS1x?`PGYq zpQsmu;|F^1Qvr3~LH`3J#~nbca1E4TDHb_zjk2;sLrP4$$MY3MBMAuzI@g6kiYUpH zN}J}uDPh7ZW&=#*yp%qv zLm%NHTe#lV6hFn@2IhjCbj11N)#zVKcI$b{mgu#BfS@R)q!T7PWjl}WRpCq~Fpqcm zW4)$sgbvkA39KEd$Q!HW%oQt>?Ll1DJNz-dG*R}H9(j5d?nVM~n55leZ#H+y*@UGN z0%QsN3Ug%N)O3`uAKGms!7otBn|cteTq)nI-q?dzGHlh^^g|9cd4yTf8sJy`8;2nx zRc_hqIP|C-!|4ZY;4``r+d9)piH{LgXhz&Wx&jyCC$hCo{Ll%*^h% zB2N&PjI0>eCjq!PWWs{EC^)D~_~hh+>oR?ywVt=UJYIuq1E1L0w%$<9!{@sX7m07b zVre?Q0hzM!OOQ0!@fl<$t#>js#uF0F#EC>bL1M51VsS^`scALYQX#r#rVC*c1a=@} zWVsi|&})nCjGd8#gBYM@yC=X=^W=O2{?28k6CII`Vm6i3%KHCi?>YD znZg>%A9S`P+%y$=c{5eq_L z;0p#4FiLO?L%GG>mhjF-Jq$RJ%D9&T$C=l?`jvwAY(q=01HVYb&DyU!w4B13&yM;l zZw?*;l_eOT7X3?dvf{5+k10xJ=CkgG-duT{_wR5SAAdpdyc1TiFBHp{X;N9}(nWu6Et$ zcm$q3AmqyI0YP8OR^(ZI6gKGtg3TF5yKd>TN1;d#=<;`K2oS?8y9mv0+?}J7^#R65o+RGxLBurexZpAsUtAE;UK1 zck1n9WRo11asn%%zod&>-YA`O%zz!~P=!c9RS^h#Qdc#jSt@5wj`yP*!B+Ci8sCwQ&3oD09HppF8*YX4@eu*W6`VWtD6muN zEr(Q7nXxw|P0mJL43THDE)FoON5EwG5uVEmc|w|qfYtynH0a_3xrUder{BkWg3HGm z@bU61BCL%hGrn{M*QzXEB4@t1AA>UFoBjBoT4s5ExQk&M?g}Hk04){ z<*EkVKdPpp*M}XfL^rf?C_5k)no3K~3v>jn!FbrS%|J$eqz?ecxmvh(Jo)y}_1XSH zaad1VgrRtRz?Or6er#eQ{lApCwxBz(@9yl3zQ{|}^Y(6fZzdst!Jigrl~%&Uay@d2 zm};bEmc7m&FY0?Ygtgp@NkJ*8--q_(q}VljS*c7(!S(AR00GCuwObY83He4S6>{%lPj&CB-|Ei{>s2Y2sqmRK4Ca|&n4+9<4g66 ze8l$nDWCW!E{>JW)>~{0FY^uGTqTTnskRDU&kpWn9r?v#K##Cc(_YA`)|XWlZBNXX zw~})&_mbnSxNlTamnG8q?6c3U!v=dW_=;CJ#KL>kZDJY z6A3Xk>Hch8df>YBrQfx`HeUx*b9&!x-dH@U1vLOww=;N%7-n;`v3MYpP zV*G6+)M_%>GSIze!UIPS}!3f!*(%Q*^suiWfRUq;I$#EuidmfniSAYwJ zq82wwTbCx)m&J18Z{{GE{B4sOZDL8}oRQ zZsZOfEqDJ!t5NGBkP#DH0U)*XjGapGVu*j~ddu>U%W6Z|8<_{6U^WGiLzGmJQHGUU$NU}mI)0_^>zND^6V}5R?-1W)=;CP z??v?)abzUfGGjJ8_LTr>GTdf2Ak1ldgKSyOAXMSIX}C94t4XFgK5cQt{LWWV>ntGl z4AP9FUM%y?=*szRlpBy6H(7q6BtXNt126#ioRNJC-1`ZLp^qOe{~$KOW_NV;W2p8E z=G>$uggA10)mnRZwg>^QnC#Y47mo_06=LaO&U`uc*8b?XpZ2k^=!VmNfmQRCpo*^)f%16cUO10CceD&C*BcZ?EQK3P_NU%E}>7~q1XU&xAU%@7HCO3pJ z>WqgzmHTuvQ{!>Jd{iM;w&sFZKs^S>{sK%jV|0||R!@peXH0orl2?F~5p^$ZeiujR zlxn$AP86sn{r?Xx0BlKHf*M1}0h)gV&!kYpiP!*tAQJJq{^#sGfC;I|FUPK=?hG$B zgiugWqOIVmOTggZ^PDIkcO9|QC5g+Y@X<`Y-dGOJxTk^)X<()Jh%7qsUb=E{fV zuF=1g*a2v;>&`sFxjiFEA9n$-37UHWYFu+P5J{wjLc+pT4<=iR zymtfCgkiX9U0=uCBFaeU$y;D2@R0!8l^aC8HYHT^eVMCAej+)dvs@^+&H$DqzmCRVM?N}!)M7DyIZDjml z8Ew#FKMeBZtKPkEI7MaM&*NEP(1Dn&kQ59p4qjbwmcME#Z1hKPw|M_)jr#KdfXV$+ zDPk{cA1L`X{qiB+0cZLaGk_M}i$^B>rCU_~sVxPtlp+-HupU=D1r8cKAn$d4r%nAG zsBS7YXvD>{AkU-Blrlw9)|X$qQtWnt+f=8yh9|23<|QvJQ8*lAyB%kN>9#G0Bd&l+ zBFjAo1#%bj*AFND0>WKie!G}Fc|2YwP56xEHh0@%np2k{G~}DaR$%VtXR25$*|oMZ zJ7?GOx2N^VLya3#mJ!Z^^sq5cwtBgEF@o$8=XZU1pJH&xX)suq`){M;ou0Eqo$1~p z_k_x)+K8F+m`;M&u$rX_&dQaZut(NA2@cZdhmMYuh1V_cv9+g5iIWjiSyQB-j$S^U zHY)HYjaeJ0je8nNDK2Kc1ON$d5q>Z6rZ8{dBd-KxJsG9Bx3yuOUyGD=(`Jn(&E$i9r6Zm5x&D}8 z)Ts1mC^c!zy)>)l0jTS}D4%kKf~^%zhz3Qb*@Ijz*m|gc1dfO+KeWpS3wRYT~NTdwipAw+MS>Z2731Cxz}#}@w4Odk0_S0Q{FXC?~Kgq zx%QLtc`^J89Wcgzbo|`Ljr3Tf$pQ@1{eWD@c90$jO$b6DYFIw)0j2$q);}^2GKbmd z>1Fl5It8wHbb%q#)a0V0|JfyS2UZO4W#X!MZDet!jCcaXM(UQnrzX zqrsDP!*e@zVm(nr3SUYsz}%9<$JPZ*+n*9^lB>Al?Utde*>hj|a7tVPPF?ZyW5z*hrA%6&mB~G0 z3+XTDH~g^(fR)TP%0~ODr=UOoVzb{(RTmD zbF{n!zB3e9OrE9xQ#`J%1sUmEeE6I!PD#~g%IEwMZA}?04QD5(cykv#G)DC#ym>pmG(a;bj32*$fU3QuQ*8mn(#IqBOanzMHOS=H zYs&tVZUBHg3@17>lO4E8L&C%HK?~jQEbWUNZ4bs@7h;=%*dZD!s(-w*;|dGG&{gFT zbUIm$K${`shAet_#%Xmo^ds*%b%*p`fA|cRB##zC` z1Yh?PEE0hWdRKYmC}p&QmMuIAeOZqGuJG-#|FT>rw>(W8LnU}10RpI)$V#F-lf6X3 zdj$fe9DcL{b=Bfv6u7)%lK!)y{z>#mQ(R`Ot$p3u3Z(DWXK6nBtOiN11Xf1VXGMTF z7x&54d1&W0Gj2>ggjK7U=2H9QSQ_BsIa^x=nmOaZ&9jQX%-Cx>R`Qu=r`uJ%(z9C5 z?hVn@wGVDaCVPpXV7sAi&aT1t5}h2=jz_qhk+%^m%fI{B@nhv9XMn#)No60Okn^>| z!(1iBMw%`H>2)UbocNk+fW!=0gKG!=tp%=;$a7TCdQcc;af$=Ccu62A2??fCzhBN3 zH8;a7b8%U7I<0#n_a$dW76S_TbD<$XBe!mR6QZi?mmeZQH-`2438Q+-ZPM9mKLokf zS|F92oAGJ`_5A!^LpI4l*h!M?BPnl(yN-c90&`)e!GSjo65BPgS?}tu<$RTeK7TX%cUxriHS)} z#0CfWuIZ1O6bhEPI_{=MsacW6{|5oNGG~xG;z)>4oGh9uS=>aR)h-g6=*0mJP$<4z z;dr#g(%ISB7$Ww1fATstH5C{W|FfqaJ>Q#yDLeL>QhrsC+W)3G`Q&#er z&fm_*Regt676e{X zGj1f~?EK+X+Ybke=ArKy%$7>~G+PnBMRL1mjB3JxzD~rsUOb}-sB|nib@#wi{P=Un zBK*bNp+9r!Yxe1nzn@w^0M@Cf+w*PU^Sv}?MgHFb*%NtoKV8r##Xh;R9$??Dl)B}9 z1E%cp+0Avv-c%AJSb&|jD$taq8|Vd?09cL&y{*I2RE~hXTHOPGoU*y`=Zlhteu0$i zB51sfbR#)v;r-YN5--~vAbly1G0|}RkEA@jn3^O)PwoVo{z9q1&O-l*aR)q7-LIFL zo11a3GDW?$l9lMoHyRvQWznGjv(?v-3-v-0wz7Ogbj9KD4g{{}1OiJ}IBj?KGSy^&Gg8Eicb2ajU0~$HOAKtPnKY)jP z(C;vzc!EA*GNOYytPYFJbG{{jY5#|XKq;pL9t)AQ5sLQft)4gt*#$ZGh{ z(GbaVxb>kgs%dj@`Qi8Fn*^uF4*d>UT$1oU(qcvXLP_W(bFp6*LZ z)Q*e)eKYOuZth%f!AA0A5Nm|zw=E=)E)4hts}yA4N?i3all8HXJ6b&{=gXMZo3+xG z=9Chkp{G0J@|56UfJcQ69=e1v+>wh=39`yxe?9l+TmKp~(M~~n;HZx`g47PIu=l5L z$cyMcAllLHa>j{l{tZM>VME%{oJnQk(YC#2Hma5>=-QxZDle+jinWC^1*ZC09G_l* z^#FMX0Rbpub92lf51k6kW@d2PoyiU%yE;E02IL|R26k)eS9tq?#oE-MTN~PX4S5%?t9vHRg-jx&}0i^jLdf4j@YV^(__} z*pa0GkV6u1i(k2T__?%LY^bPLxfE4sm#(^r7m~`^n-&0HQ*!LnJM|N~{PE$I{htb4 z;`0B;*;|K2`FvsHNF&k;Dhr5|BB4mPG$J6~B`HgHBdsD!2}nzKcZUMff^>K664KJY zS@?eH{pWYR?{j&`C2{dCgePuTrX~ZO%_qSfzUf zW9?Z4G114SzAGF%D2zj1#p{B^Ck>SLA+e%R1gegX%4>E_hch2X=`&*^V- z`^4>3zIJj6r9HBWsz^w}aa&m%PXjj)MhKl*432*_^%IL~eiKNMr08q!gR5t^Ic$;Rf5Pgx1Wa@1MVFou?Lc%Od>ArRIzg1MBs6v-IW9L$zD z6YxeF89;(o%Qz1A$0{ugkepl7`rxOfUe9=fW0r~F6BYT0Rm=-dMTN`VLoJJ}L-Z>i zGQhazn?`#z!e2AfYX=Z!JHC_8gDG(sKJj$vJ|-@@Yl%1#bohQFc4m2~q=SL;p6+sfQ+_j^Az=-a(T`J49c zy*C3e0uFBo|C5r4;-Kf4;pikK`HB>+w7z)dv?95Ej{aBOhLFd$m_J9+sD*W)oPzf2 zAr7*3lz;zSbKngqv4L!TX2gMxuKK>q4E;8fHxFq1ZisJZOngh^Id;fY&$n`_ulfj!Ou)4s~i7$ z)H_+Uk$~sz$)B@Qv!^)!drM&6{!2XIR{sZO-ZkUk|DKQXGyjTH@UOQh&40f_zWBc( z?)(3L>d?@TKPW$z+Gbayo$G`$R%$F0+!O$a<&94&|9&izoe-=k_pKUIazPIl$hqV7JqAIhYn=B!I%GG3%qIoc>7NWA8<21dV~#l3-JIi@J(>bRjQ4l8<~OB zgaHPqnlDh8zlw{YprXG(p}TQEN4elkyOBft44VMO5TDhq@4>@Q&uscyX2=_yhcv?# zeeLlzq1e?M&AOys@}f7mD!+t^ShTAE7-jI2l`f4 zg>_D!k~?7<^^J|~=Uz`tj7ggu92{=Acpy8`eH+(jCt04EtvL- z3JN^yU?4!?U~m6i3a_K1AWeJ%0IGVAD}O>dMG+Y*w{!$-rn&rzVr0-ROj0rPzrcv74E3bg_q3lI=FtDda}XTqtIVxV1br9n`SI*u>^Y>NnMsa&5a^|NOKtK90rvhkd6IqK@_z6lDk zu*ms7&Y! zj*x98UMl@6Lj(os*)s|U0Dws+W~7`3fcfMx{>(CEDV#;?wcdD@#K zphdxBCwA&8!iOn6mXe!w@tIdtwC1_@^2t;YWW4LyIsF&Y)pN4axyP~ z*gs5Ydt+m$7Uv!q+Y_Xm>-$nEQK|mW=Mz3G`c{N}~KT$FJMxlLmvq6aWSLYMz|Ad2Xc! z*HlP4pw_bUco5%DK*5_HAjWjvEKnLI0H&v6sObXKGacONFz)7RPdsFWpZE+RF3$6w&nquAdWdKo)n{RAtO2U0p*y~Nigc7@~ zPNGu5g@<9?iE{z&@a5K;QZ6({QQ*mExMu2wjC;|EDYF3lXqYp{*(56WVnh3mko0s$ z%w#*z()EwlB`7RcZi z=cjNm3*lSSb#TCa4+q$MIEa&*1G(hp<;gUPjtK?6E3c^Fxv>sP(`N(n;cP(5*jb%$ z;JUvSUZ%S1T&fEG^K4)?cy|{?1M4{UJD|!R0=HFp`*uBhF+Dy9y-nz3jmFf|NU-tp z!ktHVWKiu$HXP8Z4N-vNu1K~Sd!Z>%zP0WAf#J#Fr1h|xo@a(!0{6T_cYZ-Z6dBEr zTM^yZ@oT|1}?gbY28OmOZCPdJKd+_J`smqD#lhadX>>BlAQYZd8X06~g zZ!3H}JPb%St&MVYTrQ>Zh>Vn2D^2@_?4$?|<1s$vc@<2&&~cBLSP!yiY#T7}<>IAb z(6r(2VkQQ8R59YYoeI*@Kxam{k*v2i^adgKVC(2^S@m0MYj4|6{-5|^zoeSQTP5$^ zyVuyEqNm3?Pl3~KcJPhD&q0@&iRr8a)?(i$ilzg+ljrv%{jDt;spxJmvu%+z?a6%U zMwmuAYL=S~1Z%P#8TJOChrQxe>*9S`ybeMlc8w*V_=;wssmkxaar8i9pzNEh;DpIE zP~bLwQH$mFAolJNk_MDz9tQ~Ukgv2XJR76R534#^SzdOf1lR#XAhHFd$dE@S%Dv!Q zuP(q^vFrWmR(h|me{!(RkL?@*DmcoxW%tpFQ6v02<=MrnKxXVw8}{bE~m6>9p0`v8rx?(Xg{=BQqpqE zL>ECl=pffrws`ewi8^M>xNp|DjUoGTe1J^&N88pjZN`EKd*9(QZB*mKel&gm=5T+d z{o?R@IK8wC3_(1U4SupHOQvDX?*ov6kangxt^?`mjv%t47vCK25Fdg6V*czCi0p*T z8nz}yR?WCUd!9u_N9Tg|iS8;SwaOGat3-eAU$S^$Qw}P>Tb6BseaZs^$7nHd))oLQ z-Y%+x3=OdghNU+xn(Dvni}jgPFKh0Rk!1mXchc8KoT!pG&z`}l`nDs4 zrRFe$GsPix$4$6i2OF2-t_8<;%fo`F4cC7BP|TI=!O`22<%`LSfbTfe2wb8?d6LO^xVEc^q)U2IVqMi75bD+_x;ZI zcQBh`XIGGGLMrBQfy`%%o-R;nu{IKfigI{B$v#5bcZd?wKpogp$aE>DuHk3l2=vV* z=1EPi7(mNkhbl>$AAr%1i#zi0Bsm_?2~X7bB=AHwhYJzkyf4HwSfPAg;YtB_23v=z ziv93*VQkigiBgtB{k^^V%dwF>Vnaikn>A;3BLTT|G)lGm=wPn7-|}uO5y-Cyb8A{X z);!CEOB`UqSMt2so1Wx<9gL050JCV0+$RkX8)Op*o&ChAX*!y5H#ah(&F^C+Mv<10 zA$Mj1>i43$Vr#Z(+usBnu@?ecW*9)PhGX=+?#W3>HKJXM7i4^=D-}5vtl>l6>Lh*g zS^;JBJ~@B#*mj@@_4jS9p#nz2+}Y`aBR>zl2A7?M>cz8_cx&Z)%Avm#!GXxpVe~-` zbpWJSTxn2QP{2GTJ2`>54-y;Q8V@-5__RPlsxC(XXqQC7Pq(7RlicAw{mZ)>rhh5$ zALO+aais%{Mv3fft02a#0AMQ-cxOZbSn9YT4qpaE?k@n+vRuHfBS^A)Y$Ku%0*_I6 zX@yX3kieE>>OJ>kp`!S})c~QXzCZPOOLtmrjVaKyiErr*L(J zjyAVwRXOyYuts7$mBNoU91cfjTZ+jhvvpe$-reVC(eN6$fr?+PmPXN*@(|DE>Dys# z$C7Gob1k93x6;yveTzujpe{Hw2R(GvPEI8Cq(1#k&)mRl;_TZ?&AVvWkj}E7Pr|}K ze_rw^Y63vuFC0tmYcA8K9XAKSRw&b0)p?{|wYPj4f5wtE{Bxvx>)DzQjX*seg=@Kx zH`sU`ZrGtJ?VgT=(?}**HG>dsBuh)*Wi%O)#dPg~Bsq7)>@%R{myRUY`*LUPPqdp{ zd|Cl-CvE<+WB#b~t5}&Ld!xP#_Za_m{w8ETs0?f`mpZwrGuiZCD?@lrY9@mB>C>;4 zL(>3=YXRG#pj9t<6X2vRBH~;5xH==Fts>LH21mdOfXzpG{LT#@s2j`*NdFKQ(NSa| zF1;bg`}+?i7BmH%xsGgY5^DZ<yZ*hetC^)`6t53_ZS8>#yYBg)KhNrJ zTR!yAN8&m*z(^_TtSg50mOR%XvpiBqu}19Pa!*} zBVVz=he*dfJnkcQv#_@>TTS41KYSH$x~{+OSU>5lCM73FnJ1$#Hj9>lyLlJNRb&5m zq6?4_7{N(hz~-<$p+d{b+HZuGt7^Ej&}KzGS+NM^B6j%Hwc zZb|#z0a=fcygp%gUL_?Z9xT4pEqpaFwW`Oxzke4qva*gsOGx=yH|GV%~NT1Yw*SogxjiV)cxU;VEah{=;os@ZEX!P*3Mb0D|dJOhO=R(Q6Py-sol`VZR3^!{wS{Ch29LolQ`kIl&67=JrX z;4vXTWPAR+g14ceVZyezw|By}l&HI4<>$|^k%H!Eq$dSDf_dN(?8~YvGCTq&0Uj)< z8^nNc(C{|*;HBjoW*6NtAp&&R20jGuw%oz3$b>|VH_C`Nwl$^&U*5F}5-=kC;`O@Q ze{;q23Ka3sJ?_jNi5H*IfwA0<(cmFi0WKAwBxA>~mtnYHr5Q>k6s=z}T4TrDkKE8Y zpZTCCb6U?>tlsTGlbqNtRDf{rZitPVLZ~`&D6Gho?nmS1h}$55rML@3eA2l6KDsrjyvBL@G1*A zjyA@h!>d6pG)-=T!_bt!lv#VtniH4cFvxelbk4ze~>L4tu3ry&PBdv-(wF(@pY z4Qdf2a>;eHweeU-$jQm60^%<@Vd-`x7g$Xr!qf;P*a>s3iQR>x4 z{-wbhv1NK%Os=NrkQYG5HLM6(uRkkPNk~{YetxzBmw2+;0ui1w1MX7$!IB1C!MevP zzxe-O+u_I+S2W02VU~Ov!h1w@J0sEBDZbztS@SvN6-FA0Ly24_dZTxJ_zZujV zS(csIbuOf6`4}9G1JT&4fA3Y<^9^_#B1Np$9Wir8=o~l@Pdx=Pb+yEmWD}Q>xT9a6 z-ixwO^|RnwSuvA~nrkPla(H`Bd+e?D+UJ_qKpUEVj#=$#qF`b}n00E0s*}#VmQ{-K zdk)H&Ss8!xOE!KxIhH$H8=x6=qw@Ieb7icpHwj5N&zUWEMHO}=3wlmGVmbmK+!_kj zqXMV=dRm%nnA&b#lp3?^hYtU~|B7X3czC%|L9G@hR(eAvZxs016kOIb{G+{aD~_PR zK#|bMsy@wUV1D@ka~#A3i1^1HvP0I9F^rbvu;AlN2^^W~z|AFlP`qWqEy>}t+h)aR z`5y3)@&NAuHbevHVyDU;KZiGwvUw?nPiM?z=cM-X%?r_`=%?UQXFwLe_EA1RhIWL- zgsr*u#xHX;nqLG}>W;d3=jHrbsX)0!$Zc+A#aUPdcnOQ#cBk1kOv5SBpVnhwHq*+oVD zj%ix}9ZHiMA03@Jys^DK3X2DnC{76$y3Tnu*0YU27mbvHIFLpHcFmZLd?{(mWSMCw zC(C-P=#REnrlwh{d(A#*j3AJfzXxnXTBG!UsGGRB8n~y)WQS$mltxMwoG@UX0hi@u znq!Zi&ZfLV|D_mp%;od|*;KtIcVMh^XOjIrWIPWV=u^FYEA>o%e+IHf!NhO-{O^!_eFgfPG0Gt z=VEF-HD~$E+}zjy^gj>8lG=?cYr?~Vr}pfUgGSs>H>>ENp(=E)B2rii;{gNc_RaA=L5*tmj zslr6pX3u>7ZZ5+!oBiYo(usP~cQ;Tai6scwY?g*QjX{OlNYcX^r_DHHq)*iuj6r`k z160xFrcd)gD6$^pUl%$|QBiTIx%nMJVj2WEFdI`C%P$Ib>O4kYN=f}}uLE=6eWm5% zS#j*FFYpqubwO;3voI-%Qjlyul0{5YN@~kmr~>3#2=K~XHQAXGRM;!@3^d9|hdn%U zhsJ~1w}0O!?OE?jxt)Z%@ImC18#rSbb-T>Z2x?aN41_i@p}FX`%YT#$sJxckx`O=elLnyo z71pzYqan2b{)vC$Hc^33!Mjwa3TRiH8PGsb;9q?KXaLT_#zsLwGEArK8G+mpkX|}p z75(WO4N5!Gmg@tvNv1S~-GLu5T11d7=#w_9JiT_$p+-eD%__Lp$Vi4 z!Gc;l+uDwEIZXQ?mQ%n!IYe5k`p=uLG-iEydHFju7WAE-+1A3Q$Nc5G;0OfTviDGP z^#!lXTf>`Hiwr(#e0LmmUy$Lnyc+D6o_oa1(q~WMC2tvN+wf&o`G^f@!<3T5tKQHE z&ECMm!fJp^Gsuo2)oy)X`0L{1CI#U1f}OJPK=98T+F!#oJ4w%EQx10aes>X6^N}6^ z=l}b9U;}KhOu0nf49oXXRW+5Bm2yLl#!5j>z4i6{dKI9eP`M@mfU6>RN6;5$WJDOJ z^w;Nk(+?HgHgnC{nqc4kVB|5;WDAn441tLyw#mOSRzl;Tz02u7P78VMi7J^KrR;*K zL+av8_t1v@hVrQ5DB>d0Wbfx}Pr6aR2s$hk9UEdf+c;f41Dt(+1gP@rmINZ- z0;Bd45)z*}!s6o*9GE!5T1cys$R`aXpgMzL+ASq1;`qE>#o6=sVHD^ZSX~rqf4RJ3e4k@t3kAT%LV*6&==oD}Rvp`mI=+q2FE2Ou}Ug!fmMc5M>UtOKmf25k7Q(e4+oK%Jlpr&}vNG^mo>4M#Kn z7_f9i;pqKBpvIS0BZ?C}utv?O>uvt6{(x+p&OsiWWn^KP+zk-6id}mqwR(4R!oVv3 zr&PzgpS+SVNQoIz4lOtNt~4M^GV{1co911Rg4ds|iH3&e1?`l0ZD~XT#rp^`P?)-bkB(bhgAA$dqJO`<;DY>+kwb+ zT0?4T8hv;8#NK|AAG*ny@N(|a%XiHK09O@)N;Ew^om5e%+rT@sZIZMK6y6AeKa%ic z*s}@VtHGwhA(U00ld7e1FPLu&CX;QwAl3|iH1zk`D;RNX$Xj51ffdBA9L?C7w3S6vXU9(YCoN;F0OhJZEYrDhrF zESzClQ>&&?l*zzQmlPix_SH*QbJ?|VO!H|#v%*~yx-1u`55$+wEpIBE;kTlQ$yVLG z6ckHqX`usUQ)TT!R$G_-aWqUphVtVOMB27cW!-?{)x1N1q+G0?0@BZn58YP0o!^-;HRsfv6s%&BP z?}@v+yW8yjcY1W11OVnhVgJb&V!jX-ikn8yWz|>JR8%^7G_gp=Jq$Ye)rBy9?~qPK z<_Bcf)EtWkJzjqY>atKC)^v7uYOb|#^Jf|`i)>EUjqWE!R~2+?ZB%IPjz6?9>MfhR znj>TNu6x-#iTtjLoU-!Go)U9rGG5`7Otv_b=ZVLOa@^|*Dt;$G)xrC@DxuTi>^d?k z=GqW2W6q=6VZ|d0+k$$*LNh;8y=M0g{`|r#fa_J&vv0XBG-zZ1?T7_tI9M5(GoD8} zSy}@CIhK%o3C?0pO5C1`o(kSGaS@{#jYM=E7(;e%HF+G{sW0j^c{L0pO%5XNT2PhDJCWh82AaY-K+h{qkYrWwrR%KGi}UP-i>DI;a;u# zk=5|*>^3?oVE@knL?a1Y0c3aXbgoME*>a923VLex4g4TaH8eETz!e3j6@^C?9&#rq zC+VW$`FEHBv8M+7&*ADrspwN&IH?D_wOFlzIKwxbPe#{##nADKg!+z;{ulBEp(X2&7;%w z`nw_s{M(8C4PtpcN%AFK>AqP@%tI zz;;dO8e(6UxNX+Fe95AoU%E(w4Y^m#o26MuRvcw6E|+w^hjN$NhSujj7#IoS+%S|6 z{Log)eqbCXkReaUa=;AG6uNFLFs|gx=A>T5vWbHjn$XYFd645y{4Nyc`0w#VhovvR zcVNL;s0F(YJ2L)*{)DNP!B28-4N#v=n0Sx0)*E(%Akomx9*|9)&WYS@1~>@@Wn~eC znG}+9k8EUxdS74G=n%yI85}Q)OCF7^MThn9$%TAY#U$f|Yp0H^-kA_0c=rrda&vPt zx1gZcIeP&d_zfNmneh)Qm;f`<&Wn)tDP2>QIv?gK8W79(jq$Q!P&O8|h6)_0@EsRI z1Q3{i%NeQHKYaf#RsjIgv!i^VL>qi#gT0pChsO7g>NHrXmC`z`nxH`8VFPBVh85ry zD~;Cl9BG}6%hzktg^MqNjeGEhgs&$$Fzm#q`2m}PXdc5+ohvh{q}LJyeNJ+Ws^^y{a>0M^{@F2f z1m#7e;^WB&s%PA{1#(uqK{0RRTZ4)1htK{XS6oE@Tsk^T%+0NK0yv`RfgZCY;J8x> zP-G6&c>Sw`@1zL>0s?ZgvN~KBw?UmUqi_BsQ=o2X0xxjGuC}JjKKd^yDbzUrKPEjg zP9<*lVO29wTcfZtGDhH?4ia^Y=R5ANDKL~jgg)5wKKo*Iz*#Eno0>iDX@S2|X-{-!&Bkz!uRB1uxI+vkbrTi-J%X z8hNt6BS3zvc<4nzy+I5V4ko?amsR9JGf2pSgVTFBfDg#McL8yw-MSS2NXvVopMA~> zLHYMoWF3?|Qe3^{YU(nooz#-WxO^GWKRFo7WZ?A!?ulR! z$&H9ZYwl!7u3sJX@l6x@+igU`)2`r>IDgZH|BX8f{|6a`{2I!?uxZ!u%72h}*X{ck zdhjX^{TB%HuRr}idhu^u;`N_)2?I?om7!RN4A#*6HO>EZoBy@~`R-r$M85r}NyvBq z!p-1XmUXKyt6z*zF; zL0h}K5%VcE%GD+wjF7=$65d>B4^mUT8zi`v{DYE3??j#XyNTc{cJ??0dSv6STi)#9Y52#*#8&MR`u2I6XXW(NeS9m#kJ7O*BSBYo zHI)FYRmFjpP91@rP)tdb=5bLPo*Dd(yqEO2i2EC<=mV-M6m_S#673>v;ZO6B{3d@1 z2xhU3Js-B{?D%&3-M!7S?Mi}aM>0L8!g%>leek&7B5oXqgv*AwZ_By}KvSGvylp>r zJ@Q5jeOkLZ)4v8Rh6!=kirFZmw-Bj(5Od*P>68fPQsw$~$B<+N1LYV8w&6>xtfoLj zsV5cWJX-li53>&f;bcX&;*jqO6!o>Bl<_9kVOtgS^11!tQubkA0;?q1(SCgRT=rZd z|I>1WLFds(W$Usbi9u@0GuoaU3uU^PC^dqxo+t^3#=%A1gd+gyx_v-WT3u!Pkt@qGG=a-icymyM(=VtcN zqgHZr)jReN+ay^6Z19|3#MUSASLZR*m&KibPpivZ-MHFxt~&m1?)? zuY=S$*Xx52Le1Uflr$%0queYRpGFsy@~ABN<6P z*w|=E3MwpxKSw#f@DAEu?^m}p=d{1DvvDZAx*=tpj4|ZB2TO$o3x>%5nj>zz<5pUi z$%$~2qrA(Q9{W#I^y@2GOi_s2uuZsCNqWqmjA+e^9)abbcBP!pV+K!%gGE?N7ag*ODM2J zz(2jM^NEq^nS9Gr3y=Qq*%Gn$6tw)d7buiX+Ia5W8{oI5e9zEt)GmI}l+tJXJe-4z zNW*Xu!+UXT<7C&xq(|*jHe=yLd8Mw^`y<@;KQsM}0@%03;7_GV$vp~X)T#w&i#MR`&eLEbLZ{60_72tnZwM@UX z`$`Tbb11FaAjq&i#aj_d{UT*=u(!sx#@I-NrPs(fc}w^0N3jt9@RpA+TS!(z<tV)r-|BWcG^`-WmA65fXj6rQmcB+?Q4=(WF_n$F1 z!{j=dc?q<)KbSWjZotDo#A$xOK>d85$@kPFBhDQ~A`eQ+1LNs9(_8%1wW;}2i@4gf z&eAE_p8))8J8i@E%RA}Q$)o$t2GkM#@Q^imE*h8^6G&)~gVN;>O7x$%oQq*ImIat*uchxP-8C8yFp4EH#9 zl6*~&%W*#{U8p8HJIGt?D=pBTJ2(~&qqB&%H&p}fV4M7(q4FmD2+}! z+*DJ^JlvHhFR-co2}Q1cJc1BizX0!EbDtQSOw+aJ=w%lpa+BC~?R)uZ?)A5QS&K_E zrq>e|c72c-&Rgco{)3V5rN`=x8_Oe0UzPtbNy)Uo3DbNEOa4Qs`+)HUf9XTW=2w53 ztoqiY2A_0N(Ptc^-@F+iFGk!(V%6PrFDHd1x}Ml>y~O=kx`)dS6*YKbD7vKKG9^&! z_M7)R#hG``#@Gyx_bqJkQQkBe0kXE0^_$yA`k94-+nsw`!Z(<2LKW7aY+PuJtM*uI zcYhH)S_}9z|KzYOmZ`nCt7~SOp{bkfX6nJSp0b#lci5|17k>V$j$0){oEGLgbX_Zc zasvN z^-6Y*QB#9z#NeAz9be^f8x#vejiMD~)~JXC@#nlHM`#`w<7 z^JU+b`Q^l526!C{9E_fb?@{bKtNUnzVhr!Lc--(`?M%sL2|{e2u>_n7Rnrz(zew>fbUz&Z~b*#J`YVF;1poR5r%on&Wv!dYSN(vFtiO)DuLh;fNi|V}gZW zaR(tR?ddj4Yrb1ZJYN#3Z64%#wNU2=U&2D4KcmT3sw>h+Q&-zV~$TZ?zHH8F*z*6yC?i_6(N_>P04?{d>eL=q(jxQ zv^7L{q4#tioA^CxTz;9ieLRAPyS|`IKeZQz*IP&%e$;WH7xw4$4dq8x$h;tQJqXd# zXtU1>km`w2(U+cQKS`wG{6TdoVQp$^fAj@uhQ!L)k#I_9XXnv_Y1`3@8i4bzE2yhG z_55SEvj1GW+Mn@}8+7kt(a|I`{)uA^hNIJV(Dr2!{=sQHtp)AAURRT=Lr+QbfML!n zmNDDQF|n@2YJ`h-F<{P0T6h4Wp=o=II^EZk^vzd?9_frdcg2z@Ef( zl1P6Vjf|OuxXKaG}N{<)x%h}^cp1<=@67dp)7Q-FT3A_5D72kFJ~B|khE&q#zH z(VGs-hh_}Pw=)bEy-FVz%8E(9snqFo8Li90w@>@xlU*SK+Fdu~zN%{P>Fr^llT*<^ zUU?j}-iEjOAmuAwhu&n?g}VtI*`wnMG0pQAb`s~a8}LBH?~Du`a!gPB@`@Oa3qw)c z3g$Z2R$V<7+Tn$R-0CI;o%`#mmtS-zibEGgE!ikfTYLa=GQ`XNVZ+;2i3PgN-*9m> zQ5XgY@j4sLA`JZa_CzIJRV4PkPR}oV(Gska6J~4#$qooe_b){bPYiv8HLyJ8*Wr(O zJE}(-Z|6MvS|#*&LdVISN56<_%+o}3@>j;TEKivBXNda9Drt7!FI~0IoG=hFG3Tboe7fEVZkB#Lv%XJlBKr7fv3;zx=sA1~SmT+wZg}UeIIfhRZA3*S!12N}oC050lSH zz9+MMah&&|+|41o{#&V<(?K-0)P{Ij@X?rC=KNzq z`KbqZ;sh;;zs55fOY7@WU4LlCO?1Zz2}Qh4;VrVI(1j#Ex`)sAcuGNGZjJAWyK>KL z^}OcH)blXUb815&)=#wioEt%1AZnL9^GZesB5m|r8EZP2K=ZIDBHn4}@Jtm3uuV*+y(OiI}d<|2fwI6j_rL95R=32$2b z;m>MH?ululaPONrb~M9rq2ev*Qru*;gzt+Q1^h`Bd4)$qpFFoZ}Uix~p z?Dwru150U6>ZEvgCVBjq=|v9^_;6BBc{yphkiLO@I`CFCqb~ygQ3>t&A)zzn91csZ#ef)LPQ)N{M*bYMP zcGT4s)tl2P?sN=Ew$7Ftoa#Lx8v0|!X%@+p78<3Wr-)doh&R7^cM=m0f2q34(^Qt1 z?^s=2mbc`tCJhX8w$%q-Rvukr{q81Jv6H1#78o#o4dRo@R|YghyC?hKVig~MA81yP z^z_TA{jAL1>AtBIsnp)+>?p=Wp&sQ2KS6ANWUwfRy+E81OO$VSrQ<(1W zFNgOFi{M3pN!XvUx-X!m5}L*4x(F0S%uW0|LC+Uf7@yXrs!+3(tFFH~Oh!lFJE?YN zT90#liUE^DY*nxa6&85eM{#b+s%>^g*|@hrGMO-y4?eOven;LP{q7|X! zTGZtAU3;1Nj>Y3I?%6ZiAB>o%6e_xCh?NIVcVk=S;+)Nb9Ib;xE}J(%gfY}<8 zE*~kk+Z#X8=ql)oB-|6MkRpnGu4o+r>4eN)ajChkKF36Lbx+Ze!I2v-InhHpv- zT@Y`$>2u+#qT(sO)pWj$8Ng2bvqTGTW&XR7mrB<9cqv+`n|N$-(M5J8lUlwXwatFd zetrQDf80y*R;8(Umhs4_UrkSXR8EmSwL^-foed{(rFVTj=iXm?&oIq68LDJOIm2LE z`*j3e4mr&Vwp0v?ikwCZDJm1pZ)ShnOswf*|f(L*L&K< zA-8L_ZRsR~{5m83N7iz?#}aedwbzP@7EN?6o3qL2aYn`%vhFMj3OC3_14s1u?dERN z3;}#Y^4|g2JKCx9&xppYFB_~x<*ui%Eep@HIuzS^9EL}=;7~zA_CvZGw{d-F8t#YE z_1_95Kh?6tDWMX>@JS<+WZ-lhle)z|!fCVr)1`C?Q8b(znJ_qP=wX@OqB*z5Qs6dd znDgm;JNn^^0*cK<;|dBZi!SRtiirjf8+BO>tOk z@w#sOqxC!M`#jp5*=iUL2fSl=5NWA_5y%XCco$-|a*X>ZlW=P+lFqNNj_)CSs_};7 z-kSOrpDe1$_N$EHNTuf(x?MdaV1+GZ3UogIgvK(2D%nrMoqJW96$PcUS&B5UIsDrU zPt@ZR%(MLk^MIVI2pQ7O5pbJpqkht&df;7_H}R(r>y;dr8hQjHFGtOxo=mzie}}Y7 zhs#f%DFcftuG^I!vPXw__fGjD@;+wKm1yJBZq}vFe z_@qUqPPdOb{g`4#hf&^@Uuig;|DL{yFlS{uoavJq-(;nLM03(Lu$6`3GHwKmsU*+J zU(FEce(?u1Cnt%UBd1bMltsq*zg92J7iP#t# zpp##0ef>GA#^IkSdg zx8W~ZZkV6W6Q@R6yoyP|kH6V^9-b&I^Xm2yM4Nx5sC^Bn@x5arDSABKTg zu$!NfA$$e(TE>F*Yod$W78S_$30~Hf3UF{l@-4+%;Pa}w0{D|98onK&R=Zs*iLvT$ z^8>j1IAq`cl2;uUk~qo*(1H`%#S91LGDl_xDu^rfafwtPjnF{Dz%F;E>m5g!jioIY z!r|V44ok4xnX_q0y_8WQrMT)T06fgfF>`w*0(*usHT!MzQk+>)$)-=`VO;&FH%G&3 zfMBZOM3d}pQSBaeuyjr?X)5DQ-N1_XNfVOk#aV=u4;fwe{ZKK@%c@(c?hjAb8>LcN~wW^5cFum2fz=bF*=@Ei4 z{4d(G#`x_UcmdE|U76xMQlGRv8FZK&BN4YI6i1^mGrsmTXpH z07=-y+;#x30G;3ea!QfEv8U};n9t)tS`&J>K9BEQgaz!?atb@W3tZg zgxq#rLS)h|Ay|He>gs<@YRzJiD$k~q5_QGI`&-I5-jU`%2(5l+vRJ?GqtyHc#1*}`h#=w zhG>n~-$G>3VcK`OBaYOytZ}r4_G?9TlMfm;E*wDyHa}4B*OrAcV@dheuIEbtK?x5= zdT97AYHUKkSrCe@P1l_Z%MVWS4u5saC+$A-Ve%$_3tjNd{|$TgH#NP~m%T44W;Atw z8duO6@#)*CN)Bm?KfpRW5o_nh!Wla=tLG*4WsXLboVc&K+t>1?q-m3x`cO2$ho*#i z>>)MNqKCKrLr-@9gKuD9c()%c9nkC;-reQ5D0 z@7r`kyI;SvZxy;c1pWK=q0rEd!c(?pUI=Cq8j1 zosHO>+4D`XXR}{CywQcGk~emB$N{#cdNZE8o$Vk?v6B4F;)zIia?KlsYxM;P4hre* zJ=OHa&+A?FzgsnnwX(KX3JFB#cDkSc`TfNff70B+=6H$I{^yDm)7zS+%Xl4*!_oCT zQz7NYHncO(j0)-Lw%D*Tw6`OCsL#pvydR-Sj^66n)pZ9;*Xba4eB^b@*ztj_REhiqLK)#A)Z8?l^tyh@ATjAOv*;xUjb~u)7hNnf%OS(F;h>! z0z`ygiJP9Mm$&SbcWXCdWw3%Mc=8c6HcMYri{$mJaZpCiCJxZnLNnM-pxR~lEZ7iR z>sozz7(3@Wf;p<1=|Ew1N6O|Sa%%RL1LtNS-+vN!Wk{)FRs6coQY+%!EmE9;%?cIg z`wNU9$sT#ly+MZ+BH+(;7c;`QN>A2`tY4d-dQILS*%@BeX+Ol8oanyvNf^K}6v_(h zy%CwQLTXs&++P^Y*N7hc$sqQ!D}M|h@?l)Kc*B){NXTMi)o^bzWOIz*5KU6646EOPJBF)UdM+-#r>JqgZnEhsp6*GVPYcYo5Gx^Bc1 z4{sSmr;@^Y!&Iv{!$BpHm^!vQO~ANd6@-~WJnJ>x1Tq%nIvvmYdp=HRwzqtX6@Cq3 zOYL4>j|~JNKfH>mxQU7M8cw=)t@aLzlD^W%qq^~_LG$yTaDR0*k)JKWfwYkT^@VvJ zf>G4OXLbG#n%$^N5nFN}_OySVExrkUDaNR@`PvVnTWGNS|IzlAQBi(f_%Mx<0@6cC z3sMq8rwo!(f=GjaLV-x_KlbX!q@a9pM)#fWRID>0pz1)~UdOd0ORyVx+dRko zABT4E3_7evK(Ca!f812L3f!cz^$e<^?|}jVaH~k0#+}#U(xfPXNbXdDn+Pl0;ug+hLkz?uxCDo3V)fUaXocCVrC=l27 zBy5mdSxQO*tHsL?zY<0PP>Jr9G%H|etL{EP__oZG*3Bvk+Ri7PvCdDD??;BmEBqNg z>}OFOW?nxM;E88B?#J-NJg-%?dC`C?Sj&urUGrN{MG)3?4M5+b@4VT86I^6tpJ#f; zcJJ6UM~vuWXA^>XfDP*ZfO4GG^m=X@|8XWrIb~e;o;Q*YRb2mA6Tlj%YI!w=sgGQg zX&T>|o4vZd8f%D@7k1Ch8u1O$Ama(-JQTIPJL?zEwRkZH!A{v+x-o%DvH>_R@U`V%uC{@G7z<<4}`auHE%)YjQ_{;Dzv8 zzo^R@*rALR)ha6j9XBZyU@_TN5h3k;W=nGC=duqeMd#7vxXskSD@SMw_C(9_Um)r7G_U3x z`&q-kG6H2>>^%Q&R{9)IN&L4{=E8>0s5fcst?^vXaK95hiadnTuQXFA*n;njUO-nr zn+Kl-^zLFZ17UT)>1VWKWNDnfXj{=LJl};y?fKQ12yj6GnHd$LMzvDe@SNr9J7=a) z3s9i4549ZHP>%{Ks^uE~xht~pJ&9vxKgIqwLB8IeLBE3LG3#!)Q=T?$B&7i!YwsN) za*5X2<*nuWnnsIKsrCZsm&)aumC&~mk*J-7^1T%m>l2VxItO1j-Y4Cf1k(UZ2n}jr zMuS;Lw$1Ql?^DH$){1hk+V$;0+~+-cE$E9nIG?JSAq~k7 zSzj8y@X7qeda+i%c0(O{M&yEVV+4f6Ljo^nOO2b%{q#1Bs@*Ywu6r4sCYGW6f&7^@MmXlxX*Ku>?P zsGhB5{q~noyUKYb{;k^^$_`Wo^N783;Al>e>)p{+Szz0Hk{^kB$A=4=--9m6fhN{9 zkOiln2V3mjp!jHtev2!d(XXNZQ7VdG3*6D42y75LlQL_1?yXm)KswiFt&{wQjODtY#OZC;bo zN9@TrZ#FDY4~0CLe5-=XIvs*-YZAZp7fli#$W4?w&s4)fStVk1qW5fda`EepapR4# zXFm!=?M3$%Jc@Y-K;cD2&Yb4!Sv=p8ouhW5#q$5uZoO0ZnZtuew4o^tWXzOm&XQ6- z#QW%b)TP%nFGvK9QD;H8Ho!%FtXyI0f4+s#u4m)9aV zXBr>4xcE5F_AIZ1igCl$YS6b~VtkeBJn9)H!vRg=n<9M!AZ0ne0OA^N!5-DNUeCvm z=F>{_N1^!L92J4%CNW!~Y%VgVgF(MvqoduHvis3*^cX?&eAD_n6q~ElHK(u_Uc7g> z*emCk7O(E?Tocl*#v8x{;@Nx+^9RmGw`U(JL;Hr008}aru%Q4D5NZ2HNBv0dOTM=6 zqSUzPKPwNI!;`Q7UYyQLKk0^lxo+!uclPUQPyY3*@^U*-FugE zL$4^QQU{G46*$_DzlMA~Td36p3_E!nVHX#3qb?<>7Pa|sr~yQ^Fitl*&a>Qy&iyf9rD;o))x_R9+Zoi*~_TTpx=NqJU=gxXyjvMmf!#`Gi64~B` zhOx^80|MR#ZSfq01+_mn9GWx2>@jsXb-DLKDC1x49(ylkRYzTRC0P z=(xV{do`E2NuJuavg5(I>s}Ft8|Sm3Tz-6WwC!z&gRA}wliE-$9?W+{@q>mV`uHrvBR{w0JADEX-px*vtH$EuZA@H-2o&B&Os>THaeyHA}$^P{etz9k$>HZ7o$EfF7Ii~Dr62E@c1yY-7RHa_0oEj2ct-0b3$st2gZ zM0n40&^ZeM$mq8vQrN`6BDc|Ng8BBgr2*Yp z5O5)p4de$=#S08?ORm>55kFiK{}OdC!T@UXua!kM5d7(8HP;XpiNDD^bQT2UJ%&cc zzTGJ6j-UIj^~_HHy@BLQBKwclmBe10aFO6{@iB8%v&%?mT@r9VDQ@~(2?eF-bUC{l zc69B-CLU^i1hd5d`~9P3)1|iiH;27BDe*!wS3yg;%E(AVZ&|{~DfU1jj7g&l1U!{u ze?7Pk*}sy4yyoT0VO8hQ#gYBtq0LEUQMO%eZwI{r;10dhs?QS;mEc+!mq@9|Tq)FE zdqNE_JU;AiW$IAtnBBjUTv@sUB4dn5NYSOan-@k8BLQBSh5GN1{{2M@=IQzW^Yfd) zrEZ3Q@aaE~@%?}M{GUnw-8A^-lt!s!258k!dPe-+gN|MTBf`v39;_V>3ZZBg`% z;#H33THR|rXZ-kv2EJZ?e2rMaSx7O5~*H)MP zi`L=h|9ZB+qi*jY9n1&&{)iK;H?)nTMLdh`{k&70sBY8|N^+vJk*#Efqo>z_)njnd zfMiAZEV`YgM_rb!}eKA|09(;p-Q`$_s#x&EB4x93qF7F6Ni=aUlGJs zmN*igfUraxP)V&0h@m^p6+aGN)3pFMYtUU;9dv&(984N|;vS(#M>I_aKSB8dpZPI# zNcweTA;Hcz?d>^G+WIilQ9Zn$mzM`ZQ7u$NE2rkT9-qGwOI4!UJ!S409oJMW`np=; zrti!5*q?rmd6c8M!D)>4&w8SQcc%9z%y+X$x0dIoh2}=`x841@ z9ZmC2>s6K$*uH6TBM#g`@JSyjs>XSJYOqknIi522dn2$45A%O|)-Ojz0!S*C)zbAh zJpqlgv_x&ZI?fLM`LhaoF@MtLIQZgmNz)AZ`TpKxdU{c#$>ROtwwd=;>{tSGT*65X z@`8$~Dak;qANg8nC;1w5CET%%K7#$xY?X5mm2jPGiO-?o!6w=H!2uOj7h4HCu8LSK z*PJ(EZurQ>X*Gi;;Njgw>d_%%vx(tihkjcR$hDR_8 zOFX>DfF+ARz+^t*^Zm~YFa#H{;ic^@%u^*Kboyu?!i3ke@qVqH5D9u_s9>{dp0ABtq_35w$z00!*71O;{Qwxx&ZEbJMsH(cL zsBpZ5E@p~dNaOe8J8qB|lSwNArCE&J5T+GaADlP9 zCGD1hZ`%gvt@f05Ke^bfb?=iycl6w@%%x0LDrmu$xgWq1c>Wn7^zn!=x5EY`8QeGK z9z_3mHo1i%=%L}7WQ$cv5%sG_uu@JmNIMy*qnXnf8x}1f0uth_wPH%mYP_9VJbY_S3MC4FPX+Bo z!?Ucr2L`mpOFzE-KE=Gittd)CN-WhzSuWjXUf{zhP;-w3-nG1}>dLUE2tdbAl; zyBaSz9szddkC*-)eN9CZ!)CuCI0(b0t6Bo}yA zLc(vOwmLfv-JN_kG19W>_0$_je|o4dXy2xU8ZmZ5Mi$=W?J8;UNOXPi!FVKY_mzMk zhfNPQo~>de#vJ0e)7QPVLW4|^`qMwdh5cD1{e=eU@1HI;R~d|31g=okwT24}P7pH05_D0M!M_mRXLpA1;~61N}YPp@6; zaIHGI+kCeZ#&8(&0mm7;Wmw`~A|kGW)Jds6QF3w6Z|@62gWOC_zwCT@ z4{Y*)jv+1)VVe_nN7Tw10U(A05vsf8!g1guF(}K(05Dr2aHx-g20jc}ix`jF%*qPh z@SW>ey&v8yfNY4@@{E;vaCY`KCYP|#agW~~ce7ZCL#N~IteuLufPjq-NauZ*z@5ym zI9$%A8mGboqBgQ;+A%0GGr-U<4}hUh)!28cPFf#dSi0gwKCYb$d)%`j+`6rKe_VwI znYQLGtUp#Do_y!JMjF$67vqBmtP&dJ5lrMSf_PYxXI@jE4i-|L|BPIEgph(hGmMU-4h@XFQo-Ygq^vKOKburA^C!I6m{D&8c- zi&mzY%;W|*CSMGdWR;+wm%dOms9?dCitB$v^vVMQ`uRjK;yxjrVoUoZhKBPO-@8~? z37h{enVc@y{p) zA4d5sXvxAb?b|hZ!>O8ix7o|CQ!f$@#e4RP-L1#*eS^0%8fho(L|>Wg)134zLFMM8 zfLB4Y;<5CnM}v$ld8t9sTo>mZ#`tC@wQ_s7+aneh7PxqMoiuK5Zx6a_qN^#3bgoqL zkSqXO4>~_T$+>Y455I!0t)*VYS5tZkk_S7ZJh(^}6u_hYGoJvCqc3y#@P6CZ(BYE~ zRE8-A)Y=_J-88ty({o=1?9d~khaLLtF>InpnC{GNqVQwt&;`)F^N4#;$st12v&QZ> zo?nUn{Evp@Tq%{oQ@O4uEeTKKE^k}hpMb8C-$K#+Glbe!BE+fhmhkVEa)HZ2*Ldx+ zS*2!YJ}?4GFVTw1WG~&~>FKLC+wQl$`W3R41P^0;1cVuM(L)o zOk6B3`ql4`K-+LXB)RJAxTT6zBtUl?et43)l)0``ImomD71&*9!&e(*Ib)u z9t1RT=LLu=_`zi`Zv({o&0d-W;G%$+d~3k_J0+ZayILUTq+Vq(UHD!#KK+x@N_2=G zT+ga-nLxBH-rP)v`f{P)Dtcpizn;%eZ-Af+6hoMvsNGjQ7HmBcsOJ*$=bQS-nDA38 z_h8|JLTGAtHK=OlIa>9sv0MuKcaW1=JyMGM^Uo?`M;Q=&fzB{{qhnKHvwjETJI|Nd zDy}9spO}Mi9alC|y*{nriWk>&NW|GYN~XKFM73k?wNQ&(=svl>+v&_z#p_GnX&=kO zvrj}^O}t0eb=E{m$d-k+h;LMk-aK8QZMqlpZSoQ|F8VlH7$-2uWZY^pR1k|v;z0bsR=MhhkYHHJW8(@F(hv z$JvS}`nmCGZR{Am5SaR4UwTny=o7`cviZ_nqlLu6A=iUKFMLQ7=9yT9` zx|-6L*_|b}qEM-oV2C(OERmU9k!s;?75Ok5?9mzgzdYuvc7x&|{RhCqCDK zoA zlg+1>UqAOaK8i_D(8IYjj~M$g)6z1tfsd^a=HNLHdueTZI%ksSaz9kpSCox?e>e5(47#7_6WY;TlG4VJ ztvwXR9g33D6EISokXvIsvK3O{P3Jh^E@G@yuMw{pAQJicu;A)DObD`iJJIU7$<6qkB7_d)~N{^U4jPd4t z?loeOVJ-`T>tsFKs{E0L&jA&YV_jc#B-wAX!S4uy&OC29f5UG!^C>Zw?Rz+cCkv_&P1f*^UtQToHz)IV3m!y7T#99N@kU>w8ZsFOKYSD+ErC?ZfaVk;r@HJ@6%<~4)iFilW*qmY3gf}VZF*+}*D(0JXUR*%D zT(-ZCv$|8T>XoQTQph=Ysz!s^*OM+!kd9RIBE55ph|Nd}w~B+qc|wL&k7#|80TuGr zvW6&@lkX2zz~i6=V&wY?@8GI}qMOK`no1_0|+Xt}Q%CGIOYQU*KM6YHYb9^+ma8PrD#ey=li9ng5VT0AOGB?VLT-M$keO-Y<7N{#$Y4+f&Rg6UgUdUpU zn_ooN?c^(n;!x7MMo=8NL9z2&8q z)-OGS!wL3jx_NVN@4BVXbGamFA~i!K61)RX@H`5{pr$UVA~%OMm)iwUWuu^iVtFGy zOH@ddoOZ*ZlnBdBCfc~6Xt91W7FP9>+mlq);Ss{#V`OAOiO;)g$F+k(cu1O=YYSen zKW6JHpESSZ9Cefo#L>Ypq!}0Ef;zPm*qc^ko$hx>j?V^58qa|b#QNf6a8C6jM48ZW zk2t1E3Nc|=SkF7U2}%eK&FA8Zo<(iWhS&tl^tRa5&Ln~F6ijt^O1;U!t?uf3q)vBN z8(-xZj9);XZj%OXRhh($=E}@Y{xUc*(neU>EiOrVe?T*Ef(X9&34`X(!UQ5y->@DG z;`fdtxGTSTFY9T#W)}&h2S#ljg}C4H9qq^-^FdLqqW$P+`531? za5@6f5dp&|{s;KH1;gu>x0Sw%+HDm}_I9Y(k;Y+BV%kP`cW`*rRm~#|(3$h~i9NjX zDCW9KGH;x+2|)Bp-t1ERsOFjY2$#7XepoIM3^V9@rNoW zz71b|hYxCzbG_aoSJQ{Yht>6D|Ki4aB+=}}BXAwG+~l=#DTs6Q+v}&9-if1;7{{1o zA~GtW&I*^AV(p?BQYQ4f=-Jr9YVW#t<*0H;Ca15fKTP`m&c5G1w}OTL%#S{9|HCbK zGfj=i9ys6nraW4R9}H3}R%hn<6B$M_-HRktNOud~EuBjo?7wJ%@qN7Rn{izvMD-2v zLj-()58HQ*uUT`zM9PGQ+zpo=mA-y8(1`^9Wt>fKT1y*$q~W~emvs$~YVj&-YI@^& z^vWm)2^X7$q0%qoY$ry?>(dhQ{Tp~^cwSNj&~eR(+sWcrMWcp%(O^z$iWfVR;+Ni~ zkF1L4<*D((N@0V6y4sF_0euGy=yRdoQ+~D4A1}B~Rd%?D{-oY%EKOsMyXNPI8dAyc z)L-ZmUQ8fE0t3hKPEYv#!aHGi^SxO*doe{$*Xa3;1(**g!`eP?nZcJxWd z5l5~H`PpAX!6t@nd~GO-pKBGvd_LFV{l@kwn1_ZG;~W!v0J}*%Qfvzw@wuH#dXQ(ea*xNyO%GHN!5%UDD+C7Z9C$Uvc;Xf&m z8+U%PYxzGhv|rBF*xG_+n-D&Hhv>z<62CFBv1;T>V2+u8#hb8b$pP!AtE3RZz?J`! z5mEf(gQ)#N(c3G9UbeTV(Png#;z$x(mW$&gYtwAf^N>q;?8jT*-YY4w4o}Hl8yRvGhG4h*K2>|ySciOH&&P&^ z)BR~9Mf9uAONwtlWM!0;qR7BpA-j^94bOQiW^JEtKfZRp-x{5__g;_pI_&V?vxifp z3Rf%R(C9N=pMCwR$P`*RG2;s7?Tzj2-=pN`H3qSNQSw@Pw4;t9Z`7xlMEVvL!n1^b zkf+KVqPc5eY7-rX&Z@#fN7$46Zqbv5T{~udklobdB~lz&jkq=%2$y0t6hFG7Fe^)U zx5-0yY!YH`Yhs<`s`Lys#k#qZqJ={3Jw6U-+4eIc`V>dDs(XEXtlHewHEF&EV$`_o zDf3ot3(T$^`F0y<^?O|St)?rDsv_8BSZuu}I~xhXw$DGCiazwkg9sVMKF!S8P?|aF z8zg>TOJ=TYxU@MSto~=GbNp!)BkzRnf z>X&D`ySO7t2~W!@z|Wt{f0dSPf~2K#XWTtA{-u~x5=+pg?@%fHv32qpA#2+~U4^BU z74oL(I3QBtN(Ob>{naIO5sLl({zA`np7Cw5E-RCA5=#&c`JcHWSJL|3vae)dXd2l| zvoO>*sf>CBT6)gk9|cOClLu9MT1nl!E8#csa4hT}x-1R;iBM_0|8SkC_Wbxfq&hz9 zKKkdN{!Uxkqfvyp*D6!_8u7D+_fIk8$vO{-FDI;@{+!QvW>+=ZMY?L%0ktvhBI|B8 zV4}%jB>ug(GJovN=s{y{z5lw}8<+ARd6C|~kJjd3YPD}1l!HGg|639@-DRI(y04lm zH)Sk?k4<7he*ke2QS~7!PT#-8%Ojz?jh86(imwMAMV0WL&Oqx+Z~OoPpM&Iz5B-_$ z4Anc@nKGn39hPG}&JJpp`_Nllto6OwZ9vs>eWmsE&hV~b34y9wGaOQ0!ua8*aMCd( zwhBe&N^=p=9>bcM(bd^XR$cGWuSI3UQ#QUGPHonX_|+b_Y;D&o#?v!wG$17UJdj&P z{OazB#816YnT6~8UH81GeWUaCKpv<}8G{jyEW_;iZk^n0oYB3GMu?~e4bO57m;2u> z|Lb){RcMp6BfGX!R($CX#W-zV*H6C!0Q8QsA_{r+r&c z#X`Em_*DSS3impO!8pDpD6p2y5LUnrr|WP<)|P4dfzKl83W|J;QK|_^dxF!kktE&Q zwrZtiosSCPDply);i^v*;w;2~;epdM96Hs{mvP&WV@i>`yPV~ zoA5~rU!RzhtfP2jY0%4li)kVzRY+w_w;`_=*Tw`D>5R)=qga^6>KS{VyKTjzKkAq` zGsFT5{rN(j8-p}RW+LuN8?h_ro9Jbp5cxfoCyVf`U}5DE)U+2k0-;Z&qnWl(@#5#O zZ5CxMZscbyZW3a(ZQy35c4OeUJC1#()A_=j>Qw*=M25ykm)864Bom;jKUwid=AuI^buEW5t5Hpy^f24JQ?jjp5%>$*H}?9dzhj5 zPw+cMaZ#98A>}a#jhSKOnLxy%sl}Cv{8ss2l+C}{nQ}^{#oB(Ai^jKmH!nT};=pQ? z;UJQr!8-cpnlY#rBi+$6rLuQjQb+frBa1``&U#iCfwppNW*E&lonGpVxA-l*la1xnM`#iUx(g(UgvM^9}kEya&#>=F>NpaYPSyI+iSetDU`q}`)W^b6u9 zTz~Ujj27{=;3iv%%Pz>lkgU_wZt$BwXZgz4-F#;qE>g1#gI zE$I74Un>Wtc(qsC?5rV|{!1*1>k9%=q5=D)+dM!Rw;CCFi470u7&2PAGZcU_1SoP* zJ3FhQ6Y-+!A>GW>P~#v$Rtur#v!PZ=^OmI%Xopgr^jYWjTEjqv^`Xt?h3%~zdbZgRc$*@UJgOA1T zlY{H7))QZS_>k4wEa($E#_g~wCyd)B&K@f+%=R@kRWku76@0QNG?^ZbOUv=7is+6oJ`Q7F6=GVQDa$)9L zNp^fnf5~eMSmDqK?*4^GNwquGMJ6lR)4|Du*?W!6h-M{wBWoWnpNDMm5uDP-#8m2F z?(;zY0Is(ETyuQe;y&(Zy_6Tp91R(m=PBtnoPftY5Sw@)>0=fPWG34gs!LWUu04cV z{_FMWr+U{*i0o>fdm^-HNPD9(;V;|qV6jVIFsHxa2^WT%UVM=~smFmWI;RBX#mDl%nTkueP^yb3ISH+7>M7lG|Ogu!I0hkD)~ z(xjB%O)K*oACzmRogh#$py|E#+kMZTOrThbn*(dSuWsE$9TgmHuITp!lRuSI){kBg zO`^=270Xd-`?S89pD(Lhq?*(_!deFvgJEo0{p2B8>`#4{jZ9>rR4juk=tP%S2nk-vwzK0sqVnF3xMUICVl8dA)YwFE0=G@1f;v93w+Fd6GFg1}|eUpuqKY!9vI(-ha z5raD(I8RrXh#R_HIUERK;G{WEWfHV`EBIzCw|O(3&u{44!|x&l-KBU1=4r3bgrzk! z!wHw6`}+yR#L};4ZxN{c3oMK;_vqlj|GG0`wi&iYgzzOPqS z-hxHK(=R-H%;bCnRYQZ8>u1S%XjELOp$v!-feO`8kvmD@l~Z#s88F3!zzR)VDeL~n zPLj<(mfwXUmjlg+u0D!-P241yE_Gux4s&D-G&*lP@6vQpFB4AWX+9*1Tvg(6;+&Uv z61-gUU1zLkUi`Y0bdG3`q%gtHW)cXN6{Do|{;@xD!2X6$3C}LBKLiL3b=d={reP*N z2@*t|@yYz=Hyx_U%ALhno1^ak!41fC89e|yt;@vgD|PzL3P}4f_12JHZ#Jjm8KMNZ zguCmV>KR5)3gC?52qy4|ldi8wQB~v>YP|duD0S&xSq~$BIW{pK!aRY=Kgvuv-!0@% z{@xXoUm)xZ>g&qJfC9Sf+;IRWsh+K&LqiI5K8UJA22KBTnlvunk*O*rW^<1cYA}pw z!`oR#cmavzO#-ivSv;m<-y)4Q3e0eXX*&PLRN$FT!xXW)uQC}}ZD_$G$KRZvL3YL| zvRSiRNT)nom7a(iK-p8w$Pyl?kOD14YJ|Ukz zUu*~&zR~4^nz8{tUiZoP$44S*<*7_YJ+`7 zq);>y=AQ01>g6kayp@%&EVQWl(ok@I9)0jKCS#iZ*t#6Kjz~zwKC%CaS8F{rM3!4z zX*EABU^ZB+`CQ!dQ+&aV;KuH%@JZ*;Pg}>A6B^Hk^{hbrw!8E3D~4hK{gu(#$%0&v z)`nlgLq)2G0#4xisYZ&zVEOUq^qY~bXPRkvE6Pi7Yn?jY7w1#-eq{^Ji3b5!e0gqW z+)$Z)d_8KgPSac?^&727KA2-w1#g)iBO?I@>?yBH;cxGvCY8ytr_M;-Lx|prk1hKv zm+xh1z&zzD6XUN$lrCvJpAbt2t@7*y2|-UM-dn!u{t)Zd_PmGPK=I~ku(4NDGinMC zhrduao?&outb4<7g8iagU}1BAMa7504t==kuC7#Xg5I?@(Kg-ix1G0i*LXwUAUZ1K z90}6xnXN{e)~zBQF28eq-20^jF?crF+jW!diY5H~YuJaB1OGyOJsNPdRrgYX^9(wd z%=TQyeQnC%LH)&TvH8U`VjmO%eAT3`qf%NON7JRTmM9>MT|UTlgIJhO^{GfExM>hiko$bL;b z8Sv+S2(iSGqpte?n9BrluK`;?IaJysvdlbr9Mce4F(6s26Nq8{=gAhwrqw+T`*Sl% z7lm|;go?+MdhNm(4nwig{DA=@27-*7kkb106@=ir=mOl(Qnb5$5A>}2x zF@;a(sTUZ!REu)}xnMWptKUDqf0RU;nv_cp4{zxg6W-Hchl$lucx0EjiUV}5vwH23 zSe!u&mN~EqR_}&@E)da-X3MP=ezoRH788XOC?c4m*cWr^%LmvfY&+(lR};csOWl29 zzeGTXFIPmMfc?7H`~5_-OX`Tm{Upf{@oQiX-)6#DzlR!5?%b_$v+l_0_mR1(pdyf z7DRRwa_GhGm{`u)fgV}Y{Y+L945CIkBO|u=m2d(L194$!J!0=fqJCFa>M6+t;QF3` zXKL(C(&_*;%-wu*K&=@__{O2JAq9ngpT0ANjE0P_C zvZwmd-_~$7ifcn3(AQ?R&b8+dzN!+dCOCk&CDfiZP-wS792k@s$0Mjrc_|CqnCR{| zyXuVvl}WU&z$?J=#I#XBxX-gqxXb$trh{kv{11>nt^W`1^3B9hHWk@&fU9~n_I9g; zwTElUQ^53fEq9LV7>+g%_^V=3$ zMsw|qdN{+G^y5LhRu$-Ottb%1D>qy7eu#h6(9eq40AoqloXDLK)LGbJZ$tr307s!f zh=~c5%1vHzOpp?scS!~i{=pQ_b;fyXYE$F1;3h20MT|ZQoG$!d(XbF1#?_UHALnxh zker!z-b(e`dez0QLv^Lh8F<8p6ibY(qhsH&ENXCfP$3u>J&64iH199^9!1^U&vTOE zzP6<;Zo!B1H7zej)K$(fU=6-`>FK5B@xlj+=)YMmfiO36o#M%}EL-hX7Fb`np7d8Fh36NEYG`OhkoK%10b;7lbHv8VH_k*+a-0eq>_1 zlWI#A8oeYrc+Ms!JkzOTe9%GcBVh~}4xl*!v}(|p1X}&*o)zjh&WN=gVxLW?HdiKd zI~2M8urej3HOp_h^QAW~6)DzTwJ9cXyBM!LJ6a3kUzw(PsgY_Xgb$Yb5rF^l)OB)f zeL%!pk+rCqm87sZW~To@A$+3Uv*wNQx5oUOtER1oWWahtpZgfbG0K5cmZ7fQ3?w!H z`O|)9*y7f5ftk)c8{b@QvHMFYnk-d48~^Q%Xa?88#J`c!VQEt%+-K$1B&dn9D^TwO z)6t8ICQ$jy#4I`s;2u;yO2!%xkjPW=sIb%9mPWeWTS=H#dMELZ$fu2W)96 zPY6!S=;I(_s#(TC;-0SyWGBOn`IUzUYAJ0rl9t6X3zXtddBBPZeBo0&0a#|X2754a zX}^s8d?_V*USt?jFceLdw{h4V$-PS6?ZD5ZNcf!i# zM9Ea%`(}*nZ_B>3i8qMB0liD>{m4(8&Plb5eW~zVX2CbtZK->thO6{HE^XQ+`^W%o zFf)0P)=vmlGK9%yTddAvcYEvSM}P9b`;!b`d+o&HKDAz|DP6lWOnU(H*fS;JV$XCb zd-TnW7++=9DQ8E$=CD|KEcet%K))~J$)q(=~9nzZKBiR>*C5I&f6 z`$vKcOz35TB?wMZQ_1-{y>6)uC%S?`^%3~O(S%d_e)#c>W z=hrzG4}JqqZXaXQ!wFoG@n~PiLTHlVl^l;j%LRaj^EvHnucEEp@}2RY!EbXrJ0mj~ zwtks>9ZqEvI#Jw!My5dFst`jy}bDf7>buUFD6MdmZ>(hpMOSiPr1X4T)ws zYE;xj(^B&zOqk)uJTf@6!=Z5Yw%@$9|+gWX(rK2w9?A6$+BqH@+~cV5cPe{MK|aXXzbXr97N z-Q_rlj(Z?}B!d+pa({zgI^G&s(Hs;cqJGGbY+L(7j;#5;-7)?mPP^#~H1Ia)!5MZt z_~eGJKE25+8PuwGStCE^_HH?r84}fqs8C{_(9j@IY*E2Xlp}5=W)VMn4DS|k zF|H}j+|`>yMR}hC)XMXV6l&z_UG<{bAC9!J`zuLb`UP(zppSQZOEZ;-M#jMoqc83s z(wjkioGv&T_?UR(`Czq2!%m1zJA(Oai3-jhGX5+IFp&_MXHiHHo*t^qyW5q4n6*n( zh|HGL6U|5LjCj&={+LOTi96*{hicmtW2N>cF22CYhjGqMzv+uh1UkA+r0$G8oWN`i=7gNcm|SHXA2wDfe} zodX_=H@Y?pa}p`xi)(99qH!%`pJo{*MZZ3Vem;?|MuN#Jyk-Qo<08X^kia_i{8>A$ zTO*kk#`ageO#}kYMU< z@4$={(f&oZc_EL;-ZuO$MK&q&d2#3G$pOj2u7jyn`}XsdB~4hn7{o#N_)%5mX0Mv> zXA|`SHTl%_mpFt~WQDIb0=>|{{`2qe?<*BI6u(ZBcWJf@w22khJTp6u!XK@1pLl0K zH@f%q>lqV#c!&-Vq%m3YHHg}lZ7~c-g5daO0KJ2-p{Ch81#{@Iv}PtM1|7Z{OpuKN znfS>ccCBgA%DzU13fC*2vxF&pB@`z~92+%X`a23@$@Dzu#7_m(J=wowQ`?Zhe|AW3 zR!{?Or3UbySVMdclE(oyw+V-o#T)Tn&tn?b>kD+t*W%+tcOjhC8_rhxi21lpnaDMStPtI&c?lClE-lkz%0&czY+@*m zf8#Yu25voIQcN?+{LXiIKsx7_F`V(S?5+tRq|hgJb0|Mz&hW=B;=&Ig&Bc9@pvf&{ zHM0!&qF=G0pY5HPmLB~QRDcsm@cgsx)dPA<7TaTGZ)Z<;Na=0d&vB-yQU7F~l|N|) z$EO~Qo;QA}yT5w`e+n5I?xMjQkK>kPhDWW>?rVWjl7{sodwV%4rL}Q!J59dGI6N&D zKa}XJxK_32wy8Ff?yWH&%yvYKD2NnL+P}jF9*7C$wbmXIgv!u0h5>~Q+~sk>Wcl^3 z?O!6NUm{N}r`YCw?5Ej=r)Hy457yXlY2(7>CcP!@*#H+nj{zT6g-|iVqvG#Y9Rf3k zRcA2Vv-I62tOhAa)tfY$T1oSwHrG3Xd678pFKQhe1BKxP-mX|mPkP-ygcIp0O3lXa z&%uY~C!bTCRKG@sP5stN%n|9b^7epK9(zU&%+VN(?;5^|Lx#3@bCR`V-XQ{$XujO- z@j#u-@HY%Qcy`WNH!wTl1b^2b##)82J!JDTuxn*%=e$g%0Y~^DLwUJn7j1l`n_KlI zCTPB6Grs-$uL;PYfO;5QedXm*Rf;jxT2h6N&O|?01*Zk;X`NhIHTME!4eqvB+ZiQh$Etjjp z=Dn^c!dk`)VN?8JbF&RUAiqusP63u@Laj*|$6`p++`8O|2L6K& zdJH`^*J1+=mncfl#!N)7b2{OIN6u6#xD;r7wRNPfJ9S;E$#xXbHbJS|^66qUiBFeu zPq5!8-M{%tbI4b$}KCC;1h_AXTnc)(ZLGo ztcu}?g0jP-DF3wv*#n>R>9bXZOH_=_pEwLXL2cf!6ZoRQ3nYkka3D6(s*ttQ{Vn~? z1@;}BU}7GLiN$4XBVW_G?hfg!QUK?qJauaW=*=hujMFRz=Yky>1`;8C5=6Dc@-*G! zt)t^>%&9me2%FY~sa2{(2M^CccJ{MgO*-VF8MmgzgMJ_w_#}P44+D{pEtSUAttaHV zZzTJNrDc5OggIiskX+)crt8L2lx}tmIwN~CB7&4=foj{xIiM4rT-NAQYw)epZBqI( z;-ZCs-|wHw3vPh)-edf!25bNTE(wW6C5xfN!-dF-%{N*0g|+*2ad-@#2pbbbqIl|* zWA#XGl6A&AWQIzcrEl}4{{*P-1z%=8kQP#U-@lDiAsE7wxrTT&<^VB|HdkeJV8ax^=mdj z0y~)Y%BbukpEqhVd$(NQzba6l4G_MO>Z0PE5ox=<4Vz_Dq^_8iv zT)s__F*Yq(_6dCE!2;^G)!5!@P`*`so#hW$z&bEJvIVgq7wy2kJERbs>F9~GYKITb z9<#*A`B0~yS7^qgh5YRcVeLs3zK;v~NiF8qh4)d2x{g`M~5rK_*t8Nr<(XwV2h$`5w9HiKJm6k_pbO9IJcGbC!J3>|%hPTTr=`Kw5aB{p2**dA6J^(h z_YaG0Tj=tFnkIw=4A7f5TifMfYRDX38F|E`W4QG7C$v60BHpZWfr=#+Xc&YpPVYLU~1ZXvF zPiwx&-nQEUxoE31wKgIf9RPukwCni;t5&|IM zo5uT7_r0_69Q+X0OTG8@(G~G8yB5T0FSd#Kg|VFz!Ge|=+Fp0HADt;|V8>G^kRbpb z;LeI53jYsnZygr(*7c3k-Kf-1f`lR{NS7FdlF|}Gg96gsAR+=ogEWZJosu(zbcn>z zT~Z@CFvPsy@tkwt=iJY8{hsT&-uL(YLk5JIz1LoA?X^B@@6S3Ga@I~fle*ZCUUzRW z#brKkbi1!5bQ6kzs|D0aE#Xby7%yP)evieJ3f`U;q=ME`E%xX|&?$_IF09rU0{cTF z1<;|<#_zJuK{Q(U_;>=nlPfSe+@slS!i)1?Y1=zLl#Ap^b zx!^P$PIo1hS_M8E5(2C4#E;5D`X%VJwlMFo=iX$FiRsk>=N%t9R&NI!Haf)PfWnjL z1Lg9Q?qfmdPw~;GFcT?gS8j`$JrH ze*t`zH-*&D#Q^_BSpouBEc;jQr(Y=Q+WkwLTEA-9z4#;U2fX~EB3DDm+f_v)oaq$n zJjFQUx(9yVDf-{8^`{DjwLkB*sF+*7OZAJrH;Joox+LAHhg}*^%-IqX{R7D80KH%P z!TKP1K}m@1sW)_Qx-06HuUqE1)Gwq8DS%08U1LimWt+5{?>ds{(XRH6 z6qSb;>+6Dt)l`Qq=aE8YTR=GQj`3bL>;)Kl30$wnJq;CdJeoA`+I8RU)3mgl*g5#s zp|U`z9{Z}v>(Hj@xxihmfHNR4RCG%y)OLMdKShUB&*roUU=FzhtlR7Y=xL|5jC%Q zrBR;+MP9I=Nx8S8CCjdZ0S>$|1E4l3>hFEGH}e@w;ilF`PWVjnEkkUGFMjLL+P@Np zCx9uRkA#&XU#grR98m~j-SNy|1!58e-86rXA;r7GG`9YEfCD5_3!31{n+;M z-tTC@_rs(-)c-z-`S<(P>4aCUub9Pxi;74TtAy~NLz|+Bl!fj(W%@dkWAm2kIDKQlOFW7M z;!EV49e5Y<;rCbt`RX`d$|zP=Gjh=7x@exc!ZF)(^RI`hhe+|&7{xohFa`J1RAG#$vKnKS!_jc=lN;uMn)dJBlu_NA$>K8$OwN9GR)~iESpSl=D zyfKf3GsS?@xwuLtG2Ii-dx5h;0}lW?D(aKanvc#U3YEP&1;o->Poslm9mlGY zvbIjF(b2s?i&_Hg~-W<%&!@8u?DO9D8rT1mm6p7Ku>%(Z#NQ z{4W!pEK4&8`FDG=oSx_5E)s2x---NcLvM~PSveyB03Lx#J-#;?X3cI1oDwLV&R5-< z(~-rZ>p8^kY}4Io9S!H+f^lngn+XzJiS*hH-(-|&{$3#XJQ)wNDCt>7OGV-2w9=Kp zu?SSHUg{H$yO*@~5Buw=6|MZLB)o#fQqy}~>`$OuA8Nx~hR2aE)311Ew3C2i*6p`F z~&5wY+uA@_hGpApIgT+Tn>Q(>7_n;gyvfI56l1o3!8Z$Zp@A8Nh~?6UTV*! zIS<^=(FSjFOjwGleJ|Z+>=CVLk1S?8P45Cz!2!tyT)A-O9{LF~sF%0Co`)a9XTpZx zG!~AFv%hR%4CkF=65E>Dz`;2igA3RvTT`-n=k7Ihyt`_+oHzO%p*U=iC@}G5KCQns z%_3+Na#|N1Q!B$S`Z41E5wo6ci`v^~G7C4o^ZxSZ;$gB-XT=}FV@>t7Z*OtVPpR-I8J?SF|&#r7ni|++SWTL!}AGhsj>;M zu+d(Nh&0te4x8`UA59~rPbTr=Hb3qH9*Lv#MsA+7MD5OJ>9-ez3o zoAv;IkylnDdWSdsk0rTb)J6TV zC&01e+S>}}2(<}v69HBqz*n%dU>R~=BC6FoU&w~B8o#P_z7dqUnNDY|6?8L$BL4DS zdg#aQ-l^(AQ`XI*;^op{33cO4UCHWiCvPoXpXDFw;VNL!0K1%!eMH~G!wmoivrbGV z9K%$!-6%4>xF*(5HC~0*joWVPtoR%I-k-FZAr<&+-w@va5)e56e_f&AA79(?-HTFr z&yKons#U?=WS%b6J!Tzl5?_HBA_I+2u#{e0RqUR8`^GUQC;Le|l!TPf)o)P|qgHz* z?gFOta4ofSVmlk?ow@q}Y^cX>k9*lbqO?1a8Q{#jy8+o6h|ha|anwJxAY7ql#l2-~ zLJQU}F%#sFKR>;5*7T>7YDM{?`~#`^T5|=~^Dhk(U1ho&oTd@p&jW@Jf01782etVF z!S9Q^%gnfGsdoF1Z$VYR%hc%zVnI&--0<>XBN1+WOuxiu3`}S@!56`UXF+Iszb8G00(zJUF}B)N3J`L7uCV3e?2j{1aKEJ1w#*`8T(}Zs1@T0jEM#Ty7k`J zUmQH=?*ppCN(;1y$qNPtViis?b7XUA%?kz)l&Vgo1m*tJl+_l>4=4 zFu7H_tBWVXD0+fVXil@(gFqI~&d%!8+D!>&+%P;V19cCYOr#1@Gp3I{yNlDSGQFBkev_OcIe~PEH6rr*X$1V4l!^T z3+ur}M-@rzs!Pj7qICpuNu8@uQZn>Sp#?aan;~+RTI!THaneaQ?ON z!%1b`z}e}$x38d*qrY%TFYo;#P5M)_x3#Nfp5Gb9W+(|=D3-FWZ>FT4J|u*!UOdDv z$lJZ#s3+#Y%GLIA@teI2#!`3!*Wv}ov=WYt(T6g!1-@9OGaRA>b-`vu?`}SQIru!^ zZH=b*>0h+~Y=}ji7gLe>4FCEL74c5sI!!pvc(E?Mdw69Go;!|AB_>i_t+u9SXJHt+&sL~k z-RGFsZip~uDxoXdj%3g*kOQw_wM&ejnF82CA^1}&#k$muer>9GhB`4PGvejbJs;~~ ze)xKR8xYS0h#ph!NSk-xuqB=`4Q)V-aAa?7k=#Rw!Be}4O4O_?!)(T){pV;Sy$NDXkIJbqV#R$@&S7K`T3M?VnXB(wp??q1sS@6^L59tgYu_r{gCDsx&tH^<%)ipZeI!SgwDyP@d9k_XJUvi(W_*ziX6DO^D zu_F3#2h=JOxg|*<797JPzkuyxZ%L+z^pEYLD5vugjc)VDeD_K~ zZ}H51a{|0U{y*YYNm%Jw-s~rSxz*>QieJR~YyV&S#*cLaT7$_ zBveBAUI0-G9y@mWK#)-mBMH`f<*caN&$cJNd>7e%S;Nz7M|NQ!H=6l$ZO1p%WBbVl zVW1&o`2ma*%QR3j9ZTVTJ(gyb1!bT){WOph5xsuH-#_hwZHxV~T4LkWq`hHd+J`IK zaxz}ru~Sx6M7V*_!}n07l>oW!f)9Bw;xHuRTWhOp+?73iab|JxB#R^gdot;pq?u)L9n+)u5-#Rz}Esf@)^Yz;hXh7SU@-n zXd5`H2{tkC?{fg2up;F~Hhx#3+zv9gtZzrFZp z(DcqNj(J6z9(_zkJn*ELNE}XEJH@oXJnr5dt#_Qj8=!xxZ8OV4KjHK~1U9cBThl!{AZX9eup$FJ5RsQy z!eA#r5V(pwCyQTP+HUbtU^v4hGmL_qd-M_#=Q}`0>57Y; zYGOGoi2dmv>l}_)u)1{rP}3)xp?M#L?_uVPL?i?*RXEHUUREU6J-=dd-S_R_f`qN3 zl!DhAn|2{B-rq=UE8x?$wN0j40C3YU<~61fTk==|9I&fN$f`WVUlPQj6)&+};yJO7 z^$_5qpe7xMza*q{-y3lFQf0brFMGxreRVmg@#hMUl;~^R9hxo=JeszZt6lJ)lI)j0 zFYy9}096vlXc6F?7vm|@+97@;B}N^v6p&4ZIc$5nnY#8|Iev!GMT`Z;BbC=7*;3_7 zG`=AR12t67&%+Wn{KCR*SSRAW5OxRG*Q^L{dvb(s-S`|ZgsGfAF70I;!$Nbahj8Qw zhQ4;h0^R>bDzhJi#sq^Tjz)S*vo~55?+m}?L9G&C?3Zv1HYvd4_yomD?Sv&Emx0@as=U5>5I11K z6$=#0c`9sM0Jfi-&i?U}jRR9DlMC#INbB6gm6#{uf~1`98r8lrq(J;x~sgr8z4% zDr$g?lp6mDyu5xdE6^FZdSXG2(+N^d)e3(0hCbTL=hY6>lfwT~-;LWZ3*|zVZwnv@ zPn}2e9*C1xM#p#Vk&Knr%WL3w-Jf+DRk<(h$X2OP2RJ{ijxC6!4LD`%a2R*%pns(( zhke+rc4*?*==|zLt6{1%o;}4dC9Q_JmtIF}DRB0H_kd=gQT; ze=L_0_{^u<{}4xV+Jn>aN!%jZ^cTy*=R|9*F2CAlxC1T2FuuOp05_PaCMki^=MrZ1 zVt!C5QPWzAE*(>5&y)D7?&U6~{IR9*<=Khzl3i$@95|2pcR@wN7XU5+U9s`6JZQG4 z{?HFDVtyEC2P07&qEv(9u=KZX5jz*$4qjE{TwUUh6V))n zhsV0+1Auz4z;)~0h;GGYAWzgJrQ=d}!X^$V>M(wKtSj-fLD6a(*y};?RH5HZQ>X_^I7AU?P*; zh8U}DXKD>g2P?sJxbx67qG@GSeB(3r`c25qOdQV_QBmv7rdn35XaafCRiNgB|+}r^C&TZsrsEsx8&Qe*X^kFUib!|E@h;S#@*t>8o1G_T&=C$?3DAD#U zFq))r=1qi+kBuR-w~f~I8#Lf+y)WMzVnMPS8>LE@4awYt`kro$s$FiSIUHci6f#R5 zjMJ*U9jmizOy2TF-WO0>orLV12= zR)boBvA;Bn-yMag3jVx1?h0FZ{Se)+EzzPJ`sh`1Hy2HK^J&womxf+t1zMTiwg#;i z7vsq5te9lM_PFm*`I#60_cFB)ywM9YYa5-q@%d5_&l5NLZm)TjQH+ZvY{b7y50w|vG{x;ptvJ>DAq7y z)v2;~=lNS<76y$>p$AM&IgPi1PFhemd`?fGfz+oz)24^RYPSQv+Z_Zvt0HHlK6`f2 z=kg-uz)tNG4RzPA4o~;1~&O-dm zhTnp5QXhXp?puxttX;4z3-rTcDY%S{Ke%Y)FICTT`r|pBBtnkd*ra1L~nE3|>IzMWz zE)x5x-czzeW??AO&jX#Ww8-G7gNqf|9vefuKO`v~i(NDO-F%wTgvVuLfllhoLcuOj zSTH@p4|{_1A^X!p!~1ught}QM&YY;isbQ%VCQt(D`KQ1%DQD5dCxR~4rG#D)Ac@F{C`a&U)NF;_plmyfIGTV`J)k6Bz#MbV8X?1n80}uB3@$U#8xnjbZs^06Ro3vKYnTT34(KAzu@a{AQPgrU6+<@h~Z z8s~$Fa#jdg_Fa8Jn-GnYoruFUnHKK2k(|f0IgJvxm@uPUBn!^u+@3#*Wa=x{*(#_3bJ=TOcF+R$wblI@kDJd>2bXC1U5z6r)wOvCb zjbg!H@>nQS#_0NwpC6pPz*xQ_F-*@?<`3NUHGkOB?2uM)UB~e7KU`AmA?_hBuC2Ge z`GWT`X@V#qC>GD`TOu%t`x@M73sZC^DmW#^()8!(A1b0olWgZTuL|#(%RB5K%k}Q7 zUu6+>(_mw4CS~6p_voaHPYUd#-XPdxfdx+j3I{o*Sas`eqR7HG5Px)jkr&x<6=3| z&dj%%?=OG9)i?JsK{emP;6h#O(NX~$2Zy#-7GkxR073QNj+r}<&Uo_!8I(mg9G0(To0jgrK@LRnxN=c&dh+h>;bZ(5E>21sL1lLqLA=X1p zO|DrtT^G-#(4l)i?qGl~lBdK#6eQxnLYyW-9tNyJdzEE~De9>8*XauL(mSRq_IQm4 zIDO&mBXb_`HNQGa8Al(0Wf_YH1aL%REIr~HY*5s?LulAlKB13|5BRSKqWK+u$Z?gz z(z}PO3m=k+>*sVNzYGm2hg)L$R%v~{-EIkoKh@&85SIDv>2g-}9Su@n1jrpZ);Q@qhg;@B(lS7JvU zo(X^a6!1s?7_Y18HOL>0ng05#|LutXhXH&KrFQ=N41ZhYU!R5f`oA6V|0H1}`q11z z+3)}O7|c5VeFPY{@P9J^SJQtkapOG_h0wo$0N_#ozZdy`Ie^V}qW`*Pe>Q6PVH_SOXnS~=B70>X0(u#3=Y6CA3xtA#a zG&S&=OZ+GL+=5SR)dj%?acO4wcMC@PjgReX9CE%FpVUG3Oxa^H@7oPaq}XIeY?wVA zLZ2Fi;X2DOmu<9AGm{(mZu|02#c^ZzUP{+IXr&*f>L|8LjJ#L@9yS67#rl@-_C0+iKb zZ?@MhBZ^71YcyXiSEu;f(UB`i##hYS+uQC>=USp3%)x=X8pBySGEv7bA$gvgn=A0_ z3;D?OOVxlmjAMoo-c^bdb6k8V<$obI-|E-Y12Ewo7z#y22*RJueRblvo%mty59JEH zt^kajEi6M48lH8vx*r@Av>$yk{POlC&%1X+-!^2?F1}~q7M3S%Iw$v0GRzJ8L096u zW%g0+tp_)MmQTIQJIxay(Ktiba^JaN0f@S7fG;ndVrB8d4f%F4caAdH*6k6-r+b#-^ALI3nT00n6Fn>rE z09y^U_+NS-di*IxjNfU~K*eiEgT&*+t=$L|f^#8|R%JWaBV9CPZ!hD{hRi;W_{E#Y zhvr#U^SBF7!R6<?U1bw{ccHy_3cI^ZOg{X^Y=mvp!5qV+Sb>g_`+-ZNmct%4B3@7umLy6ck-YM@N$8xw#6_015naGIDZa z$PFUMvoD!lnGtk7asVB6&mj(0Hu3A)=}$cyBe@DH4biQwt;&vCr8>!LJI}tv`RAe} zcPA@57OwyCVVF%PwX~&0dMI5yKHQJrxS2jp)M3bP&a9H2kdh@5p!S*|jrsvr1GDL! zUUG171m}{qjraup>(k;KYPn)-u5<8S&;4F?kp=$MfF&UzVdn4eudyn0|NcnLx!38h zrB6N$UWe;d>5{_2iJ3^%jo~aL^3O;RP`4Cxl?Qyu9&|nrv)0Y~Xz{$xQa{PUAdcCl zgPcWlfI?i!h3896n}|9^0zmotCfl!nAS|U1$b5ey20hQEexkU!=M(FNG+G0E_gc6! znFq_PtTtqeBO$wBxyA%zOaj#sA@ zk~TlyCW{1|gpEn8_@oL&*mTthyz2Wb`f6YktqyIatHBR;c78@BcJL@7s}r%U*qqF^ z@5d1ir{&y>j{B%1-(Ha{ynUdQPRF%x7Tl?;M6>W9&hwVs@&}?6l{v%uwoPrt`V%5FM6kL+|I z=bV2PGd%rzhFfXd3oWg>oPIC70b4M_Pk%~a5QjB<3Y#YXozexr)v@@LK&y)W@N&fG zaci`Znwj6-@U`o!#l0JDKNq;E#eSrlGIG94iV+jEi0Vg=8TcU%KMPyGcs3L|aq8O; z)XCvQlPq7dub-3)RO`@AIj{X60$-0qj>T6lIUy9WUnS+2L%oYB{V&b4E*_ZHZdZEK zz@I4YfR(J`{4#y2_Uhvd2KcMdes5q~xm5vgs!-P6yfk$0D*YXYP%^rq>H467A*VL| zr3`7DiRQ}}Av>f7>)WDCtCKe8Qk86qt$k87^mM3l)+2`yh?s1#BXToJl0cl%5Ea6#e@N^d^HM-?Kjkr-66MZ3Y^f)JmZ*(mvmm^v# zPClANMO@q$cknxK#ZN;1Xg; z?*kX+fOQzQ?tz35H|~on|4U}(Du=};PP@zVtHinhYgOAj-1z z83s9=3`(2lL$8Hzb660#jN7xxwo3TToKQ5{_OmVzWrbX*Qk29&iL#iNC>rj&t0d08 z-6{hc-e4Dkoxe@;qXBNMN8M%Le-e^*RblxUc{_PKC3$kgYRK9~g8wLsbqp#{;cwzj z**7@7hgu!16?~Yye`xA9Om25JQxsF}ZnU(erCY-K@?r>a`Q=>+1D#cDG}y8v-6I0EQREgByielOZ^w}d1341`SV5m4K!lMh8*rtw%_8n>F+l+E z$V$H&;`7L1WS|fv0|RH&%qqPeG>tnk=@Iq4+T;OcPL#3WK_W9qm8j6#PFBu^$J>*` zu4Wz6KH;i_l)l&woZPW>$bEVR@DE1X8LUoR2W>1tn?FvLg z3Adc*zJkL7$PLjl;jq{@R>^MK-@EsT$y-r4#$lgeu_&h;cYk$sD-0EMUqq5S-3uJU zZ5qY98)t$)6WIEkIzWCeqM(*etcQ_T$F4Ku?{sQ>o{@**6C zl^?!)u>ezHW~nth+mvh_vcVhJ+3QRO$wg$yC1qmwziL9^_Yy++)Gc zYJhUQ+HqKpkoifQNlfDK1IHR5SYZ@%WMg<&Iew5UAJx|f(_p(d`D*fgEH_^5&?$c| zOyk~ZMC7yyddD`y{^N;TuD(#fDR2&TX%l@jV`i39t@c#gYoqU3lZP`|)`oxez3SGJ z4RTQFrpe){GhJGD7@fzQ%hw{S^UQLV50)sh(^t6ZD2$9w254BrqvMU3P8gQhCMzl) z0f(b5zpBg1Zk}MIRL`rK_CoOEh+Er-8_;7!fHO6u>1Ob8NV|H-)k?b@aKM` zu45+LDF=;`8x`Rp2Qj3z%=7bHK598f5nS7M&tw?-(10q)g;e3&4gnWez8p3zAgoQZ zevamI{MoYUFCjf+cYGU0Mv{<}^rOnMU$0^#5SJqRAsejE8elvSvZf#<-?hP9-MgBX z)3c%_-wa@QnhVXVs=CtB(ptzXvBUbd;xk&2Q@_7$2weQ{`0Qk!Y2wzyHYV_HZqEHc zI3h6c;AQUiMf^`ab8-YAAkL`@a~iF7*xy`yX)4dPG&jxeDX0>TZLW(esF zm>3b;CXbOb;dj%ntOym!?o^6Aho-GsmTz|wJZ<=S*{_9Cu?o|Uo2vdk{qPl$pmOf+ z1Cm@__He&o&Z`vv>Q4;4=UyT)0u}8y2HJ+ytm2VeS803xFF4;s_kug#G&z8I)H2D; z=2o)JXd*&5udIx^kDQ=RFAE`}3on_p;P0kY@u?nvP&(qTQT_5!mp@>)sY7Me>f=goC6hHjK+X_mommgj8rp`b-9Gu*1%`+2z96~COe8UMTpKs)5oCGD^T?xjAoboD7 z2+?oUukYAo`dUp~xS3oh#jcDY?g~BGCOo!Rmla7dFFKPZ<9FAE>o@azebN^h7^gFG zjlHW^4aDK&E{#%_y%StsB(yjf{P^EbHVKY`XHWJ+eSHR?k5XKy_bRj(>bAd8NgL(f z3DfX8%dU}2(cnPe?vS2oZvFHr#Yz<|vI5g^JGOAYEJ=B?^s7eIC`-A_0#3=~-IQys z@#4o5Vd2tO$Gd(a#j-355y|%4pv+dkH}pxFrQ96Dt5Bj#N5Zr;Rkcwt3UCE^MhzR1 zl^P`u8jXX=&ehr*B5&px*Wdya-T-?J(1IDZe4Kb;ML4{Rs+^xQi?dJk5V^1du|7^zm*HS#ZK@gN%g6)H75hXq9 zK|3!12h|+FNdyq@W2q$kS6phoQO?d1(8{VjD=VP0J@%!5C0tav)ZJB}iL5y(~d;iaQ zOvKY6yS0l%K5O@4uJ87|SJ0X4HKU{BjlLL9*jMsCv1!$yJuu z9+a$HN~>aq0=-C5)@}X!x*O~3RVIVw{>OLL4v%^B)6Hy0iMi7QVbp(#@%LAr5EwO! zAWwzk(xV%j`V}VFmj}tv&p>QF0`#m&bmGph^g3;oxT zS(7)7mhBGf^!mA*T? zkJ?c=0qg-~P#2lu)L5x2=9Z5=oQ|D->6}7SgGL!Zct<7nLWCcL2U$;)gqEYnnuv}} z4SDos3mihOf^ru=6OX9yy6AKt?@lA5gjuRh%P0s!`1D49{P^VCYTV>rTB-tc?2r-o z2dan_$On+U#2g3Zsv5L-1N~aXV#qpxUZY=9Mxk|~HdccdLCV!ICutQGTi~{nv-5|k z+KzYg>s$VSzK-jtMeiwmEhGeZCF3kU8ZhXp0hiJj3}>9C!u?zC3#M*dN@p6VZ4@hqZScQ z1p2uY>h7}G!s45}g{!dD9f~@WTR`H69d}#=&ct(lRam~Lj_@_2E79AmGWtV0Lj38+ zVXSd`s6*_;=CY96N+yODRsJwWd6mT;iHz-0_l31CRV48p`XlWo50qQ2zK||_Y^(wX z9JgCZM20`65bvDG>*sHZO#DZfjD@jXj)#lyQ)K)kfCi+i>q(VVgYVZB46ktZ?!kjN zpiqIPy24krY3@DQaiy7n?RscZ;wU(9))`*~eQmjT8Vl*)d(kPPxepdV!j{-iZ1;hP zkI`6pd7D!Jp#D8PLGrF1vursZPO4}i^8*UH12oXNc*GsAq$hZ}tcNJ;W5S*!&Zv*y>ctFZBbvwnksCAuMbbe|7u{3|4S^Ow~SXB zi1pT09|+t{j+{6$qU@!t3Hi$IuB9`P6>5VzmR`^{^74{{2jwbS z+-R!H%Ny60M4iaMb<_@jozIPhz(!Ww3pgVdhZWv9V|#e^R;*Pem3w^ zfXMl7?t8_dFAo@7r{aF5BH@&*(l7+k2P&j_qM1SS*XQKKPOzyDhuH!R0+Lmy?0ZHFtLqhpo_B6$#D8Tcufs+UZk^mfHQDQcmR4A5E}W zskOy;PV`J|Y}t&Ij4W)Mb=A35e`fF8FIbk;Cm_if zrT?EA#YPG^_CT`h!lI)2RW~gwSrlHjxDYHA<{>2uTa5xs=ct3>g8Qi;Wxen5`aSU-N7 z@i`{;%k>K(kuQqA$*v#ZhtJH;i9z_za}Eh^YJZrR?ypg;j}DBbV3_RJxF=cdCFGz& zM!MS@7+Wi0{RkbO>c485KlVG@8htB4Q7|B-S9yP{nc}x@@iJqQAi|f&O$S-tEOxN3 z-vchQTgg!bkfeG96R#kLmjTr3>2)YqYO=PAn;6LI4>QXu*DcXAwH^JEY@FJPsZsvz z!DNlt1DVokp#c_D#6h`35l^hDsZ=-xyWRZaxm(w7JC03y7Vsg$lX?*i4Rm;rtLCVv zSkb3v0umlhi#>b~lrHXfm1(nxO(!g)PgHRkysY5<+=Ti$*lNwaS)paV!e`Bwz8q!9 zF{Bb6#C1hT(U9K#D5JmOks$;7{doagZovPdqDd_eL#}=c04+S(e^oei*_1C49dN=( z=lA?6o9Y@0JBR~+rTyum4U`0lJW2lAQbtG1d5`}HjM<^;f;faeK3_g}M|$^&te*$e zlg`gE4L3GSBaqdw5g=hs9EKCJ`c{;xSZDdUqpJQkf8Zs?wD71%LiJ9q0f-K;8>)yw zbM{n6&(v)cSESF7_F{nol0%9Vq+)wE83CilQ4ocDvxw1nJh9YIeld>^;g9%?9*D4Q zJdxDbytRGY<%7ynhn-W-;BDgn&IwRcwNKtWaGU3zSFN!Z5hnEoIMsnEcgwX!n+sM!!qY=fC#n?Xg8=Ft?M!@#mGXJ}?}^rX`?im~f1wZY0YI|?s&FTNK_-$_ffx1mu0qZ# z+sTblSz}J}lWDNni~8{ig8OP}6JnhmDmJX#^$6IAT%xgG<`u>T*r&Liaq4Krdft;? zF1Fa{Ua=+TB)DEo2Kp(>e{Fyg^&3LTL;}2szHaMn9}@Xd)+d;dr198VX32&X*agMQ zcHCMLIfI;XkSIB{NC72C<>=67d#>%PL~E)aT0S!+(dAf0bk2elIglZ#d*Gt8J!GE2oLl#rnO9$ z%}xpH&v2JF?MWDXwI2EOv~R|B=_y?wO`0A{!BRd~Vp%PjTyfvv9Q_$QGT(p{nR+k}@h*)ootz31ln9t?SvyB>ak zyWEYZ1N&CqovnU7etXS+y23Q1R0ZG@-1{o^&qe<2*nqAVEOozz57zpr#hkN0nQ@Yi zJP={oX>8RO>eXK4xsldAO--RT{(G)Q_lHH~QAG!yXQYM~&PN#g+jzHt=h>p!=iUs{$mz}M_$E9bP^W;=?|TQzG{wahlW%47e_Gzg`G<8YOiM55 z3Vk&9;9bsY5i4NRi#^^Z#DkoE{Urmad+oW84@X2L9fo*SvtYazS8<6z zmkn>pc+EO>Pqj;1r#rp-adPeY^{Hu&+PXS-U(A7$zdgUFj6q~?TyqbX=7@$HC1Z)I{5k& z6iCuG_p-ztUF|#P{MP8DY@8iHzx~&hy*jJdGgiZvqAr#?)aSWWb0te1Wbc>f$VHCTkjDMRS@Y2E*K=JfyUnc_o3vTQKY~g{g)_=##3k^kg=s|lD zjsTSO)=1J3mMB380X&H4-rT#ToLkKopto?wX0&oN1`IH{k?Om0a-CWYN5M)|$frB>(_c|bC)FK+ZAUk- zt(Va!wVYs+r@+}aDzW92_H)?CLdl63XGm;wS;S3xx~VFEb&Tcadaa!dpWke-Bp2>* zK+kw63HCczHL78XLioOYePbEz4**8|iA+zay)z&l6M5m{;u7Y4v>Alt`G*MDFo>K) zQAvr#5^DoHP7sH6p6VIw#-|kF_?`!(AoytR`OD-Wj^3Co+a~vePI!jH^#1i1a&om% z7otGgKm?j&J$}>i%SKiJ3R@~<;CQy?mPr8l*!t92lTiTeiklK-xRGUVcVgdX4DTO8 z$i0a>3_Y;(Jbma=-`NPTo6iRBY#V?EM83YpR4-l(V@fD_1#?=^CRFAdx+E{2Brm39 z?O*#e?yMFXviu2yl&QbH`w8*EL4;x1I14~sUDTO>Q!jS+UuIClySCS4Xxz3fQS$+> zD^&is7U6|apkYs^0<<-W8qq;+4WyVm=K4&w2ltzQhBGIq#0sUcLu?|tx?;Ku%WQ&E?Zk%P$O zc7tf9*ZB<{3xB}~U{^T9WEMfkxYf^7E6;p3xEnr>NHO$O05N26q9#>I&%`k-~ug|Ttw_O^K?J+s$pEZ+q!MHt{Xc@iZ8 ze}hPg7!XP6OP&=$amOp5@!>1-CjTdg2nnASGIWJzoK-!|neSZlZ;7c7G?8~4IE-!j zzUd~3;tzEP|s4t{7-0$^*`#V?YpMZeT63=ADTALVX!^8Conh4P#T% zModd?=|;H{jtPVRQn4coX$G&nQ4dlCZIyo{Y19M;COQO~?3DM__NDATQY;sVx#u3) zfSPp~t_}T-i{CnQWuwYAaA?t%J0<>4z-^I;QlA*;l-6N$yfyy7|H6|bR02voagU5a zCk|eW^5hg>XQFv$0X_< z!zf>NEXP%6nLW$ZLpo`0Jjlne?dBQ!sXFu zM~R_)b0vM;lMY|kwJ;dH0bLkHf_>Cn&v$amznmE_JnK^lnrWUW>EFmtRxH+ojyI{T zGtJb!bufI;@2n>-j~3bNnB1v;aA|6Em$*ZYS#<0`0#eY|?DzPCR|_lmnwTRvA1Kh6 z`F}qI^fKg7v$|C=j($8GakHDv>64pmWV10Epyr}XCmXjrzjX2A^usd06KSY<=+uU* zFc4L1apU0JBoF0PAQvac`)`o5@fWA;VE=m0cM2ih;VjuKe7mBeNsrwIVp^^W_oJVq z{}tPOC%4Gs!{%r~y31!!7y0t#%Yp#(m6ooq0+7UABO{o(@{nT5_rFAqd{&CzgyB*q ztc^~4ZDatNizy+GzVmx&?W=H!GFFW3;k$izF1*pL*k1ExqYzN5_`)9IkS$()>IURh zKh{wqd8O7r-s%=q?wgR{5opTE>1DQ#oj@Ku(P0y24=`R zhTSWApI`MIe|!N%#yxa>)gmAINAI4H^hG(G3?dNRWB8EIhp&Gubc|4l7L*pNfQLzs zIVnnR-Y@v*JMLw1<9zz6e$zI@IFV*2PyxU1|Px*=R0Hz1d281gIm8{*CF2pJOz6>>SZRvI7 zbFF=>-5Z(MG|`=-VA)R(4%yTz1ulE#vc8mnH?xeny2ERGwIM-E-zN0*b>x<7Dx@wS zE;!|w0R3n&j;LwfrULTN&8dLqlWxnA5lhb@NbxrRck;9`Kuo zAWBa6@R`>Dfa?MD=^08`3a9>3^~QE62@%xxjq{}30&yoT-2aa{GEn2(pLAWq^6{MK zzm+u%XaRB?9*u9OQ=-?_@2!{#@t?9xo|*hRf$%OVt<7OE|*PR5(MvF0_PQZH~CNYUm&yrjatjC=0 zzzuaVLFJH6m64-e1JI7ICtIAt@*!t=M-+Oj-yK+ivB@1Zw~Nf##s~*Cc%Ir#$Ir6< zAJo^czHJ!6St1)8!kR?^WECLKOGe^PP|iA?h*&;(hxDe~Vijvg$vrKQJO1j(D%RML z)HxGAu!okDQ8P0v0L${cd0dAFDG40U)9RL6XSOLjIrDWL6oyaYh}6$}-}&;QFw1^+ zuWsfI-)gnaDt%8JHYjiv486`^ zgU7z98k353xivMUYR!)p-=F7pb6-nXi}4&>hagwvyQ+-eNG?1Q1N$WAd$Td{R&)>MVVYXUv4a1prNfsx2lU zG9N941jAf#C1(w#1Fn2;REckwR2O7t!w&afg24i6LS|VD^$uV>2>m}4;CH2i4@X5s zPK8Kp@xbMB{r(SYZygrp*8Pp6pro`QFqEJmC?GjB0y2W6luAh`4MR5w2nfPZ zA|NFp9nuXF0+JFkba!{hyN7d*`keRqUccYWHniinq*sO(E3%I(M0y4d>uS4bt_*go zZ(qx*bziVn9urpD`dR5n#)1M1kB(LO{nfcfI9wb8+fyyH#(ABre;}pzFF<%8Drpy@ zGWLL&y+Y{Q>|WF{;iuLYD8$)g*}yS-**tJb1R#fRe~wQ%@ankN4*KY_ngv`Wag%w| zX=B)A*=F~TrJv;T*q4=8fP*hBDi&{(74aX=gx?{=a@;GgcHT`|21kUO4}9mq`|s0+ zu|=*_>98&z4*Dsh5*i?<3py&R+8#{$^>%|sYkRe`9!|AD@=9KJ7a8{&ZA{duXlt+O zR)S`{(IAzCus3&qi%KS?Dx7Ao?l2fXZ)@guU+L{D-7hD_!rLsO_VKZjVcbi8P^npZ z$d!-;K%?&VMV--1ludH#LsYTn-szj4v^D3_FC-DYrD2R`&tZQNb+jPdQ|$o|Vn4OeGApF;Qj* zjj?7Pl=ac}6HIW!4G2hR74OtKEDLWM*DsN9mTk(T`={|8*JAmfvb3m&D_p*ak-T^f zMB9JjlC#NDl{_o8pa$XI6JulJNH;ZL>OiE_0}ho5+vCE-heVw{|6_w3oUe@9*{UFG zzHU0a>LI)u$zk>6?xTsR52=@>;WrtJcfZIieG9lX5;iiwhWb0}vT<;57|vr_&dH50 zzC-RSOL;p%RHUUn)@|`CH3pOJ2He>k~D}esltNRb^;>93=Vr3ITE~Plo9JS`1v<_c=kZ|%n zL9=HFm+bDN;MyF8gEtCTg|Fmd1atldtgsMxD6X#<9OK8pfa7o_q1#fLyNUEN+w-D@ zlKgH!>2oGeS>*kPj$IdeL7B%wp!ICb`!mI3>74%5q4s%@ut|}i)bsIiB%54taEg^O zpea5IYh3y3A+L=k;07&dUkOT5bY$+;wiUk$G9`9pD+?~WeFcVAXxN2MO-(%s-i0Kw z8|iV1^y@mx?qV^{85$b$|GL0hGsRlZ4%vFRI$H$98-s7)j158aomDjm}nEZ&5fD4zyK~)}I`~lh?Cz|Ya zof}t?j0c*srWg14`@4(TftCYOhsoh;v|)eQ?YeorqXwQkzc?;{c6d>x;KlIwC1@8T zLPMkbzkU*N>-()q3Er;nE#z4p|M2HO;r;#le=bKuEo05DMlFvX8`qyTDyYvf{v-y_ z0WKR@w_g{cU0nMA@ssB_PZkvIf0A7JCl30*9r2?u z#-gI4H-OT-(Wk87qpt0AOS9biRv-f5o1dQ#2kXnh$w|znQv=ah%J{paW4|3w_W zfa`qi&21Y3%bLSi=~-DM5LHGKlcoAG;c+rw`8OK}6K`6ve~I12C0+~|FjZC6NkG0W z)m;9mu5;~pZxweLnMVLDZ{pLtserF4R07;^_}WOh28|#T$_&kXbXU7-e)Y$rKbIbi zcSibQ7$d0Ms$ldHr;inO*^Bp1<}vM0X?|EyS=oE)_G8+nToc8#w>{~I;cLi#RtSj0 zz7tr#-$4u%UU*^BIMT%m*s%n-T8xy1j=3%5_6xWkz>DN7>>*U6V*t*k$|-a`w60U) zr~f75;2uBfu@H3CmEF-?hDl|Hwzk}02}gFFyM*^Oi$I^?ZLPfRn*D0_=Z45!EwAJP zak!*&WJzadr$e#DsDRBMl|c6bC*HP#foE%sNgEj$Fmm(qekhuYU{&Wdtp-OMI=DF` ztC*Xc7v;Gf?_ndxlmSmZgi)0~(q-b_PkQOC>-+OoV6qmt4&~MJwCzTJ-}yC}6kPIU zW<~~fLqmg7pUvt}v7(NS&Q=A`J`{kr&T1Sdo=CX5I#K8Cl`QQwv9K^%i`9%c*&U{& z^5g8{;}fN(ahqYP-%LIyyo$+r+;&5NsJ{PR0_&gCP{iStd`yATY3$&{DAJu2ofLMm zcfESSAc*QdLr@FehE`Zw9Zb-EtLv;TPZPwu7T1y;aaGDvwA5lXsB)+ov8uE6pbI&4 zmG|pZ?L+9^w8;%GP z-lq0^O3SxexaXZ%zUcpBJ_O>fZBcCG9V6`Rsa6W4XS`McH-W@gTf zJ<%98BArxGXAjb$s*DtVSf^yZTC)M4C#X3+o`#*%b92kCd8ns&_H8D6B=B2O;zw|H zosFHhXBV0;lgqZ!0Gs#g?-Q{3_Zft?+qsm?-n(bG*Lhv(wa5b-ShK?R&d_?iunWsp zmlVA5O}E;#7&=dRyy^jz3hzfm2hw}Oxo#`>24=u zA5*?l_Xqlf(hpnHKIGbOFUL<#PHupy^$llI@KsKe_wn@f{4qL8t(Nor`qtrzOF>s= zX6D99VV9JP+iEegwU7z0{gWS!Z+c+c%;&O9QzJ_x=glmfw{rU(%eFB&n`u`LN3B6M zz^^})Dqu;NSg@CplB(ZZ9hL}VR4!@W(e(EA?$(xq!6eMhS4meT0LkCzTR>#1`x^Ra zZ7Bb|giGx)A~+`_}xDymq3 zxmsB5s6Bu2I6WhSy;u8>odYxsR-KXoILz(kxDN1C zY{!6#--_3OOG?7~esJ)dk18tn62^Ia3s7HM7+5>44dc%(oIY;-^2frVbY&(yTc=i} zsJPe%)EMCSh^Ob~;+Jb$Od;*;>~!Zl<8&Pz4?fg&m)p#XhcUh!)_}p9?{!tW?62L4 z4MmM$Jsyeb0Yh)9k+HO~d8k?!uilm)hKxFZydr(Jpi|qqK!nTA~UN zO(!pJKiZnvLmGe|-f=%i*%23ek7>~1;=_mD?&El_`MP16LaS*e1MP8#6CH6jb*;{S z&nF%}zSJc}%A0a~PACge%mB>YdfhP@gdS>Qc|LH*ZT!%c9&hK=;T6F$aP~TE? z^rXDgE|RFbL@*%Sxx(Eoa}QO${>Ml*PPV%Y^*%-FxF5zNfg!Ya+#59P-MtBlgg$!O zpk7ZVOcUySkjHsEP_?L>gq+>>;rOwyv;NclUqT`uFBFaK#im&XS6IHMS;kRyw3M~@ zJTyK&ol4cV8&!9k^5HLL$X$lFQ zk`I7fusY=&9UZ}e!nTcT0Tg}C2E%*c&A2_zd>2m1BVS51`U!e)Y`Zp(Sthg!|7#cE z5fB*Ge?leaibC`{KEkJ)f|$7}X=w>S#K~)l8Wi^EvB#alNTBgfR_B2Ol2pyheX#!J z&fjG!s8OM|lV+{EFbP&1a1?Tp1LZb`H>jxI=_T*v1Lq*7aN_MS2JFyPSLzBZOHHd~ z<#X-6sDy~<@p;3yw&-~T?WrHIxi5zwQ_9%e+t*|PCQZ4;@5w_6tKO@OoSdMWiDzeL zf+8Z)VepBso;ziaoJ*5I%Qw^mWX)_ua1bUYl&@6a+@}2nMxq^Z3i3k8-rcO|W~t_`Cy%Vy@$@SjHhAl`ufQfxQMqR zT{^)X=!b3-n(~i z5@c_c?yBhMcqr6$1FB0y*saG?NCxQ5>Tm_ppJq?bb-CD}CKk>&3lr)*3GL0!3)=Oy zjy)3FkN-5$s8v_dEwf*JeuIJn8|*IN(T#0dNr$E6KXEoA#jQS=dbfGsfdUf8Z*$vh zsL1$e3IhuC^Krp zXtAdgw93x@yB2p&u^;Z&wg6ju7%00Xgcm6%EzfRP@38LldLy z_Z{z&l9G*`UIjl8AcT3x&&Rv40SEWCwhp*OQufD~cr0|cbFOLcD(>vUr`$>1U6`S{}}k)s4`Hf?SdlIY0JP7Fq|58myr#}-QeI2w3Zg8hI^F4w#`I1xq{3SRlVO z3Mw)sggjuB-kKZ;t?g)(0&W+7VTSAPU;G^&<{usDcaH|qxWWg_SZIHL{r3&b*5fU~ z)l5g{d@8CPTroJ9zkl*q{6?6Ot4(~tC)e(_)$JQPUxLY zgYUxa&0qNAH-=BoWfta7?T^OVbn;i1KDTR28@l)OZgACVd|GBa$q!kFuG(>9rqiW= zGz}p{D;yOXx6HSRH*1~WBBL6u+DLn)9Qb>PD4}^hfz=eGkuWftUg4~7)%nNU{S`=y z!)+~%jGcs2Q&Os!4S%mN+FwiX#|M9}dH)}`xcJBu`+xBf%H&|le)$I-LX8;&Ck$dQ zdTgHl1LvSVyjbPi|8G7*p$j;)Q7?qiW~|G9{P;l#YMaSx4m&J;QQ2dNp#9xgK?gS1 zlg(yS$U6xLBa^KWtcj_qP3?3HpxQEN-43~b3~GBPlY>QYfWgEcKV5TZXk)L1?5&Mb zfr=|)P|jwqjT$%VPb?KRhq(`4c(t;gVGnu%o#n0|gv6UhK#&>`nkr?xxwO0NY%=OT{?P z=g*&6Hir-hqQ!(X{*asrX5G!HZ*%`3IA{i5Km#RWVt_e>AMGp-I6DD8O#3Zw7FN~< zfFag|Oc)Io5KSU$g0RShLUzDA zy`Fd*pOu>{FGPg`JNDMcX@Qgev$*hQEWb^CAO%-F$m2->Z;+Xlm1GDD5g=vS7Na}* zk&w&yiEe^lxuysn^$^X+kJ@ZtczX;Yd*wadZH#}M5Ps^ujeP$n@ z%axt>*AmZlRNqLIcVbadl{+4prx9^=+^I&?jBAZ=1LNoestbKU38JKx($pdR+ZWvx)R&-S}30hfIE@Zr=T5UroA z^A(G!^!|=>GvDWy$F3|CBPpM7@!7Q0^z>wYvHs=}>?7=O@3=HECB@?bg7%7d_kG-# z9hrnzuYJ_s;J*vneeStBE`E;WgnRsY76uGy0LsTPU|0w-cq0H#^!6)&{ZjAj9np+< zYlxsRuWHR@@g~U=b}i#Q-RAadkLo$dk?d3EJM{O02qv)OwtYBhYusdT7&|MK=p!S|$6Q>j3BsdV7uipEPLKR{wri!0b8w(Y6=Fqc457`##CX7#-|#%`<_s_%a2c z3#*5^m$&|ySy*)DWkiTeg5Q?JVpxDH(ovcH~@O$mWkql4Z&O`;Cc+dmo}KeNw^WlHGs(K$8Iz8gPSl5<>32F@xQmox&!T~N?&C+}%uI9y5pv`JI^gy#BpnCvpu8BC z0Hb982vx_w_PW|Sm-gg^+THl_<25BPF(b~)KQ6|E^7L)b^GwET+#YVaML{=1B^!GO zHiEq3r*mJPv)P~gWR=i!NM2TYHu%1*KQ*I^d_@4T;i)yyLE!TET=*BY!AW}4gi+c zDG@mzua@fXANOlmu10Lf3JpTu8Cq0XZScfv^y=s3c`hvl`M)+?dY{(gT&;u^Q8pIMHO3BbA{QDB zbkMCpe)_kE2k_)rd%PPQbV6G#4E{e1L3OR}z!zQPa^H3mAd2wq4n8LP>~d`sz}hmu z{p~u0=+utWzLw8?sE>7?-?`{MS(hejKfhh(t-Ya8hBjy0&M*-6x(T>vw}8!N-rRuH zHhlz{?uIp|+2DI6)3o>q0>WIrqv348IgQNY-pWEXr^5q)h>VE&1PD#;vh=K2dIR6H;+LAYMh{)s%H536r^Q+z%ZdBw!Lz|9l4E1D^k_g z=ugrB2u2lpUaac5jN=-lbwuDFfurjTFvL!))80z-jdzADtdH}KhJZFa`M#X=bYVN* zr8m{e-)O;yd?{C-JUVQ{&jZS}SEF;HXJKRpiRwqa!93Ct};f@(01$EHjH_WB9yvynPLeVdIQMRs?wd+;;O zSgU)ij#Yb5%${u0cAbpOv)%db)0?J2+}(Y0$fvpOrXZvg?%1`rI$c`?w%)BENcr9J zN~PX+VBU2bEaWw}ftJ5BV|@tJ{MXl){CNnkWZjAV$9o2#M^i}eTe%qCTjB`|jxHuhn~hc!FGr58SFYE<&rkRLRI}84hAk>{Oy`5b!orF)CFW3WHWbiGr$pGF zewpB+od=nm>yVe+(AHUN-M(}sEt{cyeHbd9EKRTkjT$HrpDXRj0|xVx1vV>OMamg^ zx;)0nmX=vLxe0u)X}rgBc>Y{lZgqEV`=!4aOThu6mTK#;$18pr0JsZ#hwz<+Zou1V z;s8mKqLtgf`of_=-W?K%)^MFSW~Dp-{m8b@vy_|?z>)k40)4&xgK5xI6*#jAhft-I zJJ42bIH}JiTGx#_%M-Kps%`nH?U&M|#Bl=G3H+0^0!>U=MT&8|qa>q>?3T*{JG^~X zMFV^Uv((QLe&mh6wa^iC+!*0--pN$JqY;|Ntr^pd5}X&m$@{!~%HvIIYsM8(9esU$ zsK?ofrSmJveA8gWuc!lsdIJ>hDL`$W=hBm)97U9-vkFdd-TF>LomEqF_LvItFi{rd zc`T25);{nVw1k*Sp@R&bZiDZ&#H5?Yf(No6RcPGz3iOUK#T4}UoYsK^Ne77A+j4JRmjQ1ONsKnkX4EXS(Ko4e(Y zycuwaAm*bLJSa3cQNoXGREXD{GIF2}@D@Y0L|qm?`wk?WpUj&l=CYa6lktrn_$3UD zGQTM(=+3}HP*T;<#Bu4?zqtom94E&;0EK4BS~E$te)7t{p^;BM_h-2ETHoK%64VU@ zM(cfKq#vM?`nrmY?|Og^N1R8u<`yEOD}&tZ*G2|++ukkK`tG1i#gCDZ*s^AT0{o13Q7vYiiUZD5 zko$)U5D{5;*w(!H9`4{VX_J+mjRy?q`N{7T!v(^r^rLrdY|MNE^(sl_S5aYWweehg z^yoK6VUe+X{bmfG0NuE_Yt0fPmbk_UJjqCt=0V=yDsj z#;G_Epe&4gxGs4mH~Csh&C5jfI3D0eD@#jDBXu6{fqqQ#u}~rpchZ}`GjJ%o^rGV< zkN*Hu!0R55Yl|oi`2uvN@^^upK2r!r4i4UdvLHYVx4$;(KYCuUQis{B&BGg@mohYj zv&^K=!m?C9^mFsI;auQ;Qo?5z0Q0%?3n+*`Zp+eXi3ROgNXML)b3l+8@~@X?kP3X% zC}N7ty;pJJEdHPZ$B>7VH3N5WX>$`nBm6Oc;w@k$P*PIX2V7^Z2WwXkeEwWY!V&vn z^M~A#noyUL&%+Z&Z67xK<*#7wZBt zF8KrVp)i^||BMH0aDNveu#0GD^9l>MA5%b3ID5sIHXp!?WmjEoXIerB=3O?wk-wX( z++MX*@SjS`T3Wafn%MRDaoe(gNLo^o$n`p<@fz=jq`Z@x0`~Pg{iQV%99cq}BO0~t zZtJnXw9Z8e1r`609j^=(XEEnpY~w`0`MJGjMLNE-;|N@tHVc3l%7BIpax2@_Tdk}Q zH>;l&o6PX&C$|K9jF2@2E+&L_wa1nakla^LRW(gdPd^PJD>;Ym)m&K}SEzdR_4P-Z zt0E-zai!<03uV~%?&Y2F+P`}&v~OY(mhh{PL=3J%=*8eT;fbl2-_;o>_-^YWS|%Op z%TOlScl;J`9qbp76Me@FTBhXyPj>GRL?Z7G*JVkGPG^|R^UD^3&y1wXrV+aS3k%iz zAH_uy+7|9&zQ<{CY~wt?kydSJlCxj!!3Sa1giU zoQ1Nr;)JAj3`syUUyX#HlMR0QT|NNTB|rOZ@ln7t9u@ChvLi{gT+L`t(?^&n1qM*w z;L&NYZ~S_Cdb(U=LH2@N2`(v;5Zo`b;?Bpz^Ky4vs#}qi;G15O=yBmQ-5;N75{B-X zKDsF*;E;O@I3is9AQ$7HZKIB2EL>mE1lyU776d5^d#70fXAU>`t)I!%S7GXzPJoPt zkLWLXz1YGaLMzUX-lyoy$ z&~vt7u<)LL$O1yp*KYsF2$|eyO6!vS9Ilcw*LCdu6kPHHH+JxiLn@K$)%)77M3<9;5egWRc{M}uVkE4R=3yo6 zH|_H_olflDRFLs-mW6Zc9jy8f7!8Jb&;Sjryz2z^V$4%abWHsA#_C^D2P){iQs4pj zFd#&RgSgBO)VFKyA6u7elHxpEmwO|EitD;~uw+}%mOVk+I0u)!1i)HVeD>^+Y8;R~ zXu)PvH>e{*B|rkcq?DJlfFsK{2NqCarth_7hmQSG5GhNh*a9etnVp>oay@WjVa`YN z+H|w1BH^uDr?{wz@;d_ng#PlU@^XIked2#48ifUuazX=q1cF7+9G{k$J&U@pFBQe1 zD-M>};0C7wfMfut2_JOJBmm2buX8+vOhP(jfxBpdjYp534S0soAFHPbcVkzeDs=&k zMR%mks(YKWr}$XI#l;0#xCJ27Zqs*np;H@^4f!tBCO8)vtL0*+6mldn`8@8JQlZYXDip0h`~)`}y_nl3%0}sYu)gVqG;_?m*r~xVe8rGHIo2SfbqhE9- zfcNgYatNPl#NL+qMMk*Dd7zNEg>o>XObG-?GM`7UFe$pbyEmh2&Os!B_>E;pqcjLg zRrI5OWzDMso?2bEoxi;>=Wje77lp@PSRS+}&X+P!yQTLNSO6Q{*=l3=%gki4dHgGF zg$jekCeeWey#_IkA1F*?5;{NGMoE$v10lqY-(}AXmAZRcVQak5n-(1X`PZeWaeUf9 zjYEtr5*HMw;pjIbt^sqHn4f>2n~%@WxHr}A4l64cQ_EWrWZ1doX*_=}uB@yKC=FO7 zO!9c3S0z6BRXmPgfE=CaMSAK#Q!M{4KgxXvAiqnfA^(ypRL9Z(is=1i z6!i7${;$v5YN&@5F`AShL6>ZkUXgs3F(!_~28Vje=bYMCSzi4-PntHrF17Eiewh%& z9N^+V6HFK|1Re;6f1@ub>L>&HWs<*{z!%REgU__Q{)*x9>!B#}AoSn2`YTuECH%*) zP&AW^3m1+>wuKC}kN`)ThK|hYqn&@R$W@kc%3iJ@ujT9I7CxIBE^(XS6&o%oUl%;C zF?{wRa5^g0`0VhXzQ!oO2Ut@AG*#7?H+(gb!PS*70!*bFpdw!5jE;DIFDGP1Mz5DE zG3LsSXeD}m8y&?-LSJ61QE%-Bhupyi92R#o;#)k+A;UJ*kU-Z7K$OdpZiy*fjlqchKU;lVN)o;UAF~7-KeQ-&N`Cf_8~Sk>K@d zsw`16vNqGD$6$Makd~I6Nj}zbR!Yy#8FL$>7xW7&(3 z{9hqWkuygFIulLbF@h!f`}a4CO+B5jmTR&tn-7cr%7>xKhd~#n^p`7=yF+&mjh=@} zZq;#OMZI=LtBC*nxRE~Tc$?N7LJsJ+vmig1H(CZdNtd$;xPul^Pnl?iooDzy0Mv+r z0?NX+_W24)&4$l|OLN z(@zF1*8#1RgXz9P`^UB^;J`r076~yaRP(l_?k(x}M&*O%gR9mL@HkA7wo+!A5Q3~!d1FakX!o_m0N9ENOmDf-eSIyh9mc}Xzy3%zkhO80XqN-{F;1IPK6|K~Rn+dDEY*LA zp=`lvz)@-j((u{KSMp4V@UKdmnz7tGJcqk>>tn+HJ>EJPvSPw$x}XrOQk~uEK>Mx4 z*_afmFx+4}gSymWH0=HR_xPo&*5xxm8Z$dSIUj5!Ha0fi(8OeBX8s}HSS03>mmw}$ z2N?&IMOctT<$meQu!?;B@Zye50-7C{Wo41hcplOBCapq*K%~OLl8S3;PFHoqBFV{p z_x+u32-v0{xQeVs>k7x34*XFR7UH8Dwn{#0->~r4T>r)p)NW`mm{oD0u*g_o+x2v~|lde|S2x38Eo@ zco+Gypa^(>rpfaGU< z3~6kXw5l9ka+a2pivW%Qina4KFDpGAbeLg4qF&hjbPBvMIeX1PIuD%|P4XG=$ z3;P<%#>y%`4AD`KJnz@_TOIBYogD~tq63=<1HaI~&=0vN)#rUScDgy;>~89PRM|G$ zlY1@W&z%HsWE{41v<`3%`e5G5j@M>c4<4G4o7>OpC+v2la@u$BVn0ouv*+jum3ZaM z2_eU&U9{I4msj`_z zs5t-(I-j&j)Z?tGUrJk>#*^VjsXQ^X=UX$(Bxc%Sz0+-3Za+)yWt5JKZ#%jt!xA|5 zMI|S%u`!*aoW0N62VRD=VS@DO`$N(|wQ1PuyxI1sbT1IJ8h)$i18(SS~GOt`ycT(dNRXxShx>dtH;{KkeM&M zOF{uDTVxIyPqYoX$AMZuT%|;4}JDusw zRtxlKHlTlF{dd4bbT?H7{MQYyDfzUbl9HohusM$GOVjEZ6%s^tw?W2BQNcHw&oX{b z_AV=H;fOrQ>lWKrX|sDWL=}N`a1L5`HB29$I|v96v8-NnU+N=8UusLakRsIn&#rXd z%^W`hbr5+vd9ip8u-DSmH$bJdyWd(sIB*Q z^rulsdiQ|K1AiXo^ru^+a>L_%)gR43#6NZ{QtPU15ragxHeA!Z-EexcImWo(>D0+( z*a`8St(vEQLnw~r!+>wi+RK-jd}}gYK#-l;q6$doE}4a*x;hg$?fH^(VWv6&cy$-n zfqPGwz#OH>K_5#{N>@4)cf3y0RV=mXy1hJgxXb>H!GpYO-JKzx)>T0$;jqY2{%3&U z?gyvmib}dC?oD``RVPV~?t3JgC#QKbUiaZUZ_5*|-T6NCthN*K zn5=Y6qppziTj8P7W|hr$|Ka(p!c?fo+j)XolCEG6=6Iy`^)AoTDGH&o4jkCCXU|N` zSy)&Kl%Y>H*K5z+UFV@K_e4c?Ha={Fu%+%*BY0gb##8_aW5??Q>3w;Ac3J?=w2lVe z7f9hW^g}>*Ii*eM&Uj&zcq}LYC&TJmNW$a*Nb)lvr^jvW(OjSr{XM8U zzsH%-+~rPM)t9rNiiU8-0A$h4)u0tt4C7z;-ABsUI%tl!+Pv|a$*zB!u-TvXvibyX zJe+tBCncT=oto+_fa`jJ_LXR}Z5u6`&gszNN3(yONmk z9Y=vM$^wZ5$4Oj^aNW3z9LWcVIE0RjX!cHrL`VCVR>ja@&TxWEB6cw^IepKKsRto& zXL;xyaG0kHs4pfO?}^pS*Sq45xuId<`PC~*?KPo_lG0=iBvyy%Iw3v1z(;P`HzczjWx+`-&d*@H?d~3o!d2HHRQl-8=qFl28B7`yI5GKm1d6Y$06QkHSCJiu)cdBh`VW+usZcXz`gBMqNHWn^XFF!$(*Ub%9` zcm8hBrc+lSp7QhO0Va0@K1hGB%eL*y)e00e>^^ppvuYAb;~}X6*A; zT>wL-e|iIT_vZPQ!w)T#XQAl%!W(sIi!QUX};n~d+a_N z@qp7v5l^pz4s$=30Qj{1Sr`?f|9xV^Z7pbT>rnE2FM`_|y-*s41b4>8j08F#?HE^G z7yaZ$K*1@w3pyC@KjBDxAr7TwhInSFH*R~cA2LM=*^P=!ViAWlqlaRjQ-hv#GvCj& z-sNbxcIkK5?^nZBw6x5hM$)liIx}!SErTbno<@axoM0BnCy2P+#fAZL#7+i*N;QRu zYgrfn1GNpSX>d+Q_LFDNjF%{Fm;2?uJ^k|H!517D)S+5gax-sHpsE*m>Ssz+y%BtQjQdy?7p8NA@0rLaUYv@Ug9Ar?;LjhS zACV{s(T`R-5ICNLT1~Ee!8wsI6D#w?A@^p09dc=EF%e~(FY~4-XT7eT0~ zVvuwBd#aq2)8cF-=7SOV3&;pNglK-gAzpY9feWj4ewfZ;Ffr%$v2Y|1M`j4)*K*+dLhC zZyI^It`3;lZ_P*-AL1rVR*LQGC@OwBisv!?0Kb&-*G^qzc{qlk)u ztr8&=FU=kro^Owf9{W4qmb11P>5RiJf~OpImNtfupYPol7jNV`cHcaiwydZQo{HeR zdD)5E-*D7VRnyWnRs(<^9D_2SPV{f#^BCY~3HzWSbFV=R@a9VES1^ zB*E4ccdNQu5N<-C+t$2{W-MOpCq@!jPn4^x{8O5~@8BjPN2hj7=Msi$s0yGnzKS~3 z62le+=ju3U;p69phh!3JT*AiQ(!pKLM`Q?Tu|YCeZmw4;-=(MTpas0i_bN*0>7@kTAVM+%wW~^et&z$tJ9M%^ zUvBn`g%+nCYiORwxlzK}>ce+O>3c7}zBW>yok-fflz!etZ0ak(hV?&r7g0!7+VcsF z-uiBzut^IM%hTItr)st;!X^=CD6-@3)iwDzf#|mn>fXRbLg)w)H9HSC?H49ovI#o+ z?w@TjHE!rYozu6*!TH0YV=0mla-sU}gtHfGu@0+!_sQ6|M4PX-*^TsP?V;1jr`us$ z2MTW%&*)`;P5j27LX0!Pg&~RmbN%%tblGp|+1V=h=Q`s|pF=4H?ajiQ!7*dJ&z!JS zBV7r3=2&F#}i1nu1UvMnfDVYaAddUpHDdHNE;F^%g(%( zkzUf~cA`l?NbUr&R=p}ev|4`5rb}4vRNgOB?ZbTdu@6Jw<6sX9y29J8qq%_0#rReBr13|)%)pHwrchV@Yl8KUNhrka7Fdu;UuSMbn*kDQC+ z^dX=xq*PQq|G=)p2J(@#yvG0_ISUC7Pd);Lv?cyGNM(U9flWMV)bH2cd_2Qs8=J46 zg9H1hb1GhS=R5Rv*_&kZ;OKYZ5gGa`gQK_KfX<}QVzxwQxlcz_{MIQqvOrVT{>EiOhyyEQQgKyTzE3he=|{_3G+yOYn6U?nxp<2F z%Jlby3JMA~Dt#}t+_7i{8qOMM+-JyCa8;+R$a zNYG826!A98Cwa%#O{c%l;8{8`4IAjOX7(1;y`z!OOlSjwb2^LLRXO~BJI!D;5QBM& z0e-T1vyYfhdWOT`GhBeXOKOIPi;cZmYH4P~-PlCc56<$787zwMEk&Nk^!2IW+^)NX zGJ!k6wUaj6n`*f~^40PR6rj(G2*)uK;P1or*~r|r&klo|Zp?R;U{9t4TCs^1CD$ui zvE#<=uRu@#P=5y!bKgO<_t|p1#(iHyO|4%ug1%5pmd6w8Ib2?vXq#i0(#Mv0lYyOdamCiIBvbD7}atFdsVBjI)4ip9F&oj`W z*muuS*YlcFIUA-QQu+ju>Yi7?fmEb_S05_Zhur6DL37!Ebua?@LTXx!am!%uk0QZW zv|vVnTdeFR8#gpM#U)!3aGi)~$qO>_9pDPrOfhEmKYjln)Vpz9(mib0@YYp~Pv?=2+`Z2SxV*1_WWyNH-%eQJKQVE9f1yFU{*_raUwg!8`V zRhAyTH_|q(V+aw%BqTp8xb+&}zTU?jdge8a&ebDQOiTtGZImOoY0e&uqD)O3X zBRGxDoAbZBuM)0MuI4bf3Mn~lUp>(cVdtV*cRsU$Ph$CIFv66WKqEHU=5$4w{&dkWbcih8@&8 zPo99&k8Vc;n2ugvRW(9kHB})Y*Se*pG#~&+!X33;f1)b*mmpT6;*z})mF-im z_-s#^l)lOBf(*H9Z3-O@?2Lq#HZ_w}RpmhKdrB@F^2gd&Pg&9JM7Sg~L>PFr#D`Vd zrd`&_uw_?R;9Hvq_-h7>J)bkToH^#i{v);perqDU@qs;><)gP%B1iJQ1>J4QO)`(D zDA21`Jpjt>cwAz;)Q26j#Rxj2P}P5NlDjP%^*R$x&SD4@+2y)azDlV)=2x1M=JOsEzFQp*v*D*!MTH`AgcR193_qx zk)T(>9gxaDB}M=y&RJ!3nEQu&8n=CXe9B;Q-|R#%k=fyd?5eb&eC5ORMI#LDEx zq^vjIMk5LTy^=*F`x9vlLR@CZA!Z`n_QbJ-{_OlLZ#Q#xa4?Qg0^5hJr7q|bPO5GY zDBHkoh5UQ2=}8gL7JLrw8r)7KcUDi~4-uoUz9S%M%v0{q&cxKb&T?GUi~6@WdFQS9jZA{8s-#K~;)-*K3)xhIz&*DKYg zBaCQmv!55sm=goYo}+qk4P?iBZ#XI&aWyMLlm2pbh0FS!+xf;hnvR-~C*+6{OI&Rb zPCvkboj(Mq`}0V}OEB7HNV;nw$Rf;PV5oR)-a>>$684(N1Fn^tli120P=0`mC}%cO zq7L;+_td|P#)zrYMBwFRA_%yJpROZ7Jao-w1beb&dAAkN{8g^>4qMH&Qvfaf{^aB& z^_%Ft4ZKajKcG01!1WamO{T6Av;dG&s1gqC!)BKHela~c z4(tu^0&$&u4~mQVKj;HxnBfXCs;gcQO>AxA7f%^bd^cPE|108ThFFDA)7|7&5#cHs zDKhJW+F}f0-tzbNms7*!AVQBh>eJY)v|R*|sh6}3VJ9XI40lc=_;3oh>8a>J{CRzM zW<(t;WOY{m06l(zEx0sTh8f z49fPe$U=Lrv#+AgFBJ(I2STYj48#J=4mij3g%G0fWSVo#)$r z8z3nxsnh&rFXHaryQk_#N=Eh^;jr+79tXzzL@Q2@@G_fDr{&(j18=?eVj=Nkq4h+G za0B$9phMpSSn#XE{P<$!LpJS^W)O@Mo@S$W3oQH(&h^(BZEUD|FA6If!en(MDVq#l z0lQ$M+}zbw2!lc5`14~+jdJgLqAMizhhmdPXF|*Obq+khw4Bt`))PraPFzRqt)#*Y zBu_OHz*ackJNrMZy>(QS>l!yKprjI#!VpRcil}s>AdPgF0!j)4NH>C@(ukCRNVjx{ z2!cv?NFyLAF?4*_xc5G1pZA>oy=#5z^ABAMnVDyv=f1D|ieJdxzyJJ!Y4&IvY&dJu z&@13i%#MH(MD#&Z4^T%iSrDMqv(N4IDUe9($>p81Daf-`*tf`GsvZt-6X}E9bxuI= zKU>6zkh&`&p@P?@++haeYcEJ6p=&GW>MF2CTJ`j2WS0Z*GBjbvP4a0U^4j|VbL!We zUIf?{S!laSpk&%y+AGQ}>o30Oo8wp`$Aa&yK@&+* z940d&<@PJVdN||q-7bJ;c2A*T>jSdT!2*Na8QbrbJ?iv8gD+O$?-fV-tprw~k5=`I zcf~qD<&YdY2M#KPorO^_yj?D(FbWbr-ahk;?1P7^k)ytgOIGcs zT*P$c>3(t&Stv{h5-O3GyNDagd0XxChKG^S>))&JAW$bF#Js+LkeV`cz4=e~r(l|P z?%OOYB;}zLWT~FYB^G@wpXf)Fl7xR+=~*w{qrrma@9@g#MHiu}6az=cGC^$H+nEpU zjw0R?k%ej&z|A71=lgtcv~U#x8=s`^7VUuJ#3W5a-SCmEZqh`RLuN_`lodzWweJVF zWTRL{SP)O3-(ob~_F6o(CD;e^qwEiGw`zJv777L6qaaVHpP_fbL!Me(+?$4+6NCMo zwe+ZcQac52AXY!}+19eDmskB)Zz#IUJFY>dur>AU1vcB%h#AgZ$=e8rg+zl3t>}!a zx!GTZ{|Y?8nctDvVZr{`g`%gpt8RA(onuLATs0^*l~w+yJF|bRicHGbf3TZmPTziY z1IKp1^af(&8zg0HvEk)7=;W%kTsLh0c%9nB^T^=$T6qM5@it>j!5t^h-!3mLDZI_p znbwVpj5Idxt8<-R1V}etEK*%pHz$lG-4)eq zc+&AstD|3FHa!PHe@S1ttd&-Pzv2F4Gqc?9FkZA4pko(?+Z|KynfjVaS)I&;e;(aL z-K}wYG#m>}XgGeLwIXqpnMD0S0O|uA^?GvhacDaq!Xc_ECX{hMky`y9BJ31ndaA-V zDRi}tx8>F&nl)1AUNLcA@{i017doz;dipRcBn>4gs(5g=meY9w6J=QB3Cm@i9K?$bT)$vb_ zCjLu_@9jb}T)A24SDz&T7M$v&?PS;_Oy!RQ7ZWcawPLcE;@UN}Rza`Q3j`1#YDq}) zMNiZ+6jZF#6cmD=Y;0|A9(|W7jDuSG@&q7TbYBNP?ubv{Y-I7ib`0}KgBCz|7Ax|D zl8IWQe=5K#9EDBsGq2fT=3ddYvAL0kg9WAWy8HB15fOtHba|Xj#oq;eM}ZrNfWW}i zrtmlVZ@WHTSZ2!Men`vJ+$v(stSKdh9gup)u1iGZyfGjM&qsdvpl8+59#?mMQsmUb z*Z=u*<==ZDdhRew^y0-U94+xee0N&p6hrJGcQ%39&XSq5v9WRY+&=_Tl#aj~|J0+{ zPILNxCMKpVv0_e;zy9M$A(nwe^tf|b%N7V^oN4dhFJu+`flDuq&t76$MhyenTrYhc=#sx^St|xi`^gX+o6e0GXv5$87;hQY;634rqR-h9v-#& zb#4R13otR;>*SqYMAKVhk!OLOP%z5G%9=nO`1PwCIU^+8h3wY>y_v!1{kf$jn?II* zuQP-^^rqHP#QJNb=}CQKS=m!jKy%%0zLS0f^3z{}+3X3Iu5xhj(Bizu2}o@$vNd{s zhj6%tPa-mkF`C<_>nft``SpA@h+nC*3e#7wEo0?`#m6K1?5Z6JVk#!sd7E9AvN6!7 z&&p(jkx1q_`TyNI!J(Q+zt-8sO_Y{abMjp}1gtXW^{rQ$v32@r6pjP`N>&!PlB0-? za=p*sVppqPoKfSq4}+ppQIxFbFO2Mhe8xwQW{{B!O4-km~^W{o!?K}|LYqs zIRw993wm&K&7V=9wYh}7?VZTy@mgfseAvas_9PQi(=@=Fe0Zjzf5Y4Ec9yZ@1$nxEAxhwR5>EER$thAKg#B`>Gabs6#h1{n$y!2 znQOJT8f?8wT6iz7j@20Pv$GBEA1_hPD9Tx*T!m~Wgv&%7S4RiR_n_gZwsH9a#5BS# zwv0L4HnMr<==t1_fa;UCu_;jUYlot&TgrFG311p5rIdy2&(-1_z!vY{aI34ZBEUQA z7h|ahSW-7bg(P8}mXFW7p(S86e~vdg_d*&2XIG}&L;jdIjR=j6%jKoroiQhu&DmTD z&r@~V2Rwt$m!)rKEz;l4X4BapqQi_(vWfW09U&gu#IBD#%cfmPA|xeWyw{>GxuO_~2alI#qO@-EOsYKRrq-j>0~H}-IOLlBWJfA}s0 zb9ManGd*C4Fd0_>z72_xF;$(VT(0wDBcE%P;}i3y(|lkY22ey*wef2sH17)noxm!$2Yf zWp)HkQjsYrw`6hmn$`ehi?KYhiNrri9AEm(?LbSMUmkcQS9y5IO?;Nv_gD*F1=EWe zYPe!Nfaxv;?^@s&;MT?mPi%Gm{l(A9c+&I9J>-YG>#h2Y>*TQc zDfMymvG9n90?#}X@b&2TIL9C)H1@k8?*|+v#)9`LDR+Qt$N=ND$nbCmJ3G5GyEtCS zQ9x9-aD|fo`09u_D0kjl4^b0BXLFcm15*9{Wn8y9jGMJq#$qlzj}IvJ_6f;_(M?~Z zq-60tkQASbsB$2k8!f|7EEjUUJ?1D-iE&h004?nA$yshMyPo~iSYP31w2uQ<$F{%d z6J`F*x_E74ot{lNJ*1kc(Suc+_R*2NNJ_Q{<>iQ?W9AT__jzip z<`Hx~$Vv$0BW^~cu_dcZG?--mI5jZQ_s1_qp4GXdAyI_O`-X0<-WuOTqFq}_G&9yTW=kn6Cnv2nKP5b$YzOWMB;5a$Uh03j z2`A;k`dcP?^U0*92ohJY$Vmf;&Y$6`m%6Ekk*0;qI_u8Strk|X%M+E__|i{Q0OxEk z!{6JUz*m^PbR`REBJZJY4&$`*Go#o!Q<73r@n5lw+o45qv`RyBpt5oH)+$A)G7sBS z6N&hvETEx)4tgu3hDn+AZ0-79=<-^p{(lYPQc-X?q z!^$vIbqmLAP}WoI-Nl4^7^GH+&g3SQ#^mLM0##t(lkT0cAyPIO4piP%mry*A)guk9 zoe1BZ*B5KJm#k&P0q#-N2>mlTx7qi}-^o3?`A><}8ts+2YriY7odwG3{n`ONkD?dA zytI15H@P}ogq1L?E9CrV&5HY->wpBh4cI!^EER9RK{w+E zcB~%aAvvxc(-IGXkxu@g$DMp!#V9z^s<#q(ps|(Gtnc zc8SQdH=pAW(Q)gI;0_V4J|PKhgwp*7Xc2iOI)l^c(@hreGf-Ecz{A4ac z&9g%ms_T32)l128`S60I*h{coDIK|$flOoLTxS_7xNwtWzxHtL!AJ=! zsYbx}m}dmyD7hnq<=yT8Vyb^wU@uIj6c>lJ(VQH>aJ~WhiY%m*6X(Me1_v6Fwlzd_Wp zmChNo&=fV}ip=(3y3m&vG7}O;+7&qTav}B9-O3P9Hx-ga4JSIn4F>@(^}Dni9tUa_ z^w zL--l~jjWgca#F=$w_SC5a=4*sZ(*y3lC$Rb&$p6zCjD?vgBE&FlfP6&4vmw z$UOKY2*^8!%aSQe1oQrH`Ry==_Ykz<5@`5uNvN906g)qOxWS{;kWsY)8sm#U%`y8 zu=pp&=idCaM|WQa$??t|Yz=y8pQz@>cZ z>V)xjk+ZF*=lCU!o95iq8^>WPE6oXeQmH*d^?wpX&@^n!vn<0zxS{WcmRs~pSv)^b z+UjOEUqACUD(YFP%b|9yon<8S^?S#&>>W|kEWB>8R7wv$9UW0or=K@?Bi{R^f`s>X zQH4HkDV%d%*yd%r8?azU!1J+nYz06QU5#H6KiXQhrHr7<4Gj6 zR38+q{=6}Nl9P@>`fn!C6(GseD=XKXof6-^RewZyrc?H#%I9w}@^Qn9<28YoWgp|i ztuenzHJ8Lg7lsx?j=gYGOzgCWivhdp+O=ybnz_-A|KplVM$R95i3LlgE)y+s-nh~9 z^QT4n<1^@+elLHJZ~FK!Fm7tG<<;Ri5hLVNBr@E65GaVRA7ecQo9x}2ihawwUe3;Z z*Eu-@-RcZe{{2ipk^pPV3!DSu!a6%J-dQd%>FJFtSd)pk{7M`lb4b+=-oM?D-r3ca zxmSR}#l^MpylAQ5Pkb|)#(%~aZ|ApRz~@<`+eJMId<}uR9r`c3*LNKnAm3wo%tij^ zZ9?mOU;z0G2d%e#ox?MsX55_rsK*+=xS}FvpO)NK$g*PWF&FLs`gLLN6EzmzgJ08y z$X%O0Yy6u+LNvYH7h+;!PA?G#{=sXP9^{Ys z?*HlX@S7C(clGx_b`V$=U_V1HC+F5Sv_8gqJ>IY~?koM)j;e8E_baO2K*OTS0^voccaSL-*HzcwzqcSblV$q?aj z{MW7cy{g~~h<|*w5FtsHnC!^+FZL?3iAdK4wv z+S)2IGCemZi9Cyxz{W0?iTv7d?Cf>&y7i(+WY^)ckVL$cYW8c^e=CKcnTep`t(hw_ z2J&ghW6QF~*Et(rNfUYNOG?W^(D?XZ%ZbT$QgRa|Pe=PV7@E5DI)I z{1WOADFr1Z={m!(?Ck8=w{P2x?t&O}7$ikhw6q}+5fL6Sp!eQZe7%>uW0w?xp^x)X zW$my+W^f3UuxzTr0<~}VXgYSP;v>miAVP1q9 z@BHhz13gkZ&ZsA1~7X@SVcxw9rHm}9j%yBEiGSpkzIQv5s~^z;0uBK^a~aqT47YhwgeudWeR zIE|0nj*o}zl=q`lIUSu_r(K7V@&?9Ac9iE=E@4J_o$jf}u9%6Lt#cKAPndKo{m_%6 zk;??~&2tBkUWQg@zO{e3!v#E?4<@B^MB1F`%zQFWP`SO@r!N$2Mp*kYf=anp!w*KC z)9jl_Z$E9LPtz*=d6Ara=yKP`<&X$Nk+6vO?~P>c?Q3S|x=O@Ti^j0!&xpMmoEPcs z{}rdMVH0&Ll{4n;+m?%@Q6mr6o61wum6D^<)Arop_xl>W#{^d1Jg+8t)Z4sZIv3W6>_vudck*^8$*mTKo*a6gWNQ~Tj5>KY?3Zb`(p>|M z$G}x#;hrAjL>E78EhDzUT+WKs!h^jff}#mm`Mgt6=0UL&mchKZivuFeGg#72_sg|& zwW=Hr5c&6qU4)GlA(L0Zfsz1su8rPp;nY8 zpvg9pQ-JZ(H@a4YLvZR2=)O(vT*5`%QC0nF>d}J5-Zm}gFdGw@P@`{M6SXWtu*qkE zV$l?3qYGQjxo>U#1|H&iR%+8t_75f(^S;o3xD)V7opwm-{As47H0!O8jdJ10Ma_cx~DhE0ig1)W54ygXl6V`*1920BU1-%a@b3t1M>&fBD zY3HnU6Ly2TVo3TA+S@I3>3O2cb7k)pxU+E{Dh+oU?|o>H?l(A#kBBBSV!hx<|D3{$ zy`F86?f@k;?!k#E{m_hvT^)mlgW+LjCXSZLS2B^|Uq>aDsu71?Yt<6Dk5)Ln?Hjx; zWcPMXhs5p@#p*i-Xs_3j>(UPykb2OUn33=wly@XFIb$ygX=+osO=VRHl!|r=M*Sc5 zvfzsx9!3`w78V1Qm-)j~@M)2OdcJa3jWh~z2q@}MaQEDR8ofJKJ~KL zpxgT3leA?zH&pydVw9VDn1#iK$k*!E@$jCdONX)l96yxgQM@`uP5xdrCA+PXfCHIk zVY#P(PvFgzojq`oUQF58*iBwvzdkMPwXDsWy`vP40U%oLDT}-&GjjLGk_HCu^5D`( z|7$mdo?g9j<9^=mgk3?@v2h61T7BSb=wYX<$O+x@QZqG|uJFBQqb#4>_k817o__F= z?oMHAF&Q%!*_WKs9Wq)@_L#fGuUwm*ZOqCNlo-c0m=$51C@P&7NO!*02B~rtgY>wL z|L}TIPEPZUHcFt}Zk%r;wX)9EmXFEe65JczWH?=aca2j_7gKs^q<_n+BC~?FyfI?D zuu$9GIk&nxw~%bPne+(bimh(^@QWA5yFWQJWnXAtd-Do)BG6EOwRMO9^G1`v#lfk|}E7kSzfLa+tq$iGiureHxXt7MCB z>3P3%=8T$M0UxgDJz0$(eYzavzxE3pB?6D`=&AAl(oZeP%J)*t9q28UIA={*rWs&U z%BCo%IoKZb`>`ppsZJM21eUwek^Vw_m9r(v!71d^M3E>PPUz+X0rurdiJ-<9nQv-V zRwG70b@jU8Zh}#ut>4!jN|bK0cMc|RpkeM^KAfGO%Ss~5d&gFm+bDKqZ#VIGH}cKy zXKc?gNIm5uXxmTgZad~^AMPwJ+t%Nzq%$^Fr^nFA)wFb6eQkPd<`@Y0!gY9GG&DLZ zc~;9P%XziiN~3WpFad@7T3OsZ8OUcyYSlKiUNF58=YWI7Z zq?RbjNH1O_{N@Fu{4u5Drda?F_lx0_f?GozVD1&(@~c2gn2|0lu#rUY_4KEcoB;mK z&B4l?TlUTSp{OXmomWq!Yu1=Ar^pcG_7Bx(-o1+9U9VR`a{I~4t%clN!<(Z*HwqZK zO)r;8ck^uGSa(|nQ@c+0I8tK!rpC*1z8az-eM(g4o=kj|KYajst>RQQzu?KCem?`! z^edfuRtBbkyX%%?k%jG1It~_?1NoiNTPLD7!{KyXn=spf<*GT22V6uJ0 zQ8;;5XjIkI;gE&L-HEDk%G$zZd+y3OV!Ul4JNX zKCzEcHJ}|me0ManaJi0XDY3ZZ;OyilCGYn`v0MrNE4T=^CyD40>}4Ul>{@AALAy7c z^gjO`7Nw-?fK&mBb1Dl-Kq(+4BS#sTz@<%1EgTr=pUkt|joxBJ*SR&eGUWBuxd*6- zo!h4=(|v}0EZiu`q?Zts)+G1h#V5s`3;ZHx5KL>bQ!-Y~F|zPx=>@9Sni!D%HM=it zxxQE* z1`pVobqeiH2dAuRQO_M#LkqV*M9U&`JoL>mqArOcy_1$~+CSYs8~XghKr$+cV@<*% zF3v4zJ$f~zj%eZSYC)i%N8RTx*nWR2^_q*-*do#~sv{ZW;S;yiS1~Xvw2E zFf{b)$=KP@D^!>`3UV(y)~XBUFG$n!thT0ww$4W9e0?&Smg4XKF*JF3()-2WVWVG3 zaMyd6b{<`ks9&l-{99WDQhtsHRT0$Tcn8TJSKZ+^kJG%yH{|giT&{`7pGqv&Wp%I5 zhFL^Chrst%tin8{{&Ze({?O1a&ajKAcDwsoC$(+uW4g7Yb-QG?Qp%&2{5wS=~7ria3_!uKfnvVD99mSentK$=AcvOx%I-@0S_J;`rx()XW zHMrYWJook_O6Ux|2Xq#`ej7;s&qs`luxkryZ;ZJ8H0$suHjEunfze;TeS6dvemOER zkpo;pFM`+#Xdca=+>X^=d59)MCUJ-*2YCM&$R^IMJcJz(84&@d+Qyf;99~jPwY9}s zt6RzR*wQ+p18H`J-%*IJ?eRg!mba#^{WIPG)?0SwGKXcn>-PP5S0_g|&`TdYbX%lE zvVO(HEBsiQ<;9eapyO8^%pX`z7R_8Ou`1}z_@ym@9augYlPqL4QIhVt{;o{Jd*Tg6 ziEhJDKuKo@Up!9e4gRh)9P$(VAIA*Hr$1W`UUT-n05~mmogT(yAkG@!@^oCLL4DMJ zK6CULG^Yin-eBFG_~+>3)8S(Z4Zb=-S|Hn80$ba(7 z)=!?(Rtg&*c;R>a|ic8atf#Z7pQ=`8n1<08&2uW@u%+t%9{%GXJ| zxpb{~R`y>-l$PXA$g%&|=T{@tdj@ZF#n zU-~U6=WN$poF5YNf9*7UaHK%`S!^jwLu(7ZN9aXZcm?}Twz>?hYTQ@nL~1Wxa$CKy zJhm$k!!h87o8UZgn+TD3tLrF^u5wamIeHZ~9jZU7vs!PR%e$ekciTa)<}+-%Ra@M@ zH<{qR>%^{`P2tKYDh~LG0yEHRR}?^kc_&gW7?CPl5zcc&TPD9?WT7FDJjZ9Xj!3TcbZa+^*@?r zXicN~24BVppzRd;uFE1bad1K;%R)+bDyyJJbingarLW9TqyD?9u`HqO4Kn-o10ajFM?@-`>;pkqEF2&7f}5P*70HFNo*wpGF6r*NGyNl@tCOVf>Z@1GPO7n9>UT)u_j2wwINrdPd-c951sP z-4&p0A97Q^ll5VM?*gJD!OC#!B)?O)(3%x#O5Hu;mTbpiYnkI^vpjh5zp`5!5`N6b z?XlCi2jK2hIqnVugoBu9CsYt&dZDf@O@L%#4iT_CSRS%1C}}vuQn3R$bJ<}X@|#FzBnDBh0SY2e5LOc<%$h=+v&^K zOFD%W*B@?YG1Bwv77y3XLo~4x+2Zz1eIT;^u4K(5EPm2Tlm3}IGcxUOLLRU((YjGS z!1(PU*@i&(ux7U##_=qW)GUs>Kc|?IQL+_gcU$gdmWE4o*dBxy(Do7vD}Mn}7mBb} z-idF^Ap@3#^g9)y&gfXs)I@)2$SUiwQN_ymhc_O=5!6-^$CdIDjf4)}P7R7O=nGGD z5>94{o@~__o1o&o4@^Mn>{M~cJ*!Y`(>JxG>vrM(PC`b?B}{2&Tf0HeS)MIjM(M=` zrvn7$zg-UC!q13LwQ*odHv(=2aVHsu$))Z@AgZA|W!@fp3+{4+swz9CLaB~h^P%c= z3S4fF+qX9J4R2A)xqwkKS68dMqYn1pyrk=jdxZoi45-eAN`=(6{US^?9VIi%w|nF) z0YQd*h(Q7z1 zR)M4Omhqlgn2QlyY+3#1;QGykuGG}1wCriM)&(`zS4>Rjc_&J$L87tlV08D7@4(I~ zY@>cn)a!vywu<)!_o=q!5N2e5l4gGYGr}0dqXq^^RlXuom#+Q&dXX76YSa3KzOlEc z36DC1Y4ikT_6cK;?QPc(s)rLSc^L;cO}?`=T;V? z!kBX0Uv8NtB%p3Km!H056&$r*w<^F_YMdQ5X&J5k>HUV2z$USkaWKiClg`k+1$Dyi zGpnfRsOd1o(EnIpDvQpL@!^*lOcd3iZJP8b-qkMXjxv!lK8TPOcVX{w2$ZUaDu%%4H;AUYmQ)6B3Jo&OWjC{hTs_Zo`#!sRs^lN3`J_$_wDH zcBGlk`P@dbV8K)EoIF)cIkv_W#Uh$Hur#oYVESV|-5#(IvUG;)42S_$`6SucB!Y2m2j_(gyvM`;$jO-^AP89t4@$936 z4c{Ssx1y60v6G0AlLX$SvQB|9gA0XP0jZ_L>fOr~6Pdd=Jz{IXLAopWF^M4&JP$s2< zKx~jC&3#^Fx81dTKM~z2K*^4`aOUhr)z%7w7Tae}a6+~edF!^6P2$OSHZ(k@LX*Jm zb<8;F_QB#JSzIr*IeX~g7n*j|h^uj2vtkj;FoqcAwytNN1#TxlT=RrOOj$>VY zeXqvwFCS98RY~0mZ$-4RlK;>vD|?jgT)D<5P$d}m!WiD^oX08zVBHOq)S{rYn|mb1MFKr zf32Q3@WkRkH}QCv6}i2iX~}-y{By9=kc3^4wteGBtCmp^ALA!a+#h9H&1;s#!tPs+ zb#RpDT5tstnwg^T5MH`2icitrQFTf3beeDLR zkmjMy5;YB~JIa2DHl-ocL~7Yl>`*e%bFs{k-83Dlegl_!UXev*tA3_J5QZBw+Fm$5 zkT3ciCbm7AbycKsh@}$sU%4XmNS}Uaj9^SFdGHYvEeizVr?Q%wZvem`Yj0nCy6$sqlNHn0+ za8}T|-^OFS5VdPzu0cR`J3HUYz}_K7UbWYJW54(KG979c3gXDbI&nD0@k{Rq_~@?| z`dxSAu{C!**h!@AKj@95DJ^4se%gl;fSN+x3X58+{GPpo7Bs;$B4hdWXJ+t^F0=6r zm_zg6%iNn|j3H>vzlg2r#*%j1vwZN8DBXP*|8$NunNzX)>6eJKv|Eu;CCcny*M$~G zOG~T6C)H5xYOKp;dI`>7!rxEINlE3Fjw{xmevgW3Jy>UDHH#o4KUPIi@B5~9XaBn2 zeR%lndZG1@Rl6`pCH0VgdZEU{3*YP)`qcOUY|9BjY7HQRqo+j`x19?QAQsHyR%g7w#Rj(kNQD6O;T3_01?~;CtR$ z21jLjXI*L9sux8&<+7QWMqTyTRyw8n@voY-_;)*6X4b1?q?MmThH}>f-3-YqE!`>Y z4=VzW2lFo+d8)3}@MYEE{h#?c6{hrJw{NO)S!t!0QfZ?~P=7x&dE^rDF6`A?w?qcG zFLSg#e4n#vvElOl+{W_@$FDRq-ya!Ls0>_f=L6 zE*ao)>kXmOBg_ulEOu|&Dag@%?wN%rdt;XoX?i@pdvL(ve6GguoKe3zOP!QwU5&#p zm*!D7qrJ|l44UtOmbbYEOf!G2oHozS6s>k+vY@9@?(6=8t%((Z>joNSlI_8lXjOa} z8%jFQPuAn?WcyJ6*Fb;_A5)qEnbss_ShyR64UlzRCcp}=C_76|;f_~_gwKEGyo>*a zo6n1RV`D8NEInh;+!3n38wTGMYZv<#nDXyKWpa@=aVF>f)2FK1ccr2KFK2D7DLH=c zU8BmK6Bb!nwkQj=b_u1Po`(cxITms`F*~>j68?B@S-sqhb0fzG)$Y$pA1^wJdKj&c zIj;vmDJYzh>O7$uW!AoCvUjsc^yFsgvDmS8UejF-&QhN*2ad)e9OUvlG=WJgb7{Zo za#N)}lQE^)Z)Tj^3|=|X&0AV}xBEZO7>O_6zD0o?={M+g21|%$COXA~;3D-dF(oA{ zDT_ilP+h2ZLD1bkj^FORq_nhioBI{yS@O+GB1;!j#bJgMCZn(Kn|mziDEIpFL0GBo z@ge7}rG~uioin6v-y3SmSEGE-naM(m@;oYJEgVvIsYZjdl>Dm6>6v_0f??TF_Y@0M zoe?{`rCMDk8dq0uV#CmK1ls0xhvoH7J$FkMD)*)81~s%Q3;U`{v=jJVpuR{y?(+Jk zIJ25S-kZ3GrA3)!OR-($oeNuQyE+2|c3mZ&)ocw{w9>yWA|-7)t-qg;an~YH47oi= z%AQ5)6=N`S5~n1f1EbJ{y09UmTqWKsNK?YUj+@{AqLZ<^bDR4fw;wc~0o&qe&>?99 z{WVk6(f}H#HUe@C2Q{aZ#Grz(LPW*G!}A5Og&>S&^Kkj&?1qe+TQ#`VeFavNDY%jp z8@J%=RM;en5tjkbcpyqFmfLwv|FjFR^zu$l<+_J;m8_7{gsd`-jF`1S>9-I{BOEAiU`op^bY@46dB=H!J=HGk!pw%SFC2$yMJJ@$ais=Q zVb$uzC6qD>3iA)^Xn3mFIc-CNIjS^Jn;mgkH5PE3Q7=uzKz51p7WEjOJnov_N_Px* zCN1w8qOjQ?Q9_?i=m9ZB^+-uB2X~RX*%(ubS+a_nl{&vPk&}PhTAyBC6_mE?-Ukvi zmiCdT9}C7`Fp758$(M6Eo84x4iq>ik@{&&^^Lj7lOYvh$zvL?m)Rw2ntsBLBWaN=? zU{26eds?8~C3bD_9%Yc@XW@;B zA|pHdMkjOLgtnHJX?4#IN>k&hi#i2MI6iDGeKYplzBA^26=!tf9Ql;HTY^|#hM&8W z;f={3r)KMf`tKFC&V)_|lPB~GjO)<4b3AJuPkTCIgBQzmFTDB61Id8LngmzRkP$GF zkt+^d@qbW;OLaLz@?6@N6WT*Qkyb_|Ls!lHATBPxT?|p>ZNb8$`Ds_PspFl0*>`gb z{b6?d&JC&VEgn6U<@E10_{aYMB#s7y7YGVPtbhse2HRZp6D1Tv^&|2&Nu9JU5r=)$RvIPJ8r=Yb? z6wpMJ;IY*)*^W(pJ*F#A%+uRAs{B)6$G-)mmn8o9uK&JH0Gpt{(|@?v{$HileaO&n z@CTCX|K?}=2efevd}IIp2Q3kgwq5=APtN@R@S|=Qa2211Qg#}YYNsJ3dT3+Qsjo|j z1pdH>;^K>d29l`KCq$bgg1^;YkTh|wi-=41$G&Kt{WCsb%?ZX8K&qsO?9$rW+Irk? z??XlT$TQR9rPbiR+v!2Q2n@(+pit-;Dj9*+`05ZnohZWV zw9Y$f((CZ@*6_wg18eIIj^mnpW<=a>-dD-+H5!zJ-L_?({`n0WPqAS$NC3hK?VIib zs&z9^Fm6nqV{!CF`{BZ!aC38O0;WzAj6M01e2Qvo5u#p4RD*+qO;AJcfk3ymuI^~1 zjwk%yEVbr!ijG1&cp<>>14c$hI11D4l;Bzmrm}v(k_89YS~nEC*W+<}`nR#M<|}!B zK791Yti=(BU=dGV4*BEwo$clzm(cnj z-wymLIZt-EQm2AoG|;{~2ew<&@aR(1*_oH`A^S1Kk*}L$u&}TmK7P#NprmhPv|Cl? z`sZFkFSfJN8}r>RpF9Tzy1=UIriFzz(FzEPli>$&gailUhAz!PFM8~JNF>eZvdaam zWOtLwdQb-{;=>OeZt(Wr+y1Gx=>_sKEYGEcoRa9h6`uK_Q0rV_v^0mj0#0@+$bQpz z>AQiz!~6yQLZ-GJJ1aV*9e*8%u*HI>vcSp-aPHlclbknYLqECgc{hW3&=N6%1S^Gq zEb*f4;>yy}?J;U!D$|J?XHIM{ja{ja5t%eCtV1p9GD3%vwGAv0jhmYrgKjK(;;NJXE1s-;6Y;0R_$bH~WRp{V>qXK-`LRDoY zm03b;axxK6ZKuKNn1;`U;#JFqjV|>40|9{R*RPwNSXb%uPEz}-X7^urH~CI#JQqoI zX~Q5FVbe) ze3oa~>dL6gs)Co7qa%-@RtHr)6ThYBQ)g$^(NpNjF^=|MMf zds`;nh`c;^k3_=fYO~DB%d3W>#_Fof@3YRfO!RC!$ye_)o%Wp^h%T2LO_U`0#+8_{ zxINz`DkL*oHxpY}@!WZ9x;iBMTW5+a)FtZ6E1ZE4(BkpO?eFPH>Fw*Q>awq}A=sm)5$lt8x|4Y%uzdHaFbXuhSo;}l0 zQ;Q<@1()OZfS9S}A#7%DyO(jRy1H8Z;lpWy8YiGqEc?QT!@bWqJOoAgZv!FXy1MbP z*VM}{GGx#!plXYjD{)T?#gHg^&*9F?1=l>-Rf}27hF&*?O3}*{TtkfnINJOs* zja)+-RwgFN)$tmwU^P|MCRdjiXGxn-;#U!OO5;GZVdL5Y944P1HiO7-4%ldCPftGt zwGR%Sn>XKy9xO7VcE)T|{lc^wI2&QB4}cV8Kh*f@Mn=gNN8pV_MSd-O40NH?U0f<# zXEn6662$cr`9ZGJxPW1M)bqmp+*}q|foA~^z!6TMK9BFUu4=%dk*x!NwVbLd9Z*J~ zS*P&QyI>E53#of;Yil+pw1zcK9mM@ePQaU)v{})6{PG>Guuax2vy6Tj5`r45!aaXp zQiF3g5j4?XQBAhZ!VzYPM0O7|g5w^?tn16*;LWb##N8eUzwU%XK+Hf?U zCyCJz`=Bii=A4%L*-V~*@ZEv2hq?l})%*AFn=*%v=Ds|QVgiwgqo60=dnw=h%imua zWfi!it5bFR4r+T&wC1#B$>@|_>-4aJD|n;fsCaK=^r||DmE7kb6buvOV8O|wsTH8!@N`Km>2~w5n78WUs%X|V1J26IYM9rp~ z_#b&?zVa?Nn$NXu;LuP?*2MpE)<^6lOFfYA(fhC`aUw!%BV`m+LkDBF(Vy!CoNp*~ zB+>-B-Y!$TPpAoAu$rGfwJc>Ov-fj0sEfLLy$W%RkC+}g;zvZ}q+CXgIM1r1eoa3` zp@x{LK4}xV@ZRhk$UR3j8JpbQy>U_{CiCmmSK*L($C7qB=^qx?9$UB%%xwM7`eRLi zD#ZkXAdskqABbfO!l1d$+2zJS7W#ox!nl!2v(eXH28Z8zt!FPTE-uU8%wh#jxLnYR zq(&*1Tf4P_xFpzUOe}XUko~@F(5tkFbqn*cNu2BqIIV zc$Uf@cBIhyC~qI{K4L6CMh)R>=vo@ov$4Na1)YQIg*bDnS}}ev)pkbdxwQe@HO$4s zu21@363LgJJ_MmEMyBi673%iq6YgRPy8L?gGAwL&NgJe^j1lSu-J!C7hDpQ1*Shd>zbcz6i^O$wj8i+&Y(t*KBkDE9--K+Nm zqp5epgUX;@mA3;;aduF4)-vLc23-EewDVB!`Y3qO zPZChbddFaOEJ+6|xX*33(f!p4>YJsOQ#^s0A6|3h$B%cyHqk~ZV*=N8is9U_-L+H- zU_{*Cy&6_sEoeJVuX344qtc_!$jMphmMms=HY0)KLTB6$tRRVri=mxwzi1eF>8wON z*f=??I%s;aAWrPd{iqP3k1Jhb);isF`RSL9BXxd3yDMX>sB%-;+L~P~^1SbP)@0cy zMDifF}SHwI1xw1l=g5uGrxiMTz#$KD6s4-YU1(`kxva%NNT>6n6m>YP(wFWN%{ zsgS#V2)2GD@*@?_>_h$FFkyx?nEz@!Iys5jx^K-ZsvEe1R#Z+~kd^qFldf&nyG>BT ze7Wp$v{$sWxOg*X6`Io7i;L!|su$|}9PI7;;Sf+)QVQ#H72z~Y8RTRr#2M$wst1E>0^J}+!C2gsFUl&airDYP z19S7X@OvP05FV&9eT|v<9%#2rH{M?B3G$>R4Ac`4N4n{NZ~{$%GdDw}%ye6)dzm)T zUE}5Tb?+pc9n)YfL&H!3-p`zDY$~~$`FDR5M+}k-R`ad(Z0VnAbeLHd*#fD*C??`d z0-L*AU!nw9itd&7P=reI#10Og*U-6?%A!Q5_Tt4yc1A{Za`Jm3dYNpgUpbkXdnl4# z5Tlk0i{D=~4NFSWFSCE-cX_?J}9ka()G{KJQ@a|)Gci*gjb8?cI=L_H&z#&z(? zku?ss8p^m-+&NnIMT#dWfM7P*Qsxy!OK!US?ByW_r7=9|WKT`&@6SGd#MGx@KbX>$ zOsDs8GV;_o&@X5zn~k@!iW=aXeEo9Az(C-})}5BL1is7{_1;G+`wGafTx*VxA7{M` zxd1{7zU-GT54YJJA22!okn`uvlIN|sXmbxF;YC;wn>ln%Z4sa2-FbLDuMoOgH zr1rQx=ATJ?%ZfLpCI~bUpady_AuLx5e@1l!l8wu2;?zjb4_s%+`GhaxgQiyE4s>|# zMhj~ls~AYAOS@r!p0Jh-3!lyRo3v>a7~xpWp8j(_OE+w`1GO0rB%XI?hc8Mh`%H0J zHh{B}t%kDiFBaoF*3TZyzUNG$S4qbce_hh5kNZ(lovmr1z_|UbK;O?Tyjv}a2tPl+ zo1tn@bFt1yNlLbrUu@pNvu!vo2lb^At>wZ%^yvrZRn5`59~4P5RllNRU&xtfRNB_> z&l|Dpi(69h+02#W5Q)YRF{tlJ^4}eZ?N%O|Obi$DI?Pwy7IWwAS`{Xw@4R>nc?rTe zO3%0r6501+S8s$CD-quCPwnkBZ{uaTWWDyCKV*1^IJEH@&b_5*EzH;Z`>oD75~b&A zoaIS)`S|pYH($AWin?)+hu{YmT@m#!J+4%HW9R4xQSEiwWfpQ-oSDSY{A^VH z^d|v%sImwWiBt{_W9M|zvjvNj8Nr*grA{ACTHeT_W}5T&^~E4ZAXZ8}H8m-6 zPGd(?XMz!WO8ye*Ou^GO!H{|eQMoh}wdx07kA0_0D9PaLAU?oqHuF08VTcwiU}xLX zMC9CIovydY14U*grpiP}+@A&cihTcc_^gW3?y`<6abNMfUxnV$H7*&a4d3n8C!Q7( zNM{X`l5tP0@@MVLD0CvZuygu?PPiUxACkQ4?6hXZe0jNWgb|0bsV776i&Qk?XzLfU zNbWwNlu!dj=wQCQ{b+gK^-+r-DR`uQQvVNQUjY^Mw)U-pQYsz7&?OxbgCHQ`03szV z4GNM&iAX8ZNQ)vVB@NQjf}}x*w15)Q-S9o*IrqNrUFW;s`p!D*$XUWLv;TYVr+$&U z$2|Bh{Aq>Vy%5ym)LhCJMzvuxpKfVQInTKyH;e!J97I5+HjoGe4<`#jKU2%gt8S#i zj^=U+b>L`eY3cp@c%k`*HG@Kfn5z%)1@Jwe8t$c~r_08^etnmpapF0qPVuGUG;?!v zyB7}fGa0#f{p>Wl7xhmp9qt27!%Dr06 z5)jpR1sZ?P>qZ8id646Pgk6#v-P_U#)B%bfQ>Un;(vT{CGw|)@tUJ?%li0 zd6)eC!+5`XpSTC-97jlLON`d!cgV!B`G+{(R{D8uid}kxQlr=k_0J>#Q|rmKrlEgQ zYtn$r*(XM$f_2c%wF=QuS5G}zkMQ}CQm$8KMSPxgn)L%6NY81;Z)#-1aF((dEj_N) z07Zw#uczM5&YQ-(h^a$I@NzL51C87tYIQdT;|NkQ=DpX883f{{-;PAwLTJkSQqO{Q<&WVWRwP&FrMkbFKSOoD+QM5bOludx1sQ%@( z2|A$fsGxJVvqyIaaOgiPEIOhEm=VV(9_LTSobo~SGz1iY-hEhCX1`u!n_i9*ljAlB zrFBB`P|0edZA45X)MN^7D`KU@>vX%+u2DJbakLGc=N+7}LD{wm0Gy zce_CRz%y(jYB?>6APFMMlcEwlIPH?B^XU;1IsB|FSx}3bNEGY>V%l#`IgY0hf7|f>XUV>uj&hMx}EI;)m1g~Lr24kO|v3Yi@u(n@%YU)G%;*t`J*tgGd z48Oz{6kJI&e)1$p`|_PTB}yuf9(}mvgjPj9S$m61(g~?%{a%_y|Bjc}{=1z(Ld&r4 zB2rQ^V_$l5<$nG23*H&6$ecHzlw-Y{xbtXTd5?fd^3LIGcXwnt)j#yJWpE9tFsfU` zS9y6WgtYDLSAt*<)nsS469vl1$Y`3FFkD`z4wU=U)TF7TgrCb87PksbPL4RDuD>o& zS31q`o&sx87_LXLvoM5eoX;(?y3OH}i7ta_l)yv`yQ*4nbA^pv>x(PQ-%{^W)6m>; zWT5qkz6a6??RFq6(`pHn$~62gDDH1iuRBCxo1e>g~y1dM_E6IByv2fEr9& zKTcX$p=PO-dhLf~_swbB$mbqSJ!4gZ;SKnxN(aht@RHp9#?*DsA&grb`~pKff~9D3 zj*s?9UFOu@TXtF8O)RzCJbH8)d>FxzW}T@Xp$v=`qK?b<8Ps*qUsKh zjfuIIMkGiA@KRDQP}(aJmaPAB!a0>)T}{1yo`}J=c97wAuuW6#6Imi(lOH$j9~<8s zV066t2wVr5=D?29U65iTLhfrtg@{i)f#DQx?}r`XOP4Q)SSy0iaIp@6gc)QW{(OpW z@eY}7@_XS1DBnjtCD8L?0Z|zLSKsEB{9QCt{95OURjMe*Vx$ z9<0;|3fqrO9_b-V${wktB%4_`n4=D^GPwuE#pLHl`KJ%$k;;2~%}dUeev;hii+u0bmX1Nrot(OsMH(T18h&lNgD@~}LgNFW|lr-c>F%G?9PjR#>X!lpjN z)1>~)9+)kMQ=8tv-J}i>lXlE!Fu#S&&AZ(b?lyBP^?nuf{LkG@SsWrLZ%aX{hp^tO zP%Z;yOE7Vo=!jiD(nV4u%GeOXqFHcCg@ya0(PgHxC03_f4>J#-;?4_lhYqKiPm-)A zuh4SBYd+&g!-4<2+y3;`h!EKn(S&j=qK7j-(&mc}zZ?N#mb@699qEe~^`{G&j5v@4 zOX5fQadA{p?De;AErKH(>j4=#`NKK%>4{egJ_@R9S%aI9VH^*|=a2o=QX6kQY4qKer_U`UoWJ!n7jov4ZXTn5{sHd)Saw`1{ zR5FEwmz$%w^Y$Q4Z|n-)BOaZx>ie%=Ubui?))o;;Kr)26vn$#`3b|yXUza3YazEo^ z%dT``j@R9oUBC2#dw08A***6&Pw`RUC(gf|06P1w;}QSm^JA2vgKxCC^2Q+_kL|?zxE)r@R z1hT#;Wobk(+j6FooQO`?zY&y#>D{&5?N#^YI1Aos64v>z$!=-&ku zu4GMWqNW}g+JlxH;h&2a`mjIBWtSqA3h2yIfCM%_({bXxyJ85LArK*Q>*{FNvBAO5 zyL^ygU{A>jZwNwg61Isho4MI9K!D1$AG2BQker&**m-F8?fsv9{w;xB19`wV;nC&R zr0!L>>X+_woHyn$w+3U7cV3VP_SMz@x42Wg-b%yPG51Y$(xql~_FKXoFVMnTY&`oO zaw~F5N=On(3UOqn6i&M<0~@UAXlZ#iT(qtf)z%tpfez#P&-YcLAjfq2Bbniqw9ph;Iw&W3EUP*D_(=IP(<}`<0`>+nw|=7T1=M@ofjG)`9dL4o*%IFSTt2%cGAUr3nc?eOX*s zTqG5M6Z|Po&ju7v-5+k;t9Hrx^7}@%Q*2z^d=IAg&9nk~^R1l*3XO7-ebk<7jX3Xg zL6rb1!S_0&3dp8okrsK^>S88@-EbOTg+YToh1<#mkJIqnXY$evm*o*5!rag2#p~#3 zelom8YyOz_Fv;!mONah)&%{(vvt_f4Yxm%w_U-}6KT9-BH;{M(s;xIH^oTTus`u0r*9N3XyE9}0>D$kw84myke#_=4BZH-g zHlXYCXALNanCLL@+R4Il(60+w(QPgD4l=LTV_Elk5%=N?LvM9@e8u0K~Ir3 zJjHjFqLcRdFvfT#i8#aL}1K}r!n=o?9eR1(PgdTSLyT>qmJ9S&E4 zE->MkDC8bF{JA4Vi2j@gO{ha26|@Unzy3rS7o}53X4MieA*S4X-4prcQWcls*6rH_ z1D{ii1@1I|?!YURzf2aMkB5pJ_GCr0wBdyA(9)(C+!q9)vtrBY?G?HIQq3uVT5O~z zI;d;>1jd-c+snUyHx-R8o@^AhvvP5T!paa~R>lhENlYR;4oSKo;!acy8MwjD;g9Ep za;)H-ESE=)W(cyP4?vx^w%+QYf7=U1%0g(eTO;K5s+@QriuCcW>A7B<%lir4WH-@k z8c_N4WcyhT*NEZ52$ydgD1Z&Xm3#JSq+LQ)q;Igg9?FJSr$GPL zHm4@o= zDOjvRH!_;}2ZUGty-stT`-K?m2cNqQC;Fz=r!d_5GUPXRRYc^w-{XoSkVL-F=N-Iz zx$-3C(tkTom=rFW@bYH$XanZrS5;LVI{sxy{ACj>^H1w76-YoyJZ34-G{_>MmBYT9 z2uoZw;0C9ZDX`9CS3mZ8x9TCkr>SXb-wDw@XsY^(n9Cr~fgC7_xn8WN+wusj8F+ga z)<2Uil2JaBz4kNXMlM}&1>{P7)r6qj%S17l8%uTe>{(q|8Q+pd%(Xhr>#i)xzxI`vSA8BD8xknFl$^WF+=hL{=EF?49_A!*W-hF@>=h11 z{I`CA?I(!0#;wKIhl|2rh|WsqzwtQkg|ynQo7 z1YAJK*9)|_Fyi7tJ!4}__T=I{l(r*fc>7gLt7v3D^jHjWQGcfdRoJoYW<#t$uY3i$(|4_Sbq2=lJwuJU_t!&y;TnyF{^rchh0$Fiza2N$1-$DLf zScQ}Zozmr5#r3u(|j$w^Sy!L zW9Jr>o13mb*IdqZfaD=E+woJ%@Dn2>9uuuTS<$Q|>y07HDwEz8Al`*@|6zA; zY*D(zseBdF)z&0*8o)WshR#k6E(-ESCe{4lVg|&szN{>X1g@dpopgrvYOOy1uS7*Mzm|5J)3@e>E_L| zzo%O~dv=$GB^nZI0J$4dN3!~fy7-@W<)87FE$q*jw|#?y@3af_GoiNYhc1jJpd&&; zL$94AgC!|^5r(x4>muus^+EE*)!}Mat^@o9+`u+<`G*-;-x(PhTN!(K?o|Yxyv@xG z@eN*PG$3TTex2HR@fy)&l7w3Euc=RgD&~kAPspYT{OD&sie%8YOTxG^_uac&Q0|B? zyTNciZ@|LOz>Hio24kvP4^7&t_x@;Xm@qB6d<9whY+;+hx10mcXD|A+)igu6lDkiQ zhT*JU?5m`Fo-xwOgUZUv(E3PWgB|h#DT+|!DUX7tj!qu949@HWfmE1+;?*g4jfT&_U6H$S)vD zREeI1J1k`XrhWGGQv;qbH^4VE?_MW5UWP1B9;8}%DcsXa`gB1M6z2Q6v$HN*8YBh1 zy)s(1w(pe`@zgJ)GDbc)ru|-Zd-1(8mveAgg6I%P0ZFaR+*^5zG5C$(1Qo{1=m%#WY@_9H~4y?{1`23l>$8X4QVPVh)uC5%d&QHsUsIO1# zc|hw5Dn#ww74qwgfl4Ocq7G1=$mF(qga$CE{&NFhTAvm^R}tJg0p818wL&qz_)vAfV#A@k}@_L zUI<5_BT}T+X&EpaXJ=b`_rQ~d$WaBnx_=GJWYQ3)=jVUbplhd*38)-w#Q3ZTQ+8sL z)|wktImz32cIDCF5#1Ii3{r;f9?*Gi1Q|-T>&}TAXSPlhM1;n-(^6v{!4~JTm~?&~cikgU7mq|- z)?|}0umet_)?fYI8-JSNjTnO@A5gFp8HkXgsZ$6G(F1;c|NF{Z)1qWaueA4|)uAh@a- zzc?DX{~|AU-+W-Wfa5MLQqpDcfhc_KO0K+K6+I!nq>$X3ZnahViDY3Lip#2p2FQc8 zPlN*DLyh7kaJP!%p&m~pYJGj)jem2%7%Ep0k4K3ICmy@-l4x7%GzQ%08M_o?j#NdQkO-p4 zB>XppTnzuMBx}IJ!GhZ&7aS)GAzovq<<<@kI)Kc(3!vY<8pkyX99>4L0;4*8Ep6>w z=pYr%`C@VJ36Fy~6O~{;AVUWL6}+Ce(t6Y2=ktb{NyjykKn)vfYjoV0lNQz=Kmt+M z&SG>l381hn5$C|fFOBgC4(%k7xBX@& z@M=+1ff@p*x;VOo$o>eQde419Y|}C4T93V7Uby)9zGG$v=5B74Fqb3ANSG5uBoiZk z9`DUWtV?2v;g|*9m;>wwHbAJ>R;*rNpkwyq)&3GM=GFks{Clj**&5`NtwA?T^0kDT z@I$agA|j3=Si$TZ+|iX4O3A?H@WrRN?R6s&S8_oBIj3c&){8CE zC^8XGB|J=^bNbG5_dTAY(`RW@YjI~u%9MobeVs>7R4nP->z(Z%$$vyLb-MZd4K@B- zQ#BkXBuS04{t2qny>EE7Nb}M2IMjb*&rITn@j+ZRw5obNhXnpYCz` zbu_qF)$dJ*s)0MVQ7Gl#ukjan9!d9}u@>;UZJ_2cd*oGNKOT>CfDoN9J?#4fSG&k4 zX&0Yh&CjT68P zM{|Qo6+g6$IUJRNnSKk6{W8&3M0_z`@G}4C$cPM?{OrHL;M0Ft2qwNWXLIxNK0%t; zx$X^>yqHe}qzWvZ3GwmN*Df>?k3BAU3|?=t4i2l^-B#AtoS2dq^RoB9yfX9|Pfkp{ z2xg_Jd3juA6%_%>Z03@GzfCei4D;d~DT0t+MC2867OEE4d%FeM*|@9qhxXGa%*@R0 zt2iK3Tv(`rc|B-{Pu=+YXIoSOBL4Ivb{iHXgZz$PjcXq9U|MgcaQaQ*Pz=okDzlL~ zysfRj=?QJ~R7mlZm6cgmXlxuDMDKwnu>i@xNfdvp$A;qsNj>udNV4Q00aLx1hP!(e zX2CJ)xqtnmmj4$C0xcnJV`K9H%(V>LZW;R=yL!sATs!~2sUC0RFxYCMxMuiP5Y?oj zrmjx!p5OTOWvYD0hyX0k9^n0N7KijY&<%h%pxCs2X4qDwtg&7cDD7(gy-Hpb zbjOE3p8H~v*4?X-ke-v%oObVD-~6x5@~{7gKmX!g{13(DZ(7H{7vf*v^1rw#7)4vz z3;(lL@Gbl}fA;hL`=|atzU3b;{72aMe?BezD$ECd>VGNxj0s$WQy-sUnWEABFCroW zi;D%EG5CJn=9RkL2{iN~_yq+?4h|1L^{GnHmJH_)!(aZbAKXa%aU5pT1iNF-s=C!K z7&9SUS6A26++5C+Cmm9|S3{as#%n%7mND&$0Y``K7K5sQ$@rya#~x7NTmwTlzgMp) zuKl%c7#@W_ZutD~-yuE?&e}#s_TC&@AF&Ai0N>|#a&pq&nE}(RrO`^ht?g~YhLA3R zPu=NC04dezWO*+yFDg2^`i0GiIp?g&n#@cQ7q_BsJ;PPM+1eg@O;^y;ehGb2QCGJc zD0TAKrIV9WP=1XnWYx{_Xzze#Wc2m;wB(uo{+IqEBdnsDI+WhmKI{^zA;9Xr37V)* z&BoVg7VQ`9btNG2-aPS{N={CW?07k-|CcVnUxX$igyZYv$J4=j5rKfX5s6KChe(lv z>iSM6i$6^YybMKWid4$(zR&)z*KSA0DIWIjOcwi7fq@U|mT&VFsEqA2`D-^u!3_j( z0guj28mhfEo)xT*TU)YXKH{n=6N0Y~Uw0njFkF5?vgo&G^T2%EZv0Xx?9@*@UFD?g zDna2&cz+(wU(X-tNb5QLX;<-~b*S9QlnL*FTaV<{ty>$CyU-l*2XxGr08{vdxD5W- zz=vwD9<8PcS+sV63;`e9`M!A6(~3DY*Zz4)1$uZqlyq>`JhysK=LZG{MdsQZx8{5H z>d#l2e!9@8ezB2QL^8AaT9<_Ly*V&mSBB%R6c-e#FksE(<7*g4LAhJenjaA4%_JzWJ`SX?aZWIRq9Vt*7@JSFiHrkojv-~Dvp(hnc2)Pvc_Wp(~ulKLma*&;l`k{b+c@DEY&tz~=uxD2&*tA%E)7$9k9*A)49Bp>7 zclPYbKK%NJhxoMN1*mLeuMdP7dGG&{8@q-?et7$=3y?U@bgIV2#t_C@8i{?G;R+}$ zMwyKBAUQAR>lQOPhCh1rDE`jxKc62H@+cJU-@pHOdq9V@xW{9)juKL> zI+F;16LVt5O=1xbVcNCsLyBNTo})?8VD-L}n4H}CM%K-3xAx>~iucH?QoKEXO6`fA z+3Bq0&-n1m&aW>PRW+&`Paex3dt#&HdM0J`^vGUucld2=C?ART8-%?0(S8U5{l3ik zuyf=YLtgnQzdQ2blp%}#w%LX8g%z8dw@mSRz?<_&!3LA6=)JuJ^4#OW->m@3l5bG; zK83dy>_`&ZT%b4E-QUlGltF8noZesMPM=n&mh|@J#ZKXGXW+9Z7LsG|ttkc5iY`uz z8x<=b**@gg)EutN?e@(S8q-w~o?iDrW~mBWJgF9c^QMm8o2z@kbs=|U!S^sPG}jdP zduEo(3f_BIkHFagZlfNEp?4ruZ9&b_2lz{?$$Br%d-rViHlbVf3@8orfTqL5ysHNd zQ2TIJ1$_sTpQ{WEAD16-*xA_)fW_*7Rwy5IF`Z>Khrr)0%gVw+E{N~>^XF!X_6^66 zMrz%!WoBlI-JFi88KV>g(nGK7$GMC*Ltx8UO0M{EU|=eS4oENOL(JzoF9~pmH_Q3x z*9_ir8;`wJS64b;KC~e>kf17+bUVdMM0M-o@%d~pr_jRqF9}WZbLc*)^0dA*;!eEkOe(-anY>pBP1le>)^nL zxsLjWhZP~I%m77^jon>0t|?p_>U`1lnnC~~gt}fDyar^z>2bOt?9~I9{gTI)FD@>2 zm=(uq7m-O zGO21(S{~!%U6{cdDwPpX-Jo`lU|Kz^F7~SEocimA6H`qWJO*p$v~*6S28K?e z^y5!>yzAcu_-NQ|^W~KNwE5iOt!6;OSCq#zH|2l~@gVEM8IxTRIlU5KO7$QA`ZL$J zzaX8On?pg1`LzWz%Mo16gZIc zm8*sTFT8z>aq9##RV$x1TDPn9m?Ysf&FayS=eHqxyl1x*vydqx!g9S$!1NGm8R+SO zmf+2Jv+w0Llq1xaNnRRk)T`li1ZenNdl098{>-@uCcMXuzVA6C+g=8L1HOOD#~@te z>mDMP=K3y1?>f{8`}_LV>LH!3P0fFNhP}SMv}E#Ry~Utr4qGmxFDvFMOEXGG!g&_E zFFoSH!{iu;+9=gL?O_J)`66vIqDaa_sSE7X1XmQeL!4##n}*J^T;*|0l1y5XSyWKv zfLry{A{HyuD(V=>Mt zc_m4u6k1{FT}pX)0S~pZck)r8t6j_mpn%tpcrTsBY4T_GGA}UOs;LVMH1D#lrrtshbr=xU#aRujlXf?+m86 z=IN(%Ln(Vdmv;RxWUvS=-E!C%lXEIz!lTlXV-w%$%^VIfXJ#(y8*sDACgdEPe{}^N z{!yBbBHVyVlTBUe65h*~WYYBBy7S$MR9D`}UVDIK5s?;=j-@tqCeeCa7Q&m|=~prP zS+bM<`M!CoF;c(UrBzjH;oN#%N+#N6E-5@XEz;l9>jrI(wcl^8>bYr;RdThPjr{|z zwj%qINJl2e&mshr0lC|OU2J!>eANo@j76o9PBptYR~~>QQ1(T$c5&f}o8?<}<@!CH z9DeD*veqQ(9T)9mU5*2{fgm2-iiLO$9X;W`o2_lwUG% zYGYc=97Cw`^76=wlO(;UeH1LGf=s8{8Nlf6*(P<<_wQ8TT=DR?6enlMEfmUi8@S3} znxYhgRTXr*uZes=KRQ9R2J#%{-qSIghKXV^)3-_p2~d>077Xh~Ly6McVGsMtv_o)Z{E1~}e};)#lirR`NdFq` zWx#o1vrVP}t*L22Z0vKi{$}qq1wb;7i{*zN+fEi9J3B89>VBGKW~s=?$l;=`J9$!{ zb}85Pj_c9vx8Lh`SVi~u9;a{i=rw+-Q0Kb;S~z#V2BsSqk#@uM2*E+RQ;o_5p#3eJoN{e?+feO(U~bzr{hM* z65WvQ&NJP+tfj4ZOa(54&A2esvEi0?+?;TgPy55IAaCW|SW9=iBhIsez za1QGQ1;5-mjKy9z;el*Jnolz^J-sUAPc8tbQ$d8vRRiq(HD$Q12n~t;@H58+?Z9wSwrr_x`aVR6+yRro3 zo1m9Homh0X!nw=%@mpfpIjE@j1zE38nWuGqd{mW` zx3XGW6@pka#BtAR=M{bVBFT;Ds9nD$xjaFux;g6~Bt}F$b$fmNM9AY2KaVk;u=k|J zoe`j=8uTSDEyvDL_&tSW0D$&e^c1tV&z?0ht4~cs+1RkSx^_(CS-g2kcF4v0*6hW8 zNyKKG$%*bfCAcHVGDc@B*%O&F*fX|9lZ0jmXzEj|#Kul(-X(qJzWBL`_-8@zXO|C! zlzb1m?6^eH*MTR@rg!T&F%BEuN zh~IErS%-@{p)$Mv_4IggMus1#gs<1o7ZYFNTxD<4u)s0<7HZ7{c69F`%`l-&bI8jcZX_9%`*nEb!&3$RpvFwj%b>`>D6_P<`**)!Y{%G`K&o$rBh+ zNLi|Ne_cOBM%UKKws-LbG&SMFk5k6J@?S5EjdFSt%BG{2wU*CIpo1^FwOt z0xofiB27bUH`qZ6K=-wo-1K<@)CMK z8jrnIQGOXnl?%c8DxStxmL?|BjuS9U|1FsnkV~vEn^MB`72+^yTm6A`a=7;ZX@Rk~ zSVU8k=TbEBN)?KPnStg#`e&NwUTXFRASY|^;(yL9RsRr?XPRm+!c zpZl+Iiavrh3dcwJH3@H_fX!fjl$p@d(Vsk#u}A5;kBUn8D`yi?qXop{*6%&q!aWzs zBg(dnp`V|IZVp!cp84Ine8ejm6lZSFeWY3lQyn2UQ2F6l2e;aX)67k#9;H?Ha+cYK z?ZN(Fi_yxqI|y;1mj!u~EulObX~KRN4&A=ht3+!?zFZN(#494|vUbi$bxp3fegOwa zZsB}Go83h0?2|MrLcGtT_fB;SbcqXmE+cI&c1lqIBHLDvZ1&ZjgXUpy$cAgL$D+?t zlAEsP(9SL&EBZ>CjDtqTrCxE)V3Xi922L}1k|HHi0crxXOQLKcI_vuUK|wcqxjBZm z%oIIhPA4Xy7;ZSc|83KQt;>6`{p)aI)ip%DkEh1v(joAI8GbM6Q6+~=GtYUL;;7`i^zh?C9JAdON_KBbvae`uwKS!By>mOu3G$~EhV-4DStMJCt@R%5 zOG{1uLL3*gXw6cteLTc6dH-7i25b7}YQikmT*O2~{42!;y2VYdn+Ej?=NCg~Q#&gN z@$gKwSQK8GqzruMzM!R~r0jB1SN85*K+D^z)I7g*h$+2P6Q?-XWfv5iuI=yzI^#o z8hMT=TnL&EPBb5MeMvYw6?E-c=Xug_mJYL7Wl{%o^psUw zI5Lb};obKruS6xQ%n+%3p7A;TT~_X|#z%YR0_AQ>7X;sUW?M(xjn-7`C@PsLwUlQP zcFkqEQJ<}J&ob+Xc5vu*s(ZtPJG)-UO*29}oYpxQa`cKbcgX6SL-^=f4P===_F%$8 zL1vK8mphTc+6n;5jGZlytCyCCWoYnwNod`)?dHM0^Z*}KTOEs?COCGOnlbPF!1vJBSVs1Xf#aA}Biq80#g&zJ%m02z zm@l5*e1`UWzU0k-5PKTUg^!Q#_xd%ZA2TlMBSTXUh+J&z6Tc>r)#X;oaO__J5NS2b zy6t2=ZBtYzNs5`dFl%P-F7~~%o&Y~hj@|otawzjAJNqhyGvMML8(C+^gSy-WKV~dk zRK8%;h1}e|V(W*&S|nTw7u3E}MpI=V8xF?-eTg8vPWij3=l6heNCH`tx>=gy%pq1o zoA~u;&6S6|CsuE>*pphQ^Fl^oS71PE%Q}R)MG@s*v%d#iY+}<^8~94>zI0V`RjX&x zbDYpPSQT-0558h(`Ci5mQlWb8BOFckx@&-p9SfULrwkt>EMnUXlsdY3_YlCi?~hrh z%xVX?t)?#3`2#G3TR>2-NwU&zR0L~`60^nyoQRu9C50c+8Bu=B#xNH6R9mIg5R;{( zrja%az1XxqJ(#UAtDks*zS5)23jwkev;BzGqnI0_G1sm*m zQVftG_5j>71JD^h)1-K&O2tn+JTj5c`>|K>+?YR(_~2x!%|A=$Cz_(jAE2*};aT?UJH2K$;C@S5^*X zkYWgA(vEa5^H`#UMcax6np-c-ZzSDhVSUr4t0$>`VCzgB-# z(|&|LcYf76o2in~FMWg6NA!!Hl6>ZYUsb>5FT>glmrT5>DzrE)6aRdO`q*l!|l3rp_m zbye*`kNit$>#w~`bq*JWY+u2FdkQbKg{kS&C;tu$5>N|o8XX-ym;}y2T6VUAkdV-K z((w6+l|mJfw-%Rkx}M_@mS{1yo%drtGZhq_nDGHRpflM*kzZT&jEp27B*3g_@Ex=w za(tdVx{2(SS`UtXs%dr%9M_lAkyO87`Bm%rUMeapCvG*V%lInh8`FzD@#-X*>&(>f z$F+$*NJmwHWR+)YUzYy`sJs!h$hSu1R*#XWknOcp^VIs>5c-*|t%pj-4&$6U>Q|`R z1JKQH6y|*KP@2EmzATEyC?d@^UT9DFNZk%`UQcswQdd>2?q5ldcuCp*b}?wVD_)q` z+>5=qD?xdqRv7tR^XB@qcQ*|->SiFxy;Vc^ z2_Lm3UI_4|AQ0sFt$OMFRJ*N6=?;vk>6j5cs|bJy-PiGblV3voSJq?Zb;SrILTvAw zXXj9ueY5`d-dwkMDWz)qLlhaO;V#T`UAtWWr7QT?vH0l!42>-f7LJ%*-^KeoBA2W9 zB%6fPkNL(~qVUH~pP@dFH9rq7ua3Q?=J_JP*t>66Qd-)kUSLMm6xA853e=!mDxOZK zUa249N$7ori6PCNn8MJz$`4Pp3XRTA;WiPk*GzuX43lSiPPUj=v_V@jTq_nYnI~%S z*cUByw(C4)xW2v_djVRGeBOmLoNQ!!`@Ypuf);b{R{p|@N{pnj9!HlU4YfCUAf!E| zcDw8A(aAPdRek;j$BgnJw}gQeMjU!1Pv6)FM_E9k zgd`>+NK`H|BK8jt`#f$eZgw#u04`g+10efNs;PNEhCM1e3&W?uiFuQWFn3WL00Fly zC^7`S&wPiOTsTNFYc%NYO;Q-8m`tII)# z0EH1pdli};%}Xn)HFcGV$+rc#tmRp_C{4paJLdR=1U--R=kB7j;|N?72gf11KUzq9 zJMN2LdhX}bAJwZOyen1zQr`P}A^)tPRf~k;xsiIW8m@y>xr=O~>MhL2hrVcR1_VGl zJgQkA$0@UY!=qzmWzE0y;K92MDu6>VA{G+%HT`0VJ_ zFIyJXQ*$0KLEIbdn(!9ys7R`Bt3O;BvZOOKJ~^>YQ&Wpf`QXI*Jd%_9j*7IdE>(x* zpxYP_IkPeoK)EL>F;RlppEddS%3gir$B4NlHp;UQxx2>$gKgB?~javJCK;2TRCh?0d`SNVq4sA;L6>Yz+*)ev}Ui{IEiW;2%%T9*5FDo9D477#wfw@8o$KCXwfeya4O3+07 z6fM`mQC;9CX5I?H85P@&Pe7oT0L}^HEEjQ6km?;B%7npONkJe-kikxrDN7~ueX~O@ zS*pB=mCbGbY&79r=b$-{wbr+3P-_c$7O zbgz07gtrQCxD|$Iyk6JX zN&M&1{mJ9{2L=?Gx?!f^vifOgNCyC3w~s&Y;$dM{&IRDP96(sGY%A3ep|OOKsIHwA z>%+l-TsjU(sq7nm%q)_3J{-!Ny*{U*e6W(SeCsD<2OLue9WgS*)W3^3T6@wJ|J(t> z!Y!O_znAa4HalKWbysRb-teOKV-|gJbIO297wL<3Ierq*zcR?P9r7kB$^Z#W-1REY zJ^rDc{XZ9p$Kdkj9L{Kk&!HU{yKQ~b5Wk*WR+qt|Mvc``S~fm#287Bj3oiCfPM$X9 zN^73AI){g{H3mo&JIM41wOHBN!JxpZzG=r5X#UA;2z7b(c%AntQct$p(Xnj;5c+AF zqD=jnsT-ovLN?mW5cj(ggx)IaN~-`cSfTmPSbv7{LKE?sqK1=dmUBJy6Wc4yKq@o4 z-ECb{ILwYoje9`$F5?44Fs<;|moJD(VpaY8o2Lg|(_@uJX=H6MT%cZJMxDlzelwsRt7jr8GNG=7`*&3~o&Pxl5Bw zwqn{u4EGTGb#d`!?MfwJQ+(Zqs53hb?|}ocf1r|Cq12>qYfEcGbET@u9K^ogDVq-6 z15)B)>;Gs(V>aJk5gd9GEayN)W?`ZY&{`Ri6P}xQ^i2ok53w<&+XxU3$aW#decl}d zEb%b%VZxW_hR5YBnBy8Bx9finI6}6ukC=@XgM-=pGaNcUN{je0KVO@PC;@Mr%;dd; zBllF0RVcq0Xy@dd)n_@*7b}g_z%1EC4n&f~8>aHZg)FA2<$|5@Iw-D2Qy{fORNSjn zso#0cjaP0j<>L**(#|Buoe>RrwoywF+n|bjNqlUrKVNMUNP}CJM+z(P!!%s*DJ-t$ zK7*cWI)8sE2uiK!5xAqie)40^VIp0oKOBSnQXYig7z=H_)(ETypnvK$MGf0dHK{8l z_*%pla3lQvUUDd?g7b)&-WS)^C;xdqKkyTUpRsa)p)f-o={^<~mOKg-*xv>OO~VhW z@K=5qbrlM6K|u{3M$=_|3NFbB$C8B~Ki>Awf^?74@zCI4F8lJDwc<;YO&JV}CuYy@ zucR{Hs4l)GNx(c{D%t1F8-uI5)k2yx_-zv`ucVQJ+31WXyv)qU!^H>3t1+|{1ebm- zU#3^tvYKk2oNSBy_ueZnYwn$MC3dN>4@=#t)sOnb;$0;O5Tbn7!?~2X(Fz`YvIF0$ zN50F~XlWG(?S_ghzgKu2yQbE3@}1F43e*xCsdCP`?Z=#3n7+HmLqV_@I7_B)wzs#( zZ>o@vZuZNB5EDTj9t6|?$C=hkJHs%xAtoU)%eFym+JCJXhg2nob$rQ!+iLpusCfQ6XWK+>M`4Ts*70jja`tvh)?O0aoW1OwC_4(U3;jzu4w?CMk-y_zoNTFm{IYdz!efE^Rmabn7e6=+W0I06*jl4N;b8xU(98SdJIj?7x|*zt4~?5X9m_jA zj}Zii;PbDQ<7JcF0S1DcX=;4!BWQIm)WvvP&V+ncEZn1216kljOXwWMn?ZJWSG=H! z_+B%Luxk1j#5z#fDJ!-f;CzjXY6hlwGbk<{N*EG8C>`eC#mA)aHT1Zslao|idS~Zq z;Wm!;RUOb&;46MmKK2NjnLQF0=;{0Bz33Qkj&4alxL08tRk$A&MNDEb?ws_$F}!Ea zpiLPNXW!cn3$h`|$;lV?0`EE$J4{Nx)>fPT)257$j@Dgrn{Y=tBlKYg^c*UFC^ND~ z>?dm9giV2@L4Ul9{4xWAalM0o*B|R@V?_ zHL1h>DiXk@BdCc@%O(QUqD`6Aa+@pBNEoFpX~r@^xpasyL|wCt&k(Skq|0-WxF-1B zQT@Ze^1a7>%W7Wcj)3OMDJY9%xBTadGeCb0QdK7>r`A|(A{v_8 z9W2VoX|CejnCR%H>AM=w%_K0fEGpo$G|1p|9A({cUa0|%+H}3c75llOFAIIfX0h%H=(Www9@ES{B9V%NC&KED-^}A8 z=gu`n9m0L_czf7#-xk5jI+B~|;(|VFw>p7+Y4Uizw_GkZc)lU{_Ui``dbA6H^xou2 zDk&8T=2v+y`#~P3a18=)nFBYT@uESmh2Z~T@2%sa+`7MEOi*Gd=~5&Nx`y@$0)mJr zC0zoN14x&Mgv6kvNC`-nv~+_gA>9li3_Tzn1MeO^&&_zw{d|6L-@niMzR%}5e;m(s zyk=iJ)?RDvwb%N7l`m;t>jW7mt>QJHibhZ(%#N<)(QZ6Nv)ZM!4DmLCiwz{%6itQ% z5QxS8xTdWwPmt~InnCnMS!v*JRh|z3X@+mkK6!p{?&orV1J#SH3wO~2D)>`K%H=~h zrTx3+LYz~d4TbMnMKrTX))K3+yxMMTl|=+SGzNT3 z@$~zCBXGVhIh=|%W-RlHU1F3UrA`L~mIfn|8U{(fofl!`&H4kTi8_Wk%L zH46qRDq@g`c0Y$J&G$vb%0L=KK{OOf@htE4uC((aI4%Q&sBs8Xv6MJ78tu{4 zCHXayH9*+j1bUe-wmCgMT2o_!i%^|t zFnnrirTQ`@^O5Oj$eZX zs`_MiirrMk8g{eGHzx7XT+B2DRO4G4+N#L0`VCbsNQBc_p9dm5_g(PTA6YhL^nt8Cs8qCHY7p z%QLU3k(0L*gG15?*V5LTC_&Yn$7Fv@H{g#(MV+^xX?;a@&2dJ|`8Bh-Mamu5eSQ+U zWz)#_^N725=em(nAE;=)6b{0(PA}NHXGm5)94JFjyb^aa>Gsq_k&!xtg{KEBFFzfy zS{elGFcSgkGqd$ZYlj#`UEM%3zEi7qAq>D}M`qP^m&hV02P`fN3f5g8vmB>kW{_wv z8C?Z87>Y9xe7E(DiX6*ji|lIgdTY^rh7XBSKqY=S-Em5{_+ukLUb_R3-0=trOOAB? zn&`Z|ym+ie_?J+A6r9@Zn4;D)an+dqq%T3^U;emy*J`{%6<|L-MwEe)qTJd_;3lUE zGjhoNp-MOJq;Y?ze|)@S-(`0#spN$s0I%fel-e+LElV%Iwj%mUt%q(41XF0Kpa5585C&b9E^>P-SqSGTP{s8nxUBr=>7JsZiE!r=gnQWQy2v# z4lMD73mkonDRz6cq(vqIfeXDwcW&J(zC`NN&=?(9JZ$soiNbNxN>RCRbn{~5@gra^ z=Exz+qUX25!wU7zp1Tw}(fX!g&?##R!JpUEq+4Z)0dTDW1mE$s?&ya~ha8pNk+D>O+X`fj0TK z+cx>zAD)I?Oc1-)H@k}{4{y$15B6DI<)1Bh9XDD2=jsFJ<&U1rCB0`zk#Y}ut019_ z$k7l=28r#WsF&<+D{w|7aP2^L^<&kfPDs`Ym8qV~rOP_PZreH5GbxB;vlYGBIORL6 z<|$tQNAA3n`V2TUcFOah4Jp-O<(ARL?ja?spVf)0=T6)>J$H_v!odDy2;(VloH0 z3+|*+CFYME0tqqapq|&eeM3VTJrFJB@T|NH1~N^9%A%r2j}nVD9YD%di9ZZ@^A5o0 zWG?{MW^OkIddvCSi|iIv^wzs&&2P5}A;=$;kY^>Fp8EVAsAfWyYsjVi{+DE7v?lEj zv@VE%+fq>GcRDboU0rWBs7X3JuQlNM{sUhwhvC*0qqiS_np^yM89_Ng}ub)5TvG6=T_E;Gau>Jm-L|ILZ_0=UO)I|JRLpQk0XLq^f z1fau1o7mu{W0Z>z!jh`L=wDqOmKI|sX0#zab7olc2JIV5>6H);;BzIfTn*$_Hn<5~ z$f4^jZ#!ycXdpU9wZ|U3w9$Opl~I2TmIftgB~62yF0c@2BiLa1+t-+JbOv6Unx2wc zDO}{LZNFsN)oBtLQvA`yokiwzZXJN@fuoW{8n-mDH9AQ4D6$)K2_F5~voC zKgeze75CCA5vyGS`}D*e>e|=oNL22|UY{|~wUjO-DPc^9HGPQ3An=1khM~qrxbV8wAkn6P)K5G?GU^kO6j|5V8u&gU%}&W##2jfG`kWlkj`#<-HA` z<^rR;DXkK{njF)WsK8uRl>`Y6az?K>Q$-a?7}Fo^v6NTc-Cx6u+;;^EEgxq<9j@O2 znb<_Cp9(KBDJ4?8Qj%z+l#+U!oWlILuTMJgHL;}50X$$gS73F0rfpzpZGA?2eWmQq zz!3&%1;FM&UG?Syf#xc(P_O#j>4^3a_SjdLE*VU2F1OEAVQCjk09WhDfe%XE{5&Tn z5|~P@f-dh_8ixLX)}|u9)eoQRBqUW-EKsvu0MW(uJ>=fz_#cBlTbj;?(8QN&**T>K zQv9m-_~zGfKtfqWMCU~GyhkSpgFmD@lclD3>B)jelqaQh!?~5?y1KfIV2?yNq@I?jjg;2<0Z6r8Z)I)Gr5fR9D{o+THU==oa^Rds6K+*NNJGmKtyksz z<~s75=VcUd0@B^Jpn$W^XXXXqU0a`Fa%EUU~lu*_+6ImKQ#H10`Ort7XN- zRUfbD*JBvm#5Bhlp>R=T+`EuA4e7J;hNooBSU#MB*85%X0VI|3cTRtZk~e>$uNs+E zyLPY1E@cod| z4pUjy@C8@WXPf6gm=sZ0uW-LPz`>EW;c;D(cxr3gErGK(0flmkP;myXR@6*o>*lk; zeibzSucng8@{9&Mx)P7{6wW7;+2rTtRfq?W#t$SkS>fO$m$f#nhK#H@Zr;lGz%0C zp`AK}ih29?BhM>RaoEF5m4=QE#bsBhxOfQ(&TA+*7#18PgKCS{ZN|%IaH>T2+>bhH zA=3Ws?VX)|TzWM_zbehn%F6f|gYssPcp@$?u6zkph)fC+Ve8^TU1=>QEfm@9OM~2NgTwz=Fsv%4BS1n?nNr*N3+X+m1EQ5U*L;dbS5R<~fA|Lex?1v4`s zQv-x(Q=l}LQBwbztu0A4Nn08Y&TD-{trv>Ud~I`c(|>mM$><@jK0qsq_&STQc6T3} zNF@1X4u468zOnJu<>lqW+;8*S+k!bcIWM1yfczb-_$*i;P$vDl3n`VUvKV)(2Ebar z>o9=|3tz}pyAhX|=nov*j{xaqU~o{XM3b<$xA$_S{P1comSX=UHdt2p*SE3$2WCRC z9&vu|0PO#PSvu@zObgi0nEAkZ#!M;JBc?$7FF$uR{mTcbsj+{688!AZW(Zi%fA8;K ze_qY^mk<8m{$kA^AZ+{>=lA!YV~EeNn=j_ZF1J5wozRhJbujk8(JkQMm)6H84QdN~ zf*+=d$H(VGXJTSfTx52UkIz1b8?A^|v(S5IZYsd%_|!?J%b#stq6`(|mc8GI?g#tP z>$L2<-{kJU`drBU`|n-Ipgq3};=la-C6V>Ftx)&ofAsm5=UF)a?|bLp{QQF%_Mr`X zbpZqOzxDYwqc^kSZ`=Lf{QUe7kM8O3`rzO24BMNne5vO(&S4rEnYyojPYnA)5+j&+ zZzo-_=IymF3E+agw}yS;`?&#+?$l{kX9leIOfG}@z2)HWSflX6qMpcB-#{|K?=5}y z!3dQs!|+Z07f39= z!&Go?)qVKz-3gE}+Cq26w%4L-30?|KXk3ywa#q}(i(OyqRjTyms-?q6RhNlWtu@Gf zLT|6a4%fd*xw&l-AwX*H;~~?;7T7{+<;#v(+{RcNxSx{5V={o@VratH+dIQ|e6(D| zJeA<)+VF~v6F($GRdjhjKE8iyvsbIp2eR#pOw<#$&s|t}1#TCQtBwY8XZSo^=3*kJ z@+vDD@3L_~6cqu?p%`F!ei?a#wqe-R>7_rzBBV=Pi1dKl9)<9dqy``pyzU1p#^A8M zzP3G@-H@gzHPu2}+30y7;5Ra2hvGUJ_Rmqz-chpNGNMU4hO?;7Qe7gv7!!9EPaNNhD%q7p@EM=@@ib~(v$)U%jW4?%}+Y+YM`>&IK?%?>@o|9><***f2HXPA@7Fp|h1%a0UzCRsp@7k(rq_ znc!~}szYJHI*?0?=g%-gcmDk1Z6hO9upR+qnI>tsR|*vzhHPqEV6F7x1*o=>O4RBW zC)PeFt&d&Tj1t zKG88U&*I3mJy;okoR2UHO>NtU4zrJLb#&l2lp##cTN%F1{+8gMp4b^T06;}j$_D~^ zUx$geyn1kF%Npyd2{X>V{z!i*h!s(+5X7HSm+BScH%j8O@Y39TuK2|wmks?+hj;I? z!ZHPIYGNE7u$*@b^B99kncjB;x3qYY$8qKUt&EJFuIPGPHV=5Os~y3J@qOWuj|Lwn zPs`@lCI~+@NADlSS>$N;6LZ!$BMH`b_8=auVV<4mr-hjkaHq?e5+HL^Wh>Fu{1f;(sBWf)?l0*%X_#fPpOGc*!d;J>tUB?jG5eW6G|tW1?Uegk zaGkOz=O=yS2S?e~hAQ)T2etjYXHKS+G_I@V?U@FNUNx){5#MY4p?6G&3$u><$Ex&+ zyt0dN^Q#K8>Q2i(HM?;?Z*ei}67=1lHuhoj9+ zX()Pg;DL?~D{OO=DS?)5>_p>Zq$Y6q$1Hw0@!4~-lV%jLf`m`{0AfjZl?5STKih%W z+}o(fgQ{v#EKAmvxk$<69gH4*Nfy=d62{>2K~ij^{ma^qua$lvU!0K9{Ua-nxVY|` zcM8~-$LgYl4C9_|PGF-(w;&WJ*~yyhrNktmRVVx9r^3n>U7eqpYi-ghC5X|#)qNJ8 z;BE&^SuN^+=F1!Z-RSY`# zVbt}K8+tyae=16=qVfCp=}!^^-iDN2=SJh~$h%1PPe%IF253*KM14OqovYRAaqC{e zIk+JcYs#u0q0cB;pTf4w(O!|#b#sgC`vdWgnxrc4$d(3oko27Ud&oAbZ`UU4l+B+N zU%t;HziJ`K==sUSEvM^Zn7oA6^2SweELF&cYvljZ*a`Q?evH-fh+2-Cuf@<0Ffz5vB3-TdZy+FL9RO zCi(Mp3i^WCj%EzIi`kn#`!zKq$(2fH;kwQSS5sDvLJ5&N7Hwf!#)%e#rCk+ynb&lL z1O#@-;H$N@Lc^`hp_|CQrKP;3n}v1C*Zp$#50)A(u-ybeS-oWG)ab9@x}6Y;c=XEc z(|b%Vt24s4ZBB-6Y!E00``$RUGohsuu@hL=9j-)V+UEgu{3zc!w*MteQc^&e4mXgV z$wRn|#^+5-t?41aO%U$?G#j;gnuu;Tzp_&B$fUr(R+t5#E;k+A>kdSo{o~2WcOFxD zr%YcuL)s?WxHLdWK3jbS@EPgFCi zP)&^OE&N0w|CITrQcG%5sNuv}I2@YHlIgM8&Ee8N@`=a83AiDJng`#c(4tp&ixHk7 zQ^37A9?VQHH7T*Syh(`PRD-lz>Cf(^@uh$+F6R(I#J)vOg?ed+spqQeK8`GCC8RxH z-PN95r!1y4f8u5QoG}ty`2N0m&<`+MG;}!%<~9>zarW_Zb6EgOG@RN26p$TUyMv4i zzpq)b)(~$$BK7p?-QDG)f?yi18fX|GR-w}PGP^G{-lqzbnYZ_*%cre@Lsl{Xg=8iZ zUwfoF88CgR>%wW-lZnJw#O52GSL4_R-0ngt)81KpyZdS2kcSEmrtXo-9|FKwfU(cz9~+p8DaK>2M5ky1Co{ zz$>U9TI%Xvv7FEj-!3n2KpFvO-ej2yfnHrUqfEQuS(=r_URtUAJ;^_>Hp`y!(yXtN zq*bVg=S0;FFMmJ3o;5V8E6_ubf{qY>JK~X%zDa2& z(t7v$dLPku#>d8N+j||hb_|L!l#L7KAy7Y7D;1||4p{xl?Pa%hzJ70G0RU^sHtH#+ z2{EJ+d&bryUHyZ4PW?zp4_DXajcCpe{OW3lZkLpCuVkJTTK{<(wHzu+Ux8~$JrFOb zCrN^ooc6+iwtL=41Wq4&8)JouGZ!G7cAs@ek`E%HR|4QFZ5ndMO-4x_>Kxmd-) zXGdnZ30-zIXK*zeI)p;o_9x9oiVK4i0c|-&m)IQEnbHgZZVflR0RL_?z9NR+Buw0k zt37<8^;XDcQgk>Xn$q~H$o{I6sf;LzPH%Y%y&G7=x#yibMTs4+9B&0WYJb_EWCxf% z{nVl;B~M;ahWFlkCk77SG1k91*GO>ZMarkVJlmsJ#?11b_GAz;WVXv zqf@PDC0F}!Nw&n8!(dYv%k^tF+wp}EVyt4@L*G9-p+b}odnhlX_Xn+}dX+{G^4Lbi zk>A?}Fw2*svVpm!42@ zxjj+x`uABDyKUWono+Ra9y<*Q;vt}>G-_UVp4K06m?nO)WB-Uj^4LWSAzt9+rQp2Y zJfD#9WD>`)r3#adX}+Aq6SoT2p2{PE%?*ObYTwC|Apo z2_Sj0kQ*S91Ki$gP+qT-O@L7kH>nuzGX?r5XUsRfBAZGHm8hT*CT7BMLU`<`N^T(b z2g(`%Mcz4CY8Q#5psx!Zjp5>x=PYS-(g zX7T4w-`}$(y7N+y6F9;)BlClaXa!YTgBf(*YRy>DefFMY?->~}Kf)H%_rBC{j9Q?R zaECte-W#kva+nD-0%^;Qpa7wEZE}7Oxzr;OtEl*-Txhk$n+^{S;D`U(1PSO!T+mtB zU>bqNiw52R>8~kxz^RemLMrguBi;jvdso8@Hs^f}Mv5gb;?Eu5{q&?wkEkqnSKXlh z%Q2m`9$CXk|K%LbJw~a)A6^Vmo?Bi1a2HdljgZRQcbYf3u0r?cgleDurQiSfD5GQz z;=MkAnwy%7wIKpnx=Dao={pkXFMZ{5F|}Gf$(=h!4U4PCQKYmE9LJ`YV{Ud131@*@ zpBvU_+3o^d;|2BO+Zj1=iQeZ;F84%|+0u;NR8b-&JkthGV&ohWu zASTT~dB2Y%eRcJMR4lNT+6>1xsc_R2N9pn17Z*!SmUnY=ZJOYc#NC{7;cSv&>!?}) z&{vG|2e-5vxEol-H6YOb`Nfp>Rp=FPTNel5Fs&YdlcBiTV1a{$)rhJ6@=&ri{Q+qF z;>GI?S&_%rSeDDJnrrb~T$p)n57~(W;W0cG>i*nz-`j)Xe*hktk)1|x5#P>;ZMrbg zdwf6p$jJae&X`Jg5maK~uFx>J&hHm@nHU)8=E2=4g3kyEiqi(U(kv!^{#+2=HvMsW zz$;9UZhxewmLg4{mYnr|m3S~sKgsp$X*;iuP>V~b`B8_3fqZm)abo$I zNP>GOiLC@NR*r%IdA*(lAUZttc>!t{2}T5-IfVv^M^kc@&Mv;C^}qQ#TAftQ5gi-x z*7V6>E&NEFxivp)QJ$8dq_~QL^wsxEl8JKP{RakwdROhpSK1>oZHJ0X!C0k0uKu16 zmTGXl{Pnz`5f_zF?o*}1%a6Z>fMe6bv=_@24lP_i)4GiPif4XceP(y$y3Qj~%|{ z8SHQV7_xU+(^s$#ai9nWEMHO@pI`>H07cxd836>5K+l^^S zGJN0bHz>6?Y*`gup^kAC6}jNkAg{C-<=308B+C=_zZsvhmezry2s+wEyY4Tf`!^$|{AiDkHJW<+b~}O-W=by|^Um&CsQFqca3(-Jx=UO=T45&c+zb;m@G7Z`!Cql) zBI(*Q#5Ut?PtV7GPT{VscdS;@PSK}-ggv_neb>EjEt9wIjmseC#%MWFHGKF77S1%r z*#O!n*QEU|38-l4_pqj0 zxTq%njS&h!^R9ScvgS8%>ral;e@dEQ#X?$a!`=om{|axQ+d^veZQd9$ZTFpK5kTJ(07g-9oGj9cIZF7}E8!9J7o@}yH1 z3dfrARYm5rUKh`uWAqxMdXW+prOs!!43XGnTJZpUk7h?8H{u`W=a=>A6asw`XMmU9}+SJ*e&YqtY*&&Gds<^!WG;uj}EpNAis}UZV+i@E}U0 zUv~ppxQ@M4BOkT!_CjxZ z?>O$UDP@%eww3y|*-ibU0gBPem36?B>nF?T!SBBJRgVZ@&Kdypcn@n3pZ@5)K3(&6 z5)|32cg?xOnm}q&&rwGis6{Xv1WsUa1k$cM`AcvjfG88$KCJyA->ABLC7iNmr@AlR zpHt@@<-2!Z3hh7-7dXoIx>8??W>+37u-^<0J$_KAf8=CXul!^-T5`iSAB4_5Q9j1J zPyg9;v4XPcr<4J*Bt3wSGJkh3EiDarzUw(eaFD4+u46MdyT-`~7_$xMF zd()#$59wT7ek~#WNB#O}&VzEcgp3dmlisveVr-iwUJ0~)RH!KV6(fN7Mwp7Tv_~uuDg)3wmqtoUAYf-JMf^01ziVl^@%q zHvRxCRBv6B^Ks!-HpCfm@&1CHx+sqDp5VvsvL6uWJdS(un(w4$>fiDN8BN`{SXz?W zeas0z_wdb=vcr(q_b7~)#XxF&`LyVj5fYRyr7j*wivuUX=EIYiAA3VQ~Q7$<7a;WzmHz;4u)v%HXuR0UxS7wQ?7n26FaMNf~C^BM5o{b6r63w{^^8u5!SnXLF_9LXs>fL@oEQE2*kV zI0XqPdje2) E{VSIB`SZ*r)!{IxL#c&xG-lsLIIjV8Wyi=Q`$cb{)g_!jMx8J% z-PZQD-}+1|a<*^UM33IYxo$kGOY+9L%jPd`$JCnPKm9q4zwJEqoL8SZ`i z1BE%~nwhb86!1)b-KgCG^5gqJTg*W2ysTn~*L4xo_U~;=l7kyEwoeok6g~mwh6a%F z-uQ-D7K3Vh(h0C&>d@$47BQV4iF#IkoXXovADN zC28;ak5th>Gd2Lt$WV>H@9@ojxy!=byaQM*awRyyO*Q%dr=zfYY@*M!042hkepYqQ~ z2?+)oeyFJEp*!e|h!T7`I{4wdSdr;Ukf-2>pNhY?MJ6{l-)q%~-*I{9hQG`|`vxEm z0N)U{pCj0HMuGD;(K%Ui3JO2qnFs)Yj=8KeFF?9AQBc8MRL7r7kpOsqAO>NNmN`oct|=){zQE)( zDtUriTI5dmdD<-;h9zTA3e@qB~fgB&$ z&~JPPf#{%}hEW>?6B*G30=<5d?h=L9>_adYbHO|3t%AWR z>A+*hYNYtuMamAwzicpN!H@dRfDpdGcS_lv@7v4@qE-*aPw*l|&dJGX1oa66(Cx*R zqbn{k>+!m?ImpUjx`{;iNBmP8QIa5+>(@w$^zT`U{pW!+8~Dznj)VAd!py0 z6BXR5Xk!y-H+ke)!>2&G>r({2udnYM1X}7v8TPl!(wir6~Tvn4q5n?)3RR`bx@neCN zg2kmW4}%$i(db=_@?Bgs|C`qp!Euucq}oEjzLk4SRRg#WPSIzBBH`o7fVhnYe6A0K z_<$NBtO&6Ot}gp1EuK5gKlRWOQ8IjV_dD;oTi{+v7y5Fzwj<|-v zE6aby$h=?H7S6bLyY(r^)&+x(kB|TRpkp<-4?$UY+D!sUkNs!t?ChWBW-v^@F#ccw zi*waV16p*whPR%6i4;eAXvTw5~6dH-ZRC7&-?(;(mIan`IrcV z6q1yVg|v-3Wh=KhQEwcLXaL?s&6=$%psDDczyMG9ffH$2yv&mXAjc-UEQGzd7Mg$ngCtD=G|w8UZ5) z`hm8#dw(maato4R11cSGLi8S0ryQ_S)&dS}fdZ$xrF^07orCT?+3r=@YqiG<=_}y0 zbg{ns`2~1Ohz<=fu4DV5x1TQbUEa_E#6mq2xPae=_itVjh?h=XAY=WY!*nzq#N`K~ zJ2yN%fmWCTe!z{csFi&b7KL_bVC);lz`rsA9XAu8;#m7QXQ z3c;r|c^MWaRnX7HvrMwx^E>sD*m?2h5FD@M`01SZOdYI z_qyb@$?t99V91jg1Xec);G^dr|>38o>WE99^Kio{WH)_@R`2Ha*A_chf zxH*7$R_O1O+VWzGodOt%_UDEv^rDV0!O0iYXWWF+oChX4ep>>hVzkAeh9-_u*A5U) zAH;S*&`IcC9CZ2}+!=cc6lPGu1|x9K=3(tTT>aLvBv zm;?Oqi*UQJNi#6-3#-0nNanvUQpZgyYjg99AnxWgzp_H;wzEnIglTaU&29&@%G!XI zjW1xl`S$G_cl#=CR#p~gWv?or9pPg_M-m!bL0nTG&Al%R-Cx)MP+xfeS9VT_LKA2x26ae4fdEQ>PL zd3_CYk~Y%I4?k)a|1aLZn#x+psMn#7v;f9Jpq2Cxcu|iT>R6fkOjSsS_tHphoxuNfd zXJ(AvB_9!q%36xTIvdzrX)8H@8?$F0S6Tw!0!? zV)sDmyVtBu595hP$qgkf^fAD>g*BaZlX9Pl{7&JZu}%s;%$G%}&f{PYkpTX3S)U5$ z+kem)h0I?Yd(QBm{ONzYAM^G9?VtYl=fm~C|I`2EeEfYXaem1e&T}kjdCn1B|K_ht zO3^a;8CWNAsKEwU8&C8cKaBgkB%n=Q4wJ1E1qmRBk(Cc?}@Gz{Du+_-DVzY$*A9O3B!6w7-MK1?9^&PG80UEgXSYIm(nk1IQ2dA5I zGwt%p?=Zd0$eIPM5@mt1wQfi<+q{C*NeUgNU1|n_4wHBHO6eX$$Z(_~0TTLVn~;+x zsOT>ImMIN{5i9!=2j{%(?UVMv`~X#OGT|VX1Bk*&V*od2GK29yctP&BG6;Rx)!&lM z!8ZCWEBWvJ+b8)CUikm|09^kk2C&;aL9d@d(PBV%{*O-&KILg?N6V3yuku6j$nd_M zH#w6F7>{!F1-Y%jpG2AuXU;*{>V(rF5C*(`HxC@i6XW&QvJ&7OpF{zG0D!Z~NjeO8 z{=Kf@7mwh{J_0#Y|D6VYhg1A7SJM2K3R`|sA!79y6O}$mj0ArH?iWvD*5DZvYQ%aU z=fB(ld3S@hlUu#=XlHB|&t|Wgc3%i~d#~qG2kJkBV5r|je%ou{mTby!27}fABEI_2iq?pcwU^ZTx9${kZXK~G-cvtjgNkrOh1A!UR$lq- zjk>{*o{GMM=ow2+=;9aD6gRU_RqjA&6+ZT8dp?a>==C(=!7Db`ZS0+PyO4|9Ui_;Y z6xc7x^@f$s>TZNlq%9p&(xuKxm-i1zzmZ(cE zs`3e0t`Z+BloEycDt&DPfRU~HP5&_cMHqe;oYS%bC(0ZM4Jf9;79H&TzF#fxg=~LY zBTN@;E2BhJ2*1VJ;+XGB@=?(wRF~d0FiRBfo1(*N>MR_GxR?j~Tiz+KuC1OZuGNgr zlG5$i1M3e1Zu?E{pG|n5^i7|8q+n}OIo*)dXhQHpa1N`XkCkWPA{U$2x>NBpOC)SJ z%2q*`-t*~c**c}PvsU|>sJy@Qs@tg5WIBOds9~#gTl6^f0^KP@zZS1qII1e>bToF$ zOt8)I*88ag0iFl#?i#aXp#C_!EoRx!G;L*Oxnn&#_X zFhI|_WJfpRQgrzXb>#ZXhTQj06zQksq!&5FL40S1k=qoxHVj$1Gwy6rH<~RC-qxse zJ@#rvObczz7sOPoCe=Ps+J&dEHR|nz`ccMfRctAGP9LLL)j9nkT;sG8f=)`#Uv{;3 z$0w53B6VaN>st=#_c+hO!)SJ9!K`_jPj-4*+ha)yG1PUsNqaGYs)Fk2u-mBkR!Q+o zF9y2MsQ?Y9)`^0TBtG)9=R*xOu9c_}h^zh}K#X`?DVbA>6MIDIodV$)*DCbicAq*D zs2%3}nBqj1m^=bxv>{yQ4qFyhRyZipsXIkim!_QJ(vdE6sji#t80ECCj!ucJ3fi@F=xyvd^0}PTD&D`7 z;JdM&7*p}qr>>g_-Db?&R5YMlGP0Lis=;?z(kY|RRg&jz&erbiYmV>cSbi%J1Iwk$_g<0GXm$BzFv zT(8c}Jn;IVf`TW^HY1~YOlS@=K>sS|gr*PRsOp~A3geq=%bCrEHEkLwl9b-5TEFxL zqZX5fB@?x;7q6p-+9v+&><<{P8DCAUd5O)q$!0*aG@6QTzKsynJaNJ(<6zzV{Z zsLNTt1Ge@P$<~;ts6K|H4>nixFjJWe8(f?XL(Oy8FO}UES=Tx0S~K2_PI|Ql@tK)I z;kH<#cf1G`{qz65 z&y<1WhJTJ<`*LC#YIb%P`icxcn|^v?^Vp##>0md?W2a;}6HS+K!?$KY(IBY> zpI$V3V|1pC=2-Aiiv*S)ISW_g^i99to_=&x-@Gve<869akc!5A)b*;2XywCzg{j(& z8pXK>MiK(Mo3Y|&p2QzlL~Q5@#M^nsw-((o}XOJS|~s zhOKKkV<3NXGkxGoM8UC_p8~GpMA^rJm5FX3e5S3m_N&Ep-I5SEs@MbwThBsdA75oq zGkyPl8uLOK9okSyZv}a4yv=>@m9hT(LUxj^UQHER&rYmB$S?GV|JUPRXc@m|ffy=Z zjh>f&^r+u;cb4P!Z6sv*=Fq0gicV&U2!6BGj-G{u(s-@w01`-f*GPWV8wRj zVYGRRY5pHw%fH9iBxoUQa}(0$`b>9GQ<*gFNfU2u5bg@f+eM*KWyh#4mNT-o0%~*R zSksP22lg7{<9iU{Dnk>N;_r5<3sb1`Em@AS?UqYNeVTwX$EH#;w(TW^Gl8r8m}_6Q zbnIZe+)aMfZGQgQmxO&nI&{xMjr@dz_$G1fQXe0qxM0zYYfP-+e2z*r@*c;43DH(4 zf?nag|B<`hsJJhm8>w6J^j;?~Hgd$RNwYme4auRXeYZ`?#&FOFNq<(OYMq@0f6*_C z$iYs6h_U0gSiYz2#`3E%qh9Y{*e?meo>^uyX;iq*U+%mLRRmzepRyVVa zZjo^~JHBo0ThV}2Qst8+55z?H*v8w`*KMX>B`LAS@13%H0EwT!t3!tF%bXZpotk1s z8s_Tk+yQ%Ft9P&vIk!*CVxetg!Bvjjar2kYJ6`Ll=J}vfQrG?C=!~tRVxt7ulQ7vG zSm98F$T32KPeZw5uq!VzXQySjakg-0}qtkixQeu#Bg6gpp`Gn z(MWZ(BBnoVYl6Rw6DHlvJABW~`LjE(+@?--?7)*CU~^waHdVA!($`jR{5Gh-nu;Z} z#r=8eaQw@OZOfnhk7*L*bN8Y>n5Ve*vyH6%4dQ{D!qxwXKyJJ?jVJs<~0_cDaO^&N?iDK;|w)h_jqBOAAPB$<#VoSugd4S?3;gP zWFMOw#u_mm9gEGz-7O?q6k>dcuG28DraH>#4;q3Fsa51}Sxh}JIvRMlWVMnyn4|lu z?CJ%&eglY`U3uT0aYr~{eji^@#PH*)AQzZAMftKeM2~Gxb}fb39CI``X+s-Gnpab z7T{eFhO9Agv}!H6PZ9eNf%K70TNHt9B3_NQ^@y8Tng|_C+N6hjCnr)>9hcqK;^7x# zrk1;&Q=*Qt#2VyTcyg~|$K@Ptc|@h7zyy(sBLsL38s@o-BHcwP$OVgGGC!?tYtm!g zHh0hM&EYT)aU;9S{H8^hb96cP4yyf$@ag((A^C6b;`fi^>4;W2EG?Dp)_A3+*Cw2i zT|X>5EgMRkINl+#`@*QLuA3}Ms`Pc`me#hy{i|MX-*20Jev;*eZ9q=Tc84_5U(V4} z7(dRO4dQvLq6Wb~Ao|e%s_a@M`X-MC`I*b9i&Zf5%;dc|GxO_vaqBh+ufu0;MHAw+ zB)qn@b;{%0YkFE^V;jHpei19>LkkbpL1pihQJJF$2E80IA(SGk2WZB$aPJh9Sdpj) z)^sqz$T5nr58Vy?3n>eunNo-C?{@2IANoY}+`el(?)rgh49^q*#{a`KwYZBR=K%X? zSE2+h%~|+jg+HT2clZ$;Waz@Qei}~av2fM_5@;5Yrx8EN&A{VYn2FM~jq>4W-WJw3 zfzA*Nzo0~o5DDJ+*u79_eei1O;Zlws{xKBF02dO79CKqzgwzg-7C&Ls>l@Zt53b26 z60LT8rK=<$pw0tR@zASTxp@{oEqbq#Dr&jkwKxDYB`0=0{V*kAhx}zLD3gCe?iS;_|Fnr^!sN;FEJV5=3|yclul= zTQQaI1H#ia|E0DvUdtlX|GTf z?+oQ^^o&yKlpWTY(F@)w={Ya8EsRQjw@~ckPV}NBD;!dfat}&#c!mnu^0Li8&V&mk z&Vc<~isY|F)omklb%{F4co_c` z6%Z@&dgcfffNeIixtb%G>&mQZrr5m-Q%8_k8;J=fEdeZmM#TdWSh1tPvrB;jD-fpe zj+cJ^99PfCdP$VinqsM3CRmecu~XWF^=3x*!n+;Z2ig))Z){n(y3jyE%r;GC33r6#ZCCO82Cd(~Gg`FzaV-OPE! z9GIJ4pGsToxa(S=c8UFh?F79GM0w(Te$fRg%veZdnjevv@RSjzh6S!rsiD<>``OCh29B z25MxVGeTntXvHnW$t$!RXKrGR`z+kKt6{GPb99~3H>ydiK4pAy_}ki0s`2DJgzc~I z0;?G1TG{OdQR)ZZK5Xs;Bl)biH1gMxXcSO^U<&(!TtVg>`V_zJA^{=7h4u1i#HcIQ zWjD}5SUvf#hUorHKmDKW#G2Po*_q&r$=n2uwYQ9edGKZ@giE~DcunwgSwyVmib?Z-2dMh{JBm3g&F*xx^M~phP{FR zg?k+wESm7cK|tvSQM$Vk38lM1KsrQXB953WGxj!I&bteC^F5`97u*rQgC&P0GxIQQ$G320eS=%_uRmG5(Wo0HuXS4Pv z+p~%^kM(d}T`S)!CwmYrVGQ(q!W)g!vW?+d%s%@iO=^x0eK}7o?jI*Y)UTtzK_h&o_R(v+|spgWoK9F(24Wcd;fm!ejtf0 z)7sh^0%Y|-tc-dU9Q>uHCp0TJ_e)0y%G%EE%g9JH*Oe*rl;SnWj>;-3I=gZA z`5EHm>43TcFyps^0*;W!mJA3~!043}A0MA&ttfPOeI6JHUqD|xoY-FKzf|st2JRhK zc|*f^HzCHQGfnHHOOVC5dw1%=;Ay1eky*+l)xzP(StM@ag`p?TQ_t&8`K6SU@Qv<} z;y{Jw-xm;^)o+xS-y9wt6+Fc-(f;|fqZzkhuGTY!S&$*P#>ba-ORI^Zl8mCWv-1nI zIDVSnY=yyCW>8V)>#si)eo~K9c$@*Z|J==+!&U5W;$=OIhsMVGww2^PrMQ*S-@TJc zK;PLG|9GyvynIVyqlRcv09aL*=unq9IhpMxr&`>NWcode`Rwrl1^BVxN`t@%q5jM1 zX_LU9pp%`#IKNl5>f*@PKr+`1sri@|p239)X%Hs@ojilVo89wPIH~#h-A4jLlcdXU z!^4*>I6ZPZ$Tur73O%HSl{{r%sxxo=2@M@7kUQ?0*L`GAN0nMvz|&B*Zu zCMn7dbm`Gv0%oulBaD6U-TT0^RCj6%{k5Y*X%|Lk(|LOmvKt)9|0ti?f4${gHqd%Z zhha`xUS4oVgqelq(>hu(pO8T%zldySz22p}yBkaMyy?S0Kj(^xy3zd-v>kOQkjb>> zo$+s>)i0%Qx8;2Gd*y^4QoME2eR!77>r@vuXFoCMKQ{U%->CgUQl0I^h5DH$#$yyn z?8?a~-}$C<7!1$k3+SfKUJ%_49JqaxdMDqPoc)hSTz2&g^!+i}cR8DwNGKP)hVI+e z&!0p4`qba~W@8j8Dl6}KcnC}tizKWMdG2oYDsSsb!&a3CebRf*dA{T&z454^phfSS zqHT8F*DaE17Z(?4@KFm=Ajy-TcKkI^^S&!9)9y$R&Gr3J{B-+Bcx-J$2KKT~ZD_E_ zo{V9&2erKsEw^DR?F)23yECAIDUL1YSYjWHXgizP78Br4kZr4E*y$F2Vl(xjygX|D zyXb|q8u!hntdO(V8~S6piQ4N_VeqK#{NTjI1cvMtlgzVLpv1*{dTDxky3NWz_q6>3 zH*aqP6sblJaNKj@6yt4uZ@+T{>~Z%IzC^P?qV3NcQ%@tz5pw9 z7fxVrJqc|BY~h}IPg8^J(jBpnoX`s2mG?6KN$UIW4@9?|ibX>sBR?e3u7>$sma(>8 zAx4XHW0gU((m%eIt`-4?yT|96=-$44yVcOR&n&qF9k;nggztO0yOR>+;hA>Ne{mK0 zdAMBr@;TOY;G-r;538f2*9Xb*yt0l~|P?5wF@?i4&dFaFN*+oeE>&|sq z?l!+0XyuE^w9qHIp2g44|NeZkX|}40%H0+Dk2G5i6j#84P|PkfU%2qBE~N1LirV)& zRU78*V?+o)?8!s}BjfM3E|1VJ1@`V)yqw|T;R|Oacm_acSoFs>^!+z&(+zd`x<>PU z{_Ci~wVn{bp1uZ5l{I99k_I>VLqi?t0W+vwh=% z(+Y2LN=ne_x~(^7FIa{}MO}os5^;-1ACC-&&^7i+w8rR(tzEC%k;;$n;G+-$^ATC1 zt;P_XV=%%FmMyZ!_3x;uy)qt$u?-d@Q9;4|j$)v1ZytXf zFJ!u6Y;WK7YyFnNqAsqj@ktQNEsEON*zhW!cI46iItPoWuyaR^KWCeT_xPN7DA53E*s`X)P*qH<5T?AXEl|u66fqj z)w;L->=^SbCaZycF=bSF~+^Z@sd+70Rn_X}_OEJH^nCDtQ|!Q59@mmhZ6tDra6 zNc6f6|FUFHLxV(dFzaqrdHFC^Ao2#;+Wr&?Y;cAHep5?!ZN=yt7ges+?mLBQM?N?h z9R*#|?Mr9KO+fvsMh0J6j`Bu;+m%3l#PfjtDB`u?jX6XcT3KbHXIoFhjFaa? zdkp^_tJ$X~=~4F_tFnUWdN^D_VgoKw~X;P<_9hZXE^(qCKM{ zqF+XbrSH0<*9_J{g=GSSFxB32g1l#@A~6MGm*ScBP?vsx)3F~jFx@=yl9pS|XK^zV z#xOlWuySb#rVO{wz8A?iX?%W)^60S1ytGLye|N2Ny(&{HH*KI$S@f{)5;u47tQSa) zrMnUZl6S@nXYM9C9X5Hn!RA53sEX%ct`QomNuI4=-s8EPU0PtstsbWxBYtLKJp`qv zq=Z^`FW6g=__JpON4U@8P@AqI^kwL=wi?r>SH$0*g-*7ojvpL&p_}WSnGh732w{&K zZy)r$S7w@I4L;X;u+}MSVqEZ`JDH466mzht#lzTWGMHmvKoj)fD8{EfL3Hw1$V*jywBn=3gJ(ow?@v2w(DRC%Sf|OpxRC&(GcfEHAq2t;@8Q))LhJv84jtg zlll2>n>p-zI$(}c%=D+1-lNM-pIwv!6RdHW+X)gxMh=MTRlR;o+F*~@jk|S^ip<6V z8s6{MT5YTO^yyR50hS>nIvW^+%0`y()lc*dH4bBn4^dfGwfPDU5SrRur*;7f^tLB#Q)mC!G z+F^>CmJPzCrne^DdKv0Na?qtZGpAxPYV&N-ubj}5u$HnoiE^wVfoIhZyMH%JAY`q0x2d=FKGTYBG-}$XGTm!`G7SD9YY)bq8?z`+dC>MmN7MC^A8M~PAj{?-?>CUJC13P8 zdpf}9V1|iMdCt{CiIVj6>TP;&sn|q{mpX;_-wgxyCO4az0kW~oJq>mB+3=Q6e%fWV zhDeH+XR?5eMRBz=GgW4_C3uPh<)4!9<~X|b!^1b-&wB5z5urM?9)8?iu4)`TyjM$z z_h?F{(_fX8F2|sf{XC9;N+b~~S)yOAVB;O=cz7NixX&`jSQ9A2Q(92U5B?|uKLW>} zOhd0H-{)}8eG(`YmN}7XY(rN*-Fk~E*uMAe^V^Wl=79mtz!9%bEs(@{KxSo%D9qN$ zZdaCkN8){d6sEoZ(`Ng~jTEb~6dRtU2UCG^GI?Olx_rQ+rtMw@<~Q1=`m0Q1w3=SP zQgL6xXRGy~qXT<9LF|Q$Z_;Bq8+$w@S~WmpOE%N-O+rF~Gj0_A?bUsdInZw&JB8gz z=s{B0NspZi;Y~1+wQu-r$%Y73lf6ZWsmxjSj|p*)+viy=Ejy2l<`ivP4tnmZKEp=p zf$s7=hEpFhAaY$*lyj~v>haVEVItIx!5j0}I$9Gj2lL|&J{mXMkz^1FP%=GyKh$i@ zgm^B6Bi;;yyK2qAyz>E5i}Gjj=4bz^5iyg5UR3Zo!6c$TeXck-7AC75)T4zT_4f7xSs4jt$|8zc{D}nK?k58kBXXO(6bApnd;E$ZYmc>2Nug%vs zYe3jkf1YWqd5eF~%x7?(HJ?ZI?Zra5H@dmv`WWdaj( zZ~ydJ5pK`o4Ld8tYDhqmf3cqTEiphd*;x(heq&?Q^az~1*(iU|Z#+!=cBiKM);a+= zDVTdZd%E6ktSp2M&jvT&qL)1v{I8(Hv}6-28rVx%kW1nUkv!*T^xY1A=9fNPR3j$e z;z~l-_8lj}dWDVMA78kykDL*7u{QUSc^=x`1dI_?Fr}R~_YH=~x3fOH5IZ|RyEr=+s^N?^ELIw6#B__^$TsXRNyyPej@H%WG+hVkKJ;g8{GlErvEyc4JyRN zVN>uE7Q}^cJDma+qY7d$J|5y++MArroST{|IbS@|N8Yx&dReceZP&qmlCYFGv~B$; zmX(Hm#C@PB9iQd8(rR~Pu2JoTm9@1xuCMk6PJUh@$(=NrTfl~KtJSyS!b4vf{Itfi z8d5)kzP>(x%dGQQeTY@Qy>GR>D9u`KOvc*12~mT>z$p%$o@V)hIaj&ldo7u#5r+{1 z+#C0zA|m@b<+m35#W~(&b!<|KW`3u{ydRjrpzo==FRR4_`QDl7^j&V;@y*-1YC+fK zeuC3cfc9i-(+g&UT3<|Zjp4Mq`#j%~1i4}np_qLtr{qB63TOklgJWHMcv&^n!#r@_ zV-7}n$?HQhUcHHkFfZ!u>tn5d+^*Erers#u!SbbzMgS1i{{Fbjv4E_c-!lVA9J{l} z5hye-o$U%%$~*+8CT(-g*xF_K5qU==b6MgojYL+Vjm=fyYq;q5D#sY+Y||}y;RL<4 zzqXyrx1e2MCToo^O-E=DESb8R`F!!ZHvJ0@nz-k6TWewYYGoJcu8A^jp=>hmrn%a9 zuiq~avXCnfBuPS=No{wOSZH_x9L2cXPlZ*4M=gL%}PN8?fP$ZHw)*)tY1 zr!x(N^$7C5y&_+0ZeT_hj22mon4UlGpJG?Ddpn`nfHKn3OK^D~z?uuE3!RXgz2+d6 zw_|jLD3GpDq_kY;GeE?4K1#9Z{se`j&;bF_{fx12=T}?$Q>M52N5-S%|5!wDIhC3| zKUy!;Xh_M)%j2;nM)S?J$IQnJ*_P;4x@6}nt}>3)jKh}<&Jap_pNpD2ycw96Tu`9q z!Ytm((rOmE&&O&fdj%8@b z-nd)5JynlqRr~ehGeR0p9UjhOI%`Jw(qzrdWm7F#PZ+G~RqZz-){HfN=8s&hjkwCc zn!mjdG!1wLoxpdKUBaqzeKeR!bfPqy(=Tc{>f)17j@A`^0Khwk>W8hla+-05^{ zgM%|VW;^u%=*WkM859&`L7cx=UkDnYL}^tnP^BMfZ~+ z&JaHH`n5!|T(4$Xh67OXw=)MmTCvob7>FCE^=Zc^`Y>X`#r@MHDewYhI!b9n02 ze!Nm7dz4rTDN`l+Pm_xoPSNq<7XIPG3e= zxUL%}?q;22@Slj71_qx2AD{#fpFGSe0hhm`WjtD%y;5XX3Sl={b7!33d%5yx^ZWfN zWQXbjEk)iS_$)Ss9`Wp*0c1QWMu;E3u<~0X1@w<4oksZFa8c{PT8MXyS zZLtd6Ak$V(K(xUyvO1Liu^ww|S9yeO$I7l;w;tkoAG$l95Z2frN$kwz_1!P@wVLb` zP(M#M$b#A1^>4GY9O*2@^gxOluLXM5lpL+WV6qnuYS1l-;*TlHAD(Q#z=roZhntWL zk;e$r^qp;~Y9?QgJiZE%y?TrFll6*1nhMt$$S?y)z~WE$H%GP+W{i2upu$(%RY}G;iDVY{9Y;U z#S{k|OPGT`UQ+6bw#}>t=e)PG3v^rA-nWAp8D}C4>z4pQI@_yg0+GwKJ#PZj@-QHDn=m9o10R&Lxc`mI(M6>YS zHAsBl2c8VCjrW^y<*`kDEl0h~N%T&)rW5`@W(JCyXy5nVGG8Adh9#H)7?U?86( z{Q?^<{Y}TzQV@${*vux+Z+ z%CBXdNV&NS**hA=7xUT;Z4QiHR*PP{aU6XdRu=rryHITOo^ADOp-E9i<etl_T&2zlq!mza%TLait$3j{5s>Eb1>&FSTtJYUI;!UlKie|sPW6qJ@3OMz*eFGtKieMj#Dymr z-x>5|EfIW_-%y*2cSZ;OP(0_f?n=5zo?SwmpzD&GYl@W=Y%dQkRubYXk6zSHEsVQP z2FVd|05t*nIG)Yi>7{5$AAYk^UVd%lslmoSn(@PWpSMj&1d=3u`EM_2x%}J*xV0rL zw-m{D&;972d{|4v4bLEWg6SmvbiXF|A5)lM3n8z(t=JdGZ)X^>LPJHBIt)}5KDw1~ zRtn>M%61CV4K9q9_LBEpdG**-ct33eTs5?$v~d8c7TPR5S!|3 zC-4~iOWw9Hc?W`_CSU73PT|Ee5waym`2e5iC*k8nr~#TR zxTDA5YeRsw<>Ob7oEIjB(Vu`kO7PkHUGbkoRNOsT|cAb97-vc;l;_K{iFT$_r-VEC|4=d z8@FbfgD(-w%W@3Fsg90f-RkcfNv@Eq8_XxswPE`{DG5O8U#p`2ZO)kn(H<{cIZ7Z+xu(7M zN8Uy3aOqDc2<}q)eW!(syd5iI9%1Sv9V%0#Nz=O11-JmvaqB)^u|BYH@04kzm|cxchZa=Q<*^&)NYlxS@u0UL)qjXDr|DE4#954 zGYTHS5ydz&j8T@zKr^yMIbN(K%#=`(_$%$N@0FrhoPo-Rlm1vyxqWOM^-M-krBBMOP(1 z-@bQ`4KfI%s3sHxSd9$I(UoC7*`ZqBT9m6GsNG9~)er-kB*gh&XJJRD#>@SK)!rv= zpRZQR66f{ajfIDY7wz17dO|i^N;zK00^^!J%CIL2`OJ?SP!CFjHg-a$NWN{QGe12@ zNJ-hkm+GJpYBVAA-_^k*B-;We+NGEef_4*CEuH4^nSfe~vY`Yg&xQxF@=Ye0IajQi z_@Gjdyf_Fs0P9h@`&o56D&&!HH%Y6ypb86NC5ISR!!4j>=s`K z>a8>S#21l!g#EBSV|k1&OkmHKAZPks<0a6NMHSmK)T?F@NWU;m?Ju;Z4g;8KvC6Wc zr{34s2RzRZlahfhB!WQy(pH>gs>vWgbKQOY8n2t#hd>5g4Lq|&wcG|3MczglVn4D| zQx&ha)yy4-O80NCDIp@%*2hIi=z5=aZf6Qlkq~Vw5$yy*lA@Om9C}!`LLcR*Yo7uf z?7Im6f;-HdBqSus)Me)yue;Eaq1G~YcIG-0l)1FIO$5m@rtbYTV-;$G-KCCPiYN*e zx6-hWsUG<$S`0VY()HI(s`b<9QSO3!DlEAU%G@GiN9FMd`gS zG*(Q3j1|r&zzkDhi#ngUF3JGYgtu_S)*&S&=q)ivIb4MhlUn-Z`?3LMA(d$ zMA@i2j}G1s9wGX-djIQ&DG(>Yi3vVjP|=lG0V2G&eZ4mG8V%|09X&lgDkZ=>8h<|% z5>{}lb%al-vFY1W!UJ-5>etvzl2~hYN{U{(MI2lgotbc-XTZYYQ3vgE$9tZ&MK3Eu zCrx;Eun*(x0a^g#bg(_uy3u+*PF=x6bMa^lVqCKtTAi>KJoWSH0b=;lS1AzSq;K|c zvO`WRZ-k!b?jz@vQ}Rs0dKFyAP@)URAw@sLIy_X6tUH7R= zeB{Hqu8uAXQcRXx+OmQuG}F7{v%(%luE0ae#hEvJR>&=H81pUrk10qTu(8xyZI-7c zd}DZwB}(JHD8ReHMnQi1@ zYb}d3s;HE!2R}+%jXd zlR$>mGm^Qq3Gr6%Q9L9LY7+J|ZTI(FcczlQ=80 z?@0+Si-5ynb#RXe8)CEn3GVk4;*-8T)e2pZCG&Cc?g}@}KOfJv~&UD89@0X@vHEk!#Xw_zo69FxD4JGk&YU=k?B@xtYm# z1^mH0UIWQ5_>B_r-dhk^n(75|qHR}`Q;(=GX+|a}CfPsZkJM$z)gedNJ>^h#&p$XeziH^gD+tC>=f))A?bT8K6o#NrAD@wDy9js&V=;2Pu;=~dO!J>vIqx9 zBDJF!Q()k=P1j5t=J2e&3!7m?D1q}jZ!dYe92sOsXzQ)8ZF=mJl6-coYTPB^{@Oom zb5Oj*=!SI_(SSiO-_(^I_YhGJEwP&f{!7lQdN!4;$e#V!CjQfKFpA=CS-GbjQEJ^> zdc2=}JcT)E+d!q0#$z)4XX17GlP6F5t?@e<+K!ee(g*(BSslzxD1~+mrA|?ZIJ-ZW|e73Yy>jOUTpI3Mem*`MF$Vms9X z0_+E$h>k`s&Rw7-2RIJau5r9i!bXbDd4_S81b&#p(D*O$TV0=Hd?KrZFT+bI-)wGaaId@8Yj%7d<)QV9RfAAYTY zWO3k%WJjuO7zNmw7vsnqH*Ta3gZgq`z8kP5)`$EocRzXRYHjTbS^=(laW^qDaC*c| zjM~nG3+ovd-zRtgdSC3>_T6mf*U>UzxbfgM6xYLKnvMD^SVh*CkbuoEN#qCbiy$dU zA!P_x70qka$0w(rf5|FI+0@kZwr2+J+@LF%$g}&FA0fH+$62BP43>dR{>-Ktt0lTJ z(it#CWE`;Xbj^bT!OPF@dUZHqUm{Rf&~@!ic8iKck~Irl7FDT(3NLSAMf5Ox4tD+f zE)9Q?k4=AWyMoaJYs3TE^*j);s2|&eZIE>O)7z>mf|EY`HeOiwLnTeD%t}SB4+e8#rr?vHPlOvJ&A!ac4EI{TuK)l^y) z_WId1;tFwA+|JuPrNL)^l78Uef=!;CoppOjbD6}u1{{JFx*um=(*8+aL-9>nt~OTZ zz+y;6Q41WGBkAcVdhyO8LHo(eU!8fL2GdtC%MRM{Iwx~@@@d_e%botOZj5< zvmjd}NgbjLIAtUzQ^-um(erR#CeKvCg7`GXlt z?u~UTUk#Pn;*H7CpMy3S451Aq{WJ`x-%}e-zck_2p^7NRW{LtSYuQW&H)p#3X|g3W(bgCX>UI_oxU?v#0t>X%pf4QJ4GM#k$WcrKIp@l?H_>7}tGVC%Yudrsz@ zgumFMlA+C$6C@ppe13KAY8PP~?$&HI z?d4w22yKPy$1DZrWe$o5vWrQ?%(JWI(u3m(PTqJV9_y4G&|UwI%8${pgZ~}tY2I5z z53U>#;dl!Lt`B|ObluS7&Z4h!t|D->?I6Y{RM|2TY#}%zp%ZC5v$0_~{%A3{TJU=o z=gJJu+C;eK=kStOStWTi1ai+Ws*-%+G*KhwJDGhZNL}^vTtT#M@o~Pw@%-`1qx#9^ zHqyazz4emPwT@~guP*zwnf=(!tS{@8e>V)3Do{rcZGv0wQ0AO86k4vxzIJ`MZD-`ZjOFAB?}A7#@cvgWK>ijlw!0E4N-t3I3m8}7Zgyw zeED(%N;{E}kOfyaZUtpEEpONDiS?1W%ka_g@q4QICp8OP%Ba;?vIxs z)CpaGqc?#E{vcEfSbY9|@p|2oS3}5=NVO&oqN?3D*+C#>cW@x;#Q8bLa^XT_66q6U zWSZVIq2`Ma8G!`LOuWsx4vz2E$@ZxaSP1852ksq0FK{!o5NAx_0i~w{ly<6L|0}Qf zs6o}-+`O%`bG^vyjT#qCN@*z?Q_%#R-fqxY`lE#H@pI2K`$hoQq5Hyb`&U-1)oz5U zK1HS!kPF2igxq+*T9w}5;Zez+4Xx)Ldb#4HG*RZjqN$~I2VD;j)++AbSuOZcA_-Um zqw(-pYN39`b8~YBx!h-OBbby(H4yhE*~rT@{s-u-@lr-U_SiRO54~yDH!;$dhF+X=i80nF7ihpVQLb z(BX8llSrREM>ub`v_A{EvroFAzVn;Ay5IiYQ;GK2MDvUK9EcnrSXd12I0Kh+iZ+*~ zex^F-C#YJUIB^Nl{|;I$Qm+X(FTJt0R8BvJeZFSgEkifmf$z4@Bh=qFXyCU`EP|}T z)xK>=^Dr1e69gA8tIKpFG2TZKY3Fnm4)xivH|SY4Pq~wi%wf$v#dkVdfxf-Z<2WH9 zMu*1R+dJlm@V_UI4%MJ~CE_Jyk6$F^z&2X@=>bHtt@NRsu>k(-@)}gfEo^O3j^+9x zon2k8t$R)^hwfDuLZ#>=HnG|{|IOb#><0Xp?$@zlklxGH?rdyq6x|(z=J(l6zU?31 zj;F4td?(^YcWOy@Xi2Iorw(+!08 zE!8)^2MZNP8&%P1U#YKUpq&kP6i>go7g(O3V7LB5h}`&0vSG`CD}wOV43TW;BaRn# z?I$%f7K1mXRHsZhc8+}$6JFa_Dyzsz`KCBpB2Mu{dOn=%%al9gtUIbgS|pDt@bnG; zucfx5$3OC@bT&Gi2)}piBahLYkB|MFlD8qYyN)Er$Z~L zo>M!s8bP?Z{$YT``N@~yfEv5Q%l+j+uU;+aKU8+Idx3H4sh#J*_F5k#gb97rR(VwW z-D~Uc!59#VQT$`fuz$AwIHu93sjcwN{|+r}PO<<)ZRqFK*zUeQD)7f|oE4}^CTe{} z;Y2G7vo9SbH8@b;8i{{KvJWSgzOTRkCNaVQa=bgS(8Q{Fl0W@LLHlxVReDQ}Ml4gW zvqC+?VJ!#sn`NhDG5ARJ?#_&%s_N?Ty|Idl3Mvzh`5G06ToUg)L5i@oc=-4w0wm0-YXKg>|UX{FG@yoDQdsc z=g_0(gW>sWnNDZv=t!X5q>TSl!p%jD6BV}M{HRkl-k59FvAiW8vImO)0rC3ysJ_+2 zyvQX0c^)i21I@gG`3pmaR1F}TAj5#8#-z88N{^8537Y*ju?NgcO zhj8bBNIRokHAupP0KK)@hARzh{2KLEt?Qo9HD#QH!G_R2ns$B4x_z168Kkl!yB}=n z7#J8v-t#(lwi4>A^`Il_>7=GOCci#_R6}%b6d?-4CQ@^#ENbwaBUOf)puy@8IYfw3 zkIcsC-AU~BI{tOyq3DG}U(~P3oX(rA*I!iwbQWA>mYZt%16(|+Qw>R;s;Q~b5q`F| zW@|_C6_C1ypXvK`8eSw)JAG5-?!5tAX;7wcm`_BBX*j2d_#Rb#-`i^1Q^1oZXA}Yg zjpfxtuyqPT{C)W?Yq33dc#@$5+EM`qAs#1)`f5J(9;$G*3K)dFR_VG<<|}gTS~AA` zEK*Ip!2i_Mg#YPL>y@sHdklw0oPu6zaxVWYnBO!6)6gK$~Y1E{Sdi?YV z#}W`;Br=CaZ!PxPU&ac^X`jno$GWVq(OVFLnT!uUv>A(;-i>{TK}f+EObEs))clO+ z62kJKGqe5dA2=4KU*MpU*Z5)>^|ZIYeW9gJzHi``>7?Rk#6^u4J+A>HHIr{mycuCs zY%ZT_LglMba)TZ93f*XC-sqkXI1!fp?wD>tLBTNmfN7G`8ptS%DVa@4skJ#iPTQO& z`fW%ZUC-HsHpnOflw^IJ`{ta~+!(ktAEwcJthPQe1hLUp?>eNv-g3g!`W*In$*3)4 zF3TRe_&8JXl-5G8<@Bn?UAqZdfWabJsv6YDkrEp{V+ti-y}s47>1K_)pAb#~(?1x( zJBAL+n@`(P|4zC#w>sfv#xLhOoOaDSTr zzV^I>F%#~;vCJ=%IyIfhsmnKMZFfAlFDWr8$#|eMyR_7GfaIFS89Ri0fLmaxou%b9 zJO&ag?YPGi4;ayW+b8MySSOmH|E10Q!}BYJbs++8BkS>0yHZK)RN8Cb3|cZFmlhWT z53M~tJ@s8rJEzL1Z)Mm^q;IymDsUE=Hj`yqsSTcXVuJ1#nX2lF6OmS-t7REskKD0x zV^;=0WRN1_0H$DS*_Ip&y>@>npgbWKD=QZ0j|I8$UYmHvBmns_PC_U^NmUt6+n?Wl-v6l*#bw zvG>#hv}|h5ca4qdSIN_((*~V-{xC_x?mrq=w$guRK!97;XRON3zI=v(;WDGZHImQ! zdwc%S8IJa2366}To2YU(Ek1-aQ2VmR0?T$x{RMV*PDUhFE9;5DEOh^Ac!%Za7IQkb zkB^VTroPbxlPMSXc0szOq4N^e&raL>bLC)fKZzuK`NlcmE-B7tYDB`tI^yEx<<;Z@ z<0G5*MYbrBpQn8Ch{{tJ1QNUS>V5jgKUMziB6M|ivrxI)?JMVcCMP?qE$opO;zXs( z$;%I#Cm4`}_S?RQgj0&g#nj*Qqy|aeex!*o@gKTtTvzH?Yz$KiH;RUuPlOcr1#9rUC7Aud>+5gWnp1K?1h1ZOHz}D zoiH~C2Zibf)@;9&f`V&>(WObzD;c=TYSGVzuoQZK`2;!rdn&rX}6t)~VrA?q9 zanwY|(z^qRu-n_?SV`6>lKoinI5xRgz+Ape}86O#05)cr0wYIjFClyF% z?vxD*!GRi6GInO`D=RmA@9?xA%?+oQmAL_|h<3^qID%0eznSgBQ>gwm$+UG4VVjU? z&b%vZk2P}(%g|SJ)dnIKZ}mwiQ1ov+{qO)g6=Vy>q2k#A^)e;0XN@l;7Z1uRS7)-z zsps?|So7O_U=uu}yK0PRIF6!HJJJ6P+HHjG;}d-L0zG@b^ISL-`eo7HoCK#9`Ms#u zFj0B0^w}R2D>yifRgc5i6&*qJ(5ZgnpKw@%k z-=&n!*N=rd0N}`hC~4cOU0gLl3Dc�OV8&P(`LPYJMruxbezuMR2_;Onqtr@PnVJ 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\Ii(FZW9xC4?x2KC!>pfLb7}jVS&J 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 From 92f78c40a1cdaa7f0356ea1be7c1fa9833fc8b35 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 17 Oct 2022 14:46:47 +0200 Subject: [PATCH 0892/1520] Add flask signal handler --- docs/frameworks.md | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/docs/frameworks.md b/docs/frameworks.md index cecda40a..b1a7c81e 100644 --- a/docs/frameworks.md +++ b/docs/frameworks.md @@ -1,4 +1,4 @@ -# Integration with Frameworks +# Frameworks To have consistent log output, it makes sense to configure *structlog* *before* any logging is done. The best place to perform your configuration varies with applications and frameworks. @@ -14,7 +14,31 @@ If you use standard library's logging, it makes sense to configure them next to See Flask's [Logging docs](https://flask.palletsprojects.com/en/latest/logging/). -Generally speaking: put it *before* instantiating `flask.Flask`. +Generally speaking: configure *structlog* *before* instantiating `flask.Flask`. + +Here's a [signal handler](https://flask.palletsprojects.com/en/latest/signals/) that binds various request details into [*context variables*](contextvars.md): + +```python +def bind_request_details(sender: Flask, **extras: dict[str, Any]) -> None: + structlog.contextvars.clear_contextvars() + structlog.contextvars.bind_contextvars( + request_id=request.headers.get("X-Unique-ID", "NONE"), + peer=peer, + ) + + if current_user.is_authenticated: + structlog.contextvars.bind_contextvars( + user_id=current_user.get_id(), + ) +``` + +You add it to an existing `app` like this: + +```python +from flask import request_started + +request_started.connect(bind_request_details, app) +``` ## Pyramid @@ -30,6 +54,7 @@ class StructLogTween: registry: Registry def __call__(self, request: Request) -> Response: + structlog.contextvars.clear_contextvars() structlog.contextvars.bind_contextvars( peer=request.client_addr, request_id=request.headers.get("X-Unique-ID", "NONE"), From 3bfb7a0621dec1da1293610d830a414158e975cd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 18 Oct 2022 12:08:22 +0200 Subject: [PATCH 0893/1520] Write coverage to summary Is this markdown? newlines More newlines? Simplify oops Work around sed/tee swallowing errors Don't need the tee Try simpler --- .github/workflows/ci.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0e8705a1..c76dbba5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,6 +91,11 @@ jobs: run: | python -m coverage combine python -m coverage html --skip-covered --skip-empty + + # Report and write to summary. + python -m coverage report | sed 's/^/ /' >> $GITHUB_STEP_SUMMARY + + # Report again and fail if under 100%. python -m coverage report --fail-under=100 - name: Upload HTML report if check failed. From db31d79e5514a1690403550dd7853fb4e392eac7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 19 Oct 2022 06:59:44 +0200 Subject: [PATCH 0894/1520] There can be too much air --- docs/_static/custom.css | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/_static/custom.css b/docs/_static/custom.css index 60c3f275..939ad58b 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -1,19 +1,19 @@ div.article-container>article { font-size: 19px; - line-height: 31px; + line-height: 30px; } div.admonition { font-size: 19px; - line-height: 31px; + line-height: 30px; } p.admonition-title { font-size: 15px !important; - line-height: 20px !important; + line-height: 21px !important; } article>li>a { font-size: 19px; - line-height: 31px; + line-height: 30px; } From 10d4d23ffe5925955437ff0c8ff05ecbe79154e3 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 19 Oct 2022 10:50:36 +0200 Subject: [PATCH 0895/1520] Be more modern --- docs/_static/custom.css | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/_static/custom.css b/docs/_static/custom.css index 939ad58b..5ffc07a0 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -1,19 +1,19 @@ div.article-container>article { font-size: 19px; - line-height: 30px; + line-height: 1.6rem; } div.admonition { font-size: 19px; - line-height: 30px; -} - -p.admonition-title { - font-size: 15px !important; - line-height: 21px !important; + line-height: 1.6rem; } article>li>a { font-size: 19px; - line-height: 30px; + line-height: 1.6rem; +} + +p.admonition-title { + font-size: 15px !important; + line-height: 1.5rem !important; } From a6d297e3370c4a504096d492a3259fe15552bb68 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 19 Oct 2022 11:45:42 +0200 Subject: [PATCH 0896/1520] align --- docs/_static/custom.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_static/custom.css b/docs/_static/custom.css index 5ffc07a0..8be2b164 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -15,5 +15,5 @@ article>li>a { p.admonition-title { font-size: 15px !important; - line-height: 1.5rem !important; + line-height: 1rem !important; } From 1782427a69de7b17a7352c4b995b308ec00a2f0e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 19 Oct 2022 11:55:00 +0200 Subject: [PATCH 0897/1520] Clarify --- src/structlog/stdlib.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index c0ff55c2..32269ed8 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -382,7 +382,8 @@ def get_logger(*args: Any, **initial_values: Any) -> BoundLogger: .. warning:: - Does **not** check whether you've configured *structlog* correctly! + Does **not** check whether -- or ensure that -- you've configured + *structlog* for standard library :mod:`logging`! See :doc:`standard-library` for details. From 850c282ae4c348d902ebb40506d6001ead902a50 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 19 Oct 2022 12:45:02 +0200 Subject: [PATCH 0898/1520] Add OpenTelemetry recipe --- docs/frameworks.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/docs/frameworks.md b/docs/frameworks.md index b1a7c81e..488f0f92 100644 --- a/docs/frameworks.md +++ b/docs/frameworks.md @@ -5,6 +5,28 @@ The best place to perform your configuration varies with applications and framew If you use standard library's logging, it makes sense to configure them next to each other. +## OpenTelemetry + +The [Python *OpenTelemetry* SDK](https://opentelemetry.io/docs/instrumentation/python/) offers an easy API to get the current span, so you can enrich your logs with a straight-forward processor: + +```python +from opentelemetry import trace + +def add_open_telemetry_spans(_, __, event_dict): + span = trace.get_current_span() + ctx = span.get_span_context() + parent = span.parent + + event_dict["span"] = { + "span_id": hex(ctx.span_id), + "trace_id": hex(ctx.trace_id), + "parent_span_id": None if not parent else hex(parent.span_id), + } + + return event_dict +``` + + ## Django [*django-structlog*](https://pypi.org/project/django-structlog/) is a popular and well-maintained package that does all the heavy lifting. From c5ea3d0d8560315e2f5d867f53fbc05082d5805f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 19 Oct 2022 12:49:21 +0200 Subject: [PATCH 0899/1520] Streamline --- docs/recipes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/recipes.md b/docs/recipes.md index ff025641..905f17bf 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -26,9 +26,9 @@ With the {class}`structlog.processors.EventRenamer` processor you can for instan ## Fine-Grained Log-Level Filtering *structlog*'s native log levels as provided by {func}`structlog.make_filtering_bound_logger` only know **one** log level – the one that is passed to `make_filtering_bound_logger()`. -Sometimes it can be useful to filter more strictly for certain modules or even functions. +Sometimes, that can be a bit too coarse, though. -You can achieve that with by adding the {class}`~structlog.processors.CallsiteParameterAdder` processor and writing a simple own one that acts on the data you get: +You can achieve that with by adding the {class}`~structlog.processors.CallsiteParameterAdder` processor and writing a simple processor that acts on the data you get. Let's assume you have the following code: From 0a7320a30550f916453313b0e0969eae3442f160 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 19 Oct 2022 13:45:12 +0200 Subject: [PATCH 0900/1520] Let li ps breath --- docs/_static/custom.css | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/_static/custom.css b/docs/_static/custom.css index 8be2b164..2d725132 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -13,6 +13,13 @@ article>li>a { line-height: 1.6rem; } +article ul>li>p { + font-size: 19px; + line-height: 1.6rem; + margin-top: 0.75rem !important; + margin-bottom: 0.5rem !important; +} + p.admonition-title { font-size: 15px !important; line-height: 1rem !important; From c62752cba0dee110b6c59408e4018e0d4b37d0f7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 19 Oct 2022 14:29:33 +0200 Subject: [PATCH 0901/1520] Add async log methods to filtering bound logger (#457) * Add async log methods to filtering bound logger * Add changelog entry * Save the tmp var * Add docstrings and complete protocol * Add to getting started * Clarify around AsyncBoundLogger * Typo --- .pre-commit-config.yaml | 1 + CHANGELOG.md | 7 ++++ docs/getting-started.md | 22 ++++++++++++ src/structlog/_log_levels.py | 67 ++++++++++++++++++++++++++++++++---- src/structlog/typing.py | 59 +++++++++++++++++++++++++++++++ tests/test_log_levels.py | 59 ++++++++++++++++++++++++++++++- 6 files changed, 207 insertions(+), 8 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 96d5a6df..5b6ddac2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -38,6 +38,7 @@ repos: rev: v2.2.1 hooks: - id: codespell + args: [-L, alog] - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.3.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 4309fac3..614b5c62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,13 @@ You can find out backwards-compatibility policy [here](https://github.com/hynek/ [#454](https://github.com/hynek/structlog/pull/454) +- `FilteringBoundLogger` now also has support for *asyncio*-based logging. + Instead of a wrapper class like `structlog.stdlib.AsyncBoundLogger`, async equivalents have been added for all logging methods. + So instead of `log.info("hello")` you can also write `await log.ainfo("hello")` in async functions and methods. + + This seems like the better approach and if it's liked by the community, `structlog.stdlib.BoundLogger` will get those methods too. + [#457](https://github.com/hynek/structlog/pull/457) + ### Changed diff --git a/docs/getting-started.md b/docs/getting-started.md index 72e387f2..b06941fd 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -231,6 +231,28 @@ To make this common case as simple as possible, *structlog* comes with [some too As noted before, the fastest way to transform *structlog* into a `logging`-friendly package is calling {func}`structlog.stdlib.recreate_defaults()`. +## asyncio + +*structlog* comes with two approaches to support asynchronous logging. + +The default *bound logger* that you get back from {func}`structlog.get_logger()` doesn't have just the familiar log methods like `debug()` or `info()`, but also their async cousins, that simply prefix the name with an a: + +```pycon +>>> import asyncio +>>> logger = structlog.get_logger() +>>> async def f(): +... await logger.ainfo("hi!") +... +>>> asyncio.run(f()) +2022-10-18 13:23:37 [info ] hi! +``` + +You can use the sync and async logging methods interchangeably within the same application. + +--- + +The standard library integration on the other hand offers an asynchronous wrapper class {class}`structlog.stdlib.AsyncBoundLogger`. + ## Liked what you saw? Now you're all set for the rest of the user's guide and can start reading about [bound loggers](bound-loggers.md) -- the heart of *structlog*. diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index 04fe7db1..997d948c 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -9,6 +9,8 @@ from __future__ import annotations +import asyncio +import contextvars import logging from typing import Any, Callable @@ -73,12 +75,27 @@ def _nop(self: Any, event: str, **kw: Any) -> Any: return None +async def _anop(self: Any, event: str, **kw: Any) -> Any: + return None + + def exception(self: FilteringBoundLogger, event: str, **kw: Any) -> Any: kw.setdefault("exc_info", True) return self.error(event, **kw) +async def aexception(self: FilteringBoundLogger, event: str, **kw: Any) -> Any: + kw.setdefault("exc_info", True) + + return await asyncio.get_running_loop().run_in_executor( + None, + lambda: contextvars.copy_context().run( + lambda: self.error(event, **kw) + ), + ) + + def make_filtering_bound_logger(min_level: int) -> type[FilteringBoundLogger]: """ Create a new `FilteringBoundLogger` that only logs *min_level* or higher. @@ -86,6 +103,10 @@ def make_filtering_bound_logger(min_level: int) -> type[FilteringBoundLogger]: The logger is optimized such that log levels below *min_level* only consist of a ``return None``. + All familiar log methods are present, with async variants of each that are + prefixed by an ``a``. Therefore, the async version of ``log.info("hello")`` + is ``await log.ainfo("hello")``. + Additionally it has a ``log(self, level: int, **kw: Any)`` method to mirror `logging.Logger.log` and `structlog.stdlib.BoundLogger.log`. @@ -109,6 +130,8 @@ def make_filtering_bound_logger(min_level: int) -> type[FilteringBoundLogger]: .. versionadded:: 20.2.0 .. versionchanged:: 21.1.0 The returned loggers are now pickleable. .. versionadded:: 20.1.0 The ``log()`` method. + .. versionadded:: 22.2.0 + Async variants ``alog()``, ``adebug()``, ``ainfo()``, and so forth. """ return _LEVEL_TO_FILTERING_LOGGER[min_level] @@ -122,33 +145,63 @@ def _make_filtering_bound_logger(min_level: int) -> type[FilteringBoundLogger]: of a ``return None``. """ - def make_method(level: int) -> Callable[..., Any]: + def make_method( + level: int, + ) -> tuple[Callable[..., Any], Callable[..., Any]]: if level < min_level: - return _nop + return _nop, _anop name = _LEVEL_TO_NAME[level] def meth(self: Any, event: str, *args: Any, **kw: Any) -> Any: return self._proxy_to_logger(name, event % args, **kw) + async def ameth(self: Any, event: str, *args: Any, **kw: Any) -> Any: + await asyncio.get_running_loop().run_in_executor( + None, + lambda: contextvars.copy_context().run( + lambda: self._proxy_to_logger(name, event % args, **kw) + ), + ) + meth.__name__ = name + ameth.__name__ = f"a{name}" + + return meth, ameth + + def log(self: Any, level: int, event: str, *args: Any, **kw: Any) -> Any: + if level < min_level: + return None + name = _LEVEL_TO_NAME[level] - return meth + return self._proxy_to_logger(name, event % args, **kw) - def log(self: Any, level: int, event: str, **kw: Any) -> Any: + async def alog( + self: Any, level: int, event: str, *args: Any, **kw: Any + ) -> Any: if level < min_level: return None name = _LEVEL_TO_NAME[level] - return self._proxy_to_logger(name, event, **kw) - meths: dict[str, Callable[..., Any]] = {"log": log} + return await asyncio.get_running_loop().run_in_executor( + None, + lambda: contextvars.copy_context().run( + lambda: self._proxy_to_logger(name, event % args, **kw) + ), + ) + + meths: dict[str, Callable[..., Any]] = {"log": log, "alog": alog} for lvl, name in _LEVEL_TO_NAME.items(): - meths[name] = make_method(lvl) + meths[name], meths[f"a{name}"] = make_method(lvl) meths["exception"] = exception + meths["aexception"] = aexception meths["fatal"] = meths["error"] + meths["afatal"] = meths["aerror"] meths["warn"] = meths["warning"] + meths["awarn"] = meths["awarning"] meths["msg"] = meths["info"] + meths["amsg"] = meths["ainfo"] return type( "BoundLoggerFilteringAt%s" diff --git a/src/structlog/typing.py b/src/structlog/typing.py index ca4e8c0b..48c90ae8 100644 --- a/src/structlog/typing.py +++ b/src/structlog/typing.py @@ -153,6 +153,8 @@ class FilteringBoundLogger(BindableLogger, Protocol): .. versionadded:: 20.2.0 .. versionadded:: 22.2.0 String interpolation using positional arguments. + .. versionadded:: 22.2.0 + Async variants ``alog()``, ``adebug()``, ``ainfo()``, and so forth. """ def bind(self, **new_values: Any) -> FilteringBoundLogger: @@ -188,26 +190,61 @@ def debug(self, event: str, *args: Any, **kw: Any) -> Any: Log ``event % args`` with **kw** at **debug** level. """ + async def adebug(self, event: str, *args: Any, **kw: Any) -> Any: + """ + Log ``event % args`` with **kw** at **debug** level. + + ..versionadded:: 22.2.0 + """ + def info(self, event: str, *args: Any, **kw: Any) -> Any: """ Log ``event % args`` with **kw** at **info** level. """ + async def ainfo(self, event: str, *args: Any, **kw: Any) -> Any: + """ + Log ``event % args`` with **kw** at **info** level. + + ..versionadded:: 22.2.0 + """ + def warning(self, event: str, *args: Any, **kw: Any) -> Any: """ Log ``event % args`` with **kw** at **warn** level. """ + async def awarning(self, event: str, *args: Any, **kw: Any) -> Any: + """ + Log ``event % args`` with **kw** at **warn** level. + + ..versionadded:: 22.2.0 + """ + def warn(self, event: str, *args: Any, **kw: Any) -> Any: """ Log ``event % args`` with **kw** at **warn** level. """ + async def awarn(self, event: str, *args: Any, **kw: Any) -> Any: + """ + Log ``event % args`` with **kw** at **warn** level. + + ..versionadded:: 22.2.0 + """ + def error(self, event: str, *args: Any, **kw: Any) -> Any: """ Log ``event % args`` with **kw** at **error** level. """ + async def aerror(self, event: str, *args: Any, **kw: Any) -> Any: + """ + Log ``event % args`` with **kw** at **error** level. + + ..versionadded:: 22.2.0 + """ + def err(self, event: str, *args: Any, **kw: Any) -> Any: """ Log ``event % args`` with **kw** at **error** level. @@ -218,17 +255,39 @@ def fatal(self, event: str, *args: Any, **kw: Any) -> Any: Log ``event % args`` with **kw** at **critical** level. """ + async def afatal(self, event: str, *args: Any, **kw: Any) -> Any: + """ + Log ``event % args`` with **kw** at **critical** level. + + ..versionadded:: 22.2.0 + """ + def exception(self, event: str, *args: Any, **kw: Any) -> Any: """ Log ``event % args`` with **kw** at **error** level and ensure that ``exc_info`` is set in the event dictionary. """ + async def aexception(self, event: str, *args: Any, **kw: Any) -> Any: + """ + Log ``event % args`` with **kw** at **error** level and ensure that + ``exc_info`` is set in the event dictionary. + + ..versionadded:: 22.2.0 + """ + def critical(self, event: str, *args: Any, **kw: Any) -> Any: """ Log ``event % args`` with **kw** at **critical** level. """ + async def acritical(self, event: str, *args: Any, **kw: Any) -> Any: + """ + Log ``event % args`` with **kw** at **critical** level. + + ..versionadded:: 22.2.0 + """ + def msg(self, event: str, *args: Any, **kw: Any) -> Any: """ Log ``event % args`` with **kw** at **info** level. diff --git a/tests/test_log_levels.py b/tests/test_log_levels.py index 509a485b..285dbfc2 100644 --- a/tests/test_log_levels.py +++ b/tests/test_log_levels.py @@ -32,6 +32,14 @@ def test_exact_level(self, bl, cl): assert [("info", (), {"event": "yep"})] == cl.calls + async def test_async_exact_level(self, bl, cl): + """ + if log level is exactly the min_level, log. + """ + await bl.ainfo("yep") + + assert [("info", (), {"event": "yep"})] == cl.calls + def test_one_below(self, bl, cl): """ if log level is below the min_level, don't log. @@ -40,6 +48,14 @@ def test_one_below(self, bl, cl): assert [] == cl.calls + async def test_async_one_below(self, bl, cl): + """ + if log level is below the min_level, don't log. + """ + await bl.adebug("nope") + + assert [] == cl.calls + def test_log_exact_level(self, bl, cl): """ if log level is exactly the min_level, log. @@ -48,6 +64,14 @@ def test_log_exact_level(self, bl, cl): assert [("info", (), {"event": "yep"})] == cl.calls + async def test_alog_exact_level(self, bl, cl): + """ + if log level is exactly the min_level, log. + """ + await bl.alog(logging.INFO, "yep") + + assert [("info", (), {"event": "yep"})] == cl.calls + def test_log_one_below(self, bl, cl): """ if log level is below the min_level, don't log. @@ -56,6 +80,14 @@ def test_log_one_below(self, bl, cl): assert [] == cl.calls + async def test_alog_one_below(self, bl, cl): + """ + if log level is below the min_level, don't log. + """ + await bl.alog(logging.DEBUG, "nope") + + assert [] == cl.calls + def test_filter_bound_below_missing_event_string(self, bl, cl): """ Missing event arg causes exception below min_level. @@ -78,7 +110,7 @@ def test_filter_bound_exact_missing_event_string(self, bl, cl): message = "missing 1 required positional argument: 'event'" assert message in exc_info.value.args[0] - def test_exception(self, bl, cl): + def test_exception(self, bl): """ exception ensures that exc_info is set to True, unless it's already set. @@ -87,6 +119,15 @@ def test_exception(self, bl, cl): assert [("error", (), {"event": "boom", "exc_info": True})] + async def test_async_exception(self, bl): + """ + exception ensures that exc_info is set to True, unless it's already + set. + """ + await bl.aexception("boom") + + assert [("error", (), {"event": "boom", "exc_info": True})] + def test_exception_passed(self, bl, cl): """ exception if exc_info has a value, exception doesn't tamper with it. @@ -95,6 +136,14 @@ def test_exception_passed(self, bl, cl): assert [("error", (), {"event": "boom", "exc_info": 42})] + async def test_async_exception_passed(self, bl, cl): + """ + exception if exc_info has a value, exception doesn't tamper with it. + """ + await bl.aexception("boom", exc_info=42) + + assert [("error", (), {"event": "boom", "exc_info": 42})] + @pytest.mark.parametrize("level", tuple(_LEVEL_TO_NAME.keys())) def test_pickle(self, level): """ @@ -111,3 +160,11 @@ def test_pos_args(self, bl, cl): bl.info("hello %s -- %d!", "world", 42) assert [("info", (), {"event": "hello world -- 42!"})] == cl.calls + + async def test_async_pos_args(self, bl, cl): + """ + Positional arguments are used for string interpolation. + """ + await bl.ainfo("hello %s -- %d!", "world", 42) + + assert [("info", (), {"event": "hello world -- 42!"})] == cl.calls From ec2fbefa39d29a5a9841c4d9744c090350b4fc83 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 19 Oct 2022 14:31:57 +0200 Subject: [PATCH 0902/1520] Simplify --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 614b5c62..2c62e509 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,8 +44,8 @@ You can find out backwards-compatibility policy [here](https://github.com/hynek/ ### Changed - The documentation has been **heavily** overhauled. - Have a look, if you haven't lately! - Especially the graphs in the [standard library chapter](https://www.structlog.org/en/latest/standard-library.html) are both surprising and useful to many. + Have a look if you haven't lately! + Especially the graphs in the [standard library chapter](https://www.structlog.org/en/latest/standard-library.html) have proven valuable to many. - The build backend has been switched to [*Hatch*](https://hatch.pypa.io/). From 10e09b25f8e4ffcf028988ea7bff934409c74052 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 30 Oct 2022 09:54:51 +0100 Subject: [PATCH 0903/1520] Fix preposition --- docs/why.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/why.md b/docs/why.md index 971e6de0..793c4c92 100644 --- a/docs/why.md +++ b/docs/why.md @@ -100,7 +100,7 @@ Internally, formatters are processors whose return value (usually a string) is p Or the other way round: *structlog* comes with a `logging` formatter that allows for processing third party log records. - Don't format it to a string at all! *structlog* passes you a dictionary and you can do with it whatever you want. - Reported use cases are sending them out via network or saving them in a database. + Reported use cases are sending them out via network or saving them to a database. ### Highly Testable From fcf774dd5f5c4110acb55e090e0706955177b81c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 30 Oct 2022 10:01:44 +0100 Subject: [PATCH 0904/1520] Fix links --- docs/why.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/why.md b/docs/why.md index 793c4c92..6cfe4ae1 100644 --- a/docs/why.md +++ b/docs/why.md @@ -80,8 +80,8 @@ There are [plenty of processors](structlog.processors) for most common tasks com *structlog* is completely flexible about *how* the resulting log entry is emitted. Since each log entry is a dictionary, it can be formatted to **any** format: -- A colorful key-value format for [local development](https://www.structlog.org/en/stable/development.html), -- [JSON](https://www.structlog.org/en/stable/api.html#structlog.processors.JSONRenderer) for easy parsing, +- A colorful key-value format for [local development](console-output.md), +- [JSON](structlog.processors.JSONRenderer) of [*logfmt*](structlog.processors.LogfmtRenderer) for easy parsing, - or some standard format you have parsers for like *nginx* or Apache *httpd*. Internally, formatters are processors whose return value (usually a string) is passed into loggers that are responsible for the output of your message. @@ -106,4 +106,4 @@ Internally, formatters are processors whose return value (usually a string) is p ### Highly Testable *structlog* is thoroughly tested and we see it as our duty to help you to achieve the same in *your* applications. -That's why it ships with a [test helpers](https://www.structlog.org/en/stable/testing.html) to introspect your application's logging behavior with little-to-no boilerplate. +That's why it ships with a [test helpers](testing.md) to introspect your application's logging behavior with little-to-no boilerplate. From 111aec93fb8c499c5f9f3ad649cfcdfd64d0df9e Mon Sep 17 00:00:00 2001 From: Bruce Szalwinski Date: Wed, 2 Nov 2022 03:47:18 -0500 Subject: [PATCH 0905/1520] recipe for passing context to worker threads (#459) --- docs/recipes.md | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/docs/recipes.md b/docs/recipes.md index 905f17bf..de0bdb78 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -146,3 +146,42 @@ You can observe the following: These two methods and one attribute are all you need to write own *bound loggers*. [dry]: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself + + +(passing-context)= +## Passing Context to Worker Threads + +When using Threads to process work in parallel, there is a need to pass global information, such as `request_id` to the worker threads. Outside of the Thread world, it is easy enough to use `bind_contextvars()` for this purpose, but how to do the same for Threads? One way is to retrieve the context vars and pass them along to the worker threads. Inside of the worker, re-bind them using `bind_contextvars`. A small example may help here. This example uses `pathos` to create a ThreadPoool. The context vars are retrieved and passed as the first argument to the partial function. The pool invokes the partial function, once for each element of `workers`. Inside of `do_some_work`, the context vars are bound and a message about the great work being performed is logged. + + +``` +from functools import partial + +import structlog +from pathos.threading import ThreadPool +from structlog.contextvars import bind_contextvars + + +def do_some_work(ctx: dict, this_worker: str): + logger = structlog.get_logger(__name__) + bind_contextvars(**ctx) + logger.info("WorkerDidSomeWork", worker=this_worker) + + +def structlog_with_threadpool(f): + ctx = structlog.contextvars.get_contextvars() + func = partial(f, ctx) + workers = "12345" + with ThreadPool() as pool: + return list(pool.map(func, workers)) + + +def manager(request_id: str): + bind_contextvars(request_id="my-request-id") + logger = structlog.get_logger(__name__) + logger.info("StartingWorkers") + structlog_with_threadpool(do_some_work) + +``` + +See [Example of passing context variables to worker threads](https://github.com/hynek/structlog/issues/425) for a more complete example. From 9509a8c24f82e2ebfa70001b5a4d8f6831c64e7d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 2 Nov 2022 10:07:00 +0100 Subject: [PATCH 0906/1520] Semantic newlines --- docs/recipes.md | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/docs/recipes.md b/docs/recipes.md index de0bdb78..76e3a652 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -148,22 +148,30 @@ These two methods and one attribute are all you need to write own *bound loggers [dry]: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself -(passing-context)= ## Passing Context to Worker Threads -When using Threads to process work in parallel, there is a need to pass global information, such as `request_id` to the worker threads. Outside of the Thread world, it is easy enough to use `bind_contextvars()` for this purpose, but how to do the same for Threads? One way is to retrieve the context vars and pass them along to the worker threads. Inside of the worker, re-bind them using `bind_contextvars`. A small example may help here. This example uses `pathos` to create a ThreadPoool. The context vars are retrieved and passed as the first argument to the partial function. The pool invokes the partial function, once for each element of `workers`. Inside of `do_some_work`, the context vars are bound and a message about the great work being performed is logged. +Thread-local context data based on [context variables](contextvars.md) is -- as the name says -- local to the thread that binds it. +When using threads to process work in parallel, you have to pass the thread-local context **into** the worker threads. +One way is to retrieve the context vars and pass them along to the worker threads. +Then, Inside of the worker, re-bind them using `bind_contextvars`. +The following example uses [*pathos*](https://pypi.org/project/pathos/) to create a `ThreadPool`. +The context variables are retrieved and passed as the first argument to the partial function. +The pool invokes the partial function, once for each element of `workers`. +Inside of `do_some_work`, the context vars are bound and a message about the great work being performed is logged -- including the `request_id` key / value pair. ``` from functools import partial import structlog -from pathos.threading import ThreadPool + from structlog.contextvars import bind_contextvars +from pathos.threading import ThreadPool +logger = structlog.get_logger(__name__) -def do_some_work(ctx: dict, this_worker: str): - logger = structlog.get_logger(__name__) + +def do_some_work(ctx, this_worker): bind_contextvars(**ctx) logger.info("WorkerDidSomeWork", worker=this_worker) @@ -171,17 +179,17 @@ def do_some_work(ctx: dict, this_worker: str): def structlog_with_threadpool(f): ctx = structlog.contextvars.get_contextvars() func = partial(f, ctx) - workers = "12345" + workers = ["1", "2", "3"] + with ThreadPool() as pool: return list(pool.map(func, workers)) def manager(request_id: str): - bind_contextvars(request_id="my-request-id") - logger = structlog.get_logger(__name__) + bind_contextvars(request_id=request_id) logger.info("StartingWorkers") structlog_with_threadpool(do_some_work) ``` -See [Example of passing context variables to worker threads](https://github.com/hynek/structlog/issues/425) for a more complete example. +See the [issue 425](https://github.com/hynek/structlog/issues/425) for a more complete example. From 14cb331a62a38c71e4de19d66f75d3a8d3389c58 Mon Sep 17 00:00:00 2001 From: Peter Schutt Date: Thu, 3 Nov 2022 19:31:25 +1000 Subject: [PATCH 0907/1520] Adds `log()` and `alog()` to `FilteringBoundLogger`. (#461) * Adds `log()` and `alog()` to `FilteringBoundLogger`. Closes #460 * Include `amsg()` method to `FilteringBoundLogger`. Adds typing test to typing_examples.py for async methods. --- src/structlog/typing.py | 15 +++++++++++++++ typing_examples.py | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/structlog/typing.py b/src/structlog/typing.py index 48c90ae8..8cec1a54 100644 --- a/src/structlog/typing.py +++ b/src/structlog/typing.py @@ -292,3 +292,18 @@ def msg(self, event: str, *args: Any, **kw: Any) -> Any: """ Log ``event % args`` with **kw** at **info** level. """ + + async def amsg(self, event: str, *args: Any, **kw: Any) -> Any: + """ + Log ``event % args`` with **kw** at **info** level. + """ + + def log(self, level: int, event: str, *args: Any, **kw: Any) -> Any: + """ + Log ``event % args`` with **kw** at *level*. + """ + + async def alog(self, level: int, event: str, *args: Any, **kw: Any) -> Any: + """ + Log ``event % args`` with **kw** at *level*. + """ diff --git a/typing_examples.py b/typing_examples.py index 8437bf9e..c47d1bfd 100644 --- a/typing_examples.py +++ b/typing_examples.py @@ -292,6 +292,21 @@ def typecheck_filtering_return() -> None: fblog.warn("no value unbound because key not defined") fblog = fblog.new(new="value") fblog.info("this is a whole new logger") + fblog.log(logging.CRITICAL, "this is synchronously CRITICAL") + + +async def typecheck_filtering_return_async() -> None: + fblogger: FilteringBoundLogger = structlog.get_logger(__name__) + await fblogger.adebug("async debug") + await fblogger.ainfo("async info") + await fblogger.awarning("async warning") + await fblogger.awarn("async warn") + await fblogger.aerror("async error") + await fblogger.afatal("fatal error") + await fblogger.aexception("async exception") + await fblogger.acritical("async critical") + await fblogger.amsg("async msg") + await fblogger.alog(logging.CRITICAL, "async log") # Structured tracebacks and ExceptionRenderer with ExceptionDictTransformer From 6b06c062dbcd166bfba0da407e9af63432bedea2 Mon Sep 17 00:00:00 2001 From: Peter Schutt Date: Thu, 3 Nov 2022 23:01:15 +1000 Subject: [PATCH 0908/1520] Async log methods: copy contextvars outside of executor. (#463) * Async log methods: copy contextvars outside of executor. Ensures that contextvars are copied in the same context as the caller of the async logging method, and then references that context inside callable that is run in the executor thread. Closes #462 * Fixes test assertions. --- src/structlog/_log_levels.py | 11 +++++----- tests/test_log_levels.py | 39 ++++++++++++++++++++++++++++-------- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index 997d948c..501c44ae 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -88,11 +88,10 @@ def exception(self: FilteringBoundLogger, event: str, **kw: Any) -> Any: async def aexception(self: FilteringBoundLogger, event: str, **kw: Any) -> Any: kw.setdefault("exc_info", True) + ctx = contextvars.copy_context() return await asyncio.get_running_loop().run_in_executor( None, - lambda: contextvars.copy_context().run( - lambda: self.error(event, **kw) - ), + lambda: ctx.run(lambda: self.error(event, **kw)), ) @@ -157,9 +156,10 @@ def meth(self: Any, event: str, *args: Any, **kw: Any) -> Any: return self._proxy_to_logger(name, event % args, **kw) async def ameth(self: Any, event: str, *args: Any, **kw: Any) -> Any: + ctx = contextvars.copy_context() await asyncio.get_running_loop().run_in_executor( None, - lambda: contextvars.copy_context().run( + lambda: ctx.run( lambda: self._proxy_to_logger(name, event % args, **kw) ), ) @@ -183,9 +183,10 @@ async def alog( return None name = _LEVEL_TO_NAME[level] + ctx = contextvars.copy_context() return await asyncio.get_running_loop().run_in_executor( None, - lambda: contextvars.copy_context().run( + lambda: ctx.run( lambda: self._proxy_to_logger(name, event % args, **kw) ), ) diff --git a/tests/test_log_levels.py b/tests/test_log_levels.py index 285dbfc2..1a372733 100644 --- a/tests/test_log_levels.py +++ b/tests/test_log_levels.py @@ -10,6 +10,11 @@ from structlog import make_filtering_bound_logger from structlog._log_levels import _LEVEL_TO_NAME +from structlog.contextvars import ( + bind_contextvars, + clear_contextvars, + merge_contextvars, +) from structlog.testing import CapturingLogger @@ -88,7 +93,7 @@ async def test_alog_one_below(self, bl, cl): assert [] == cl.calls - def test_filter_bound_below_missing_event_string(self, bl, cl): + def test_filter_bound_below_missing_event_string(self, bl): """ Missing event arg causes exception below min_level. """ @@ -99,7 +104,7 @@ def test_filter_bound_below_missing_event_string(self, bl, cl): message = "missing 1 required positional argument: 'event'" assert message in exc_info.value.args[0] - def test_filter_bound_exact_missing_event_string(self, bl, cl): + def test_filter_bound_exact_missing_event_string(self, bl): """ Missing event arg causes exception even at min_level. """ @@ -110,23 +115,23 @@ def test_filter_bound_exact_missing_event_string(self, bl, cl): message = "missing 1 required positional argument: 'event'" assert message in exc_info.value.args[0] - def test_exception(self, bl): + def test_exception(self, bl, cl): """ exception ensures that exc_info is set to True, unless it's already set. """ bl.exception("boom") - assert [("error", (), {"event": "boom", "exc_info": True})] + assert [("error", (), {"event": "boom", "exc_info": True})] == cl.calls - async def test_async_exception(self, bl): + async def test_async_exception(self, bl, cl): """ exception ensures that exc_info is set to True, unless it's already set. """ await bl.aexception("boom") - assert [("error", (), {"event": "boom", "exc_info": True})] + assert [("error", (), {"event": "boom", "exc_info": True})] == cl.calls def test_exception_passed(self, bl, cl): """ @@ -134,7 +139,7 @@ def test_exception_passed(self, bl, cl): """ bl.exception("boom", exc_info=42) - assert [("error", (), {"event": "boom", "exc_info": 42})] + assert [("error", (), {"event": "boom", "exc_info": 42})] == cl.calls async def test_async_exception_passed(self, bl, cl): """ @@ -142,7 +147,7 @@ async def test_async_exception_passed(self, bl, cl): """ await bl.aexception("boom", exc_info=42) - assert [("error", (), {"event": "boom", "exc_info": 42})] + assert [("error", (), {"event": "boom", "exc_info": 42})] == cl.calls @pytest.mark.parametrize("level", tuple(_LEVEL_TO_NAME.keys())) def test_pickle(self, level): @@ -168,3 +173,21 @@ async def test_async_pos_args(self, bl, cl): await bl.ainfo("hello %s -- %d!", "world", 42) assert [("info", (), {"event": "hello world -- 42!"})] == cl.calls + + @pytest.mark.parametrize( + "meth,args", + [ + ("aexception", ("ev",)), + ("ainfo", ("ev",)), + ("alog", (logging.INFO, "ev")), + ], + ) + async def test_async_contextvars_merged(self, meth, args, cl): + clear_contextvars() + bl = make_filtering_bound_logger(logging.INFO)( + cl, [merge_contextvars], {} + ) + bind_contextvars(context_included="yep") + await getattr(bl, meth)(*args) + assert len(cl.calls) == 1 + assert "context_included" in cl.calls[0].kwargs From 465a0c8aebce89b1b50a66535ee2024583fa70fd Mon Sep 17 00:00:00 2001 From: Peter Schutt Date: Mon, 7 Nov 2022 15:28:09 +1000 Subject: [PATCH 0909/1520] Updates __all__ to include all names in testing module API docs. (#465) Closes #464 --- src/structlog/testing.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/structlog/testing.py b/src/structlog/testing.py index 92e25406..1884ea26 100644 --- a/src/structlog/testing.py +++ b/src/structlog/testing.py @@ -21,7 +21,15 @@ from .typing import EventDict, WrappedLogger -__all__ = ["LogCapture", "capture_logs"] +__all__ = [ + "CapturedCall", + "CapturingLogger", + "CapturingLoggerFactory", + "LogCapture", + "ReturnLogger", + "ReturnLoggerFactory", + "capture_logs", +] class LogCapture: From 0092bc56b099ff5b3a0379222a67cd5b29c96fa0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 7 Nov 2022 19:35:27 +0100 Subject: [PATCH 0910/1520] [pre-commit.ci] pre-commit autoupdate (#466) --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5b6ddac2..41e17da2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,12 +7,12 @@ default_language_version: repos: - repo: https://github.com/psf/black - rev: 22.8.0 + rev: 22.10.0 hooks: - id: black - repo: https://github.com/asottile/pyupgrade - rev: v2.38.2 + rev: v3.2.0 hooks: - id: pyupgrade args: [--py37-plus] @@ -35,7 +35,7 @@ repos: exclude: docs/code_examples - repo: https://github.com/codespell-project/codespell - rev: v2.2.1 + rev: v2.2.2 hooks: - id: codespell args: [-L, alog] From 0fa57d67b57bd2644da8fead602911e7ad204af6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 16 Nov 2022 15:23:38 +0100 Subject: [PATCH 0911/1520] Update sponsors --- README.md | 29 +++++++++++++++++++++++--- docs/_static/sponsors/FilePreviews.svg | 1 + docs/_static/sponsors/Tidelift.svg | 1 + docs/_static/sponsors/Variomedia.svg | 1 + docs/index.md | 1 - 5 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 docs/_static/sponsors/FilePreviews.svg create mode 100644 docs/_static/sponsors/Tidelift.svg create mode 100644 docs/_static/sponsors/Variomedia.svg diff --git a/README.md b/README.md index 3fcf3797..ca75671b 100644 --- a/README.md +++ b/README.md @@ -42,14 +42,37 @@ The output format is just as flexible and *structlog* comes with support for JSO [![image](https://github.com/hynek/structlog/blob/main/docs/_static/console_renderer.png?raw=true)](https://github.com/hynek/structlog/blob/main/docs/_static/console_renderer.png?raw=true) -*structlog* has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio*, context variables, or type hints as they emerged. -Its paradigms proved influential enough to [help design](https://twitter.com/sirupsen/status/638330548361019392) structured logging [packages across ecosystems](https://github.com/sirupsen/logrus). +## Sponsors - +*structlog* would not be possible without our [amazing sponsors](https://github.com/sponsors/hynek). +Especially those generously sponsoring us at the *The Organization* level and higher: + +

    + + + + + + + + + + + +

    + +

    + For a limited time, you can add your logo here for as little as $50 per month! +

    --- +*structlog* has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio*, context variables, or type hints as they emerged. +Its paradigms proved influential enough to [help design](https://twitter.com/sirupsen/status/638330548361019392) structured logging [packages across ecosystems](https://github.com/sirupsen/logrus). + + + A short explanation on *why* structured logging is good for you, and why *structlog* is the right tool for the job can be found in the [Why chapter](https://www.structlog.org/en/stable/why.html) of our documentation. Once you feel inspired to try it out, check out our friendly [Getting Started tutorial](https://www.structlog.org/en/stable/getting-started.html). diff --git a/docs/_static/sponsors/FilePreviews.svg b/docs/_static/sponsors/FilePreviews.svg new file mode 100644 index 00000000..2fff3aa3 --- /dev/null +++ b/docs/_static/sponsors/FilePreviews.svg @@ -0,0 +1 @@ + diff --git a/docs/_static/sponsors/Tidelift.svg b/docs/_static/sponsors/Tidelift.svg new file mode 100644 index 00000000..8b4da42c --- /dev/null +++ b/docs/_static/sponsors/Tidelift.svg @@ -0,0 +1 @@ + diff --git a/docs/_static/sponsors/Variomedia.svg b/docs/_static/sponsors/Variomedia.svg new file mode 100644 index 00000000..90e750d2 --- /dev/null +++ b/docs/_static/sponsors/Variomedia.svg @@ -0,0 +1 @@ + diff --git a/docs/index.md b/docs/index.md index cdcda822..f0d9e2e1 100644 --- a/docs/index.md +++ b/docs/index.md @@ -11,7 +11,6 @@ Release **{sub-ref}`release`** ([What's new?](changelog)) :parser: myst_parser.sphinx_ :start-after: :end-before: - ``` If you’d like more information on why structured logging in general – and *structlog* in particular – are good ideas, we’ve prepared a [summary](why.md) just for you. From 56b554d102d03ac1e139b604a83fea502c8e5872 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 16 Nov 2022 15:32:01 +0100 Subject: [PATCH 0912/1520] Use links for logos --- {docs/_static => .github}/sponsors/FilePreviews.svg | 0 {docs/_static => .github}/sponsors/Tidelift.svg | 0 {docs/_static => .github}/sponsors/Variomedia.svg | 0 README.md | 8 +++++--- 4 files changed, 5 insertions(+), 3 deletions(-) rename {docs/_static => .github}/sponsors/FilePreviews.svg (100%) rename {docs/_static => .github}/sponsors/Tidelift.svg (100%) rename {docs/_static => .github}/sponsors/Variomedia.svg (100%) diff --git a/docs/_static/sponsors/FilePreviews.svg b/.github/sponsors/FilePreviews.svg similarity index 100% rename from docs/_static/sponsors/FilePreviews.svg rename to .github/sponsors/FilePreviews.svg diff --git a/docs/_static/sponsors/Tidelift.svg b/.github/sponsors/Tidelift.svg similarity index 100% rename from docs/_static/sponsors/Tidelift.svg rename to .github/sponsors/Tidelift.svg diff --git a/docs/_static/sponsors/Variomedia.svg b/.github/sponsors/Variomedia.svg similarity index 100% rename from docs/_static/sponsors/Variomedia.svg rename to .github/sponsors/Variomedia.svg diff --git a/README.md b/README.md index ca75671b..14af70eb 100644 --- a/README.md +++ b/README.md @@ -50,15 +50,15 @@ Especially those generously sponsoring us at the *The Organization* level and hi

    - + - + - +

    @@ -68,6 +68,8 @@ Especially those generously sponsoring us at the *The Organization* level and hi --- + + *structlog* has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio*, context variables, or type hints as they emerged. Its paradigms proved influential enough to [help design](https://twitter.com/sirupsen/status/638330548361019392) structured logging [packages across ecosystems](https://github.com/sirupsen/logrus). From 910246b6d11ab0dae837fcc1d4a69824d6fd79e7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 16 Nov 2022 15:33:56 +0100 Subject: [PATCH 0913/1520] Better wording --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 14af70eb..a58dfa12 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ The output format is just as flexible and *structlog* comes with support for JSO ## Sponsors *structlog* would not be possible without our [amazing sponsors](https://github.com/sponsors/hynek). -Especially those generously sponsoring us at the *The Organization* level and higher: +Especially those generously supporting us at the *The Organization* tier and higher:

    From 8c88a1c79ea6e7ab9dae2517f453c5e52f64100c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 16 Nov 2022 19:17:38 +0100 Subject: [PATCH 0914/1520] Update sponsors --- .github/sponsors/Sentry.svg | 1 + README.md | 4 ++++ 2 files changed, 5 insertions(+) create mode 100644 .github/sponsors/Sentry.svg diff --git a/.github/sponsors/Sentry.svg b/.github/sponsors/Sentry.svg new file mode 100644 index 00000000..fdb774a0 --- /dev/null +++ b/.github/sponsors/Sentry.svg @@ -0,0 +1 @@ + diff --git a/README.md b/README.md index a58dfa12..263fdfa2 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,10 @@ Especially those generously supporting us at the *The Organization* tier and hig + + + + From b56d49f346b8051be4fdec798e0f6fbae35486ce Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 17 Nov 2022 08:05:52 +0100 Subject: [PATCH 0915/1520] Pricise wording --- docs/recipes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/recipes.md b/docs/recipes.md index 76e3a652..76d80f8d 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -28,7 +28,7 @@ With the {class}`structlog.processors.EventRenamer` processor you can for instan *structlog*'s native log levels as provided by {func}`structlog.make_filtering_bound_logger` only know **one** log level – the one that is passed to `make_filtering_bound_logger()`. Sometimes, that can be a bit too coarse, though. -You can achieve that with by adding the {class}`~structlog.processors.CallsiteParameterAdder` processor and writing a simple processor that acts on the data you get. +You can achieve finer control by adding the {class}`~structlog.processors.CallsiteParameterAdder` processor and writing a simple processor that acts on the data it adds. Let's assume you have the following code: From 270875a48fbb8ff59302f6920e1079f04797b2cd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 17 Nov 2022 08:07:46 +0100 Subject: [PATCH 0916/1520] Even more precise --- docs/recipes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/recipes.md b/docs/recipes.md index 76d80f8d..c3c08334 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -28,7 +28,7 @@ With the {class}`structlog.processors.EventRenamer` processor you can for instan *structlog*'s native log levels as provided by {func}`structlog.make_filtering_bound_logger` only know **one** log level – the one that is passed to `make_filtering_bound_logger()`. Sometimes, that can be a bit too coarse, though. -You can achieve finer control by adding the {class}`~structlog.processors.CallsiteParameterAdder` processor and writing a simple processor that acts on the data it adds. +You can achieve finer control by adding the {class}`~structlog.processors.CallsiteParameterAdder` processor and writing a simple processor that acts on the call site data added. Let's assume you have the following code: From d4b097f9597345a625d993ae661f66dab920696f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 17 Nov 2022 09:25:58 +0100 Subject: [PATCH 0917/1520] Improve timelessness --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 263fdfa2..96c2f5ca 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ Especially those generously supporting us at the *The Organization* tier and hig

    - For a limited time, you can add your logo here for as little as $50 per month! + Please consider joining them to help make structlog’s maintenance more sustainable!

    --- From 0266d016ee1a5f4849b7ba4ec23360f140ec42c0 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 17 Nov 2022 09:39:05 +0100 Subject: [PATCH 0918/1520] Add Celery recipe --- docs/frameworks.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/frameworks.md b/docs/frameworks.md index 488f0f92..9767fe70 100644 --- a/docs/frameworks.md +++ b/docs/frameworks.md @@ -85,9 +85,25 @@ class StructLogTween: ) return self.handler(request) +``` + + +## Celery + +[*Celery*](https://docs.celeryq.dev/)'s multi-process architecture leads unavoidably to race conditions that show up as interleaved logs. + +Celery ships standard library-based helpers in the form of [`celery.utils.log.get_task_logger()`](https://docs.celeryq.dev/en/stable/userguide/tasks.html#logging) that you should use inside of tasks. +The most straight-forward way to integrate that with *structlog* is using {doc}`standard-library` and wrapping that logger using {func}`structlog.wrap_logger`: + +```python +from celery.utils.log import get_task_logger + +logger = structlog.wrap_logger(get_task_logger(__name__)) ``` +See [this issue](https://github.com/hynek/structlog/issues/287) for more details. + ## Twisted From 2b288d206dd341b03fc3aaa5c4eabce20659a2c2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 17 Nov 2022 09:44:56 +0100 Subject: [PATCH 0919/1520] Make otel example more defensive --- docs/frameworks.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/frameworks.md b/docs/frameworks.md index 9767fe70..4667e823 100644 --- a/docs/frameworks.md +++ b/docs/frameworks.md @@ -14,8 +14,12 @@ from opentelemetry import trace def add_open_telemetry_spans(_, __, event_dict): span = trace.get_current_span() + if not span.is_recording(): + event_dict["span"] = None + return event_dict + ctx = span.get_span_context() - parent = span.parent + parent = getattr(span, "parent", None) event_dict["span"] = { "span_id": hex(ctx.span_id), From c9bca88acc789916a97110ddae457ef0430754b1 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 17 Nov 2022 09:46:29 +0100 Subject: [PATCH 0920/1520] Streamline --- docs/frameworks.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/frameworks.md b/docs/frameworks.md index 4667e823..2266e79b 100644 --- a/docs/frameworks.md +++ b/docs/frameworks.md @@ -95,8 +95,7 @@ class StructLogTween: ## Celery [*Celery*](https://docs.celeryq.dev/)'s multi-process architecture leads unavoidably to race conditions that show up as interleaved logs. - -Celery ships standard library-based helpers in the form of [`celery.utils.log.get_task_logger()`](https://docs.celeryq.dev/en/stable/userguide/tasks.html#logging) that you should use inside of tasks. +It ships standard library-based helpers in the form of [`celery.utils.log.get_task_logger()`](https://docs.celeryq.dev/en/stable/userguide/tasks.html#logging) that you should use inside of tasks to prevent that problem. The most straight-forward way to integrate that with *structlog* is using {doc}`standard-library` and wrapping that logger using {func}`structlog.wrap_logger`: From 8c9035d3d0c2ffa47a183882913e5e018c1e1be2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 17 Nov 2022 09:51:59 +0100 Subject: [PATCH 0921/1520] Add another Celery example --- docs/frameworks.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/frameworks.md b/docs/frameworks.md index 2266e79b..bfcccdeb 100644 --- a/docs/frameworks.md +++ b/docs/frameworks.md @@ -105,6 +105,16 @@ from celery.utils.log import get_task_logger logger = structlog.wrap_logger(get_task_logger(__name__)) ``` +If you want to automatically bind task metadata to your {doc}`contextvars`, you can use [*Celery*'s signals](https://docs.celeryq.dev/en/stable/userguide/signals.html): + +```python +from celery import signals + +@signals.task_prerun.connect +def on_task_prerun(sender, task_id, task, args, kwargs, **_): + structlog.contextvars.bind_contextvars(task_id=task_id, task_name=task.name) +``` + See [this issue](https://github.com/hynek/structlog/issues/287) for more details. From d7686cfc65fd9a30d757dcb3387cabbeb1096c68 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 17 Nov 2022 10:18:41 +0100 Subject: [PATCH 0922/1520] Document how to disable pretty-printing --- docs/console-output.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/console-output.md b/docs/console-output.md index eb6ddd8a..fc258d8b 100644 --- a/docs/console-output.md +++ b/docs/console-output.md @@ -45,3 +45,8 @@ structlog.configure( cache_logger_on_first_use=True, ) ``` + + +## Disabling Exception Pretty-Printing + +If you prefer the default terse Exception rendering, but still want *Rich* installed, you can disable the pretty-printing by instantiating {class}`structlog.dev.ConsoleRenderer()` yourself and passing `exception_formatter=structlog.dev.plain_traceback`. From 556517a2a7e9967360b6c92c6af5c17f3fb4c09c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 17 Nov 2022 10:20:05 +0100 Subject: [PATCH 0923/1520] pre-commit autoupdate --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 41e17da2..ba477be5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,7 +12,7 @@ repos: - id: black - repo: https://github.com/asottile/pyupgrade - rev: v3.2.0 + rev: v3.2.2 hooks: - id: pyupgrade args: [--py37-plus] From 255de58cf7a9be044dc6b11ae5e7a491c24525ec Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 17 Nov 2022 10:53:09 +0100 Subject: [PATCH 0924/1520] Use proper Tidelif URL in credits --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 96c2f5ca..3831b389 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ If you prefer videos over reading, check out [Markus Holtermann](https://twitter *structlog* is written and maintained by [Hynek Schlawack](https://hynek.me/). The idea of bound loggers is inspired by previous work by [Jean-Paul Calderone](https://github.com/exarkun) and [David Reid](https://github.com/dreid). -The development is kindly supported by my employer [Variomedia AG](https://www.variomedia.de/), *structlog*’s [Tidelift subscribers](https://tidelift.com/subscription/pkg/pypi-structlog), and all my amazing [GitHub Sponsors](https://github.com/sponsors/hynek). +The development is kindly supported by my employer [Variomedia AG](https://www.variomedia.de/), *structlog*’s [Tidelift subscribers](https://tidelift.com/subscription/pkg/pypi-structlog?utm_source=pypi-structlog&utm_medium=referral&utm_campaign=readme), and all my amazing [GitHub Sponsors](https://github.com/sponsors/hynek). A full list of contributors can be found in GitHub’s [overview](https://github.com/hynek/structlog/graphs/contributors). From 17cb70219fd2ea45cfb6b5e6304ff478a52366d9 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 17 Nov 2022 10:54:52 +0100 Subject: [PATCH 0925/1520] Grouping --- pyproject.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8f45a771..0852871a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -126,12 +126,10 @@ strict = true show_error_codes = true enable_error_code = ["ignore-without-code"] - ignore_missing_imports = true warn_return_any = false - [[tool.mypy.overrides]] module = "tests.*" ignore_errors = true From 5dcb24dab0d4c5567eef1ee69e1faf0b1a707854 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 19 Nov 2022 12:45:49 +0100 Subject: [PATCH 0926/1520] Fix link --- docs/standard-library.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/standard-library.md b/docs/standard-library.md index 0d466047..3bcdd824 100644 --- a/docs/standard-library.md +++ b/docs/standard-library.md @@ -540,4 +540,4 @@ If you leave `foreign_pre_chain` as `None`, formatting will be left to `logging` Meaning: you can define a `format` for {class}`~structlog.stdlib.ProcessorFormatter` too! -[*python-json-logger*]: https://github.com/madzak/python-json-logger> +[*python-json-logger*]: https://github.com/madzak/python-json-logger From 4d00ebff8faaad1df8f5539df651776be772fb58 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 19 Nov 2022 12:47:16 +0100 Subject: [PATCH 0927/1520] Prepare 22.2.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c62e509..ddc1cf56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ You can find out backwards-compatibility policy [here](https://github.com/hynek/ -## [Unreleased](https://github.com/hynek/structlog/compare/22.1.0...HEAD) +## [22.2.0](https://github.com/hynek/structlog/compare/22.1.0...22.2.0) - 2022-11-19 ### Deprecated From 7cf81c3325054eb36cbde5a353fd2f3eb17f4000 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 19 Nov 2022 12:51:41 +0100 Subject: [PATCH 0928/1520] Start new development cycle --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ddc1cf56..9d7ed2ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,9 @@ You can find out backwards-compatibility policy [here](https://github.com/hynek/ + +## [Unreleased](https://github.com/hynek/structlog/compare/22.2.0...HEAD) + ## [22.2.0](https://github.com/hynek/structlog/compare/22.1.0...22.2.0) - 2022-11-19 ### Deprecated From 87cdcaf0205f9b62f793f331160d17cb12316e0d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 22 Nov 2022 17:56:52 +0100 Subject: [PATCH 0929/1520] Be more defensive about string interpolation (#475) --- CHANGELOG.md | 7 +++++ src/structlog/_log_levels.py | 17 +++++++--- tests/test_log_levels.py | 60 ++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d7ed2ef..8ddee6fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,13 @@ You can find out backwards-compatibility policy [here](https://github.com/hynek/ ## [Unreleased](https://github.com/hynek/structlog/compare/22.2.0...HEAD) +### Changed + +- String interpolation in `FilteringBoundLogger` (used by default) is now only attempted if positional arguments are passed. +This prevents crashes if something different than a string is passed for the *event* argument. + [#475](https://github.com/hynek/structlog/pull/475) + + ## [22.2.0](https://github.com/hynek/structlog/compare/22.1.0...22.2.0) - 2022-11-19 ### Deprecated diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index 501c44ae..4d497807 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -153,14 +153,20 @@ def make_method( name = _LEVEL_TO_NAME[level] def meth(self: Any, event: str, *args: Any, **kw: Any) -> Any: + if not args: + return self._proxy_to_logger(name, event, **kw) + return self._proxy_to_logger(name, event % args, **kw) async def ameth(self: Any, event: str, *args: Any, **kw: Any) -> Any: + if args: + event = event % args + ctx = contextvars.copy_context() await asyncio.get_running_loop().run_in_executor( None, lambda: ctx.run( - lambda: self._proxy_to_logger(name, event % args, **kw) + lambda: self._proxy_to_logger(name, event, **kw) ), ) @@ -174,6 +180,9 @@ def log(self: Any, level: int, event: str, *args: Any, **kw: Any) -> Any: return None name = _LEVEL_TO_NAME[level] + if not args: + return self._proxy_to_logger(name, event, **kw) + return self._proxy_to_logger(name, event % args, **kw) async def alog( @@ -182,13 +191,13 @@ async def alog( if level < min_level: return None name = _LEVEL_TO_NAME[level] + if args: + event = event % args ctx = contextvars.copy_context() return await asyncio.get_running_loop().run_in_executor( None, - lambda: ctx.run( - lambda: self._proxy_to_logger(name, event % args, **kw) - ), + lambda: ctx.run(lambda: self._proxy_to_logger(name, event, **kw)), ) meths: dict[str, Callable[..., Any]] = {"log": log, "alog": alog} diff --git a/tests/test_log_levels.py b/tests/test_log_levels.py index 1a372733..fff9cce7 100644 --- a/tests/test_log_levels.py +++ b/tests/test_log_levels.py @@ -61,6 +61,26 @@ async def test_async_one_below(self, bl, cl): assert [] == cl.calls + def test_no_args(self, bl, cl): + """ + If no args are passed, don't attempt intepolation. + + See also #473 + """ + bl.info(42) + + assert 42 == cl.calls[0][2]["event"] + + async def test_async_no_args(self, bl, cl): + """ + If no args are passed, don't attempt intepolation. + + See also #473 + """ + await bl.ainfo(42) + + assert 42 == cl.calls[0][2]["event"] + def test_log_exact_level(self, bl, cl): """ if log level is exactly the min_level, log. @@ -93,6 +113,32 @@ async def test_alog_one_below(self, bl, cl): assert [] == cl.calls + async def test_alog_no_args(self, bl, cl): + """ + If no args are passed, interpolation is not attempted. + + See also #473 + """ + await bl.alog(logging.INFO, 42) + + assert 42 == cl.calls[0][2]["event"] + + def test_log_interp(self, bl, cl): + """ + Interpolation happens if args are passed. + """ + bl.log(logging.INFO, "answer is %d.", 42) + + assert "answer is 42." == cl.calls[0][2]["event"] + + async def test_alog_interp(self, bl, cl): + """ + Interpolation happens if args are passed. + """ + await bl.alog(logging.INFO, "answer is %d.", 42) + + assert "answer is 42." == cl.calls[0][2]["event"] + def test_filter_bound_below_missing_event_string(self, bl): """ Missing event arg causes exception below min_level. @@ -149,6 +195,20 @@ async def test_async_exception_passed(self, bl, cl): assert [("error", (), {"event": "boom", "exc_info": 42})] == cl.calls + def test_exception_pass_exception(self, bl, cl): + """ + If an Exception is passed for the event, don't explode. + + Not a documented feature, but a regression for some people. See #473. + """ + try: + raise Exception("foo") + except Exception as e: + bl.exception(e) + exc = e + + assert exc is cl.calls[0][2]["event"] + @pytest.mark.parametrize("level", tuple(_LEVEL_TO_NAME.keys())) def test_pickle(self, level): """ From 2134a446a1a16c91374d42b1caafd4fed91b31a5 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 23 Nov 2022 14:58:10 +0100 Subject: [PATCH 0930/1520] Fix interpolation in filtered log calls (#478) Fixes #476 --- CHANGELOG.md | 6 ++++++ src/structlog/_log_levels.py | 4 ++-- tests/test_log_levels.py | 16 ++++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ddee6fa..48eeb0c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,12 @@ This prevents crashes if something different than a string is passed for the *ev [#475](https://github.com/hynek/structlog/pull/475) +### Fixed + +- String interpolation doesn't cause crashes in filtered log call anymore. + [#478](https://github.com/hynek/structlog/pull/478) + + ## [22.2.0](https://github.com/hynek/structlog/compare/22.1.0...22.2.0) - 2022-11-19 ### Deprecated diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index 4d497807..6e9fb1af 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -71,11 +71,11 @@ def add_log_level( return event_dict -def _nop(self: Any, event: str, **kw: Any) -> Any: +def _nop(self: Any, event: str, *args: Any, **kw: Any) -> Any: return None -async def _anop(self: Any, event: str, **kw: Any) -> Any: +async def _anop(self: Any, event: str, *args: Any, **kw: Any) -> Any: return None diff --git a/tests/test_log_levels.py b/tests/test_log_levels.py index fff9cce7..2a0e579c 100644 --- a/tests/test_log_levels.py +++ b/tests/test_log_levels.py @@ -61,6 +61,22 @@ async def test_async_one_below(self, bl, cl): assert [] == cl.calls + def test_filtered_interp(self, bl, cl): + """ + Passing interpolation args works if the log entry is filtered out. + """ + bl.debug("hello %s!", "world") + + assert [] == cl.calls + + async def test_async_filtered_interp(self, bl, cl): + """ + Passing interpolation args works if the log entry is filtered out. + """ + await bl.adebug("hello %s!", "world") + + assert [] == cl.calls + def test_no_args(self, bl, cl): """ If no args are passed, don't attempt intepolation. From fc60f2fbb0523f1dc3d8eefeeb11fb19f441f33f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 23 Nov 2022 15:01:54 +0100 Subject: [PATCH 0931/1520] Add test to ensure % can be logged w/o args Ref #479 --- tests/test_log_levels.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/test_log_levels.py b/tests/test_log_levels.py index 2a0e579c..e9d3cf05 100644 --- a/tests/test_log_levels.py +++ b/tests/test_log_levels.py @@ -267,3 +267,11 @@ async def test_async_contextvars_merged(self, meth, args, cl): await getattr(bl, meth)(*args) assert len(cl.calls) == 1 assert "context_included" in cl.calls[0].kwargs + + def test_log_percent(self, bl, cl): + """ + As long as there's no positional args passed, logging % is possible. + """ + bl.info("hey %! %%!") + + assert [("info", (), {"event": "hey %! %%!"})] == cl.calls From 968523ef8d8b27220066ceb7f8f97c7df78b6455 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 24 Nov 2022 08:11:19 +0100 Subject: [PATCH 0932/1520] Document new string interpolation behavior --- docs/bound-loggers.md | 3 ++- src/structlog/typing.py | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/bound-loggers.md b/docs/bound-loggers.md index 0a6c3593..7b8601c4 100644 --- a/docs/bound-loggers.md +++ b/docs/bound-loggers.md @@ -82,7 +82,7 @@ Now `log` is a *bound logger* of type {class}`~structlog.typing.FilteringBoundLo Now if you call `log.info("Hello, %s!", "world", number=42)` the following happens: -1. `"world"` gets interpolated into `"Hello, %s!"`, making the event "Hello, world!". +1. `"world"` gets interpolated into `"Hello, %s!"`, making the event "Hello, world!"[^interpolation]. 2. The *bound logger*'s context gets copied and the key-value pairs from the `info` call are added to it. It becomes an *event dict* and is `{"foo": "bar", "number": 42}` now. 3. The event from step 1 is added too. @@ -99,6 +99,7 @@ Now if you call `log.info("Hello, %s!", "world", number=42)` the following happe By replacing the last processor, you decide on the **format** of your logs. For example, if you wanted JSON logs, you just have to replace the last processor with {class}`structlog.processors.JSONRenderer`. +[^interpolation]: String interpolation only takes place if you pass positional arguments. (filtering)= diff --git a/src/structlog/typing.py b/src/structlog/typing.py index 8cec1a54..d27625a9 100644 --- a/src/structlog/typing.py +++ b/src/structlog/typing.py @@ -155,6 +155,9 @@ class FilteringBoundLogger(BindableLogger, Protocol): String interpolation using positional arguments. .. versionadded:: 22.2.0 Async variants ``alog()``, ``adebug()``, ``ainfo()``, and so forth. + .. versionchanged:: 22.3.0 + String interpolation is only attempted if positional arguments are + passed. """ def bind(self, **new_values: Any) -> FilteringBoundLogger: From c5971088852ab527e47f1aa9883baaec47f5ea72 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 24 Nov 2022 08:35:41 +0100 Subject: [PATCH 0933/1520] Prepare 22.3.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48eeb0c7..ee09c4ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ You can find out backwards-compatibility policy [here](https://github.com/hynek/ -## [Unreleased](https://github.com/hynek/structlog/compare/22.2.0...HEAD) +## [22.3.0](https://github.com/hynek/structlog/compare/22.2.0...22.3.0) - 2022-11-24 ### Changed From bbd1998cae15f6f8471e3f73c5093907f007da33 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 24 Nov 2022 08:44:11 +0100 Subject: [PATCH 0934/1520] Start new development cycle --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee09c4ca..7fa33c9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ You can find out backwards-compatibility policy [here](https://github.com/hynek/ +## [Unreleased](https://github.com/hynek/structlog/compare/22.3.0...HEAD) + + ## [22.3.0](https://github.com/hynek/structlog/compare/22.2.0...22.3.0) - 2022-11-24 ### Changed From d61a8043204da8291a7895f9dc5fd8aa35394cc7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 25 Nov 2022 09:05:40 +0100 Subject: [PATCH 0935/1520] Add Zenodo badge --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 3831b389..dba7dadf 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,9 @@ PyPI release + + DOI + Downloads per month From 3c7b3b5de1c10b389d24e2af7cb242a34380f736 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Dec 2022 14:58:01 +0100 Subject: [PATCH 0936/1520] Bump step-security/harden-runner from 1 to 2 (#480) Bumps [step-security/harden-runner](https://github.com/step-security/harden-runner) from 1 to 2. - [Release notes](https://github.com/step-security/harden-runner/releases) - [Commits](https://github.com/step-security/harden-runner/compare/v1...v2) --- updated-dependencies: - dependency-name: step-security/harden-runner dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-docset.yml | 2 +- .github/workflows/ci.yml | 10 +++++----- .github/workflows/codeql-analysis.yml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-docset.yml b/.github/workflows/build-docset.yml index 7f8e660f..bcc89366 100644 --- a/.github/workflows/build-docset.yml +++ b/.github/workflows/build-docset.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@v1 + uses: step-security/harden-runner@v2 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c76dbba5..0cea32e0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,7 +35,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@v1 + uses: step-security/harden-runner@v2 with: egress-policy: block allowed-endpoints: > @@ -67,7 +67,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@v1 + uses: step-security/harden-runner@v2 with: egress-policy: block allowed-endpoints: > @@ -148,7 +148,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@v1 + uses: step-security/harden-runner@v2 with: egress-policy: block allowed-endpoints: > @@ -172,7 +172,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@v1 + uses: step-security/harden-runner@v2 with: egress-policy: block allowed-endpoints: > @@ -201,7 +201,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@v1 + uses: step-security/harden-runner@v2 with: egress-policy: block diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index dc28ba5a..6a3f369d 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -27,7 +27,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@v1 + uses: step-security/harden-runner@v2 with: egress-policy: block allowed-endpoints: > From e08011a10726ceb224a44d16b786133687c87138 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 6 Dec 2022 05:44:08 +0000 Subject: [PATCH 0937/1520] [pre-commit.ci] pre-commit autoupdate (#481) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/asottile/pyupgrade: v3.2.2 → v3.3.0](https://github.com/asottile/pyupgrade/compare/v3.2.2...v3.3.0) - [github.com/PyCQA/flake8: 5.0.4 → 6.0.0](https://github.com/PyCQA/flake8/compare/5.0.4...6.0.0) - [github.com/pre-commit/pre-commit-hooks: v4.3.0 → v4.4.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.3.0...v4.4.0) * Disable flake8's E741 `l` is a perfectly good variable name in a lambda. Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Hynek Schlawack --- .pre-commit-config.yaml | 6 +++--- tox.ini | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ba477be5..493e7ebc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,7 +12,7 @@ repos: - id: black - repo: https://github.com/asottile/pyupgrade - rev: v3.2.2 + rev: v3.3.0 hooks: - id: pyupgrade args: [--py37-plus] @@ -29,7 +29,7 @@ repos: - id: yesqa - repo: https://github.com/PyCQA/flake8 - rev: 5.0.4 + rev: 6.0.0 hooks: - id: flake8 exclude: docs/code_examples @@ -41,7 +41,7 @@ repos: args: [-L, alog] - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.3.0 + rev: v4.4.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer diff --git a/tox.ini b/tox.ini index f2ad31b6..3d5932ae 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [flake8] -ignore = E203,W503,W504 +ignore = E203,W503,W504,E741 # Keep docs in sync with docs env and .readthedocs.yml. # We don't run pre-commit in CI, because we use pre-commit.ci. From 34db9218bf644df8f87ed378d9b0cbabcc6b685f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 30 Dec 2022 18:19:51 +0100 Subject: [PATCH 0938/1520] Fix coverage config --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 0852871a..9ff499f1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -89,7 +89,7 @@ branch = true source = ["structlog"] [tool.coverage.paths] -source = ["src", ".tox/*/site-packages"] +source = ["src", ".tox/py*/**/site-packages"] [tool.coverage.report] show_missing = true From 4c3f8b752a16b323d2ec362acb6133033abfd891 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 30 Dec 2022 18:20:35 +0100 Subject: [PATCH 0939/1520] Remove PyPI linting, we use baipp --- tox.ini | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/tox.ini b/tox.ini index 3d5932ae..d621d99b 100644 --- a/tox.ini +++ b/tox.ini @@ -13,7 +13,7 @@ python = [tox] -envlist = pre-commit,mypy,py37,py38,py39,py310,py39-colorama,py310-be,py310-rich,py311,docs,pypi-description,coverage-report +envlist = pre-commit,mypy,py37,py38,py39,py310,py39-colorama,py310-be,py310-rich,py311,docs,coverage-report isolated_build = True @@ -82,21 +82,6 @@ commands = python -m coverage report -[testenv:pypi-description] -basepython = python3.10 -skip_install = true -deps = - twine - pip >= 18.0.0 -# Needs to run last, otherwise we have a race condition about coverage files -# lying around. -depends = coverage-report -commands = - pip install --upgrade pip - pip wheel -w {envtmpdir}/build --no-deps . - twine check {envtmpdir}/build/* - - [testenv:docset] deps = doc2dash extras = docs From 037f609c27dd7e95359abb03318dd5919a433d05 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 2 Jan 2023 20:38:20 +0100 Subject: [PATCH 0940/1520] [pre-commit.ci] pre-commit autoupdate (#484) --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 493e7ebc..6b6482f9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,18 +7,18 @@ default_language_version: repos: - repo: https://github.com/psf/black - rev: 22.10.0 + rev: 22.12.0 hooks: - id: black - repo: https://github.com/asottile/pyupgrade - rev: v3.3.0 + rev: v3.3.1 hooks: - id: pyupgrade args: [--py37-plus] - repo: https://github.com/PyCQA/isort - rev: 5.10.1 + rev: 5.11.4 hooks: - id: isort additional_dependencies: [toml] From b678023e11ab15c60a76e8a5d827c655181d8308 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 3 Jan 2023 06:24:42 +0100 Subject: [PATCH 0941/1520] Use 3.11 proper for mypy --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0cea32e0..ca65c586 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -116,7 +116,7 @@ jobs: - "3.8" - "3.9" - "3.10" - - "~3.11.0-0" + - "3.11" steps: - uses: actions/checkout@v3 From 62e39b4c8d71bf074a947cd85d119c05a9e9004b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 3 Jan 2023 07:03:53 +0100 Subject: [PATCH 0942/1520] Use 3.11 by default --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ca65c586..966befef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ env: PIP_DISABLE_PIP_VERSION_CHECK: "1" PIP_NO_PYTHON_VERSION_WARNING: "1" SETUPTOOLS_SCM_PRETEND_VERSION: "1.0" # avoid warnings about shallow checkout - PYTHON_LATEST: "3.10" + PYTHON_LATEST: "3.11" permissions: contents: read From 99e71137eb15efea159196a8e9339eaa26017396 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 3 Jan 2023 07:04:56 +0100 Subject: [PATCH 0943/1520] Fix file name --- tox.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index d621d99b..32022239 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,7 @@ [flake8] ignore = E203,W503,W504,E741 -# Keep docs in sync with docs env and .readthedocs.yml. +# Keep docs in sync with docs env and readthedocs.yml. # We don't run pre-commit in CI, because we use pre-commit.ci. [gh-actions] python = @@ -18,7 +18,7 @@ isolated_build = True [testenv:docs] -# Keep basepython in sync with ci.yml/docs and .readthedocs.yml. +# Keep basepython in sync with ci.yml/docs and readthedocs.yml. basepython = python3.10 extras = docs passenv = TERM From 7e5ccd31fd0a3483645b8795167486f458573028 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 3 Jan 2023 07:05:09 +0100 Subject: [PATCH 0944/1520] Use 3.11 proper in tests --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 966befef..c4804aa5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: - "3.8" - "3.9" - "3.10" - - "~3.11.0-0" + - "3.11" steps: - name: Harden Runner From 975edbad14434f9ee40feeb1c9e08244e748cd2e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 3 Jan 2023 14:44:44 +0100 Subject: [PATCH 0945/1520] Fix tox.ini --- tox.ini | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tox.ini b/tox.ini index 32022239..eaf221b4 100644 --- a/tox.ini +++ b/tox.ini @@ -13,8 +13,8 @@ python = [tox] -envlist = pre-commit,mypy,py37,py38,py39,py310,py39-colorama,py310-be,py310-rich,py311,docs,coverage-report -isolated_build = True +envlist = pre-commit,mypy,py37,py38,py39,py310,py311,py39-colorama,py311-be,py311-rich,docs,coverage-report +isolated_build = true [testenv:docs] @@ -51,7 +51,7 @@ deps = twisted commands = python -m coverage run -m pytest {posargs} -[testenv:py310] +[testenv:py311] deps = twisted commands = {[testenv:py37]commands} @@ -61,22 +61,23 @@ deps = colorama commands = python -m coverage run -m pytest tests/test_dev.py {posargs} -[testenv:py310-be] +[testenv:py311-be] deps = better-exceptions commands = {[testenv:py39-colorama]commands} -[testenv:py310-rich] +[testenv:py311-rich] deps = rich commands = {[testenv:py39-colorama]commands} [testenv:coverage-report] -basepython = python3.10 +# Keep in sync with ci.yml/PYTHON_LATEST +basepython = python3.11 deps = coverage[toml] skip_install = true parallel_show_output = true -depends = py37,py310,py39-colorama,py310-be,py310-rich +depends = py37,py311,py39-colorama,py311-be,py311-rich commands = python -m coverage combine python -m coverage report From 626fc959e7bbce52334f97e713945466ba5a8ebb Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 10 Jan 2023 08:06:08 +0100 Subject: [PATCH 0946/1520] Rename readthedocs.yml to .readthedocs.yaml The good name is deprecated now: https://docs.readthedocs.io/en/stable/config-file/index.html --- readthedocs.yml => .readthedocs.yaml | 0 pyproject.toml | 22 ++++++++++++++++++++++ 2 files changed, 22 insertions(+) rename readthedocs.yml => .readthedocs.yaml (100%) diff --git a/readthedocs.yml b/.readthedocs.yaml similarity index 100% rename from readthedocs.yml rename to .readthedocs.yaml diff --git a/pyproject.toml b/pyproject.toml index 9ff499f1..70a6b379 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -173,3 +173,25 @@ pattern = "\n(###.+?\n)## " path = "README.md" start-at = "## Credits" end-before = "" + + +[tool.hatch.envs.tests] +features = ["tests"] +dev-mode = false + +[tool.hatch.envs.tests.scripts] +run = "coverage run -m pytest" + +[[tool.hatch.envs.tests.matrix]] +python = ["3.7", "3.8", "3.9", "3.10", "3.11"] + + +[tool.hatch.envs.coverage] +detached = true +dependencies = [ + "coverage[toml]>=6.2", + "lxml", +] +[tool.hatch.envs.coverage.scripts] +combine = "coverage combine {args}" +report = "coverage report --skip-covered --skip-empty" From 41f024a4e7b0a481ad7473488c19a4455a2894be Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 12 Jan 2023 07:28:52 +0100 Subject: [PATCH 0947/1520] Fix typo --- .github/CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 3c956201..71de7194 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -24,7 +24,7 @@ The official tag is `structlog` and helping out in support frees us up to improv - No contribution is too small! Please submit as many fixes for typos and grammar bloopers as you can! - Try to limit each pull request to *one* change only. -- Since we squash on merge, it's up to you how you handle updates to the `main branch. +- Since we squash on merge, it's up to you how you handle updates to the `main` branch. Whether you prefer to rebase on `main` or merge `main` into your branch, do whatever is more comfortable for you. - *Always* add tests and docs for your code. This is a hard rule; patches with missing tests or documentation won't be merged. From 330e961fe0b25aee644e8971fd0e35d624e0f09b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 12 Jan 2023 09:17:27 +0100 Subject: [PATCH 0948/1520] Add full changelog to PyPI readme --- pyproject.toml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 70a6b379..208d27c5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -169,6 +169,15 @@ path = "CHANGELOG.md" start-after = "" pattern = "\n(###.+?\n)## " +[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]] +text = """ +--- + +[Full changelog](https://www.structlog.org/en/stable/changelog.html) + + +""" + [[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]] path = "README.md" start-at = "## Credits" From bf128713d8dc61c6b468aa4730f1d484b7be097a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 12 Jan 2023 09:46:42 +0100 Subject: [PATCH 0949/1520] Get rid of eval-rst --- docs/bound-loggers.md | 58 ++++++++------- docs/conf.py | 2 +- docs/contextvars.md | 102 +++++++++++++------------- docs/getting-started.md | 44 +++++------- docs/index.md | 16 ++--- docs/logging-best-practices.md | 46 ++++++------ docs/recipes.md | 53 ++++++-------- docs/standard-library.md | 77 ++++++++++---------- docs/testing.md | 62 +++++++--------- docs/thread-local.md | 127 ++++++++++++--------------------- 10 files changed, 255 insertions(+), 332 deletions(-) diff --git a/docs/bound-loggers.md b/docs/bound-loggers.md index 7b8601c4..da313568 100644 --- a/docs/bound-loggers.md +++ b/docs/bound-loggers.md @@ -157,34 +157,32 @@ For that times there is the {func}`structlog.wrap_logger` function that can be u (proc)= -```{eval-rst} -.. doctest:: - - >>> import structlog - >>> class CustomPrintLogger: - ... def msg(self, message): - ... print(message) - >>> def proc(logger, method_name, event_dict): - ... print("I got called with", event_dict) - ... return repr(event_dict) - >>> log = structlog.wrap_logger( - ... CustomPrintLogger(), - ... wrapper_class=structlog.BoundLogger, - ... processors=[proc], - ... ) - >>> log2 = log.bind(x=42) - >>> log == log2 - False - >>> log.msg("hello world") - I got called with {'event': 'hello world'} - {'event': 'hello world'} - >>> log2.msg("hello world") - I got called with {'x': 42, 'event': 'hello world'} - {'x': 42, 'event': 'hello world'} - >>> log3 = log2.unbind("x") - >>> log == log3 - True - >>> log3.msg("nothing bound anymore", foo="but you can structure the event too") - I got called with {'foo': 'but you can structure the event too', 'event': 'nothing bound anymore'} - {'foo': 'but you can structure the event too', 'event': 'nothing bound anymore'} +```{doctest} +>>> import structlog +>>> class CustomPrintLogger: +... def msg(self, message): +... print(message) +>>> def proc(logger, method_name, event_dict): +... print("I got called with", event_dict) +... return repr(event_dict) +>>> log = structlog.wrap_logger( +... CustomPrintLogger(), +... wrapper_class=structlog.BoundLogger, +... processors=[proc], +... ) +>>> log2 = log.bind(x=42) +>>> log == log2 +False +>>> log.msg("hello world") +I got called with {'event': 'hello world'} +{'event': 'hello world'} +>>> log2.msg("hello world") +I got called with {'x': 42, 'event': 'hello world'} +{'x': 42, 'event': 'hello world'} +>>> log3 = log2.unbind("x") +>>> log == log3 +True +>>> log3.msg("nothing bound anymore", foo="but you can structure the event too") +I got called with {'foo': 'but you can structure the event too', 'event': 'nothing bound anymore'} +{'foo': 'but you can structure the event too', 'event': 'nothing bound anymore'} ``` diff --git a/docs/conf.py b/docs/conf.py index f848d4e6..b5868537 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -33,7 +33,7 @@ templates_path = ["_templates"] # The suffix of source filenames. -source_suffix = ".rst" +source_suffix = [".rst", ".md"] # The master toctree document. master_doc = "index" diff --git a/docs/contextvars.md b/docs/contextvars.md index 31543a50..59fb4ba8 100644 --- a/docs/contextvars.md +++ b/docs/contextvars.md @@ -2,17 +2,13 @@ # Context Variables -```{eval-rst} -.. testsetup:: * - - import structlog +```{testsetup} +import structlog ``` -```{eval-rst} -.. testcleanup:: * - - import structlog - structlog.reset_defaults() +```{testcleanup} +import structlog +structlog.reset_defaults() ``` The {mod}`contextvars` module in the Python standard library allows having a global *structlog* context that is local to the current execution context. @@ -35,51 +31,49 @@ The general flow is: We're sorry the word *context* means three different things in this itemization depending on ... context. -```{eval-rst} -.. doctest:: - - >>> from structlog.contextvars import ( - ... bind_contextvars, - ... bound_contextvars, - ... clear_contextvars, - ... merge_contextvars, - ... unbind_contextvars, - ... ) - >>> from structlog import configure - >>> configure( - ... processors=[ - ... merge_contextvars, - ... structlog.processors.KeyValueRenderer(key_order=["event", "a"]), - ... ] - ... ) - >>> log = structlog.get_logger() - >>> # At the top of your request handler (or, ideally, some general - >>> # middleware), clear the contextvars-local context and bind some common - >>> # values: - >>> clear_contextvars() - >>> bind_contextvars(a=1, b=2) - {'a': at ...>, 'b': at ...>} - >>> # Then use loggers as per normal - >>> # (perhaps by using structlog.get_logger() to create them). - >>> log.info("hello") - event='hello' a=1 b=2 - >>> # Use unbind_contextvars to remove a variable from the context. - >>> unbind_contextvars("b") - >>> log.info("world") - event='world' a=1 - >>> # You can also bind key-value pairs temporarily. - >>> with bound_contextvars(b=2): - ... log.info("hi") - event='hi' a=1 b=2 - >>> # Now it's gone again. - >>> log.info("hi") - event='hi' a=1 - >>> # And when we clear the contextvars state again, it goes away. - >>> # a=None is printed due to the key_order argument passed to - >>> # KeyValueRenderer, but it is NOT present anymore. - >>> clear_contextvars() - >>> log.info("hi there") - event='hi there' a=None +```{doctest} +>>> from structlog.contextvars import ( +... bind_contextvars, +... bound_contextvars, +... clear_contextvars, +... merge_contextvars, +... unbind_contextvars, +... ) +>>> from structlog import configure +>>> configure( +... processors=[ +... merge_contextvars, +... structlog.processors.KeyValueRenderer(key_order=["event", "a"]), +... ] +... ) +>>> log = structlog.get_logger() +>>> # At the top of your request handler (or, ideally, some general +>>> # middleware), clear the contextvars-local context and bind some common +>>> # values: +>>> clear_contextvars() +>>> bind_contextvars(a=1, b=2) +{'a': at ...>, 'b': at ...>} +>>> # Then use loggers as per normal +>>> # (perhaps by using structlog.get_logger() to create them). +>>> log.info("hello") +event='hello' a=1 b=2 +>>> # Use unbind_contextvars to remove a variable from the context. +>>> unbind_contextvars("b") +>>> log.info("world") +event='world' a=1 +>>> # You can also bind key-value pairs temporarily. +>>> with bound_contextvars(b=2): +... log.info("hi") +event='hi' a=1 b=2 +>>> # Now it's gone again. +>>> log.info("hi") +event='hi' a=1 +>>> # And when we clear the contextvars state again, it goes away. +>>> # a=None is printed due to the key_order argument passed to +>>> # KeyValueRenderer, but it is NOT present anymore. +>>> clear_contextvars() +>>> log.info("hi there") +event='hi there' a=None ``` diff --git a/docs/getting-started.md b/docs/getting-started.md index b06941fd..935b3a35 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -21,13 +21,11 @@ On **Windows**, you also have to install [*Colorama*](https://pypi.org/project/c A lot of effort went into making *structlog* accessible without reading pages of documentation. As a result, the simplest possible usage looks like this: -```{eval-rst} -.. doctest:: - - >>> import structlog - >>> log = structlog.get_logger() - >>> log.info("hello, %s!", "world", key="value!", more_than_strings=[1, 2, 3]) # doctest: +SKIP - 2022-10-07 10:41:29 [info ] hello, world! key=value! more_than_strings=[1, 2, 3] +```{doctest} +>>> import structlog +>>> log = structlog.get_logger() +>>> log.info("hello, %s!", "world", key="value!", more_than_strings=[1, 2, 3]) # doctest: +SKIP +2022-10-07 10:41:29 [info ] hello, world! key=value! more_than_strings=[1, 2, 3] ``` Here, *structlog* takes advantage of its default settings: @@ -180,24 +178,20 @@ The next processor in the chain receives that returned dictionary instead of the Let's assume you wanted to add a timestamp to every event dict. The processor would look like this: -```{eval-rst} -.. doctest:: - - >>> import datetime - >>> def timestamper(_, __, event_dict): - ... event_dict["time"] = datetime.datetime.now().isoformat() - ... return event_dict +```{doctest} +>>> import datetime +>>> def timestamper(_, __, event_dict): +... event_dict["time"] = datetime.datetime.now().isoformat() +... return event_dict ``` Plain Python, plain dictionaries. Now you have to tell *structlog* about your processor by {doc}`configuring ` it: -```{eval-rst} -.. doctest:: - - >>> structlog.configure(processors=[timestamper, structlog.processors.KeyValueRenderer()]) - >>> structlog.get_logger().info("hi") # doctest: +SKIP - event='hi' time='2018-01-21T09:37:36.976816' +```{doctest} +>>> structlog.configure(processors=[timestamper, structlog.processors.KeyValueRenderer()]) +>>> structlog.get_logger().info("hi") # doctest: +SKIP +event='hi' time='2018-01-21T09:37:36.976816' ``` @@ -211,12 +205,10 @@ While usually it's a string or bytes, there's no rule saying it _has_ to be a st So assuming you want to follow [best practices](logging-best-practices.md) and render your event dictionary to JSON that is picked up by a log aggregation system like ELK or Graylog, *structlog* comes with batteries included -- you just have to tell it to use its {class}`~structlog.processors.JSONRenderer`: -```{eval-rst} -.. doctest:: - - >>> structlog.configure(processors=[structlog.processors.JSONRenderer()]) - >>> structlog.get_logger().info("hi") - {"event": "hi"} +```{doctest} +>>> structlog.configure(processors=[structlog.processors.JSONRenderer()]) +>>> structlog.get_logger().info("hi") +{"event": "hi"} ``` diff --git a/docs/index.md b/docs/index.md index f0d9e2e1..e3cdec7a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -6,13 +6,12 @@ Release **{sub-ref}`release`** ([What's new?](changelog)) --- -```{eval-rst} -.. include:: ../README.md - :parser: myst_parser.sphinx_ - :start-after: - :end-before: +```{include} ../README.md +:start-after: +:end-before: ``` + If you’d like more information on why structured logging in general – and *structlog* in particular – are good ideas, we’ve prepared a [summary](why.md) just for you. Otherwise, let’s dive right in! @@ -103,11 +102,8 @@ api ## Project Information -```{eval-rst} -.. include:: ../README.md - :parser: myst_parser.sphinx_ - :start-after: ## Project Information - +```{include} ../README.md +:start-after: "## Project Information" ``` % stop Sphinx from complaining about orphaned docs, we link them elsewhere diff --git a/docs/logging-best-practices.md b/docs/logging-best-practices.md index 08be3db4..8539986d 100644 --- a/docs/logging-best-practices.md +++ b/docs/logging-best-practices.md @@ -36,30 +36,28 @@ This makes analyzing errors easier, since log aggregators can render JSON much b Here is a simple example of how you can have pretty logs during development and JSON output when your app is running in a production context: -```{eval-rst} -.. doctest:: - - >>> import sys - >>> import structlog - >>> - >>> shared_processors = [ - ... # Processors that have nothing to do with output, - ... # e.g., add timestamps or log level names. - ... ] - >>> if sys.stderr.isatty(): - ... # Pretty printing when we run in a terminal session. - ... # Automatically prints pretty tracebacks when "rich" is installed - ... processors = shared_processors + [ - ... structlog.dev.ConsoleRenderer(), - ... ] - ... else: - ... # Print JSON when we run, e.g., in a Docker container. - ... # Also print structured tracebacks. - ... processors = shared_processors + [ - ... structlog.processors.dict_tracebacks, - ... structlog.processors.JSONRenderer(), - ... ] - >>> structlog.configure(processors) +```{doctest} +>>> import sys +>>> import structlog +>>> +>>> shared_processors = [ +... # Processors that have nothing to do with output, +... # e.g., add timestamps or log level names. +... ] +>>> if sys.stderr.isatty(): +... # Pretty printing when we run in a terminal session. +... # Automatically prints pretty tracebacks when "rich" is installed +... processors = shared_processors + [ +... structlog.dev.ConsoleRenderer(), +... ] +... else: +... # Print JSON when we run, e.g., in a Docker container. +... # Also print structured tracebacks. +... processors = shared_processors + [ +... structlog.processors.dict_tracebacks, +... structlog.processors.JSONRenderer(), +... ] +>>> structlog.configure(processors) ``` diff --git a/docs/recipes.md b/docs/recipes.md index c3c08334..05ebbfdc 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -80,21 +80,16 @@ Pick the data you're interested in from the {class}`structlog.processors.Callsit ## Custom Wrappers -```{eval-rst} -.. testsetup:: * - - import structlog - structlog.configure( - processors=[structlog.processors.KeyValueRenderer()], - ) +```{testsetup} +import structlog +structlog.configure( + processors=[structlog.processors.KeyValueRenderer()], +) ``` -```{eval-rst} -.. testcleanup:: * - - import structlog - structlog.reset_defaults() - +```{testcleanup} +import structlog +structlog.reset_defaults() ``` The type of the *bound loggers* that are returned by {func}`structlog.get_logger()` is called the *wrapper class*, because it wraps the original logger that takes care of the output. @@ -118,23 +113,21 @@ To make it easy for you, *structlog* comes with the class {class}`structlog.Boun It’s easiest to demonstrate with an example: -```{eval-rst} -.. doctest:: - - >>> from structlog import BoundLoggerBase, PrintLogger, wrap_logger - >>> class SemanticLogger(BoundLoggerBase): - ... def info(self, event, **kw): - ... if not "status" in kw: - ... return self._proxy_to_logger("info", event, status="ok", **kw) - ... else: - ... return self._proxy_to_logger("info", event, **kw) - ... - ... def user_error(self, event, **kw): - ... self.info(event, status="user_error", **kw) - >>> log = wrap_logger(PrintLogger(), wrapper_class=SemanticLogger) - >>> log = log.bind(user="fprefect") - >>> log.user_error("user.forgot_towel") - user='fprefect' status='user_error' event='user.forgot_towel' +```{doctest} +>>> from structlog import BoundLoggerBase, PrintLogger, wrap_logger +>>> class SemanticLogger(BoundLoggerBase): +... def info(self, event, **kw): +... if not "status" in kw: +... return self._proxy_to_logger("info", event, status="ok", **kw) +... else: +... return self._proxy_to_logger("info", event, **kw) +... +... def user_error(self, event, **kw): +... self.info(event, status="user_error", **kw) +>>> log = wrap_logger(PrintLogger(), wrapper_class=SemanticLogger) +>>> log = log.bind(user="fprefect") +>>> log.user_error("user.forgot_towel") +user='fprefect' status='user_error' event='user.forgot_towel' ``` You can observe the following: diff --git a/docs/standard-library.md b/docs/standard-library.md index 3bcdd824..e51267db 100644 --- a/docs/standard-library.md +++ b/docs/standard-library.md @@ -134,21 +134,20 @@ For instance, if you log JSON in production, configure `logging` to use [*python This is the simplest approach where *structlog* does all the heavy lifting and passes a fully-formatted string to `logging`. Chances are, this is all you need. -```{eval-rst} -.. mermaid:: - :align: center +```{mermaid} +:align: center - flowchart TD - %%{ init: {'theme': 'neutral'} }%% - User - structlog - stdlib[Standard Library\ne.g. logging.StreamHandler] +flowchart TD + %%{ init: {'theme': 'neutral'} }%% + User + structlog + stdlib[Standard Library\ne.g. logging.StreamHandler] - User --> |"structlog.get_logger().info('foo')"| structlog - User --> |"logging.getLogger().info('foo')"| stdlib - structlog --> |"logging.getLogger().info(#quot;{'event': 'foo'}#quot;)"| stdlib ==> Output + User --> |"structlog.get_logger().info('foo')"| structlog + User --> |"logging.getLogger().info('foo')"| stdlib + structlog --> |"logging.getLogger().info(#quot;{'event': 'foo'}#quot;)"| stdlib ==> Output - Output + Output ``` A basic configuration to output structured logs in JSON format looks like this: @@ -230,22 +229,20 @@ hello You can choose to use *structlog* only for building the event dictionary and leave all formatting -- additionally to the output -- to the standard library. -```{eval-rst} -.. mermaid:: - :align: center +```{mermaid} +:align: center - flowchart TD - %%{ init: {'theme': 'neutral'} }%% - User - structlog - stdlib[Standard Library\ne.g. logging.StreamHandler] +flowchart TD + %%{ init: {'theme': 'neutral'} }%% + User + structlog + stdlib[Standard Library\ne.g. logging.StreamHandler] - User --> |"structlog.get_logger().info('foo', bar=42)"| structlog - User --> |"logging.getLogger().info('foo')"| stdlib - structlog --> |"logging.getLogger().info('foo', extra={"bar": 42})"| stdlib ==> Output - - Output + User --> |"structlog.get_logger().info('foo', bar=42)"| structlog + User --> |"logging.getLogger().info('foo')"| stdlib + structlog --> |"logging.getLogger().info('foo', extra={"bar": 42})"| stdlib ==> Output + Output ``` ```python @@ -314,26 +311,24 @@ Here, you use *structlog*'s {class}`~structlog.stdlib.ProcessorFormatter` as a { Consequently, the output is the duty of the standard library too. -```{eval-rst} -.. mermaid:: - :align: center - - flowchart TD - %%{ init: {'theme': 'neutral'} }%% - User - structlog - structlog2[structlog] - stdlib["Standard Library"] +```{mermaid} +:align: center - User --> |"structlog.get_logger().info(#quot;foo#quot;, bar=42)"| structlog - User --> |"logging.getLogger().info(#quot;foo#quot;)"| stdlib - structlog --> |"logging.getLogger().info(event_dict, {#quot;extra#quot;: {#quot;_logger#quot;: logger, #quot;_name#quot;: name})"| stdlib +flowchart TD + %%{ init: {'theme': 'neutral'} }%% + User + structlog + structlog2[structlog] + stdlib["Standard Library"] - stdlib --> |"structlog.stdlib.ProcessorFormatter.format(logging.Record)"| structlog2 - structlog2 --> |"Returns a string that is passed into logging handlers.\nThis flow is controlled by the logging configuration."| stdlib2 + User --> |"structlog.get_logger().info(#quot;foo#quot;, bar=42)"| structlog + User --> |"logging.getLogger().info(#quot;foo#quot;)"| stdlib + structlog --> |"logging.getLogger().info(event_dict, {#quot;extra#quot;: {#quot;_logger#quot;: logger, #quot;_name#quot;: name})"| stdlib - stdlib2[Standard Library\ne.g. logging.StreamHandler] ==> Output + stdlib --> |"structlog.stdlib.ProcessorFormatter.format(logging.Record)"| structlog2 + structlog2 --> |"Returns a string that is passed into logging handlers.\nThis flow is controlled by the logging configuration."| stdlib2 + stdlib2[Standard Library\ne.g. logging.StreamHandler] ==> Output ``` {class}`~structlog.stdlib.ProcessorFormatter` has two parts to its API: diff --git a/docs/testing.md b/docs/testing.md index d7447426..33f8be6f 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -4,15 +4,13 @@ If you need functionality similar to {meth}`unittest.TestCase.assertLogs`, or you want to capture all logs for some other reason, you can use the {func}`structlog.testing.capture_logs` context manager: -```{eval-rst} -.. doctest:: - - >>> from structlog import get_logger - >>> from structlog.testing import capture_logs - >>> with capture_logs() as cap_logs: - ... get_logger().bind(x="y").info("hello") - >>> cap_logs - [{'x': 'y', 'event': 'hello', 'log_level': 'info'}] +```{doctest} +>>> from structlog import get_logger +>>> from structlog.testing import capture_logs +>>> with capture_logs() as cap_logs: +... get_logger().bind(x="y").info("hello") +>>> cap_logs +[{'x': 'y', 'event': 'hello', 'log_level': 'info'}] ``` Note that inside the context manager all configured processors are disabled. @@ -45,38 +43,32 @@ def test_my_stuff(log_output): You can also use {class}`structlog.testing.CapturingLogger` (directly, or via {class}`~structlog.testing.CapturingLoggerFactory` that always returns the same logger) that is more low-level and great for unit tests: -```{eval-rst} -.. doctest:: - - >>> import structlog - >>> cf = structlog.testing.CapturingLoggerFactory() - >>> structlog.configure(logger_factory=cf, processors=[structlog.processors.JSONRenderer()]) - >>> log = get_logger() - >>> log.info("test!") - >>> cf.logger.calls - [CapturedCall(method_name='info', args=('{"event": "test!"}',), kwargs={})] +```{doctest} +>>> import structlog +>>> cf = structlog.testing.CapturingLoggerFactory() +>>> structlog.configure(logger_factory=cf, processors=[structlog.processors.JSONRenderer()]) +>>> log = get_logger() +>>> log.info("test!") +>>> cf.logger.calls +[CapturedCall(method_name='info', args=('{"event": "test!"}',), kwargs={})] ``` -```{eval-rst} -.. testcleanup:: * - - import structlog - structlog.reset_defaults() +```{testcleanup} +import structlog +structlog.reset_defaults() ``` --- Additionally *structlog* also ships with a logger that just returns whatever it gets passed into it: {class}`structlog.testing.ReturnLogger`. -```{eval-rst} -.. doctest:: - - >>> from structlog import ReturnLogger - >>> ReturnLogger().info(42) == 42 - True - >>> obj = ["hi"] - >>> ReturnLogger().info(obj) is obj - True - >>> ReturnLogger().info("hello", when="again") - (('hello',), {'when': 'again'}) +```{doctest} +>>> from structlog import ReturnLogger +>>> ReturnLogger().info(42) == 42 +True +>>> obj = ["hi"] +>>> ReturnLogger().info(obj) is obj +True +>>> ReturnLogger().info("hello", when="again") +(('hello',), {'when': 'again'}) ``` diff --git a/docs/thread-local.md b/docs/thread-local.md index f42bd384..3ed17dfa 100644 --- a/docs/thread-local.md +++ b/docs/thread-local.md @@ -8,21 +8,16 @@ The standard library {mod}`contextvars` module provides a more feature-rich supe Therefore, as of 22.1.0, the `structlog.threadlocal` module is frozen and will be removed after May 2023. ::: -```{eval-rst} -.. testsetup:: * - - import structlog - structlog.configure( - processors=[structlog.processors.KeyValueRenderer()], - ) +```{testsetup} * +import structlog +structlog.configure( + processors=[structlog.processors.KeyValueRenderer()], +) ``` -```{eval-rst} -.. testcleanup:: * - - import structlog - structlog.reset_defaults() - +```{testcleanup} * +import structlog +structlog.reset_defaults() ``` @@ -62,22 +57,19 @@ In order to make your context thread-local, *structlog* ships with a function th Within one thread, every instance of the returned class will have a *common* instance of the wrapped dict-like class: -```{eval-rst} -.. doctest:: - - >>> from structlog.threadlocal import wrap_dict - >>> WrappedDictClass = wrap_dict(dict) - >>> d1 = WrappedDictClass({"a": 1}) - >>> d2 = WrappedDictClass({"b": 2}) - >>> d3 = WrappedDictClass() - >>> d3["c"] = 3 - >>> d1 is d3 - False - >>> d1 == d2 == d3 == WrappedDictClass() - True - >>> d3 # doctest: +ELLIPSIS - - +```{doctest} +>>> from structlog.threadlocal import wrap_dict +>>> WrappedDictClass = wrap_dict(dict) +>>> d1 = WrappedDictClass({"a": 1}) +>>> d2 = WrappedDictClass({"b": 2}) +>>> d3 = WrappedDictClass() +>>> d3["c"] = 3 +>>> d1 is d3 +False +>>> d1 == d2 == d3 == WrappedDictClass() +True +>>> d3 # doctest: +ELLIPSIS + ``` To enable thread-local context use the generated class as the context class: @@ -93,44 +85,37 @@ As all instances of a wrapped dict-like class share the same data, in the case a `structlog.threadlocal.wrap_dict` returns always a completely *new* wrapped class: -```{eval-rst} -.. doctest:: - - >>> from structlog.threadlocal import wrap_dict - >>> WrappedDictClass = wrap_dict(dict) - >>> AnotherWrappedDictClass = wrap_dict(dict) - >>> WrappedDictClass() != AnotherWrappedDictClass() - True - >>> WrappedDictClass.__name__ # doctest: +SKIP - WrappedDict-41e8382d-bee5-430e-ad7d-133c844695cc - >>> AnotherWrappedDictClass.__name__ # doctest: +SKIP - WrappedDict-e0fc330e-e5eb-42ee-bcec-ffd7bd09ad09 - +```{doctest} +>>> from structlog.threadlocal import wrap_dict +>>> WrappedDictClass = wrap_dict(dict) +>>> AnotherWrappedDictClass = wrap_dict(dict) +>>> WrappedDictClass() != AnotherWrappedDictClass() +True +>>> WrappedDictClass.__name__ # doctest: +SKIP +WrappedDict-41e8382d-bee5-430e-ad7d-133c844695cc +>>> AnotherWrappedDictClass.__name__ # doctest: +SKIP +WrappedDict-e0fc330e-e5eb-42ee-bcec-ffd7bd09ad09 ``` In order to be able to bind values temporarily to a logger, `structlog.threadlocal` comes with a [context manager](https://docs.python.org/2/library/stdtypes.html#context-manager-types): {func}`structlog.threadlocal.tmp_bind`: -```{eval-rst} -.. testsetup:: ctx - - from structlog import PrintLogger, wrap_logger - from structlog.threadlocal import tmp_bind, wrap_dict - WrappedDictClass = wrap_dict(dict) - log = wrap_logger(PrintLogger(), context_class=WrappedDictClass) +```{testsetup} ctx +from structlog import PrintLogger, wrap_logger +from structlog.threadlocal import tmp_bind, wrap_dict +WrappedDictClass = wrap_dict(dict) +log = wrap_logger(PrintLogger(), context_class=WrappedDictClass) ``` -```{eval-rst} -.. doctest:: ctx - - >>> log.bind(x=42) # doctest: +ELLIPSIS - , ...)> - >>> log.msg("event!") - x=42 event='event!' - >>> with tmp_bind(log, x=23, y="foo") as tmp_log: - ... tmp_log.msg("another event!") - x=23 y='foo' event='another event!' - >>> log.msg("one last event!") - x=42 event='one last event!' +```{doctest} ctx +>>> log.bind(x=42) # doctest: +ELLIPSIS +, ...)> +>>> log.msg("event!") +x=42 event='event!' +>>> with tmp_bind(log, x=23, y="foo") as tmp_log: +... tmp_log.msg("another event!") +x=23 y='foo' event='another event!' +>>> log.msg("one last event!") +x=42 event='one last event!' ``` The state before the `with` statement is saved and restored once it's left. @@ -175,44 +160,24 @@ The convenience of having a thread-local context comes at a price though: ```{eval-rst} .. module:: structlog.threadlocal -``` -```{eval-rst} .. autofunction:: bind_threadlocal -``` -```{eval-rst} .. autofunction:: unbind_threadlocal -``` -```{eval-rst} .. autofunction:: bound_threadlocal -``` -```{eval-rst} .. autofunction:: get_threadlocal -``` -```{eval-rst} .. autofunction:: get_merged_threadlocal -``` -```{eval-rst} .. autofunction:: merge_threadlocal -``` -```{eval-rst} .. autofunction:: clear_threadlocal -``` -```{eval-rst} .. autofunction:: wrap_dict -``` -```{eval-rst} .. autofunction:: tmp_bind(logger, **tmp_values) -``` -```{eval-rst} .. autofunction:: as_immutable ``` From bcfc7f9e60640c150bffbdaeed6328e582f93d1e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 12 Jan 2023 09:47:23 +0100 Subject: [PATCH 0950/1520] Stop using custom css --- docs/_static/custom.css | 26 -------------------------- docs/conf.py | 1 - 2 files changed, 27 deletions(-) delete mode 100644 docs/_static/custom.css diff --git a/docs/_static/custom.css b/docs/_static/custom.css deleted file mode 100644 index 2d725132..00000000 --- a/docs/_static/custom.css +++ /dev/null @@ -1,26 +0,0 @@ -div.article-container>article { - font-size: 19px; - line-height: 1.6rem; -} - -div.admonition { - font-size: 19px; - line-height: 1.6rem; -} - -article>li>a { - font-size: 19px; - line-height: 1.6rem; -} - -article ul>li>p { - font-size: 19px; - line-height: 1.6rem; - margin-top: 0.75rem !important; - margin-bottom: 0.5rem !important; -} - -p.admonition-title { - font-size: 15px !important; - line-height: 1rem !important; -} diff --git a/docs/conf.py b/docs/conf.py index b5868537..2f7a6a72 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -92,7 +92,6 @@ html_theme_options = {} html_logo = "_static/structlog_logo_small_transparent.png" html_static_path = ["_static"] -html_css_files = ["custom.css"] htmlhelp_basename = "structlogdoc" From 397fac3403e4fdd22294a1ebcc20cb8703ac90c7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 1 Feb 2023 17:28:50 +0100 Subject: [PATCH 0951/1520] pre-commit autoupdate --- .pre-commit-config.yaml | 4 ++-- src/structlog/dev.py | 2 -- src/structlog/processors.py | 1 - 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6b6482f9..60f8d150 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,7 +7,7 @@ default_language_version: repos: - repo: https://github.com/psf/black - rev: 22.12.0 + rev: 23.1.0 hooks: - id: black @@ -18,7 +18,7 @@ repos: args: [--py37-plus] - repo: https://github.com/PyCQA/isort - rev: 5.11.4 + rev: 5.12.0 hooks: - id: isort additional_dependencies: [toml] diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 9abf86fe..6cf9bbe0 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -344,7 +344,6 @@ def _repr(self, val: Any) -> str: def __call__( self, logger: WrappedLogger, name: str, event_dict: EventDict ) -> str: - sio = StringIO() ts = event_dict.pop("timestamp", None) @@ -471,7 +470,6 @@ def get_default_level_styles(colors: bool = True) -> Any: def set_exc_info( logger: WrappedLogger, method_name: str, event_dict: EventDict ) -> EventDict: - """ Set ``event_dict["exc_info"] = True`` if *method_name* is ``"exception"``. diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 6de68986..b9d81df9 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -142,7 +142,6 @@ def __init__( def __call__( self, _: WrappedLogger, __: str, event_dict: EventDict ) -> str: - elements: list[str] = [] for key, value in self._ordered_items(event_dict): if any(c <= " " for c in key): From 08beb8ecece58367151ddcc3fac56cd287b612f0 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 2 Feb 2023 08:02:58 +0100 Subject: [PATCH 0952/1520] Fix comments --- tox.ini | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index eaf221b4..1398c59e 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,6 @@ [flake8] ignore = E203,W503,W504,E741 -# Keep docs in sync with docs env and readthedocs.yml. # We don't run pre-commit in CI, because we use pre-commit.ci. [gh-actions] python = @@ -18,7 +17,7 @@ isolated_build = true [testenv:docs] -# Keep basepython in sync with ci.yml/docs and readthedocs.yml. +# Keep basepython in sync with ci.yml/docs and .readthedocs.yaml. basepython = python3.10 extras = docs passenv = TERM From 846d8d9488da3d7b6141e1c5d99e927590936281 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 2 Feb 2023 08:07:12 +0100 Subject: [PATCH 0953/1520] tox gh --- .github/workflows/ci.yml | 4 ++-- tox.ini | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c4804aa5..f2682c58 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,9 +49,9 @@ jobs: - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - - run: python -m pip install --upgrade wheel tox tox-gh-actions + - run: python -m pip install --upgrade wheel tox tox-gh - - run: python -m tox + - run: python -m tox run - name: Upload coverage data uses: actions/upload-artifact@v3 diff --git a/tox.ini b/tox.ini index 1398c59e..13f466eb 100644 --- a/tox.ini +++ b/tox.ini @@ -1,14 +1,14 @@ [flake8] ignore = E203,W503,W504,E741 -# We don't run pre-commit in CI, because we use pre-commit.ci. -[gh-actions] + +[gh] python = - 3.7: py37 - 3.8: py38 - 3.9: py39 - 3.10: py310 - 3.11: py311 + 3.7 = py37 + 3.8 = py38 + 3.9 = py39 + 3.10 = py310 + 3.11 = py311 [tox] From f9f2b56022b6053a3d826d7848b0edddb3c1bb29 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 2 Feb 2023 08:09:08 +0100 Subject: [PATCH 0954/1520] Enable support for git archive installs --- .git_archival.txt | 4 ++++ .gitattributes | 5 +++++ 2 files changed, 9 insertions(+) create mode 100644 .git_archival.txt create mode 100644 .gitattributes diff --git a/.git_archival.txt b/.git_archival.txt new file mode 100644 index 00000000..8fb235d7 --- /dev/null +++ b/.git_archival.txt @@ -0,0 +1,4 @@ +node: $Format:%H$ +node-date: $Format:%cI$ +describe-name: $Format:%(describe:tags=true,match=*[0-9]*)$ +ref-names: $Format:%D$ diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..4118aee5 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +# Force LF line endings for text files +* text=auto eol=lf + +# Needed for hatch-vcs / setuptools-scm-git-archive +.git_archival.txt export-subst From f1f4c8210e194470572a9e4e6c5edebff71617b3 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 2 Feb 2023 08:19:10 +0100 Subject: [PATCH 0955/1520] Use neither --- .github/workflows/ci.yml | 4 ++-- tox.ini | 9 --------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f2682c58..6a05ad5a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,9 +49,9 @@ jobs: - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - - run: python -m pip install --upgrade wheel tox tox-gh + - run: python -m pip install --upgrade wheel tox - - run: python -m tox run + - run: python -m tox run -f py$(echo ${{ matrix.python-version }} | tr -d .) - name: Upload coverage data uses: actions/upload-artifact@v3 diff --git a/tox.ini b/tox.ini index 13f466eb..33549882 100644 --- a/tox.ini +++ b/tox.ini @@ -2,15 +2,6 @@ ignore = E203,W503,W504,E741 -[gh] -python = - 3.7 = py37 - 3.8 = py38 - 3.9 = py39 - 3.10 = py310 - 3.11 = py311 - - [tox] envlist = pre-commit,mypy,py37,py38,py39,py310,py311,py39-colorama,py311-be,py311-rich,docs,coverage-report isolated_build = true From ccd21e8b5d72bef849fbcbfe50d040d8496ea8e6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 6 Feb 2023 08:58:42 +0100 Subject: [PATCH 0956/1520] Fix Markdown --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fa33c9b..7876c838 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,7 +21,7 @@ You can find out backwards-compatibility policy [here](https://github.com/hynek/ ### Changed - String interpolation in `FilteringBoundLogger` (used by default) is now only attempted if positional arguments are passed. -This prevents crashes if something different than a string is passed for the *event* argument. + This prevents crashes if something different than a string is passed for the *event* argument. [#475](https://github.com/hynek/structlog/pull/475) From 2eedf6d3f97f2b9eaf46dd8fe579fac2fa0f7c64 Mon Sep 17 00:00:00 2001 From: Andrew Clemons Date: Mon, 6 Feb 2023 18:31:03 +0900 Subject: [PATCH 0957/1520] Correctly figure out exc_info in ConsoleRenderer. (#483) * Correctly figure out exc_info in ConsoleRenderer. If the `exc_info` key was filled with a raw exception, and not a tuple, the `ConsoleRenderer` code would call `sys.exc_info` and overwrite it. This is different to how the other processors handle the exc_info key. Additionally, if that call to `sys.exc_info` returned None, an explosion would happen. This is the case if we placed an exception in `exc_info`, but did not actually log until outside of the `except` block. * Fix markdown --------- Co-authored-by: Hynek Schlawack --- CHANGELOG.md | 6 +++++ src/structlog/dev.py | 4 +-- tests/test_dev.py | 61 +++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 66 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7876c838..e21336ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,12 @@ You can find out backwards-compatibility policy [here](https://github.com/hynek/ ## [Unreleased](https://github.com/hynek/structlog/compare/22.3.0...HEAD) +### Fixed + +- ConsoleRenderer now reuses the `_figure_out_exc_info` to process the `exc_info` argument like `ExceptionRenderer` does. + This prevents crashes if the actual Exception is passed for the *exc_info* argument instead of a tuple or `True`. + [#482](https://github.com/hynek/structlog/issues/482) + ## [22.3.0](https://github.com/hynek/structlog/compare/22.2.0...22.3.0) - 2022-11-24 diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 6cf9bbe0..fa72cd59 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -18,6 +18,7 @@ from typing import Any, Iterable, TextIO, Type, Union from ._frames import _format_exception +from .processors import _figure_out_exc_info from .typing import EventDict, ExceptionRenderer, ExcInfo, WrappedLogger @@ -417,8 +418,7 @@ def __call__( sio.write("\n\n" + "=" * 79 + "\n") if exc_info: - if not isinstance(exc_info, tuple): - exc_info = sys.exc_info() + exc_info = _figure_out_exc_info(exc_info) self._exception_formatter(sio, exc_info) elif exc is not None: diff --git a/tests/test_dev.py b/tests/test_dev.py index 84660aaa..7266c527 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -283,6 +283,53 @@ def test_stack_info(self, cr, padded): assert (padded + "\n" + stack) == rv + def test_exc_info_tuple(self, cr, padded): + """ + If exc_info is a tuple, it is used. + """ + + try: + 0 / 0 + except ZeroDivisionError: + ei = sys.exc_info() + + rv = cr(None, None, {"event": "test", "exc_info": ei}) + + exc = dev._format_exception(ei) + + assert (padded + "\n" + exc) == rv + + def test_exc_info_bool(self, cr, padded): + """ + If exc_info is True, it is obtained using sys.exc_info(). + """ + + try: + 0 / 0 + except ZeroDivisionError: + ei = sys.exc_info() + rv = cr(None, None, {"event": "test", "exc_info": True}) + + exc = dev._format_exception(ei) + + assert (padded + "\n" + exc) == rv + + def test_exc_info_exception(self, cr, padded): + """ + If exc_info is an exception, it is used by converting to a tuple. + """ + + try: + 0 / 0 + except ZeroDivisionError as e: + ei = e + + rv = cr(None, None, {"event": "test", "exc_info": ei}) + + exc = dev._format_exception((ei.__class__, ei, ei.__traceback__)) + + assert (padded + "\n" + exc) == rv + def test_pad_event_param(self, styles): """ `pad_event` parameter works. @@ -305,7 +352,7 @@ def test_pad_event_param(self, styles): + styles.reset ) == rv - @pytest.mark.parametrize("explicit_ei", [True, False]) + @pytest.mark.parametrize("explicit_ei", ["tuple", "exception", False]) def test_everything(self, cr, styles, padded, explicit_ei): """ Put all cases together. @@ -313,8 +360,13 @@ def test_everything(self, cr, styles, padded, explicit_ei): if explicit_ei: try: 0 / 0 - except ZeroDivisionError: - ei = sys.exc_info() + except ZeroDivisionError as e: + if explicit_ei == "tuple": + ei = sys.exc_info() + elif explicit_ei == "exception": + ei = e + else: + raise ValueError() else: ei = True @@ -339,6 +391,9 @@ def test_everything(self, cr, styles, padded, explicit_ei): rv = cr(None, None, ed) ei = sys.exc_info() + if isinstance(ei, BaseException): + ei = (ei.__class__, ei, ei.__traceback__) + exc = dev._format_exception(ei) assert ( From ae9ed072067b29444ecff25c412afc1dc80d3b87 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 6 Feb 2023 17:21:05 +0100 Subject: [PATCH 0958/1520] Clean up tox.ini --- .flake8 | 4 ++++ tox.ini | 24 ++++++++++++------------ 2 files changed, 16 insertions(+), 12 deletions(-) create mode 100644 .flake8 diff --git a/.flake8 b/.flake8 new file mode 100644 index 00000000..c2e7c7f3 --- /dev/null +++ b/.flake8 @@ -0,0 +1,4 @@ +[flake8] +ignore = E203,W503,W504,E741 + +# vim: ft=dosini diff --git a/tox.ini b/tox.ini index 33549882..73129ab6 100644 --- a/tox.ini +++ b/tox.ini @@ -1,9 +1,14 @@ -[flake8] -ignore = E203,W503,W504,E741 - - [tox] -envlist = pre-commit,mypy,py37,py38,py39,py310,py311,py39-colorama,py311-be,py311-rich,docs,coverage-report +envlist = + pre-commit, + mypy, + py37, + py38, + py39,py39-colorama, + py310, + py311,py311-{be,rich}, + docs, + coverage-report isolated_build = true @@ -36,16 +41,11 @@ commands = python -m pytest {posargs} # For missing types we get from typing-extensions -[testenv:py37] +[testenv:py3{7,11}] deps = twisted commands = python -m coverage run -m pytest {posargs} -[testenv:py311] -deps = twisted -commands = {[testenv:py37]commands} - - [testenv:py39-colorama] deps = colorama commands = python -m coverage run -m pytest tests/test_dev.py {posargs} @@ -67,7 +67,7 @@ basepython = python3.11 deps = coverage[toml] skip_install = true parallel_show_output = true -depends = py37,py311,py39-colorama,py311-be,py311-rich +depends = py37,py39-colorama,py311,py311-{be,rich} commands = python -m coverage combine python -m coverage report From 4e7bf267ab7a86b8b004cc76bbe60d3b41655346 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 6 Feb 2023 17:33:37 +0100 Subject: [PATCH 0959/1520] Streamline tox.ini --- tox.ini | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tox.ini b/tox.ini index 73129ab6..ffca0a37 100644 --- a/tox.ini +++ b/tox.ini @@ -1,22 +1,22 @@ [tox] -envlist = +min_version = 4 +env_list = pre-commit, mypy, py37, py38, - py39,py39-colorama, + py39{,-colorama}, py310, - py311,py311-{be,rich}, + py311{,-be,-rich}, docs, coverage-report -isolated_build = true [testenv:docs] # Keep basepython in sync with ci.yml/docs and .readthedocs.yaml. -basepython = python3.10 +base_python = python3.10 extras = docs -passenv = TERM +pass_env = TERM commands = sphinx-build -n -T -W -b html -d {envtmpdir}/doctrees docs docs/_build/html sphinx-build -n -T -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html @@ -36,7 +36,7 @@ commands = mypy src typing_examples.py [testenv] extras = tests -setenv = PYTHONHASHSEED = 0 +set_env = PYTHONHASHSEED = 0 commands = python -m pytest {posargs} @@ -67,7 +67,7 @@ basepython = python3.11 deps = coverage[toml] skip_install = true parallel_show_output = true -depends = py37,py39-colorama,py311,py311-{be,rich} +depends = py37,py39-colorama,py311{,-be,-rich} commands = python -m coverage combine python -m coverage report From 0614664ca0a5bbc88f8c5450641a3f1d96d216c5 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 10 Feb 2023 16:24:44 +0100 Subject: [PATCH 0960/1520] Fix type --- src/structlog/stdlib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 32269ed8..9213fbbd 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -912,9 +912,9 @@ def format(self, record: logging.LogRecord) -> str: record = logging.makeLogRecord(record.__dict__) logger = getattr(record, "_logger", _SENTINEL) - meth_name = getattr(record, "_name", _SENTINEL) + meth_name = getattr(record, "_name", "__structlog_sentinel__") - if logger is not _SENTINEL and meth_name is not _SENTINEL: + if logger is not _SENTINEL and meth_name != "__structlog_sentinel__": # Both attached by wrap_for_formatter if self.logger is not None: logger = self.logger From 48ee400699060ae5c6d1309c887c9c6d5c4524fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20W=C4=99grzyn?= Date: Fri, 10 Feb 2023 16:33:32 +0100 Subject: [PATCH 0961/1520] Fix missing exception info in aexception() (#489) * Fix missing exception info in aexception() * Semantic Newlines * Update CHANGELOG.md * Yoda FTW * Pacify flake8 --------- Co-authored-by: Hynek Schlawack --- CHANGELOG.md | 3 +++ src/structlog/_log_levels.py | 6 +++++- tests/test_log_levels.py | 30 ++++++++++++++++++++++++++---- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e21336ac..cee51a9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,9 @@ You can find out backwards-compatibility policy [here](https://github.com/hynek/ This prevents crashes if the actual Exception is passed for the *exc_info* argument instead of a tuple or `True`. [#482](https://github.com/hynek/structlog/issues/482) +- `FilteringBoundLogger.aexception()` now extracts the exception info using `sys.exc_info()` before passing control to the asyncio executor (where original exception info is no longer available). + [#488](https://github.com/hynek/structlog/issues/488) + ## [22.3.0](https://github.com/hynek/structlog/compare/22.2.0...22.3.0) - 2022-11-24 diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index 6e9fb1af..d3863a02 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -12,6 +12,7 @@ import asyncio import contextvars import logging +import sys from typing import Any, Callable @@ -86,7 +87,10 @@ def exception(self: FilteringBoundLogger, event: str, **kw: Any) -> Any: async def aexception(self: FilteringBoundLogger, event: str, **kw: Any) -> Any: - kw.setdefault("exc_info", True) + # Exception info has to be extracted this early, because it is no longer + # available once control is passed to the executor. + if kw.get("exc_info", True) is True: + kw["exc_info"] = sys.exc_info() ctx = contextvars.copy_context() return await asyncio.get_running_loop().run_in_executor( diff --git a/tests/test_log_levels.py b/tests/test_log_levels.py index e9d3cf05..727b4a9f 100644 --- a/tests/test_log_levels.py +++ b/tests/test_log_levels.py @@ -188,12 +188,33 @@ def test_exception(self, bl, cl): async def test_async_exception(self, bl, cl): """ - exception ensures that exc_info is set to True, unless it's already + aexception sets exc_info to current exception info, if it's not already set. """ - await bl.aexception("boom") + try: + raise Exception("boom") + except Exception as e: + await bl.aexception("foo") + exc = e - assert [("error", (), {"event": "boom", "exc_info": True})] == cl.calls + assert 1 == len(cl.calls) + assert isinstance(cl.calls[0][2]["exc_info"], tuple) + assert exc == cl.calls[0][2]["exc_info"][1] + + async def test_async_exception_true(self, bl, cl): + """ + aexception replaces exc_info with current exception info, if exc_info + is True. + """ + try: + raise Exception("boom") + except Exception as e: + await bl.aexception("foo", exc_info=True) + exc = e + + assert 1 == len(cl.calls) + assert isinstance(cl.calls[0][2]["exc_info"], tuple) + assert exc is cl.calls[0][2]["exc_info"][1] def test_exception_passed(self, bl, cl): """ @@ -205,7 +226,8 @@ def test_exception_passed(self, bl, cl): async def test_async_exception_passed(self, bl, cl): """ - exception if exc_info has a value, exception doesn't tamper with it. + exception if exc_info has a value (other than True), exception doesn't + tamper with it. """ await bl.aexception("boom", exc_info=42) From 757b3b41aa7ba265b44152b2dca9a2eade70c5d9 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 10 Feb 2023 16:34:30 +0100 Subject: [PATCH 0962/1520] More precise job names --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6a05ad5a..08df3887 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ permissions: jobs: tests: - name: tox on ${{ matrix.python-version }} + name: Tests on ${{ matrix.python-version }} runs-on: ubuntu-latest strategy: fail-fast: false @@ -106,7 +106,7 @@ jobs: if: ${{ failure() }} mypy: - name: mypy on ${{ matrix.python-version }} + name: Mypy on ${{ matrix.python-version }} runs-on: ubuntu-latest strategy: fail-fast: false From a88d919b8347e2a5dae2681662d42778ed3d2f3b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 10 Feb 2023 16:40:25 +0100 Subject: [PATCH 0963/1520] Always be releasing --- .github/workflows/pypi-package.yml | 93 ++++++++++++++++++++++++++++++ pyproject.toml | 2 +- 2 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/pypi-package.yml diff --git a/.github/workflows/pypi-package.yml b/.github/workflows/pypi-package.yml new file mode 100644 index 00000000..d0396759 --- /dev/null +++ b/.github/workflows/pypi-package.yml @@ -0,0 +1,93 @@ +--- +name: Build & maybe upload PyPI package + +on: + push: + branches: [main] + tags: ["*"] + pull_request: + branches: [main] + release: + types: + - published + workflow_dispatch: + +permissions: + contents: read + +jobs: + # Always build & lint package. + build-package: + name: Build & verify package + runs-on: ubuntu-latest + + steps: + - uses: step-security/harden-runner@v2 + with: + disable-sudo: true + egress-policy: block + allowed-endpoints: > + files.pythonhosted.org:443 + github.com:443 + pypi.org:443 + + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - uses: hynek/build-and-inspect-python-package@v1 + + # Upload to Test PyPI on every commit on main. + release-test-pypi: + name: Publish in-dev package to test.pypi.org + environment: release-test-pypi + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + needs: build-package + + steps: + - uses: step-security/harden-runner@v2 + with: + disable-sudo: true + egress-policy: block + allowed-endpoints: > + test.pypi.org:443 + + - name: Download packages built by build-and-inspect-python-package + uses: actions/download-artifact@v3 + with: + name: Packages + path: dist + + - name: Upload package to Test PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + password: ${{ secrets.TEST_PYPI_API_TOKEN }} + repository_url: https://test.pypi.org/legacy/ + + # Upload to real PyPI on GitHub Releases. + release-pypi: + name: Publish released package to pypi.org + environment: release-pypi + if: github.event.action == 'published' + runs-on: ubuntu-latest + needs: build-package + + steps: + - uses: step-security/harden-runner@v2 + with: + disable-sudo: true + egress-policy: block + allowed-endpoints: > + upload.pypi.org:443 + + - name: Download packages built by build-and-inspect-python-package + uses: actions/download-artifact@v3 + with: + name: Packages + path: dist + + - name: Upload package to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/pyproject.toml b/pyproject.toml index 208d27c5..a1a0a2f3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -72,7 +72,7 @@ dev = ["structlog[tests,typing,docs]"] [tool.hatch.version] source = "vcs" -raw-options = { version_scheme = "no-guess-dev" } +raw-options = { local_scheme = "no-local-version" } [tool.pytest.ini_options] From ce7cf4ee09c407e2c5ca085a9fdd51be917d47f5 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 10 Feb 2023 16:44:22 +0100 Subject: [PATCH 0964/1520] Building in CI once is plenty --- .github/workflows/ci.yml | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 08df3887..c5594bb1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -140,29 +140,6 @@ jobs: - run: python -m tox -e docs - package: - name: Build & verify package - runs-on: ubuntu-latest - env: - SETUPTOOLS_SCM_PRETEND_VERSION: "" - - steps: - - name: Harden Runner - uses: step-security/harden-runner@v2 - with: - egress-policy: block - allowed-endpoints: > - files.pythonhosted.org:443 - github.com:443 - pypi.org:443 - - - uses: actions/checkout@v3 - with: - fetch-depth: 0 # get correct version - - uses: hynek/build-and-inspect-python-package@v1 - - run: python -m pip install hatch-fancy-pypi-readme - - run: python -m hatch_fancy_pypi_readme - install-dev: name: Verify dev env runs-on: ${{ matrix.os }} @@ -195,7 +172,6 @@ jobs: - coverage - docs - install-dev - - package runs-on: ubuntu-latest From 4000a57982f59a53eec755a8ff52ebb287ef6cf0 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 12 Feb 2023 09:41:09 +0100 Subject: [PATCH 0965/1520] Leave venv creation method to contributors --- .github/CONTRIBUTING.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 71de7194..1b1c11d9 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -43,10 +43,9 @@ You can (and should) run our test suite using [*tox*]. However, you’ll probably want a more traditional environment as well. We highly recommend to develop using the latest Python release because we try to take advantage of modern features whenever possible. -First create a [virtual environment](https://virtualenv.pypa.io/) so you don't break your system-wide Python installation. -It’s out of scope for this document to list all the ways to manage virtual environments in Python, but if you don’t already have a pet way, take some time to look at tools like [*direnv*](https://hynek.me/til/python-project-local-venvs/), [*virtualfish*](https://virtualfish.readthedocs.io/), and [*virtualenvwrapper*](https://virtualenvwrapper.readthedocs.io/). +First create a [virtual environment](https://virtualenv.pypa.io/) so you don't break your system-wide Python installation in your preferred way. -Next, get an up to date checkout of the *structlog* repository: +Get an up to date checkout of the *structlog* repository: ```console $ git clone git@github.com:hynek/structlog.git @@ -58,11 +57,11 @@ or if you prefer to use *Git* via `https`: $ git clone https://github.com/hynek/structlog.git ``` -Change into the newly created directory and **after activating your virtual environment** install an editable version of *structlog* along with its tests and docs requirements: +Change into the newly created directory and after activating a virtual environment install an editable version of *structlog* along with its tests and docs requirements: ```console $ cd structlog -$ pip install --upgrade pip wheel setuptools # PLEASE don't skip this step +$ pip install --upgrade pip wheel # PLEASE don't skip this step $ pip install -e '.[dev]' ``` From 8d05f02590ef66f0a55597b4436bb9253348236a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 12 Feb 2023 09:42:20 +0100 Subject: [PATCH 0966/1520] Complete --- .github/CONTRIBUTING.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 1b1c11d9..1426d374 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -43,8 +43,6 @@ You can (and should) run our test suite using [*tox*]. However, you’ll probably want a more traditional environment as well. We highly recommend to develop using the latest Python release because we try to take advantage of modern features whenever possible. -First create a [virtual environment](https://virtualenv.pypa.io/) so you don't break your system-wide Python installation in your preferred way. - Get an up to date checkout of the *structlog* repository: ```console From 462e82a98b7a12065d7df1c719eae6a1cb456c6d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 12 Feb 2023 10:06:17 +0100 Subject: [PATCH 0967/1520] Wordsmith --- .github/CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 1426d374..41d34bdc 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -43,13 +43,13 @@ You can (and should) run our test suite using [*tox*]. However, you’ll probably want a more traditional environment as well. We highly recommend to develop using the latest Python release because we try to take advantage of modern features whenever possible. -Get an up to date checkout of the *structlog* repository: +Clone the *structlog* repository: ```console $ git clone git@github.com:hynek/structlog.git ``` -or if you prefer to use *Git* via `https`: +Or if you prefer to use Git via HTTPS: ```console $ git clone https://github.com/hynek/structlog.git @@ -93,7 +93,7 @@ $ pre-commit run --all-files ``` and our CI has integration with [pre-commit.ci](https://pre-commit.ci). -But it's way more comfortable to run it locally and *git* catching avoidable errors. +But it's way more comfortable to run it locally and catch avoidable errors before pushing them to GitHub. ## Code From 0dc1219030294c66bdb6af57d4c1955d5647ea98 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 9 Mar 2023 10:19:38 +0100 Subject: [PATCH 0968/1520] Narrow type ignore to fix Mypy error --- src/structlog/_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 6946a463..bfffc7cc 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -353,7 +353,7 @@ def finalized_bind(**new_values: Any) -> BindableLogger: self._cache_logger_on_first_use is None and _CONFIG.cache_logger_on_first_use is True ): - self.bind = finalized_bind # type: ignore[assignment] + self.bind = finalized_bind # type: ignore[method-assign] return finalized_bind(**new_values) From 74cdff93af217519d4ebea05184f5e0db2972556 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 9 Mar 2023 10:20:13 +0100 Subject: [PATCH 0969/1520] Give internal variable that determines colors a better name --- src/structlog/_config.py | 4 ++-- src/structlog/dev.py | 9 ++++++--- tests/test_dev.py | 12 ++++++------ 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/structlog/_config.py b/src/structlog/_config.py index bfffc7cc..c608dfea 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -17,7 +17,7 @@ from ._log_levels import make_filtering_bound_logger from ._output import PrintLoggerFactory from .contextvars import merge_contextvars -from .dev import ConsoleRenderer, _use_colors, set_exc_info +from .dev import ConsoleRenderer, _has_colors, set_exc_info from .processors import StackInfoRenderer, TimeStamper, add_log_level from .typing import BindableLogger, Context, Processor, WrappedLogger @@ -35,7 +35,7 @@ set_exc_info, TimeStamper(fmt="%Y-%m-%d %H:%M:%S", utc=False), ConsoleRenderer( - colors=_use_colors + colors=_has_colors and sys.stdout is not None and hasattr(sys.stdout, "isatty") and sys.stdout.isatty() diff --git a/src/structlog/dev.py b/src/structlog/dev.py index fa72cd59..d72fff22 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -98,10 +98,13 @@ def _pad(s: str, length: int) -> str: if _IS_WINDOWS: # pragma: no cover # On Windows, use colors by default only if Colorama is installed. - _use_colors = colorama is not None + _has_colors = colorama is not None else: # On other OSes, use colors by default. - _use_colors = True + _has_colors = True + +# Prevent breakage of packages that used the old name of the variable. +_use_colors = _has_colors class _Styles(Protocol): @@ -278,7 +281,7 @@ class ConsoleRenderer: def __init__( self, pad_event: int = _EVENT_WIDTH, - colors: bool = _use_colors, + colors: bool = _has_colors, force_colors: bool = False, repr_native_str: bool = False, level_styles: Styles | None = None, diff --git a/tests/test_dev.py b/tests/test_dev.py index 7266c527..ee3e3053 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -30,7 +30,7 @@ def test_negative(self): @pytest.fixture(name="cr") def _cr(): return dev.ConsoleRenderer( - colors=dev._use_colors, exception_formatter=dev.plain_traceback + colors=dev._has_colors, exception_formatter=dev.plain_traceback ) @@ -135,11 +135,11 @@ def test_init_accepts_overriding_levels(self, styles, padded): Stdlib levels are rendered aligned, in brackets, and color coded. """ my_styles = dev.ConsoleRenderer.get_default_level_styles( - colors=dev._use_colors + colors=dev._has_colors ) my_styles["MY_OH_MY"] = my_styles["critical"] cr = dev.ConsoleRenderer( - colors=dev._use_colors, level_styles=my_styles + colors=dev._has_colors, level_styles=my_styles ) # this would blow up if the level_styles override failed @@ -334,7 +334,7 @@ def test_pad_event_param(self, styles): """ `pad_event` parameter works. """ - rv = dev.ConsoleRenderer(42, dev._use_colors)( + rv = dev.ConsoleRenderer(42, dev._has_colors)( None, None, {"event": "test", "foo": "bar"} ) @@ -455,7 +455,7 @@ def test_colorama_force_colors(self, styles, padded): If force_colors is True, use colors even if the destination is non-tty. """ cr = dev.ConsoleRenderer( - colors=dev._use_colors, force_colors=dev._use_colors + colors=dev._has_colors, force_colors=dev._has_colors ) rv = cr( @@ -479,7 +479,7 @@ def test_colorama_force_colors(self, styles, padded): + styles.reset ) == rv - assert not dev._use_colors or dev._ColorfulStyles is cr._styles + assert not dev._has_colors or dev._ColorfulStyles is cr._styles @pytest.mark.parametrize("rns", [True, False]) def test_repr_native_str(self, rns): From 6baee34771dfabd15ce7b77453da64803bf50a90 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 16 Mar 2023 14:23:43 +0100 Subject: [PATCH 0970/1520] PDF docs are failing to build --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index f563d645..b09dd677 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -1,6 +1,6 @@ --- version: 2 -formats: all +formats: [htmlzip, epub] build: os: ubuntu-20.04 From 44395f5c2d4cc0191cd94a47a03008a02c47df09 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 16 Mar 2023 15:07:47 +0100 Subject: [PATCH 0971/1520] Add explanation --- .readthedocs.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index b09dd677..d20d02a5 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -1,5 +1,6 @@ --- version: 2 +# PDF builds are broken. formats: [htmlzip, epub] build: From ed18411f0f5b59388179df56f5dc5dda146d2af1 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 16 Mar 2023 15:15:23 +0100 Subject: [PATCH 0972/1520] Fix warning --- .github/workflows/pypi-package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pypi-package.yml b/.github/workflows/pypi-package.yml index d0396759..369c04de 100644 --- a/.github/workflows/pypi-package.yml +++ b/.github/workflows/pypi-package.yml @@ -63,7 +63,7 @@ jobs: uses: pypa/gh-action-pypi-publish@release/v1 with: password: ${{ secrets.TEST_PYPI_API_TOKEN }} - repository_url: https://test.pypi.org/legacy/ + repository-url: https://test.pypi.org/legacy/ # Upload to real PyPI on GitHub Releases. release-pypi: From 8b198da5d5319e875ee26afcb41f4d5fe106c75e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 17 Mar 2023 06:49:13 +0100 Subject: [PATCH 0973/1520] Build docs on 3.11 --- .github/workflows/ci.yml | 28 ++++++++++++++-------------- .readthedocs.yaml | 2 +- tox.ini | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c5594bb1..2e15e91d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,9 +49,9 @@ jobs: - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - - run: python -m pip install --upgrade wheel tox + - run: python -Im pip install --upgrade wheel tox - - run: python -m tox run -f py$(echo ${{ matrix.python-version }} | tr -d .) + - run: python -Im tox run -f py$(echo ${{ matrix.python-version }} | tr -d .) - name: Upload coverage data uses: actions/upload-artifact@v3 @@ -81,7 +81,7 @@ jobs: # Use latest Python, so it understands all syntax. python-version: ${{env.PYTHON_LATEST}} - - run: python -m pip install --upgrade coverage[toml] + - run: python -Im pip install --upgrade coverage[toml] - uses: actions/download-artifact@v3 with: @@ -89,14 +89,14 @@ jobs: - name: Combine coverage & fail if it's <100%. run: | - python -m coverage combine - python -m coverage html --skip-covered --skip-empty + python -Im coverage combine + python -Im coverage html --skip-covered --skip-empty # Report and write to summary. - python -m coverage report | sed 's/^/ /' >> $GITHUB_STEP_SUMMARY + python -Im coverage report | sed 's/^/ /' >> $GITHUB_STEP_SUMMARY # Report again and fail if under 100%. - python -m coverage report --fail-under=100 + python -Im coverage report --fail-under=100 - name: Upload HTML report if check failed. uses: actions/upload-artifact@v3 @@ -123,9 +123,9 @@ jobs: - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - - run: python -m pip install --upgrade wheel tox + - run: python -Im pip install --upgrade wheel tox - - run: python -m tox -e mypy + - run: python -Im tox -e mypy docs: name: Build docs & run doctests @@ -135,10 +135,10 @@ jobs: - uses: actions/setup-python@v4 with: # Keep in sync with tox.ini/docs & readthedocs.yml - python-version: "3.10" - - run: python -m pip install --upgrade wheel tox + python-version: "3.11" + - run: python -Im pip install --upgrade wheel tox - - run: python -m tox -e docs + - run: python -Im tox -e docs install-dev: name: Verify dev env @@ -161,8 +161,8 @@ jobs: - uses: actions/setup-python@v4 with: python-version: ${{env.PYTHON_LATEST}} - - run: python -m pip install -e .[dev] - - run: python -c 'import structlog; print(structlog.__version__)' + - run: python -Im pip install -e .[dev] + - run: python -Ic 'import structlog; print(structlog.__version__)' # Ensure everything required is passing for branch protection. required-checks-pass: diff --git a/.readthedocs.yaml b/.readthedocs.yaml index d20d02a5..3f7ab7ad 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -7,7 +7,7 @@ build: os: ubuntu-20.04 tools: # Keep version in sync with tox.ini/docs and ci.yml/docs - python: "3.10" + python: "3.11" python: install: diff --git a/tox.ini b/tox.ini index ffca0a37..126c9bb9 100644 --- a/tox.ini +++ b/tox.ini @@ -14,7 +14,7 @@ env_list = [testenv:docs] # Keep basepython in sync with ci.yml/docs and .readthedocs.yaml. -base_python = python3.10 +base_python = python3.11 extras = docs pass_env = TERM commands = From c3161d238e14c37ad55ff2de3914eabf923b9c00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Howe=20Gersager?= Date: Sat, 1 Apr 2023 13:14:08 +0200 Subject: [PATCH 0974/1520] remove duplicate for (#499) --- src/structlog/tracebacks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/tracebacks.py b/src/structlog/tracebacks.py index 8c025141..b032df08 100644 --- a/src/structlog/tracebacks.py +++ b/src/structlog/tracebacks.py @@ -208,7 +208,7 @@ def extract( class ExceptionDictTransformer: """ - Return a list of exception stack dictionaries for for an exception. + Return a list of exception stack dictionaries for an exception. These dictionaries are based on :class:`Stack` instances generated by :func:`extract()` and can be dumped to JSON. From 46e130a93555f244da3412893827b731cd345286 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 4 Apr 2023 06:40:43 +0200 Subject: [PATCH 0975/1520] [pre-commit.ci] pre-commit autoupdate (#500) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/psf/black: 23.1.0 → 23.3.0](https://github.com/psf/black/compare/23.1.0...23.3.0) - [github.com/codespell-project/codespell: v2.2.2 → v2.2.4](https://github.com/codespell-project/codespell/compare/v2.2.2...v2.2.4) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 60f8d150..5001cb0b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,7 +7,7 @@ default_language_version: repos: - repo: https://github.com/psf/black - rev: 23.1.0 + rev: 23.3.0 hooks: - id: black @@ -35,7 +35,7 @@ repos: exclude: docs/code_examples - repo: https://github.com/codespell-project/codespell - rev: v2.2.2 + rev: v2.2.4 hooks: - id: codespell args: [-L, alog] From ecabf70d5b8d28276b73cfe69672edcef40fdc43 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 5 Apr 2023 15:03:30 +0200 Subject: [PATCH 0976/1520] Remove ko-fi PayPal's fees make it not worth it. --- .github/FUNDING.yml | 2 -- pyproject.toml | 1 - 2 files changed, 3 deletions(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 3fbd7100..fd64f81f 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,5 +1,3 @@ --- - github: hynek -ko_fi: the_hynek tidelift: pypi/structlog diff --git a/pyproject.toml b/pyproject.toml index a1a0a2f3..8e2a2d36 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,7 +44,6 @@ Changelog = "https://www.structlog.org/en/stable/changelog.html" "Source Code" = "https://github.com/hynek/structlog" Funding = "https://github.com/sponsors/hynek" Tidelift = "https://tidelift.com/subscription/pkg/pypi-structlog?utm_source=pypi-structlog&utm_medium=pypi" -Ko-fi = "https://ko-fi.com/the_hynek" [project.optional-dependencies] From f416ccc1a477e6c9ee83e7e13fee7eed62873ce2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 5 Apr 2023 15:16:24 +0200 Subject: [PATCH 0977/1520] Remove harden-runner The idea is great, but the hostnames are too unpredictable. --- .github/workflows/build-docset.yml | 5 ---- .github/workflows/ci.yml | 34 --------------------------- .github/workflows/codeql-analysis.yml | 11 --------- .github/workflows/pypi-package.yml | 23 ------------------ 4 files changed, 73 deletions(-) diff --git a/.github/workflows/build-docset.yml b/.github/workflows/build-docset.yml index bcc89366..1791a4db 100644 --- a/.github/workflows/build-docset.yml +++ b/.github/workflows/build-docset.yml @@ -17,11 +17,6 @@ jobs: docset: runs-on: ubuntu-latest steps: - - name: Harden Runner - uses: step-security/harden-runner@v2 - with: - egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@v3 with: fetch-depth: 0 # get correct version diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2e15e91d..5ac5eaee 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,17 +34,6 @@ jobs: - "3.11" steps: - - name: Harden Runner - uses: step-security/harden-runner@v2 - with: - egress-policy: block - allowed-endpoints: > - api.github.com:443 - files.pythonhosted.org:443 - github.com:443 - objects.githubusercontent.com:443 - pypi.org:443 - - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: @@ -66,15 +55,6 @@ jobs: needs: tests steps: - - name: Harden Runner - uses: step-security/harden-runner@v2 - with: - egress-policy: block - allowed-endpoints: > - files.pythonhosted.org:443 - github.com:443 - pypi.org:443 - - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: @@ -148,15 +128,6 @@ jobs: os: [ubuntu-latest, windows-latest] steps: - - name: Harden Runner - uses: step-security/harden-runner@v2 - with: - egress-policy: block - allowed-endpoints: > - files.pythonhosted.org:443 - github.com:443 - pypi.org:443 - - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: @@ -176,11 +147,6 @@ jobs: runs-on: ubuntu-latest steps: - - name: Harden Runner - uses: step-security/harden-runner@v2 - with: - egress-policy: block - - name: Decide whether the needed jobs succeeded or failed uses: re-actors/alls-green@release/v1 with: diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 6a3f369d..c8e7cab3 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -26,17 +26,6 @@ jobs: language: ["python"] steps: - - name: Harden Runner - uses: step-security/harden-runner@v2 - with: - egress-policy: block - allowed-endpoints: > - api.github.com:443 - bootstrap.pypa.io:443 - files.pythonhosted.org:443 - github.com:443 - pypi.org:443 - - name: Checkout repository uses: actions/checkout@v3 diff --git a/.github/workflows/pypi-package.yml b/.github/workflows/pypi-package.yml index 369c04de..8a613ff0 100644 --- a/.github/workflows/pypi-package.yml +++ b/.github/workflows/pypi-package.yml @@ -22,15 +22,6 @@ jobs: runs-on: ubuntu-latest steps: - - uses: step-security/harden-runner@v2 - with: - disable-sudo: true - egress-policy: block - allowed-endpoints: > - files.pythonhosted.org:443 - github.com:443 - pypi.org:443 - - uses: actions/checkout@v3 with: fetch-depth: 0 @@ -46,13 +37,6 @@ jobs: needs: build-package steps: - - uses: step-security/harden-runner@v2 - with: - disable-sudo: true - egress-policy: block - allowed-endpoints: > - test.pypi.org:443 - - name: Download packages built by build-and-inspect-python-package uses: actions/download-artifact@v3 with: @@ -74,13 +58,6 @@ jobs: needs: build-package steps: - - uses: step-security/harden-runner@v2 - with: - disable-sudo: true - egress-policy: block - allowed-endpoints: > - upload.pypi.org:443 - - name: Download packages built by build-and-inspect-python-package uses: actions/download-artifact@v3 with: From 60db9f5764c58e4ab80bbbdeef3879cf2370c05a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 5 Apr 2023 15:22:20 +0200 Subject: [PATCH 0978/1520] Fix file name --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5ac5eaee..d5bf318c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -114,7 +114,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: - # Keep in sync with tox.ini/docs & readthedocs.yml + # Keep in sync with tox.ini/docs & readthedocs.yaml python-version: "3.11" - run: python -Im pip install --upgrade wheel tox From 89fd0531eb49d987af7d723c3f2868b351c3020b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 5 Apr 2023 15:36:21 +0200 Subject: [PATCH 0979/1520] Switch CI to pre-built sdists (#501) --- .github/workflows/ci.yml | 60 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d5bf318c..db5c511f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,15 +13,43 @@ env: TOX_TESTENV_PASSENV: FORCE_COLOR PIP_DISABLE_PIP_VERSION_CHECK: "1" PIP_NO_PYTHON_VERSION_WARNING: "1" - SETUPTOOLS_SCM_PRETEND_VERSION: "1.0" # avoid warnings about shallow checkout PYTHON_LATEST: "3.11" + # For re-actors/checkout-python-sdist + SETUPTOOLS_SCM_PRETEND_VERSION: "1.0" # hard-code version for predictable sdist names + sdist-artifact: python-package-distributions + sdist-name: structlog-1.0.tar.gz + permissions: contents: read jobs: + build-sdist: + name: 📦 Build the source distribution + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: ${{ env.PYTHON_LATEST }} + - run: python -Im pip install build + + - run: python -Im build --sdist + + - uses: actions/upload-artifact@v3 + with: + name: ${{ env.sdist-artifact }} + # NOTE: Exact expected file names are specified here + # NOTE: as a safety measure — if anything weird ends + # NOTE: up being in this dir or not all dists will be + # NOTE: produced, this will fail the workflow. + path: dist/${{ env.sdist-name }} + retention-days: 15 + tests: name: Tests on ${{ matrix.python-version }} + needs: build-sdist runs-on: ubuntu-latest strategy: fail-fast: false @@ -34,7 +62,12 @@ jobs: - "3.11" steps: - - uses: actions/checkout@v3 + - name: Get source code from pre-built sdist + uses: re-actors/checkout-python-sdist@release/v1 + with: + source-tarball-name: ${{ env.sdist-name }} + workflow-artifact-name: ${{ env.sdist-artifact }} + - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} @@ -51,11 +84,16 @@ jobs: coverage: name: Combine & check coverage. - runs-on: ubuntu-latest needs: tests + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - name: Get source code from pre-built sdist + uses: re-actors/checkout-python-sdist@release/v1 + with: + source-tarball-name: ${{ env.sdist-name }} + workflow-artifact-name: ${{ env.sdist-artifact }} + - uses: actions/setup-python@v4 with: # Use latest Python, so it understands all syntax. @@ -87,6 +125,7 @@ jobs: mypy: name: Mypy on ${{ matrix.python-version }} + needs: build-sdist runs-on: ubuntu-latest strategy: fail-fast: false @@ -99,7 +138,11 @@ jobs: - "3.11" steps: - - uses: actions/checkout@v3 + - name: Get source code from pre-built sdist + uses: re-actors/checkout-python-sdist@release/v1 + with: + source-tarball-name: ${{ env.sdist-name }} + workflow-artifact-name: ${{ env.sdist-artifact }} - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} @@ -109,9 +152,14 @@ jobs: docs: name: Build docs & run doctests + needs: build-sdist runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - name: Get source code from pre-built sdist + uses: re-actors/checkout-python-sdist@release/v1 + with: + source-tarball-name: ${{ env.sdist-name }} + workflow-artifact-name: ${{ env.sdist-artifact }} - uses: actions/setup-python@v4 with: # Keep in sync with tox.ini/docs & readthedocs.yaml From 88a39b54eceaf34c44ef6270542c659da9695470 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 5 Apr 2023 15:37:34 +0200 Subject: [PATCH 0980/1520] tox: python -m is not necessary --- tox.ini | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tox.ini b/tox.ini index 126c9bb9..04d72d1e 100644 --- a/tox.ini +++ b/tox.ini @@ -37,18 +37,18 @@ commands = mypy src typing_examples.py [testenv] extras = tests set_env = PYTHONHASHSEED = 0 -commands = python -m pytest {posargs} +commands = pytest {posargs} # For missing types we get from typing-extensions [testenv:py3{7,11}] deps = twisted -commands = python -m coverage run -m pytest {posargs} +commands = coverage run -m pytest {posargs} [testenv:py39-colorama] deps = colorama -commands = python -m coverage run -m pytest tests/test_dev.py {posargs} +commands = coverage run -m pytest tests/test_dev.py {posargs} [testenv:py311-be] @@ -69,8 +69,8 @@ skip_install = true parallel_show_output = true depends = py37,py39-colorama,py311{,-be,-rich} commands = - python -m coverage combine - python -m coverage report + coverage combine + coverage report [testenv:docset] From 776864bd934c1ae43219b6993a54fe4629b30d13 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 6 Apr 2023 07:50:04 +0200 Subject: [PATCH 0981/1520] Add async log variants to structlog.stdlib.BoundLogger (#502) --- CHANGELOG.md | 5 +++ docs/api.rst | 2 +- docs/getting-started.md | 13 +++--- docs/standard-library.md | 22 ++++++++-- src/structlog/stdlib.py | 86 ++++++++++++++++++++++++++++++++++++++++ tests/test_log_levels.py | 12 ++---- tests/test_stdlib.py | 60 ++++++++++++++++++++++++++++ tox.ini | 2 +- typing_examples.py | 12 ++++++ 9 files changed, 192 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cee51a9d..b8f59ab7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,11 @@ You can find out backwards-compatibility policy [here](https://github.com/hynek/ ## [Unreleased](https://github.com/hynek/structlog/compare/22.3.0...HEAD) +### Added + +- `structlog.stdlib.BoundLogger` now has, analogously to our native logger, a full set of async log methods prefixed with an `a`: `await log.ainfo("event!")` + + ### Fixed - ConsoleRenderer now reuses the `_figure_out_exc_info` to process the `exc_info` argument like `ExceptionRenderer` does. diff --git a/docs/api.rst b/docs/api.rst index d968dbe3..9b6670b0 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -277,7 +277,7 @@ API Reference .. autofunction:: get_logger .. autoclass:: BoundLogger - :members: bind, unbind, try_unbind, new, debug, info, warning, warn, error, critical, exception, log + :members: bind, unbind, try_unbind, new, debug, info, warning, warn, error, critical, exception, log, adebug, ainfo, awarning, aerror, acritical, aexception, alog .. autoclass:: AsyncBoundLogger diff --git a/docs/getting-started.md b/docs/getting-started.md index 935b3a35..7f770a99 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -225,25 +225,22 @@ As noted before, the fastest way to transform *structlog* into a `logging`-frien ## asyncio -*structlog* comes with two approaches to support asynchronous logging. - -The default *bound logger* that you get back from {func}`structlog.get_logger()` doesn't have just the familiar log methods like `debug()` or `info()`, but also their async cousins, that simply prefix the name with an a: +The default *bound logger* that you get back from {func}`structlog.get_logger()` and standard library's {class}`structlog.stdlib.BoundLogger` don't have just the familiar log methods like `debug()` or `info()`, but also their async cousins, that simply prefix the name with an a: ```pycon >>> import asyncio >>> logger = structlog.get_logger() >>> async def f(): -... await logger.ainfo("hi!") +... await logger.ainfo("async hi!") ... +>>> logger.info("Loop isn't running yet, but we can log!") +2023-04-06 07:25:48 [info ] Loop isn't running yet, but we can log! >>> asyncio.run(f()) -2022-10-18 13:23:37 [info ] hi! +2023-04-06 07:26:08 [info ] async hi! ``` You can use the sync and async logging methods interchangeably within the same application. ---- - -The standard library integration on the other hand offers an asynchronous wrapper class {class}`structlog.stdlib.AsyncBoundLogger`. ## Liked what you saw? diff --git a/docs/standard-library.md b/docs/standard-library.md index e51267db..6339db8d 100644 --- a/docs/standard-library.md +++ b/docs/standard-library.md @@ -48,13 +48,29 @@ See also {doc}`typing`. ### `asyncio` -For `asyncio` applications, you may not want your whole application to block while your processor chain is formatting your log entries. -For that use case *structlog* comes with {class}`structlog.stdlib.AsyncBoundLogger` that will do all processing in a thread pool executor. +For `asyncio` applications, you may not want your whole application to block while the processor chain is formatting your log entries. -This means an increased computational cost per log entry but your application will never block because of logging. +For that use case *structlog* comes with a set of non-standard methods that will do all processing in a thread pool executor. +They have the same names as the regular methods, except they are prefixed by an `a`. +So instead of `logger.info("event!")` you write `await logger.ainfo("event!)`. +No extra configuration is necessary and you can mix-and-match both types of methods within the same application. + +This means an increased computational cost per log entry, but your application will not block because of logging. + +```{versionadded} 23.1.0 +``` + +--- + + +*structlog* also comes with {class}`structlog.stdlib.AsyncBoundLogger` that blankly makes all logging methods asynchronous (i.e. `await log.info()`). To use it, {doc}`configure ` *structlog* to use `AsyncBoundLogger` as `wrapper_class`. +```{versionadded} 20.2.0 +``` + + ## Processors diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 9213fbbd..0e336692 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -137,6 +137,9 @@ class BoundLogger(BoundLoggerBase): It also contains a bunch of properties that pass-through to the wrapped `logging.Logger` which should make it work as a drop-in replacement. + + .. versionadded:: 23.1.0 + Async variants `alog()`, `adebug()`, `ainfo()`, and so forth. """ _logger: logging.Logger @@ -375,6 +378,89 @@ def getChild(self, suffix: str) -> logging.Logger: """ return self._logger.getChild(suffix) + # Non-Standard Async + async def _dispatch_to_sync( + self, + meth: Callable[..., Any], + event: str, + args: tuple[Any, ...], + kw: dict[str, Any], + ) -> None: + """ + Merge contextvars and log using the sync logger in a thread pool. + """ + ctx = contextvars.copy_context() + + await asyncio.get_running_loop().run_in_executor( + None, + lambda: ctx.run(lambda: meth(event, *args, **kw)), + ) + + async def adebug(self, event: str, *args: Any, **kw: Any) -> None: + """ + Log using `debug()`, but asynchronously in a separate thread. + + .. versionadded:: 23.1.0 + """ + await self._dispatch_to_sync(self.debug, event, args, kw) + + async def ainfo(self, event: str, *args: Any, **kw: Any) -> None: + """ + Log using `info()`, but asynchronously in a separate thread. + + .. versionadded:: 23.1.0 + """ + await self._dispatch_to_sync(self.info, event, args, kw) + + async def awarning(self, event: str, *args: Any, **kw: Any) -> None: + """ + Log using `warning()`, but asynchronously in a separate thread. + + .. versionadded:: 23.1.0 + """ + await self._dispatch_to_sync(self.warning, event, args, kw) + + async def aerror(self, event: str, *args: Any, **kw: Any) -> None: + """ + Log using `error()`, but asynchronously in a separate thread. + + .. versionadded:: 23.1.0 + """ + await self._dispatch_to_sync(self.error, event, args, kw) + + async def acritical(self, event: str, *args: Any, **kw: Any) -> None: + """ + Log using `critical()`, but asynchronously in a separate thread. + + .. versionadded:: 23.1.0 + """ + await self._dispatch_to_sync(self.critical, event, args, kw) + + afatal = acritical + + async def aexception(self, event: str, *args: Any, **kw: Any) -> None: + """ + Log using `exception()`, but asynchronously in a separate thread. + + .. versionadded:: 23.1.0 + """ + # To make `log.exception("foo") work, we have to check if the user + # passed an explicit exc_info and if not, supply our own. + if kw.get("exc_info", True) is True and kw.get("exception") is None: + kw["exc_info"] = sys.exc_info() + + await self._dispatch_to_sync(self.exception, event, args, kw) + + async def alog( + self, level: Any, event: str, *args: Any, **kw: Any + ) -> None: + """ + Log using `log()`, but asynchronously in a separate thread. + + .. versionadded:: 23.1.0 + """ + await self._dispatch_to_sync(partial(self.log, level), event, args, kw) + def get_logger(*args: Any, **initial_values: Any) -> BoundLogger: """ diff --git a/tests/test_log_levels.py b/tests/test_log_levels.py index 727b4a9f..8faa576d 100644 --- a/tests/test_log_levels.py +++ b/tests/test_log_levels.py @@ -15,16 +15,10 @@ clear_contextvars, merge_contextvars, ) -from structlog.testing import CapturingLogger - - -@pytest.fixture(name="cl") -def fixture_cl(): - return CapturingLogger() @pytest.fixture(name="bl") -def fixture_bl(cl): +def _bl(cl): return make_filtering_bound_logger(logging.INFO)(cl, [], {}) @@ -79,7 +73,7 @@ async def test_async_filtered_interp(self, bl, cl): def test_no_args(self, bl, cl): """ - If no args are passed, don't attempt intepolation. + If no args are passed, don't attempt interpolation. See also #473 """ @@ -89,7 +83,7 @@ def test_no_args(self, bl, cl): async def test_async_no_args(self, bl, cl): """ - If no args are passed, don't attempt intepolation. + If no args are passed, don't attempt interpolation. See also #473 """ diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index e09ee30a..d479438e 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -340,6 +340,66 @@ def test_proxies_try_unbind(self): assert {} == get_context(bl) + @pytest.mark.parametrize( + "meth", ["debug", "info", "warning", "error", "critical"] + ) + async def test_async_log_methods(self, meth, cl): + """ + Async methods log async. + """ + bl = build_bl(cl, processors=[]) + + await getattr(bl, f"a{meth}")("Async!") + + assert [ + CapturedCall(method_name=meth, args=(), kwargs={"event": "Async!"}) + ] == cl.calls + + async def test_alog(self, cl): + """ + Alog logs async at the correct level. + """ + bl = build_bl(cl, processors=[]) + + await bl.alog(logging.INFO, "foo %s", "bar") + + assert [ + CapturedCall( + method_name="info", + args=(), + kwargs={"positional_args": ("bar",), "event": "foo %s"}, + ) + ] == cl.calls + + async def test_aexception_exc_info_true(self, cl): + """ + aexception passes current exc_info into dispatch. + """ + bl = build_bl(cl, processors=[]) + + try: + raise ValueError(42) + except ValueError as e: + await bl.aexception("oops") + exc = e + + (cc,) = cl.calls + + assert isinstance(cc[2]["exc_info"], tuple) + assert exc == cc[2]["exc_info"][1] + + async def test_aexception_exc_info_explicit(self, cl): + """ + In aexception, if exc_info isn't missing or True, leave it be. + """ + bl = build_bl(cl, processors=[]) + + obj = object() + + await bl.aexception("ooops", exc_info=obj) + + assert obj is cl.calls[0].kwargs["exc_info"] + class TestPositionalArgumentsFormatter: def test_formats_tuple(self): diff --git a/tox.ini b/tox.ini index 04d72d1e..e84d268f 100644 --- a/tox.ini +++ b/tox.ini @@ -25,7 +25,7 @@ commands = [testenv:pre-commit] skip_install = true deps = pre-commit -commands = pre-commit run --all-files --show-diff-on-failure +commands = pre-commit run --all-files [testenv:mypy] diff --git a/typing_examples.py b/typing_examples.py index c47d1bfd..ab10880f 100644 --- a/typing_examples.py +++ b/typing_examples.py @@ -309,6 +309,18 @@ async def typecheck_filtering_return_async() -> None: await fblogger.alog(logging.CRITICAL, "async log") +async def typecheck_stdlib_async() -> None: + logger: structlog.stdlib.BoundLogger = structlog.get_logger(__name__) + await logger.adebug("async debug") + await logger.ainfo("async info") + await logger.awarning("async warning") + await logger.aerror("async error") + await logger.afatal("fatal error") + await logger.aexception("async exception") + await logger.acritical("async critical") + await logger.alog(logging.CRITICAL, "async log") + + # Structured tracebacks and ExceptionRenderer with ExceptionDictTransformer struct_tb: structlog.tracebacks.Trace = structlog.tracebacks.extract( ValueError, ValueError("onoes"), None From db7a294cf9dd34015ceb5fced6c2d8b10edb9c86 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 6 Apr 2023 08:53:02 +0200 Subject: [PATCH 0982/1520] Minor style / performance fixes --- src/structlog/__init__.py | 3 ++- src/structlog/_base.py | 25 ++++++++++++------------- src/structlog/_config.py | 12 ++++++------ src/structlog/_output.py | 6 +++--- src/structlog/_utils.py | 6 +++--- src/structlog/dev.py | 14 ++++++-------- src/structlog/processors.py | 23 +++++++++++++---------- src/structlog/stdlib.py | 7 ++----- src/structlog/testing.py | 4 ++-- src/structlog/threadlocal.py | 4 +--- src/structlog/tracebacks.py | 6 ++---- src/structlog/twisted.py | 4 ++-- 12 files changed, 54 insertions(+), 60 deletions(-) diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 2abd189d..52c55d32 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -121,7 +121,8 @@ def __getattr__(name: str) -> str: if name == "__uri__": return meta["Project-URL"].split(" ", 1)[-1] - elif name == "__email__": + + if name == "__email__": return meta["Author-email"].split("<", 1)[1].rstrip(">") return meta[dunder_to_metadata[name]] diff --git a/src/structlog/_base.py b/src/structlog/_base.py index ba736eb0..3b865fda 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -57,10 +57,7 @@ def __repr__(self) -> str: def __eq__(self, other: Any) -> bool: try: - if self._context == other._context: - return True - else: - return False + return self._context == other._context except AttributeError: return False @@ -163,18 +160,20 @@ def _process_event( if isinstance(event_dict, (str, bytes, bytearray)): return (event_dict,), {} - elif isinstance(event_dict, tuple): + + if isinstance(event_dict, tuple): # In this case we assume that the last processor returned a tuple # of ``(args, kwargs)`` and pass it right through. return event_dict # type: ignore[return-value] - elif isinstance(event_dict, dict): + + if isinstance(event_dict, dict): return (), event_dict - else: - raise ValueError( - "Last processor didn't return an appropriate value. Valid " - "return values are a dict, a tuple of (args, kwargs), bytes, " - "or a str." - ) + + raise ValueError( + "Last processor didn't return an appropriate value. Valid " + "return values are a dict, a tuple of (args, kwargs), bytes, " + "or a str." + ) def _proxy_to_logger( self, method_name: str, event: str | None = None, **event_kw: Any @@ -205,7 +204,7 @@ def _proxy_to_logger( args, kw = self._process_event(method_name, event, event_kw) return getattr(self._logger, method_name)(*args, **kw) except DropEvent: - return + return None def get_context(bound_logger: BindableLogger) -> Context: diff --git a/src/structlog/_config.py b/src/structlog/_config.py index c608dfea..b0a424e6 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -255,7 +255,9 @@ def configure_once( cache_logger_on_first_use=cache_logger_on_first_use, ) else: - warnings.warn("Repeated configuration attempted.", RuntimeWarning) + warnings.warn( + "Repeated configuration attempted.", RuntimeWarning, stacklevel=2 + ) def reset_defaults() -> None: @@ -346,8 +348,8 @@ def finalized_bind(**new_values: Any) -> BindableLogger: """ if new_values: return logger.bind(**new_values) - else: - return logger + + return logger if self._cache_logger_on_first_use is True or ( self._cache_logger_on_first_use is None @@ -377,9 +379,7 @@ def new(self, **new_values: Any) -> BindableLogger: else: _CONFIG.default_context_class().clear() - bl = self.bind(**new_values) - - return bl + return self.bind(**new_values) def __getattr__(self, name: str) -> Any: """ diff --git a/src/structlog/_output.py b/src/structlog/_output.py index 5b0b915e..2f214948 100644 --- a/src/structlog/_output.py +++ b/src/structlog/_output.py @@ -67,7 +67,7 @@ def __getstate__(self) -> str: if self._file is stdout: return "stdout" - elif self._file is stderr: + if self._file is stderr: return "stderr" raise PicklingError( @@ -171,7 +171,7 @@ def __getstate__(self) -> str: if self._file is stdout: return "stdout" - elif self._file is stderr: + if self._file is stderr: return "stderr" raise PicklingError( @@ -271,7 +271,7 @@ def __getstate__(self) -> str: if self._file is sys.stdout.buffer: return "stdout" - elif self._file is sys.stderr.buffer: + if self._file is sys.stderr.buffer: return "stderr" raise PicklingError( diff --git a/src/structlog/_utils.py b/src/structlog/_utils.py index 715ec631..b57e55ab 100644 --- a/src/structlog/_utils.py +++ b/src/structlog/_utils.py @@ -12,6 +12,7 @@ import errno import sys +from contextlib import suppress from typing import Any, Callable @@ -41,8 +42,7 @@ def get_processname() -> str: # Errors may occur if multiprocessing has not finished loading # yet - e.g. if a custom import hook causes third-party code # to run when multiprocessing calls import. - try: + with suppress(Exception): processname = mp.current_process().name - except Exception: - pass + return processname diff --git a/src/structlog/dev.py b/src/structlog/dev.py index d72fff22..6a2517a0 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -321,7 +321,7 @@ def __init__( else: self._level_to_color = level_styles - for key in self._level_to_color.keys(): + for key in self._level_to_color: self._level_to_color[key] += styles.bright self._longest_level = len( max(self._level_to_color.keys(), key=lambda e: len(e)) @@ -342,8 +342,8 @@ def _repr(self, val: Any) -> str: if isinstance(val, str): return val - else: - return repr(val) + + return repr(val) def __call__( self, logger: WrappedLogger, name: str, event_dict: EventDict @@ -428,7 +428,8 @@ def __call__( if self._exception_formatter is not plain_traceback: warnings.warn( "Remove `format_exc_info` from your processor chain " - "if you want pretty exceptions." + "if you want pretty exceptions.", + stacklevel=2, ) sio.write("\n" + exc) @@ -451,10 +452,7 @@ def get_default_level_styles(colors: bool = True) -> Any: *colors* parameter to `ConsoleRenderer`. Default: `True`. """ styles: Styles - if colors: - styles = _ColorfulStyles - else: - styles = _PlainStyles + styles = _ColorfulStyles if colors else _PlainStyles return { "critical": styles.level_critical, "exception": styles.level_exception, diff --git a/src/structlog/processors.py b/src/structlog/processors.py index b9d81df9..8c5e0c7c 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -95,8 +95,8 @@ def __init__( def _repr(inst: Any) -> str: if isinstance(inst, str): return inst - else: - return repr(inst) + + return repr(inst) self._repr = _repr @@ -336,11 +336,11 @@ def _json_fallback_handler(obj: Any) -> Any: if isinstance(obj, _ThreadLocalDictWrapper): return obj._dict - else: - try: - return obj.__structlog__() - except AttributeError: - return repr(obj) + + try: + return obj.__structlog__() + except AttributeError: + return repr(obj) class ExceptionRenderer: @@ -492,7 +492,8 @@ def stamper_unix(event_dict: EventDict) -> EventDict: return event_dict return stamper_unix - elif fmt.upper() == "ISO": + + if fmt.upper() == "ISO": def stamper_iso_local(event_dict: EventDict) -> EventDict: event_dict[key] = now().isoformat() @@ -522,9 +523,11 @@ def _figure_out_exc_info(v: Any) -> ExcInfo: """ if isinstance(v, BaseException): return (v.__class__, v, v.__traceback__) - elif isinstance(v, tuple): + + if isinstance(v, tuple): return v # type: ignore[return-value] - elif v: + + if v: return sys.exc_info() # type: ignore[return-value] return v diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 0e336692..b73fc899 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -114,10 +114,7 @@ def findCaller( """ sinfo: str | None f, name = _find_first_app_frame_and_name(["logging"]) - if stack_info: - sinfo = _format_stack(f) - else: - sinfo = None + sinfo = _format_stack(f) if stack_info else None return f.f_code.co_filename, f.f_lineno, f.f_code.co_name, sinfo @@ -788,7 +785,7 @@ def add_logger_name( _LOG_RECORD_KEYS = logging.LogRecord( - "name", 0, "pathname", 0, "msg", tuple(), None + "name", 0, "pathname", 0, "msg", (), None ).__dict__.keys() diff --git a/src/structlog/testing.py b/src/structlog/testing.py index 1884ea26..34c62f94 100644 --- a/src/structlog/testing.py +++ b/src/structlog/testing.py @@ -108,8 +108,8 @@ def msg(self, *args: Any, **kw: Any) -> Any: # Slightly convoluted for backwards compatibility. if len(args) == 1 and not kw: return args[0] - else: - return args, kw + + return args, kw log = debug = info = warn = warning = msg fatal = failure = err = error = critical = exception = msg diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index 70685eb3..4fa043f7 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -216,9 +216,7 @@ def __len__(self) -> int: return self._dict.__len__() def __getattr__(self, name: str) -> Any: - method = getattr(self._dict, name) - - return method + return getattr(self._dict, name) _CONTEXT = threading.local() diff --git a/src/structlog/tracebacks.py b/src/structlog/tracebacks.py index b032df08..50643516 100644 --- a/src/structlog/tracebacks.py +++ b/src/structlog/tracebacks.py @@ -202,8 +202,7 @@ def extract( # No cover, code is reached but coverage doesn't recognize it. break # pragma: no cover - trace = Trace(stacks=stacks) - return trace + return Trace(stacks=stacks) class ExceptionDictTransformer: @@ -266,5 +265,4 @@ def __call__(self, exc_info: ExcInfo) -> list[dict[str, Any]]: *stack.frames[-half:], ] - stack_dicts = [asdict(stack) for stack in trace.stacks] - return stack_dicts + return [asdict(stack) for stack in trace.stacks] diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index b00568ec..22b62301 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -324,5 +324,5 @@ def __call__( "_why": self._dictRenderer(logger, name, eventDict), }, ) - else: - return self._dictRenderer(logger, name, eventDict) + + return self._dictRenderer(logger, name, eventDict) From e968ce129ef27ddf47a2df582e2cd50866282c14 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 6 Apr 2023 10:08:06 +0200 Subject: [PATCH 0983/1520] Add support for FORCE_COLOR (#503) fixes #495 --- .github/workflows/ci.yml | 19 +++++++++++++++++++ CHANGELOG.md | 5 +++++ src/structlog/_config.py | 12 ++++++++---- tox.ini | 6 ++++++ 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index db5c511f..8bafdd64 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -199,3 +199,22 @@ jobs: uses: re-actors/alls-green@release/v1 with: jobs: ${{ toJSON(needs) }} + + + colors: + name: Visual check for color settings using env variables + needs: build-sdist + runs-on: ubuntu-latest + + steps: + - name: Get source code from pre-built sdist + uses: re-actors/checkout-python-sdist@release/v1 + with: + source-tarball-name: ${{ env.sdist-name }} + workflow-artifact-name: ${{ env.sdist-artifact }} + - uses: actions/setup-python@v4 + with: + python-version: ${{env.PYTHON_LATEST}} + - run: python -Im pip install tox wheel + + - run: tox -f color diff --git a/CHANGELOG.md b/CHANGELOG.md index b8f59ab7..bd99e37c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,11 @@ You can find out backwards-compatibility policy [here](https://github.com/hynek/ ### Added - `structlog.stdlib.BoundLogger` now has, analogously to our native logger, a full set of async log methods prefixed with an `a`: `await log.ainfo("event!")` + [#502](https://github.com/hynek/structlog/issues/502) + +- The default configuration now respects the presence of `FORCE_COLOR` (regardless of its value except empty string). + This disables all heuristics whether it makes sense to use colors. + [#338](https://github.com/hynek/structlog/issues/338) ### Fixed diff --git a/src/structlog/_config.py b/src/structlog/_config.py index b0a424e6..68159571 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -9,6 +9,7 @@ from __future__ import annotations +import os import sys import warnings @@ -35,10 +36,13 @@ set_exc_info, TimeStamper(fmt="%Y-%m-%d %H:%M:%S", utc=False), ConsoleRenderer( - colors=_has_colors - and sys.stdout is not None - and hasattr(sys.stdout, "isatty") - and sys.stdout.isatty() + colors=os.environ.get("FORCE_COLOR") is not None + or ( + _has_colors + and sys.stdout is not None + and hasattr(sys.stdout, "isatty") + and sys.stdout.isatty() + ) ), ] _BUILTIN_DEFAULT_CONTEXT_CLASS = cast(Type[Context], dict) diff --git a/tox.ini b/tox.ini index e84d268f..0f3c6182 100644 --- a/tox.ini +++ b/tox.ini @@ -73,6 +73,12 @@ commands = coverage report +[testenv:color-force] +help = A visual check that FORCE_COLOR is working. +set_env = FORCE_COLOR=1 +commands = python -c "import structlog; structlog.get_logger().warning('should be colorful')" + + [testenv:docset] deps = doc2dash extras = docs From 02a48b7caff53519d05fdc7df27f1ae6fb64b9eb Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 6 Apr 2023 10:31:54 +0200 Subject: [PATCH 0984/1520] Add support for NO_COLOR (#504) * Add support for NO_COLOR * Document * ' --- CHANGELOG.md | 8 ++++++-- docs/console-output.md | 11 +++++++++++ src/structlog/_config.py | 15 +++++++++------ tox.ini | 6 ++++++ 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd99e37c..fdb2ca86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,9 +20,13 @@ You can find out backwards-compatibility policy [here](https://github.com/hynek/ - `structlog.stdlib.BoundLogger` now has, analogously to our native logger, a full set of async log methods prefixed with an `a`: `await log.ainfo("event!")` [#502](https://github.com/hynek/structlog/issues/502) -- The default configuration now respects the presence of `FORCE_COLOR` (regardless of its value except empty string). +- The default configuration now respects the presence of `FORCE_COLOR` (regardless of its value, unless an empty string). This disables all heuristics whether it makes sense to use colors. - [#338](https://github.com/hynek/structlog/issues/338) + [#503](https://github.com/hynek/structlog/issues/503) + +- The default configuration now respects the presence of [`NO_COLOR`](https://no-color.org) (regardless of its value, unless an empty string). + This disables all heuristics whether it makes sense to use colors and overrides `FORCE_COLOR`. + [#504](https://github.com/hynek/structlog/issues/504) ### Fixed diff --git a/docs/console-output.md b/docs/console-output.md index fc258d8b..fe3905dd 100644 --- a/docs/console-output.md +++ b/docs/console-output.md @@ -47,6 +47,17 @@ structlog.configure( ``` +## Standard Environment Variables + +*structlog*'s default configuration uses colors if standard out is a TTY (i.e. an interactive session). + +It's possible to override this behavior by setting two standard environment variables to any value except an empty string: + +- `FORCE_COLOR` *activates* colors, regardless of where output is going. +- [`NO_COLOR`](https://no-color.org) *disables* colors, regardless of where the output is going and regardless the value of `FORCE_COLOR`. + Please note that `NO_COLOR` disables _all_ styling, including bold and italics. + + ## Disabling Exception Pretty-Printing If you prefer the default terse Exception rendering, but still want *Rich* installed, you can disable the pretty-printing by instantiating {class}`structlog.dev.ConsoleRenderer()` yourself and passing `exception_formatter=structlog.dev.plain_traceback`. diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 68159571..2eb5c4e0 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -36,12 +36,15 @@ set_exc_info, TimeStamper(fmt="%Y-%m-%d %H:%M:%S", utc=False), ConsoleRenderer( - colors=os.environ.get("FORCE_COLOR") is not None - or ( - _has_colors - and sys.stdout is not None - and hasattr(sys.stdout, "isatty") - and sys.stdout.isatty() + colors=os.environ.get("NO_COLOR", "") == "" + and ( + os.environ.get("FORCE_COLOR", "") != "" + or ( + _has_colors + and sys.stdout is not None + and hasattr(sys.stdout, "isatty") + and sys.stdout.isatty() + ) ) ), ] diff --git a/tox.ini b/tox.ini index 0f3c6182..71e52e65 100644 --- a/tox.ini +++ b/tox.ini @@ -79,6 +79,12 @@ set_env = FORCE_COLOR=1 commands = python -c "import structlog; structlog.get_logger().warning('should be colorful')" +[testenv:color-no] +help = A visual check that NO_COLOR is working. +set_env = NO_COLOR=1 +commands = python -c "import structlog; structlog.get_logger().warning('should be plain')" + + [testenv:docset] deps = doc2dash extras = docs From 092fad9e5e37edca46db76b3ff0d7bb2c50e0619 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 6 Apr 2023 10:55:52 +0200 Subject: [PATCH 0985/1520] Remove stale experiment --- pyproject.toml | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8e2a2d36..18ebb192 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -181,25 +181,3 @@ text = """ path = "README.md" start-at = "## Credits" end-before = "" - - -[tool.hatch.envs.tests] -features = ["tests"] -dev-mode = false - -[tool.hatch.envs.tests.scripts] -run = "coverage run -m pytest" - -[[tool.hatch.envs.tests.matrix]] -python = ["3.7", "3.8", "3.9", "3.10", "3.11"] - - -[tool.hatch.envs.coverage] -detached = true -dependencies = [ - "coverage[toml]>=6.2", - "lxml", -] -[tool.hatch.envs.coverage.scripts] -combine = "coverage combine {args}" -report = "coverage report --skip-covered --skip-empty" From 4d9bc1ee3051050008604f6dd89f905a5734a830 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 6 Apr 2023 11:03:04 +0200 Subject: [PATCH 0986/1520] Prepare 23.1.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fdb2ca86..d5f18727 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ You can find out backwards-compatibility policy [here](https://github.com/hynek/ -## [Unreleased](https://github.com/hynek/structlog/compare/22.3.0...HEAD) +## [23.1.0](https://github.com/hynek/structlog/compare/22.3.0...23.1.0) - 2023-04-06 ### Added From 7794e1f96abbcee0c7dc673ca6d2df264bb40f55 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 6 Apr 2023 11:15:25 +0200 Subject: [PATCH 0987/1520] Start new development cycle --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5f18727..dfdf2161 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ You can find out backwards-compatibility policy [here](https://github.com/hynek/ +## [Unreleased](https://github.com/hynek/structlog/compare/23.1.0...HEAD) + + ## [23.1.0](https://github.com/hynek/structlog/compare/22.3.0...23.1.0) - 2023-04-06 ### Added From e72558f3146a474f512997c1d7fa53ef55299598 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 6 Apr 2023 14:31:52 +0200 Subject: [PATCH 0988/1520] Use SPDX for license field yay PEP 639 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 18ebb192..317ca518 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ name = "structlog" description = "Structured Logging for Python" authors = [{ name = "Hynek Schlawack", email = "hs@ox.cx" }] requires-python = ">=3.7" -license = { file = "COPYRIGHT" } +license = "MIT OR Apache-2.0" keywords = ["logging", "structured", "structure", "log"] classifiers = [ "Development Status :: 5 - Production/Stable", From b5a650156545941811b831bf1dcd71a204ef4626 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 24 Apr 2023 15:15:27 -0600 Subject: [PATCH 0989/1520] Switch to PyPI Trusted Publisher --- .github/workflows/pypi-package.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/pypi-package.yml b/.github/workflows/pypi-package.yml index 8a613ff0..cdd26b99 100644 --- a/.github/workflows/pypi-package.yml +++ b/.github/workflows/pypi-package.yml @@ -14,6 +14,7 @@ on: permissions: contents: read + id-token: write jobs: # Always build & lint package. @@ -46,7 +47,6 @@ jobs: - name: Upload package to Test PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: - password: ${{ secrets.TEST_PYPI_API_TOKEN }} repository-url: https://test.pypi.org/legacy/ # Upload to real PyPI on GitHub Releases. @@ -66,5 +66,3 @@ jobs: - name: Upload package to PyPI uses: pypa/gh-action-pypi-publish@release/v1 - with: - password: ${{ secrets.PYPI_API_TOKEN }} From 09a5056d5eaa79891c4b3b4d02fe01897e32f83f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 1 May 2023 16:47:53 -0600 Subject: [PATCH 0990/1520] [pre-commit.ci] pre-commit autoupdate (#508) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5001cb0b..dd12e214 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,7 +12,7 @@ repos: - id: black - repo: https://github.com/asottile/pyupgrade - rev: v3.3.1 + rev: v3.3.2 hooks: - id: pyupgrade args: [--py37-plus] From 1e9c6c92e539c550f8204b54de8432c7fee7dbd1 Mon Sep 17 00:00:00 2001 From: "JC (Jonathan Chen)" Date: Fri, 12 May 2023 17:45:14 -0400 Subject: [PATCH 0991/1520] docs: fix spelling (#512) --- src/structlog/dev.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 6a2517a0..9a812571 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -169,7 +169,7 @@ def plain_traceback(sio: TextIO, exc_info: ExcInfo) -> None: To be passed into `ConsoleRenderer`'s ``exception_formatter`` argument. - Used by default if neither *Rich* not *better-exceptions* are present. + Used by default if neither *Rich* nor *better-exceptions* are present. .. versionadded:: 21.2 """ From 3a5b9fe3a364d0541a112a3b3314129700a04db2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 13 May 2023 08:20:36 -0600 Subject: [PATCH 0992/1520] Fix type hint ignore --- src/structlog/stdlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index b73fc899..54f9920f 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -1006,7 +1006,7 @@ def format(self, record: logging.LogRecord) -> str: # We need to copy because it's possible that the same record gets # processed by multiple logging formatters. LogRecord.getMessage # would transform our dict into a str. - ed = record.msg.copy() # type: ignore[attr-defined] + ed = record.msg.copy() # type: ignore[union-attr] ed["_record"] = record ed["_from_structlog"] = True else: From 214944a6bb6ce0c4843b16220f342cebfbd12f9c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 13 May 2023 08:21:12 -0600 Subject: [PATCH 0993/1520] pre-commit update --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index dd12e214..258c7070 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,7 +12,7 @@ repos: - id: black - repo: https://github.com/asottile/pyupgrade - rev: v3.3.2 + rev: v3.4.0 hooks: - id: pyupgrade args: [--py37-plus] From 9eba060391904ec1de5ad4940d3da4e40e9d0713 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 13 May 2023 09:15:46 -0600 Subject: [PATCH 0994/1520] Build docs on 22.04 --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 3f7ab7ad..5736bad0 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -4,7 +4,7 @@ version: 2 formats: [htmlzip, epub] build: - os: ubuntu-20.04 + os: ubuntu-22.04 tools: # Keep version in sync with tox.ini/docs and ci.yml/docs python: "3.11" From f21e352a23f80c9add430f84247813c6cc4a45fd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 22 May 2023 16:47:13 +0200 Subject: [PATCH 0995/1520] Stop using deprecated utcnow --- src/structlog/processors.py | 4 ++-- tests/test_processors.py | 17 ++++++----------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 8c5e0c7c..aeaff887 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -477,7 +477,7 @@ def _make_stamper( if utc: def now() -> datetime.datetime: - return datetime.datetime.utcnow() + return datetime.datetime.now(tz=datetime.timezone.utc) else: @@ -500,7 +500,7 @@ def stamper_iso_local(event_dict: EventDict) -> EventDict: return event_dict def stamper_iso_utc(event_dict: EventDict) -> EventDict: - event_dict[key] = now().isoformat() + "Z" + event_dict[key] = now().isoformat().replace("+00:00", "Z") return event_dict if utc: diff --git a/tests/test_processors.py b/tests/test_processors.py index b6e74e9f..b3d2112b 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -440,21 +440,16 @@ def test_pickle(self, fmt, utc, key, proto): None, None, {} ) - @pytest.mark.parametrize( - ("utc", "expect"), - [ - (True, "1980-03-25T16:00:00Z"), - (False, "1980-03-25T17:00:00"), - ], - ) - def test_apply_freezegun_after_instantiation(self, utc, expect): + def test_apply_freezegun_after_instantiation(self): """ - Instantiate TimeStamper after mocking datetime + Freezing time after instantiation of TimeStamper works. """ - ts = TimeStamper(fmt="iso", utc=utc) + ts = TimeStamper(fmt="iso", utc=False) + with freeze_time("1980-03-25 16:00:00", tz_offset=1): d = ts(None, None, {}) - assert expect == d["timestamp"] + + assert "1980-03-25T17:00:00" == d["timestamp"] class TestFormatExcInfo: From ad28ca3586ec82598c540ff5253801679744a30c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 22 May 2023 17:13:26 +0200 Subject: [PATCH 0996/1520] Add support for Python 3.12 (#515) * Add support for Python 3.12 * Run mypy too * Add changelog entry * Add missing allow-prereleases option * Fix race condition --- .github/workflows/ci.yml | 4 ++++ CHANGELOG.md | 5 +++++ pyproject.toml | 1 + tests/test_generic.py | 3 +++ tox.ini | 1 + 5 files changed, 14 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8bafdd64..aca9293b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -60,6 +60,7 @@ jobs: - "3.9" - "3.10" - "3.11" + - "3.12" steps: - name: Get source code from pre-built sdist @@ -71,6 +72,7 @@ jobs: - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} + allow-prereleases: true - run: python -Im pip install --upgrade wheel tox - run: python -Im tox run -f py$(echo ${{ matrix.python-version }} | tr -d .) @@ -136,6 +138,7 @@ jobs: - "3.9" - "3.10" - "3.11" + - "3.12" steps: - name: Get source code from pre-built sdist @@ -146,6 +149,7 @@ jobs: - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} + allow-prereleases: true - run: python -Im pip install --upgrade wheel tox - run: python -Im tox -e mypy diff --git a/CHANGELOG.md b/CHANGELOG.md index dfdf2161..3917f50e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,11 @@ You can find out backwards-compatibility policy [here](https://github.com/hynek/ ## [Unreleased](https://github.com/hynek/structlog/compare/23.1.0...HEAD) +### Added + +- Official support for Python 3.12. + [#515](https://github.com/hynek/structlog/issues/515) + ## [23.1.0](https://github.com/hynek/structlog/compare/22.3.0...23.1.0) - 2023-04-06 diff --git a/pyproject.toml b/pyproject.toml index 317ca518..265baef8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,7 @@ classifiers = [ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Programming Language :: Python", diff --git a/tests/test_generic.py b/tests/test_generic.py index 7f30ac77..65ff141a 100644 --- a/tests/test_generic.py +++ b/tests/test_generic.py @@ -7,6 +7,8 @@ import pytest +from freezegun import freeze_time + from structlog._config import _CONFIG from structlog._generic import BoundLogger from structlog.testing import ReturnLogger @@ -52,6 +54,7 @@ def test_proxies_anything(self): assert "gol", "bar" == b.gol("bar") @pytest.mark.parametrize("proto", range(3, pickle.HIGHEST_PROTOCOL + 1)) + @freeze_time("2023-05-22 17:00") def test_pickle(self, proto): """ Can be pickled and unpickled. diff --git a/tox.ini b/tox.ini index 71e52e65..2897ed83 100644 --- a/tox.ini +++ b/tox.ini @@ -8,6 +8,7 @@ env_list = py39{,-colorama}, py310, py311{,-be,-rich}, + py312, docs, coverage-report From 2e2b6543b5b73aaaa2a375e03e482d4ebef58dae Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 2 Jun 2023 16:36:31 +0200 Subject: [PATCH 0997/1520] Use .python-version --- .github/CONTRIBUTING.md | 10 +++++++++- .github/workflows/ci.yml | 14 ++++---------- .pre-commit-config.yaml | 3 ++- .python-version | 1 + 4 files changed, 16 insertions(+), 12 deletions(-) create mode 100644 .python-version diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 41d34bdc..bd1a1ad3 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -41,7 +41,15 @@ The official tag is `structlog` and helping out in support frees us up to improv You can (and should) run our test suite using [*tox*]. However, you’ll probably want a more traditional environment as well. -We highly recommend to develop using the latest Python release because we try to take advantage of modern features whenever possible. + +First, create a [virtual environment](https://virtualenv.pypa.io/) so you don't break your system-wide Python installation. +We recommend using the Python version from the `.python-version` file in project's root directory. + +If you're using [*direnv*](https://direnv.net), you can automate the creation of a virtual environment with the correct Python version by adding the following `.envrc` to the project root: + +```bash +layout python python$(cat .python-version) +``` Clone the *structlog* repository: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aca9293b..301e5082 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,13 +13,15 @@ env: TOX_TESTENV_PASSENV: FORCE_COLOR PIP_DISABLE_PIP_VERSION_CHECK: "1" PIP_NO_PYTHON_VERSION_WARNING: "1" - PYTHON_LATEST: "3.11" # For re-actors/checkout-python-sdist SETUPTOOLS_SCM_PRETEND_VERSION: "1.0" # hard-code version for predictable sdist names sdist-artifact: python-package-distributions sdist-name: structlog-1.0.tar.gz + # N.B. default Python version for setup-python comes from the .python-version + # file at the root of the project. + permissions: contents: read @@ -31,8 +33,6 @@ jobs: steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 - with: - python-version: ${{ env.PYTHON_LATEST }} - run: python -Im pip install build - run: python -Im build --sdist @@ -97,9 +97,6 @@ jobs: workflow-artifact-name: ${{ env.sdist-artifact }} - uses: actions/setup-python@v4 - with: - # Use latest Python, so it understands all syntax. - python-version: ${{env.PYTHON_LATEST}} - run: python -Im pip install --upgrade coverage[toml] @@ -182,8 +179,7 @@ jobs: steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 - with: - python-version: ${{env.PYTHON_LATEST}} + - run: python -Im pip install -e .[dev] - run: python -Ic 'import structlog; print(structlog.__version__)' @@ -217,8 +213,6 @@ jobs: source-tarball-name: ${{ env.sdist-name }} workflow-artifact-name: ${{ env.sdist-artifact }} - uses: actions/setup-python@v4 - with: - python-version: ${{env.PYTHON_LATEST}} - run: python -Im pip install tox wheel - run: tox -f color diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 258c7070..4f9858dd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,8 @@ ci: autoupdate_schedule: monthly default_language_version: - python: python3.10 + # Keep in-sync with .python-version + python: python3.11 repos: - repo: https://github.com/psf/black diff --git a/.python-version b/.python-version new file mode 100644 index 00000000..2c073331 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.11 From a23932c4a8e87b9fcc79ef893d1822b2c5acf6aa Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 3 Jun 2023 05:54:44 +0200 Subject: [PATCH 0998/1520] Fix comment --- tox.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index 2897ed83..0a4218ad 100644 --- a/tox.ini +++ b/tox.ini @@ -41,7 +41,7 @@ set_env = PYTHONHASHSEED = 0 commands = pytest {posargs} -# For missing types we get from typing-extensions +# Run oldest and latest under Coverage. [testenv:py3{7,11}] deps = twisted commands = coverage run -m pytest {posargs} @@ -63,7 +63,7 @@ commands = {[testenv:py39-colorama]commands} [testenv:coverage-report] -# Keep in sync with ci.yml/PYTHON_LATEST +# Keep in sync with .python-version basepython = python3.11 deps = coverage[toml] skip_install = true From d87abcb83cca4a439924ca9bd8ecde49c676f94c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 3 Jun 2023 06:50:27 +0200 Subject: [PATCH 0999/1520] Ruff life --- .flake8 | 4 ---- .github/CONTRIBUTING.md | 2 +- .pre-commit-config.yaml | 26 ++++----------------- pyproject.toml | 44 ++++++++++++++++++++++++++++++++++-- src/structlog/_config.py | 6 ++--- src/structlog/_greenlets.py | 4 ++-- src/structlog/_output.py | 6 ++--- src/structlog/dev.py | 9 ++------ src/structlog/processors.py | 7 +++--- src/structlog/threadlocal.py | 5 ++-- src/structlog/tracebacks.py | 2 +- tests/test_dev.py | 2 +- tests/test_processors.py | 12 +++++----- tests/test_stdlib.py | 39 ++++++++++++++------------------ tests/test_testing.py | 5 ++-- tests/test_threadlocal.py | 29 ++++++++++++------------ tests/test_tracebacks.py | 10 ++++---- typing_examples.py | 4 ++-- 18 files changed, 111 insertions(+), 105 deletions(-) delete mode 100644 .flake8 diff --git a/.flake8 b/.flake8 deleted file mode 100644 index c2e7c7f3..00000000 --- a/.flake8 +++ /dev/null @@ -1,4 +0,0 @@ -[flake8] -ignore = E203,W503,W504,E741 - -# vim: ft=dosini diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index bd1a1ad3..a32f43a6 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -120,7 +120,7 @@ But it's way more comfortable to run it locally and catch avoidable errors befor """ ``` - If you add or change public APIs, tag the docstring using `.. versionadded:: 16.0.0 WHAT` or `.. versionchanged:: 16.2.0 WHAT`. -- We use [*isort*](https://github.com/PyCQA/isort) to sort our imports, and we use [*Black*](https://github.com/psf/black) with line length of 79 characters to format our code. +- We use [*Ruff*](https://ruff.rs/) to sort our imports, and we use [*Black*](https://github.com/psf/black) with line length of 79 characters to format our code. As long as you run our full [*tox*] suite before committing, or install our [*pre-commit*] hooks (ideally you'll do both – see [*Local Development Environment*](#local-development-environment) above), you won't have to spend any time on formatting your code at all. If you don't, [CI] will catch it for you – but that seems like a waste of your time! diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4f9858dd..176c3ef4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,28 +12,11 @@ repos: hooks: - id: black - - repo: https://github.com/asottile/pyupgrade - rev: v3.4.0 + - repo: https://github.com/charliermarsh/ruff-pre-commit + rev: v0.0.270 hooks: - - id: pyupgrade - args: [--py37-plus] - - - repo: https://github.com/PyCQA/isort - rev: 5.12.0 - hooks: - - id: isort - additional_dependencies: [toml] - - - repo: https://github.com/asottile/yesqa - rev: v1.4.0 - hooks: - - id: yesqa - - - repo: https://github.com/PyCQA/flake8 - rev: 6.0.0 - hooks: - - id: flake8 - exclude: docs/code_examples + - id: ruff + args: [--fix, --exit-non-zero-on-fix] - repo: https://github.com/codespell-project/codespell rev: v2.2.4 @@ -46,6 +29,5 @@ repos: hooks: - id: trailing-whitespace - id: end-of-file-fixer - - id: debug-statements - id: check-toml - id: check-yaml diff --git a/pyproject.toml b/pyproject.toml index 265baef8..7de9c754 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -117,8 +117,48 @@ exclude_lines = [ line-length = 79 -[tool.isort] -profile = "attrs" +[tool.ruff] +src = ["src", "tests"] +select = [ + "E", # pycodestyle + "W", # pycodestyle + "F", # Pyflakes + "UP", # pyupgrade + "N", # pep8-naming + "YTT", # flake8-2020 + "S", # flake8-bandit + "B", # flake8-bugbear + "C4", # flake8-comprehensions + "T10", # flake8-debugger + "ISC", # flake8-implicit-str-concat + "RET", # flake8-return + "SIM", # flake8-simplify + "DTZ", # flake8-datetimez + "I", # isort + "PGH", # pygrep-hooks + "PLC", # Pylint + "PIE", # flake8-pie + "RUF", # ruff +] +ignore = [ + "RUF001", # leave my smart characters alone + "N802", # some names are non-pep8 due to stdlib logging / Twisted + "N803", # ditto + "N806", # ditto + "B018", # "useless" expressions can be useful in tests +] + +[tool.ruff.per-file-ignores] +"tests/*" = [ + "S101", # assert + "S301", # I know pickle is bad, but people like it. + "SIM300", # Yoda rocks in tests + "PLC1901", # empty strings are falsey, but are less specific in tests +] + +[tool.ruff.isort] +lines-between-types = 1 +lines-after-imports = 2 [tool.mypy] diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 2eb5c4e0..b91ebdc1 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -36,9 +36,9 @@ set_exc_info, TimeStamper(fmt="%Y-%m-%d %H:%M:%S", utc=False), ConsoleRenderer( - colors=os.environ.get("NO_COLOR", "") == "" + colors=os.environ.get("NO_COLOR", "") == "" # noqa: PLC1901 and ( - os.environ.get("FORCE_COLOR", "") != "" + os.environ.get("FORCE_COLOR", "") != "" # noqa: PLC1901 or ( _has_colors and sys.stdout is not None @@ -134,7 +134,7 @@ def get_logger(*args: Any, **initial_values: Any) -> Any: return wrap_logger(None, logger_factory_args=args, **initial_values) -getLogger = get_logger +getLogger = get_logger # noqa: N816 """ CamelCase alias for `structlog.get_logger`. diff --git a/src/structlog/_greenlets.py b/src/structlog/_greenlets.py index 43db1c10..0583048b 100644 --- a/src/structlog/_greenlets.py +++ b/src/structlog/_greenlets.py @@ -30,7 +30,7 @@ def __getattr__(self, name: str) -> Any: try: return self._weakdict[key][name] except KeyError: - raise AttributeError(name) + raise AttributeError(name) from None def __setattr__(self, name: str, val: Any) -> None: key = getcurrent() @@ -41,4 +41,4 @@ def __delattr__(self, name: str) -> None: try: del self._weakdict[key][name] except KeyError: - raise AttributeError(name) + raise AttributeError(name) from None diff --git a/src/structlog/_output.py b/src/structlog/_output.py index 2f214948..d73739eb 100644 --- a/src/structlog/_output.py +++ b/src/structlog/_output.py @@ -85,7 +85,7 @@ def __setstate__(self, state: Any) -> None: self._lock = _get_lock_for_file(self._file) - def __deepcopy__(self, memodict: dict[Any, Any] = {}) -> PrintLogger: + def __deepcopy__(self, memodict: dict[str, object]) -> PrintLogger: """ Create a new PrintLogger with the same attributes. Similar to pickling. """ @@ -189,7 +189,7 @@ def __setstate__(self, state: Any) -> None: self._lock = _get_lock_for_file(self._file) - def __deepcopy__(self, memodict: dict[Any, Any] = {}) -> WriteLogger: + def __deepcopy__(self, memodict: dict[str, object]) -> WriteLogger: """ Create a new WriteLogger with the same attributes. Similar to pickling. """ @@ -291,7 +291,7 @@ def __setstate__(self, state: Any) -> None: self._flush = self._file.flush self._lock = _get_lock_for_file(self._file) - def __deepcopy__(self, memodict: dict[Any, Any] = {}) -> BytesLogger: + def __deepcopy__(self, memodict: dict[str, object]) -> BytesLogger: """ Create a new BytesLogger with the same attributes. Similar to pickling. """ diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 9a812571..d651faaf 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -95,13 +95,8 @@ def _pad(s: str, length: int) -> str: GREEN = "\033[32m" RED_BACK = "\033[41m" - -if _IS_WINDOWS: # pragma: no cover - # On Windows, use colors by default only if Colorama is installed. - _has_colors = colorama is not None -else: - # On other OSes, use colors by default. - _has_colors = True +# On Windows, colors are only available if Colorama is installed. +_has_colors = not _IS_WINDOWS or colorama is not None # Prevent breakage of packages that used the old name of the variable. _use_colors = _has_colors diff --git a/src/structlog/processors.py b/src/structlog/processors.py index aeaff887..86b6c344 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -171,7 +171,7 @@ def _items_sorter( sort_keys: bool, key_order: Sequence[str] | None, drop_missing: bool, -) -> Callable[[EventDict], list[tuple[str, Any]]]: +) -> Callable[[EventDict], list[tuple[str, object]]]: """ Return a function to sort items from an ``event_dict``. @@ -214,7 +214,7 @@ def ordered_items(event_dict: EventDict) -> list[tuple[str, Any]]: "items" ) - return ordered_items + return ordered_items # noqa: RET504 class UnicodeEncoder: @@ -482,7 +482,8 @@ def now() -> datetime.datetime: else: def now() -> datetime.datetime: - return datetime.datetime.now() + # A naive local datetime is fine here, because we only format it. + return datetime.datetime.now() # noqa: DTZ005 if fmt is None: diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index 4fa043f7..05afdd1d 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -51,13 +51,12 @@ def _deprecated() -> None: Raise a warning with best-effort stacklevel adjustment. """ callsite = "" - try: + + with contextlib.suppress(Exception): f = sys._getframe() callsite = f.f_back.f_back.f_globals[ # type: ignore[union-attr] "__name__" ] - except Exception: # pragma: no cover - pass # Avoid double warnings if TL functions call themselves. if callsite == "structlog.threadlocal": diff --git a/src/structlog/tracebacks.py b/src/structlog/tracebacks.py index 50643516..9f6195b4 100644 --- a/src/structlog/tracebacks.py +++ b/src/structlog/tracebacks.py @@ -56,7 +56,7 @@ class Frame: @dataclass -class SyntaxError_: +class SyntaxError_: # noqa: N801 """ Contains detailed information about :exc:`SyntaxError` exceptions. """ diff --git a/tests/test_dev.py b/tests/test_dev.py index ee3e3053..e179a064 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -366,7 +366,7 @@ def test_everything(self, cr, styles, padded, explicit_ei): elif explicit_ei == "exception": ei = e else: - raise ValueError() + raise ValueError() from None else: ei = True diff --git a/tests/test_processors.py b/tests/test_processors.py index b3d2112b..4a5d7d80 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -1026,12 +1026,12 @@ def make_processor( return CallsiteParameterAdder( additional_ignores=additional_ignores ) - else: - parameters = cls.filter_parameters(parameter_strings) - return CallsiteParameterAdder( - parameters=parameters, - additional_ignores=additional_ignores, - ) + + parameters = cls.filter_parameters(parameter_strings) + return CallsiteParameterAdder( + parameters=parameters, + additional_ignores=additional_ignores, + ) @classmethod def filter_parameters( diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index d479438e..0333cb3f 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -563,7 +563,7 @@ class TestExtraAdder: [ (None, None), ({}, None), - *[({key}, None) for key in extra_dict().keys()], + *[({key}, None) for key in extra_dict()], ({"missing"}, {"missing"}), ({"missing", "keys"}, {"missing"}), ({"this", "x_int"}, None), @@ -605,7 +605,7 @@ def test_no_record(self): [ (None, None), ({}, None), - *[({key}, None) for key in extra_dict().keys()], + *[({key}, None) for key in extra_dict()], ({"missing"}, {"missing"}), ({"missing", "keys"}, {"missing"}), ({"this", "x_int"}, None), @@ -657,15 +657,13 @@ def _copy_allowed( ) -> EventDict: if allow is None: return {**event_dict, **extra_dict} - else: - return { - **event_dict, - **{ - key: value - for key, value in extra_dict.items() - if key in allow - }, - } + + return { + **event_dict, + **{ + key: value for key, value in extra_dict.items() if key in allow + }, + } class TestRenderToLogKW: @@ -738,7 +736,7 @@ def configure_logging( pre_chain, logger=None, pass_foreign_args=False, - renderer=ConsoleRenderer(colors=False), + renderer=ConsoleRenderer(colors=False), # noqa: B008 ): """ Configure logging to use ProcessorFormatter. @@ -831,7 +829,7 @@ def test_pass_foreign_args_true_sets_positional_args_key(self): If `pass_foreign_args` is `True` we set the `positional_args` key in the `event_dict` before clearing args. """ - test_processor = call_recorder(lambda l, m, event_dict: event_dict) + test_processor = call_recorder(lambda _, __, event_dict: event_dict) configure_logging((test_processor,), pass_foreign_args=True) positional_args = {"foo": "bar"} @@ -910,7 +908,7 @@ def test_foreign_pre_chain_gets_exc_info(self): If non-structlog record contains exc_info, foreign_pre_chain functions have access to it. """ - test_processor = call_recorder(lambda l, m, event_dict: event_dict) + test_processor = call_recorder(lambda _, __, event_dict: event_dict) configure_logging((test_processor,), renderer=KeyValueRenderer()) try: @@ -929,26 +927,26 @@ def test_foreign_pre_chain_sys_exc_info(self): ProcessorFormatter should not have changed it. """ - class MyException(Exception): + class MyError(Exception): pass def add_excinfo(logger, log_method, event_dict): event_dict["exc_info"] = sys.exc_info() return event_dict - test_processor = call_recorder(lambda l, m, event_dict: event_dict) + test_processor = call_recorder(lambda _, __, event_dict: event_dict) configure_logging( (add_excinfo, test_processor), renderer=KeyValueRenderer() ) try: - raise MyException("oh no") + raise MyError("oh no") except Exception: logging.getLogger().error("okay") event_dict = test_processor.calls[0].args[2] - assert MyException is event_dict["exc_info"][0] + assert MyError is event_dict["exc_info"][0] def test_other_handlers_get_original_record(self): """ @@ -1154,10 +1152,7 @@ async def test_correct_levels(self, abl, cl, stdlib_log_method): aliases = {"exception": "error", "warn": "warning"} alias = aliases.get(stdlib_log_method) - if alias: - expect = alias - else: - expect = stdlib_log_method + expect = alias if alias else stdlib_log_method assert expect == cl.calls[0].method_name diff --git a/tests/test_testing.py b/tests/test_testing.py index 99b4a75c..d7e4a51a 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -64,9 +64,8 @@ def test_restores_processors_on_error(self): """ orig_procs = self.get_active_procs() - with pytest.raises(NotImplementedError): - with testing.capture_logs(): - raise NotImplementedError("from test") + with pytest.raises(NotImplementedError), testing.capture_logs(): + raise NotImplementedError("from test") assert orig_procs is self.get_active_procs() diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py index eac054c4..ae744a61 100644 --- a/tests/test_threadlocal.py +++ b/tests/test_threadlocal.py @@ -89,14 +89,15 @@ def test_bind_exc(self, log): tmp_bind cleans up properly on exceptions. """ log = log.bind(y=23) - with pytest.raises(ValueError), pytest.deprecated_call(): - with tmp_bind(log, x=42, y="foo") as tmp_log: - assert ( - {"y": "foo", "x": 42} - == tmp_log._context._dict - == log._context._dict - ) - raise ValueError + with pytest.raises(ValueError), pytest.deprecated_call(), tmp_bind( + log, x=42, y="foo" + ) as tmp_log: + assert ( + {"y": "foo", "x": 42} + == tmp_log._context._dict + == log._context._dict + ) + raise ValueError assert {"y": 23} == log._context._dict @@ -408,9 +409,8 @@ def test_cleanup(self): """ Bindings are cleaned up """ - with pytest.deprecated_call(): - with bound_threadlocal(x=42, y="foo"): - assert {"x": 42, "y": "foo"} == get_threadlocal() + with pytest.deprecated_call(), bound_threadlocal(x=42, y="foo"): + assert {"x": 42, "y": "foo"} == get_threadlocal() with pytest.deprecated_call(): assert {} == get_threadlocal() @@ -435,10 +435,9 @@ def test_preserve_independent_bind(self): """ New bindings inside bound_threadlocal are preserved after the clean up """ - with pytest.deprecated_call(): - with bound_threadlocal(x=42): - bind_threadlocal(y="foo") - assert {"x": 42, "y": "foo"} == get_threadlocal() + with pytest.deprecated_call(), bound_threadlocal(x=42): + bind_threadlocal(y="foo") + assert {"x": 42, "y": "foo"} == get_threadlocal() with pytest.deprecated_call(): assert {"y": "foo"} == get_threadlocal() diff --git a/tests/test_tracebacks.py b/tests/test_tracebacks.py index fd55ec6a..2503d5cc 100644 --- a/tests/test_tracebacks.py +++ b/tests/test_tracebacks.py @@ -201,7 +201,7 @@ def test_raise_nested(): try: 1 / 0 except ArithmeticError: - raise ValueError("onoes") + raise ValueError("onoes") # noqa: B904 except Exception as e: trace = tracebacks.extract(type(e), e, e.__traceback__) @@ -274,7 +274,7 @@ def test_syntax_error(): """ try: # raises SyntaxError: invalid syntax - eval("2 +* 2") + eval("2 +* 2") # noqa: PGH001 except SyntaxError as e: trace = tracebacks.extract(type(e), e, e.__traceback__) @@ -308,7 +308,7 @@ def test_filename_with_bracket(): Filenames with brackets (e.g., "") are handled properly. """ try: - exec(compile("1/0", filename="", mode="exec")) + exec(compile("1/0", filename="", mode="exec")) # noqa: S102 except Exception as e: trace = tracebacks.extract(type(e), e, e.__traceback__) @@ -343,7 +343,7 @@ def test_filename_not_a_file(): "Invalid" filenames are appended to CWD as if they were actual files. """ try: - exec(compile("1/0", filename="string", mode="exec")) + exec(compile("1/0", filename="string", mode="exec")) # noqa: S102 except Exception as e: trace = tracebacks.extract(type(e), e, e.__traceback__) @@ -478,7 +478,7 @@ def test_json_traceback(): def test_json_traceback_locals_max_string(): try: - _var = "spamspamspam" # noqa + _var = "spamspamspam" 1 / 0 except Exception as e: result = tracebacks.ExceptionDictTransformer(locals_max_string=4)( diff --git a/typing_examples.py b/typing_examples.py index ab10880f..3f4eb66b 100644 --- a/typing_examples.py +++ b/typing_examples.py @@ -120,8 +120,8 @@ def bytes_dumps( ] structlog.configure( - processors=shared_processors - + [ + processors=[ + *shared_processors, structlog.stdlib.ProcessorFormatter.wrap_for_formatter, ], logger_factory=structlog.stdlib.LoggerFactory(), From 49b2b2b99136b2a38be2e1e03921788916e54f6a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 3 Jun 2023 08:57:47 +0200 Subject: [PATCH 1000/1520] Calm down --- .github/CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index a32f43a6..ec1af5b0 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -120,7 +120,7 @@ But it's way more comfortable to run it locally and catch avoidable errors befor """ ``` - If you add or change public APIs, tag the docstring using `.. versionadded:: 16.0.0 WHAT` or `.. versionchanged:: 16.2.0 WHAT`. -- We use [*Ruff*](https://ruff.rs/) to sort our imports, and we use [*Black*](https://github.com/psf/black) with line length of 79 characters to format our code. +- We use [Ruff](https://ruff.rs/) to sort our imports, and we use [Black](https://github.com/psf/black) with line length of 79 characters to format our code. As long as you run our full [*tox*] suite before committing, or install our [*pre-commit*] hooks (ideally you'll do both – see [*Local Development Environment*](#local-development-environment) above), you won't have to spend any time on formatting your code at all. If you don't, [CI] will catch it for you – but that seems like a waste of your time! From 2810d69022e73f453981cc9545cffc8cd94dee10 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 3 Jun 2023 08:59:24 +0200 Subject: [PATCH 1001/1520] More calming --- .github/CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index ec1af5b0..a052a35a 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -147,9 +147,9 @@ But it's way more comfortable to run it locally and catch avoidable errors befor ## Documentation -- We use [*Markdown*] everywhere except in `docs/api.rst` and docstrings. +- We use [Markdown] everywhere except in `docs/api.rst` and docstrings. -- Use [semantic newlines] in [*reStructuredText*] and [*Markdown*] files (files ending in `.rst` and `.md`): +- Use [semantic newlines] in [*reStructuredText*] and [Markdown] files (files ending in `.rst` and `.md`): ```markdown This is a sentence. @@ -216,4 +216,4 @@ or: [*tox*]: https://tox.wiki/ [semantic newlines]: https://rhodesmill.org/brandon/2012/one-sentence-per-line/ [*reStructuredText*]: https://www.sphinx-doc.org/en/stable/usage/restructuredtext/basics.html -[*Markdown*]: https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax +[Markdown]: https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax From fbf570bfdffe2d274965b18ce9aab53c78582461 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 3 Jun 2023 10:51:08 +0200 Subject: [PATCH 1002/1520] Add warning --- .github/CONTRIBUTING.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index a052a35a..442ca870 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -51,16 +51,16 @@ If you're using [*direnv*](https://direnv.net), you can automate the creation of layout python python$(cat .python-version) ``` -Clone the *structlog* repository: +[Create a fork](https://github.com/hynek/structlog/fork) of the *structlog* repository and clone it: ```console -$ git clone git@github.com:hynek/structlog.git +$ git clone git@github.com:YOU/structlog.git ``` Or if you prefer to use Git via HTTPS: ```console -$ git clone https://github.com/hynek/structlog.git +$ git clone https://github.com/YOU/structlog.git ``` Change into the newly created directory and after activating a virtual environment install an editable version of *structlog* along with its tests and docs requirements: @@ -103,6 +103,12 @@ $ pre-commit run --all-files and our CI has integration with [pre-commit.ci](https://pre-commit.ci). But it's way more comfortable to run it locally and catch avoidable errors before pushing them to GitHub. +> **Warning** +> **Before** you start working on a new pull request, use the "*Sync fork*" button in GitHub's web UI to ensure your fork is up to date. +> **Always create a new branch off `main` for each new pull request.** +> Yes, you can work on `main` in your fork and submit pull requests. +> But this will *inevitably* lead to you not being able to synchronize your fork with upstream and having to start over. + ## Code From cfa31d504c647c5a1e2c01edce1a7a0bec90aacf Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 3 Jun 2023 10:52:23 +0200 Subject: [PATCH 1003/1520] Itemize --- .github/CONTRIBUTING.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 442ca870..202f5656 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -104,10 +104,10 @@ and our CI has integration with [pre-commit.ci](https://pre-commit.ci). But it's way more comfortable to run it locally and catch avoidable errors before pushing them to GitHub. > **Warning** -> **Before** you start working on a new pull request, use the "*Sync fork*" button in GitHub's web UI to ensure your fork is up to date. -> **Always create a new branch off `main` for each new pull request.** -> Yes, you can work on `main` in your fork and submit pull requests. -> But this will *inevitably* lead to you not being able to synchronize your fork with upstream and having to start over. +> - **Before** you start working on a new pull request, use the "*Sync fork*" button in GitHub's web UI to ensure your fork is up to date. +> - **Always create a new branch off `main` for each new pull request.** +> Yes, you can work on `main` in your fork and submit pull requests. +> But this will *inevitably* lead to you not being able to synchronize your fork with upstream and having to start over. ## Code From ade1f4b10f361a7ba126e72111d455c1c50779e6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 3 Jun 2023 10:54:23 +0200 Subject: [PATCH 1004/1520] Move to a better spot --- .github/CONTRIBUTING.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 202f5656..88003521 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -63,12 +63,18 @@ Or if you prefer to use Git via HTTPS: $ git clone https://github.com/YOU/structlog.git ``` -Change into the newly created directory and after activating a virtual environment install an editable version of *structlog* along with its tests and docs requirements: +> **Warning** +> - **Before** you start working on a new pull request, use the "*Sync fork*" button in GitHub's web UI to ensure your fork is up to date. +> - **Always create a new branch off `main` for each new pull request.** +> Yes, you can work on `main` in your fork and submit pull requests. +> But this will *inevitably* lead to you not being able to synchronize your fork with upstream and having to start over. + +Change into the newly created directory and after activating a virtual environment, install an editable version of *structlog* along with its tests and docs requirements: ```console $ cd structlog -$ pip install --upgrade pip wheel # PLEASE don't skip this step -$ pip install -e '.[dev]' +$ python -Im pip install --upgrade pip wheel # PLEASE don't skip this step +$ python -Im pip install -e '.[dev]' ``` At this point, @@ -103,12 +109,6 @@ $ pre-commit run --all-files and our CI has integration with [pre-commit.ci](https://pre-commit.ci). But it's way more comfortable to run it locally and catch avoidable errors before pushing them to GitHub. -> **Warning** -> - **Before** you start working on a new pull request, use the "*Sync fork*" button in GitHub's web UI to ensure your fork is up to date. -> - **Always create a new branch off `main` for each new pull request.** -> Yes, you can work on `main` in your fork and submit pull requests. -> But this will *inevitably* lead to you not being able to synchronize your fork with upstream and having to start over. - ## Code From 99a9e1d27c14ccf75ecd8328738827ee022693b3 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 6 Jun 2023 08:03:56 +0200 Subject: [PATCH 1005/1520] Move typing tests into tests Fixes #517 --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- pyproject.toml | 4 ++++ typing_examples.py => tests/typing/api.py | 0 tox.ini | 2 +- 4 files changed, 6 insertions(+), 2 deletions(-) rename typing_examples.py => tests/typing/api.py (100%) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index ec7e8c0e..f58dcfb0 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -15,7 +15,7 @@ If an item doesn't apply to your pull request, **check it anyway** to make it ap - [ ] Added **tests** for changed code. - The CI fails with less than 100% coverage. -- [ ] **New APIs** are added to [`typing_examples.py`](https://github.com/hynek/structlog/blob/main/tests/typing_examples.py). +- [ ] **New APIs** are added to [`api.py`](https://github.com/hynek/structlog/blob/main/tests/typing/api.py). - [ ] Updated **documentation** for changed code. - [ ] New functions/classes have to be added to `docs/api.rst` by hand. - [ ] Changed/added classes/methods/functions have appropriate `versionadded`, `versionchanged`, or `deprecated` [directives](http://www.sphinx-doc.org/en/stable/markup/para.html#directive-versionadded). diff --git a/pyproject.toml b/pyproject.toml index 7de9c754..2407e4d1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -174,6 +174,10 @@ warn_return_any = false module = "tests.*" ignore_errors = true +[[tool.mypy.overrides]] +module = "tests.typing.*" +ignore_errors = false + [tool.hatch.metadata.hooks.fancy-pypi-readme] content-type = "text/markdown" diff --git a/typing_examples.py b/tests/typing/api.py similarity index 100% rename from typing_examples.py rename to tests/typing/api.py diff --git a/tox.ini b/tox.ini index 0a4218ad..bd0d7a7a 100644 --- a/tox.ini +++ b/tox.ini @@ -32,7 +32,7 @@ commands = pre-commit run --all-files [testenv:mypy] description = Check types extras = typing -commands = mypy src typing_examples.py +commands = mypy src tests/typing [testenv] From e5336dbcf799d9ce2dc96a28a121b3da617dcff7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 6 Jun 2023 09:14:24 +0200 Subject: [PATCH 1006/1520] Proudly typed --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 2407e4d1..005dee4d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,6 +32,7 @@ classifiers = [ "Programming Language :: Python", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: System :: Logging", + "Typing :: Typed", ] dependencies = [ "typing-extensions; python_version<'3.8'", From bcd607b92551b9e33056b661d7da0a4b7cbdebe6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 6 Jun 2023 10:11:53 +0200 Subject: [PATCH 1007/1520] Simplify classifiers --- pyproject.toml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 005dee4d..bbeea346 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,12 +15,9 @@ license = "MIT OR Apache-2.0" keywords = ["logging", "structured", "structure", "log"] classifiers = [ "Development Status :: 5 - Production/Stable", - "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "License :: OSI Approved :: MIT License", - "Natural Language :: English", "Operating System :: OS Independent", - "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", @@ -29,8 +26,6 @@ classifiers = [ "Programming Language :: Python :: 3.12", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", - "Programming Language :: Python", - "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: System :: Logging", "Typing :: Typed", ] From 3b4db9980492e0dd0e494ded73592f175dec3531 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 7 Jun 2023 07:57:56 +0200 Subject: [PATCH 1008/1520] Update ruff / remove our bug --- .pre-commit-config.yaml | 2 +- src/structlog/processors.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 176c3ef4..8d57ea6a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,7 +13,7 @@ repos: - id: black - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.0.270 + rev: v0.0.271 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 86b6c344..cceedea6 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -214,7 +214,7 @@ def ordered_items(event_dict: EventDict) -> list[tuple[str, Any]]: "items" ) - return ordered_items # noqa: RET504 + return ordered_items class UnicodeEncoder: From e71d78d8e4a4aa73751c869e102f06b3e5cf9972 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 8 Jun 2023 07:55:46 +0200 Subject: [PATCH 1009/1520] Move ignore --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index bbeea346..d96e00e3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -141,7 +141,6 @@ ignore = [ "N802", # some names are non-pep8 due to stdlib logging / Twisted "N803", # ditto "N806", # ditto - "B018", # "useless" expressions can be useful in tests ] [tool.ruff.per-file-ignores] @@ -150,6 +149,7 @@ ignore = [ "S301", # I know pickle is bad, but people like it. "SIM300", # Yoda rocks in tests "PLC1901", # empty strings are falsey, but are less specific in tests + "B018", # "useless" expressions can be useful in tests ] [tool.ruff.isort] From e18368c8fef91d54a456ac7dbc8fbb22fdb3fa80 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 9 Jun 2023 08:08:06 +0200 Subject: [PATCH 1010/1520] Add pip caching to CI --- .github/workflows/ci.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 301e5082..e52fd5b9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,6 +33,8 @@ jobs: steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 + with: + cache: pip - run: python -Im pip install build - run: python -Im build --sdist @@ -73,6 +75,7 @@ jobs: with: python-version: ${{ matrix.python-version }} allow-prereleases: true + cache: pip - run: python -Im pip install --upgrade wheel tox - run: python -Im tox run -f py$(echo ${{ matrix.python-version }} | tr -d .) @@ -97,6 +100,8 @@ jobs: workflow-artifact-name: ${{ env.sdist-artifact }} - uses: actions/setup-python@v4 + with: + cache: pip - run: python -Im pip install --upgrade coverage[toml] @@ -147,6 +152,7 @@ jobs: with: python-version: ${{ matrix.python-version }} allow-prereleases: true + cache: pip - run: python -Im pip install --upgrade wheel tox - run: python -Im tox -e mypy @@ -165,6 +171,7 @@ jobs: with: # Keep in sync with tox.ini/docs & readthedocs.yaml python-version: "3.11" + cache: pip - run: python -Im pip install --upgrade wheel tox - run: python -Im tox -e docs @@ -179,6 +186,8 @@ jobs: steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 + with: + cache: pip - run: python -Im pip install -e .[dev] - run: python -Ic 'import structlog; print(structlog.__version__)' @@ -213,6 +222,8 @@ jobs: source-tarball-name: ${{ env.sdist-name }} workflow-artifact-name: ${{ env.sdist-artifact }} - uses: actions/setup-python@v4 + with: + cache: pip - run: python -Im pip install tox wheel - run: tox -f color From e89f5da0608e6298bdaf095ce3a84416f0c29c46 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 10 Jun 2023 06:24:49 +0200 Subject: [PATCH 1011/1520] Fix Mermaid diagrams for Mermaid 10 (#519) * Fix Mermaid diagrams for Mermaid 10 * Set theme globally --- docs/conf.py | 1 + docs/standard-library.md | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 2f7a6a72..70021989 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -28,6 +28,7 @@ "smartquotes", "deflist", ] +mermaid_init_js = "mermaid.initialize({startOnLoad:true,theme:'neutral'});" # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] diff --git a/docs/standard-library.md b/docs/standard-library.md index 6339db8d..7de07503 100644 --- a/docs/standard-library.md +++ b/docs/standard-library.md @@ -154,7 +154,6 @@ Chances are, this is all you need. :align: center flowchart TD - %%{ init: {'theme': 'neutral'} }%% User structlog stdlib[Standard Library\ne.g. logging.StreamHandler] @@ -249,7 +248,6 @@ You can choose to use *structlog* only for building the event dictionary and lea :align: center flowchart TD - %%{ init: {'theme': 'neutral'} }%% User structlog stdlib[Standard Library\ne.g. logging.StreamHandler] @@ -331,7 +329,6 @@ Consequently, the output is the duty of the standard library too. :align: center flowchart TD - %%{ init: {'theme': 'neutral'} }%% User structlog structlog2[structlog] From 88a2532350a4ae492728bd9d273141b91c3df27e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 10 Jun 2023 11:16:50 +0200 Subject: [PATCH 1012/1520] TOX_TESTENV_* doesn't work anymore --- .github/workflows/ci.yml | 1 - tox.ini | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e52fd5b9..ea577291 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,6 @@ on: env: FORCE_COLOR: "1" # Make tools pretty. - TOX_TESTENV_PASSENV: FORCE_COLOR PIP_DISABLE_PIP_VERSION_CHECK: "1" PIP_NO_PYTHON_VERSION_WARNING: "1" diff --git a/tox.ini b/tox.ini index bd0d7a7a..2aa552c6 100644 --- a/tox.ini +++ b/tox.ini @@ -38,6 +38,7 @@ commands = mypy src tests/typing [testenv] extras = tests set_env = PYTHONHASHSEED = 0 +pass_env = TERM commands = pytest {posargs} From f0c0304305f6144b0b841319a2c045ce85cad942 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 10 Jun 2023 11:18:18 +0200 Subject: [PATCH 1013/1520] Just TERM doesn't work --- tox.ini | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 2aa552c6..bb7686fc 100644 --- a/tox.ini +++ b/tox.ini @@ -38,7 +38,9 @@ commands = mypy src tests/typing [testenv] extras = tests set_env = PYTHONHASHSEED = 0 -pass_env = TERM +pass_env = + FORCE_COLOR + NO_COLOR commands = pytest {posargs} From 88798e0053ac1dfb074806b024fb0a9f8f8552bd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 11 Jun 2023 18:23:06 +0200 Subject: [PATCH 1014/1520] Run explicitly --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ea577291..78dcb1fe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -154,7 +154,7 @@ jobs: cache: pip - run: python -Im pip install --upgrade wheel tox - - run: python -Im tox -e mypy + - run: python -Im tox run -e mypy docs: name: Build docs & run doctests @@ -173,7 +173,7 @@ jobs: cache: pip - run: python -Im pip install --upgrade wheel tox - - run: python -Im tox -e docs + - run: python -Im tox run -e docs install-dev: name: Verify dev env @@ -225,4 +225,4 @@ jobs: cache: pip - run: python -Im pip install tox wheel - - run: tox -f color + - run: tox run -f color From af60c94023160bea740afd7723ff468242de51b6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 12 Jun 2023 16:01:00 +0200 Subject: [PATCH 1015/1520] Speed up local builds --- tox.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tox.ini b/tox.ini index bb7686fc..bcb7f925 100644 --- a/tox.ini +++ b/tox.ini @@ -36,6 +36,8 @@ commands = mypy src tests/typing [testenv] +package = wheel +wheel_build_env = .pkg extras = tests set_env = PYTHONHASHSEED = 0 pass_env = From 2181a2d074474d19b6323faf4d04268bccc76c3e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 12 Jun 2023 16:03:08 +0200 Subject: [PATCH 1016/1520] Simplify CI --- .github/workflows/ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 78dcb1fe..a56aeb13 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -75,7 +75,7 @@ jobs: python-version: ${{ matrix.python-version }} allow-prereleases: true cache: pip - - run: python -Im pip install --upgrade wheel tox + - run: python -Im pip install tox - run: python -Im tox run -f py$(echo ${{ matrix.python-version }} | tr -d .) @@ -152,7 +152,7 @@ jobs: python-version: ${{ matrix.python-version }} allow-prereleases: true cache: pip - - run: python -Im pip install --upgrade wheel tox + - run: python -Im pip install tox - run: python -Im tox run -e mypy @@ -171,7 +171,7 @@ jobs: # Keep in sync with tox.ini/docs & readthedocs.yaml python-version: "3.11" cache: pip - - run: python -Im pip install --upgrade wheel tox + - run: python -Im pip install tox - run: python -Im tox run -e docs @@ -223,6 +223,6 @@ jobs: - uses: actions/setup-python@v4 with: cache: pip - - run: python -Im pip install tox wheel + - run: python -Im pip install tox - - run: tox run -f color + - run: python -Im tox run -f color From b0a4df4c43420dd028a875e87f0960edb768df63 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 13 Jun 2023 10:13:10 +0200 Subject: [PATCH 1017/1520] Update compat policy --- .github/SECURITY.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/SECURITY.md b/.github/SECURITY.md index 6a34429d..4357414a 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -5,8 +5,8 @@ We are following [*CalVer*](https://calver.org) with generous backwards-compatibility guarantees. Therefore we only support the latest version. -That said, you shouldn't be afraid to upgrade *structlog* if you're using its documented public APIs and pay attention to `DeprecationWarning`s. -Whenever there is a need to break compatibility, it is announced [in the changelog](https://github.com/hynek/structlog/blob/main/CHANGELOG.md) and raises a `DeprecationWarning` for a year (if possible) before it's finally really broken. +Put simply, you shouldn't ever be afraid to upgrade as long as you're only using our public APIs. +Whenever there is a need to break compatibility, it is announced in the changelog, and raises a `DeprecationWarning` for a year (if possible) before it's finally really broken. You **can't** rely on the default settings and the `structlog.dev` module, though. They may be adjusted in the future to provide a better experience when starting to use *structlog*. @@ -15,6 +15,5 @@ So please make sure to **always** properly configure your applications. ## Reporting a Vulnerability -To report a security vulnerability, please use the [Tidelift security -contact](https://tidelift.com/security). Tidelift will coordinate the fix and -disclosure. +To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). +Tidelift will coordinate the fix and disclosure. From f7145a6a815083a748ec2e41a1d66dd63ce6c411 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 13 Jun 2023 10:17:14 +0200 Subject: [PATCH 1018/1520] We're not GitHub's KB --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index dba7dadf..3be319d0 100644 --- a/README.md +++ b/README.md @@ -96,8 +96,6 @@ The idea of bound loggers is inspired by previous work by [Jean-Paul Calderone]( The development is kindly supported by my employer [Variomedia AG](https://www.variomedia.de/), *structlog*’s [Tidelift subscribers](https://tidelift.com/subscription/pkg/pypi-structlog?utm_source=pypi-structlog&utm_medium=referral&utm_campaign=readme), and all my amazing [GitHub Sponsors](https://github.com/sponsors/hynek). -A full list of contributors can be found in GitHub’s [overview](https://github.com/hynek/structlog/graphs/contributors). - The logs-loving futuristic beaver logo has been contributed by [Russell Keith-Magee](https://github.com/freakboy3742). From 5e9b513895f98ef4a32c0721b5c5c203f2473b4f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 14 Jun 2023 11:24:56 +0200 Subject: [PATCH 1019/1520] contextvars: add warning about hybrid apps (#521) --- docs/contextvars.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/contextvars.md b/docs/contextvars.md index 59fb4ba8..07d25de1 100644 --- a/docs/contextvars.md +++ b/docs/contextvars.md @@ -12,13 +12,19 @@ structlog.reset_defaults() ``` The {mod}`contextvars` module in the Python standard library allows having a global *structlog* context that is local to the current execution context. -The execution context can be thread-local if using threads, or using primitives based on {mod}`asyncio`, or [*greenlet*](https://greenlet.readthedocs.io/) respectively. +The execution context can be thread-local if using threads, stored in the {mod}`asyncio` event loop, or [*greenlet*](https://greenlet.readthedocs.io/) respectively. For example, you may want to bind certain values like a request ID or the peer's IP address at the beginning of a web request and have them logged out along with the local contexts you build within our views. For that *structlog* provides the {mod}`structlog.contextvars` module with a set of functions to bind variables to a context-local context. This context is safe to be used both in threaded as well as asynchronous code. +:::{warning} +Since the storage mechanics of your context variables is different for each concurrency method, they are _isolated_ from each other. + +This can be a problem in hybrid applications like those based on [*starlette*](https://www.starlette.io) (this [includes FastAPI](https://github.com/tiangolo/fastapi/discussions/5999)) where context variables set in a synchronous context don't appear in logs from an async context and vice versa. +::: + The general flow is: - Use {func}`structlog.configure` with {func}`structlog.contextvars.merge_contextvars` as your first processor (part of default configuration). From 3681500021535edae68ff5e1da0152773c22174c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 14 Jun 2023 12:19:44 +0200 Subject: [PATCH 1020/1520] Only type-check the API on all platforms (#522) --- .github/workflows/ci.yml | 27 +++++++++++---------------- tox.ini | 22 +++++++++++----------- 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a56aeb13..c13604a2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -75,9 +75,13 @@ jobs: python-version: ${{ matrix.python-version }} allow-prereleases: true cache: pip - - run: python -Im pip install tox - - run: python -Im tox run -f py$(echo ${{ matrix.python-version }} | tr -d .) + - name: Prepare & run tox + run: | + python -Im pip install tox + + python -Im tox run -f py$(echo ${{ matrix.python-version }} | tr -d .) + python -Im tox run -e mypy-api - name: Upload coverage data uses: actions/upload-artifact@v3 @@ -127,19 +131,9 @@ jobs: if: ${{ failure() }} mypy: - name: Mypy on ${{ matrix.python-version }} + name: Type-check package needs: build-sdist runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - python-version: - # mypy on 3.7 fails but there's nothing we can do about it - - "3.8" - - "3.9" - - "3.10" - - "3.11" - - "3.12" steps: - name: Get source code from pre-built sdist @@ -149,12 +143,13 @@ jobs: workflow-artifact-name: ${{ env.sdist-artifact }} - uses: actions/setup-python@v4 with: - python-version: ${{ matrix.python-version }} allow-prereleases: true cache: pip - - run: python -Im pip install tox - - run: python -Im tox run -e mypy + - name: Prepare & run tox + run: | + python -Im pip install tox + python -Im tox run -e mypy-pkg docs: name: Build docs & run doctests diff --git a/tox.ini b/tox.ini index bcb7f925..160a938b 100644 --- a/tox.ini +++ b/tox.ini @@ -2,13 +2,9 @@ min_version = 4 env_list = pre-commit, - mypy, - py37, - py38, - py39{,-colorama}, - py310, - py311{,-be,-rich}, - py312, + mypy-{api,pkg}, + py3{7,8,9,10,11,12} + py311-{colorama,be,rich}, docs, coverage-report @@ -29,10 +25,14 @@ deps = pre-commit commands = pre-commit run --all-files -[testenv:mypy] -description = Check types +[testenv:mypy-api] extras = typing -commands = mypy src tests/typing +commands = mypy tests/typing + + +[testenv:mypy-pkg] +extras = typing +commands = mypy src [testenv] @@ -73,7 +73,7 @@ basepython = python3.11 deps = coverage[toml] skip_install = true parallel_show_output = true -depends = py37,py39-colorama,py311{,-be,-rich} +depends = py37,py311{-colorama,-be,-rich} commands = coverage combine coverage report From 35691f2422ef2efd2d66f3febb0aa6a179ef0fd4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 14 Jun 2023 12:20:06 +0200 Subject: [PATCH 1021/1520] Minor consistency --- .github/dependabot.yml | 1 + .github/workflows/build-docset.yml | 2 +- .github/workflows/codeql-analysis.yml | 7 ++++--- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 8ac6b8c4..64284b90 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,3 +1,4 @@ +--- version: 2 updates: - package-ecosystem: "github-actions" diff --git a/.github/workflows/build-docset.yml b/.github/workflows/build-docset.yml index 1791a4db..69494bc1 100644 --- a/.github/workflows/build-docset.yml +++ b/.github/workflows/build-docset.yml @@ -10,7 +10,7 @@ env: PIP_DISABLE_PIP_VERSION_CHECK: 1 PIP_NO_PYTHON_VERSION_WARNING: 1 -permissions: # added using https://github.com/step-security/secure-workflows +permissions: contents: read jobs: diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index c8e7cab3..ca6d0d3c 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,10 +1,11 @@ +--- name: "CodeQL" on: push: - branches: ["main"] + branches: [main] pull_request: - branches: ["main"] + branches: [main] schedule: - cron: "41 3 * * 6" @@ -23,7 +24,7 @@ jobs: strategy: fail-fast: false matrix: - language: ["python"] + language: [python] steps: - name: Checkout repository From f282c78b43ebc438cc7ece466aed37aac22b0191 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 14 Jun 2023 12:26:57 +0200 Subject: [PATCH 1022/1520] Use PyPI data to document supported versions --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3be319d0..3ddd61f3 100644 --- a/README.md +++ b/README.md @@ -16,12 +16,12 @@ - - PyPI release - DOI + + Supported Python versions of the current PyPI release. + Downloads per month @@ -105,7 +105,6 @@ The logs-loving futuristic beaver logo has been contributed by [Russell Keith-Ma - **License**: *dual* [Apache License, version 2 **and** MIT](https://www.structlog.org/en/latest/license.html) - **Get Help**: please use the *structlog* tag on [*Stack Overflow*](https://stackoverflow.com/questions/tagged/structlog) -- **Supported Python Versions**: 3.7 and later - [**PyPI**](https://pypi.org/project/structlog/) - [**Source Code**](https://github.com/hynek/structlog) - [**Documentation**](https://www.structlog.org/) From 6b6581351df3fb5011f553b1f639c20a4ed5e9f7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 14 Jun 2023 12:53:59 +0200 Subject: [PATCH 1023/1520] Streamline tox.ini --- tox.ini | 82 ++++++++++++++++++++++++--------------------------------- 1 file changed, 35 insertions(+), 47 deletions(-) diff --git a/tox.ini b/tox.ini index 160a938b..ab7428aa 100644 --- a/tox.ini +++ b/tox.ini @@ -4,42 +4,15 @@ env_list = pre-commit, mypy-{api,pkg}, py3{7,8,9,10,11,12} - py311-{colorama,be,rich}, + py3{7,11}-{colorama,be,rich}, docs, coverage-report -[testenv:docs] -# Keep basepython in sync with ci.yml/docs and .readthedocs.yaml. -base_python = python3.11 -extras = docs -pass_env = TERM -commands = - sphinx-build -n -T -W -b html -d {envtmpdir}/doctrees docs docs/_build/html - sphinx-build -n -T -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html - - -[testenv:pre-commit] -skip_install = true -deps = pre-commit -commands = pre-commit run --all-files - - -[testenv:mypy-api] -extras = typing -commands = mypy tests/typing - - -[testenv:mypy-pkg] -extras = typing -commands = mypy src - - [testenv] package = wheel wheel_build_env = .pkg extras = tests -set_env = PYTHONHASHSEED = 0 pass_env = FORCE_COLOR NO_COLOR @@ -47,38 +20,53 @@ commands = pytest {posargs} # Run oldest and latest under Coverage. -[testenv:py3{7,11}] -deps = twisted +[testenv:py3{7,11}{,-colorama,-be,-rich}] +deps = + py311: twisted + colorama: colorama + rich: rich + be: better-exceptions commands = coverage run -m pytest {posargs} -[testenv:py39-colorama] -deps = colorama -commands = coverage run -m pytest tests/test_dev.py {posargs} - - -[testenv:py311-be] -deps = better-exceptions -commands = {[testenv:py39-colorama]commands} - - -[testenv:py311-rich] -deps = rich -commands = {[testenv:py39-colorama]commands} - - [testenv:coverage-report] # Keep in sync with .python-version -basepython = python3.11 +base_python = py311 deps = coverage[toml] skip_install = true parallel_show_output = true -depends = py37,py311{-colorama,-be,-rich} +depends = py3{7,11}{,-colorama,-be,-rich} commands = coverage combine coverage report +[testenv:docs] +# Keep base_python in sync with ci.yml/docs and .readthedocs.yaml. +base_python = py311 +extras = docs +pass_env = TERM +commands = + sphinx-build -n -T -W -b html -d {envtmpdir}/doctrees docs docs/_build/html + sphinx-build -n -T -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html + + +[testenv:pre-commit] +skip_install = true +deps = pre-commit +commands = pre-commit run --all-files + + +[testenv:mypy-api] +extras = typing +commands = mypy tests/typing + + +[testenv:mypy-pkg] +extras = typing +commands = mypy src + + [testenv:color-force] help = A visual check that FORCE_COLOR is working. set_env = FORCE_COLOR=1 From 9f683b1d69bdf9dfc5b03ced5327a3a327f6066d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 14 Jun 2023 12:58:28 +0200 Subject: [PATCH 1024/1520] Let's be fancy --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index d96e00e3..8775bec8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -213,7 +213,7 @@ pattern = "\n(###.+?\n)## " text = """ --- -[Full changelog](https://www.structlog.org/en/stable/changelog.html) +[→ Full Changelog](https://www.structlog.org/en/stable/changelog.html) """ From 6b6125938679f743cb1a88397d954e924bcf604d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 14 Jun 2023 13:02:42 +0200 Subject: [PATCH 1025/1520] Test against latest PyPy in CI --- .github/workflows/ci.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c13604a2..0d1d10bf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -62,6 +62,7 @@ jobs: - "3.10" - "3.11" - "3.12" + - "pypy-3.9" steps: - name: Get source code from pre-built sdist @@ -78,9 +79,17 @@ jobs: - name: Prepare & run tox run: | + V=${{ matrix.python-version }} + + if [[ "$V" = pypy-* ]]; then + V=pypy3 + else + V=py$(echo $V | tr -d .) + fi + python -Im pip install tox - python -Im tox run -f py$(echo ${{ matrix.python-version }} | tr -d .) + python -Im tox run -f $V python -Im tox run -e mypy-api - name: Upload coverage data From 5aacdaa6b0c0a280294f6dab34d84fd87a9795c0 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 14 Jun 2023 13:17:51 +0200 Subject: [PATCH 1026/1520] Revert "Test against latest PyPy in CI" This reverts commit 6b6125938679f743cb1a88397d954e924bcf604d. --- .github/workflows/ci.yml | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0d1d10bf..c13604a2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -62,7 +62,6 @@ jobs: - "3.10" - "3.11" - "3.12" - - "pypy-3.9" steps: - name: Get source code from pre-built sdist @@ -79,17 +78,9 @@ jobs: - name: Prepare & run tox run: | - V=${{ matrix.python-version }} - - if [[ "$V" = pypy-* ]]; then - V=pypy3 - else - V=py$(echo $V | tr -d .) - fi - python -Im pip install tox - python -Im tox run -f $V + python -Im tox run -f py$(echo ${{ matrix.python-version }} | tr -d .) python -Im tox run -e mypy-api - name: Upload coverage data From 181423273425366ae156ece796aa8c39ffd0fb37 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 14 Jun 2023 15:39:48 +0200 Subject: [PATCH 1027/1520] Fix typo --- docs/recipes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/recipes.md b/docs/recipes.md index 05ebbfdc..c3ddbebc 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -100,7 +100,7 @@ That class still ships with *structlog* and can wrap *any* logger class by inter Nowadays, the default is a {class}`structlog.typing.FilteringBoundLogger` that imitates standard library’s log levels with the possibility of efficiently filtering at a certain level (inactive log methods are a plain `return None` each). -If you’re integrating with {mod}`logging` or Twisted, you may was to use one of their specific *bound loggers* ({class}`structlog.stdlib.BoundLogger` and {class}`structlog.twisted.BoundLogger`, respectively). +If you’re integrating with {mod}`logging` or Twisted, you may want to use one of their specific *bound loggers* ({class}`structlog.stdlib.BoundLogger` and {class}`structlog.twisted.BoundLogger`, respectively). — From 3787a251bdcc85e2a24be1c7bdc643fd853bbb01 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 19 Jun 2023 14:57:56 +0200 Subject: [PATCH 1028/1520] Fix name --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c13604a2..04a86ef9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -163,7 +163,7 @@ jobs: workflow-artifact-name: ${{ env.sdist-artifact }} - uses: actions/setup-python@v4 with: - # Keep in sync with tox.ini/docs & readthedocs.yaml + # Keep in sync with tox.ini/docs & .readthedocs.yaml python-version: "3.11" cache: pip - run: python -Im pip install tox From 2f44f02bfae1c1e07530b19f54a0e3c0f3405dfe Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 21 Jun 2023 10:03:31 +0200 Subject: [PATCH 1029/1520] Typo --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3917f50e..95eb097a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ The **first number** of the version is the year. The **second number** is incremented with each release, starting at 1 for each year. The **third number** is for emergencies when we need to start branches for older releases. -You can find out backwards-compatibility policy [here](https://github.com/hynek/structlog/blob/main/.github/SECURITY.md). +You can find our backwards-compatibility policy [here](https://github.com/hynek/structlog/blob/main/.github/SECURITY.md). From 8ad9e27905bb5128a14aa929cbdcde04bbccba83 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 21 Jun 2023 15:08:03 +0200 Subject: [PATCH 1030/1520] Remove pointless indent --- src/structlog/_config.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/structlog/_config.py b/src/structlog/_config.py index b91ebdc1..e297320a 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -24,10 +24,10 @@ """ - Any changes to these defaults must be reflected in: +Any changes to these defaults must be reflected in: - - `getting-started`. - - structlog.stdlib.recreate_defaults()'s docstring. +- `getting-started`. +- structlog.stdlib.recreate_defaults()'s docstring. """ _BUILTIN_DEFAULT_PROCESSORS: Sequence[Processor] = [ merge_contextvars, From 37fc7db6946fbb644897e1f8e7a0183663990ad3 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 21 Jun 2023 18:15:27 +0200 Subject: [PATCH 1031/1520] Lint stricter --- .gitignore | 1 + .pre-commit-config.yaml | 4 +- docs/conf.py | 4 -- pyproject.toml | 64 +++++++++++++++----------- src/structlog/__init__.py | 3 +- src/structlog/_base.py | 7 +-- src/structlog/_output.py | 2 - src/structlog/dev.py | 2 +- src/structlog/processors.py | 20 ++++---- src/structlog/stdlib.py | 15 +++--- src/structlog/tracebacks.py | 12 ++--- src/structlog/twisted.py | 6 +-- tests/test_base.py | 10 ++-- tests/test_dev.py | 2 +- tests/test_frames.py | 2 +- tests/test_generic.py | 14 ------ tests/test_log_levels.py | 2 +- tests/test_processors.py | 70 +++++++++++++++------------- tests/test_stdlib.py | 22 ++++----- tests/test_threadlocal.py | 10 ++-- tests/test_tracebacks.py | 92 ++++++++++++++++++++----------------- tests/test_twisted.py | 27 +++++------ tests/utils.py | 6 +++ 23 files changed, 201 insertions(+), 196 deletions(-) diff --git a/.gitignore b/.gitignore index 89b4da12..e2980f24 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ htmlcov tmp structlog.docset structlog.tgz +Justfile diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8d57ea6a..fe4dc309 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,13 +13,13 @@ repos: - id: black - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.0.271 + rev: v0.0.274 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] - repo: https://github.com/codespell-project/codespell - rev: v2.2.4 + rev: v2.2.5 hooks: - id: codespell args: [-L, alog] diff --git a/docs/conf.py b/docs/conf.py index 70021989..5f4ac3bb 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -77,10 +77,6 @@ # If true, '()' will be appended to :func: etc. cross-reference text. add_function_parentheses = True -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -# add_module_names = True - # Move type hints into the description block, instead of the func definition. autodoc_typehints = "description" autodoc_typehints_description_target = "documented" diff --git a/pyproject.toml b/pyproject.toml index 8775bec8..4f954450 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,7 +54,7 @@ tests = [ ] # Need Twisted & Rich for stubs. # Otherwise mypy fails in tox. -typing = ["mypy", "rich", "twisted"] +typing = ["mypy>=1.4", "rich", "twisted"] docs = [ "furo", "myst-parser", @@ -115,41 +115,49 @@ line-length = 79 [tool.ruff] src = ["src", "tests"] -select = [ - "E", # pycodestyle - "W", # pycodestyle - "F", # Pyflakes - "UP", # pyupgrade - "N", # pep8-naming - "YTT", # flake8-2020 - "S", # flake8-bandit - "B", # flake8-bugbear - "C4", # flake8-comprehensions - "T10", # flake8-debugger - "ISC", # flake8-implicit-str-concat - "RET", # flake8-return - "SIM", # flake8-simplify - "DTZ", # flake8-datetimez - "I", # isort - "PGH", # pygrep-hooks - "PLC", # Pylint - "PIE", # flake8-pie - "RUF", # ruff -] +select = ["ALL"] ignore = [ - "RUF001", # leave my smart characters alone - "N802", # some names are non-pep8 due to stdlib logging / Twisted - "N803", # ditto - "N806", # ditto + "A", # shadowing is fine + "ANN", # Mypy is better at this + "ARG", # unused arguments are common w/ interfaces + "C901", # sometimes you trade complexity for performance + "COM", # Black takes care of our commas + "D", # We prefer our own docstring style. + "E501", # leave line-length enforcement to Black + "EM101", # simple strings are fine + "FBT", # bools are our friends + "FIX", # Yes, we want XXX as a marker. + "INP001", # sometimes we want Python files outside of packages + "N802", # some names are non-pep8 due to stdlib logging / Twisted + "N803", # ditto + "N806", # ditto + "PLR0913", # leave complexity to me + "PLR2004", # numbers are sometimes fine + "PLW2901", # overwriting a loop var can be useful + "RUF001", # leave my smart characters alone + "RUF001", # leave my smart characters alone + "SLF001", # private members are accessed by friendly functions + "T201", # prints are fine + "TCH", # TYPE_CHECKING blocks break autodocs + "TD", # we don't follow other people's todo style + "TRY003", # simple strings are fine + "TRY004", # too many false negatives + "TRY300", # else blocks are nice, but code-locality is nicer + "PTH", # pathlib can be slow, so no point to rewrite ] [tool.ruff.per-file-ignores] "tests/*" = [ + "B018", # "useless" expressions can be useful in tests + "BLE", # tests have different rules around exceptions + "EM", # tests have different rules around exceptions + "PLC1901", # empty strings are falsey, but are less specific in tests + "PT005", # we always add underscores and explicit name + "RUF012", # no type hints in tests "S101", # assert "S301", # I know pickle is bad, but people like it. "SIM300", # Yoda rocks in tests - "PLC1901", # empty strings are falsey, but are less specific in tests - "B018", # "useless" expressions can be useful in tests + "TRY", # tests have different rules around exceptions ] [tool.ruff.isort] diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 52c55d32..f580c48b 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -99,7 +99,8 @@ def __getattr__(name: str) -> str: "__email__": "", } if name not in dunder_to_metadata.keys(): - raise AttributeError(f"module {__name__} has no attribute {name}") + msg = f"module {__name__} has no attribute {name}" + raise AttributeError(msg) import sys import warnings diff --git a/src/structlog/_base.py b/src/structlog/_base.py index 3b865fda..535a49d3 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -169,11 +169,8 @@ def _process_event( if isinstance(event_dict, dict): return (), event_dict - raise ValueError( - "Last processor didn't return an appropriate value. Valid " - "return values are a dict, a tuple of (args, kwargs), bytes, " - "or a str." - ) + msg = "Last processor didn't return an appropriate value. Valid return values are a dict, a tuple of (args, kwargs), bytes, or a str." + raise ValueError(msg) def _proxy_to_logger( self, method_name: str, event: str | None = None, **event_kw: Any diff --git a/src/structlog/_output.py b/src/structlog/_output.py index d73739eb..64dfb5e8 100644 --- a/src/structlog/_output.py +++ b/src/structlog/_output.py @@ -24,8 +24,6 @@ def _get_lock_for_file(file: IO[Any]) -> threading.Lock: - global WRITE_LOCKS - lock = WRITE_LOCKS.get(file) if lock is None: lock = threading.Lock() diff --git a/src/structlog/dev.py b/src/structlog/dev.py index d651faaf..7ff9be1c 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -340,7 +340,7 @@ def _repr(self, val: Any) -> str: return repr(val) - def __call__( + def __call__( # noqa: PLR0912 self, logger: WrappedLogger, name: str, event_dict: EventDict ) -> str: sio = StringIO() diff --git a/src/structlog/processors.py b/src/structlog/processors.py index cceedea6..8d8b8161 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -145,7 +145,8 @@ def __call__( elements: list[str] = [] for key, value in self._ordered_items(event_dict): if any(c <= " " for c in key): - raise ValueError(f'Invalid key: "{key}"') + msg = f'Invalid key: "{key}"' + raise ValueError(msg) if value is None: elements.append(f"{key}=") @@ -182,7 +183,7 @@ def _items_sorter( def ordered_items(event_dict: EventDict) -> list[tuple[str, Any]]: items = [] - for key in key_order: # type: ignore[union-attr] + for key in key_order: value = event_dict.pop(key, None) if value is not None or not drop_missing: items.append((key, value)) @@ -195,7 +196,7 @@ def ordered_items(event_dict: EventDict) -> list[tuple[str, Any]]: def ordered_items(event_dict: EventDict) -> list[tuple[str, Any]]: items = [] - for key in key_order: # type: ignore[union-attr] + for key in key_order: value = event_dict.pop(key, None) if value is not None or not drop_missing: items.append((key, value)) @@ -470,7 +471,8 @@ def _make_stamper( Create a stamper function. """ if fmt is None and not utc: - raise ValueError("UNIX timestamps are always UTC.") + msg = "UNIX timestamps are always UTC." + raise ValueError(msg) now: Callable[[], datetime.datetime] @@ -510,7 +512,7 @@ def stamper_iso_utc(event_dict: EventDict) -> EventDict: return stamper_iso_local def stamper_fmt(event_dict: EventDict) -> EventDict: - event_dict[key] = now().strftime(fmt) # type: ignore[arg-type] + event_dict[key] = now().strftime(fmt) return event_dict @@ -601,7 +603,7 @@ class StackInfoRenderer: .. versionadded:: 22.1.0 *additional_ignores* """ - __slots__ = ["_additional_ignores"] + __slots__ = ("_additional_ignores",) def __init__(self, additional_ignores: list[str] | None = None) -> None: self._additional_ignores = additional_ignores @@ -742,11 +744,7 @@ class _RecordMapping(NamedTuple): event_dict_key: str record_attribute: str - __slots__ = [ - "_active_handlers", - "_additional_ignores", - "_record_mappings", - ] + __slots__ = ("_active_handlers", "_additional_ignores", "_record_mappings") def __init__( self, diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 54f9920f..a7e09b19 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -495,7 +495,7 @@ class AsyncBoundLogger: .. versionchanged:: 20.2.0 fix _dispatch_to_sync contextvars usage """ - __slots__ = ["sync_bl", "_loop"] + __slots__ = ("sync_bl", "_loop") sync_bl: BoundLogger @@ -807,7 +807,7 @@ class ExtraAdder: .. versionadded:: 21.5.0 """ - __slots__ = ["_copier"] + __slots__ = ("_copier",) def __init__(self, allow: Collection[str] | None = None) -> None: self._copier: Callable[[EventDict, logging.LogRecord], None] @@ -962,10 +962,8 @@ def __init__( super().__init__(*args, fmt=fmt, **kwargs) # type: ignore[misc] if processor and processors: - raise TypeError( - "The `processor` and `processors` arguments are mutually " - "exclusive." - ) + msg = "The `processor` and `processors` arguments are mutually exclusive." + raise TypeError(msg) self.processors: Sequence[Processor] if processor is not None: @@ -973,9 +971,8 @@ def __init__( elif processors: self.processors = processors else: - raise TypeError( - "Either `processor` or `processors` must be passed." - ) + msg = "Either `processor` or `processors` must be passed." + raise TypeError(msg) self.foreign_pre_chain = foreign_pre_chain self.keep_exc_info = keep_exc_info diff --git a/src/structlog/tracebacks.py b/src/structlog/tracebacks.py index 9f6195b4..7f7b0ba9 100644 --- a/src/structlog/tracebacks.py +++ b/src/structlog/tracebacks.py @@ -94,7 +94,7 @@ def safe_str(_object: Any) -> str: """Don't allow exceptions from __str__ to propegate.""" try: return str(_object) - except Exception as error: + except Exception as error: # noqa: BLE001 return f"" @@ -105,7 +105,7 @@ def to_repr(obj: Any, max_string: int | None = None) -> str: else: try: obj_repr = repr(obj) - except Exception as error: + except Exception as error: # noqa: BLE001 obj_repr = f"" if max_string is not None and len(obj_repr) > max_string: @@ -231,11 +231,11 @@ def __init__( max_frames: int = MAX_FRAMES, ) -> None: if locals_max_string < 0: - raise ValueError( - f'"locals_max_string" must be >= 0: {locals_max_string}' - ) + msg = f'"locals_max_string" must be >= 0: {locals_max_string}' + raise ValueError(msg) if max_frames < 2: - raise ValueError(f'"max_frames" must be >= 2: {max_frames}') + msg = f'"max_frames" must be >= 2: {max_frames}' + raise ValueError(msg) self.show_locals = show_locals self.locals_max_string = locals_max_string self.max_frames = max_frames diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index 22b62301..3ac75953 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -311,9 +311,9 @@ def __call__( ) -> Any: if name == "err": # This aspires to handle the following cases correctly: - # - log.err(failure, _why='event', **kw) - # - log.err('event', **kw) - # - log.err(_stuff=failure, _why='event', **kw) + # 1. log.err(failure, _why='event', **kw) + # 2. log.err('event', **kw) + # 3. log.err(_stuff=failure, _why='event', **kw) _stuff, _why, eventDict = _extractStuffAndWhy(eventDict) eventDict["event"] = _why diff --git a/tests/test_base.py b/tests/test_base.py index ed2eef8a..faa9aead 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -13,6 +13,7 @@ from structlog.exceptions import DropEvent from structlog.processors import KeyValueRenderer from structlog.testing import ReturnLogger +from tests.utils import CustomError def build_bl(logger=None, processors=None, context=None): @@ -161,9 +162,9 @@ def test_chain_does_not_swallow_all_exceptions(self): If the chain raises anything else than DropEvent, the error is not swallowed. """ - b = build_bl(processors=[raiser(ValueError)]) + b = build_bl(processors=[raiser(CustomError)]) - with pytest.raises(ValueError): + with pytest.raises(CustomError): b._process_event("", "boom", {}) def test_last_processor_returns_string(self): @@ -223,10 +224,9 @@ def test_last_processor_returns_unknown_value(self): """ logger = stub(msg=lambda *args, **kw: (args, kw)) b = build_bl(logger, processors=[lambda *_: object()]) - with pytest.raises(ValueError) as exc: - b._process_event("", "foo", {}) - assert exc.value.args[0].startswith("Last processor didn't return") + with pytest.raises(ValueError, match="Last processor didn't return"): + b._process_event("", "foo", {}) class TestProxying: diff --git a/tests/test_dev.py b/tests/test_dev.py index e179a064..dfbed0cb 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -366,7 +366,7 @@ def test_everything(self, cr, styles, padded, explicit_ei): elif explicit_ei == "exception": ei = e else: - raise ValueError() from None + raise ValueError from None else: ei = True diff --git a/tests/test_frames.py b/tests/test_frames.py index 3aa878fd..00263d69 100644 --- a/tests/test_frames.py +++ b/tests/test_frames.py @@ -85,7 +85,7 @@ def test_tolerates_f_back_is_None(self, monkeypatch): assert (f1, "?") == (f, n) -@pytest.fixture +@pytest.fixture() def exc_info(): """ Fake a valid exc_info. diff --git a/tests/test_generic.py b/tests/test_generic.py index 65ff141a..4bc7b36e 100644 --- a/tests/test_generic.py +++ b/tests/test_generic.py @@ -39,20 +39,6 @@ def test_caches(self): assert "msg" in b.__dict__ - def test_proxies_anything(self): - """ - Anything that isn't part of BoundLoggerBase gets proxied to the correct - wrapped logger methods. - """ - b = BoundLogger( - ReturnLogger(), - _CONFIG.default_processors, - _CONFIG.default_context_class(), - ) - - assert "log", "foo" == b.log("foo") - assert "gol", "bar" == b.gol("bar") - @pytest.mark.parametrize("proto", range(3, pickle.HIGHEST_PROTOCOL + 1)) @freeze_time("2023-05-22 17:00") def test_pickle(self, proto): diff --git a/tests/test_log_levels.py b/tests/test_log_levels.py index 8faa576d..fb4075af 100644 --- a/tests/test_log_levels.py +++ b/tests/test_log_levels.py @@ -267,7 +267,7 @@ async def test_async_pos_args(self, bl, cl): assert [("info", (), {"event": "hello world -- 42!"})] == cl.calls @pytest.mark.parametrize( - "meth,args", + ("meth", "args"), [ ("aexception", ("ev",)), ("ainfo", ("ev",)), diff --git a/tests/test_processors.py b/tests/test_processors.py index 4a5d7d80..9d7482c6 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -3,6 +3,8 @@ # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. +from __future__ import annotations + import datetime import functools import inspect @@ -15,7 +17,6 @@ import threading from io import StringIO -from typing import Any, Dict, List, Optional, Set import pytest @@ -46,6 +47,7 @@ from structlog.threadlocal import wrap_dict from structlog.typing import EventDict from tests.additional_frame import additional_frame +from tests.utils import CustomError try: @@ -284,11 +286,9 @@ def test_invalid_key(self): "invalid key": "somevalue", } - with pytest.raises(ValueError) as e: + with pytest.raises(ValueError, match='Invalid key: "invalid key"'): LogfmtRenderer()(None, None, event_dict) - assert 'Invalid key: "invalid key"' == e.value.args[0] - class TestJSONRenderer: def test_renders_json(self, event_dict): @@ -365,11 +365,11 @@ def test_disallows_non_utc_unix_timestamps(self): A asking for a UNIX timestamp with a timezone that's not UTC raises a ValueError. """ - with pytest.raises(ValueError) as e: + with pytest.raises( + ValueError, match="UNIX timestamps are always UTC." + ): TimeStamper(utc=False) - assert "UNIX timestamps are always UTC." == e.value.args[0] - def test_inserts_utc_unix_timestamp_by_default(self): """ Per default a float UNIX timestamp is used. @@ -457,13 +457,16 @@ def test_custom_formatter(self): """ The exception formatter can be changed. """ + formatter = ExceptionRenderer(lambda _: "There is no exception!") + try: - raise ValueError("test") - except ValueError as e: - formatter = ExceptionRenderer(lambda _: "There is no exception!") - assert formatter(None, None, {"exc_info": e}) == { - "exception": "There is no exception!" - } + raise CustomError("test") + except CustomError as e: + exc = e + + assert formatter(None, None, {"exc_info": exc}) == { + "exception": "There is no exception!" + } @pytest.mark.parametrize("ei", [False, None, ""]) def test_nop(self, ei): @@ -504,18 +507,21 @@ def test_gets_exc_info_on_bool(self): def test_exception(self): """ - Passing exceptions as exc_info is valid on Python 3. + Passing exceptions as exc_info is valid. """ + formatter = ExceptionRenderer(lambda exc_info: exc_info) + try: raise ValueError("test") except ValueError as e: - formatter = ExceptionRenderer(lambda exc_info: exc_info) - d = formatter(None, None, {"exc_info": e}) - - assert {"exception": (ValueError, e, e.__traceback__)} == d + exc = e else: pytest.fail("Exception not raised.") + assert { + "exception": (ValueError, exc, exc.__traceback__) + } == formatter(None, None, {"exc_info": exc}) + def test_exception_without_traceback(self): """ If an Exception is missing a traceback, render it anyway. @@ -695,7 +701,7 @@ def test_exception_on_py3(self, sio): assert "XXX" in sio.getvalue() -@pytest.fixture +@pytest.fixture() def sir(): return StackInfoRenderer() @@ -791,7 +797,7 @@ def test_all_parameters(self) -> None: "determine the callsite for async calls." ) ) - @pytest.mark.asyncio + @pytest.mark.asyncio() async def test_async(self) -> None: """ Callsite information for async invocations are correct. @@ -854,7 +860,7 @@ def test_additional_ignores(self, monkeypatch: pytest.MonkeyPatch) -> None: assert expected == actual @pytest.mark.parametrize( - "origin, parameter_strings", + ("origin", "parameter_strings"), itertools.product( ["logging", "structlog"], [ @@ -870,7 +876,7 @@ def test_additional_ignores(self, monkeypatch: pytest.MonkeyPatch) -> None: def test_processor( self, origin: str, - parameter_strings: Optional[Set[str]], + parameter_strings: set[str] | None, ): """ The correct callsite parameters are added to event dictionaries. @@ -917,7 +923,7 @@ def test_processor( assert expected == actual @pytest.mark.parametrize( - "setup, origin, parameter_strings", + ("setup", "origin", "parameter_strings"), itertools.product( ["common-without-pre", "common-with-pre", "shared", "everywhere"], ["logging", "structlog"], @@ -935,7 +941,7 @@ def test_e2e( self, setup: str, origin: str, - parameter_strings: Optional[Set[str]], + parameter_strings: set[str] | None, ) -> None: """ Logging output contains the correct callsite parameters. @@ -978,7 +984,7 @@ def test_e2e( callsite_params = self.get_callsite_parameters() logger.info(test_message) elif origin == "structlog": - ctx: Dict[str, Any] = {} + ctx = {} bound_logger = BoundLogger( logger, [*common_processors, ProcessorFormatter.wrap_for_formatter], @@ -1007,8 +1013,8 @@ def test_e2e( @classmethod def make_processor( cls, - parameter_strings: Optional[Set[str]], - additional_ignores: Optional[List[str]] = None, + parameter_strings: set[str] | None, + additional_ignores: list[str] | None = None, ) -> CallsiteParameterAdder: """ Creates a ``CallsiteParameterAdder`` with parameters matching the @@ -1035,8 +1041,8 @@ def make_processor( @classmethod def filter_parameters( - cls, parameter_strings: Optional[Set[str]] - ) -> Set[CallsiteParameter]: + cls, parameter_strings: set[str] | None + ) -> set[CallsiteParameter]: """ Returns a set containing all ``CallsiteParameter`` members with values that are in ``parameter_strings``. @@ -1057,8 +1063,8 @@ def filter_parameters( @classmethod def filter_parameter_dict( - cls, input: Dict[str, Any], parameter_strings: Optional[Set[str]] - ) -> Dict[str, Any]: + cls, input: dict[str, object], parameter_strings: set[str] | None + ) -> dict[str, object]: """ Returns a dictionary that is equivalent to ``input`` but with all keys not in ``parameter_strings`` removed. @@ -1076,7 +1082,7 @@ def filter_parameter_dict( } @classmethod - def get_callsite_parameters(cls, offset: int = 1) -> Dict[str, Any]: + def get_callsite_parameters(cls, offset: int = 1) -> dict[str, object]: """ This function creates dictionary of callsite parameters for the line that is ``offset`` lines after the invocation of this function. diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 0333cb3f..463bd376 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -237,7 +237,7 @@ def test_stdlib_passthrough_attributes(self, attribute_name): assert bound_logger_attribute == stdlib_logger_attribute @pytest.mark.parametrize( - "method_name,method_args", + ("method_name", "method_args"), [ ("addHandler", [None]), ("removeHandler", [None]), @@ -467,7 +467,7 @@ def test_args_removed_if_empty(self): class TestAddLogLevelNumber: - @pytest.mark.parametrize("level, number", _NAME_TO_LEVEL.items()) + @pytest.mark.parametrize(("level", "number"), _NAME_TO_LEVEL.items()) def test_log_level_number_added(self, level, number): """ The log level number is added to the event dict. @@ -559,7 +559,7 @@ def extra_dict_fixture(): class TestExtraAdder: @pytest.mark.parametrize( - "allow, misses", + ("allow", "misses"), [ (None, None), ({}, None), @@ -601,7 +601,7 @@ def test_no_record(self): assert {} == actual @pytest.mark.parametrize( - "allow, misses", + ("allow", "misses"), [ (None, None), ({}, None), @@ -1135,14 +1135,14 @@ def test_sync_bl(self, abl, cl): CapturedCall(method_name="info", args=(), kwargs={"event": "test"}) ] == cl.calls - @pytest.mark.asyncio + @pytest.mark.asyncio() async def test_protocol(self, abl): """ AsyncBoundLogger is a proper BindableLogger. """ assert isinstance(abl, BindableLogger) - @pytest.mark.asyncio + @pytest.mark.asyncio() async def test_correct_levels(self, abl, cl, stdlib_log_method): """ The proxy methods call the correct upstream methods. @@ -1156,7 +1156,7 @@ async def test_correct_levels(self, abl, cl, stdlib_log_method): assert expect == cl.calls[0].method_name - @pytest.mark.asyncio + @pytest.mark.asyncio() async def test_log_method(self, abl, cl): """ The `log` method is proxied too. @@ -1165,7 +1165,7 @@ async def test_log_method(self, abl, cl): assert "error" == cl.calls[0].method_name - @pytest.mark.asyncio + @pytest.mark.asyncio() async def test_exception(self, abl, cl): """ `exception` makes sure 'exc_info" is set, if it's not set already. @@ -1180,7 +1180,7 @@ async def test_exception(self, abl, cl): assert ValueError is ei[0] assert ("omg",) == ei[1].args - @pytest.mark.asyncio + @pytest.mark.asyncio() async def test_exception_do_not_overwrite(self, abl, cl): """ `exception` leaves exc_info be, if it's set. @@ -1197,7 +1197,7 @@ async def test_exception_do_not_overwrite(self, abl, cl): ei = cl.calls[0].kwargs["exc_info"] assert (o1, o2, o3) == ei - @pytest.mark.asyncio + @pytest.mark.asyncio() async def test_bind_unbind(self, cl): """ new/bind/unbind/try_unbind are correctly propagated. @@ -1228,7 +1228,7 @@ async def test_bind_unbind(self, cl): assert {} == l5._context assert l4 is not l5 - @pytest.mark.asyncio + @pytest.mark.asyncio() async def test_integration(self, capsys): """ Configure and log an actual entry. diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py index ae744a61..3e58c7bd 100644 --- a/tests/test_threadlocal.py +++ b/tests/test_threadlocal.py @@ -26,6 +26,7 @@ unbind_threadlocal, wrap_dict, ) +from tests.utils import CustomError try: @@ -89,15 +90,16 @@ def test_bind_exc(self, log): tmp_bind cleans up properly on exceptions. """ log = log.bind(y=23) - with pytest.raises(ValueError), pytest.deprecated_call(), tmp_bind( - log, x=42, y="foo" - ) as tmp_log: + + with pytest.raises( # noqa: PT012 + CustomError + ), pytest.deprecated_call(), tmp_bind(log, x=42, y="foo") as tmp_log: assert ( {"y": "foo", "x": 42} == tmp_log._context._dict == log._context._dict ) - raise ValueError + raise CustomError assert {"y": 23} == log._context._dict diff --git a/tests/test_tracebacks.py b/tests/test_tracebacks.py index 2503d5cc..3e5f1ef1 100644 --- a/tests/test_tracebacks.py +++ b/tests/test_tracebacks.py @@ -1,14 +1,14 @@ import sys from pathlib import Path -from typing import Any, Dict, Optional +from typing import Any, Optional import pytest from structlog import tracebacks -@pytest.mark.parametrize("data, expected", [(3, "3"), ("spam", "spam")]) +@pytest.mark.parametrize(("data", "expected"), [(3, "3"), ("spam", "spam")]) def test_save_str(data: Any, expected: str): """ "safe_str()" returns the str repr of an object. @@ -25,12 +25,14 @@ class Baam: def __str__(self) -> str: raise ValueError("BAAM!") - pytest.raises(ValueError, str, Baam()) + with pytest.raises(ValueError, match="BAAM!"): + str(Baam()) + assert tracebacks.safe_str(Baam()) == "" @pytest.mark.parametrize( - "data, max_len, expected", + ("data", "max_len", "expected"), [ (3, None, "3"), ("spam", None, "spam"), @@ -53,7 +55,9 @@ class Baam: def __repr__(self) -> str: raise ValueError("BAAM!") - pytest.raises(ValueError, repr, Baam()) + with pytest.raises(ValueError, match="BAAM!"): + repr(Baam()) + assert tracebacks.to_repr(Baam()) == "" @@ -75,7 +79,7 @@ def test_simple_exception(): frames=[ tracebacks.Frame( filename=__file__, - lineno=65, + lineno=69, name="test_simple_exception", line="", locals=None, @@ -107,7 +111,7 @@ def test_raise_hide_cause(): frames=[ tracebacks.Frame( filename=__file__, - lineno=97, + lineno=101, name="test_raise_hide_cause", line="", locals=None, @@ -139,7 +143,7 @@ def test_raise_with_cause(): frames=[ tracebacks.Frame( filename=__file__, - lineno=129, + lineno=133, name="test_raise_with_cause", line="", locals=None, @@ -154,7 +158,7 @@ def test_raise_with_cause(): frames=[ tracebacks.Frame( filename=__file__, - lineno=127, + lineno=131, name="test_raise_with_cause", line="", locals=None, @@ -182,7 +186,7 @@ def test_raise_with_cause_no_tb(): frames=[ tracebacks.Frame( filename=__file__, - lineno=172, + lineno=176, name="test_raise_with_cause_no_tb", line="", locals=None, @@ -214,7 +218,7 @@ def test_raise_nested(): frames=[ tracebacks.Frame( filename=__file__, - lineno=204, + lineno=208, name="test_raise_nested", line="", locals=None, @@ -229,7 +233,7 @@ def test_raise_nested(): frames=[ tracebacks.Frame( filename=__file__, - lineno=202, + lineno=206, name="test_raise_nested", line="", locals=None, @@ -258,7 +262,7 @@ def test_raise_no_msg(): frames=[ tracebacks.Frame( filename=__file__, - lineno=248, + lineno=252, name="test_raise_no_msg", line="", locals=None, @@ -293,7 +297,7 @@ def test_syntax_error(): frames=[ tracebacks.Frame( filename=__file__, - lineno=277, + lineno=281, name="test_syntax_error", line="", locals=None, @@ -321,7 +325,7 @@ def test_filename_with_bracket(): frames=[ tracebacks.Frame( filename=__file__, - lineno=311, + lineno=315, name="test_filename_with_bracket", line="", locals=None, @@ -356,7 +360,7 @@ def test_filename_not_a_file(): frames=[ tracebacks.Frame( filename=__file__, - lineno=346, + lineno=350, name="test_filename_not_a_file", line="", locals=None, @@ -432,7 +436,7 @@ def bar(n): ) # Buffer for frames from pytest assert frames[0] == tracebacks.Frame( filename=__file__, - lineno=414, + lineno=418, name="test_recursive", ) # Depending on whether we invoke pytest directly or run tox, either "foo()" @@ -440,12 +444,12 @@ def bar(n): assert frames[-1] in [ tracebacks.Frame( filename=__file__, - lineno=408, + lineno=412, name="foo", ), tracebacks.Frame( filename=__file__, - lineno=411, + lineno=415, name="bar", ), ] @@ -457,23 +461,24 @@ def test_json_traceback(): except Exception as e: format_json = tracebacks.ExceptionDictTransformer(show_locals=False) result = format_json((type(e), e, e.__traceback__)) - assert result == [ - { - "exc_type": "ZeroDivisionError", - "exc_value": "division by zero", - "frames": [ - { - "filename": __file__, - "line": "", - "lineno": 456, - "locals": None, - "name": "test_json_traceback", - } - ], - "is_cause": False, - "syntax_error": None, - }, - ] + + assert result == [ + { + "exc_type": "ZeroDivisionError", + "exc_value": "division by zero", + "frames": [ + { + "filename": __file__, + "line": "", + "lineno": 460, + "locals": None, + "name": "test_json_traceback", + } + ], + "is_cause": False, + "syntax_error": None, + }, + ] def test_json_traceback_locals_max_string(): @@ -492,7 +497,7 @@ def test_json_traceback_locals_max_string(): { "filename": __file__, "line": "", - "lineno": 482, + "lineno": 487, "locals": { "_var": "'spam'+8", "e": "'Zero'+33", @@ -507,10 +512,8 @@ def test_json_traceback_locals_max_string(): @pytest.mark.parametrize( - "max_frames, expected_frames, skipped_idx, skipped_count", + ("max_frames", "expected_frames", "skipped_idx", "skipped_count"), [ - # (0, 1, 0, 3), - # (1, 1, 0, 3), (2, 3, 1, 2), (3, 3, 1, 2), (4, 4, -1, 0), @@ -559,5 +562,10 @@ def bacon(): {"max_frames": 1}, ], ) -def test_json_traceback_value_error(kwargs: Dict[str, Any]): - pytest.raises(ValueError, tracebacks.ExceptionDictTransformer, **kwargs) +def test_json_traceback_value_error(kwargs): + """ + Wrong arguments to ExceptionDictTransformer raise a ValueError that + contains the name of the argument.. + """ + with pytest.raises(ValueError, match=tuple(kwargs.keys())[0]): + tracebacks.ExceptionDictTransformer(**kwargs) diff --git a/tests/test_twisted.py b/tests/test_twisted.py index 5b930319..725c8506 100644 --- a/tests/test_twisted.py +++ b/tests/test_twisted.py @@ -100,7 +100,10 @@ def test_extractFailsOnTwoFailures(self): """ Raise ValueError if both _stuff and event contain exceptions. """ - with pytest.raises(ValueError) as e: + with pytest.raises( + ValueError, + match="Both _stuff and event contain an Exception/Failure.", + ): _extractStuffAndWhy( { "_stuff": Failure(ValueError()), @@ -108,20 +111,15 @@ def test_extractFailsOnTwoFailures(self): } ) - assert ( - "Both _stuff and event contain an Exception/Failure." - == e.value.args[0] - ) - def test_failsOnConflictingEventAnd_why(self): """ Raise ValueError if both _why and event are in the event_dict. """ - with pytest.raises(ValueError) as e: + with pytest.raises( + ValueError, match="Both `_why` and `event` supplied." + ): _extractStuffAndWhy({"_why": "foo", "event": "bar"}) - assert "Both `_why` and `event` supplied." == e.value.args[0] - def test_handlesFailures(self): """ Extracts failures and events. @@ -212,15 +210,18 @@ def test_noFailureWithKeyword(self): ) def test_catchesConflictingEventAnd_why(self): + """ + Passing both _why and event raises a ValueError. + """ la = EventAdapter(_render_repr) - with pytest.raises(ValueError) as e: + with pytest.raises( + ValueError, match="Both `_why` and `event` supplied." + ): la(None, "err", {"event": "someEvent", "_why": "someReason"}) - assert "Both `_why` and `event` supplied." == e.value.args[0] - -@pytest.fixture +@pytest.fixture() def jr(): """ A plain Twisted JSONRenderer. diff --git a/tests/utils.py b/tests/utils.py index 79630d75..44b2b6ec 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -11,3 +11,9 @@ stdlib_log_methods = [m for m in _NAME_TO_LEVEL if m != "notset"] + + +class CustomError(Exception): + """ + Custom exception for testing purposes. + """ From 6d5e1baef388aaeba7672d3289409681de4554e7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 22 Jun 2023 08:50:30 +0200 Subject: [PATCH 1032/1520] Fix some type hints --- src/structlog/_config.py | 4 ++-- src/structlog/processors.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/structlog/_config.py b/src/structlog/_config.py index e297320a..c0464a7b 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -144,7 +144,7 @@ def get_logger(*args: Any, **initial_values: Any) -> Any: def wrap_logger( - logger: WrappedLogger, + logger: WrappedLogger | None, processors: Iterable[Processor] | None = None, wrapper_class: type[BindableLogger] | None = None, context_class: type[Context] | None = None, @@ -299,7 +299,7 @@ class BoundLoggerLazyProxy: def __init__( self, - logger: WrappedLogger, + logger: WrappedLogger | None, wrapper_class: type[BindableLogger] | None = None, processors: Iterable[Processor] | None = None, context_class: type[Context] | None = None, diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 8d8b8161..889fda4c 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -183,7 +183,7 @@ def _items_sorter( def ordered_items(event_dict: EventDict) -> list[tuple[str, Any]]: items = [] - for key in key_order: + for key in key_order: # type: ignore[union-attr] value = event_dict.pop(key, None) if value is not None or not drop_missing: items.append((key, value)) @@ -196,7 +196,7 @@ def ordered_items(event_dict: EventDict) -> list[tuple[str, Any]]: def ordered_items(event_dict: EventDict) -> list[tuple[str, Any]]: items = [] - for key in key_order: + for key in key_order: # type: ignore[union-attr] value = event_dict.pop(key, None) if value is not None or not drop_missing: items.append((key, value)) @@ -512,7 +512,7 @@ def stamper_iso_utc(event_dict: EventDict) -> EventDict: return stamper_iso_local def stamper_fmt(event_dict: EventDict) -> EventDict: - event_dict[key] = now().strftime(fmt) + event_dict[key] = now().strftime(fmt) # type: ignore[arg-type] return event_dict From 752b7028a1593975b217158323726940c0d745fd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 22 Jun 2023 08:52:26 +0200 Subject: [PATCH 1033/1520] Oops wrong Mypy version --- src/structlog/processors.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 889fda4c..8d8b8161 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -183,7 +183,7 @@ def _items_sorter( def ordered_items(event_dict: EventDict) -> list[tuple[str, Any]]: items = [] - for key in key_order: # type: ignore[union-attr] + for key in key_order: value = event_dict.pop(key, None) if value is not None or not drop_missing: items.append((key, value)) @@ -196,7 +196,7 @@ def ordered_items(event_dict: EventDict) -> list[tuple[str, Any]]: def ordered_items(event_dict: EventDict) -> list[tuple[str, Any]]: items = [] - for key in key_order: # type: ignore[union-attr] + for key in key_order: value = event_dict.pop(key, None) if value is not None or not drop_missing: items.append((key, value)) @@ -512,7 +512,7 @@ def stamper_iso_utc(event_dict: EventDict) -> EventDict: return stamper_iso_local def stamper_fmt(event_dict: EventDict) -> EventDict: - event_dict[key] = now().strftime(fmt) # type: ignore[arg-type] + event_dict[key] = now().strftime(fmt) return event_dict From 88d26aa8b9b6c7cb8d86dcbf0b7132e130b6c9e7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 22 Jun 2023 09:38:45 +0200 Subject: [PATCH 1034/1520] Fix docstrings --- src/structlog/_base.py | 2 +- src/structlog/_config.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/structlog/_base.py b/src/structlog/_base.py index 535a49d3..56abacbd 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -100,7 +100,7 @@ def try_unbind(self, *keys: str) -> BoundLoggerBase: def new(self, **new_values: Any) -> BoundLoggerBase: """ - Clear context and binds *initial_values* using `bind`. + Clear context and binds *new_values* using `bind`. Only necessary with dict implementations that keep global state like those wrapped by `structlog.threadlocal.wrap_dict` when threads diff --git a/src/structlog/_config.py b/src/structlog/_config.py index c0464a7b..9bf6b7fb 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -283,14 +283,14 @@ def reset_defaults() -> None: class BoundLoggerLazyProxy: """ - Instantiates a ``BoundLogger`` on first usage. + Instantiates a bound logger on first usage. Takes both configuration and instantiation parameters into account. - The only points where a BoundLogger changes state are ``bind()``, + The only points where a bound logger changes state are ``bind()``, ``unbind()``, and ``new()`` and that return the actual ``BoundLogger``. - If and only if configuration says so, that actual ``BoundLogger`` is + If and only if configuration says so, that actual bound logger is cached on first usage. .. versionchanged:: 0.4.0 From a5baddcda7fc92e7d6e1ab9f071f2eaa0d11db34 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 25 Jun 2023 11:02:59 +0200 Subject: [PATCH 1035/1520] Decouple dev env from docs --- .github/CONTRIBUTING.md | 16 ++++++++++++---- pyproject.toml | 2 +- tox.ini | 19 ++++++++++++++++++- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 88003521..1b4a15df 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -83,13 +83,21 @@ At this point, $ python -m pytest ``` -should work and pass, as should: +When working on the documentation, use: -```console -$ cd docs -$ make html +```bash +$ tox -e docs-serve ``` +... to watch your files and repeatedly build. +And use: + +```bash +$ tox -e docs +``` + +... to build it once and run our doctests. + The built documentation can then be found in `docs/_build/html/`. --- diff --git a/pyproject.toml b/pyproject.toml index 4f954450..95fdf0d9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -63,7 +63,7 @@ docs = [ "sphinxcontrib-mermaid", "twisted", ] -dev = ["structlog[tests,typing,docs]"] +dev = ["structlog[tests,typing]"] [tool.hatch.version] diff --git a/tox.ini b/tox.ini index ab7428aa..689f9031 100644 --- a/tox.ini +++ b/tox.ini @@ -45,11 +45,28 @@ commands = # Keep base_python in sync with ci.yml/docs and .readthedocs.yaml. base_python = py311 extras = docs -pass_env = TERM commands = sphinx-build -n -T -W -b html -d {envtmpdir}/doctrees docs docs/_build/html sphinx-build -n -T -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html +[testenv:docs-serve] +package = editable +base_python = {[testenv:docs]base_python} +extras = {[testenv:docs]extras} +deps = watchfiles +commands = + watchfiles \ + --ignore-paths docs/_build/ \ + 'sphinx-build -W -n --jobs auto -b html -d {envtmpdir}/doctrees docs docs/_build/html' \ + src \ + docs + + +[testenv:docs-linkcheck] +base_python = {[testenv:docs]base_python} +extras = {[testenv:docs]extras} +commands = sphinx-build -W -b linkcheck -d {envtmpdir}/doctrees docs docs/_build/html + [testenv:pre-commit] skip_install = true From ccdf502a3c01929bdeab4a587df98de0a48baf3d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 25 Jun 2023 11:07:01 +0200 Subject: [PATCH 1036/1520] pre-commit autoupdate --- .pre-commit-config.yaml | 2 +- src/structlog/_config.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fe4dc309..d3600d51 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,7 +13,7 @@ repos: - id: black - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.0.274 + rev: v0.0.275 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 9bf6b7fb..9d8a7442 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -36,9 +36,9 @@ set_exc_info, TimeStamper(fmt="%Y-%m-%d %H:%M:%S", utc=False), ConsoleRenderer( - colors=os.environ.get("NO_COLOR", "") == "" # noqa: PLC1901 + colors=os.environ.get("NO_COLOR", "") == "" and ( - os.environ.get("FORCE_COLOR", "") != "" # noqa: PLC1901 + os.environ.get("FORCE_COLOR", "") != "" or ( _has_colors and sys.stdout is not None From 996cc6c0011049b2706b70d792b5ff4716b388b9 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 25 Jun 2023 11:56:51 +0200 Subject: [PATCH 1037/1520] Drop support for Python 3.7 (#526) * Drop support for Python 3.7 * fix tox * Remove rest of 3.7isms --- .github/workflows/ci.yml | 12 ++++-------- CHANGELOG.md | 5 +++++ pyproject.toml | 9 ++------- src/structlog/__init__.py | 27 ++++++++++++--------------- src/structlog/dev.py | 8 +------- src/structlog/stdlib.py | 6 +----- src/structlog/typing.py | 10 ++-------- tests/test_packaging.py | 16 +++++----------- tests/test_stdlib.py | 5 ----- tox.ini | 8 ++++---- 10 files changed, 36 insertions(+), 70 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 04a86ef9..85534654 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,14 +49,13 @@ jobs: retention-days: 15 tests: - name: Tests on ${{ matrix.python-version }} + name: Tests & API Mypy on ${{ matrix.python-version }} needs: build-sdist runs-on: ubuntu-latest strategy: fail-fast: false matrix: python-version: - - "3.7" - "3.8" - "3.9" - "3.10" @@ -76,12 +75,9 @@ jobs: allow-prereleases: true cache: pip - - name: Prepare & run tox - run: | - python -Im pip install tox - - python -Im tox run -f py$(echo ${{ matrix.python-version }} | tr -d .) - python -Im tox run -e mypy-api + - run: python -Im pip install tox + - run: python -Im tox run -f py$(echo ${{ matrix.python-version }} | tr -d .) + - run: python -Im tox run -e mypy-api - name: Upload coverage data uses: actions/upload-artifact@v3 diff --git a/CHANGELOG.md b/CHANGELOG.md index 95eb097a..0b5013f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,11 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ## [Unreleased](https://github.com/hynek/structlog/compare/23.1.0...HEAD) +### Removed + +- Support for Python 3.7. + + ### Added - Official support for Python 3.12. diff --git a/pyproject.toml b/pyproject.toml index 95fdf0d9..49f0cc9a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ dynamic = ["readme", "version"] name = "structlog" description = "Structured Logging for Python" authors = [{ name = "Hynek Schlawack", email = "hs@ox.cx" }] -requires-python = ">=3.7" +requires-python = ">=3.8" license = "MIT OR Apache-2.0" keywords = ["logging", "structured", "structure", "log"] classifiers = [ @@ -18,7 +18,6 @@ classifiers = [ "License :: OSI Approved :: Apache Software License", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", @@ -29,10 +28,7 @@ classifiers = [ "Topic :: System :: Logging", "Typing :: Typed", ] -dependencies = [ - "typing-extensions; python_version<'3.8'", - "importlib_metadata; python_version<'3.8'", -] +dependencies = [] [project.urls] Documentation = "https://www.structlog.org/" @@ -42,7 +38,6 @@ Changelog = "https://www.structlog.org/en/stable/changelog.html" Funding = "https://github.com/sponsors/hynek" Tidelift = "https://tidelift.com/subscription/pkg/pypi-structlog?utm_source=pypi-structlog&utm_medium=pypi" - [project.optional-dependencies] tests = [ "coverage[toml]", diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index f580c48b..5df641b3 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -92,6 +92,10 @@ def __getattr__(name: str) -> str: + import warnings + + from importlib.metadata import metadata + dunder_to_metadata = { "__version__": "version", "__description__": "summary", @@ -102,21 +106,14 @@ def __getattr__(name: str) -> str: msg = f"module {__name__} has no attribute {name}" raise AttributeError(msg) - import sys - import warnings - - if sys.version_info < (3, 8): - from importlib_metadata import metadata - else: - from importlib.metadata import metadata - - warnings.warn( - f"Accessing structlog.{name} is deprecated and will be " - "removed in a future release. Use importlib.metadata directly " - "to query for structlog's packaging metadata.", - DeprecationWarning, - stacklevel=2, - ) + if name != "__version__": + warnings.warn( + f"Accessing structlog.{name} is deprecated and will be " + "removed in a future release. Use importlib.metadata directly " + "to query for structlog's packaging metadata.", + DeprecationWarning, + stacklevel=2, + ) meta = metadata("structlog") diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 7ff9be1c..8e9ecee7 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -15,19 +15,13 @@ import warnings from io import StringIO -from typing import Any, Iterable, TextIO, Type, Union +from typing import Any, Iterable, Protocol, TextIO, Type, Union from ._frames import _format_exception from .processors import _figure_out_exc_info from .typing import EventDict, ExceptionRenderer, ExcInfo, WrappedLogger -if sys.version_info >= (3, 8): - from typing import Protocol -else: - from typing_extensions import Protocol - - try: import colorama except ImportError: diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index a7e09b19..ea6a7124 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -67,11 +67,7 @@ def recreate_defaults(*, log_level: int | None = logging.NOTSET) -> None: .. versionadded:: 22.1 """ if log_level is not None: - kw = {} - # 3.7 doesn't have the force keyword and we don't care enough to - # re-implement it. - if sys.version_info >= (3, 8): - kw = {"force": True} + kw = {"force": True} logging.basicConfig( format="%(message)s", diff --git a/src/structlog/typing.py b/src/structlog/typing.py index d27625a9..c10e467a 100644 --- a/src/structlog/typing.py +++ b/src/structlog/typing.py @@ -14,8 +14,6 @@ from __future__ import annotations -import sys - from types import TracebackType from typing import ( Any, @@ -24,19 +22,15 @@ Mapping, MutableMapping, Optional, + Protocol, TextIO, Tuple, Type, Union, + runtime_checkable, ) -if sys.version_info >= (3, 8): - from typing import Protocol, runtime_checkable -else: - from typing_extensions import Protocol, runtime_checkable - - WrappedLogger = Any """ A logger that is wrapped by a bound logger and is ultimately responsible for diff --git a/tests/test_packaging.py b/tests/test_packaging.py index 6628c002..d8c470a0 100644 --- a/tests/test_packaging.py +++ b/tests/test_packaging.py @@ -3,26 +3,20 @@ # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. -import sys +from importlib import metadata import pytest import structlog -if sys.version_info < (3, 8): - import importlib_metadata as metadata -else: - from importlib import metadata - - class TestLegacyMetadataHack: - def test_version(self): + def test_version(self, recwarn): """ - structlog.__version__ returns the correct version. + structlog.__version__ returns the correct version and doesn't warn. """ - with pytest.deprecated_call(): - assert metadata.version("structlog") == structlog.__version__ + assert metadata.version("structlog") == structlog.__version__ + assert [] == recwarn.list def test_description(self): """ diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 463bd376..f9981b3c 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -1274,11 +1274,6 @@ def test_recreate_defaults(log_level): assert dict is _CONFIG.default_context_class assert isinstance(_CONFIG.logger_factory, LoggerFactory) - # 3.7 doesn't have the force keyword and we don't care enough to - # re-implement it. - if sys.version_info < (3, 8): - return - log = get_logger().bind() if log_level is not None: assert log_level == log.getEffectiveLevel() diff --git a/tox.ini b/tox.ini index 689f9031..dec60dd3 100644 --- a/tox.ini +++ b/tox.ini @@ -3,8 +3,8 @@ min_version = 4 env_list = pre-commit, mypy-{api,pkg}, - py3{7,8,9,10,11,12} - py3{7,11}-{colorama,be,rich}, + py3{8,9,10,11,12} + py3{8,11}-{colorama,be,rich}, docs, coverage-report @@ -20,7 +20,7 @@ commands = pytest {posargs} # Run oldest and latest under Coverage. -[testenv:py3{7,11}{,-colorama,-be,-rich}] +[testenv:py3{8,11}{,-colorama,-be,-rich}] deps = py311: twisted colorama: colorama @@ -35,7 +35,7 @@ base_python = py311 deps = coverage[toml] skip_install = true parallel_show_output = true -depends = py3{7,11}{,-colorama,-be,-rich} +depends = py3{8,11}{,-colorama,-be,-rich} commands = coverage combine coverage report From 5f32f37cdecaecffa2b8040a5531d20dfde97696 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 4 Jul 2023 08:30:37 +0200 Subject: [PATCH 1038/1520] pre-commit autoupdate --- .pre-commit-config.yaml | 4 ++-- src/structlog/_utils.py | 2 +- src/structlog/contextvars.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d3600d51..83b93f54 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,8 +12,8 @@ repos: hooks: - id: black - - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.0.275 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.0.276 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/src/structlog/_utils.py b/src/structlog/_utils.py index b57e55ab..0fa9769c 100644 --- a/src/structlog/_utils.py +++ b/src/structlog/_utils.py @@ -27,7 +27,7 @@ def until_not_interrupted(f: Callable[..., Any], *args: Any, **kw: Any) -> Any: while True: try: return f(*args, **kw) - except OSError as e: + except OSError as e: # noqa[PERF203] if e.args[0] == errno.EINTR: continue raise diff --git a/src/structlog/contextvars.py b/src/structlog/contextvars.py index ebb5941d..42373f5a 100644 --- a/src/structlog/contextvars.py +++ b/src/structlog/contextvars.py @@ -122,7 +122,7 @@ def bind_contextvars(**kw: Any) -> Mapping[str, contextvars.Token[Any]]: structlog_k = f"{STRUCTLOG_KEY_PREFIX}{k}" try: var = _CONTEXT_VARS[structlog_k] - except KeyError: + except KeyError: # noqa[PERF203] var = contextvars.ContextVar(structlog_k, default=Ellipsis) _CONTEXT_VARS[structlog_k] = var From e54fe517a6ad971f6896613487973b0f3b547313 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Jul 2023 08:42:24 +0200 Subject: [PATCH 1039/1520] Dedup --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 3ddd61f3..94c8fbd3 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,6 @@ The logs-loving futuristic beaver logo has been contributed by [Russell Keith-Ma ## Project Information -- **License**: *dual* [Apache License, version 2 **and** MIT](https://www.structlog.org/en/latest/license.html) - **Get Help**: please use the *structlog* tag on [*Stack Overflow*](https://stackoverflow.com/questions/tagged/structlog) - [**PyPI**](https://pypi.org/project/structlog/) - [**Source Code**](https://github.com/hynek/structlog) From 262e32e836c5f2cf1c54f7aed55efebdec9e01c6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Jul 2023 08:46:33 +0200 Subject: [PATCH 1040/1520] Limit perms --- .github/workflows/ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 85534654..f9ea4091 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,8 +21,7 @@ env: # N.B. default Python version for setup-python comes from the .python-version # file at the root of the project. -permissions: - contents: read +permissions: {} jobs: build-sdist: From 4494e0b9c96fd2b7ecdd711be15df2e667145913 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Jul 2023 08:50:28 +0200 Subject: [PATCH 1041/1520] Fix typo & rephrase --- docs/recipes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/recipes.md b/docs/recipes.md index c3ddbebc..9df67a96 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -1,7 +1,7 @@ # Recipes -Thanks to the fact that *structlog* is entirely based on dictionaries and callables, the sky is the limit with what you an achieve. -In the beginning that can be daunting, so here are a few examples of tasks that have come up repeatedly. +Because *structlog* is entirely based on dictionaries and callables, the sky is the limit with what you can achieve. +That can be daunting in the beginning, so here are a few examples of tasks that have come up repeatedly. Please note that recipes related to integration with frameworks have an [own chapter](frameworks.md). From ec810c50e124a58ec5ecfc07bd119c7e4c87950f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 10 Jul 2023 08:54:38 +0200 Subject: [PATCH 1042/1520] Fix separator --- docs/recipes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/recipes.md b/docs/recipes.md index 9df67a96..a09f1df8 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -102,7 +102,7 @@ Nowadays, the default is a {class}`structlog.typing.FilteringBoundLogger` that i If you’re integrating with {mod}`logging` or Twisted, you may want to use one of their specific *bound loggers* ({class}`structlog.stdlib.BoundLogger` and {class}`structlog.twisted.BoundLogger`, respectively). -— +--- On top of that all, you can also write your own wrapper classes. To make it easy for you, *structlog* comes with the class {class}`structlog.BoundLoggerBase` which takes care of all data binding duties so you just add your log methods if you choose to sub-class it. From ea950f6638daf332d5bc1c29a25f20e032798351 Mon Sep 17 00:00:00 2001 From: Alex Couper Date: Sat, 22 Jul 2023 10:46:07 +0000 Subject: [PATCH 1043/1520] Allow positional args in `exception` (#531) --- src/structlog/_log_levels.py | 12 ++++++++---- tests/test_log_levels.py | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index d3863a02..8a3a384f 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -80,13 +80,17 @@ async def _anop(self: Any, event: str, *args: Any, **kw: Any) -> Any: return None -def exception(self: FilteringBoundLogger, event: str, **kw: Any) -> Any: +def exception( + self: FilteringBoundLogger, event: str, *args: Any, **kw: Any +) -> Any: kw.setdefault("exc_info", True) - return self.error(event, **kw) + return self.error(event, *args, **kw) -async def aexception(self: FilteringBoundLogger, event: str, **kw: Any) -> Any: +async def aexception( + self: FilteringBoundLogger, event: str, *args: Any, **kw: Any +) -> Any: # Exception info has to be extracted this early, because it is no longer # available once control is passed to the executor. if kw.get("exc_info", True) is True: @@ -95,7 +99,7 @@ async def aexception(self: FilteringBoundLogger, event: str, **kw: Any) -> Any: ctx = contextvars.copy_context() return await asyncio.get_running_loop().run_in_executor( None, - lambda: ctx.run(lambda: self.error(event, **kw)), + lambda: ctx.run(lambda: self.error(event, *args, **kw)), ) diff --git a/tests/test_log_levels.py b/tests/test_log_levels.py index fb4075af..f04e5103 100644 --- a/tests/test_log_levels.py +++ b/tests/test_log_levels.py @@ -195,6 +195,24 @@ async def test_async_exception(self, bl, cl): assert isinstance(cl.calls[0][2]["exc_info"], tuple) assert exc == cl.calls[0][2]["exc_info"][1] + def test_exception_positional_args(self, bl, cl): + """ + exception allows for positional args + """ + bl.exception("%s %s", "boom", "bastic") + + assert [ + ("error", (), {"event": "boom bastic", "exc_info": True}) + ] == cl.calls + + async def test_aexception_positional_args(self, bl, cl): + """ + aexception allows for positional args + """ + await bl.aexception("%s %s", "boom", "bastic") + assert 1 == len(cl.calls) + assert "boom bastic" == cl.calls[0][2]["event"] + async def test_async_exception_true(self, bl, cl): """ aexception replaces exc_info with current exception info, if exc_info From 8a63cbf9d6bbca8e9ace1e2b89f9904d1cabcf8c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 22 Jul 2023 12:49:17 +0200 Subject: [PATCH 1044/1520] Add changelog for #531 --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b5013f8..377cbbd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,13 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ [#515](https://github.com/hynek/structlog/issues/515) +### Fixed + +- `FilteringBoundLogger.exception()` and `FilteringBoundLogger.aexception()` now support positional argument formatting like the rest of the methods. + [#531](https://github.com/hynek/structlog/issues/531) + + + ## [23.1.0](https://github.com/hynek/structlog/compare/22.3.0...23.1.0) - 2023-04-06 ### Added From d7e4c15767b61ac83daefa44e334d4eeb103ba83 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 22 Jul 2023 13:30:38 +0200 Subject: [PATCH 1045/1520] Update ruff & black --- .pre-commit-config.yaml | 4 +- pyproject.toml | 3 +- tests/test_stdlib.py | 22 ++--- tests/test_tracebacks.py | 168 +++++++++++++++++++++++---------------- tests/typing/api.py | 10 ++- 5 files changed, 120 insertions(+), 87 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 83b93f54..f940ce5b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,12 +8,12 @@ default_language_version: repos: - repo: https://github.com/psf/black - rev: 23.3.0 + rev: 23.7.0 hooks: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.0.276 + rev: v0.0.280 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/pyproject.toml b/pyproject.toml index 49f0cc9a..57079cfd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -149,8 +149,7 @@ ignore = [ "PLC1901", # empty strings are falsey, but are less specific in tests "PT005", # we always add underscores and explicit name "RUF012", # no type hints in tests - "S101", # assert - "S301", # I know pickle is bad, but people like it. + "S", # it's test; chill out security "SIM300", # Yoda rocks in tests "TRY", # tests have different rules around exceptions ] diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index f9981b3c..e36cd3b4 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -3,6 +3,8 @@ # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. +from __future__ import annotations + import json import logging import logging.config @@ -10,7 +12,7 @@ import sys from io import StringIO -from typing import Any, Callable, Collection, Dict, Optional, Set +from typing import Any, Callable, Collection import pytest import pytest_asyncio @@ -539,7 +541,7 @@ def test_logger_name_added_with_record(self, make_log_record): assert name == event_dict["logger"] -def extra_dict() -> Dict[str, Any]: +def extra_dict() -> dict[str, Any]: """ A dict to be passed in the `extra` parameter of the `logging` module's log methods. @@ -572,9 +574,9 @@ class TestExtraAdder: def test_add_extra( self, make_log_record: Callable[[], logging.LogRecord], - extra_dict: Dict[str, Any], - allow: Optional[Collection[str]], - misses: Optional[Set[str]], + extra_dict: dict[str, Any], + allow: Collection[str] | None, + misses: set[str] | None, ): """ Extra attributes of a LogRecord object are added to the event dict. @@ -613,9 +615,9 @@ def test_no_record(self): ) def test_add_extra_e2e( self, - extra_dict: Dict[str, Any], - allow: Optional[Collection[str]], - misses: Optional[Set[str]], + extra_dict: dict[str, Any], + allow: Collection[str] | None, + misses: set[str] | None, ): """ Values passed in the `extra` parameter of the `logging` module's log @@ -652,8 +654,8 @@ def test_add_extra_e2e( def _copy_allowed( cls, event_dict: EventDict, - extra_dict: Dict[str, Any], - allow: Optional[Collection[str]], + extra_dict: dict[str, Any], + allow: Collection[str] | None, ) -> EventDict: if allow is None: return {**event_dict, **extra_dict} diff --git a/tests/test_tracebacks.py b/tests/test_tracebacks.py index 3e5f1ef1..e227e265 100644 --- a/tests/test_tracebacks.py +++ b/tests/test_tracebacks.py @@ -1,19 +1,31 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the MIT License. See the LICENSE file in the root of this +# repository for complete details. + +from __future__ import annotations + +import inspect import sys from pathlib import Path -from typing import Any, Optional +from typing import Any import pytest from structlog import tracebacks +def get_next_lineno() -> int: + return inspect.currentframe().f_back.f_lineno + 1 + + @pytest.mark.parametrize(("data", "expected"), [(3, "3"), ("spam", "spam")]) def test_save_str(data: Any, expected: str): """ "safe_str()" returns the str repr of an object. """ - assert tracebacks.safe_str(data) == expected + assert expected == tracebacks.safe_str(data) def test_safe_str_error(): @@ -28,7 +40,7 @@ def __str__(self) -> str: with pytest.raises(ValueError, match="BAAM!"): str(Baam()) - assert tracebacks.safe_str(Baam()) == "" + assert "" == tracebacks.safe_str(Baam()) @pytest.mark.parametrize( @@ -42,8 +54,8 @@ def __str__(self) -> str: ("bacon", 5, "bacon"), ], ) -def test_to_repr(data: Any, max_len: Optional[int], expected: str): - assert tracebacks.to_repr(data, max_string=max_len) == expected +def test_to_repr(data: Any, max_len: int | None, expected: str): + assert expected == tracebacks.to_repr(data, max_string=max_len) def test_to_repr_error(): @@ -58,7 +70,7 @@ def __repr__(self) -> str: with pytest.raises(ValueError, match="BAAM!"): repr(Baam()) - assert tracebacks.to_repr(Baam()) == "" + assert "" == tracebacks.to_repr(Baam()) def test_simple_exception(): @@ -66,11 +78,12 @@ def test_simple_exception(): Tracebacks are parsed for simple, single exceptions. """ try: + lineno = get_next_lineno() 1 / 0 except Exception as e: trace = tracebacks.extract(type(e), e, e.__traceback__) - assert trace.stacks == [ + assert [ tracebacks.Stack( exc_type="ZeroDivisionError", exc_value="division by zero", @@ -79,14 +92,14 @@ def test_simple_exception(): frames=[ tracebacks.Frame( filename=__file__, - lineno=69, + lineno=lineno, name="test_simple_exception", line="", locals=None, ), ], ), - ] + ] == trace.stacks def test_raise_hide_cause(): @@ -98,11 +111,12 @@ def test_raise_hide_cause(): try: 1 / 0 except ArithmeticError: + lineno = get_next_lineno() raise ValueError("onoes") from None except Exception as e: trace = tracebacks.extract(type(e), e, e.__traceback__) - assert trace.stacks == [ + assert [ tracebacks.Stack( exc_type="ValueError", exc_value="onoes", @@ -111,14 +125,14 @@ def test_raise_hide_cause(): frames=[ tracebacks.Frame( filename=__file__, - lineno=101, + lineno=lineno, name="test_raise_hide_cause", line="", locals=None, ), ], ), - ] + ] == trace.stacks def test_raise_with_cause(): @@ -128,13 +142,15 @@ def test_raise_with_cause(): """ try: try: + lineno_1 = get_next_lineno() 1 / 0 except ArithmeticError as orig_exc: + lineno_2 = get_next_lineno() raise ValueError("onoes") from orig_exc except Exception as e: trace = tracebacks.extract(type(e), e, e.__traceback__) - assert trace.stacks == [ + assert [ tracebacks.Stack( exc_type="ValueError", exc_value="onoes", @@ -143,7 +159,7 @@ def test_raise_with_cause(): frames=[ tracebacks.Frame( filename=__file__, - lineno=133, + lineno=lineno_2, name="test_raise_with_cause", line="", locals=None, @@ -158,14 +174,14 @@ def test_raise_with_cause(): frames=[ tracebacks.Frame( filename=__file__, - lineno=131, + lineno=lineno_1, name="test_raise_with_cause", line="", locals=None, ), ], ), - ] + ] == trace.stacks def test_raise_with_cause_no_tb(): @@ -173,11 +189,12 @@ def test_raise_with_cause_no_tb(): If an exception's cause has no traceback, that cause is ignored. """ try: + lineno = get_next_lineno() raise ValueError("onoes") from RuntimeError("I am fake") except Exception as e: trace = tracebacks.extract(type(e), e, e.__traceback__) - assert trace.stacks == [ + assert [ tracebacks.Stack( exc_type="ValueError", exc_value="onoes", @@ -186,14 +203,14 @@ def test_raise_with_cause_no_tb(): frames=[ tracebacks.Frame( filename=__file__, - lineno=176, + lineno=lineno, name="test_raise_with_cause_no_tb", line="", locals=None, ), ], ), - ] + ] == trace.stacks def test_raise_nested(): @@ -203,13 +220,15 @@ def test_raise_nested(): """ try: try: + lineno_1 = get_next_lineno() 1 / 0 except ArithmeticError: + lineno_2 = get_next_lineno() raise ValueError("onoes") # noqa: B904 except Exception as e: trace = tracebacks.extract(type(e), e, e.__traceback__) - assert trace.stacks == [ + assert [ tracebacks.Stack( exc_type="ValueError", exc_value="onoes", @@ -218,7 +237,7 @@ def test_raise_nested(): frames=[ tracebacks.Frame( filename=__file__, - lineno=208, + lineno=lineno_2, name="test_raise_nested", line="", locals=None, @@ -233,14 +252,14 @@ def test_raise_nested(): frames=[ tracebacks.Frame( filename=__file__, - lineno=206, + lineno=lineno_1, name="test_raise_nested", line="", locals=None, ), ], ), - ] + ] == trace.stacks def test_raise_no_msg(): @@ -249,11 +268,12 @@ def test_raise_no_msg(): string. """ try: + lineno = get_next_lineno() raise RuntimeError except Exception as e: trace = tracebacks.extract(type(e), e, e.__traceback__) - assert trace.stacks == [ + assert [ tracebacks.Stack( exc_type="RuntimeError", exc_value="", @@ -262,14 +282,14 @@ def test_raise_no_msg(): frames=[ tracebacks.Frame( filename=__file__, - lineno=252, + lineno=lineno, name="test_raise_no_msg", line="", locals=None, ), ], ), - ] + ] == trace.stacks def test_syntax_error(): @@ -278,11 +298,12 @@ def test_syntax_error(): """ try: # raises SyntaxError: invalid syntax + lineno = get_next_lineno() eval("2 +* 2") # noqa: PGH001 except SyntaxError as e: trace = tracebacks.extract(type(e), e, e.__traceback__) - assert trace.stacks == [ + assert [ tracebacks.Stack( exc_type="SyntaxError", exc_value="invalid syntax (, line 1)", @@ -297,14 +318,14 @@ def test_syntax_error(): frames=[ tracebacks.Frame( filename=__file__, - lineno=281, + lineno=lineno, name="test_syntax_error", line="", locals=None, ), ], ), - ] + ] == trace.stacks def test_filename_with_bracket(): @@ -312,11 +333,12 @@ def test_filename_with_bracket(): Filenames with brackets (e.g., "") are handled properly. """ try: - exec(compile("1/0", filename="", mode="exec")) # noqa: S102 + lineno = get_next_lineno() + exec(compile("1/0", filename="", mode="exec")) except Exception as e: trace = tracebacks.extract(type(e), e, e.__traceback__) - assert trace.stacks == [ + assert [ tracebacks.Stack( exc_type="ZeroDivisionError", exc_value="division by zero", @@ -325,7 +347,7 @@ def test_filename_with_bracket(): frames=[ tracebacks.Frame( filename=__file__, - lineno=315, + lineno=lineno, name="test_filename_with_bracket", line="", locals=None, @@ -339,7 +361,7 @@ def test_filename_with_bracket(): ), ], ), - ] + ] == trace.stacks def test_filename_not_a_file(): @@ -347,11 +369,12 @@ def test_filename_not_a_file(): "Invalid" filenames are appended to CWD as if they were actual files. """ try: - exec(compile("1/0", filename="string", mode="exec")) # noqa: S102 + lineno = get_next_lineno() + exec(compile("1/0", filename="string", mode="exec")) except Exception as e: trace = tracebacks.extract(type(e), e, e.__traceback__) - assert trace.stacks == [ + assert [ tracebacks.Stack( exc_type="ZeroDivisionError", exc_value="division by zero", @@ -360,7 +383,7 @@ def test_filename_not_a_file(): frames=[ tracebacks.Frame( filename=__file__, - lineno=350, + lineno=lineno, name="test_filename_not_a_file", line="", locals=None, @@ -374,7 +397,7 @@ def test_filename_not_a_file(): ), ], ), - ] + ] == trace.stacks def test_show_locals(): @@ -415,6 +438,7 @@ def bar(n): return foo(n) try: + lineno = get_next_lineno() foo(1) except Exception as e: trace = tracebacks.extract(type(e), e, e.__traceback__) @@ -422,7 +446,7 @@ def bar(n): frames = trace.stacks[0].frames trace.stacks[0].frames = [] - assert trace.stacks == [ + assert [ tracebacks.Stack( exc_type="RecursionError", exc_value="maximum recursion depth exceeded", @@ -430,26 +454,29 @@ def bar(n): is_cause=False, frames=[], ), - ] + ] == trace.stacks assert ( len(frames) > sys.getrecursionlimit() - 50 ) # Buffer for frames from pytest - assert frames[0] == tracebacks.Frame( - filename=__file__, - lineno=418, - name="test_recursive", + assert ( + tracebacks.Frame( + filename=__file__, + lineno=lineno, + name="test_recursive", + ) + == frames[0] ) # Depending on whether we invoke pytest directly or run tox, either "foo()" # or "bar()" is at the end of the stack. assert frames[-1] in [ tracebacks.Frame( filename=__file__, - lineno=412, + lineno=lineno - 7, name="foo", ), tracebacks.Frame( filename=__file__, - lineno=415, + lineno=lineno - 4, name="bar", ), ] @@ -457,12 +484,13 @@ def bar(n): def test_json_traceback(): try: + lineno = get_next_lineno() 1 / 0 except Exception as e: format_json = tracebacks.ExceptionDictTransformer(show_locals=False) result = format_json((type(e), e, e.__traceback__)) - assert result == [ + assert [ { "exc_type": "ZeroDivisionError", "exc_value": "division by zero", @@ -470,7 +498,7 @@ def test_json_traceback(): { "filename": __file__, "line": "", - "lineno": 460, + "lineno": lineno, "locals": None, "name": "test_json_traceback", } @@ -478,37 +506,39 @@ def test_json_traceback(): "is_cause": False, "syntax_error": None, }, - ] + ] == result def test_json_traceback_locals_max_string(): try: _var = "spamspamspam" + lineno = get_next_lineno() 1 / 0 except Exception as e: result = tracebacks.ExceptionDictTransformer(locals_max_string=4)( (type(e), e, e.__traceback__) ) - assert result == [ - { - "exc_type": "ZeroDivisionError", - "exc_value": "division by zero", - "frames": [ - { - "filename": __file__, - "line": "", - "lineno": 487, - "locals": { - "_var": "'spam'+8", - "e": "'Zero'+33", - }, - "name": "test_json_traceback_locals_max_string", - } - ], - "is_cause": False, - "syntax_error": None, - }, - ] + assert [ + { + "exc_type": "ZeroDivisionError", + "exc_value": "division by zero", + "frames": [ + { + "filename": __file__, + "line": "", + "lineno": lineno, + "locals": { + "_var": "'spam'+8", + "e": "'Zero'+33", + "ln": str(lineno), + }, + "name": "test_json_traceback_locals_max_string", + } + ], + "is_cause": False, + "syntax_error": None, + }, + ] == result @pytest.mark.parametrize( @@ -567,5 +597,5 @@ def test_json_traceback_value_error(kwargs): Wrong arguments to ExceptionDictTransformer raise a ValueError that contains the name of the argument.. """ - with pytest.raises(ValueError, match=tuple(kwargs.keys())[0]): + with pytest.raises(ValueError, match=next(iter(kwargs.keys()))): tracebacks.ExceptionDictTransformer(**kwargs) diff --git a/tests/typing/api.py b/tests/typing/api.py index 3f4eb66b..719f290c 100644 --- a/tests/typing/api.py +++ b/tests/typing/api.py @@ -7,10 +7,12 @@ Make sure our configuration examples actually pass the type checker. """ +from __future__ import annotations + import logging import logging.config -from typing import Any, Callable, List, Optional +from typing import Any, Callable import structlog @@ -27,8 +29,8 @@ def bytes_dumps( __obj: Any, - default: Optional[Callable[[Any], Any]] = None, - option: Optional[int] = None, + default: Callable[[Any], Any] | None = None, + option: int | None = None, ) -> bytes: """ Test with orjson's signature taken from @@ -114,7 +116,7 @@ def bytes_dumps( timestamper = structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S") -shared_processors: List[structlog.typing.Processor] = [ +shared_processors: list[structlog.typing.Processor] = [ structlog.stdlib.add_log_level, timestamper, ] From c1edd3ef052198e8d9170442eafd6c31dcb04cd4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 22 Jul 2023 16:33:58 +0200 Subject: [PATCH 1046/1520] Fix key --- tests/test_tracebacks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_tracebacks.py b/tests/test_tracebacks.py index e227e265..b8d7e6d4 100644 --- a/tests/test_tracebacks.py +++ b/tests/test_tracebacks.py @@ -530,7 +530,7 @@ def test_json_traceback_locals_max_string(): "locals": { "_var": "'spam'+8", "e": "'Zero'+33", - "ln": str(lineno), + "lineno": str(lineno), }, "name": "test_json_traceback_locals_max_string", } From c0ac5dad9c1137fcc61064c1c6b11d334453a354 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 22 Jul 2023 16:37:02 +0200 Subject: [PATCH 1047/1520] Add MaybeTimeStamper Fixes #81 --- CHANGELOG.md | 2 ++ docs/api.rst | 10 ++++++++++ src/structlog/processors.py | 31 +++++++++++++++++++++++++++++++ tests/test_processors.py | 19 +++++++++++++++++++ 4 files changed, 62 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 377cbbd3..80dfe728 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - Official support for Python 3.12. [#515](https://github.com/hynek/structlog/issues/515) +- `structlog.processors.MaybeTimeStamper` that only adds a timestamp if there isn't one already. + [#81](https://github.com/hynek/structlog/issues/81) ### Fixed diff --git a/docs/api.rst b/docs/api.rst index 9b6670b0..85e25a5e 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -261,6 +261,16 @@ API Reference >>> TimeStamper(fmt="%Y", key="year")(None, None, {}) # doctest: +SKIP {'year': '2013'} +.. autoclass:: MaybeTimeStamper + + .. doctest:: + + >>> from structlog.processors import MaybeTimeStamper + >>> MaybeTimeStamper()(None, None, {}) # doctest: +SKIP + {'timestamp': 1690036074.494428} + >>> MaybeTimeStamper()(None, None, {"timestamp": 42}) + {'timestamp': 42} + .. autoclass:: CallsiteParameter :members: diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 8d8b8161..61b7216a 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -519,6 +519,37 @@ def stamper_fmt(event_dict: EventDict) -> EventDict: return stamper_fmt +class MaybeTimeStamper: + """ + A timestamper that only adds a timestamp if there is none. + + This allows you to overwrite the ``timestamp`` key in the event dict for + example when the event is coming from another system. + + It takes the same arguments as `TimeStamper`. + + .. versionadded:: 23.2.0 + """ + + __slots__ = ("stamper",) + + def __init__( + self, + fmt: str | None = None, + utc: bool = True, + key: str = "timestamp", + ): + self.stamper = TimeStamper(fmt=fmt, utc=utc, key=key) + + def __call__( + self, logger: WrappedLogger, name: str, event_dict: EventDict + ) -> EventDict: + if "timestamp" not in event_dict: + return self.stamper(logger, name, event_dict) + + return event_dict + + def _figure_out_exc_info(v: Any) -> ExcInfo: """ Depending on the Python version will try to do the smartest thing possible diff --git a/tests/test_processors.py b/tests/test_processors.py index 9d7482c6..122e6d4d 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -35,6 +35,7 @@ JSONRenderer, KeyValueRenderer, LogfmtRenderer, + MaybeTimeStamper, StackInfoRenderer, TimeStamper, UnicodeDecoder, @@ -452,6 +453,24 @@ def test_apply_freezegun_after_instantiation(self): assert "1980-03-25T17:00:00" == d["timestamp"] +class TestMaybeTimeStamper: + def test_overwrite(self): + """ + If there is a timestamp, leave it. + """ + mts = MaybeTimeStamper() + + assert {"timestamp": 42} == mts(None, None, {"timestamp": 42}) + + def test_none(self): + """ + If there is no timestamp, add one. + """ + mts = MaybeTimeStamper() + + assert "timestamp" in mts(None, None, {}) + + class TestFormatExcInfo: def test_custom_formatter(self): """ From 549c414acc3abed7856347a48bfc827d9e900399 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 22 Jul 2023 17:55:00 +0200 Subject: [PATCH 1048/1520] Test against wheel (#534) * Test against wheel * Don't build twice * Remove vars --- .github/workflows/ci.yml | 84 ++++++++++++------------------ .github/workflows/pypi-package.yml | 3 -- 2 files changed, 32 insertions(+), 55 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f9ea4091..15d9facd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,43 +13,26 @@ env: PIP_DISABLE_PIP_VERSION_CHECK: "1" PIP_NO_PYTHON_VERSION_WARNING: "1" - # For re-actors/checkout-python-sdist - SETUPTOOLS_SCM_PRETEND_VERSION: "1.0" # hard-code version for predictable sdist names - sdist-artifact: python-package-distributions - sdist-name: structlog-1.0.tar.gz - # N.B. default Python version for setup-python comes from the .python-version # file at the root of the project. permissions: {} jobs: - build-sdist: - name: 📦 Build the source distribution + build-package: + name: Build & verify package runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 with: - cache: pip - - run: python -Im pip install build + fetch-depth: 0 - - run: python -Im build --sdist - - - uses: actions/upload-artifact@v3 - with: - name: ${{ env.sdist-artifact }} - # NOTE: Exact expected file names are specified here - # NOTE: as a safety measure — if anything weird ends - # NOTE: up being in this dir or not all dists will be - # NOTE: produced, this will fail the workflow. - path: dist/${{ env.sdist-name }} - retention-days: 15 + - uses: hynek/build-and-inspect-python-package@v1 tests: name: Tests & API Mypy on ${{ matrix.python-version }} - needs: build-sdist + needs: build-package runs-on: ubuntu-latest strategy: fail-fast: false @@ -62,11 +45,12 @@ jobs: - "3.12" steps: - - name: Get source code from pre-built sdist - uses: re-actors/checkout-python-sdist@release/v1 + - name: Download pre-built packages + uses: actions/download-artifact@v3 with: - source-tarball-name: ${{ env.sdist-name }} - workflow-artifact-name: ${{ env.sdist-artifact }} + name: Packages + path: dist + - run: tar xf dist/*.tar.gz --strip-components=1 # needed for config files - uses: actions/setup-python@v4 with: @@ -75,8 +59,8 @@ jobs: cache: pip - run: python -Im pip install tox - - run: python -Im tox run -f py$(echo ${{ matrix.python-version }} | tr -d .) - - run: python -Im tox run -e mypy-api + - run: python -Im tox run --installpkg dist/*.whl -f py$(echo ${{ matrix.python-version }} | tr -d .) + - run: python -Im tox run --installpkg dist/*.whl -e mypy-api - name: Upload coverage data uses: actions/upload-artifact@v3 @@ -91,12 +75,7 @@ jobs: runs-on: ubuntu-latest steps: - - name: Get source code from pre-built sdist - uses: re-actors/checkout-python-sdist@release/v1 - with: - source-tarball-name: ${{ env.sdist-name }} - workflow-artifact-name: ${{ env.sdist-artifact }} - + - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: cache: pip @@ -125,17 +104,19 @@ jobs: path: htmlcov if: ${{ failure() }} - mypy: + mypy-pkg: name: Type-check package - needs: build-sdist + needs: build-package runs-on: ubuntu-latest steps: - - name: Get source code from pre-built sdist - uses: re-actors/checkout-python-sdist@release/v1 + - name: Download pre-built packages + uses: actions/download-artifact@v3 with: - source-tarball-name: ${{ env.sdist-name }} - workflow-artifact-name: ${{ env.sdist-artifact }} + name: Packages + path: dist + - run: tar xf dist/*.tar.gz --strip-components=1 # needed for config files + - uses: actions/setup-python@v4 with: allow-prereleases: true @@ -144,18 +125,20 @@ jobs: - name: Prepare & run tox run: | python -Im pip install tox - python -Im tox run -e mypy-pkg + python -Im tox run --installpkg dist/*.whl -e mypy-pkg docs: name: Build docs & run doctests - needs: build-sdist + needs: build-package runs-on: ubuntu-latest steps: - - name: Get source code from pre-built sdist - uses: re-actors/checkout-python-sdist@release/v1 + - name: Download pre-built packages + uses: actions/download-artifact@v3 with: - source-tarball-name: ${{ env.sdist-name }} - workflow-artifact-name: ${{ env.sdist-artifact }} + name: Packages + path: dist + - run: tar xf dist/*.tar.gz --strip-components=1 # needed for config files + - uses: actions/setup-python@v4 with: # Keep in sync with tox.ini/docs & .readthedocs.yaml @@ -189,6 +172,7 @@ jobs: - coverage - docs - install-dev + - mypy-pkg runs-on: ubuntu-latest @@ -201,15 +185,11 @@ jobs: colors: name: Visual check for color settings using env variables - needs: build-sdist + needs: build-package runs-on: ubuntu-latest steps: - - name: Get source code from pre-built sdist - uses: re-actors/checkout-python-sdist@release/v1 - with: - source-tarball-name: ${{ env.sdist-name }} - workflow-artifact-name: ${{ env.sdist-artifact }} + - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: cache: pip diff --git a/.github/workflows/pypi-package.yml b/.github/workflows/pypi-package.yml index cdd26b99..de146827 100644 --- a/.github/workflows/pypi-package.yml +++ b/.github/workflows/pypi-package.yml @@ -5,8 +5,6 @@ on: push: branches: [main] tags: ["*"] - pull_request: - branches: [main] release: types: - published @@ -17,7 +15,6 @@ permissions: id-token: write jobs: - # Always build & lint package. build-package: name: Build & verify package runs-on: ubuntu-latest From 7c8366e71d5b18cd036c02644bee63a16faf6e2d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 23 Jul 2023 11:02:20 +0200 Subject: [PATCH 1049/1520] Use more standard way to get version --- src/structlog/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 5df641b3..49d55712 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -94,13 +94,13 @@ def __getattr__(name: str) -> str: import warnings - from importlib.metadata import metadata + from importlib.metadata import metadata, version dunder_to_metadata = { - "__version__": "version", "__description__": "summary", "__uri__": "", "__email__": "", + "__version__": "", } if name not in dunder_to_metadata.keys(): msg = f"module {__name__} has no attribute {name}" @@ -114,6 +114,8 @@ def __getattr__(name: str) -> str: DeprecationWarning, stacklevel=2, ) + else: + return version("structlog") meta = metadata("structlog") From 53388862c295feedb9ddf366af6d1b652b77d54d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 29 Jul 2023 16:53:41 +0200 Subject: [PATCH 1050/1520] Don't crash in exception() if outside of an exception (#533) --- CHANGELOG.md | 3 ++- src/structlog/_frames.py | 3 +++ src/structlog/dev.py | 3 ++- tests/test_dev.py | 13 +++++++++++++ tests/test_processors.py | 12 +++++++++++- 5 files changed, 31 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80dfe728..ae8d7ff0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,7 +32,8 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - `FilteringBoundLogger.exception()` and `FilteringBoundLogger.aexception()` now support positional argument formatting like the rest of the methods. [#531](https://github.com/hynek/structlog/issues/531) - +- `structlog.processors.format_exc_info()` and `structlog.dev.ConsoleRenderer` do not crash anymore when told to format a non-existent exception. + [#533](https://github.com/hynek/structlog/issues/533) ## [23.1.0](https://github.com/hynek/structlog/compare/22.3.0...23.1.0) - 2023-04-06 diff --git a/src/structlog/_frames.py b/src/structlog/_frames.py index 6982463d..7db6a486 100644 --- a/src/structlog/_frames.py +++ b/src/structlog/_frames.py @@ -20,6 +20,9 @@ def _format_exception(exc_info: ExcInfo) -> str: Shamelessly stolen from stdlib's logging module. """ + if exc_info == (None, None, None): # type: ignore[comparison-overlap] + return "MISSING" + sio = StringIO() traceback.print_exception(exc_info[0], exc_info[1], exc_info[2], None, sio) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 8e9ecee7..603dde2d 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -412,7 +412,8 @@ def __call__( # noqa: PLR0912 if exc_info: exc_info = _figure_out_exc_info(exc_info) - self._exception_formatter(sio, exc_info) + if exc_info != (None, None, None): + self._exception_formatter(sio, exc_info) elif exc is not None: if self._exception_formatter is not plain_traceback: warnings.warn( diff --git a/tests/test_dev.py b/tests/test_dev.py index dfbed0cb..b99966c3 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -510,6 +510,19 @@ def test_pickle(self, repr_native_str, force_colors, proto): pickle.dumps(r, proto) )(None, None, {"event": "foo"}) + def test_no_exception(self): + """ + If there is no exception, don't blow up. + """ + r = dev.ConsoleRenderer(colors=False) + + assert ( + "hi" + == r( + None, None, {"event": "hi", "exc_info": (None, None, None)} + ).rstrip() + ) + class TestSetExcInfo: def test_wrong_name(self): diff --git a/tests/test_processors.py b/tests/test_processors.py index 122e6d4d..59d5657c 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -560,7 +560,17 @@ def test_format_exception(self): except ValueError as e: a = format_exc_info(None, None, {"exc_info": e}) b = ExceptionRenderer()(None, None, {"exc_info": e}) - assert a == b + + assert a == b + + @pytest.mark.parametrize("ei", [True, (None, None, None)]) + def test_no_exception(self, ei): + """ + A missing exception does not blow up. + """ + assert {"exception": "MISSING"} == format_exc_info( + None, None, {"exc_info": ei} + ) class TestUnicodeEncoder: From 334125e45e1fa96aeafc8a4e33d39132319e042c Mon Sep 17 00:00:00 2001 From: Jeremy Mayeres <1524722+jerr0328@users.noreply.github.com> Date: Tue, 1 Aug 2023 12:29:37 +0300 Subject: [PATCH 1051/1520] Update JSONRenderer docs (#535) I noticed *json_kw* was referred to in docs but the the actual parameter is called *dumps_kw*. While fixing that I also wanted to add a little bit of info I had to figure out on my own, which was that if you want `orjson` to handle serialization of dataclasses, datetimes, etc. natively, you need to pass a `default` (I used the `singledispatch` to use `str` by default and handle Pydantic objects and sets to work better with our logging systems) --- docs/api.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/api.rst b/docs/api.rst index 85e25a5e..e433715f 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -167,8 +167,9 @@ API Reference Please note that additionally to strings, you can also return any type the standard library JSON module knows about -- like in this example a list. - If you choose to pass a *default* parameter as part of *json_kw*, support for ``__structlog__`` is disabled. + If you choose to pass a *default* parameter as part of *dumps_kw*, support for ``__structlog__`` is disabled. This can be useful when used together with more elegant serialization methods like :func:`functools.singledispatch`: `Better Python Object Serialization `_. + Using a `default` to disable the ``__structlog__`` serialization is also useful if you are using ``orjson`` and want to rely on it to serialize ``datetime`` and other objects natively. .. tip:: From b26c1bd1668d14ea1a4c291573d6613221ea4ea8 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 1 Aug 2023 11:44:33 +0200 Subject: [PATCH 1052/1520] Rename docs-serve to docs-watch We're not serving anything. --- .github/CONTRIBUTING.md | 4 ++-- tox.ini | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 1b4a15df..99d2db64 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -86,10 +86,10 @@ $ python -m pytest When working on the documentation, use: ```bash -$ tox -e docs-serve +$ tox -e docs-watch ``` -... to watch your files and repeatedly build. +... to watch your files and automatically rebuild when a file changes. And use: ```bash diff --git a/tox.ini b/tox.ini index dec60dd3..d6069a0e 100644 --- a/tox.ini +++ b/tox.ini @@ -49,7 +49,7 @@ commands = sphinx-build -n -T -W -b html -d {envtmpdir}/doctrees docs docs/_build/html sphinx-build -n -T -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html -[testenv:docs-serve] +[testenv:docs-watch] package = editable base_python = {[testenv:docs]base_python} extras = {[testenv:docs]extras} From 2941bfd1dfa430abfc364151cf5ad1605e8f81a4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 1 Aug 2023 11:58:27 +0200 Subject: [PATCH 1053/1520] Rephrase --- docs/api.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index e433715f..5286276d 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -168,8 +168,8 @@ API Reference Please note that additionally to strings, you can also return any type the standard library JSON module knows about -- like in this example a list. If you choose to pass a *default* parameter as part of *dumps_kw*, support for ``__structlog__`` is disabled. - This can be useful when used together with more elegant serialization methods like :func:`functools.singledispatch`: `Better Python Object Serialization `_. - Using a `default` to disable the ``__structlog__`` serialization is also useful if you are using ``orjson`` and want to rely on it to serialize ``datetime`` and other objects natively. + That can be useful with more elegant serialization methods like `functools.singledispatch`: `Better Python Object Serialization `_. + It can also be helpful if you are using *orjson* and want to rely on it to serialize `datetime.datetime` and other objects natively. .. tip:: From 6056aad1516346470a9c1485822daf531e30a1ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0ediv=C3=BD?= <6774676+eumiro@users.noreply.github.com> Date: Wed, 2 Aug 2023 20:04:31 +0000 Subject: [PATCH 1054/1520] Fix typos (#538) --- .github/CONTRIBUTING.md | 2 +- docs/getting-started.md | 2 +- src/structlog/twisted.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 99d2db64..c5ea7086 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -152,7 +152,7 @@ But it's way more comfortable to run it locally and catch avoidable errors befor - To run the test suite, all you need is a recent [*tox*]. It will ensure the test suite runs with all dependencies against all Python versions just as it will in our [CI]. - If you lack some Python versions, you can can always limit the environments like `tox -e py38,py39`, or make it a non-failure using `tox --skip-missing-interpreters`. + If you lack some Python versions, you can always limit the environments like `tox -e py38,py39`, or make it a non-failure using `tox --skip-missing-interpreters`. In that case you should look into [*asdf*](https://asdf-vm.com) or [*pyenv*](https://github.com/pyenv/pyenv), which make it very easy to install many different Python versions in parallel. - Write [good test docstrings](https://jml.io/pages/test-docstrings.html). diff --git a/docs/getting-started.md b/docs/getting-started.md index 7f770a99..6de4b157 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -30,7 +30,7 @@ As a result, the simplest possible usage looks like this: Here, *structlog* takes advantage of its default settings: -- Output is sent to **[standard out](https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29)** instead doing nothing. +- Output is sent to **[standard out](https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29)** instead of doing nothing. - It **imitates** standard library {mod}`logging`'s **log level names** for familiarity. By default, no level-based filtering is done, but it comes with a **very fast [filtering machinery](filtering)**. - Like in `logging`, positional arguments are [**interpolated into the message string using %**](https://docs.python.org/3/library/stdtypes.html#old-string-formatting). diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index 3ac75953..e1ea2bef 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -199,7 +199,7 @@ def __call__( # type: ignore[override] @implementer(ILogObserver) class PlainFileLogObserver: """ - Write only the the plain message without timestamps or anything else. + Write only the plain message without timestamps or anything else. Great to just print JSON to stdout where you catch it with something like runit. From e87e021c0311808794e05aa8964360d4d53b4042 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 8 Aug 2023 05:49:11 +0200 Subject: [PATCH 1055/1520] Update linters --- .pre-commit-config.yaml | 2 +- src/structlog/__init__.py | 2 +- src/structlog/_utils.py | 2 +- src/structlog/contextvars.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f940ce5b..44472bcf 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,7 +13,7 @@ repos: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.0.280 + rev: v0.0.282 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 49d55712..2ffe2c86 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -102,7 +102,7 @@ def __getattr__(name: str) -> str: "__email__": "", "__version__": "", } - if name not in dunder_to_metadata.keys(): + if name not in dunder_to_metadata: msg = f"module {__name__} has no attribute {name}" raise AttributeError(msg) diff --git a/src/structlog/_utils.py b/src/structlog/_utils.py index 0fa9769c..28004e15 100644 --- a/src/structlog/_utils.py +++ b/src/structlog/_utils.py @@ -27,7 +27,7 @@ def until_not_interrupted(f: Callable[..., Any], *args: Any, **kw: Any) -> Any: while True: try: return f(*args, **kw) - except OSError as e: # noqa[PERF203] + except OSError as e: # noqa: PERF203 if e.args[0] == errno.EINTR: continue raise diff --git a/src/structlog/contextvars.py b/src/structlog/contextvars.py index 42373f5a..ebb5941d 100644 --- a/src/structlog/contextvars.py +++ b/src/structlog/contextvars.py @@ -122,7 +122,7 @@ def bind_contextvars(**kw: Any) -> Mapping[str, contextvars.Token[Any]]: structlog_k = f"{STRUCTLOG_KEY_PREFIX}{k}" try: var = _CONTEXT_VARS[structlog_k] - except KeyError: # noqa[PERF203] + except KeyError: var = contextvars.ContextVar(structlog_k, default=Ellipsis) _CONTEXT_VARS[structlog_k] = var From 84ec0a9c8ac975f9b1c9d3dee94b448fe85bbc4e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 9 Aug 2023 07:24:13 +0200 Subject: [PATCH 1056/1520] Update Ruff --- .pre-commit-config.yaml | 2 +- src/structlog/_base.py | 6 +++--- src/structlog/_config.py | 10 +++++----- src/structlog/threadlocal.py | 4 ++-- src/structlog/twisted.py | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 44472bcf..758bf199 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,7 +13,7 @@ repos: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.0.282 + rev: v0.0.283 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/src/structlog/_base.py b/src/structlog/_base.py index 56abacbd..6822c505 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -55,13 +55,13 @@ def __repr__(self) -> str: self.__class__.__name__, self._context, self._processors ) - def __eq__(self, other: Any) -> bool: + def __eq__(self, other: object) -> bool: try: - return self._context == other._context + return self._context == other._context # type: ignore[attr-defined] except AttributeError: return False - def __ne__(self, other: Any) -> bool: + def __ne__(self, other: object) -> bool: return not self.__eq__(other) def bind(self, **new_values: Any) -> BoundLoggerBase: diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 9d8a7442..05de0ca5 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -317,11 +317,11 @@ def __init__( def __repr__(self) -> str: return ( - "".format(self) + f"" ) def bind(self, **new_values: Any) -> BindableLogger: diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index 05afdd1d..62dc83a6 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -193,11 +193,11 @@ def _dict(self) -> Context: def __repr__(self) -> str: return f"<{self.__class__.__name__}({self._dict!r})>" - def __eq__(self, other: Any) -> bool: + def __eq__(self, other: object) -> bool: # Same class == same dictionary return self.__class__ == other.__class__ - def __ne__(self, other: Any) -> bool: + def __ne__(self, other: object) -> bool: return not self.__eq__(other) # Proxy methods necessary for structlog. diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index e1ea2bef..84239d1c 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -136,7 +136,7 @@ class ReprWrapper: def __init__(self, string: str) -> None: self.string = string - def __eq__(self, other: Any) -> bool: + def __eq__(self, other: object) -> bool: """ Check for equality, just for tests. """ From ebb3765cd8b3c2e792429b05772cc0222b965ab9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 5 Sep 2023 07:13:40 +0200 Subject: [PATCH 1057/1520] [pre-commit.ci] pre-commit autoupdate (#547) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.0.283 → v0.0.287](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.283...v0.0.287) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 758bf199..cf16cd98 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,7 +13,7 @@ repos: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.0.283 + rev: v0.0.287 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From 158e77c3f98867b34f8281906830b6be7f1769f0 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 5 Sep 2023 07:57:28 +0200 Subject: [PATCH 1058/1520] docs: fix version finding --- .github/PULL_REQUEST_TEMPLATE.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index f58dcfb0..381af11b 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -19,7 +19,8 @@ If an item doesn't apply to your pull request, **check it anyway** to make it ap - [ ] Updated **documentation** for changed code. - [ ] New functions/classes have to be added to `docs/api.rst` by hand. - [ ] Changed/added classes/methods/functions have appropriate `versionadded`, `versionchanged`, or `deprecated` [directives](http://www.sphinx-doc.org/en/stable/markup/para.html#directive-versionadded). - Find the appropriate next version in our [`__init__.py`](https://github.com/hynek/structlog/blob/main/src/structlog/__init__.py) file. + + The next version is the second number in the current release + 1. The first number represents the current year. So if the current version on PyPI is 23.1.0, the next version is gonna be 23.2.0. If the next version is the first in the new year, it'll be 24.1.0. - [ ] Documentation in `.rst` and `.md` files is written using [**semantic newlines**](https://rhodesmill.org/brandon/2012/one-sentence-per-line/). - [ ] Changes (and possible deprecations) are documented in the [**changelog**](https://github.com/hynek/structlog/blob/main/CHANGELOG.md). - [ ] Consider granting [push permissions to the PR branch](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork), so maintainers can fix minor issues themselves without pestering you. From 15d318fe17125f438ff339c539bebbe9470a39d4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 6 Sep 2023 13:18:37 +0200 Subject: [PATCH 1059/1520] Add Better Stack tutorial to docs --- README.md | 2 ++ docs/getting-started.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/README.md b/README.md index 94c8fbd3..838cc7d9 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,8 @@ Once you feel inspired to try it out, check out our friendly [Getting Started tu If you prefer videos over reading, check out [Markus Holtermann](https://twitter.com/m_holtermann)'s DjangoCon Europe 2019 talk: [*Logging Rethought 2: The Actions of Frank Taylor Jr.*](https://www.youtube.com/watch?v=Y5eyEgyHLLo) +For a fully-fledged zero-to-hero tutorial, check out [*A Comprehensive Guide to Python Logging with structlog*](https://betterstack.com/community/guides/logging/structlog/). + ## Credits diff --git a/docs/getting-started.md b/docs/getting-started.md index 6de4b157..a66355ca 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -246,6 +246,8 @@ You can use the sync and async logging methods interchangeably within the same a Now you're all set for the rest of the user's guide and can start reading about [bound loggers](bound-loggers.md) -- the heart of *structlog*. +Or, if you prefer another, more in-depth tutorial, check out [*A Comprehensive Guide to Python Logging with structlog*](https://betterstack.com/community/guides/logging/structlog/). + [*better-exceptions*]: https://github.com/qix-/better-exceptions [recipe]: https://docs.python.org/3/howto/logging-cookbook.html#implementing-structured-logging From 50c75ad41e58eb981477569f638d9e17e057eebe Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 7 Sep 2023 07:36:03 +0200 Subject: [PATCH 1060/1520] Reshuffle CI (#548) * Run Mypy against all versions locally, too * CodeQL is slow and pointless Run it only on cron. * Be kind to pyenv users --- .github/CONTRIBUTING.md | 12 +++++------ .github/workflows/ci.yml | 8 ++++---- .github/workflows/codeql-analysis.yml | 6 +----- .python-version => .python-version-default | 0 pyproject.toml | 1 - tox.ini | 24 +++++++++++----------- 6 files changed, 23 insertions(+), 28 deletions(-) rename .python-version => .python-version-default (100%) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index c5ea7086..384a1454 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -43,12 +43,12 @@ You can (and should) run our test suite using [*tox*]. However, you’ll probably want a more traditional environment as well. First, create a [virtual environment](https://virtualenv.pypa.io/) so you don't break your system-wide Python installation. -We recommend using the Python version from the `.python-version` file in project's root directory. +We recommend using the Python version from the `.python-version-default` file in project's root directory. If you're using [*direnv*](https://direnv.net), you can automate the creation of a virtual environment with the correct Python version by adding the following `.envrc` to the project root: ```bash -layout python python$(cat .python-version) +layout python python$(cat .python-version-default) ``` [Create a fork](https://github.com/hynek/structlog/fork) of the *structlog* repository and clone it: @@ -86,14 +86,14 @@ $ python -m pytest When working on the documentation, use: ```bash -$ tox -e docs-watch +$ tox run -e docs-watch ``` ... to watch your files and automatically rebuild when a file changes. And use: ```bash -$ tox -e docs +$ tox run -e docs ``` ... to build it once and run our doctests. @@ -163,7 +163,7 @@ But it's way more comfortable to run it locally and catch avoidable errors befor - We use [Markdown] everywhere except in `docs/api.rst` and docstrings. -- Use [semantic newlines] in [*reStructuredText*] and [Markdown] files (files ending in `.rst` and `.md`): +- Use [semantic newlines] in [reStructuredText] and [Markdown] files (files ending in `.rst` and `.md`): ```markdown This is a sentence. @@ -229,5 +229,5 @@ or: [*pre-commit*]: https://pre-commit.com/ [*tox*]: https://tox.wiki/ [semantic newlines]: https://rhodesmill.org/brandon/2012/one-sentence-per-line/ -[*reStructuredText*]: https://www.sphinx-doc.org/en/stable/usage/restructuredtext/basics.html +[reStructuredText]: https://www.sphinx-doc.org/en/stable/usage/restructuredtext/basics.html [Markdown]: https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 15d9facd..df24ee74 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,9 +13,6 @@ env: PIP_DISABLE_PIP_VERSION_CHECK: "1" PIP_NO_PYTHON_VERSION_WARNING: "1" - # N.B. default Python version for setup-python comes from the .python-version - # file at the root of the project. - permissions: {} jobs: @@ -60,7 +57,6 @@ jobs: - run: python -Im pip install tox - run: python -Im tox run --installpkg dist/*.whl -f py$(echo ${{ matrix.python-version }} | tr -d .) - - run: python -Im tox run --installpkg dist/*.whl -e mypy-api - name: Upload coverage data uses: actions/upload-artifact@v3 @@ -78,6 +74,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: + python-version-file: .python-version-default cache: pip - run: python -Im pip install --upgrade coverage[toml] @@ -119,6 +116,7 @@ jobs: - uses: actions/setup-python@v4 with: + python-version-file: .python-version-default allow-prereleases: true cache: pip @@ -159,6 +157,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: + python-version-file: .python-version-default cache: pip - run: python -Im pip install -e .[dev] @@ -192,6 +191,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: + python-version-file: .python-version-default cache: pip - run: python -Im pip install tox diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index ca6d0d3c..a5d32ce9 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,11 +1,7 @@ --- -name: "CodeQL" +name: CodeQL on: - push: - branches: [main] - pull_request: - branches: [main] schedule: - cron: "41 3 * * 6" diff --git a/.python-version b/.python-version-default similarity index 100% rename from .python-version rename to .python-version-default diff --git a/pyproject.toml b/pyproject.toml index 57079cfd..e8f85af7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,7 +40,6 @@ Tidelift = "https://tidelift.com/subscription/pkg/pypi-structlog?utm_source=pypi [project.optional-dependencies] tests = [ - "coverage[toml]", "freezegun>=0.2.8", "pretend", "pytest-asyncio>=0.17", diff --git a/tox.ini b/tox.ini index d6069a0e..18d6a5cb 100644 --- a/tox.ini +++ b/tox.ini @@ -2,9 +2,9 @@ min_version = 4 env_list = pre-commit, - mypy-{api,pkg}, - py3{8,9,10,11,12} - py3{8,11}-{colorama,be,rich}, + mypy-pkg, + py3{8,9,10,11,12}-{tests,mypy} + py3{8,11}-tests-{colorama,be,rich}, docs, coverage-report @@ -12,16 +12,21 @@ env_list = [testenv] package = wheel wheel_build_env = .pkg -extras = tests +extras = + tests: tests + mypy: typing pass_env = FORCE_COLOR NO_COLOR -commands = pytest {posargs} +commands = + tests: pytest {posargs} + mypy: mypy tests/typing # Run oldest and latest under Coverage. -[testenv:py3{8,11}{,-colorama,-be,-rich}] +[testenv:py3{8,11}-tests{,-colorama,-be,-rich}] deps = + coverage[toml] py311: twisted colorama: colorama rich: rich @@ -35,7 +40,7 @@ base_python = py311 deps = coverage[toml] skip_install = true parallel_show_output = true -depends = py3{8,11}{,-colorama,-be,-rich} +depends = py3{8,11}-{tests,colorama,be,rich} commands = coverage combine coverage report @@ -74,11 +79,6 @@ deps = pre-commit commands = pre-commit run --all-files -[testenv:mypy-api] -extras = typing -commands = mypy tests/typing - - [testenv:mypy-pkg] extras = typing commands = mypy src From f42a1737fda6b256dce8e7b309275700f5c55e6c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 7 Sep 2023 07:46:37 +0200 Subject: [PATCH 1061/1520] Calm down typography --- CHANGELOG.md | 14 +++++++------- docs/console-output.md | 12 ++++++------ docs/getting-started.md | 10 +++++----- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae8d7ff0..091cf927 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -263,8 +263,8 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - `structlog.contextvars.bind_contextvars()` now returns a mapping of keys to `contextvars.Token`s, allowing you to reset values using the new `structlog.contextvars.reset_contextvars()`. [#339](https://github.com/hynek/structlog/pull/339) - Exception rendering in `structlog.dev.ConsoleLogger` is now configurable using the `exception_formatter` setting. - If either the [*Rich*](https://github.com/Textualize/rich) or the [*better-exceptions*](https://github.com/qix-/better-exceptions) package is present, *structlog* will use them for pretty-printing tracebacks. - *Rich* takes precedence over *better-exceptions* if both are present. + If either the [Rich](https://github.com/Textualize/rich) or the [*better-exceptions*](https://github.com/qix-/better-exceptions) package is present, *structlog* will use them for pretty-printing tracebacks. + Rich takes precedence over *better-exceptions* if both are present. This only works if `format_exc_info` is **absent** in the processor chain. [#330](https://github.com/hynek/structlog/pull/330), @@ -280,9 +280,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ Make sure to remove `format_exc_info` from your processor chain if you configure *structlog* manually. This change is not really breaking, because the old use-case will keep working as before. However if you pass `pretty_exceptions=True` (which is the default if either `rich` or `better-exceptions` is installed), a warning will be raised and the exception will be rendered without prettification. -- All use of [*Colorama*](https://github.com/tartley/colorama) on non-Windows systems has been excised. +- All use of [Colorama](https://github.com/tartley/colorama) on non-Windows systems has been excised. Thus, colors are now enabled by default in `structlog.dev.ConsoleRenderer` on non-Windows systems. - You can keep using *Colorama* to customize colors, of course. + You can keep using Colorama to customize colors, of course. [#345](https://github.com/hynek/structlog/pull/345) @@ -391,7 +391,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - The logger created by `structlog.get_logger()` is not detected as an abstract method anymore, when attached to an abstract base class. [#229](https://github.com/hynek/structlog/issues/229) -- *Colorama* isn't initialized lazily on Windows anymore because it breaks rendering. +- Colorama isn't initialized lazily on Windows anymore because it breaks rendering. [#232](https://github.com/hynek/structlog/issues/232), [#242](https://github.com/hynek/structlog/pull/242) @@ -436,9 +436,9 @@ It has been unsupported by the Python core team for a while now and its PyPI dow ### Fixed -- `structlog.dev.ConsoleRenderer` now uses no colors by default, if *Colorama* is not available. +- `structlog.dev.ConsoleRenderer` now uses no colors by default, if Colorama is not available. [#215](https://github.com/hynek/structlog/issues/215) -- `structlog.dev.ConsoleRenderer` now initializes *Colorama* lazily, to prevent accidental side-effects just by importing *structlog*. +- `structlog.dev.ConsoleRenderer` now initializes Colorama lazily, to prevent accidental side-effects just by importing *structlog*. [#210](https://github.com/hynek/structlog/issues/210) - A best effort has been made to make as much of *structlog* pickleable as possible to make it friendlier with `multiprocessing` and similar libraries. Some classes can only be pickled on Python 3 or using the [dill](https://pypi.org/project/dill/) library though and that is very unlikely to change. diff --git a/docs/console-output.md b/docs/console-output.md index fe3905dd..53ac6748 100644 --- a/docs/console-output.md +++ b/docs/console-output.md @@ -4,12 +4,12 @@ To make development a more pleasurable experience, *structlog* comes with the {m The highlight is {class}`structlog.dev.ConsoleRenderer` that offers nicely aligned and colorful[^win] console output. -[^win]: Requires the [*Colorama* package](https://pypi.org/project/colorama/) on Windows. +[^win]: Requires the [Colorama package](https://pypi.org/project/colorama/) on Windows. -If either of the [*Rich*](https://rich.readthedocs.io/) or [*better-exceptions*](https://github.com/Qix-/better-exceptions) packages is installed, it will also pretty-print exceptions with helpful contextual data. -*Rich* takes precedence over *better-exceptions*, but you can configure it by passing {func}`structlog.dev.plain_traceback` or {func}`structlog.dev.better_traceback` for the `exception_formatter` parameter of {class}`~structlog.dev.ConsoleRenderer`. +If either of the [Rich](https://rich.readthedocs.io/) or [*better-exceptions*](https://github.com/Qix-/better-exceptions) packages is installed, it will also pretty-print exceptions with helpful contextual data. +Rich takes precedence over *better-exceptions*, but you can configure it by passing {func}`structlog.dev.plain_traceback` or {func}`structlog.dev.better_traceback` for the `exception_formatter` parameter of {class}`~structlog.dev.ConsoleRenderer`. -The following output is rendered using *Rich*: +The following output is rendered using Rich: ```{figure} _static/console_renderer.png Colorful console output by ConsoleRenderer. @@ -24,7 +24,7 @@ It will recognize logger names, log levels, time stamps, stack infos, and `exc_i For pretty exceptions to work, {func}`~structlog.processors.format_exc_info` must be **absent** from the processors chain. ::: -*structlog*'s default configuration already uses {class}`~structlog.dev.ConsoleRenderer`, therefore if you want nice colorful output on the console, you don't have to do anything except installing *Rich* or *better-exceptions* (and *Colorama* on Windows). +*structlog*'s default configuration already uses {class}`~structlog.dev.ConsoleRenderer`, therefore if you want nice colorful output on the console, you don't have to do anything except installing Rich or *better-exceptions* (and Colorama on Windows). If you want to use it along with standard library logging, we suggest the following configuration: ```python @@ -60,4 +60,4 @@ It's possible to override this behavior by setting two standard environment vari ## Disabling Exception Pretty-Printing -If you prefer the default terse Exception rendering, but still want *Rich* installed, you can disable the pretty-printing by instantiating {class}`structlog.dev.ConsoleRenderer()` yourself and passing `exception_formatter=structlog.dev.plain_traceback`. +If you prefer the default terse Exception rendering, but still want Rich installed, you can disable the pretty-printing by instantiating {class}`structlog.dev.ConsoleRenderer()` yourself and passing `exception_formatter=structlog.dev.plain_traceback`. diff --git a/docs/getting-started.md b/docs/getting-started.md index a66355ca..7628bd0c 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -10,10 +10,10 @@ You can install *structlog* from [PyPI](https://pypi.org/project/structlog/) usi $ python -m pip install structlog ``` -If you want pretty exceptions in development (you know you do!), additionally install either [*Rich*] or [*better-exceptions*]. -Try both to find out which one you like better -- the screenshot in the README and docs homepage is rendered by *Rich*. +If you want pretty exceptions in development (you know you do!), additionally install either [Rich] or [*better-exceptions*]. +Try both to find out which one you like better -- the screenshot in the README and docs homepage is rendered by Rich. -On **Windows**, you also have to install [*Colorama*](https://pypi.org/project/colorama/) if you want colorful output beside exceptions. +On **Windows**, you also have to install [Colorama](https://pypi.org/project/colorama/) if you want colorful output beside exceptions. ## Your First Log Entry @@ -39,7 +39,7 @@ Here, *structlog* takes advantage of its default settings: - All keywords are formatted using {class}`structlog.dev.ConsoleRenderer`. That in turn uses {func}`repr` to serialize **any value to a string**. - It's rendered in nice **{doc}`colors `**. -- If you have [*Rich*] or [*better-exceptions*] installed, **exceptions** will be rendered in **colors** and with additional **helpful information**. +- If you have [Rich] or [*better-exceptions*] installed, **exceptions** will be rendered in **colors** and with additional **helpful information**. Please note that even in most complex logging setups the example would still look just like that thanks to {doc}`configuration`. Using the defaults, as above, is equivalent to: @@ -251,4 +251,4 @@ Or, if you prefer another, more in-depth tutorial, check out [*A Comprehensive G [*better-exceptions*]: https://github.com/qix-/better-exceptions [recipe]: https://docs.python.org/3/howto/logging-cookbook.html#implementing-structured-logging -[*Rich*]: https://github.com/Textualize/rich +[Rich]: https://github.com/Textualize/rich From 25c361c71763df0e7f39d0d36cca08ff4b46e924 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 7 Sep 2023 07:55:19 +0200 Subject: [PATCH 1062/1520] ConsoleRenderer: add timestamp_key Fixes #541 --- CHANGELOG.md | 2 + docs/conf.py | 1 + src/structlog/dev.py | 87 ++++++++++++++++++++++++++------------------ tests/test_dev.py | 14 ++++++- 4 files changed, 67 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 091cf927..3dd3029c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,8 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ [#515](https://github.com/hynek/structlog/issues/515) - `structlog.processors.MaybeTimeStamper` that only adds a timestamp if there isn't one already. [#81](https://github.com/hynek/structlog/issues/81) +- `structlog.dev.ConsoleRenderer` now supports renamed timestamp keys using the *timestamp_key* parameter. + [#541](https://github.com/hynek/structlog/issues/541) ### Fixed diff --git a/docs/conf.py b/docs/conf.py index 5f4ac3bb..8334f67a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -17,6 +17,7 @@ "notfound.extension", "sphinx.ext.autodoc", "sphinx.ext.autodoc.typehints", + "sphinx.ext.napoleon", "sphinx.ext.doctest", "sphinx.ext.intersphinx", "sphinx.ext.viewcode", diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 603dde2d..c8d73873 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -158,7 +158,7 @@ def plain_traceback(sio: TextIO, exc_info: ExcInfo) -> None: To be passed into `ConsoleRenderer`'s ``exception_formatter`` argument. - Used by default if neither *Rich* nor *better-exceptions* are present. + Used by default if neither Rich nor *better-exceptions* are present. .. versionadded:: 21.2 """ @@ -167,11 +167,11 @@ def plain_traceback(sio: TextIO, exc_info: ExcInfo) -> None: def rich_traceback(sio: TextIO, exc_info: ExcInfo) -> None: """ - Pretty-print *exc_info* to *sio* using the *Rich* package. + Pretty-print *exc_info* to *sio* using the Rich package. To be passed into `ConsoleRenderer`'s ``exception_formatter`` argument. - Used by default if *Rich* is installed. + Used by default if Rich is installed. .. versionadded:: 21.2 """ @@ -187,7 +187,7 @@ def better_traceback(sio: TextIO, exc_info: ExcInfo) -> None: To be passed into `ConsoleRenderer`'s ``exception_formatter`` argument. - Used by default if *better-exceptions* is installed and *Rich* is absent. + Used by default if *better-exceptions* is installed and Rich is absent. .. versionadded:: 21.2 """ @@ -206,33 +206,45 @@ class ConsoleRenderer: """ Render ``event_dict`` nicely aligned, possibly in colors, and ordered. - If ``event_dict`` contains a true-ish ``exc_info`` key, it will be - rendered *after* the log line. If Rich_ or better-exceptions_ are present, - in colors and with extra context. - - :param pad_event: Pad the event to this many characters. - :param colors: Use colors for a nicer output. `True` by default. On - Windows only if Colorama_ is installed. - :param force_colors: Force colors even for non-tty destinations. - Use this option if your logs are stored in a file that is meant - to be streamed to the console. Only meaningful on Windows. - :param repr_native_str: When `True`, `repr` is also applied - to native strings (i.e. unicode on Python 3 and bytes on Python 2). - Setting this to `False` is useful if you want to have human-readable - non-ASCII output on Python 2. The ``event`` key is *never* - `repr` -ed. - :param level_styles: When present, use these styles for colors. This - must be a dict from level names (strings) to Colorama styles. The - default can be obtained by calling - `ConsoleRenderer.get_default_level_styles` - :param exception_formatter: A callable to render ``exc_infos``. If rich_ - or better-exceptions_ are installed, they are used for pretty-printing - by default (rich_ taking precedence). You can also manually set it to - `plain_traceback`, `better_traceback`, `rich_traceback`, or implement - your own. - :param sort_keys: Whether to sort keys when formatting. `True` by default. - :param event_key: The key to look for the main log message. Needed when - you rename it e.g. using `structlog.processors.EventRenamer`. + If ``event_dict`` contains a true-ish ``exc_info`` key, it will be rendered + *after* the log line. If Rich_ or better-exceptions_ are present, in colors + and with extra context. + + Arguments: + + pad_event: Pad the event to this many characters. + + colors: Use colors for a nicer output. `True` by default. On + Windows only if Colorama_ is installed. + + force_colors: Force colors even for non-tty destinations. + Use this option if your logs are stored in a file that is meant to + be streamed to the console. Only meaningful on Windows. + + repr_native_str: When `True`, `repr` is also applied + to native strings (i.e. unicode on Python 3 and bytes on Python 2). + Setting this to `False` is useful if you want to have + human-readable non-ASCII output on Python 2. The ``event`` key is + *never* `repr` -ed. + + level_styles: When present, use these styles for colors. This + must be a dict from level names (strings) to Colorama styles. The + default can be obtained by calling + `ConsoleRenderer.get_default_level_styles` + + exception_formatter: A callable to render ``exc_infos``. If rich_ + or better-exceptions_ are installed, they are used for + pretty-printing by default (rich_ taking precedence). You can also + manually set it to `plain_traceback`, `better_traceback`, + `rich_traceback`, or implement your own. + + sort_keys: Whether to sort keys when formatting. `True` by default. + + event_key: The key to look for the main log message. Needed when + you rename it e.g. using `structlog.processors.EventRenamer`. + + timestamp_key: The key to look for timestamp of the log message. Needed + when you rename it e.g. using `structlog.processors.EventRenamer`. Requires the Colorama_ package if *colors* is `True` **on Windows**. @@ -246,10 +258,10 @@ class ConsoleRenderer: .. versionadded:: 18.1 *force_colors* .. versionadded:: 18.1 *level_styles* .. versionchanged:: 19.2 - *Colorama* now initializes lazily to avoid unwanted initializations as + Colorama now initializes lazily to avoid unwanted initializations as ``ConsoleRenderer`` is used by default. .. versionchanged:: 19.2 Can be pickled now. - .. versionchanged:: 20.1 *Colorama* does not initialize lazily on Windows + .. versionchanged:: 20.1 Colorama does not initialize lazily on Windows anymore because it breaks rendering. .. versionchanged:: 21.1 It is additionally possible to set the logger name using the ``logger_name`` key in the ``event_dict``. @@ -262,9 +274,10 @@ class ConsoleRenderer: for it. .. versionchanged:: 21.2 The colors keyword now defaults to True on non-Windows systems, and either True or False in Windows depending on - whether *Colorama* is installed. + whether Colorama is installed. .. versionadded:: 21.3.0 *sort_keys* - .. versionadded:: 22.1 *event_key* + .. versionadded:: 22.1.0 *event_key* + .. versionadded:: 23.2.0 *timestamp_key* """ def __init__( @@ -277,6 +290,7 @@ def __init__( exception_formatter: ExceptionRenderer = default_exception_formatter, sort_keys: bool = True, event_key: str = "event", + timestamp_key: str = "timestamp", ): styles: Styles if colors: @@ -320,6 +334,7 @@ def __init__( self._exception_formatter = exception_formatter self._sort_keys = sort_keys self._event_key = event_key + self._timestamp_key = timestamp_key def _repr(self, val: Any) -> str: """ @@ -339,7 +354,7 @@ def __call__( # noqa: PLR0912 ) -> str: sio = StringIO() - ts = event_dict.pop("timestamp", None) + ts = event_dict.pop(self._timestamp_key, None) if ts is not None: sio.write( # can be a number if timestamp is UNIXy diff --git a/tests/test_dev.py b/tests/test_dev.py index b99966c3..2d845570 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -97,7 +97,7 @@ def test_event_stringified(self, cr, unpadded): def test_event_renamed(self): """ - Uses respects if the event key has been renamed. + The main event key can be renamed. """ cr = dev.ConsoleRenderer(colors=False, event_key="msg") @@ -105,6 +105,18 @@ def test_event_renamed(self): None, None, {"msg": "new event name", "event": "something custom"} ) + def test_timestamp_renamed(self): + """ + The timestamp key can be renamed. + """ + cr = dev.ConsoleRenderer(colors=False, timestamp_key="ts") + + assert "2023-09-07 le event" == cr( + None, + None, + {"ts": "2023-09-07", "event": "le event"}, + ) + def test_level(self, cr, styles, padded): """ Levels are rendered aligned, in square brackets, and color coded. From 91047b20a0d1f7651005ba4de7720de4d0daba43 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 8 Sep 2023 06:36:25 +0200 Subject: [PATCH 1063/1520] Add structlog.dev.RichTracebackFormatter (#549) --- CHANGELOG.md | 5 +++ docs/api.rst | 1 + docs/conf.py | 5 ++- src/structlog/dev.py | 87 ++++++++++++++++++++++++++++++++++++++------ tests/test_dev.py | 22 +++++++++-- 5 files changed, 104 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3dd3029c..858080b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,11 +24,16 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - Official support for Python 3.12. [#515](https://github.com/hynek/structlog/issues/515) + - `structlog.processors.MaybeTimeStamper` that only adds a timestamp if there isn't one already. [#81](https://github.com/hynek/structlog/issues/81) + - `structlog.dev.ConsoleRenderer` now supports renamed timestamp keys using the *timestamp_key* parameter. [#541](https://github.com/hynek/structlog/issues/541) +- `structlog.dev.RichTracebackFormatter` that allows to configure the traceback formatting. + [#542](https://github.com/hynek/structlog/issues/542) + ### Fixed diff --git a/docs/api.rst b/docs/api.rst index 5286276d..f58f50f0 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -79,6 +79,7 @@ API Reference :members: get_default_level_styles .. autofunction:: plain_traceback +.. autoclass:: RichTracebackFormatter .. autofunction:: rich_traceback .. autofunction:: better_traceback diff --git a/docs/conf.py b/docs/conf.py index 8334f67a..5948b03d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -160,4 +160,7 @@ # Twisted's trac tends to be slow linkcheck_timeout = 300 -intersphinx_mapping = {"python": ("https://docs.python.org/3", None)} +intersphinx_mapping = { + "python": ("https://docs.python.org/3", None), + "rich": ("https://rich.readthedocs.io/en/stable/", None), +} diff --git a/src/structlog/dev.py b/src/structlog/dev.py index c8d73873..1bc9bbf0 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -11,11 +11,23 @@ from __future__ import annotations +import shutil import sys import warnings +from dataclasses import dataclass from io import StringIO -from typing import Any, Iterable, Protocol, TextIO, Type, Union +from types import ModuleType +from typing import ( + Any, + Iterable, + Literal, + Protocol, + Sequence, + TextIO, + Type, + Union, +) from ._frames import _format_exception from .processors import _figure_out_exc_info @@ -160,25 +172,78 @@ def plain_traceback(sio: TextIO, exc_info: ExcInfo) -> None: Used by default if neither Rich nor *better-exceptions* are present. - .. versionadded:: 21.2 + .. versionadded:: 21.2.0 """ sio.write("\n" + _format_exception(exc_info)) -def rich_traceback(sio: TextIO, exc_info: ExcInfo) -> None: +@dataclass +class RichTracebackFormatter: """ - Pretty-print *exc_info* to *sio* using the Rich package. + A Rich traceback renderer with the given options. - To be passed into `ConsoleRenderer`'s ``exception_formatter`` argument. + Pass an instance as `ConsoleRenderer`'s ``exception_formatter`` argument. - Used by default if Rich is installed. + See :class:`rich.traceback.Traceback` for details on the arguments. - .. versionadded:: 21.2 + If a *width* of -1 is passed, the terminal width is used. If the width + can't be determined, fall back to 80. + + .. versionadded:: 23.2.0 """ - sio.write("\n") - Console(file=sio, color_system="truecolor").print( - Traceback.from_exception(*exc_info, show_locals=True) - ) + + color_system: Literal[ + "auto", "standard", "256", "truecolor", "windows" + ] = "truecolor" + show_locals: bool = True + max_frames: int = 100 + theme: str | None = None + word_wrap: bool = False + extra_lines: int = 3 + width: int = 100 + indent_guides: bool = True + locals_max_length: int = 10 + locals_max_string: int = 80 + locals_hide_dunder: bool = True + locals_hide_sunder: bool = False + suppress: Sequence[str | ModuleType] = () + + def __call__(self, sio: TextIO, exc_info: ExcInfo) -> None: + if self.width == -1: + self.width, _ = shutil.get_terminal_size((80, 0)) + + sio.write("\n") + + Console(file=sio, color_system=self.color_system).print( + Traceback.from_exception( + *exc_info, + show_locals=self.show_locals, + max_frames=self.max_frames, + theme=self.theme, + word_wrap=self.word_wrap, + extra_lines=self.extra_lines, + width=self.width, + indent_guides=self.indent_guides, + locals_max_length=self.locals_max_length, + locals_max_string=self.locals_max_string, + locals_hide_dunder=self.locals_hide_dunder, + locals_hide_sunder=self.locals_hide_sunder, + suppress=self.suppress, + ) + ) + + +rich_traceback = RichTracebackFormatter() +""" +Pretty-print *exc_info* to *sio* using the Rich package. + +To be passed into `ConsoleRenderer`'s ``exception_formatter`` argument. + +This is a `RichTracebackFormatter` with default arguments and used by default +if Rich is installed. + +.. versionadded:: 21.2.0 +""" def better_traceback(sio: TextIO, exc_info: ExcInfo) -> None: diff --git a/tests/test_dev.py b/tests/test_dev.py index 2d845570..531e76df 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -7,6 +7,7 @@ import sys from io import StringIO +from unittest import mock import pytest @@ -560,20 +561,19 @@ def test_set_it(self): assert {"exc_info": True} == dev.set_exc_info(None, "exception", {}) -@pytest.mark.skipif(dev.rich is None, reason="Needs rich.") -class TestRichTraceback: +@pytest.mark.skipif(dev.rich is None, reason="Needs Rich.") +class TestRichTracebackFormatter: def test_default(self): """ If Rich is present, it's the default. """ assert dev.default_exception_formatter is dev.rich_traceback - def test_does_not_blow_up(self): + def test_does_not_blow_up(self, sio): """ We trust Rich to do the right thing, so we just exercise the function and check the first new line that we add manually is present. """ - sio = StringIO() try: 0 / 0 except ZeroDivisionError: @@ -581,6 +581,20 @@ def test_does_not_blow_up(self): assert sio.getvalue().startswith("\n") + def test_width_minus_one(self, sio): + """ + If width is -1, it's replaced by the terminal width on first use. + """ + rtf = dev.RichTracebackFormatter(width=-1) + + with mock.patch("shutil.get_terminal_size", return_value=(42, 0)): + try: + 0 / 0 + except ZeroDivisionError: + rtf(sio, sys.exc_info()) + + assert 42 == rtf.width + @pytest.mark.skipif( dev.better_exceptions is None, reason="Needs better-exceptions." From 5e1a9cf52b6780ce604fa626bac04fc7428a98b1 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 8 Sep 2023 08:51:52 +0200 Subject: [PATCH 1064/1520] Add interrogate --- .pre-commit-config.yaml | 6 ++++++ pyproject.toml | 7 +++++++ tests/conftest.py | 7 +++++++ tests/test_base.py | 11 ++++++---- tests/test_config.py | 29 ++++++++++++++++++--------- tests/test_log_levels.py | 5 +++++ tests/test_processors.py | 43 ++++++++++++++++++++-------------------- tests/test_stdlib.py | 21 +++++++++++++------- tests/test_testing.py | 6 +----- tests/test_tracebacks.py | 14 +++++++++++++ tests/test_twisted.py | 21 ++++++++++++++++++++ tests/test_utils.py | 18 +++++++++++++++-- 12 files changed, 139 insertions(+), 49 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cf16cd98..be772cad 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,6 +18,12 @@ repos: - id: ruff args: [--fix, --exit-non-zero-on-fix] + - repo: https://github.com/econchick/interrogate + rev: 1.5.0 + hooks: + - id: interrogate + args: [tests] + - repo: https://github.com/codespell-project/codespell rev: v2.2.5 hooks: diff --git a/pyproject.toml b/pyproject.toml index e8f85af7..42d3bef4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -103,6 +103,13 @@ exclude_lines = [ ] +[tool.interrogate] +omit-covered-files = true +verbose = 2 +fail-under = 100 +whitelist-regex = ["test_.*"] + + [tool.black] line-length = 79 diff --git a/tests/conftest.py b/tests/conftest.py index ae66a011..d68a7272 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -9,6 +9,8 @@ import pytest +import structlog + from structlog._log_levels import _NAME_TO_LEVEL from structlog.testing import CapturingLogger @@ -65,3 +67,8 @@ def _stdlib_log_methods(request): @pytest.fixture(name="cl") def _cl(): return CapturingLogger() + + +@pytest.fixture(autouse=True) +def _reset_config(): + structlog.reset_defaults() diff --git a/tests/test_base.py b/tests/test_base.py index faa9aead..de810c72 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -29,11 +29,14 @@ def build_bl(logger=None, processors=None, context=None): class TestBinding: def test_repr(self): - bl = build_bl(processors=[1, 2, 3], context={}) + """ + repr() of a BoundLoggerBase shows its context and processors. + """ + bl = build_bl(processors=[1, 2, 3], context={"A": "B"}) - assert ("") == repr( - bl - ) + assert ( + "" + ) == repr(bl) def test_binds_independently(self): """ diff --git a/tests/test_config.py b/tests/test_config.py index 4f597c61..5e741d5d 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -64,9 +64,6 @@ def test_default_context_class(): class TestConfigure: - def teardown_method(self, method): - structlog.reset_defaults() - def test_get_config_is_configured(self): """ Return value of structlog.get_config() works as input for @@ -84,6 +81,9 @@ def test_get_config_is_configured(self): assert False is structlog.is_configured() def test_configure_all(self, proxy): + """ + All configurations are applied and land on the bound logger. + """ x = stub() configure(processors=[x], context_class=dict) b = proxy.bind() @@ -92,8 +92,12 @@ def test_configure_all(self, proxy): assert dict is b._context.__class__ def test_reset(self, proxy): + """ + Reset resets all settings to their default values. + """ x = stub() configure(processors=[x], context_class=dict, wrapper_class=Wrapper) + structlog.reset_defaults() b = proxy.bind() @@ -104,6 +108,9 @@ def test_reset(self, proxy): assert _BUILTIN_DEFAULT_LOGGER_FACTORY is _CONFIG.logger_factory def test_just_processors(self, proxy): + """ + It's possible to only configure processors. + """ x = stub() configure(processors=[x]) b = proxy.bind() @@ -113,6 +120,9 @@ def test_just_processors(self, proxy): assert _BUILTIN_DEFAULT_CONTEXT_CLASS == b._context.__class__ def test_just_context_class(self, proxy): + """ + It's possible to only configure the context class. + """ configure(context_class=dict) b = proxy.bind() @@ -120,6 +130,9 @@ def test_just_context_class(self, proxy): assert _BUILTIN_DEFAULT_PROCESSORS == b._processors def test_configure_sets_is_configured(self): + """ + After configure() is_configured() returns True. + """ assert False is _CONFIG.is_configured configure() @@ -127,6 +140,10 @@ def test_configure_sets_is_configured(self): assert True is _CONFIG.is_configured def test_configures_logger_factory(self): + """ + It's possible to configure the logger factory. + """ + def f(): pass @@ -136,9 +153,6 @@ def f(): class TestBoundLoggerLazyProxy: - def teardown_method(self, method): - structlog.reset_defaults() - def test_repr(self): """ repr reflects all attributes. @@ -362,9 +376,6 @@ def test_pickle(self, proto): class TestFunctions: - def teardown_method(self, method): - structlog.reset_defaults() - def test_wrap_passes_args(self): """ wrap_logger propagates all arguments to the wrapped bound logger. diff --git a/tests/test_log_levels.py b/tests/test_log_levels.py index f04e5103..ade958e8 100644 --- a/tests/test_log_levels.py +++ b/tests/test_log_levels.py @@ -293,12 +293,17 @@ async def test_async_pos_args(self, bl, cl): ], ) async def test_async_contextvars_merged(self, meth, args, cl): + """ + Contextvars are merged into the event dict. + """ clear_contextvars() bl = make_filtering_bound_logger(logging.INFO)( cl, [merge_contextvars], {} ) bind_contextvars(context_included="yep") + await getattr(bl, meth)(*args) + assert len(cl.calls) == 1 assert "context_included" in cl.calls[0].kwargs diff --git a/tests/test_processors.py b/tests/test_processors.py index 59d5657c..d9363108 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -753,6 +753,9 @@ def test_adds_stack_if_asked(self, sir): assert "stack" in ed def test_renders_correct_stack(self, sir): + """ + The rendered stack is correct. + """ ed = sir(None, None, {"stack_info": True}) assert 'ed = sir(None, None, {"stack_info": True})' in ed["stack"] @@ -831,32 +834,28 @@ async def test_async(self) -> None: """ Callsite information for async invocations are correct. """ - try: - string_io = StringIO() - - class StingIOLogger(structlog.PrintLogger): - def __init__(self): - super().__init__(file=string_io) - - processor = self.make_processor(None, ["concurrent", "threading"]) - structlog.configure( - processors=[processor, JSONRenderer()], - logger_factory=StingIOLogger, - wrapper_class=structlog.stdlib.AsyncBoundLogger, - cache_logger_on_first_use=True, - ) + string_io = StringIO() - logger = structlog.stdlib.get_logger() + class StingIOLogger(structlog.PrintLogger): + def __init__(self): + super().__init__(file=string_io) - callsite_params = self.get_callsite_parameters() - await logger.info("baz") + processor = self.make_processor(None, ["concurrent", "threading"]) + structlog.configure( + processors=[processor, JSONRenderer()], + logger_factory=StingIOLogger, + wrapper_class=structlog.stdlib.AsyncBoundLogger, + cache_logger_on_first_use=True, + ) - assert {"event": "baz", **callsite_params} == json.loads( - string_io.getvalue() - ) + logger = structlog.stdlib.get_logger() - finally: - structlog.reset_defaults() + callsite_params = self.get_callsite_parameters() + await logger.info("baz") + + assert {"event": "baz", **callsite_params} == json.loads( + string_io.getvalue() + ) def test_additional_ignores(self, monkeypatch: pytest.MonkeyPatch) -> None: """ diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index e36cd3b4..d097aa00 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -24,7 +24,6 @@ ReturnLogger, configure, get_context, - reset_defaults, ) from structlog._config import _CONFIG from structlog._log_levels import _NAME_TO_LEVEL, CRITICAL, WARN @@ -110,7 +109,11 @@ def test_ignores_frames(self): ) def test_deduces_correct_caller(self): + """ + It will find the correct caller. + """ logger = _FixedFindCallerLogger("test") + file_name, line_number, func_name = logger.findCaller()[:3] assert file_name == os.path.realpath(__file__) @@ -126,16 +129,24 @@ def test_stack_info(self): assert "testing, is_, fun" in stack_info def test_no_stack_info_by_default(self): + """ + If we don't ask for stack_info, it won't be returned. + """ logger = _FixedFindCallerLogger("test") testing, is_, fun, stack_info = logger.findCaller() assert None is stack_info def test_find_caller(self, monkeypatch): + """ + The caller is found. + """ logger = LoggerFactory()() log_handle = call_recorder(lambda x: None) monkeypatch.setattr(logger, "handle", log_handle) + logger.error("Test") + log_record = log_handle.calls[0].args[0] assert log_record.funcName == "test_find_caller" @@ -720,7 +731,8 @@ def _configure_for_processor_formatter(): """ Configure structlog to use ProcessorFormatter. - Reset both structlog and logging setting after the test. + Reset logging setting after the test (structlog is reset automatically + before all tests). """ configure( processors=[add_log_level, ProcessorFormatter.wrap_for_formatter], @@ -731,7 +743,6 @@ def _configure_for_processor_formatter(): yield logging.basicConfig() - reset_defaults() def configure_logging( @@ -1254,16 +1265,12 @@ async def test_integration(self, capsys): "level": "info", } == json.loads(capsys.readouterr().out) - reset_defaults() - @pytest.mark.parametrize("log_level", [None, 45]) def test_recreate_defaults(log_level): """ Recreate defaults configures structlog and -- if asked -- logging. """ - reset_defaults() - logging.basicConfig( stream=sys.stderr, level=1, diff --git a/tests/test_testing.py b/tests/test_testing.py index d7e4a51a..1283ddee 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -5,7 +5,7 @@ import pytest -from structlog import get_config, get_logger, reset_defaults, testing +from structlog import get_config, get_logger, testing from structlog.testing import ( CapturedCall, CapturingLogger, @@ -17,10 +17,6 @@ class TestCaptureLogs: - @classmethod - def teardown_class(cls): - reset_defaults() - def test_captures_logs(self): """ Log entries are captured and retain their structure. diff --git a/tests/test_tracebacks.py b/tests/test_tracebacks.py index b8d7e6d4..b3f762ea 100644 --- a/tests/test_tracebacks.py +++ b/tests/test_tracebacks.py @@ -55,6 +55,9 @@ def __str__(self) -> str: ], ) def test_to_repr(data: Any, max_len: int | None, expected: str): + """ + "to_repr()" returns the repr of an object, trimmed to max_len. + """ assert expected == tracebacks.to_repr(data, max_string=max_len) @@ -483,6 +486,9 @@ def bar(n): def test_json_traceback(): + """ + Tracebacks are formatted to JSON with all information. + """ try: lineno = get_next_lineno() 1 / 0 @@ -510,6 +516,9 @@ def test_json_traceback(): def test_json_traceback_locals_max_string(): + """ + Local variables in each frame are trimmed to locals_max_string. + """ try: _var = "spamspamspam" lineno = get_next_lineno() @@ -553,6 +562,11 @@ def test_json_traceback_locals_max_string(): def test_json_traceback_max_frames( max_frames: int, expected_frames: int, skipped_idx: int, skipped_count: int ): + """ + Only max_frames frames are included in the traceback and the skipped frames + are reported. + """ + def spam(): return 1 / 0 diff --git a/tests/test_twisted.py b/tests/test_twisted.py index 725c8506..902f430c 100644 --- a/tests/test_twisted.py +++ b/tests/test_twisted.py @@ -35,6 +35,9 @@ def test_LoggerFactory(): + """ + Logger factory ultimately returns twisted.python.log for output. + """ from twisted.python import log assert log is LoggerFactory()() @@ -146,6 +149,9 @@ class TestEventAdapter: """ def test_EventAdapterFormatsLog(self): + """ + EventAdapter formats log entries correctly. + """ la = EventAdapter(_render_repr) assert "{'foo': 'bar'}" == la(None, "msg", {"foo": "bar"}) @@ -265,6 +271,9 @@ def test_msgWorksToo(self, jr): ) def test_handlesFailure(self, jr): + """ + JSONRenderer renders failures correctly. + """ rv = jr(None, "err", {"event": Failure(ValueError())})[0][0].string assert "Failure: builtins.ValueError" in rv @@ -288,9 +297,15 @@ def test_repr(self): class TestPlainFileLogObserver: def test_isLogObserver(self, sio): + """ + PlainFileLogObserver is an ILogObserver. + """ assert ILogObserver.providedBy(PlainFileLogObserver(sio)) def test_writesOnlyMessageWithLF(self, sio): + """ + PlainFileLogObserver writes only the message and a line feed. + """ PlainFileLogObserver(sio)( {"system": "some system", "message": ("hello",)} ) @@ -300,6 +315,9 @@ def test_writesOnlyMessageWithLF(self, sio): class TestJSONObserverWrapper: def test_IsAnObserver(self): + """ + JSONLogObserverWrapper is an ILogObserver. + """ assert ILogObserver.implementedBy(JSONLogObserverWrapper) def test_callsWrappedObserver(self): @@ -336,4 +354,7 @@ def verify(eventDict): class TestPlainJSONStdOutLogger: def test_isLogObserver(self): + """ + plainJSONStdOutLogger is an ILogObserver. + """ assert ILogObserver.providedBy(plainJSONStdOutLogger()) diff --git a/tests/test_utils.py b/tests/test_utils.py index 87a8f2fd..7ef508a0 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -16,17 +16,31 @@ class TestUntilNotInterrupted: def test_passes_arguments_and_returns_return_value(self): + """ + until_not_interrupted() passes arguments to the wrapped function and + returns its return value. + """ + def returner(*args, **kw): - return args, kw + assert (42,) == args + assert {"x": 23} == kw + + return "foo" - assert ((42,), {"x": 23}) == until_not_interrupted(returner, 42, x=23) + assert "foo" == until_not_interrupted(returner, 42, x=23) def test_leaves_unrelated_exceptions_through(self): + """ + Exceptions that are not an EINTR OSError are not intercepted/retried. + """ exc = IOError with pytest.raises(exc): until_not_interrupted(raiser(exc("not EINTR"))) def test_retries_on_EINTR(self): + """ + Wrapped functions that raise EINTR OSErrors are retried. + """ calls = [0] def raise_on_first_three(): From 0d873c5aec58a181696a7124fd09daf1ddb993b1 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 8 Sep 2023 08:52:07 +0200 Subject: [PATCH 1065/1520] Furo only likes HTML --- .readthedocs.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 5736bad0..f8c4c2ce 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -1,7 +1,5 @@ --- version: 2 -# PDF builds are broken. -formats: [htmlzip, epub] build: os: ubuntu-22.04 From 2a6b4c051fd78fe1e2082ac0443447132143730d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 8 Sep 2023 10:35:00 +0200 Subject: [PATCH 1066/1520] Make docstrings more readable by switching to Napoleon --- .github/CONTRIBUTING.md | 10 +- docs/api.rst | 1 + src/structlog/_base.py | 74 +++++++++----- src/structlog/_config.py | 94 ++++++++++------- src/structlog/_frames.py | 10 +- src/structlog/_log_levels.py | 13 ++- src/structlog/_output.py | 40 +++++--- src/structlog/_utils.py | 10 +- src/structlog/dev.py | 11 +- src/structlog/processors.py | 189 +++++++++++++++++++++-------------- src/structlog/stdlib.py | 169 +++++++++++++++++-------------- src/structlog/testing.py | 10 +- src/structlog/threadlocal.py | 14 ++- src/structlog/tracebacks.py | 60 ++++++----- src/structlog/twisted.py | 25 +++-- src/structlog/typing.py | 31 +++--- tests/test_processors.py | 43 ++++---- tests/test_stdlib.py | 4 - 18 files changed, 488 insertions(+), 320 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 384a1454..51bfcdbc 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -121,16 +121,20 @@ But it's way more comfortable to run it locally and catch avoidable errors befor ## Code - Obey [PEP 8](https://www.python.org/dev/peps/pep-0008/) and [PEP 257](https://www.python.org/dev/peps/pep-0257/). - We use the `"""`-on-separate-lines style for docstrings: + We use the `"""`-on-separate-lines style for docstrings with [Napoleon](https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html)-style API documentation: ```python def func(x: str) -> str: """ Do something. - :param str x: A very important parameter. + Arguments: - :rtype: str + x: A very important parameter. + + Returns: + + A very important return value. """ ``` - If you add or change public APIs, tag the docstring using `.. versionadded:: 16.0.0 WHAT` or `.. versionchanged:: 16.2.0 WHAT`. diff --git a/docs/api.rst b/docs/api.rst index f58f50f0..5a911533 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -292,6 +292,7 @@ API Reference :members: bind, unbind, try_unbind, new, debug, info, warning, warn, error, critical, exception, log, adebug, ainfo, awarning, aerror, acritical, aexception, alog .. autoclass:: AsyncBoundLogger + :members: sync_bl .. autoclass:: LoggerFactory :members: __call__ diff --git a/src/structlog/_base.py b/src/structlog/_base.py index 6822c505..9fc6e7ce 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -78,7 +78,9 @@ def unbind(self, *keys: str) -> BoundLoggerBase: """ Return a new logger with *keys* removed from the context. - :raises KeyError: If the key is not part of the context. + Raises: + + KeyError: If the key is not part of the context. """ bl = self.bind() for key in keys: @@ -121,19 +123,29 @@ def _process_event( Call it to combine your *event* and *context* into an event_dict and process using the processor chain. - :param method_name: The name of the logger method. Is passed into - the processors. - :param event: The event -- usually the first positional argument to a - logger. - :param event_kw: Additional event keywords. For example if someone - calls ``log.info("foo", bar=42)``, *event* would to be ``"foo"`` - and *event_kw* ``{"bar": 42}``. + Arguments: + + method_name: + The name of the logger method. Is passed into the processors. + + event: + The event -- usually the first positional argument to a logger. + + event_kw: + Additional event keywords. For example if someone calls + ``log.info("foo", bar=42)``, *event* would to be ``"foo"`` and + *event_kw* ``{"bar": 42}``. + + Raises: + + structlog.DropEvent: if log entry should be dropped. - :raises: `structlog.DropEvent` if log entry should be dropped. - :raises: `ValueError` if the final processor doesn't return a - str, bytes, bytearray, tuple, or a dict. + ValueError: + if the final processor doesn't return a str, bytes, bytearray, + tuple, or a dict. - :returns: `tuple` of ``(*args, **kw)`` + Returns: + `tuple` of ``(*args, **kw)`` .. note:: @@ -169,7 +181,10 @@ def _process_event( if isinstance(event_dict, dict): return (), event_dict - msg = "Last processor didn't return an appropriate value. Valid return values are a dict, a tuple of (args, kwargs), bytes, or a str." + msg = ( + "Last processor didn't return an appropriate value. " + "Valid return values are a dict, a tuple of (args, kwargs), bytes, or a str." + ) raise ValueError(msg) def _proxy_to_logger( @@ -182,14 +197,20 @@ def _proxy_to_logger( handling :exc:`structlog.DropEvent`, and finally calls *method_name* on :attr:`_logger` with the result. - :param method_name: The name of the method that's going to get - called. Technically it should be identical to the method the - user called because it also get passed into processors. - :param event: The event -- usually the first positional argument to a - logger. - :param event_kw: Additional event keywords. For example if someone - calls ``log.info("foo", bar=42)``, *event* would to be ``"foo"`` - and *event_kw* ``{"bar": 42}``. + Arguments: + + method_name: + The name of the method that's going to get called. Technically + it should be identical to the method the user called because it + also get passed into processors. + + event: + The event -- usually the first positional argument to a logger. + + event_kw: + Additional event keywords. For example if someone calls + ``log.info("foo", bar=42)``, *event* would to be ``"foo"`` and + *event_kw* ``{"bar": 42}``. .. note:: @@ -211,12 +232,15 @@ def get_context(bound_logger: BindableLogger) -> Context: The type of *bound_logger* and the type returned depend on your configuration. - :param bound_logger: The bound logger whose context you want. + Arguments: + + bound_logger: The bound logger whose context you want. + + Returns: - :returns: The *actual* context from *bound_logger*. It is *not* copied - first. + The *actual* context from *bound_logger*. It is *not* copied first. - .. versionadded:: 20.2 + .. versionadded:: 20.2.0 """ # This probably will get more complicated in the future. return bound_logger._context diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 05de0ca5..718bcfb6 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -81,7 +81,7 @@ def is_configured() -> bool: If `False`, *structlog* is running with builtin defaults. - .. versionadded: 18.1 + .. versionadded: 18.1.0 """ return _CONFIG.is_configured @@ -94,7 +94,7 @@ def get_config() -> dict[str, Any]: Changes to the returned dictionary do *not* affect *structlog*. - .. versionadded: 18.1 + .. versionadded: 18.1.0 """ return { "processors": _CONFIG.default_processors, @@ -114,12 +114,18 @@ def get_logger(*args: Any, **initial_values: Any) -> Any: >>> log.info("hello", x=42) y=23 x=42 event='hello' - :param args: *Optional* positional arguments that are passed unmodified to - the logger factory. Therefore it depends on the factory what they - mean. - :param initial_values: Values that are used to pre-populate your contexts. + Arguments: - :returns: A proxy that creates a correctly configured bound logger when + args: + *Optional* positional arguments that are passed unmodified to the + logger factory. Therefore it depends on the factory what they + mean. + + initial_values: Values that are used to pre-populate your contexts. + + Returns: + + A proxy that creates a correctly configured bound logger when necessary. The type of that bound logger depends on your configuration and is `structlog.BoundLogger` by default. @@ -128,8 +134,7 @@ def get_logger(*args: Any, **initial_values: Any) -> Any: If you prefer CamelCase, there's an alias for your reading pleasure: `structlog.getLogger`. - .. versionadded:: 0.4.0 - *args* + .. versionadded:: 0.4.0 *args* """ return wrap_logger(None, logger_factory_args=args, **initial_values) @@ -158,23 +163,28 @@ def wrap_logger( Default values for *processors*, *wrapper_class*, and *context_class* can be set using `configure`. - If you set an attribute here, `configure` calls have *no* effect for - the *respective* attribute. + If you set an attribute here, `configure` calls have *no* effect for the + *respective* attribute. In other words: selective overwriting of the defaults while keeping some *is* possible. - :param initial_values: Values that are used to pre-populate your contexts. - :param logger_factory_args: Values that are passed unmodified as - ``*logger_factory_args`` to the logger factory if not `None`. + Arguments: + + initial_values: Values that are used to pre-populate your contexts. - :returns: A proxy that creates a correctly configured bound logger when + logger_factory_args: + Values that are passed unmodified as ``*logger_factory_args`` to + the logger factory if not `None`. + + Returns: + + A proxy that creates a correctly configured bound logger when necessary. See `configure` for the meaning of the rest of the arguments. - .. versionadded:: 0.4.0 - *logger_factory_args* + .. versionadded:: 0.4.0 *logger_factory_args* """ return BoundLoggerLazyProxy( logger, @@ -207,22 +217,29 @@ def configure( Use `reset_defaults` to undo your changes. - :param processors: The processor chain. See :doc:`processors` for details. - :param wrapper_class: Class to use for wrapping loggers instead of - `structlog.BoundLogger`. See `standard-library`, :doc:`twisted`, and - `custom-wrappers`. - :param context_class: Class to be used for internal context keeping. The - default is a `dict` and since dictionaries are ordered as of Python - 3.6, there's few reasons to change this option. - :param logger_factory: Factory to be called to create a new logger that - shall be wrapped. - :param cache_logger_on_first_use: `wrap_logger` doesn't return an actual - wrapped logger but a proxy that assembles one when it's first used. If - this option is set to `True`, this assembled logger is cached. See - `performance`. - - .. versionadded:: 0.3.0 - *cache_logger_on_first_use* + Arguments: + + processors: The processor chain. See :doc:`processors` for details. + + wrapper_class: + Class to use for wrapping loggers instead of + `structlog.BoundLogger`. See `standard-library`, :doc:`twisted`, + and `custom-wrappers`. + + context_class: + Class to be used for internal context keeping. The default is a + `dict` and since dictionaries are ordered as of Python 3.6, there's + few reasons to change this option. + + logger_factory: + Factory to be called to create a new logger that shall be wrapped. + + cache_logger_on_first_use: + `wrap_logger` doesn't return an actual wrapped logger but a proxy + that assembles one when it's first used. If this option is set to + `True`, this assembled logger is cached. See `performance`. + + .. versionadded:: 0.3.0 *cache_logger_on_first_use* """ _CONFIG.is_configured = True @@ -251,7 +268,9 @@ def configure_once( It does *not* matter whether it was configured using `configure` or `configure_once` before. - Raises a `RuntimeWarning` if repeated configuration is attempted. + Raises: + + RuntimeWarning: if repeated configuration is attempted. """ if not _CONFIG.is_configured: configure( @@ -290,11 +309,10 @@ class BoundLoggerLazyProxy: The only points where a bound logger changes state are ``bind()``, ``unbind()``, and ``new()`` and that return the actual ``BoundLogger``. - If and only if configuration says so, that actual bound logger is - cached on first usage. + If and only if configuration says so, that actual bound logger is cached on + first usage. - .. versionchanged:: 0.4.0 - Added support for *logger_factory_args*. + .. versionchanged:: 0.4.0 Added support for *logger_factory_args*. """ def __init__( diff --git a/src/structlog/_frames.py b/src/structlog/_frames.py index 7db6a486..7a5fb6c3 100644 --- a/src/structlog/_frames.py +++ b/src/structlog/_frames.py @@ -40,10 +40,14 @@ def _find_first_app_frame_and_name( """ Remove all intra-structlog calls and return the relevant app frame. - :param additional_ignores: Additional names with which the first frame must - not start. + Arguments: - :returns: tuple of (frame, name) + additional_ignores: + Additional names with which the first frame must not start. + + Returns: + + tuple of (frame, name) """ ignores = ["structlog"] + (additional_ignores or []) f = sys._getframe() diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index 8a3a384f..b2e721b6 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -128,11 +128,14 @@ def make_filtering_bound_logger(min_level: int) -> type[FilteringBoundLogger]: - You *can* have (much) more fine-grained filtering by :ref:`writing a simple processor `. - :param min_level: The log level as an integer. You can use the constants - from `logging` like ``logging.INFO`` or pass the values directly. See - `this table from the logging docs - `_ for possible - values. + Arguments: + + min_level: + The log level as an integer. You can use the constants from + `logging` like ``logging.INFO`` or pass the values directly. See + `this table from the logging docs + `_ for + possible values. .. versionadded:: 20.2.0 .. versionchanged:: 21.1.0 The returned loggers are now pickleable. diff --git a/src/structlog/_output.py b/src/structlog/_output.py index 64dfb5e8..4c5efbf4 100644 --- a/src/structlog/_output.py +++ b/src/structlog/_output.py @@ -36,19 +36,21 @@ class PrintLogger: """ Print events into a file. - :param file: File to print to. (default: `sys.stdout`) + Arguments: + + file: File to print to. (default: `sys.stdout`) >>> from structlog import PrintLogger >>> PrintLogger().info("hello") hello - Useful if you follow - `current logging best practices `. + Useful if you follow `current logging best practices + `. Also very useful for testing and examples since `logging` is finicky in doctests. - .. versionchanged:: 22.1 + .. versionchanged:: 22.1.0 The implementation has been switched to use `print` for better monkeypatchability. """ @@ -120,7 +122,9 @@ class PrintLoggerFactory: To be used with `structlog.configure`\ 's ``logger_factory``. - :param file: File to print to. (default: `sys.stdout`) + Arguments: + + file: File to print to. (default: `sys.stdout`) Positional arguments are silently ignored. @@ -138,7 +142,9 @@ class WriteLogger: """ Write events into a file. - :param file: File to print to. (default: `sys.stdout`) + Arguments: + + file: File to print to. (default: `sys.stdout`) >>> from structlog import WriteLogger >>> WriteLogger().info("hello") @@ -152,7 +158,7 @@ class WriteLogger: A little faster and a little less versatile than `structlog.PrintLogger`. - .. versionadded:: 22.1 + .. versionadded:: 22.1.0 """ def __init__(self, file: TextIO | None = None): @@ -226,11 +232,13 @@ class WriteLoggerFactory: To be used with `structlog.configure`\ 's ``logger_factory``. - :param file: File to print to. (default: `sys.stdout`) + Arguments: + + file: File to print to. (default: `sys.stdout`) Positional arguments are silently ignored. - .. versionadded:: 22.1 + .. versionadded:: 22.1.0 """ def __init__(self, file: TextIO | None = None): @@ -244,12 +252,12 @@ class BytesLogger: r""" Writes bytes into a file. - :param file: File to print to. (default: `sys.stdout`\ ``.buffer``) + Arguments: + file: File to print to. (default: `sys.stdout`\ ``.buffer``) - Useful if you follow - `current logging best practices ` together with - a formatter that returns bytes (e.g. `orjson - `_). + Useful if you follow `current logging best practices + ` together with a formatter that returns bytes + (e.g. `orjson `_). .. versionadded:: 20.2.0 """ @@ -328,7 +336,9 @@ class BytesLoggerFactory: To be used with `structlog.configure`\ 's ``logger_factory``. - :param file: File to print to. (default: `sys.stdout`\ ``.buffer``) + Arguments: + + file: File to print to. (default: `sys.stdout`\ ``.buffer``) Positional arguments are silently ignored. diff --git a/src/structlog/_utils.py b/src/structlog/_utils.py index 28004e15..f03aeaea 100644 --- a/src/structlog/_utils.py +++ b/src/structlog/_utils.py @@ -20,9 +20,13 @@ def until_not_interrupted(f: Callable[..., Any], *args: Any, **kw: Any) -> Any: """ Retry until *f* succeeds or an exception that isn't caused by EINTR occurs. - :param f: A callable like a function. - :param *args: Positional arguments for *f*. - :param **kw: Keyword arguments for *f*. + Arguments: + + f: A callable like a function. + + *args: Positional arguments for *f*. + + **kw: Keyword arguments for *f*. """ while True: try: diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 1bc9bbf0..5561d24c 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -515,11 +515,14 @@ def get_default_level_styles(colors: bool = True) -> Any: home-grown :func:`~structlog.stdlib.add_log_level` you could do:: my_styles = ConsoleRenderer.get_default_level_styles() - my_styles["EVERYTHING_IS_ON_FIRE"] = my_styles["critical"] - renderer = ConsoleRenderer(level_styles=my_styles) + my_styles["EVERYTHING_IS_ON_FIRE"] = my_styles["critical"] renderer + = ConsoleRenderer(level_styles=my_styles) - :param colors: Whether to use colorful styles. This must match the - *colors* parameter to `ConsoleRenderer`. Default: `True`. + Arguments: + + colors: + Whether to use colorful styles. This must match the *colors* + parameter to `ConsoleRenderer`. Default: `True`. """ styles: Styles styles = _ColorfulStyles if colors else _PlainStyles diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 61b7216a..3d29faa9 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -63,16 +63,21 @@ class KeyValueRenderer: """ Render ``event_dict`` as a list of ``Key=repr(Value)`` pairs. - :param sort_keys: Whether to sort keys when formatting. - :param key_order: List of keys that should be rendered in this exact - order. Missing keys will be rendered as ``None``, extra keys depending - on *sort_keys* and the dict class. - :param drop_missing: When ``True``, extra keys in *key_order* will be - dropped rather than rendered as ``None``. - :param repr_native_str: When ``True``, :func:`repr()` is also applied - to native strings. - Setting this to ``False`` is useful if you want to have human-readable - non-ASCII output on Python 2. + Arguments: + + sort_keys: Whether to sort keys when formatting. + + key_order: + List of keys that should be rendered in this exact order. Missing + keys will be rendered as ``None``, extra keys depending on + *sort_keys* and the dict class. + + drop_missing: + When ``True``, extra keys in *key_order* will be dropped rather + than rendered as ``None``. + + repr_native_str: + When ``True``, :func:`repr()` is also applied to native strings. .. versionadded:: 0.2.0 *key_order* .. versionadded:: 16.1.0 *drop_missing* @@ -114,17 +119,27 @@ class LogfmtRenderer: .. _logfmt: https://brandur.org/logfmt - :param sort_keys: Whether to sort keys when formatting. - :param key_order: List of keys that should be rendered in this exact - order. Missing keys are rendered with empty values, extra keys - depending on *sort_keys* and the dict class. - :param drop_missing: When ``True``, extra keys in *key_order* will be - dropped rather than rendered with empty values. - :param bool_as_flag: When ``True``, render ``{"flag": True}`` as - ``flag``, instead of ``flag=true``. ``{"flag": False}`` is - always rendered as ``flag=false``. + Arguments: + + sort_keys: Whether to sort keys when formatting. + + key_order: + List of keys that should be rendered in this exact order. Missing + keys are rendered with empty values, extra keys depending on + *sort_keys* and the dict class. + + drop_missing: + When ``True``, extra keys in *key_order* will be dropped rather + than rendered with empty values. - :raises ValueError: If a key contains non printable or space characters. + bool_as_flag: + When ``True``, render ``{"flag": True}`` as ``flag``, instead of + ``flag=true``. ``{"flag": False}`` is always rendered as + ``flag=false``. + + Raises: + + ValueError: If a key contains non printable or space characters. .. versionadded:: 21.5.0 """ @@ -222,14 +237,16 @@ class UnicodeEncoder: """ Encode unicode values in ``event_dict``. - :param encoding: Encoding to encode to (default: ``"utf-8"``). - :param errors: How to cope with encoding errors (default - ``"backslashreplace"``). + Arguments: + + encoding: Encoding to encode to (default: ``"utf-8"``). - Useful if you're running Python 2 as otherwise ``u"abc"`` will be rendered - as ``'u"abc"'``. + errors: + How to cope with encoding errors (default ``"backslashreplace"``). Just put it in the processor chain before the renderer. + + .. note:: Not very useful in a Python 3-only world. """ _encoding: str @@ -255,12 +272,13 @@ class UnicodeDecoder: """ Decode byte string values in ``event_dict``. - :param encoding: Encoding to decode from (default: ``"utf-8"``). - :param errors: How to cope with encoding errors (default: - ``"replace"``). + Arguments: + + encoding: Encoding to decode from (default: ``"utf-8"``). + + errors: How to cope with encoding errors (default: ``"replace"``). - Useful if you're running Python 3 as otherwise ``b"abc"`` will be rendered - as ``'b"abc"'``. + Useful to prevent ``b"abc"`` being rendered as as ``'b"abc"'``. Just put it in the processor chain before the renderer. @@ -290,24 +308,23 @@ class JSONRenderer: """ Render the ``event_dict`` using ``serializer(event_dict, **dumps_kw)``. - :param dumps_kw: Are passed unmodified to *serializer*. If *default* - is passed, it will disable support for ``__structlog__``-based - serialization. - :param serializer: A :func:`json.dumps`-compatible callable that - will be used to format the string. This can be used to use alternative - JSON encoders like `orjson `__ or - `RapidJSON `_ (default: - :func:`json.dumps`). + Arguments: - .. versionadded:: 0.2.0 - Support for ``__structlog__`` serialization method. + dumps_kw: + Are passed unmodified to *serializer*. If *default* is passed, it + will disable support for ``__structlog__``-based serialization. - .. versionadded:: 15.4.0 - *serializer* parameter. + serializer: + A :func:`json.dumps`-compatible callable that will be used to + format the string. This can be used to use alternative JSON + encoders like `orjson `__ or + `RapidJSON `_ + (default: :func:`json.dumps`). + .. versionadded:: 0.2.0 Support for ``__structlog__`` serialization method. + .. versionadded:: 15.4.0 *serializer* parameter. .. versionadded:: 18.2.0 Serializer's *default* parameter can be overwritten now. - """ def __init__( @@ -365,13 +382,16 @@ class ExceptionRenderer: 3. If the value true but no tuple, obtain exc_info ourselves and render that. - If there is no ``exc_info`` key, the *event_dict* is not touched. - This behavior is analogue to the one of the stdlib's logging. + If there is no ``exc_info`` key, the *event_dict* is not touched. This + behavior is analogue to the one of the stdlib's logging. + + Arguments: - :param exception_formatter: A callable that is used to format the exception - from the ``exc_info`` field. + exception_formatter: + A callable that is used to format the exception from the + ``exc_info`` field. - .. versionadded:: 22.1 + .. versionadded:: 22.1.0 """ def __init__( @@ -419,7 +439,7 @@ def __call__( The treatment of the ``exc_info`` key is identical to `format_exc_info`. -.. versionadded:: 22.1 +.. versionadded:: 22.1.0 """ @@ -427,13 +447,18 @@ class TimeStamper: """ Add a timestamp to ``event_dict``. - :param fmt: strftime format string, or ``"iso"`` for `ISO 8601 - `_, or `None` for a `UNIX - timestamp `_. - :param utc: Whether timestamp should be in UTC or local time. - :param key: Target key in *event_dict* for added timestamps. + Arguments: + + fmt: + strftime format string, or ``"iso"`` for `ISO 8601 + `_, or `None` for a `UNIX + timestamp `_. + + utc: Whether timestamp should be in UTC or local time. + + key: Target key in *event_dict* for added timestamps. - .. versionchanged:: 19.2 Can be pickled now. + .. versionchanged:: 19.2.0 Can be pickled now. """ __slots__ = ("_stamper", "fmt", "utc", "key") @@ -571,13 +596,15 @@ class ExceptionPrettyPrinter: """ Pretty print exceptions and remove them from the ``event_dict``. - :param file: Target file for output (default: ``sys.stdout``). + Arguments: + + file: Target file for output (default: ``sys.stdout``). This processor is mostly for development and testing so you can read exceptions properly formatted. - It behaves like `format_exc_info` except it removes the exception - data from the event dictionary after printing it. + It behaves like `format_exc_info` except it removes the exception data from + the event dictionary after printing it. It's tolerant to having `format_exc_info` in front of itself in the processor chain but doesn't require it. In other words, it handles both @@ -622,13 +649,17 @@ class StackInfoRenderer: involving an exception and works analogously to the *stack_info* argument of the Python standard library logging. - :param additional_ignores: By default, stack frames coming from - *structlog* are ignored. With this argument you can add additional - names that are ignored, before the stack starts being rendered. They - are matched using ``startswith()``, so they don't have to match - exactly. The names are used to find the first relevant name, therefore - once a frame is found that doesn't start with *structlog* or one of - *additional_ignores*, **no filtering** is applied to subsequent frames. + Arguments: + + additional_ignores: + By default, stack frames coming from *structlog* are ignored. With + this argument you can add additional names that are ignored, before + the stack starts being rendered. They are matched using + ``startswith()``, so they don't have to match exactly. The names + are used to find the first relevant name, therefore once a frame is + found that doesn't start with *structlog* or one of + *additional_ignores*, **no filtering** is applied to subsequent + frames. .. versionadded:: 0.4.0 .. versionadded:: 22.1.0 *additional_ignores* @@ -706,15 +737,18 @@ class CallsiteParameterAdder: The keys used for callsite parameters in the event dictionary are the string values of `CallsiteParameter` enum members. - :param parameters: - A collection of `CallsiteParameter` values that should be added to the - event dictionary. + Arguments: + + parameters: + A collection of `CallsiteParameter` values that should be added to + the event dictionary. - :param additional_ignores: - Additional names with which a stack frame's module name must not - start for it to be considered when determening the callsite. + additional_ignores: + Additional names with which a stack frame's module name must not + start for it to be considered when determening the callsite. .. note:: + When used with `structlog.stdlib.ProcessorFormatter` the most efficient configuration is to either use this processor in ``foreign_pre_chain`` of `structlog.stdlib.ProcessorFormatter` and in ``processors`` of @@ -838,12 +872,15 @@ class EventRenamer: some processors may rely on the presence and meaning of the ``event`` key. - :param to: Rename ``event_dict["event"]`` to ``event_dict[to]`` - :param replace_by: Rename ``event_dict[replace_by]`` to - ``event_dict["event"]``. *replace_by* missing from ``event_dict`` is - handled gracefully. + Arguments: + + to: Rename ``event_dict["event"]`` to ``event_dict[to]`` + + replace_by: + Rename ``event_dict[replace_by]`` to ``event_dict["event"]``. + *replace_by* missing from ``event_dict`` is handled gracefully. - .. versionadded:: 22.1 + .. versionadded:: 22.1.0 See also the :ref:`rename-event` recipe. """ diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index ea6a7124..9de32fd9 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -55,16 +55,18 @@ def recreate_defaults(*, log_level: int | None = logging.NOTSET) -> None: As with vanilla defaults, the backwards-compatibility guarantees don't apply to the settings applied here. - :param log_level: If `None`, don't configure standard library logging **at - all**. + Arguments: - Otherwise configure it to log to `sys.stdout` at *log_level* - (``logging.NOTSET`` being the default). + log_level: + If `None`, don't configure standard library logging **at all**. - If you need more control over `logging`, pass `None` here and configure - it yourself. + Otherwise configure it to log to `sys.stdout` at *log_level* + (``logging.NOTSET`` being the default). - .. versionadded:: 22.1 + If you need more control over `logging`, pass `None` here and + configure it yourself. + + .. versionadded:: 22.1.0 """ if log_level is not None: kw = {"force": True} @@ -147,7 +149,9 @@ def unbind(self, *keys: str) -> BoundLogger: """ Return a new logger with *keys* removed from the context. - :raises KeyError: If the key is not part of the context. + Raises: + + KeyError: If the key is not part of the context. """ return super().unbind(*keys) # type: ignore[return-value] @@ -484,15 +488,16 @@ class AsyncBoundLogger: Only available for Python 3.7 and later. - :ivar structlog.stdlib.BoundLogger sync_bl: The wrapped synchronous logger. - It is useful to be able to log synchronously occasionally. - .. versionadded:: 20.2.0 .. versionchanged:: 20.2.0 fix _dispatch_to_sync contextvars usage + .. deprecated:: 23.1.0 + Use the regular `BoundLogger` with its a-prefixed methods instead. """ __slots__ = ("sync_bl", "_loop") + #: The wrapped synchronous logger. It is useful to be able to log + #: synchronously occasionally. sync_bl: BoundLogger # Blatant lie, we use a property for _context. Need this for Protocol @@ -637,11 +642,14 @@ class LoggerFactory: >>> from structlog.stdlib import LoggerFactory >>> configure(logger_factory=LoggerFactory()) - :param ignore_frame_names: When guessing the name of a logger, skip frames - whose names *start* with one of these. For example, in pyramid - applications you'll want to set it to - ``["venusian", "pyramid.config"]``. This argument is - called *additional_ignores* in other APIs throughout *structlog*. + Arguments: + + ignore_frame_names: + When guessing the name of a logger, skip frames whose names *start* + with one of these. For example, in pyramid applications you'll + want to set it to ``["venusian", "pyramid.config"]``. This argument + is called *additional_ignores* in other APIs throughout + *structlog*. """ def __init__(self, ignore_frame_names: list[str] | None = None): @@ -793,12 +801,15 @@ class ExtraAdder: This processor can be used for adding data passed in the ``extra`` parameter of the `logging` module's log methods to the event dictionary. - :param allow: An optional collection of attributes that, if present in - `logging.LogRecord` objects, will be copied to event dictionaries. + Arguments: + + allow: + An optional collection of attributes that, if present in + `logging.LogRecord` objects, will be copied to event dictionaries. - If ``allow`` is None all attributes of `logging.LogRecord` objects that - do not exist on a standard `logging.LogRecord` object will be copied to - event dictionaries. + If ``allow`` is None all attributes of `logging.LogRecord` objects + that do not exist on a standard `logging.LogRecord` object will be + copied to event dictionaries. .. versionadded:: 21.5.0 """ @@ -855,8 +866,9 @@ def render_to_log_kwargs( This allows you to defer formatting to `logging`. .. versionadded:: 17.1.0 - .. versionchanged:: 22.1.0 ``exc_info``, ``stack_info``, and ``stackLevel`` - are passed as proper kwargs and not put into ``extra``. + .. versionchanged:: 22.1.0 + ``exc_info``, ``stack_info``, and ``stackLevel`` are passed as proper + kwargs and not put into ``extra``. """ return { "msg": event_dict.pop("event"), @@ -881,56 +893,67 @@ class ProcessorFormatter(logging.Formatter): Please refer to :ref:`processor-formatter` for examples. - :param foreign_pre_chain: - If not `None`, it is used as a processor chain that is applied to - **non**-*structlog* log entries before the event dictionary is passed - to *processors*. (default: `None`) - :param processors: - A chain of *structlog* processors that is used to process **all** log - entries. The last one must render to a `str` which then gets passed on - to `logging` for output. - - Compared to *structlog*'s regular processor chains, there's a few - differences: - - - The event dictionary contains two additional keys: - - #. ``_record``: a `logging.LogRecord` that either was created using - `logging` APIs, **or** is a wrapped *structlog* log entry - created by `wrap_for_formatter`. - #. ``_from_structlog``: a `bool` that indicates whether or not - ``_record`` was created by a *structlog* logger. - - Since you most likely don't want ``_record`` and - ``_from_structlog`` in your log files, we've added - the static method `remove_processors_meta` to ``ProcessorFormatter`` - that you can add just before your renderer. - - - Since this is a `logging` *formatter*, raising `structlog.DropEvent` - will crash your application. - - :param keep_exc_info: ``exc_info`` on `logging.LogRecord`\ s is - added to the ``event_dict`` and removed afterwards. Set this to - ``True`` to keep it on the `logging.LogRecord`. (default: False) - :param keep_stack_info: Same as *keep_exc_info* except for ``stack_info``. - (default: False) - :param logger: Logger which we want to push through the *structlog* - processor chain. This parameter is necessary for some of the - processors like `filter_by_level`. (default: None) - :param pass_foreign_args: If True, pass a foreign log record's - ``args`` attribute to the ``event_dict`` under ``positional_args`` key. - (default: False) - :param processor: - A single *structlog* processor used for rendering the event - dictionary before passing it off to `logging`. Must return a `str`. - The event dictionary does **not** contain ``_record`` and - ``_from_structlog``. - - This parameter exists for historic reasons. Please consider using - *processors* instead. - - :raises TypeError: If both or neither *processor* and *processors* are - passed. + Arguments: + + foreign_pre_chain: + If not `None`, it is used as a processor chain that is applied to + **non**-*structlog* log entries before the event dictionary is + passed to *processors*. (default: `None`) + + processors: + A chain of *structlog* processors that is used to process **all** + log entries. The last one must render to a `str` which then gets + passed on to `logging` for output. + + Compared to *structlog*'s regular processor chains, there's a few + differences: + + - The event dictionary contains two additional keys: + + #. ``_record``: a `logging.LogRecord` that either was created + using `logging` APIs, **or** is a wrapped *structlog* log + entry created by `wrap_for_formatter`. + + #. ``_from_structlog``: a `bool` that indicates whether or not + ``_record`` was created by a *structlog* logger. + + Since you most likely don't want ``_record`` and + ``_from_structlog`` in your log files, we've added the static + method `remove_processors_meta` to ``ProcessorFormatter`` that + you can add just before your renderer. + + - Since this is a `logging` *formatter*, raising + `structlog.DropEvent` will crash your application. + + keep_exc_info: + ``exc_info`` on `logging.LogRecord`\ s is added to the + ``event_dict`` and removed afterwards. Set this to ``True`` to keep + it on the `logging.LogRecord`. (default: False) + + keep_stack_info: + Same as *keep_exc_info* except for ``stack_info``. (default: False) + + logger: + Logger which we want to push through the *structlog* processor + chain. This parameter is necessary for some of the processors like + `filter_by_level`. (default: None) + + pass_foreign_args: + If True, pass a foreign log record's ``args`` attribute to the + ``event_dict`` under ``positional_args`` key. (default: False) + + processor: + A single *structlog* processor used for rendering the event + dictionary before passing it off to `logging`. Must return a `str`. + The event dictionary does **not** contain ``_record`` and + ``_from_structlog``. + + This parameter exists for historic reasons. Please use *processors* + instead. + + Raises: + + TypeError: If both or neither *processor* and *processors* are passed. .. versionadded:: 17.1.0 .. versionadded:: 17.2.0 *keep_exc_info* and *keep_stack_info* diff --git a/src/structlog/testing.py b/src/structlog/testing.py index 34c62f94..8f5c093a 100644 --- a/src/structlog/testing.py +++ b/src/structlog/testing.py @@ -139,9 +139,13 @@ class CapturedCall(NamedTuple): Can also be unpacked like a tuple. - :param method_name: The method name that got called. - :param args: A tuple of the positional arguments. - :param kwargs: A dict of the keyword arguments. + Arguments: + + method_name: The method name that got called. + + args: A tuple of the positional arguments. + + kwargs: A dict of the keyword arguments. .. versionadded:: 20.2.0 """ diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index 62dc83a6..f57af92b 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -83,7 +83,9 @@ def wrap_dict(dict_class: type[Context]) -> type[Context]: The wrapped class and used to keep global in the current thread. - :param dict_class: Class used for keeping context. + Arguments: + + dict_class: Class used for keeping context. .. deprecated:: 22.1.0 """ @@ -104,10 +106,14 @@ def as_immutable(logger: TLLogger) -> TLLogger: """ Extract the context from a thread local logger into an immutable logger. - :param structlog.typing.BindableLogger logger: A logger with *possibly* - thread local state. + Arguments: + + logger (structlog.typing.BindableLogger): + A logger with *possibly* thread local state. + + Returns: - :returns: :class:`~structlog.BoundLogger` with an immutable context. + :class:`~structlog.BoundLogger` with an immutable context. .. deprecated:: 22.1.0 """ diff --git a/src/structlog/tracebacks.py b/src/structlog/tracebacks.py index 7f7b0ba9..bb9a2c5a 100644 --- a/src/structlog/tracebacks.py +++ b/src/structlog/tracebacks.py @@ -6,9 +6,10 @@ """ Extract a structured traceback from an exception. -Contributed by Will McGugan (see -https://github.com/hynek/structlog/pull/407#issuecomment-1150926246) from Rich: -https://github.com/Textualize/rich/blob/972dedff/rich/traceback.py +`Contributed by Will McGugan +`_ from +`rich.traceback +`_. """ from __future__ import annotations @@ -126,18 +127,25 @@ def extract( """ Extract traceback information. - :param exc_type: Exception type. - :param exc_value: Exception value. - :param traceback: Python Traceback object. - :param show_locals: Enable display of local variables. Defaults to False. - :param locals_max_string: Maximum length of string before truncating, or - ``None`` to disable. - :param max_frames: Maximum number of frames in each stack + Arguments: - :returns: A Trace instance with structured information about all - exceptions. + exc_type: Exception type. - .. versionadded:: 22.1 + exc_value: Exception value. + + traceback: Python Traceback object. + + show_locals: Enable display of local variables. Defaults to False. + + locals_max_string: + Maximum length of string before truncating, or ``None`` to disable. + + max_frames: Maximum number of frames in each stack + + Returns: + A Trace instance with structured information about all exceptions. + + .. versionadded:: 22.1.0 """ stacks: list[Stack] = [] @@ -212,16 +220,22 @@ class ExceptionDictTransformer: These dictionaries are based on :class:`Stack` instances generated by :func:`extract()` and can be dumped to JSON. - :param show_locals: Whether or not to include the values of a stack frame's - local variables. - :param locals_max_string: The maximum length after which long string - representations are truncated. - :param max_frames: Maximum number of frames in each stack. Frames are - removed from the inside out. The idea is, that the first frames - represent your code responsible for the exception and last frames the - code where the exception actually happened. With larger web - frameworks, this does not always work, so you should stick with the - default. + Arguments: + + show_locals: + Whether or not to include the values of a stack frame's local + variables. + + locals_max_string: + The maximum length after which long string representations are + truncated. + + max_frames: + Maximum number of frames in each stack. Frames are removed from + the inside out. The idea is, that the first frames represent your + code responsible for the exception and last frames the code where + the exception actually happened. With larger web frameworks, this + does not always work, so you should stick with the default. """ def __init__( diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index 84239d1c..64f7b386 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -204,7 +204,9 @@ class PlainFileLogObserver: Great to just print JSON to stdout where you catch it with something like runit. - :param file: File to print to. + Arguments: + + file: File to print to. .. versionadded:: 0.2.0 """ @@ -227,10 +229,13 @@ class JSONLogObserverWrapper: """ Wrap a log *observer* and render non-`JSONRenderer` entries to JSON. - :param ILogObserver observer: Twisted log observer to wrap. For example - :class:`PlainFileObserver` or Twisted's stock `FileLogObserver - `_ + Arguments: + + observer (ILogObserver): + Twisted log observer to wrap. For example + :class:`PlainFileObserver` or Twisted's stock `FileLogObserver + `_ .. versionadded:: 0.2.0 """ @@ -288,8 +293,11 @@ class EventAdapter: `_ behave as expected. - :param dictRenderer: Renderer that is used for the actual log message. - Please note that structlog comes with a dedicated `JSONRenderer`. + Arguments: + + dictRenderer: + Renderer that is used for the actual log message. Please note that + structlog comes with a dedicated `JSONRenderer`. **Must** be the last processor in the chain and requires a *dictRenderer* for the actual formatting as an constructor argument in order to be able to @@ -301,9 +309,6 @@ def __init__( dictRenderer: Callable[[WrappedLogger, str, EventDict], str] | None = None, ) -> None: - """ - :param dictRenderer: A processor used to format the log message. - """ self._dictRenderer = dictRenderer or _BUILTIN_DEFAULT_PROCESSORS[-1] def __call__( diff --git a/src/structlog/typing.py b/src/structlog/typing.py index c10e467a..66f6a7e0 100644 --- a/src/structlog/typing.py +++ b/src/structlog/typing.py @@ -9,7 +9,7 @@ For now, they are considered provisional. Especially `BindableLogger` will probably change to something more elegant. -.. versionadded:: 22.2 +.. versionadded:: 22.2.0 """ from __future__ import annotations @@ -38,7 +38,7 @@ *structlog* makes *no* assumptions about it. -.. versionadded:: 20.2 +.. versionadded:: 20.2.0 """ @@ -46,7 +46,7 @@ """ A dict-like context carrier. -.. versionadded:: 20.2 +.. versionadded:: 20.2.0 """ @@ -57,7 +57,7 @@ It's created by copying the configured `Context` but doesn't need to support copy itself. -.. versionadded:: 20.2 +.. versionadded:: 20.2.0 """ Processor = Callable[ @@ -69,14 +69,14 @@ See :doc:`processors`. -.. versionadded:: 20.2 +.. versionadded:: 20.2.0 """ ExcInfo = Tuple[Type[BaseException], BaseException, Optional[TracebackType]] """ An exception info tuple as returned by `sys.exc_info`. -.. versionadded:: 20.2 +.. versionadded:: 20.2.0 """ @@ -86,7 +86,7 @@ Used by `structlog.dev.ConsoleRenderer`. -.. versionadded:: 21.2 +.. versionadded:: 21.2.0 """ @@ -102,12 +102,16 @@ class ExceptionTransformer(Protocol): Used by `structlog.processors.format_exc_info()` and `structlog.processors.ExceptionPrettyPrinter`. - :param exc_info: Is the exception tuple to format + Arguments: - :returns: Anything that can be rendered by the last processor in your - chain, e.g., a string or a JSON-serializable structure. + exc_info: Is the exception tuple to format - .. versionadded:: 22.1 + Returns: + + Anything that can be rendered by the last processor in your chain, + for example, a string or a JSON-serializable structure. + + .. versionadded:: 22.1.0 """ def __call__(self, exc_info: ExcInfo) -> Any: @@ -120,7 +124,7 @@ class BindableLogger(Protocol): **Protocol**: Methods shared among all bound loggers and that are relied on by *structlog*. - .. versionadded:: 20.2 + .. versionadded:: 20.2.0 """ _context: Context @@ -145,8 +149,7 @@ class FilteringBoundLogger(BindableLogger, Protocol): The only way to instantiate one is using `make_filtering_bound_logger`. .. versionadded:: 20.2.0 - .. versionadded:: 22.2.0 - String interpolation using positional arguments. + .. versionadded:: 22.2.0 String interpolation using positional arguments. .. versionadded:: 22.2.0 Async variants ``alog()``, ``adebug()``, ``ainfo()``, and so forth. .. versionchanged:: 22.3.0 diff --git a/tests/test_processors.py b/tests/test_processors.py index d9363108..c8628302 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -1049,12 +1049,16 @@ def make_processor( supplied ``parameter_strings`` values and with the supplied ``additional_ignores`` values. - :param parameter_strings: - Strings for which corresponding ``CallsiteParameters`` should be - included in the resulting ``CallsiteParameterAdded``. - :param additional_ignores: - Used as ``additional_ignores`` for the resulting - ``CallsiteParameterAdded``. + Arguments: + + parameter_strings: + Strings for which corresponding ``CallsiteParameters`` should + be included in the resulting ``CallsiteParameterAdded``. + + additional_ignores: + + Used as ``additional_ignores`` for the resulting + ``CallsiteParameterAdded``. """ if parameter_strings is None: return CallsiteParameterAdder( @@ -1075,11 +1079,12 @@ def filter_parameters( Returns a set containing all ``CallsiteParameter`` members with values that are in ``parameter_strings``. - :param parameter_strings: - The parameters strings for which corresponding - ``CallsiteParameter`` members should be - returned. If this value is `None` then all - ``CallsiteParameter`` will be returned. + Arguments: + + parameter_strings: + The parameters strings for which corresponding + ``CallsiteParameter`` members should be returned. If this value + is `None` then all ``CallsiteParameter`` will be returned. """ if parameter_strings is None: return cls._all_parameters @@ -1097,9 +1102,11 @@ def filter_parameter_dict( Returns a dictionary that is equivalent to ``input`` but with all keys not in ``parameter_strings`` removed. - :param parameter_strings: - The keys to keep in the dictionary, if this value is ``None`` then - all keys matching ``cls.parameter_strings`` are kept. + Arguments: + + parameter_strings: + The keys to keep in the dictionary, if this value is ``None`` + then all keys matching ``cls.parameter_strings`` are kept. """ if parameter_strings is None: parameter_strings = cls.parameter_strings @@ -1115,9 +1122,11 @@ def get_callsite_parameters(cls, offset: int = 1) -> dict[str, object]: This function creates dictionary of callsite parameters for the line that is ``offset`` lines after the invocation of this function. - :param offset: - The amount of lines after the invocation of this function that - callsite parameters should be generated for. + Arguments: + + offset: + The amount of lines after the invocation of this function that + callsite parameters should be generated for. """ frame_info = inspect.stack()[1] frame_traceback = inspect.getframeinfo(frame_info[0]) diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index d097aa00..fa89a3b2 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -1133,10 +1133,6 @@ async def _abl(cl): return AsyncBoundLogger(cl, context={}, processors=[]) -@pytest.mark.skipif( - sys.version_info[:2] < (3, 7), - reason="AsyncBoundLogger is only for Python 3.7 and later.", -) class TestAsyncBoundLogger: def test_sync_bl(self, abl, cl): """ From bf3ee6f9decfbc562acf307e53013bcf6049ea00 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 8 Sep 2023 11:03:41 +0200 Subject: [PATCH 1067/1520] Embed video to make it stick out more --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 838cc7d9..4acc81e8 100644 --- a/README.md +++ b/README.md @@ -33,8 +33,8 @@ *structlog* is *the* production-ready logging solution for Python: -- **Simple**: At its core, everything is about **functions** that take and return **dictionaries** – all hidden behind **familiar APIs**. -- **Powerful**: Functions and dictionaries aren’t just simple, they’re also powerful. +- **Simple**: Everything is about **functions** that take and return **dictionaries** – all hidden behind **familiar APIs**. +- **Powerful**: Functions and dictionaries aren’t just simple but also powerful. *structlog* leaves *you* in control. - **Fast**: *structlog* is not hamstrung by designs of yore. Its flexibility comes not at the price of performance. @@ -86,10 +86,14 @@ A short explanation on *why* structured logging is good for you, and why *struct Once you feel inspired to try it out, check out our friendly [Getting Started tutorial](https://www.structlog.org/en/stable/getting-started.html). -If you prefer videos over reading, check out [Markus Holtermann](https://twitter.com/m_holtermann)'s DjangoCon Europe 2019 talk: [*Logging Rethought 2: The Actions of Frank Taylor Jr.*](https://www.youtube.com/watch?v=Y5eyEgyHLLo) - For a fully-fledged zero-to-hero tutorial, check out [*A Comprehensive Guide to Python Logging with structlog*](https://betterstack.com/community/guides/logging/structlog/). +If you prefer videos over reading, check out [Markus Holtermann](https://chaos.social/@markush)'s DjangoCon Europe 2019 talk *Logging Rethought 2: The Actions of Frank Taylor Jr.*: + +

    + +

    + ## Credits From 93bca8673ba022d41d841b28b4285f89955cca79 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 8 Sep 2023 11:07:02 +0200 Subject: [PATCH 1068/1520] Cheat-embed --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4acc81e8..e56784e8 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,9 @@ For a fully-fledged zero-to-hero tutorial, check out [*A Comprehensive Guide to If you prefer videos over reading, check out [Markus Holtermann](https://chaos.social/@markush)'s DjangoCon Europe 2019 talk *Logging Rethought 2: The Actions of Frank Taylor Jr.*:

    - + + +

    From 05e90467032f7a82a58b967a6e9df1804ae04489 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 8 Sep 2023 11:08:18 +0200 Subject: [PATCH 1069/1520] Don't link to embed --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e56784e8..58a5015b 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ For a fully-fledged zero-to-hero tutorial, check out [*A Comprehensive Guide to If you prefer videos over reading, check out [Markus Holtermann](https://chaos.social/@markush)'s DjangoCon Europe 2019 talk *Logging Rethought 2: The Actions of Frank Taylor Jr.*:

    - +

    From 38517141bee19428467b16f6d18ad0145077814d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 8 Sep 2023 11:09:58 +0200 Subject: [PATCH 1070/1520] Link points off PyPI --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 42d3bef4..d4e932e9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -221,7 +221,7 @@ pattern = "\n(###.+?\n)## " text = """ --- -[→ Full Changelog](https://www.structlog.org/en/stable/changelog.html) +[Full Changelog →](https://www.structlog.org/en/stable/changelog.html) """ From 88a25ef3455aa29a82ed4400075d50be808ad49d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 8 Sep 2023 11:20:03 +0200 Subject: [PATCH 1071/1520] Redo links --- README.md | 6 +++--- docs/index.md | 4 ++-- pyproject.toml | 5 +++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 58a5015b..300531aa 100644 --- a/README.md +++ b/README.md @@ -109,11 +109,11 @@ The logs-loving futuristic beaver logo has been contributed by [Russell Keith-Ma -## Project Information +## Project Links -- **Get Help**: please use the *structlog* tag on [*Stack Overflow*](https://stackoverflow.com/questions/tagged/structlog) +- [**Get Help**](https://stackoverflow.com/questions/tagged/structlog) (use the *structlog* tag on Stack Overflow) - [**PyPI**](https://pypi.org/project/structlog/) -- [**Source Code**](https://github.com/hynek/structlog) +- [**GitHub**](https://github.com/hynek/structlog) - [**Documentation**](https://www.structlog.org/) - [**Changelog**](https://www.structlog.org/en/stable/changelog.html) - [**Third-party Extensions**](https://github.com/hynek/structlog/wiki/Third-party-Extensions) diff --git a/docs/index.md b/docs/index.md index e3cdec7a..dbbcee5e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -100,10 +100,10 @@ api ``` -## Project Information +## Project Links ```{include} ../README.md -:start-after: "## Project Information" +:start-after: "## Project Links" ``` % stop Sphinx from complaining about orphaned docs, we link them elsewhere diff --git a/pyproject.toml b/pyproject.toml index d4e932e9..6dc06d86 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,10 +33,11 @@ dependencies = [] [project.urls] Documentation = "https://www.structlog.org/" Changelog = "https://www.structlog.org/en/stable/changelog.html" -"Bug Tracker" = "https://github.com/hynek/structlog/issues" -"Source Code" = "https://github.com/hynek/structlog" +GitHub = "https://github.com/hynek/structlog" Funding = "https://github.com/sponsors/hynek" Tidelift = "https://tidelift.com/subscription/pkg/pypi-structlog?utm_source=pypi-structlog&utm_medium=pypi" +Mastodon = "https://mastodon.social/@hynek" +Twitter = "https://twitter.com/hynek" [project.optional-dependencies] tests = [ From 8abe048dfc31dad894cc9e21e72ea366a76d6697 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 8 Sep 2023 14:40:39 +0200 Subject: [PATCH 1072/1520] Simplify troves --- pyproject.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 6dc06d86..0d63bbed 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,14 +17,11 @@ classifiers = [ "Development Status :: 5 - Production/Stable", "License :: OSI Approved :: Apache Software License", "License :: OSI Approved :: MIT License", - "Operating System :: OS Independent", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: Implementation :: CPython", - "Programming Language :: Python :: Implementation :: PyPy", "Topic :: System :: Logging", "Typing :: Typed", ] From 0558ea11fedc613030bc4d5570d0b528a5a51739 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 8 Sep 2023 14:46:04 +0200 Subject: [PATCH 1073/1520] Shrink preview --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 300531aa..c99e57d3 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ If you prefer videos over reading, check out [Markus Holtermann](https://chaos.s

    - +

    From 924941ed506da96b79c14ae83b5c362f1f16505d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 8 Sep 2023 14:46:41 +0200 Subject: [PATCH 1074/1520] Once is enough --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c99e57d3..a6313369 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ Once you feel inspired to try it out, check out our friendly [Getting Started tu For a fully-fledged zero-to-hero tutorial, check out [*A Comprehensive Guide to Python Logging with structlog*](https://betterstack.com/community/guides/logging/structlog/). -If you prefer videos over reading, check out [Markus Holtermann](https://chaos.social/@markush)'s DjangoCon Europe 2019 talk *Logging Rethought 2: The Actions of Frank Taylor Jr.*: +If you prefer videos over reading, check out [Markus Holtermann](https://chaos.social/@markush)'s talk *Logging Rethought 2: The Actions of Frank Taylor Jr.*:

    From b2f245de6bc2e4a4eb467d70f299bf0338b3c2fa Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 8 Sep 2023 14:53:05 +0200 Subject: [PATCH 1075/1520] Don't re-render changelog --- docs/changelog.md | 2 -- docs/index.md | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) delete mode 100644 docs/changelog.md diff --git a/docs/changelog.md b/docs/changelog.md deleted file mode 100644 index 66efc0fe..00000000 --- a/docs/changelog.md +++ /dev/null @@ -1,2 +0,0 @@ -```{include} ../CHANGELOG.md -``` diff --git a/docs/index.md b/docs/index.md index dbbcee5e..e40fb353 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,7 +2,7 @@ *Simple. Powerful. Fast. Pick three.* -Release **{sub-ref}`release`** ([What's new?](changelog)) +Release **{sub-ref}`release`** ([What's new?](https://github.com/hynek/structlog/blob/main/CHANGELOG.md)) --- @@ -112,7 +112,6 @@ api :hidden: true license -changelog ``` From 5361f7e63e7ba622d3406b0c982854dcdfc4a52e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 8 Sep 2023 14:56:10 +0200 Subject: [PATCH 1076/1520] Try something --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 858080b8..ae4739be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,7 +23,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ### Added - Official support for Python 3.12. - [#515](https://github.com/hynek/structlog/issues/515) + #515 - `structlog.processors.MaybeTimeStamper` that only adds a timestamp if there isn't one already. [#81](https://github.com/hynek/structlog/issues/81) From e88bb3932dd336b981e416dd422efe5a64846187 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 8 Sep 2023 14:56:30 +0200 Subject: [PATCH 1077/1520] Revert "Try something" This reverts commit 5361f7e63e7ba622d3406b0c982854dcdfc4a52e. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae4739be..858080b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,7 +23,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ### Added - Official support for Python 3.12. - #515 + [#515](https://github.com/hynek/structlog/issues/515) - `structlog.processors.MaybeTimeStamper` that only adds a timestamp if there isn't one already. [#81](https://github.com/hynek/structlog/issues/81) From 5a8f675a42de957c3d12c607a931afa3561f43cb Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 8 Sep 2023 16:35:24 +0200 Subject: [PATCH 1078/1520] Replace Tidelift links --- README.md | 6 +++--- pyproject.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a6313369..ae876ffc 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ Especially those generously supporting us at the *The Organization* tier and hig - + @@ -102,7 +102,7 @@ If you prefer videos over reading, check out [Markus Holtermann](https://chaos.s *structlog* is written and maintained by [Hynek Schlawack](https://hynek.me/). The idea of bound loggers is inspired by previous work by [Jean-Paul Calderone](https://github.com/exarkun) and [David Reid](https://github.com/dreid). -The development is kindly supported by my employer [Variomedia AG](https://www.variomedia.de/), *structlog*’s [Tidelift subscribers](https://tidelift.com/subscription/pkg/pypi-structlog?utm_source=pypi-structlog&utm_medium=referral&utm_campaign=readme), and all my amazing [GitHub Sponsors](https://github.com/sponsors/hynek). +The development is kindly supported by my employer [Variomedia AG](https://www.variomedia.de/), *structlog*’s [Tidelift subscribers](https://tidelift.com?utm_source=lifter&utm_medium=referral&utm_campaign=hynek), and all my amazing [GitHub Sponsors](https://github.com/sponsors/hynek). The logs-loving futuristic beaver logo has been contributed by [Russell Keith-Magee](https://github.com/freakboy3742). @@ -123,4 +123,4 @@ The logs-loving futuristic beaver logo has been contributed by [Russell Keith-Ma Available as part of the Tidelift Subscription. -The maintainers of *structlog* and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. [Learn more.](https://tidelift.com/subscription/pkg/pypi-structlog?utm_source=pypi-structlog&utm_medium=referral&utm_campaign=readme) +The maintainers of *structlog* and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. [Learn more.](https://tidelift.com?utm_source=lifter&utm_medium=referral&utm_campaign=hynek) diff --git a/pyproject.toml b/pyproject.toml index 0d63bbed..bfb279c4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,7 @@ Documentation = "https://www.structlog.org/" Changelog = "https://www.structlog.org/en/stable/changelog.html" GitHub = "https://github.com/hynek/structlog" Funding = "https://github.com/sponsors/hynek" -Tidelift = "https://tidelift.com/subscription/pkg/pypi-structlog?utm_source=pypi-structlog&utm_medium=pypi" +Tidelift = "https://tidelift.com?utm_source=lifter&utm_medium=referral&utm_campaign=hynek" Mastodon = "https://mastodon.social/@hynek" Twitter = "https://twitter.com/hynek" From 039d6d3e7832a04fce0f4456f5ecc3710ed4d64a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 8 Sep 2023 17:27:32 +0200 Subject: [PATCH 1079/1520] Fix missed doc strings --- src/structlog/dev.py | 107 ++++++++++++++++++++++------------------- src/structlog/types.py | 4 +- 2 files changed, 60 insertions(+), 51 deletions(-) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 5561d24c..816f9cef 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -254,7 +254,7 @@ def better_traceback(sio: TextIO, exc_info: ExcInfo) -> None: Used by default if *better-exceptions* is installed and Rich is absent. - .. versionadded:: 21.2 + .. versionadded:: 21.2.0 """ sio.write("\n" + "".join(better_exceptions.format_exception(*exc_info))) @@ -279,37 +279,43 @@ class ConsoleRenderer: pad_event: Pad the event to this many characters. - colors: Use colors for a nicer output. `True` by default. On - Windows only if Colorama_ is installed. - - force_colors: Force colors even for non-tty destinations. - Use this option if your logs are stored in a file that is meant to - be streamed to the console. Only meaningful on Windows. - - repr_native_str: When `True`, `repr` is also applied - to native strings (i.e. unicode on Python 3 and bytes on Python 2). - Setting this to `False` is useful if you want to have - human-readable non-ASCII output on Python 2. The ``event`` key is - *never* `repr` -ed. - - level_styles: When present, use these styles for colors. This - must be a dict from level names (strings) to Colorama styles. The - default can be obtained by calling - `ConsoleRenderer.get_default_level_styles` - - exception_formatter: A callable to render ``exc_infos``. If rich_ - or better-exceptions_ are installed, they are used for - pretty-printing by default (rich_ taking precedence). You can also - manually set it to `plain_traceback`, `better_traceback`, - `rich_traceback`, or implement your own. + colors: + Use colors for a nicer output. `True` by default. On Windows only + if Colorama_ is installed. + + force_colors: + Force colors even for non-tty destinations. Use this option if your + logs are stored in a file that is meant to be streamed to the + console. Only meaningful on Windows. + + repr_native_str: + When `True`, `repr` is also applied to native strings (i.e. unicode + on Python 3 and bytes on Python 2). Setting this to `False` is + useful if you want to have human-readable non-ASCII output on + Python 2. The ``event`` key is *never* `repr` -ed. + + level_styles: + When present, use these styles for colors. This must be a dict from + level names (strings) to Colorama styles. The default can be + obtained by calling `ConsoleRenderer.get_default_level_styles` + + exception_formatter: + A callable to render ``exc_infos``. If Rich_ or better-exceptions_ + are installed, they are used for pretty-printing by default (rich_ + taking precedence). You can also manually set it to + `plain_traceback`, `better_traceback`, an instance of + `RichTracebackFormatter` like `rich_traceback`, or implement your + own. sort_keys: Whether to sort keys when formatting. `True` by default. - event_key: The key to look for the main log message. Needed when - you rename it e.g. using `structlog.processors.EventRenamer`. + event_key: + The key to look for the main log message. Needed when you rename it + e.g. using `structlog.processors.EventRenamer`. - timestamp_key: The key to look for timestamp of the log message. Needed - when you rename it e.g. using `structlog.processors.EventRenamer`. + timestamp_key: + The key to look for timestamp of the log message. Needed when you + rename it e.g. using `structlog.processors.EventRenamer`. Requires the Colorama_ package if *colors* is `True` **on Windows**. @@ -317,29 +323,32 @@ class ConsoleRenderer: .. _better-exceptions: https://pypi.org/project/better-exceptions/ .. _Rich: https://pypi.org/project/rich/ - .. versionadded:: 16.0 - .. versionadded:: 16.1 *colors* - .. versionadded:: 17.1 *repr_native_str* - .. versionadded:: 18.1 *force_colors* - .. versionadded:: 18.1 *level_styles* - .. versionchanged:: 19.2 + .. versionadded:: 16.0.0 + .. versionadded:: 16.1.0 *colors* + .. versionadded:: 17.1.0 *repr_native_str* + .. versionadded:: 18.1.0 *force_colors* + .. versionadded:: 18.1.0 *level_styles* + .. versionchanged:: 19.2.0 Colorama now initializes lazily to avoid unwanted initializations as ``ConsoleRenderer`` is used by default. - .. versionchanged:: 19.2 Can be pickled now. - .. versionchanged:: 20.1 Colorama does not initialize lazily on Windows - anymore because it breaks rendering. - .. versionchanged:: 21.1 It is additionally possible to set the logger name - using the ``logger_name`` key in the ``event_dict``. - .. versionadded:: 21.2 *exception_formatter* - .. versionchanged:: 21.2 `ConsoleRenderer` now handles the ``exc_info`` - event dict key itself. Do **not** use the - `structlog.processors.format_exc_info` processor together with - `ConsoleRenderer` anymore! It will keep working, but you can't have - customize exception formatting and a warning will be raised if you ask - for it. - .. versionchanged:: 21.2 The colors keyword now defaults to True on - non-Windows systems, and either True or False in Windows depending on - whether Colorama is installed. + .. versionchanged:: 19.2.0 Can be pickled now. + .. versionchanged:: 20.1.0 + Colorama does not initialize lazily on Windows anymore because it breaks + rendering. + .. versionchanged:: 21.1.0 + It is additionally possible to set the logger name using the + ``logger_name`` key in the ``event_dict``. + .. versionadded:: 21.2.0 *exception_formatter* + .. versionchanged:: 21.2.0 + `ConsoleRenderer` now handles the ``exc_info`` event dict key itself. Do + **not** use the `structlog.processors.format_exc_info` processor + together with `ConsoleRenderer` anymore! It will keep working, but you + can't have customize exception formatting and a warning will be raised + if you ask for it. + .. versionchanged:: 21.2.0 + The colors keyword now defaults to True on non-Windows systems, and + either True or False in Windows depending on whether Colorama is + installed. .. versionadded:: 21.3.0 *sort_keys* .. versionadded:: 22.1.0 *event_key* .. versionadded:: 23.2.0 *timestamp_key* diff --git a/src/structlog/types.py b/src/structlog/types.py index e7cbe115..5d79fd5d 100644 --- a/src/structlog/types.py +++ b/src/structlog/types.py @@ -6,8 +6,8 @@ """ Deprecated name for :mod:`structlog.typing`. -.. versionadded:: 20.2 -.. deprecated:: 22.2 +.. versionadded:: 20.2.0 +.. deprecated:: 22.2.0 """ from __future__ import annotations From bb10cbbd007c222a55c7c1e63042fc2b3e683e1d Mon Sep 17 00:00:00 2001 From: wim glenn Date: Wed, 13 Sep 2023 00:58:50 -0500 Subject: [PATCH 1080/1520] blacken stdlib example from docs (#552) --- docs/standard-library.md | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/docs/standard-library.md b/docs/standard-library.md index 7de07503..14c12c7f 100644 --- a/docs/standard-library.md +++ b/docs/standard-library.md @@ -421,10 +421,10 @@ formatter = structlog.stdlib.ProcessorFormatter( foreign_pre_chain=shared_processors, # These run on ALL entries after the pre_chain is done. processors=[ - # Remove _record & _from_structlog. - structlog.stdlib.ProcessorFormatter.remove_processors_meta, - structlog.dev.ConsoleRenderer(), - ], + # Remove _record & _from_structlog. + structlog.stdlib.ProcessorFormatter.remove_processors_meta, + structlog.dev.ConsoleRenderer(), + ], ) ``` @@ -456,6 +456,7 @@ pre_chain = [ timestamper, ] + def extract_from_record(_, __, event_dict): """ Extract thread and process names and add them to the event dict. @@ -463,27 +464,28 @@ def extract_from_record(_, __, event_dict): record = event_dict["_record"] event_dict["thread_name"] = record.threadName event_dict["process_name"] = record.processName - return event_dict -logging.config.dictConfig({ + +logging.config.dictConfig( + { "version": 1, "disable_existing_loggers": False, "formatters": { "plain": { "()": structlog.stdlib.ProcessorFormatter, "processors": [ - structlog.stdlib.ProcessorFormatter.remove_processors_meta, - structlog.dev.ConsoleRenderer(colors=False), + structlog.stdlib.ProcessorFormatter.remove_processors_meta, + structlog.dev.ConsoleRenderer(colors=False), ], "foreign_pre_chain": pre_chain, }, "colored": { "()": structlog.stdlib.ProcessorFormatter, "processors": [ - extract_from_record, - structlog.stdlib.ProcessorFormatter.remove_processors_meta, - structlog.dev.ConsoleRenderer(colors=True), + extract_from_record, + structlog.stdlib.ProcessorFormatter.remove_processors_meta, + structlog.dev.ConsoleRenderer(colors=True), ], "foreign_pre_chain": pre_chain, }, @@ -507,8 +509,9 @@ logging.config.dictConfig({ "level": "DEBUG", "propagate": True, }, - } -}) + }, + } +) structlog.configure( processors=[ structlog.stdlib.add_log_level, From 21f1fef9db684077c049f8bcda48c7c1bdcfd72a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 17 Sep 2023 13:10:20 +0200 Subject: [PATCH 1081/1520] Add chapter on exception handling fixes #474 --- docs/console-output.md | 5 ++++ docs/exceptions.md | 55 +++++++++++++++++++++++++++++++++++++ docs/index.md | 1 + src/structlog/processors.py | 32 ++++++++++++++------- src/structlog/tracebacks.py | 4 +++ 5 files changed, 87 insertions(+), 10 deletions(-) create mode 100644 docs/exceptions.md diff --git a/docs/console-output.md b/docs/console-output.md index 53ac6748..aa5fbb60 100644 --- a/docs/console-output.md +++ b/docs/console-output.md @@ -46,6 +46,11 @@ structlog.configure( ) ``` +:::{seealso} +{doc}`exceptions` for more information on how to configure exception rendering. +For the console and beyond. +::: + ## Standard Environment Variables diff --git a/docs/exceptions.md b/docs/exceptions.md new file mode 100644 index 00000000..534d8a48 --- /dev/null +++ b/docs/exceptions.md @@ -0,0 +1,55 @@ +# Exceptions + +While you should use a proper crash reporter like our sponsor [Sentry](https://sentry.io) in production, *structlog* has helpers for formatting exceptions for humans and machines. + +All *structog*'s exception features center around passing an `exc_info` key-value pair in the event dict. +There are three possible behaviors depending on its value: + +1. If the value is a tuple, render it as if it was returned by {func}`sys.exc_info`. +2. If the value is an Exception, render it. +3. If the value is true but no tuple, call {func}`sys.exc_info` and render that. + +If there is no `exc_info` key or false, the event dict is not touched. +This behavior is analog to the one of the stdlib's logging. + + +## Transformations + +*structlog* comes with {class}`structlog.processors.ExceptionRenderer` that allows you to remove the `exc_info` key and transform it into an `exception` key of a different format. +The most common use-cases are already covered by the following processors: + +{func}`structlog.processors.format_exc_info` + +: Formats it to a flat string like the standard library would on the console. + +{obj}`structlog.processors.dict_tracebacks` + +: Uses {class}`structlog.tracebacks.ExceptionDictTransformer` to give you a structured and JSON-serializable `exception` key. + + +## Console Rendering + +Our {doc}`console-output`'s {class}`structlog.dev.ConsoleRenderer` takes an *exception_formatter* argument that allows for customizing the output of exceptions. + +{func}`structlog.dev.plain_traceback` + +: Is the default if neither [Rich] nor [*better-exceptions*] are installed. + As the name suggests, it renders a plain traceback. + +{func}`structlog.dev.better_traceback` + +: Uses [*better-exceptions*] to render a colorful traceback. +: It's the default if *better-exceptions* is installed and Rich is not. + +{class}`structlog.dev.RichTracebackFormatter` + +: Uses [Rich] to render a colorful traceback. + It's a class because it allows for customizing the output by passing arguments to Rich. +: It's the default if Rich is installed. + +:::{seealso} +{doc}`console-output` for more information on *structlog*'s console features. +::: + +[*better-exceptions*]: https://github.com/qix-/better-exceptions +[Rich]: https://github.com/Textualize/rich diff --git a/docs/index.md b/docs/index.md index e40fb353..a5baa8f1 100644 --- a/docs/index.md +++ b/docs/index.md @@ -37,6 +37,7 @@ bound-loggers configuration processors contextvars +exceptions ``` diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 3d29faa9..7b2377a7 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -367,12 +367,12 @@ class ExceptionRenderer: by *exception_formatter*. The contents of the ``exception`` field depends on the return value of the - :class:`.ExceptionTransformer` that is used: + *exception_formatter* that is passed: - The default produces a formatted string via Python's built-in traceback - formatting. - - The :class:`~structlog.tracebacks.ExceptionDictTransformer` a list of - stack dicts that can be serialized to JSON. + formatting (this is :obj:`.format_exc_info`). + - If you pass a :class:`~structlog.tracebacks.ExceptionDictTransformer`, it + becomes a list of stack dicts that can be serialized to JSON. If *event_dict* contains the key ``exc_info``, there are three possible behaviors: @@ -383,13 +383,17 @@ class ExceptionRenderer: that. If there is no ``exc_info`` key, the *event_dict* is not touched. This - behavior is analogue to the one of the stdlib's logging. + behavior is analog to the one of the stdlib's logging. Arguments: exception_formatter: A callable that is used to format the exception from the - ``exc_info`` field. + ``exc_info`` field into the ``exception`` field. + + .. seealso:: + :doc:`exceptions` for a broader explanation of *structlog*'s exception + features. .. versionadded:: 22.1.0 """ @@ -414,8 +418,8 @@ def __call__( format_exc_info = ExceptionRenderer() """ -Replace an ``exc_info`` field with an ``exception`` string field using -Python's built-in traceback formatting. +Replace an ``exc_info`` field with an ``exception`` string field using Python's +built-in traceback formatting. If *event_dict* contains the key ``exc_info``, there are three possible behaviors: @@ -425,8 +429,12 @@ def __call__( 3. If the value is true but no tuple, obtain exc_info ourselves and render that. -If there is no ``exc_info`` key, the *event_dict* is not touched. -This behavior is analogue to the one of the stdlib's logging. +If there is no ``exc_info`` key, the *event_dict* is not touched. This behavior +is analog to the one of the stdlib's logging. + +.. seealso:: + :doc:`exceptions` for a broader explanation of *structlog*'s exception + features. """ dict_tracebacks = ExceptionRenderer(ExceptionDictTransformer()) @@ -440,6 +448,10 @@ def __call__( The treatment of the ``exc_info`` key is identical to `format_exc_info`. .. versionadded:: 22.1.0 + +.. seealso:: + :doc:`exceptions` for a broader explanation of *structlog*'s exception + features. """ diff --git a/src/structlog/tracebacks.py b/src/structlog/tracebacks.py index bb9a2c5a..5fbd5447 100644 --- a/src/structlog/tracebacks.py +++ b/src/structlog/tracebacks.py @@ -236,6 +236,10 @@ class ExceptionDictTransformer: code responsible for the exception and last frames the code where the exception actually happened. With larger web frameworks, this does not always work, so you should stick with the default. + + .. seealso:: + :doc:`exceptions` for a broader explanation of *structlog*'s exception + features. """ def __init__( From 246a6c1cd1cd0e762b3de6f922a26eb3dc5b54a6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 17 Sep 2023 13:15:05 +0200 Subject: [PATCH 1082/1520] Add trailing slashes to prevent redirs --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ae876ffc..779d4aee 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ Especially those generously supporting us at the *The Organization* tier and hig - + @@ -102,7 +102,7 @@ If you prefer videos over reading, check out [Markus Holtermann](https://chaos.s *structlog* is written and maintained by [Hynek Schlawack](https://hynek.me/). The idea of bound loggers is inspired by previous work by [Jean-Paul Calderone](https://github.com/exarkun) and [David Reid](https://github.com/dreid). -The development is kindly supported by my employer [Variomedia AG](https://www.variomedia.de/), *structlog*’s [Tidelift subscribers](https://tidelift.com?utm_source=lifter&utm_medium=referral&utm_campaign=hynek), and all my amazing [GitHub Sponsors](https://github.com/sponsors/hynek). +The development is kindly supported by my employer [Variomedia AG](https://www.variomedia.de/), *structlog*’s [Tidelift subscribers](https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek), and all my amazing [GitHub Sponsors](https://github.com/sponsors/hynek). The logs-loving futuristic beaver logo has been contributed by [Russell Keith-Magee](https://github.com/freakboy3742). @@ -123,4 +123,4 @@ The logs-loving futuristic beaver logo has been contributed by [Russell Keith-Ma Available as part of the Tidelift Subscription. -The maintainers of *structlog* and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. [Learn more.](https://tidelift.com?utm_source=lifter&utm_medium=referral&utm_campaign=hynek) +The maintainers of *structlog* and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. [Learn more.](https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek) From 80bf6ce6723f6f44a12390bb24f7b0de4a1ee3af Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 17 Sep 2023 13:19:14 +0200 Subject: [PATCH 1083/1520] De-dup and complete tutorials/next steps --- README.md | 3 ++- docs/getting-started.md | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 779d4aee..372e8048 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,7 @@ A short explanation on *why* structured logging is good for you, and why *struct Once you feel inspired to try it out, check out our friendly [Getting Started tutorial](https://www.structlog.org/en/stable/getting-started.html). + For a fully-fledged zero-to-hero tutorial, check out [*A Comprehensive Guide to Python Logging with structlog*](https://betterstack.com/community/guides/logging/structlog/). If you prefer videos over reading, check out [Markus Holtermann](https://chaos.social/@markush)'s talk *Logging Rethought 2: The Actions of Frank Taylor Jr.*: @@ -95,7 +96,7 @@ If you prefer videos over reading, check out [Markus Holtermann](https://chaos.s

    - + ## Credits diff --git a/docs/getting-started.md b/docs/getting-started.md index 7628bd0c..71720f80 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -246,8 +246,10 @@ You can use the sync and async logging methods interchangeably within the same a Now you're all set for the rest of the user's guide and can start reading about [bound loggers](bound-loggers.md) -- the heart of *structlog*. -Or, if you prefer another, more in-depth tutorial, check out [*A Comprehensive Guide to Python Logging with structlog*](https://betterstack.com/community/guides/logging/structlog/). - +```{include} ../README.md +:start-after: +:end-before: +``` [*better-exceptions*]: https://github.com/qix-/better-exceptions [recipe]: https://docs.python.org/3/howto/logging-cookbook.html#implementing-structured-logging From 575e2a4cfe352daaa54731fe8c543de199930329 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 19 Sep 2023 09:41:06 +0200 Subject: [PATCH 1084/1520] docs: clarify --- docs/exceptions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/exceptions.md b/docs/exceptions.md index 534d8a48..329fe3b5 100644 --- a/docs/exceptions.md +++ b/docs/exceptions.md @@ -15,7 +15,7 @@ This behavior is analog to the one of the stdlib's logging. ## Transformations -*structlog* comes with {class}`structlog.processors.ExceptionRenderer` that allows you to remove the `exc_info` key and transform it into an `exception` key of a different format. +*structlog* comes with {class}`structlog.processors.ExceptionRenderer` that deduces and removes the `exc_info` key as outlined above, calls a user-supplied function with the synthesized `exc_info`, and stores its return value in the `exception` key. The most common use-cases are already covered by the following processors: {func}`structlog.processors.format_exc_info` From d8aebf965bb6b46fd3cedd18f51821bfbe704264 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 19 Sep 2023 09:59:16 +0200 Subject: [PATCH 1085/1520] Don't rely on monkeypatching for find caller test --- tests/test_stdlib.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index fa89a3b2..4e3c9f56 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -137,21 +137,17 @@ def test_no_stack_info_by_default(self): assert None is stack_info - def test_find_caller(self, monkeypatch): + def test_find_caller(self, caplog): """ The caller is found. """ logger = LoggerFactory()() - log_handle = call_recorder(lambda x: None) - monkeypatch.setattr(logger, "handle", log_handle) logger.error("Test") - log_record = log_handle.calls[0].args[0] - - assert log_record.funcName == "test_find_caller" - assert log_record.name == __name__ - assert log_record.filename == os.path.basename(__file__) + assert caplog.text.startswith( + "ERROR tests.test_stdlib:test_stdlib.py" + ) def test_sets_correct_logger(self): """ From 43d3c9c49a9f30fb64f8ff60726df0eb1b13ea05 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 19 Sep 2023 15:51:13 +0200 Subject: [PATCH 1086/1520] Check API with Pyright (#554) --- .github/workflows/ci.yml | 39 +++++++++++++++++++++++++++------------ tox.ini | 6 ++++++ 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index df24ee74..e98c8104 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,15 +47,14 @@ jobs: with: name: Packages path: dist - - run: tar xf dist/*.tar.gz --strip-components=1 # needed for config files - + - run: tar xf dist/*.tar.gz --strip-components=1 - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} allow-prereleases: true cache: pip - - run: python -Im pip install tox + - run: python -Im tox run --installpkg dist/*.whl -f py$(echo ${{ matrix.python-version }} | tr -d .) - name: Upload coverage data @@ -76,9 +75,7 @@ jobs: with: python-version-file: .python-version-default cache: pip - - run: python -Im pip install --upgrade coverage[toml] - - uses: actions/download-artifact@v3 with: name: coverage-data @@ -112,18 +109,36 @@ jobs: with: name: Packages path: dist - - run: tar xf dist/*.tar.gz --strip-components=1 # needed for config files + - run: tar xf dist/*.tar.gz --strip-components=1 + - uses: actions/setup-python@v4 + with: + python-version-file: .python-version-default + allow-prereleases: true + cache: pip + - run: python -Im pip install tox + + - run: python -Im tox run --installpkg dist/*.whl -e mypy-pkg + pyright: + name: Pyright + runs-on: ubuntu-latest + needs: build-package + + steps: + - name: Download pre-built packages + uses: actions/download-artifact@v3 + with: + name: Packages + path: dist + - run: tar xf dist/*.tar.gz --strip-components=1 - uses: actions/setup-python@v4 with: python-version-file: .python-version-default allow-prereleases: true cache: pip + - run: python -Im pip install tox - - name: Prepare & run tox - run: | - python -Im pip install tox - python -Im tox run --installpkg dist/*.whl -e mypy-pkg + - run: python -Im tox run --installpkg dist/*.whl -e pyright docs: name: Build docs & run doctests @@ -135,8 +150,7 @@ jobs: with: name: Packages path: dist - - run: tar xf dist/*.tar.gz --strip-components=1 # needed for config files - + - run: tar xf dist/*.tar.gz --strip-components=1 - uses: actions/setup-python@v4 with: # Keep in sync with tox.ini/docs & .readthedocs.yaml @@ -172,6 +186,7 @@ jobs: - docs - install-dev - mypy-pkg + - pyright runs-on: ubuntu-latest diff --git a/tox.ini b/tox.ini index 18d6a5cb..36c773ac 100644 --- a/tox.ini +++ b/tox.ini @@ -84,6 +84,12 @@ extras = typing commands = mypy src +[testenv:pyright] +deps = pyright +extras = typing +commands = pyright tests/typing + + [testenv:color-force] help = A visual check that FORCE_COLOR is working. set_env = FORCE_COLOR=1 From bb1799fec665025f2a1e4eec4d71218d72bfe959 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 19 Sep 2023 15:52:42 +0200 Subject: [PATCH 1087/1520] Fix changelog link --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index bfb279c4..ec7cf12d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,7 @@ dependencies = [] [project.urls] Documentation = "https://www.structlog.org/" -Changelog = "https://www.structlog.org/en/stable/changelog.html" +Changelog = "https://github.com/hynek/structlog/blob/main/CHANGELOG.md" GitHub = "https://github.com/hynek/structlog" Funding = "https://github.com/sponsors/hynek" Tidelift = "https://tidelift.com?utm_source=lifter&utm_medium=referral&utm_campaign=hynek" From 739d4d93b6e79d4649b8712f78032939c8f98a43 Mon Sep 17 00:00:00 2001 From: Noam Nol <45405044+NoamNol@users.noreply.github.com> Date: Fri, 29 Sep 2023 07:57:00 +0300 Subject: [PATCH 1088/1520] Fix "default" TimeStamper args in docs/getting-started.md (#556) * Update docs/getting-started.md - Fix TimeStamper params * Update docs/getting-started.md --------- Co-authored-by: Hynek Schlawack --- docs/getting-started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 71720f80..8059b86c 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -54,7 +54,7 @@ structlog.configure( structlog.processors.add_log_level, structlog.processors.StackInfoRenderer(), structlog.dev.set_exc_info, - structlog.processors.TimeStamper(), + structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S", utc=False), structlog.dev.ConsoleRenderer() ], wrapper_class=structlog.make_filtering_bound_logger(logging.NOTSET), From 19d4f6cacac646683299fcfe5c5ebe94b50d0d6a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 14:29:12 +0200 Subject: [PATCH 1089/1520] Bump actions/checkout from 3 to 4 (#557) --- .github/workflows/build-docset.yml | 2 +- .github/workflows/ci.yml | 8 ++++---- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/pypi-package.yml | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-docset.yml b/.github/workflows/build-docset.yml index 69494bc1..0dfce69e 100644 --- a/.github/workflows/build-docset.yml +++ b/.github/workflows/build-docset.yml @@ -17,7 +17,7 @@ jobs: docset: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 # get correct version - uses: actions/setup-python@v4 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e98c8104..1f01595a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 @@ -70,7 +70,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version-file: .python-version-default @@ -168,7 +168,7 @@ jobs: os: [ubuntu-latest, windows-latest] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version-file: .python-version-default @@ -203,7 +203,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version-file: .python-version-default diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index a5d32ce9..c0e6a208 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Initialize CodeQL uses: github/codeql-action/init@v2 diff --git a/.github/workflows/pypi-package.yml b/.github/workflows/pypi-package.yml index de146827..63c6b784 100644 --- a/.github/workflows/pypi-package.yml +++ b/.github/workflows/pypi-package.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 From 0f293daf1398c25e9391a941f61e4b4c259835e0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 3 Oct 2023 09:10:07 +0200 Subject: [PATCH 1090/1520] [pre-commit.ci] pre-commit autoupdate (#558) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index be772cad..f6d1d6b5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,12 +8,12 @@ default_language_version: repos: - repo: https://github.com/psf/black - rev: 23.7.0 + rev: 23.9.1 hooks: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.0.287 + rev: v0.0.292 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From 3dbc3d8cceae713b53ef6560a76f51e2ea60745a Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Wed, 4 Oct 2023 00:40:46 -0400 Subject: [PATCH 1091/1520] Minor typo fixes (#559) * docs: Capitalize "Unicode" * docs: Fix redundant "until now" * docs: Add missing commas --------- Co-authored-by: Hynek Schlawack --- docs/configuration.md | 2 +- docs/recipes.md | 2 +- docs/standard-library.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 272ffcbb..16820042 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -67,7 +67,7 @@ Whenever you bind or unbind data to a *bound logger*, this class is instantiated ### Logger Factories -We've already talked about wrapped loggers responsible for the output, but until now we haven't explained where they come from until now. +We've already talked about wrapped loggers responsible for the output, but we haven't explained where they come from until now. Unlike with *bound loggers*, you often need more flexibility when instantiating them. Therefore you don't configure a class; you configure a *factory* using the `logger_factory` keyword. diff --git a/docs/recipes.md b/docs/recipes.md index a09f1df8..2e4d6e04 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -12,7 +12,7 @@ Please note that recipes related to integration with frameworks have an [own cha The name of the event is hard-coded in *structlog* to `event`. But that doesn't mean it has to be called that in your logs. -With the {class}`structlog.processors.EventRenamer` processor you can for instance rename the log message to `msg` and use `event` for something custom, that you bind to `_event` in your code: +With the {class}`structlog.processors.EventRenamer` processor, you can, for instance, rename the log message to `msg` and use `event` for something custom, that you bind to `_event` in your code: ```pycon >>> from structlog.processors import EventRenamer diff --git a/docs/standard-library.md b/docs/standard-library.md index 14c12c7f..37f83295 100644 --- a/docs/standard-library.md +++ b/docs/standard-library.md @@ -189,7 +189,7 @@ structlog.configure( # sys.exc_info() tuple, remove "exc_info" and render the exception # with traceback into the "exception" key. structlog.processors.format_exc_info, - # If some value is in bytes, decode it to a unicode str. + # If some value is in bytes, decode it to a Unicode str. structlog.processors.UnicodeDecoder(), # Add callsite parameters. structlog.processors.CallsiteParameterAdder( From 37f663e1632d38ad4b7abfb28d01dbf04c32d59a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 9 Oct 2023 10:47:27 +0200 Subject: [PATCH 1092/1520] Update codespell --- .pre-commit-config.yaml | 4 ++-- tests/test_output.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f6d1d6b5..fb051c2a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,13 +25,13 @@ repos: args: [tests] - repo: https://github.com/codespell-project/codespell - rev: v2.2.5 + rev: v2.2.6 hooks: - id: codespell args: [-L, alog] - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer diff --git a/tests/test_output.py b/tests/test_output.py index 7b8e986a..1854c572 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -155,7 +155,7 @@ def test_stdout_monkeypatch(self, monkeypatch, capsys): class TestPrintLoggerFactory: def test_does_not_cache(self): """ - Due to doctest weirdness, we must not re-use PrintLoggers. + Due to doctest weirdness, we must not reuse PrintLoggers. """ f = PrintLoggerFactory() @@ -180,7 +180,7 @@ def test_ignores_args(self): class TestWriteLoggerFactory: def test_does_not_cache(self): """ - Due to doctest weirdness, we must not re-use WriteLoggers. + Due to doctest weirdness, we must not reuse WriteLoggers. """ f = WriteLoggerFactory() @@ -314,7 +314,7 @@ def test_deepcopy_no_stdout(self, tmp_path): class TestBytesLoggerFactory: def test_does_not_cache(self): """ - Due to doctest weirdness, we must not re-use BytesLoggers. + Due to doctest weirdness, we must not reuse BytesLoggers. """ f = BytesLoggerFactory() From c172022fdfb5ca3dbe95824a471df0ad48d65428 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 9 Oct 2023 11:05:51 +0200 Subject: [PATCH 1093/1520] docs: add recipe for stderr Fixes #551 --- docs/recipes.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/recipes.md b/docs/recipes.md index 2e4d6e04..b990ecc4 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -186,3 +186,12 @@ def manager(request_id: str): ``` See the [issue 425](https://github.com/hynek/structlog/issues/425) for a more complete example. + + +## Switching Console Output to Standard Error + +When using structlog without standard library integration and want the log output to go to standard error (*stderr*) instead of standard out (*stdout*), you can switch with a single line of configuration: + +```python +structlog.configure(logger_factory=structlog.PrintLoggerFactory(sys.stderr)) +``` From f5cbae43c8fd2f20eeb933e5af0134225d3daa9b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 9 Oct 2023 16:43:59 +0200 Subject: [PATCH 1094/1520] Prepare 23.2.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 858080b8..baa40504 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ -## [Unreleased](https://github.com/hynek/structlog/compare/23.1.0...HEAD) +## [23.2.0](https://github.com/hynek/structlog/compare/23.1.0...23.2.0) - 2023-10-09 ### Removed From d95197c9a02b59139605515a0939d690e87550a2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 9 Oct 2023 16:49:43 +0200 Subject: [PATCH 1095/1520] Start new development cycle --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index baa40504..bc418de2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ +## [Unreleased](https://github.com/hynek/structlog/compare/23.2.0...HEAD) + + ## [23.2.0](https://github.com/hynek/structlog/compare/23.1.0...23.2.0) - 2023-10-09 ### Removed From 44a55f41a9921e54ea545f7d2801be2fb7479ad2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 16 Oct 2023 12:22:27 +0200 Subject: [PATCH 1096/1520] threadlocal: make tmp_bind work on lazy proxy, too --- docs/bound-loggers.md | 2 +- src/structlog/threadlocal.py | 3 +++ tests/test_threadlocal.py | 21 ++++++++++++++++++++- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/docs/bound-loggers.md b/docs/bound-loggers.md index da313568..fa6cb010 100644 --- a/docs/bound-loggers.md +++ b/docs/bound-loggers.md @@ -152,7 +152,7 @@ In practice, you won't be instantiating bound loggers yourself. You will configure *structlog* as explained in the {doc}`next chapter ` and then just call {func}`structlog.get_logger`. However, in some rare cases you may not want to do that. -For example because you don't control how you get the logger that you would like to wrap (famous example: *Celery*). +For example because you don't control how you get the logger that you would like to wrap (famous example: Celery). For that times there is the {func}`structlog.wrap_logger` function that can be used to wrap a logger -- optionally without any global state (i.e. configuration): (proc)= diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index f57af92b..6ddb75df 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -150,6 +150,9 @@ def tmp_bind( .. deprecated:: 22.1.0 """ _deprecated() + if isinstance(logger, BoundLoggerLazyProxy): + logger = logger.bind() + saved = as_immutable(logger)._context try: yield logger.bind(**tmp_values) # type: ignore[misc] diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py index 3e58c7bd..9a06e12f 100644 --- a/tests/test_threadlocal.py +++ b/tests/test_threadlocal.py @@ -2,6 +2,7 @@ # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. + import inspect import threading @@ -9,8 +10,9 @@ import structlog +from structlog import get_logger, wrap_logger from structlog._base import BoundLoggerBase -from structlog._config import wrap_logger +from structlog._config import BoundLoggerLazyProxy from structlog.testing import ReturnLogger from structlog.threadlocal import ( _CONTEXT, @@ -103,6 +105,23 @@ def test_bind_exc(self, log): assert {"y": 23} == log._context._dict + def test_tmp_bind_lazy(self): + """ + tmp_bind works with a BoundLoggerLazyProxy -- i.e. before the first + bind. + """ + with pytest.deprecated_call(): + structlog.configure(context_class=wrap_dict(dict)) + + log = get_logger() + + assert isinstance(log, BoundLoggerLazyProxy) + + with pytest.deprecated_call(), tmp_bind(log, x=42) as tmp_log: + assert {"x": 42} == tmp_log._context._dict + + assert {} == log._context + class TestAsImmutable: def test_does_not_affect_global(self, log): From ee90dd52417f41dcf8d2341ae9fa9a6e81774a24 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 16 Oct 2023 12:38:01 +0200 Subject: [PATCH 1097/1520] Make instances of BoundLoggerLazyProxy BindableLoggers on Python 3.12 (#561) Fixes #560 --- CHANGELOG.md | 5 +++++ src/structlog/_config.py | 5 +++++ src/structlog/threadlocal.py | 2 +- tests/test_config.py | 11 +++++++++++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc418de2..68e5ce48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,11 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ## [Unreleased](https://github.com/hynek/structlog/compare/23.2.0...HEAD) +### Fixed + +- The return value from `get_logger()` (a `BoundLoggerLazyProxy`) now passes `isinstance`-checks against `structlog.typing.BindableLogger` on Python 3.12. + + ## [23.2.0](https://github.com/hynek/structlog/compare/23.1.0...23.2.0) - 2023-10-09 diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 718bcfb6..0263b054 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -315,6 +315,11 @@ class BoundLoggerLazyProxy: .. versionchanged:: 0.4.0 Added support for *logger_factory_args*. """ + # fulfill BindableLogger protocol without carrying accidental state + @property + def _context(self) -> dict[str, str]: + return {} + def __init__( self, logger: WrappedLogger | None, diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index 6ddb75df..a1cfd86b 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -119,7 +119,7 @@ def as_immutable(logger: TLLogger) -> TLLogger: """ _deprecated() if isinstance(logger, BoundLoggerLazyProxy): - logger = logger.bind() # type: ignore[assignment] + logger = logger.bind() try: ctx = logger._context._tl.dict_.__class__( # type: ignore[union-attr] diff --git a/tests/test_config.py b/tests/test_config.py index 5e741d5d..f9a9f8eb 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -26,6 +26,7 @@ get_logger, wrap_logger, ) +from structlog.typing import BindableLogger @pytest.fixture(name="proxy") @@ -56,6 +57,16 @@ class Foo(metaclass=abc.ABCMeta): Foo() +def test_lazy_logger_is_an_instance_of_bindable_logger(): + """ + The BoundLoggerLazyProxy returned by get_logger fulfills the BindableLogger + protocol. + + See https://github.com/hynek/structlog/issues/560 + """ + assert isinstance(get_logger(), BindableLogger) + + def test_default_context_class(): """ Default context class is dict. From 24627190845d4cf37cca22ce62c8d7252f74f1a2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 16 Oct 2023 12:40:27 +0200 Subject: [PATCH 1098/1520] docs: update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68e5ce48..cfdd8222 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ### Fixed - The return value from `get_logger()` (a `BoundLoggerLazyProxy`) now passes `isinstance`-checks against `structlog.typing.BindableLogger` on Python 3.12. + [#561](https://github.com/hynek/structlog/issues/561) +- `structlog.threadlocal.tmp_bind()` now also works `BoundLoggerLazyProxy` (in other words: before anything is bound to a bound logger). ## [23.2.0](https://github.com/hynek/structlog/compare/23.1.0...23.2.0) - 2023-10-09 From e9056fe2793500a569c97d9432955bd18e373ae7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 17 Oct 2023 09:48:55 +0200 Subject: [PATCH 1099/1520] Mention logrotate --- docs/logging-best-practices.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/logging-best-practices.md b/docs/logging-best-practices.md index 8539986d..8076cffc 100644 --- a/docs/logging-best-practices.md +++ b/docs/logging-best-practices.md @@ -7,7 +7,7 @@ Therefore let's rely on proven tools as much as possible and do only the absolut A simple but powerful approach is to log to unbuffered [standard out](https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29 ) and let other tools take care of the rest. -That can be your terminal window while developing, it can be [*systemd*](https://en.wikipedia.org/wiki/Systemd) redirecting your log entries to [*syslogd*](https://en.wikipedia.org/wiki/Syslogd), or your [cluster manager](https://kubernetes.io/docs/concepts/cluster-administration/logging/). +That can be your terminal window while developing, it can be [*systemd*](https://en.wikipedia.org/wiki/Systemd) redirecting your log entries to [*syslogd*](https://en.wikipedia.org/wiki/Syslogd) and rotate them using [*logrotate*](https://github.com/logrotate/logrotate), or your [cluster manager](https://kubernetes.io/docs/concepts/cluster-administration/logging/). It doesn't matter where or how your application is running, it just works. This is why the popular [*Twelve-Factor App* methodology](https://12factor.net/logs) suggests just that. From 523942d9cb839cfecfbb4e51b67b39a26de6bdde Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 17 Oct 2023 10:19:18 +0200 Subject: [PATCH 1100/1520] Calm down --- docs/typing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/typing.md b/docs/typing.md index 1e6da4c8..210204c0 100644 --- a/docs/typing.md +++ b/docs/typing.md @@ -1,6 +1,6 @@ # Type Hints -Static type hints -- together with a type checker like [*Mypy*](https://mypy.readthedocs.io/en/stable/) -- are an excellent way to make your code more robust, self-documenting, and maintainable in the long run. +Static type hints -- together with a type checker like [Mypy](https://mypy.readthedocs.io/en/stable/) -- are an excellent way to make your code more robust, self-documenting, and maintainable in the long run. And as of 20.2.0, *structlog* comes with type hints for all of its APIs. Since *structlog* is highly configurable and tries to give a clean façade to its users, adding types without breaking compatibility -- while remaining useful! -- was a formidable task. From 830febd6db109a59fbb91dbc45fa1db36311fce1 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 17 Oct 2023 10:29:51 +0200 Subject: [PATCH 1101/1520] Comma splice --- docs/logging-best-practices.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/logging-best-practices.md b/docs/logging-best-practices.md index 8076cffc..5b2cba9b 100644 --- a/docs/logging-best-practices.md +++ b/docs/logging-best-practices.md @@ -7,8 +7,9 @@ Therefore let's rely on proven tools as much as possible and do only the absolut A simple but powerful approach is to log to unbuffered [standard out](https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29 ) and let other tools take care of the rest. -That can be your terminal window while developing, it can be [*systemd*](https://en.wikipedia.org/wiki/Systemd) redirecting your log entries to [*syslogd*](https://en.wikipedia.org/wiki/Syslogd) and rotate them using [*logrotate*](https://github.com/logrotate/logrotate), or your [cluster manager](https://kubernetes.io/docs/concepts/cluster-administration/logging/). -It doesn't matter where or how your application is running, it just works. + +That can be your terminal window while developing; it can be [*systemd*](https://en.wikipedia.org/wiki/Systemd) redirecting your log entries to [*syslogd*](https://en.wikipedia.org/wiki/Syslogd) and rotating them using [*logrotate*](https://github.com/logrotate/logrotate); or it can be your [cluster manager](https://kubernetes.io/docs/concepts/cluster-administration/logging/) forwarding them to an obscenely expensive log aggregator service. +It doesn't matter where or how your application is running -- it just works. This is why the popular [*Twelve-Factor App* methodology](https://12factor.net/logs) suggests just that. From ea588cc29db0f8cb013a2fcb1c34ebad046929cb Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 17 Oct 2023 10:34:29 +0200 Subject: [PATCH 1102/1520] Style --- docs/logging-best-practices.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/docs/logging-best-practices.md b/docs/logging-best-practices.md index 5b2cba9b..a9da40b9 100644 --- a/docs/logging-best-practices.md +++ b/docs/logging-best-practices.md @@ -1,17 +1,15 @@ # Logging Best Practices -Logging is not a new concept and in no way special to Python. -Logfiles have existed for decades and there's little reason to reinvent the wheel in our little world. - -Therefore let's rely on proven tools as much as possible and do only the absolutely necessary inside of Python[^unix]. +Logging is not a new concept and is in no way unique to Python. +Logfiles have existed for decades, and there's little reason to reinvent the wheel in our little world. +Therefore, let's rely on proven tools as much as possible and do only the bare minimum inside Python applications[^unix]. A simple but powerful approach is to log to unbuffered [standard out](https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29 ) and let other tools take care of the rest. That can be your terminal window while developing; it can be [*systemd*](https://en.wikipedia.org/wiki/Systemd) redirecting your log entries to [*syslogd*](https://en.wikipedia.org/wiki/Syslogd) and rotating them using [*logrotate*](https://github.com/logrotate/logrotate); or it can be your [cluster manager](https://kubernetes.io/docs/concepts/cluster-administration/logging/) forwarding them to an obscenely expensive log aggregator service. -It doesn't matter where or how your application is running -- it just works. -This is why the popular [*Twelve-Factor App* methodology](https://12factor.net/logs) suggests just that. +It doesn't matter where or how your application runs -- it just works, and the reason why the popular [*Twelve-Factor App* methodology](https://12factor.net/logs) suggests just that. [^unix]: This is obviously a privileged UNIX-centric view but even Windows has tools and means for log management although we won't be able to discuss them here. From 84a384948ce659ec58df79d6a07e7f0c6cabc65b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 18 Oct 2023 07:40:45 +0200 Subject: [PATCH 1103/1520] Calm down --- docs/logging-best-practices.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/logging-best-practices.md b/docs/logging-best-practices.md index a9da40b9..39e5b1a2 100644 --- a/docs/logging-best-practices.md +++ b/docs/logging-best-practices.md @@ -70,24 +70,24 @@ Parsed, indexed, and easy to search. ### ELK -The ELK stack ([*Elasticsearch*], [*Logstash*], [*Kibana*]) from Elastic is a great way to store, parse, and search your logs. +The ELK stack ([**E**lasticsearch][elasticsearch], [**L**ogstash][logstash], [**K**ibana][kibana]) from Elastic is a great way to store, parse, and search your logs. -The way it works is that you have local log shippers like [*Filebeat*] that parse your log files and forward the log entries to your [*Logstash*] server. -Logstash parses the log entries and stores them in [*Elasticsearch*]. -Finally, you can view and search them in [*Kibana*]. +The way it works is that you have local log shippers like [Filebeat] that parse your log files and forward the log entries to your [Logstash] server. +Logstash parses the log entries and stores them in [Elasticsearch]. +Finally, you can view and search them in [Kibana]. If your log entries consist of a JSON dictionary, this is fairly easy and efficient. -All you have to do is to tell [*Logstash*] either that your log entries are prepended with a timestamp from {class}`~structlog.processors.TimeStamper` or the name of your timestamp field. +All you have to do is to tell [Logstash] either that your log entries are prepended with a timestamp from {class}`~structlog.processors.TimeStamper` or the name of your timestamp field. ### Graylog [Graylog](https://www.graylog.org/) goes one step further. -It not only supports everything those above do (and then some); you can also directly log JSON entries towards it -- optionally even through an AMQP server (like [*RabbitMQ*](https://www.rabbitmq.com/)) for better reliability. +It not only supports everything those above do (and then some); you can also directly log JSON entries towards it -- optionally even through an AMQP server (like [RabbitMQ](https://www.rabbitmq.com/)) for better reliability. Additionally, [Graylog's Extended Log Format](https://docs.graylog.org/docs/gelf) (GELF) allows for structured data which makes it an obvious choice to use together with *structlog*. -[*elasticsearch*]: https://www.elastic.co/elasticsearch -[*filebeat*]: https://github.com/elastic/beats/tree/master/filebeat -[*kibana*]: https://www.elastic.co/kibana -[*logstash*]: https://www.elastic.co/logstash +[elasticsearch]: https://www.elastic.co/elasticsearch +[filebeat]: https://github.com/elastic/beats/tree/main/filebeat +[kibana]: https://www.elastic.co/kibana +[logstash]: https://www.elastic.co/logstash From ede65fedac97439dffc79ed6d307a9bbe21283c5 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 18 Oct 2023 11:05:17 +0200 Subject: [PATCH 1104/1520] pre-commit autoupdate --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fb051c2a..ed2a238d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,12 +8,12 @@ default_language_version: repos: - repo: https://github.com/psf/black - rev: 23.9.1 + rev: 23.10.0 hooks: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.0.292 + rev: v0.1.0 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From 7883d045e466b6b9b343938b22d882a49e959d5f Mon Sep 17 00:00:00 2001 From: pahrohfit Date: Mon, 30 Oct 2023 04:39:12 -0400 Subject: [PATCH 1105/1520] callsite parameter fix while operating under `asyncio` (#565) * Support for `asyncio` correct callsite params * Support for `asyncio` correct callsite params * Support for `asyncio` correct callsite params * Added `versionchanged` tags * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Typing additions and corrections * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Spelling corrections * Simplified logic and removed unused code * Corrected typing * Ensure context is cleared even if logging failure * Renamed async contextvar to match project naming convention * De-cleverfied logic for easier reading --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- CHANGELOG.md | 2 ++ src/structlog/_frames.py | 3 +- src/structlog/_log_levels.py | 58 +++++++++++++++++++++++++++--------- src/structlog/contextvars.py | 7 +++++ src/structlog/processors.py | 4 --- src/structlog/stdlib.py | 16 ++++++---- tests/test_processors.py | 16 +++++----- 7 files changed, 73 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cfdd8222..57f86b6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ### Fixed +- `AsyncBoundLogger` now properly supports callsite parameters. + - The return value from `get_logger()` (a `BoundLoggerLazyProxy`) now passes `isinstance`-checks against `structlog.typing.BindableLogger` on Python 3.12. [#561](https://github.com/hynek/structlog/issues/561) diff --git a/src/structlog/_frames.py b/src/structlog/_frames.py index 7a5fb6c3..51346d2f 100644 --- a/src/structlog/_frames.py +++ b/src/structlog/_frames.py @@ -11,6 +11,7 @@ from io import StringIO from types import FrameType +from .contextvars import _ASYNC_CALLING_STACK from .typing import ExcInfo @@ -50,7 +51,7 @@ def _find_first_app_frame_and_name( tuple of (frame, name) """ ignores = ["structlog"] + (additional_ignores or []) - f = sys._getframe() + f = _ASYNC_CALLING_STACK.get(sys._getframe()) name = f.f_globals.get("__name__") or "?" while any(tuple(name.startswith(i) for i in ignores)): if f.f_back is None: diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index b2e721b6..be132fcb 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -17,6 +17,7 @@ from typing import Any, Callable from ._base import BoundLoggerBase +from .contextvars import _ASYNC_CALLING_STACK from .typing import EventDict, FilteringBoundLogger @@ -91,16 +92,26 @@ def exception( async def aexception( self: FilteringBoundLogger, event: str, *args: Any, **kw: Any ) -> Any: + """ + .. versionchanged:: 23.3.0 + Callsite parameters are now also collected under asyncio. + """ # Exception info has to be extracted this early, because it is no longer # available once control is passed to the executor. if kw.get("exc_info", True) is True: kw["exc_info"] = sys.exc_info() + scs_token = _ASYNC_CALLING_STACK.set(sys._getframe().f_back) # type: ignore[arg-type] ctx = contextvars.copy_context() - return await asyncio.get_running_loop().run_in_executor( - None, - lambda: ctx.run(lambda: self.error(event, *args, **kw)), - ) + try: + runner = await asyncio.get_running_loop().run_in_executor( + None, + lambda: ctx.run(lambda: self.error(event, *args, **kw)), + ) + finally: + _ASYNC_CALLING_STACK.reset(scs_token) + + return runner def make_filtering_bound_logger(min_level: int) -> type[FilteringBoundLogger]: @@ -170,16 +181,24 @@ def meth(self: Any, event: str, *args: Any, **kw: Any) -> Any: return self._proxy_to_logger(name, event % args, **kw) async def ameth(self: Any, event: str, *args: Any, **kw: Any) -> Any: + """ + .. versionchanged:: 23.3.0 + Callsite parameters are now also collected under asyncio. + """ if args: event = event % args + scs_token = _ASYNC_CALLING_STACK.set(sys._getframe().f_back) # type: ignore[arg-type] ctx = contextvars.copy_context() - await asyncio.get_running_loop().run_in_executor( - None, - lambda: ctx.run( - lambda: self._proxy_to_logger(name, event, **kw) - ), - ) + try: + await asyncio.get_running_loop().run_in_executor( + None, + lambda: ctx.run( + lambda: self._proxy_to_logger(name, event, **kw) + ), + ) + finally: + _ASYNC_CALLING_STACK.reset(scs_token) meth.__name__ = name ameth.__name__ = f"a{name}" @@ -199,17 +218,28 @@ def log(self: Any, level: int, event: str, *args: Any, **kw: Any) -> Any: async def alog( self: Any, level: int, event: str, *args: Any, **kw: Any ) -> Any: + """ + .. versionchanged:: 23.3.0 + Callsite parameters are now also collected under asyncio. + """ if level < min_level: return None name = _LEVEL_TO_NAME[level] if args: event = event % args + scs_token = _ASYNC_CALLING_STACK.set(sys._getframe().f_back) # type: ignore[arg-type] ctx = contextvars.copy_context() - return await asyncio.get_running_loop().run_in_executor( - None, - lambda: ctx.run(lambda: self._proxy_to_logger(name, event, **kw)), - ) + try: + runner = await asyncio.get_running_loop().run_in_executor( + None, + lambda: ctx.run( + lambda: self._proxy_to_logger(name, event, **kw) + ), + ) + finally: + _ASYNC_CALLING_STACK.reset(scs_token) + return runner meths: dict[str, Callable[..., Any]] = {"log": log, "alog": alog} for lvl, name in _LEVEL_TO_NAME.items(): diff --git a/src/structlog/contextvars.py b/src/structlog/contextvars.py index ebb5941d..cc531889 100644 --- a/src/structlog/contextvars.py +++ b/src/structlog/contextvars.py @@ -11,6 +11,8 @@ .. versionchanged:: 21.1.0 Reimplemented without using a single dict as context carrier for improved isolation. Every key-value pair is a separate `contextvars.ContextVar` now. +.. versionchanged:: 23.3.0 + Callsite parameters are now also collected under asyncio. See :doc:`contextvars`. """ @@ -20,6 +22,7 @@ import contextlib import contextvars +from types import FrameType from typing import Any, Generator, Mapping import structlog @@ -30,6 +33,10 @@ STRUCTLOG_KEY_PREFIX = "structlog_" STRUCTLOG_KEY_PREFIX_LEN = len(STRUCTLOG_KEY_PREFIX) +_ASYNC_CALLING_STACK: contextvars.ContextVar[ + FrameType +] = contextvars.ContextVar("_ASYNC_CALLING_STACK") + # For proper isolation, we have to use a dict of ContextVars instead of a # single ContextVar with a dict. # See https://github.com/hynek/structlog/pull/302 for details. diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 7b2377a7..b4063332 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -734,10 +734,6 @@ class CallsiteParameterAdder: dictionaries with information such as the function name, line number and filename that an event dictionary originated from. - .. warning:: - This processor cannot detect the correct callsite for invocation of - async functions. - If the event dictionary has an embedded `logging.LogRecord` object and did not originate from *structlog* then the callsite information will be determined from the `logging.LogRecord` object. For event dictionaries diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 9de32fd9..0cac0354 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -24,7 +24,7 @@ from ._base import BoundLoggerBase from ._frames import _find_first_app_frame_and_name, _format_stack from ._log_levels import _LEVEL_TO_NAME, _NAME_TO_LEVEL, add_log_level -from .contextvars import merge_contextvars +from .contextvars import _ASYNC_CALLING_STACK, merge_contextvars from .exceptions import DropEvent from .processors import StackInfoRenderer from .typing import Context, EventDict, ExcInfo, Processor, WrappedLogger @@ -587,13 +587,19 @@ async def _dispatch_to_sync( ) -> None: """ Merge contextvars and log using the sync logger in a thread pool. + .. versionchanged:: 23.3.0 + Callsite parameters are now also collected under asyncio. """ + scs_token = _ASYNC_CALLING_STACK.set(sys._getframe().f_back.f_back) # type: ignore[union-attr, arg-type, unused-ignore] ctx = contextvars.copy_context() - await asyncio.get_running_loop().run_in_executor( - self._executor, - lambda: ctx.run(lambda: meth(event, *args, **kw)), - ) + try: + await asyncio.get_running_loop().run_in_executor( + self._executor, + lambda: ctx.run(lambda: meth(event, *args, **kw)), + ) + finally: + _ASYNC_CALLING_STACK.reset(scs_token) async def debug(self, event: str, *args: Any, **kw: Any) -> None: await self._dispatch_to_sync(self.sync_bl.debug, event, args, kw) diff --git a/tests/test_processors.py b/tests/test_processors.py index c8628302..9317cc08 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -823,12 +823,6 @@ def test_all_parameters(self) -> None: } assert self.parameter_strings == self.get_callsite_parameters().keys() - @pytest.mark.xfail( - reason=( - "CallsiteParameterAdder cannot " - "determine the callsite for async calls." - ) - ) @pytest.mark.asyncio() async def test_async(self) -> None: """ @@ -852,10 +846,14 @@ def __init__(self): callsite_params = self.get_callsite_parameters() await logger.info("baz") + logger_params = json.loads(string_io.getvalue()) - assert {"event": "baz", **callsite_params} == json.loads( - string_io.getvalue() - ) + # These are different when running under async + for key in ["thread", "thread_name"]: + callsite_params.pop(key) + logger_params.pop(key) + + assert {"event": "baz", **callsite_params} == logger_params def test_additional_ignores(self, monkeypatch: pytest.MonkeyPatch) -> None: """ From 94fa5743c504f7fdff7f240cf07fc963bf5a4044 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 30 Oct 2023 09:38:07 +0100 Subject: [PATCH 1106/1520] Adjust changelog --- CHANGELOG.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57f86b6a..cbc966e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,14 +15,18 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ## [Unreleased](https://github.com/hynek/structlog/compare/23.2.0...HEAD) -### Fixed +### Added + +- Async log methods (those starting with an `a`) now also support the collection of callsite information using `structlog.processors.CallsiteParameterAdder`. + [#565](https://github.com/hynek/structlog/issues/565) -- `AsyncBoundLogger` now properly supports callsite parameters. + +### Fixed - The return value from `get_logger()` (a `BoundLoggerLazyProxy`) now passes `isinstance`-checks against `structlog.typing.BindableLogger` on Python 3.12. [#561](https://github.com/hynek/structlog/issues/561) -- `structlog.threadlocal.tmp_bind()` now also works `BoundLoggerLazyProxy` (in other words: before anything is bound to a bound logger). +- `structlog.threadlocal.tmp_bind()` now also works with `BoundLoggerLazyProxy` (in other words: before anything is bound to a bound logger). ## [23.2.0](https://github.com/hynek/structlog/compare/23.1.0...23.2.0) - 2023-10-09 From 13593295d88e8cb4b2370961ca52b785c6672b05 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 30 Oct 2023 09:48:22 +0100 Subject: [PATCH 1107/1520] Stress once more to not use main for PRs --- .github/CONTRIBUTING.md | 2 +- .github/PULL_REQUEST_TEMPLATE.md | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 51bfcdbc..86430411 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -63,7 +63,7 @@ Or if you prefer to use Git via HTTPS: $ git clone https://github.com/YOU/structlog.git ``` -> **Warning** +> [!WARNING] > - **Before** you start working on a new pull request, use the "*Sync fork*" button in GitHub's web UI to ensure your fork is up to date. > - **Always create a new branch off `main` for each new pull request.** > Yes, you can work on `main` in your fork and submit pull requests. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 381af11b..60d72424 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -13,6 +13,9 @@ But please read our [contribution guide](https://github.com/hynek/structlog/blob If an item doesn't apply to your pull request, **check it anyway** to make it apparent that there's nothing left to do. --> +- [ ] Do **not** open pull requests from your main branch, but **use a branch instead**. There's a ton of footguns waiting if you don't heed this warning. You can still go back to your project, create a branch from your main branch, push that, and open the PR from that. + + This is not a pre-requisite for your your pull request to be accepted, but **you have been warned**. - [ ] Added **tests** for changed code. - The CI fails with less than 100% coverage. - [ ] **New APIs** are added to [`api.py`](https://github.com/hynek/structlog/blob/main/tests/typing/api.py). From b382c068812ac75ae5a0898510300063d9b40b32 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 30 Oct 2023 10:02:38 +0100 Subject: [PATCH 1108/1520] docs --- .github/PULL_REQUEST_TEMPLATE.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 60d72424..af3c9ba0 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -13,12 +13,14 @@ But please read our [contribution guide](https://github.com/hynek/structlog/blob If an item doesn't apply to your pull request, **check it anyway** to make it apparent that there's nothing left to do. --> -- [ ] Do **not** open pull requests from your main branch, but **use a branch instead**. There's a ton of footguns waiting if you don't heed this warning. You can still go back to your project, create a branch from your main branch, push that, and open the PR from that. +- [ ] Do **not** open pull requests from your main branch, but **use a branch instead**. + + There's a ton of footguns waiting if you don't heed this warning. You can still go back to your project, create a branch from your main branch, push it, and open the pull request from the new branch. This is not a pre-requisite for your your pull request to be accepted, but **you have been warned**. - [ ] Added **tests** for changed code. - The CI fails with less than 100% coverage. -- [ ] **New APIs** are added to [`api.py`](https://github.com/hynek/structlog/blob/main/tests/typing/api.py). +- [ ] **New APIs** are added to our typing tests in [`api.py`](https://github.com/hynek/structlog/blob/main/tests/typing/api.py). - [ ] Updated **documentation** for changed code. - [ ] New functions/classes have to be added to `docs/api.rst` by hand. - [ ] Changed/added classes/methods/functions have appropriate `versionadded`, `versionchanged`, or `deprecated` [directives](http://www.sphinx-doc.org/en/stable/markup/para.html#directive-versionadded). From 0da7ca2057eb27f53c00f8ed83b06ed67e55424c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 30 Oct 2023 10:03:37 +0100 Subject: [PATCH 1109/1520] docs --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index af3c9ba0..782cf7be 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -13,7 +13,7 @@ But please read our [contribution guide](https://github.com/hynek/structlog/blob If an item doesn't apply to your pull request, **check it anyway** to make it apparent that there's nothing left to do. --> -- [ ] Do **not** open pull requests from your main branch, but **use a branch instead**. +- [ ] Do **not** open pull requests from your main branch, but **use a separate branch instead**. There's a ton of footguns waiting if you don't heed this warning. You can still go back to your project, create a branch from your main branch, push it, and open the pull request from the new branch. From 3a593743c8eec4f2633c6b514727cb96732c3909 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 30 Oct 2023 10:04:53 +0100 Subject: [PATCH 1110/1520] docs --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 782cf7be..fec8e582 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -13,7 +13,7 @@ But please read our [contribution guide](https://github.com/hynek/structlog/blob If an item doesn't apply to your pull request, **check it anyway** to make it apparent that there's nothing left to do. --> -- [ ] Do **not** open pull requests from your main branch, but **use a separate branch instead**. +- [ ] Do **not** open pull requests from your main branch – **use a separate branch**! There's a ton of footguns waiting if you don't heed this warning. You can still go back to your project, create a branch from your main branch, push it, and open the pull request from the new branch. From 2de96fd7fb50516b5db74b17a3a18ed4b732e538 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 30 Oct 2023 10:05:18 +0100 Subject: [PATCH 1111/1520] docs --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index fec8e582..e491f17a 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -13,7 +13,7 @@ But please read our [contribution guide](https://github.com/hynek/structlog/blob If an item doesn't apply to your pull request, **check it anyway** to make it apparent that there's nothing left to do. --> -- [ ] Do **not** open pull requests from your main branch – **use a separate branch**! +- [ ] Do **not** open pull requests from your `main` branch – **use a separate branch**! There's a ton of footguns waiting if you don't heed this warning. You can still go back to your project, create a branch from your main branch, push it, and open the pull request from the new branch. From b1926e73b87213eaa53fc116c5430f7cde2bb6be Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 30 Oct 2023 10:29:02 +0100 Subject: [PATCH 1112/1520] Use 3.12 in dev (#566) --- .python-version-default | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.python-version-default b/.python-version-default index 2c073331..e4fba218 100644 --- a/.python-version-default +++ b/.python-version-default @@ -1 +1 @@ -3.11 +3.12 From 63ad13523d0b8595ac836891ac80cabaaa2049ff Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 1 Nov 2023 08:38:52 +0100 Subject: [PATCH 1113/1520] Avoid paragraphs in check list --- .github/PULL_REQUEST_TEMPLATE.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index e491f17a..bb0827ec 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -14,10 +14,8 @@ If an item doesn't apply to your pull request, **check it anyway** to make it ap --> - [ ] Do **not** open pull requests from your `main` branch – **use a separate branch**! - - There's a ton of footguns waiting if you don't heed this warning. You can still go back to your project, create a branch from your main branch, push it, and open the pull request from the new branch. - - This is not a pre-requisite for your your pull request to be accepted, but **you have been warned**. + - There's a ton of footguns waiting if you don't heed this warning. You can still go back to your project, create a branch from your main branch, push it, and open the pull request from the new branch. + - This is not a pre-requisite for your your pull request to be accepted, but **you have been warned**. - [ ] Added **tests** for changed code. - The CI fails with less than 100% coverage. - [ ] **New APIs** are added to our typing tests in [`api.py`](https://github.com/hynek/structlog/blob/main/tests/typing/api.py). From e244981c94c45f3b41ff722fae6585c621d9f2f6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 1 Nov 2023 08:53:04 +0100 Subject: [PATCH 1114/1520] Found another paragraph --- .github/PULL_REQUEST_TEMPLATE.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index bb0827ec..5599a435 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -22,8 +22,7 @@ If an item doesn't apply to your pull request, **check it anyway** to make it ap - [ ] Updated **documentation** for changed code. - [ ] New functions/classes have to be added to `docs/api.rst` by hand. - [ ] Changed/added classes/methods/functions have appropriate `versionadded`, `versionchanged`, or `deprecated` [directives](http://www.sphinx-doc.org/en/stable/markup/para.html#directive-versionadded). - - The next version is the second number in the current release + 1. The first number represents the current year. So if the current version on PyPI is 23.1.0, the next version is gonna be 23.2.0. If the next version is the first in the new year, it'll be 24.1.0. + - The next version is the second number in the current release + 1. The first number represents the current year. So if the current version on PyPI is 23.1.0, the next version is gonna be 23.2.0. If the next version is the first in the new year, it'll be 24.1.0. - [ ] Documentation in `.rst` and `.md` files is written using [**semantic newlines**](https://rhodesmill.org/brandon/2012/one-sentence-per-line/). - [ ] Changes (and possible deprecations) are documented in the [**changelog**](https://github.com/hynek/structlog/blob/main/CHANGELOG.md). - [ ] Consider granting [push permissions to the PR branch](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork), so maintainers can fix minor issues themselves without pestering you. From df469d509a2a0b9a1145efa440ec1f864e44f338 Mon Sep 17 00:00:00 2001 From: pahrohfit Date: Wed, 1 Nov 2023 09:46:32 -0400 Subject: [PATCH 1115/1520] Migrated from `event_loop` fixture (#569) * Migrated from deprecated `event_loop` fixture * Removed redundant types and changelog as requested. --- tests/test_contextvars.py | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/tests/test_contextvars.py b/tests/test_contextvars.py index 12535845..d34a16e7 100644 --- a/tests/test_contextvars.py +++ b/tests/test_contextvars.py @@ -33,11 +33,12 @@ def _clear_contextvars(): class TestContextvars: - async def test_bind(self, event_loop): + async def test_bind(self): """ Binding a variable causes it to be included in the result of merge_contextvars. """ + event_loop = asyncio.get_running_loop() async def coro(): bind_contextvars(a=1) @@ -45,11 +46,12 @@ async def coro(): assert {"a": 1, "b": 2} == await event_loop.create_task(coro()) - async def test_multiple_binds(self, event_loop): + async def test_multiple_binds(self): """ Multiple calls to bind_contextvars accumulate values instead of replacing them. But they override redefined ones. """ + event_loop = asyncio.get_running_loop() async def coro(): bind_contextvars(a=1, c=3) @@ -63,11 +65,12 @@ async def coro(): "d": 4, } == await event_loop.create_task(coro()) - async def test_reset(self, event_loop): + async def test_reset(self): """ reset_contextvars allows resetting contexvars to previously-set values. """ + event_loop = asyncio.get_running_loop() async def coro(): bind_contextvars(a=1) @@ -87,10 +90,11 @@ async def nested_coro(): await event_loop.create_task(coro()) - async def test_nested_async_bind(self, event_loop): + async def test_nested_async_bind(self): """ Context is passed correctly between "nested" concurrent operations. """ + event_loop = asyncio.get_running_loop() async def coro(): bind_contextvars(a=1) @@ -102,22 +106,24 @@ async def nested_coro(): assert {"a": 1, "b": 2, "c": 3} == await event_loop.create_task(coro()) - async def test_merge_works_without_bind(self, event_loop): + async def test_merge_works_without_bind(self): """ merge_contextvars returns values as normal even when there has been no previous calls to bind_contextvars. """ + event_loop = asyncio.get_running_loop() async def coro(): return merge_contextvars(None, None, {"b": 2}) assert {"b": 2} == await event_loop.create_task(coro()) - async def test_merge_overrides_bind(self, event_loop): + async def test_merge_overrides_bind(self): """ Variables included in merge_contextvars override previously bound variables. """ + event_loop = asyncio.get_running_loop() async def coro(): bind_contextvars(a=1) @@ -125,11 +131,12 @@ async def coro(): assert {"a": 111, "b": 2} == await event_loop.create_task(coro()) - async def test_clear(self, event_loop): + async def test_clear(self): """ The context-local context can be cleared, causing any previously bound variables to not be included in merge_contextvars's result. """ + event_loop = asyncio.get_running_loop() async def coro(): bind_contextvars(a=1) @@ -138,11 +145,12 @@ async def coro(): assert {"b": 2} == await event_loop.create_task(coro()) - async def test_clear_without_bind(self, event_loop): + async def test_clear_without_bind(self): """ The context-local context can be cleared, causing any previously bound variables to not be included in merge_contextvars's result. """ + event_loop = asyncio.get_running_loop() async def coro(): clear_contextvars() @@ -150,11 +158,12 @@ async def coro(): assert {} == await event_loop.create_task(coro()) - async def test_unbind(self, event_loop): + async def test_unbind(self): """ Unbinding a previously bound variable causes it to be removed from the result of merge_contextvars. """ + event_loop = asyncio.get_running_loop() async def coro(): bind_contextvars(a=1) @@ -163,10 +172,11 @@ async def coro(): assert {"b": 2} == await event_loop.create_task(coro()) - async def test_unbind_not_bound(self, event_loop): + async def test_unbind_not_bound(self): """ Unbinding a not bound variable causes doesn't raise an exception. """ + event_loop = asyncio.get_running_loop() async def coro(): # Since unbinding means "setting to Ellipsis", we have to make @@ -177,11 +187,12 @@ async def coro(): assert {"b": 2} == await event_loop.create_task(coro()) - async def test_parallel_binds(self, event_loop): + async def test_parallel_binds(self): """ Binding a variable causes it to be included in the result of merge_contextvars. """ + event_loop = asyncio.get_running_loop() coro1_bind = asyncio.Event() coro2_bind = asyncio.Event() From 56f2375e14c84c5bef87f8585a6f970ba160ae44 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 2 Nov 2023 08:24:37 +0100 Subject: [PATCH 1116/1520] docs: fix link --- docs/frameworks.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/frameworks.md b/docs/frameworks.md index bfcccdeb..02c5149d 100644 --- a/docs/frameworks.md +++ b/docs/frameworks.md @@ -7,7 +7,7 @@ If you use standard library's logging, it makes sense to configure them next to ## OpenTelemetry -The [Python *OpenTelemetry* SDK](https://opentelemetry.io/docs/instrumentation/python/) offers an easy API to get the current span, so you can enrich your logs with a straight-forward processor: +The [Python OpenTelemetry SDK](https://opentelemetry.io/docs/instrumentation/python/) offers an easy API to get the current span, so you can enrich your logs with a straight-forward processor: ```python from opentelemetry import trace @@ -71,7 +71,7 @@ request_started.connect(bind_request_details, app) Configure it in the [application constructor](https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/startup.html#the-startup-process). -Here's an example for a *Pyramid* [*Tween*](https://kapeli.com/dash_share?docset_file=pyramid&docset_name=pyramid&path=narr/hooks.html%23registering-tweens&platform=pyramid) that stores various request-specific data into [*context variables*](contextvars.md): +Here's an example for a Pyramid [*tween*](https://docs.pylonsproject.org/projects/pyramid/en/latest/glossary.html#term-tween) that stores various request-specific data into [*context variables*](contextvars.md): ```python @dataclass @@ -94,7 +94,7 @@ class StructLogTween: ## Celery -[*Celery*](https://docs.celeryq.dev/)'s multi-process architecture leads unavoidably to race conditions that show up as interleaved logs. +[Celery](https://docs.celeryq.dev/)'s multi-process architecture leads unavoidably to race conditions that show up as interleaved logs. It ships standard library-based helpers in the form of [`celery.utils.log.get_task_logger()`](https://docs.celeryq.dev/en/stable/userguide/tasks.html#logging) that you should use inside of tasks to prevent that problem. The most straight-forward way to integrate that with *structlog* is using {doc}`standard-library` and wrapping that logger using {func}`structlog.wrap_logger`: @@ -105,7 +105,7 @@ from celery.utils.log import get_task_logger logger = structlog.wrap_logger(get_task_logger(__name__)) ``` -If you want to automatically bind task metadata to your {doc}`contextvars`, you can use [*Celery*'s signals](https://docs.celeryq.dev/en/stable/userguide/signals.html): +If you want to automatically bind task metadata to your {doc}`contextvars`, you can use [Celery's signals](https://docs.celeryq.dev/en/stable/userguide/signals.html): ```python from celery import signals From 08111537ea9b157e0233d17d9226f11dea8c9f42 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 2 Nov 2023 08:29:39 +0100 Subject: [PATCH 1117/1520] docs: fix more links --- docs/performance.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/performance.md b/docs/performance.md index 298a60dd..7b829db0 100644 --- a/docs/performance.md +++ b/docs/performance.md @@ -38,7 +38,7 @@ Here are a few hints how to get the best performance out of *structlog* in produ You can still configure `logging` for packages that you don't control, but avoid it for your *own* log entries. - Use a faster JSON serializer than the standard library. - Possible alternatives are among others are [*orjson*] or [*RapidJSON*]. + Possible alternatives are among others are [*orjson*] or [RapidJSON](https://pypi.org/project/python-rapidjson/). - Be conscious about whether and how you use *structlog*'s *asyncio* support. While it's true that moving log processing into separate threads prevents your application from hanging, it also comes with a performance cost. @@ -93,5 +93,3 @@ Therefore a log entry might look like this: If you need standard library support for external projects, you can either just use a JSON formatter like [*python-json-logger*](https://pypi.org/project/python-json-logger/), or pipe them through *structlog* as documented in {doc}`standard-library`. [*orjson*]: https://github.com/ijl/orjson -[*rapidjson*]: https://pypi.org/project/python-rapidjson/ -[*simplejson*]: https://simplejson.readthedocs.io/ From a51e0cdbd9cb658bf0478a5099dd11367a13e5de Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 2 Nov 2023 08:44:32 +0100 Subject: [PATCH 1118/1520] docs --- .pre-commit-config.yaml | 4 +- docs/frameworks.md | 91 ++++++++++++++++++++++------------------- docs/performance.md | 7 ++-- 3 files changed, 54 insertions(+), 48 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ed2a238d..376a324b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,12 +8,12 @@ default_language_version: repos: - repo: https://github.com/psf/black - rev: 23.10.0 + rev: 23.10.1 hooks: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.0 + rev: v0.1.3 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/docs/frameworks.md b/docs/frameworks.md index 02c5149d..a0a997eb 100644 --- a/docs/frameworks.md +++ b/docs/frameworks.md @@ -2,34 +2,34 @@ To have consistent log output, it makes sense to configure *structlog* *before* any logging is done. The best place to perform your configuration varies with applications and frameworks. -If you use standard library's logging, it makes sense to configure them next to each other. +If you use standard library's {mod}`logging`, it makes sense to configure them next to each other. -## OpenTelemetry +## Celery -The [Python OpenTelemetry SDK](https://opentelemetry.io/docs/instrumentation/python/) offers an easy API to get the current span, so you can enrich your logs with a straight-forward processor: +[Celery](https://docs.celeryq.dev/)'s multi-process architecture leads unavoidably to race conditions that show up as interleaved logs. +It ships standard library-based helpers in the form of [`celery.utils.log.get_task_logger()`](https://docs.celeryq.dev/en/stable/userguide/tasks.html#logging) that you should use inside of tasks to prevent that problem. + +The most straight-forward way to integrate that with *structlog* is using {doc}`standard-library` and wrapping that logger using {func}`structlog.wrap_logger`: ```python -from opentelemetry import trace +from celery.utils.log import get_task_logger -def add_open_telemetry_spans(_, __, event_dict): - span = trace.get_current_span() - if not span.is_recording(): - event_dict["span"] = None - return event_dict +logger = structlog.wrap_logger(get_task_logger(__name__)) +``` - ctx = span.get_span_context() - parent = getattr(span, "parent", None) +If you want to automatically bind task metadata to your {doc}`contextvars`, you can use [Celery's signals](https://docs.celeryq.dev/en/stable/userguide/signals.html): - event_dict["span"] = { - "span_id": hex(ctx.span_id), - "trace_id": hex(ctx.trace_id), - "parent_span_id": None if not parent else hex(parent.span_id), - } +```python +from celery import signals - return event_dict +@signals.task_prerun.connect +def on_task_prerun(sender, task_id, task, args, kwargs, **_): + structlog.contextvars.bind_contextvars(task_id=task_id, task_name=task.name) ``` +See [this issue](https://github.com/hynek/structlog/issues/287) for more details. + ## Django @@ -67,6 +67,37 @@ request_started.connect(bind_request_details, app) ``` +## Litestar + +[Litestar](https://docs.litestar.dev/) comes with *structlog* support [out of the box](https://docs.litestar.dev/latest/usage/logging.html). + + +## OpenTelemetry + +The [Python OpenTelemetry SDK](https://opentelemetry.io/docs/instrumentation/python/) offers an easy API to get the current span, so you can enrich your logs with a straight-forward processor: + +```python +from opentelemetry import trace + +def add_open_telemetry_spans(_, __, event_dict): + span = trace.get_current_span() + if not span.is_recording(): + event_dict["span"] = None + return event_dict + + ctx = span.get_span_context() + parent = getattr(span, "parent", None) + + event_dict["span"] = { + "span_id": hex(ctx.span_id), + "trace_id": hex(ctx.trace_id), + "parent_span_id": None if not parent else hex(parent.span_id), + } + + return event_dict +``` + + ## Pyramid Configure it in the [application constructor](https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/startup.html#the-startup-process). @@ -92,32 +123,6 @@ class StructLogTween: ``` -## Celery - -[Celery](https://docs.celeryq.dev/)'s multi-process architecture leads unavoidably to race conditions that show up as interleaved logs. -It ships standard library-based helpers in the form of [`celery.utils.log.get_task_logger()`](https://docs.celeryq.dev/en/stable/userguide/tasks.html#logging) that you should use inside of tasks to prevent that problem. - -The most straight-forward way to integrate that with *structlog* is using {doc}`standard-library` and wrapping that logger using {func}`structlog.wrap_logger`: - -```python -from celery.utils.log import get_task_logger - -logger = structlog.wrap_logger(get_task_logger(__name__)) -``` - -If you want to automatically bind task metadata to your {doc}`contextvars`, you can use [Celery's signals](https://docs.celeryq.dev/en/stable/userguide/signals.html): - -```python -from celery import signals - -@signals.task_prerun.connect -def on_task_prerun(sender, task_id, task, args, kwargs, **_): - structlog.contextvars.bind_contextvars(task_id=task_id, task_name=task.name) -``` - -See [this issue](https://github.com/hynek/structlog/issues/287) for more details. - - ## Twisted The [plugin definition](https://docs.twisted.org/en/stable/core/howto/plugin.html) is the best place. diff --git a/docs/performance.md b/docs/performance.md index 7b829db0..a6f48126 100644 --- a/docs/performance.md +++ b/docs/performance.md @@ -30,15 +30,15 @@ Here are a few hints how to get the best performance out of *structlog* in produ 1. Later calls of {func}`~structlog.configure` don't have any effect on already cached loggers -- that shouldn't matter outside of {doc}`testing ` though. 2. The resulting bound logger is not pickleable. - Therefore, you can't set this option if you e.g. plan on passing loggers around using `multiprocessing`. + Therefore, you can't set this option if you, for example, plan on passing loggers around using {mod}`multiprocessing`. - Avoid sending your log entries through the standard library if you can: its dynamic nature and flexibility make it a major bottleneck. - Instead use {class}`structlog.WriteLoggerFactory` or -- if your serializer returns bytes (e.g. [*orjson*]) -- {class}`structlog.BytesLoggerFactory`. + Instead use {class}`structlog.WriteLoggerFactory` or -- if your serializer returns bytes (for example, [*orjson*] or [*msgspec*]) -- {class}`structlog.BytesLoggerFactory`. You can still configure `logging` for packages that you don't control, but avoid it for your *own* log entries. - Use a faster JSON serializer than the standard library. - Possible alternatives are among others are [*orjson*] or [RapidJSON](https://pypi.org/project/python-rapidjson/). + Possible alternatives are among others are [*orjson*], [*msgspec*], or [RapidJSON](https://pypi.org/project/python-rapidjson/). - Be conscious about whether and how you use *structlog*'s *asyncio* support. While it's true that moving log processing into separate threads prevents your application from hanging, it also comes with a performance cost. @@ -93,3 +93,4 @@ Therefore a log entry might look like this: If you need standard library support for external projects, you can either just use a JSON formatter like [*python-json-logger*](https://pypi.org/project/python-json-logger/), or pipe them through *structlog* as documented in {doc}`standard-library`. [*orjson*]: https://github.com/ijl/orjson +[*msgspec*]: https://jcristharif.com/msgspec/ From 91d3feb676ded21bccae2fd1a61c7b88df147649 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 2 Nov 2023 09:04:33 +0100 Subject: [PATCH 1119/1520] docs: update performance --- docs/performance.md | 11 ++++++----- src/structlog/processors.py | 13 ++++++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/docs/performance.md b/docs/performance.md index a6f48126..b2dfb6b1 100644 --- a/docs/performance.md +++ b/docs/performance.md @@ -37,7 +37,7 @@ Here are a few hints how to get the best performance out of *structlog* in produ You can still configure `logging` for packages that you don't control, but avoid it for your *own* log entries. -- Use a faster JSON serializer than the standard library. +- Configure {class}`~structlog.processors.JSONRenderer` to use a faster JSON serializer than the standard library. Possible alternatives are among others are [*orjson*], [*msgspec*], or [RapidJSON](https://pypi.org/project/python-rapidjson/). - Be conscious about whether and how you use *structlog*'s *asyncio* support. @@ -49,10 +49,11 @@ Here are a few hints how to get the best performance out of *structlog* in produ ## Example -Here's an example for a production-ready non-*asyncio* *structlog* configuration that's as fast as it gets: +Here's an example for a production-ready *structlog* configuration that's as fast as it gets: ```python import logging +import orjson import structlog structlog.configure( @@ -76,16 +77,16 @@ It has the following properties: The `debug` method literally consists of `return None`. - Supports {doc}`contextvars` (thread-local contexts). - Adds the log level name. -- Renders exceptions. +- Renders exceptions into the `exception` key. - Adds an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) timestamp under the `timestamp` key in the UTC timezone. -- Renders the log entries as JSON using [*orjson*] which is faster than plain logging in `logging`. +- Renders the log entries as JSON using [*orjson*] which is faster than *plain* logging in {mod}`logging`. - Uses {class}`structlog.BytesLoggerFactory` because *orjson* returns bytes. That saves encoding ping-pong. Therefore a log entry might look like this: ```json -{"event":"hello","timestamp":"2020-11-17T09:54:11.900066Z"} +{"event":"hello","level":"info","timestamp":"2023-11-02T08:03:38.298565Z"} ``` --- diff --git a/src/structlog/processors.py b/src/structlog/processors.py index b4063332..71f1d182 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -317,9 +317,9 @@ class JSONRenderer: serializer: A :func:`json.dumps`-compatible callable that will be used to format the string. This can be used to use alternative JSON - encoders like `orjson `__ or - `RapidJSON `_ - (default: :func:`json.dumps`). + encoders (default: :func:`json.dumps`). + + .. seealso:: :doc:`performance` for examples. .. versionadded:: 0.2.0 Support for ``__structlog__`` serialization method. .. versionadded:: 15.4.0 *serializer* parameter. @@ -332,7 +332,8 @@ def __init__( serializer: Callable[..., str | bytes] = json.dumps, **dumps_kw: Any, ) -> None: - dumps_kw.setdefault("default", _json_fallback_handler) + if dumps_kw != {}: + dumps_kw.setdefault("default", _json_fallback_handler) self._dumps_kw = dumps_kw self._dumps = serializer @@ -342,7 +343,9 @@ def __call__( """ The return type of this depends on the return type of self._dumps. """ - return self._dumps(event_dict, **self._dumps_kw) + if self._dumps_kw: + return self._dumps(event_dict, **self._dumps_kw) + return self._dumps(event_dict) def _json_fallback_handler(obj: Any) -> Any: From 9d626bfd04a1ea0c314fc2a7488067d47e20c8c4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 2 Nov 2023 09:07:02 +0100 Subject: [PATCH 1120/1520] docs: clarify --- docs/performance.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/performance.md b/docs/performance.md index b2dfb6b1..fc8a3590 100644 --- a/docs/performance.md +++ b/docs/performance.md @@ -75,7 +75,7 @@ It has the following properties: - Caches all loggers on first use. - Filters all log entries below the `info` log level **very** efficiently. The `debug` method literally consists of `return None`. -- Supports {doc}`contextvars` (thread-local contexts). +- Supports {doc}`contextvars` (thread-local contexts outside of *asyncio*). - Adds the log level name. - Renders exceptions into the `exception` key. - Adds an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) timestamp under the `timestamp` key in the UTC timezone. From 55f9e26ea92aee7b7a71869f6b3f691a0b758166 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 2 Nov 2023 10:37:35 +0100 Subject: [PATCH 1121/1520] docs --- docs/bound-loggers.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/bound-loggers.md b/docs/bound-loggers.md index fa6cb010..4415af89 100644 --- a/docs/bound-loggers.md +++ b/docs/bound-loggers.md @@ -77,10 +77,10 @@ logger = structlog.get_logger() log = logger.bind(foo="bar") ``` -Now `log` is a *bound logger* of type {class}`~structlog.typing.FilteringBoundLogger` (but in the default config there's no filtering). +Now, `log` is a *bound logger* of type {class}`~structlog.typing.FilteringBoundLogger` (but in the default config there's no filtering). `log`'s context is `{"foo": "bar"}` and its wrapped logger is a {class}`structlog.PrintLogger`. -Now if you call `log.info("Hello, %s!", "world", number=42)` the following happens: +If you call `log.info("Hello, %s!", "world", number=42)` now, the following happens: 1. `"world"` gets interpolated into `"Hello, %s!"`, making the event "Hello, world!"[^interpolation]. 2. The *bound logger*'s context gets copied and the key-value pairs from the `info` call are added to it. @@ -90,7 +90,7 @@ Now if you call `log.info("Hello, %s!", "world", number=42)` the following happe 4. The *event dict* is fed into the [processor chain](processors.md). In this case the processors add a timestamp and the log level name to the *event dict*. - Before it hits the last processor, the *event dict* looks something like `{"foo": "bar", "number": 42, "event": "Hello, world!", "level": "info", "timestamp": "2022-10-13 16:29:27"}` now. + Before it hits the last processor, the *event dict* looks something like `{"foo": "bar", "number": 42, "event": "Hello, world!", "level": "info", "timestamp": "2022-10-13 16:29:27"}`. The last processor is {class}`structlog.dev.ConsoleRenderer` and renders the *event dict* into a colorful string[^json]. 5. Finally, the *wrapped logger*'s (a {class}`~structlog.PrintLogger`) `info()` method is called with that string. From 4d8e11505c2e9d671ac554845825d39051e16ecf Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 6 Nov 2023 07:01:32 +0100 Subject: [PATCH 1122/1520] Remove accidental change --- src/structlog/processors.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 71f1d182..1faebfd8 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -332,8 +332,7 @@ def __init__( serializer: Callable[..., str | bytes] = json.dumps, **dumps_kw: Any, ) -> None: - if dumps_kw != {}: - dumps_kw.setdefault("default", _json_fallback_handler) + dumps_kw.setdefault("default", _json_fallback_handler) self._dumps_kw = dumps_kw self._dumps = serializer @@ -343,9 +342,7 @@ def __call__( """ The return type of this depends on the return type of self._dumps. """ - if self._dumps_kw: - return self._dumps(event_dict, **self._dumps_kw) - return self._dumps(event_dict) + return self._dumps(event_dict, **self._dumps_kw) def _json_fallback_handler(obj: Any) -> Any: From ee01cab6cbe0597a55e7407d4051da18610d0c3d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 6 Nov 2023 11:13:38 +0100 Subject: [PATCH 1123/1520] Add a new logo! (#573) * Add a new logo! Contributed by @econchick. We thank our old mascot Keith for more than 6 years of loyal service and wish him a log-abundant retirement! Co-authored-by: Lynn Root <1191069+econchick@users.noreply.github.com> * Spacing * Simplify * Compress --------- Co-authored-by: Lynn Root <1191069+econchick@users.noreply.github.com> --- .gitignore | 1 - .pre-commit-config.yaml | 1 + README.md | 6 ++---- docs/_static/.keep | 0 docs/_static/BoundLogger.svg | 2 +- docs/_static/Justfile | 11 +++++++++++ docs/_static/console_renderer.png | Bin 319196 -> 319191 bytes docs/_static/docset-icon.png | Bin 1389 -> 677 bytes docs/_static/docset-icon@2x.png | Bin 3021 -> 1810 bytes docs/_static/social card.afdesign | Bin 0 -> 577103 bytes docs/_static/structlog_logo.afdesign | Bin 0 -> 112021 bytes docs/_static/structlog_logo.png | Bin 98810 -> 152510 bytes docs/_static/structlog_logo.svg | 1 + .../structlog_logo_horizontal.afdesign | Bin 0 -> 58175 bytes docs/_static/structlog_logo_horizontal.svg | 1 + docs/_static/structlog_logo_small.png | Bin 49112 -> 22682 bytes .../structlog_logo_small_transparent.png | Bin 26266 -> 0 bytes docs/_static/structlog_logo_transparent.png | Bin 79862 -> 0 bytes docs/conf.py | 7 ++----- pyproject.toml | 2 +- 20 files changed, 20 insertions(+), 12 deletions(-) delete mode 100644 docs/_static/.keep create mode 100644 docs/_static/Justfile create mode 100644 docs/_static/social card.afdesign create mode 100644 docs/_static/structlog_logo.afdesign create mode 100644 docs/_static/structlog_logo.svg create mode 100644 docs/_static/structlog_logo_horizontal.afdesign create mode 100644 docs/_static/structlog_logo_horizontal.svg delete mode 100644 docs/_static/structlog_logo_small_transparent.png delete mode 100644 docs/_static/structlog_logo_transparent.png diff --git a/.gitignore b/.gitignore index e2980f24..89b4da12 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,3 @@ htmlcov tmp structlog.docset structlog.tgz -Justfile diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 376a324b..b1ba940d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -35,5 +35,6 @@ repos: hooks: - id: trailing-whitespace - id: end-of-file-fixer + exclude: docs/_static - id: check-toml - id: check-yaml diff --git a/README.md b/README.md index 372e8048..07142c35 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ -# structlog: Structured Logging for Python -

    - structlog + structlog: Structured Logging for Python

    @@ -105,7 +103,7 @@ The idea of bound loggers is inspired by previous work by [Jean-Paul Calderone]( The development is kindly supported by my employer [Variomedia AG](https://www.variomedia.de/), *structlog*’s [Tidelift subscribers](https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek), and all my amazing [GitHub Sponsors](https://github.com/sponsors/hynek). -The logs-loving futuristic beaver logo has been contributed by [Russell Keith-Magee](https://github.com/freakboy3742). +The logs-loving beaver logo has been contributed by [Lynn Root](https://www.roguelynn.com). diff --git a/docs/_static/.keep b/docs/_static/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/docs/_static/BoundLogger.svg b/docs/_static/BoundLogger.svg index 62152411..35a7a17a 100644 --- a/docs/_static/BoundLogger.svg +++ b/docs/_static/BoundLogger.svg @@ -1 +1 @@ - + \ No newline at end of file diff --git a/docs/_static/Justfile b/docs/_static/Justfile new file mode 100644 index 00000000..c4a919ba --- /dev/null +++ b/docs/_static/Justfile @@ -0,0 +1,11 @@ +rebuild-logos: && compress-logos + magick structlog_logo.svg structlog_logo.png + magick structlog_logo.svg -resize 220 structlog_logo_small.png + magick structlog_logo.svg -resize 16x16 docset-icon.png + magick structlog_logo.svg -resize 32x32 docset-icon@2x.png + + +compress-logos: + svgo *.svg + oxipng --opt max --strip safe --zopfli *.png + diff --git a/docs/_static/console_renderer.png b/docs/_static/console_renderer.png index c67f7c0528904b99b12dbfbe15d6dfec74fa6d1b..20a123e2dae0d20f42fdf9194234dcf395951d3f 100644 GIT binary patch delta 212268 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�yC_SYm1sY-8f5aeh>ZvPgar^$ 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°$N1Z{I}3BjBPGRdpJ^#t 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� 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 OSRJQ-}g8yicuY5ozbW{e~ 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

    SSBFGamd?`;s^cU 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≀7Nuh5IBZ`1SBtNTl9YNaPw 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 Fe*utMpL_rS diff --git a/docs/_static/docset-icon.png b/docs/_static/docset-icon.png index d83f09c6d28b0c694f30e29b5f64c3cc950882da..cf924770fa504b29c84318828183916e241097e0 100644 GIT binary patch delta 666 zcmV;L0%iT}3Z(^*7k>^20ssI2sZ9&r00009a7bBm000id000id0mpBsWB>pHS4l)c zRCwAoQ3J5tP8iQ_c=p}1t}g-S7K; z0ES@@1c4CJHH~Fil#vuZo{dfc0G!qJ7JrCyd6BBpG|jLqet$_3GvD2-SEEDyEkP?Y z{tKjel+WP+&h99?gQcdvp>V2W(UNV4kIV(=x-N{5#vk1PZq^qHx#bklGy)JxrkpB) z)X!@|-ViIR@XNUXjH=4Zs&*=+7F`x+o@Qt%MgUmyR+S7Wp_0$e1Y8V;4rT+=v2Zy) zX>aWv3}=iCYJc+Dk-HK=sMD4)J|}rw>Z+Y+axljyoPm%TF#hdRTGkj}y8FS|&z@64O&z5!00CAdQcX4EFzR zXl|*hs&+V?I5#o>;ae14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>iln8El(n8T0|T?J zuCB4RbeOwNf}eq}gNC}2n1Q+!&<)yJ8ZmzEvED9uG0w>WhGsf)K*3l)v$A+ATSIvX z5&pagv!ZAV4J8Sncz~m(je)$bnp8!Cb#Azsgs7m6p+ae#Rb#rnnXa6SgixTPW=F2G ztA(ngiBfmIi?^-1v6d`QusFu5Gtb4tN{x?~+dy3sXmWYHwV{TLjD(<-o@{%LQ)Y;X zi@6FYOw{F6B$E9N8JO6Bp`~wNU}$7ypdsUJqv~Y?3}04Y_*h$8+u7Oa=;-kC z^DE1WnCr^<*=snPDe0+6ad2>GYHAuA8v}z^P7dT91_nl;IaP6fb&39^QQox~A^D-+ z;clJ@UY=EnL8VDD!mf@^wWY&I}5$5Q=NbTSQcj$=dCxT%+ue+xFp`*+d(hhN53%2ydcVa zVu^cyP5h*afcDbp-Xf2Q#qQH9y($x}TQVJ|S9oQGnxscMO|A}|Ru?g?!mA_4xhv1b z&QQ+9T-nv$)X~8%$ip%>(z+_yt~kcBx6swX)X>Aj)7#tI$;rvwNCy~7Fz|g8L3GxG_aUy{2f<1jP=3Fihe!bpc!?FE|kJ;-R zDl7|XbzWSQcKz|mS^U)Rl*)glMoa$w&EYG1{@lXx$;;28j*qND~b^6J+6rkOVN#5=*w`a150h2rfdx@v7EBiA}L0(n)mUzFf zKxt`D7sn8Z%Zvhy@Be|6Gcc*CYiMd|>o7C0fSt~&t5;o9s}D>*Yz*uS3>=)sCUx}< zjZMuhre>hb&CO$O(c0GD(b?6~ZE3~Jz`$p1)6?DC*FRz6q{&lk`GMKr&VK5&=`&`| znmuRkJO^NY7jSZ(GJnC8g^Lz1nX}Xdn2815+?Oq1v2x0))oa$adU!Gj35$63tXscf z zT6RuuUVcGgkt{Hc%NLiFmX%j1C@NJ}DXXY5tbU)V*~t3a1L#ZD64!{5l*E!$tK_0o zAjM#0U}U6gV5w_p7-DE(Wo&F^YN%~sU}a!%g(vVPiiX_$l+3hB+!~e!zDxyb(16=e pl9`)YT#}eufY4(eVrXn-Y;I)?wdC^blw6=522WQ%mvv4FO#l|6o9h4o diff --git a/docs/_static/docset-icon@2x.png b/docs/_static/docset-icon@2x.png index 81a099d9659877e8b7577d954f3ac8a77e9bf61d..86508839b390f6b91da389d05f03c2b9a3dd3af0 100644 GIT binary patch delta 1808 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 E58qIo{{R30 diff --git a/docs/_static/social card.afdesign b/docs/_static/social card.afdesign new file mode 100644 index 0000000000000000000000000000000000000000..0a7d3810441f45479ef6b03856e54a5e7ae7e557 GIT binary patch literal 577103 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�sMcndVhAT|H$m-U&USi;a17| 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

    &-ci8!gss(wfC`~-OFg_O4_-W_OGQiV4uuB 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 X{0!I&bK$&%fG-UdUFAxp7vcW{I6;?N literal 0 HcmV?d00001 diff --git a/docs/_static/structlog_logo.afdesign b/docs/_static/structlog_logo.afdesign new file mode 100644 index 0000000000000000000000000000000000000000..0f26ebaba6a60e16c5ea9e07ebab624151c28a87 GIT binary patch literal 112021 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

    H;u^{6aX>qL=Er zI-p1O>0_lgYG>A!R7G0OQf2VS?_qotO8fpPl|R2$f4Z0R#}mS*w4c->3UjCPo3)_# zg1g_D$vXU01Zjj@X(lpwkVA#N179%HuP`FHEP6{(+x=*JYtgz}-^=TsSDEWzpsEPQ zik90=k}B0@M|NatMf#1OvIQO_sa;f`f&s6vskVyhI9G_)to&scg8AAUlH7&CP>Ff( zcY8V-Z-0Rz$WKgi>(1wEW3#A|%O7Mnt?#RnXBk{SYQV1_|77l9vA9j-_Lwib+^zrL z=O;3oZKA#9Y-(uEoXP%m)I&=ojt#$574Ym-v?tyoWtDGEYKgW+ua)7twwOZFXzXzw`=2WYrU^UHc-l>$H>r14Yo$h(B{p9$6tblgH8ehO_KkXpW`%DmoW=sz^FfYCkHt zRo=_!Mn*auUumky35@7MKjib7!g@HNXUVM}v7@S(bdXzX=^KNU=GBkf8J&;RJ9jwOG% zVGzbwFkbfjx6(MNeoc|_`$kC+3hL>$gAPybq%(L7foj@Qm4I<$e3&=>^p- z6oiJw;)DbR=5u^!>to}XP;j$W(;Ji(vDX7YF-`@X#Qe5-ZX-+m4 zd9mTCtjbnyqLIc`==?r?q%ASzP&g%s{L8dVuXIPI_>eQpdwOWQT|T?BVC|Q=n+o4v z^`5TM7@Gh{%s}iaQ}fieNw2V=Zn|<7Bo_Jkb^%l5Q@)5yXo<@&O6 zlTrnpy2sm#5YqiblKi;+Ugf-(=HHT2fw4-ac(VDaku-7gC85&(c9k1i+(=)SG&z9L zq-U)=F`3jw^r;r30B)!0kMur8!*d@H#nn%5Ckza-?FBm)J-e1NFLD^{&zne#h26%?mTxJ3CeOG1ox+@)^50wJib5fk}9ArhKr5#08ma2yCK_>TmyG?xFky)gNs+&IP16W>AvO!)_Wvmf2wb7$X;u+k{)w; z$^FEQr+WKZ>;HNBRd0AxONP;04}(E@tk2WDzYozw17}zDwgmiT?CIH^%O*AKjWKgv zI_cWLZYwuXZ4P7(OQA$zw&hL+allVfN(sfjGqxY&1&4V~jjW!2Drr>>^S>t@g>@iu zYVJAc%XmdZe)a`-;&*Fbkgm*HD`UQsq9J}{1gTBnhxEmv%e7Gbhwzly_ z<}RAl$iI4+t>iC;c}+42aW<+r&er`*v zcRi~I4H*x)pZ?d?&%u)abW_|!$UHivY6w>vp%B1#bl+XTLkbho`E&6cQ4s+Rf(q~e zM~qJ3G#a+|;Y)dCb0~L_$TWoYoh$`WIEZPwefJhmp2GxgMoQAlXp=<#R$+n-f2ARo zls~4N4@;#&8vAErjP$dG(VV*5sJEpEyXc>Dh_iQV5he3z*1C^pNEdECVw(Z2N6M&gR;%zH3{%Q%SEJmCqsY)@ET*kMmvI~TO9 zarr(19QnApV)ae8QC?Dmc`~<8<&b&mSj2p0;1A3Y=O`qZ`}&FP2PXUUw}##U@9)+g z#w1$`5!e!Q;|H$xCaaGIP2q*##waP@QI{+MxBWNK*98uAc$!V+meu#%B3|5C?YSUT*^<%*)Gq|{sh>PD>HOeaQw&3+MRaDj2J2-< z_B_>hea4%Qh(Ztu;q;YFfv+7?E&Ml7d@dp~=b`C7KtbUi`D^7Z>E!S)PgS%Tej4%tuSX%~nFRbMi&FGhV-UOyTd`Pfb=LlXdhcVU27` zDeWM6TKJF+ExL{9{$)}c`dD~&*+P;(DLMFej##1A*&ggLQ6dex6l`bXA;^O}17G~w zJP))|otYLNtQPe#@Z}s#y<)Aa#Mk8mi_TYIZ~JHsbKuFr5jxUl8Lz*8lZ+MM_?;=r z)7M8kdQ{(i8%Z+vm!zSC0<}~U&osm`l18l+POTiWx=>EfHJY7;f9NigK`&nKLGEIp zFE`w9KTTVjpJeom5mhbpxiDMxVyDysgAv2~*Prv^A1t*GR~}*V%vbQxh7-@h(O-X+ z6o|rs7ix4@{OL@2so~Gyn^0a6I5h|TPh9 zD6m~fHux&~*K$WIE-adZjHJxN{u4|7O%mhXaJ^eOUz&)>JKx)A2-0)=&U>Rdo~Qc* zqZB^vK9XOwX^1P#Dt$;GtFN+>g(R2oAoMU&VdgmSu*R*#$R8ROZtLiVa~n0r$@D^O zI3wg#up!$yi2PROuLNy6#TpIC{)Eq z^CU2tL3SCbbqf(;-@ONG8L927m=E(J6kSgO%?Sku2PwoMYkX4Ojm<7WEG?W=4&q$g z->p?(?+Fm?BRUfnQ|xpyP?%J*q*mW-@AlT~QqLht!kyRTzNfT$S*}V6;`8RK7>MlW zUWeqb#PjwH?}3cqN~q2gf3YpEn#e6T-ka}%<;qiQkIywc^!ff575YKv&i%>jFit260D-0H(m#7+dU%^3OFCHPrCRYeeFg*ILYE0acy;7B z{90MNdD$Q={a$JXViJ+CH}{CpY8jj<6}8h-TRN+Sr_l>86XK+<=YHVbCZ}Iu(4=S~sLl0pbaQUA_QUG20rc?4-{_b<=E!Xi@un_?rlsU^+R8#u=LO zH15+;pk{>`y#-;ds{y~&q56t3Uq7`~L3z49tgak)mKSLB$^!E57+QbTUHDm*8ybj8 z3!%c0;C!!!{l)!_QJiDC*Su8DBMNbLM`F)+#>h$UKKcB2W{SFzOfMcZjr=Yg>0V{) zT`YsC@S#6-HhELQ1g3ebs@8OlY8i17%{`CWkQBuYUBqq;Q%J2nUf)3QDaYNROtSxoh<^+bL^N zjHJ9bZ+x;v$Jws7k6P*J>QuEe$oXAQeEbt$T#M{*1fAc z{hr)nsPefL{LpfzG;WpD)-Y#%J?~btS>!s?Hs2dYxiNQ7v;6VZPNB6fIN!ZR!a|{G zj@-=WkWlg*2xHoI2`D*Kgid4dV3+vkUlm#3OJ&L=uWKL;I@2e+-0I9`Qjr#RfyO|q zVO~j4Z<(qtI_AmxfhObqPgdS(I^iqva4M=)XYh8ijHMJJoD3qJhGb_#eT4_Sndr#w zVnft(p9cu8xnAg`|8?voE%5P)AlGSfTQjVYaXo;j{9fM_u}OMEvyET9VC`w|^Z5uJ z6oxxc?qp#=2>cw?h{pNG&3^~ z=ZTQcC#A3kfE|Zf^zX7XdmAy7&4gP?0z^xVUZ#o;l&rY$1std(Sh4VaE4rLnOMjCx z#4D2WI#M5BIY76NQVC~Lg-&DpjmyFZZK|fcz7YW~CkV!Q86FUI#)}TKHpu4r^lPEl z@KIa!GMsANqvab0VMBRwSY{l0J3C`4cr)3`s47l6)08jkV3bs#&O%m1V&P|2MIyz{ z(Kz`|4$t$`>}Lm$Sy=fn9?Niq=V#?Os2Ft3da+zNCI02C0IKO?JVPZ~XC+(iG=yq1 zP=3D}mPSUI3lK4b>MGv>FGIT@tq>uS6q)dp1G_QoqzMUeDc&5a$^)4+h3*T%dP}?> zUekK$XdJwD>VLNHwBb04mRkxB-@AxQc~C6O@r*Q?2##rq^4-27Ei)Ij_|cB?h*4dR zU{A*qtSx)w2Z{B7O9Tb%A9spw+1YW1h!P-&#>f}QPIPPB74dmgrCHlcN?cPw1&`^o9=F2BIZoxYA=~uR z6b)5O3{Gx76{CP1L};i|+47mSLl9CEWM)@nViZ3HrT=cg1`A*10Kk1f9;vYAX^@8_ zpCoU$qF|30eSjEifRn>+=-VK7a8`W(CHE{Jue#B?93ee{e)pE=rcaAHVY7uPZ_aj9 zTE*ROkMUAcWZGSeVZ$J5FyNHIQzZ`(8N+wK<`w#@yWa>Gt;=3@FBYW}>Dc6sZ#G|D%HDpqnYb=)d z8^9xIVR*IiG_@>y&dc}PZI5b~6ZKc^7RGOG%a%%aTNF2Qf2#}jS57ifh`M{T$Ib$^ z$TG*4xeo%-5q~Kc$^0X@df}QK;&-RfD))htEncAZ`(EN(ub}ZxJF*QFhqGq?q99< z52Z=Co-MWoMX( zCSVf3I$Gn%1OsO(oWR|8fPp zJ;6T)$Tiz|(E{zlda+&hla*hxd2M{X?IsV@6rob!A!p|UJ6b4J-Drido<7A$BikF* zVNSo7ZXDB)Q*fpeu;0u3SChvYrid%+%x|i!NH{J14;fZ*V$O?-io}UB`#JgM+=Z5c zWLr_E)XQ-r1=XYrI;K*^hNCUXs)c>h0&EOh3S(-Kcc-1~{T2#T#+!TTR>Ohfx$*I? zMl@B7Td~SH0s7zKx?B5^Uk-aHx0lq!`+j@u-9KCn_-=YqcKvh^+kq{UQlY~yy<_&> z-@k{S8VY?au*)ONGcw?E2=n^fhXh+3wL%z(?)Tf@_e;c90ftu`NDo^)uB>yJhqF9C zt~i$F>WZ*sJO-ve2Fmb#mggRFF~Fu1$_;R5Q2F$Q=-tb;^UXuA?pfvMb=W z{e%?U86sf=>}C1+>KDd#ZMEE0OrF)iD;o7iN=X5vK)}iN$iFTJ-E5K^rD~xA1uNmW z2Ah%CybSO~#I&{EZxr(!Xm(8xJqs9(V^-_1U(nk|!{$@ku~1B6BG9`ifyp=tt|2qQ zk;)APRScDL82$>Pn5uYdN5t+Xh$1GH((=mvQsmXae2JfH)J(K+ophXhYuOhy!1`+~ zO2R>*@CoQl@La%pH%$`f`jc zX@=ZCE^u+7lgdkt+1tQ28HBSR*bkN9bIZj{q))f^QWV1eg@r?$4RmhPhuX{S)|lGA zkI{UxcN0+7xlK9H;Ya&qc?pqn;uujYK4Qf5DEFm4%~)`3dJlfDWiKnA7#Q1SMqe3= z;t`J@ba}1qtz!-L@(z82PmOi`nG09REDcLm`yuGAKs9dpw0byi2#9mNkk;6EDDfnb ziS~B#*xZjqjJpHe@3zLF82XEI=6%k4JS1m_>K&lx&%hmp$pH$Lc`6J1dK26ℑoB z(?C1Es{PZ-bc~=lZy1QccR6tLhf7&m1I=`~F&F==_H#ZMmB4QqxOfrYOe&|o8quSYg*Xw6y>J}q_pb2npYBxgBxQRJ-T9+57) zg@1VL_>LE74F@?G7HQ7X#+z3gK2_;{9nA#v)8*`F5C~+#Kz~T>_H?HO-}q^TCuUy9 z^!EwNVWtX;7u>v-VgH*IX@^j4=mkbzqwRM0a1*?q;h~2nJYjFk%hxN)lq*GNE=HsvK8BbTj8=X)n35KeV|62xfB z#`u2Th8ZGD?}Ij)~XCR%S188qXG+0>hMt}*p%(} z45t9n8h_op^*w!}di0O>8;|B+otjLxyV{NNnxQ{FA|Yg5dJ#Mq$${9^4#!xImMa%?RxC-VId>k-%)1vorJCD5=$s z;?Drj&Edbu)zhHpt!9o)TV(ixlRez15-)Xg_ReL*MzpH?S|uX~vXwi(#4{prOGcaj z2N=N!oMwxKHO@^cF@jE50?BC8*?J?S%lV595L27dy%IP(d4L^Qu4w2%5AKGcZzaS&Ly+i04KQ6f!ZbogNZf zg18z7kiI?)mgbYc+hkFrFq73!R$FVQcBsI}ykGu<7)VB0I1l;*2mr8fk_6fwSy*qe2D%;3||1Zf!&(V{@sLh6u|D zW|%V1*nbB$hMVBZ%8)Nl^^BFJ?QM(UAcq?!Sm2i{mqr4?HS}Qo!1s zbYIc*$7jSnyDwui$w4gRq?+%*>q%!_S#sDEyRl=ci5LkN3q_~9tC&9kC1zBS`n*uZ z>1k-ZNZ08O=lno<=_fI(4ICAy>nxpqRyzx*b}ao6CyHay0S+}!pnw1%;r3*Cs63NF z6voT5P`F1H%F?&xI-z3_Zl_O&88K;_{w7V6?2vNn97-%cBLxViDlCT!Gan16S@x0~ z3E}x&zlJ0fc@|pm;?bs0)H#wW;Cy4jP&ZZ&WritzUAcBo2iZ9<)g`hyv57XiNT^X9 zY*Q8qDF^5$OEi1okFh#X{V~G(QUZmUfgjw~u|Zp(gBh0e$Kbz^>uDJ8momif<{Lsr zhf)+eL(X|CK9su-a+7=gTK0LyvR7(Q8#F?@DnRu8C13L2z{VG9;;+=imNbMF5(L05 z{J+W{?iK;gb@8O(4bl2p2}#HeP1ZJc1g~;81-s@Nsv`bv}a6)|SUqe(>qflsrOi3_3e*BbTC0 zQC`%_PxNgY_VQZXXW@2OU=jM7yKhwvo(5jnZ*DR0=P&@oO4+=_Fgr8HahE+&7TOW2 z5IWcGm=u=&DS5&xx*PXFnz~SMWp<8F=$B6-XEuVCS5i`MFPa_LKvb{klF@^REv_+DO4w=uf@8pPS1k1<1`sDfYUs@;3)!#y^^FS1_z^o$`H7XDfr#QffqZ%dp29ko?<233C31 z?#pz;KI(Yi^K9|-cV9>qOU)c%?pM=A=4aAMrlC{ocXPvzl%b9v0KTahXUEJ=lP-@p z`SGt>4DsjQ`w+^N7+vlCZ{QNh#CV?0%+^>5V&y$e{vY3COAaE2_xWTwbh(N#`eIme z!sTbK>ih0HY7a2PB3R$qY7kM(xaqnaaFpjK1WliIOln-Jww)aE+}P_=r4(@H7mP+r z83Pu>MxmVmrc-Afn6V*JUo;}4s_SLYmDLnplkm+QP`v@+{Pn*-|It*}+R5IN$%e_U z184c#4FI|*XCmMN=7bei)_eEC8{Su!$ zXai3Z*$4z@==q#|4W*IP3QzGdU=OtGC#;$rPOh}OT z{ip%}D4&R~kNT!5#TD9aM2iko$%Z^zAU|#-x=PV=+ESE|F;$U^7|X-nGEO4URRD0? z9jX*9haH&EOiNS>nJK@Ix;&>CXdc&RDEp2VZ_QGR@-8TEoTHHbB z|78I-FoQ6c1D>&FXXmbD_B3vagnAf5?s(e_?0wCYL=x#~;H%L^wFrIp3*x?07ii9= z0R<#{hXEwBz5)c|+33TRm%>#RSMFyju%`G#W2sQ@@>RtH&O|DinSqxUZ`FaA#2cV7MF5%q3}0py?a$0kSf zATNdf03m{AEkMZ!{^mcRqoFsU-`6$ao7b8u#iqS+lnz9LtFns7#nhCiFWOexy{11n zo3vTq1M4xCC(9Ckv8@8-->8$cg+m>cPHERfq0~Yl&2(tucHY4{ zWHjIL*HxC~B&`IKCIL5mLW95Zrq z;??dD1Z&?$H>$<~bW;gI-&~-Cl#md~9W$r)4o6Yc=gDqAoV|V^@D~Gy4h@@K2E4^@ z3(hXL55x<_1fVgHAKRI;iwO(bM1M8#|4xdKv{2qrW!+2|Ft9Shxr*TEY3k?Kx19ED z5M%pXpZ_@!=bbJoZci|rt@-5O;4n7x*A#R1W2G953Vy_^WohRcPoWH8+Nktt%6<4x zcZ2#A!rp~^8T8+)*^7TPp2wjO7&{?C8y&|!t9e*E=0*gSdSZ5Y_STG7emphI$8Gb= zB>E?!wcSrWu8q^iU|m#O4BS6>49o{PC;NPNvi7pFX8yWb56S5Yct|#1dU9ERL&9Ya zr>_cchO(}wt&yJMI0Y2m`=lV_NbAo9m(@l%wP3Dx$L}rN(5D|uA;Zf+C5kN};ca{;$aoKos`%5giD@sa5b;@uT?dyyPA`EE)? z%s&#c$N0Y8M^nUsCEkrS6$gAHXvdDmiA!1oaz>`mPscW)%ZvxjBlC9IX_I5wxhckZ zPH#%wc-8N9z}Nmv*Zu%8{aQ24!#Ao< z*G+3I2E4;r@0%1W$43G8%C>7HpLhu(1UvxgfmTy4^CkwIFA&a9W`%pYSr}c2h^a`^ z57UA2U54P!SJ^^g{{-N%t0n9 zW ziBq)VYUb%o?~25HwW9zx54Z~xIDfljY*iRP0x2ayVa~C%ipSj#$5jo=^#jtebJ7`W zMLrgLL#XgLfA8<0qXLsg8ox_pu&4P%`)fna+*W_qf6g-iR%?>h{U{E1IT2Ge;t@v- zbd!>BOwq@JHzS{@FR!xwZK&AKTi|jcG`3p!$#a@!|LW4AY2|~V_S;JuKZ;BqfUHAB zbtAy2e+ZGkF=61$@uo)qzK>O4ut6qZN|m{cQ)M@69skY~|0`@a1}VPz_CNyPd3< zgt$8dt{KhO{MXT zLt`P4sNn-6{4J4!3}5GO!yO}jvpLymD}=9X&8I}8th;w)3Nn zyuH4lR1+WdF%=!+v3c}+T(tIPm89_vgGo8qQOltWEQRtxQ~X|&F_KTAO2sJ(sb=@AIPouoR#1d@^7-54m_tVI8 z8#qorHIf;2*G{p_K9`R=!CP?PN~|&$Yx}O)vK9Z++#uLlwz$6eztCv_aSB=ry{;G` z-8(=yo3%4WM@JjAbuO_bUXeOVEuMOKV*cs*fFrIcoU|3Kt)KfA#6ERpeF<-dc3u%q zHP{vWoa+}f4ZxNsU`}`}DFz2AY-#q#)-GQ)6UWF?VAxJV0S7{}BkPj2aEci#A#LUq z;1~=ksotm3ZF;w;YrmDvbOWPrR!3HoVMR@C(l|;^^LqA3PJ5cy6T2Dj%};Ow)%zm> zdcJDDqJMG{qv=7aP3*c)+x>FTt^3^*Qs?6c&+!Sx?(sZt)33RU%#7=+Ogi5n3wjCR zzz?8P(2GQ-6fsraKOecX^-I#F-$#GIhIobS5kCe@0b69E;DS#eOP74l@x6WGlJ`8* zFfJ$3>4yKxKmJuw<9YYFuhUgIZ+OjjPAM5QiKoMm2`pz*@N8#6d;Qw3NrM@ZRRR#ouT|h9vh&I1ladtLr z$~3MPId3t#GP5s)eS%O3n=0mY_ftWGF^0P-NoQ$BX$DW4_<<pw^K^VghL9)pSE?EC$#zk_#qowHBPVqGniuMxkP~F(ymKr(s)u|4y_?lDEjiZ z!6_>NAwNDx5#z<%y`37kj*rbe%`Q#ZuPqyy|S=;Y*QwQB1Mx zaVeBBY`gtk=b&XZ=o`p8)8Du;)1(0OUzz7WRAEZi73yrDML>92u0lG$x>|VVnMv(l zk1eS+ogFt2YbUIEA&9Gz*M?OB9&6co8xyXiosv1xao{do$;>eTal#v-%PlWG5RSD> zm1pkjTs4uAf}VMP-1Z*jBO3novB#*jDC=EQt?58(G;%P+g>u}hU|T8acx!j|-Kn02 zoXSQ9<|MqUJk3#+60tBYe%LK&E!U@%D8=zDFy9oeD?)g^zbb029y)>Z$XT14BlGMp#iyv`APXF(w`0|N@y z{h$~5@}G}EvS;+D@Z=eNfM!lg3PD&y9zo&?#2x$q_XSk+ruh#`)pJwW>JVpA(dky@ zbWnDtii0-2%SwCfjF*>w{RF$uZaEx#=~;Ip>-!-(E*08*MJ~e6DXm{+)H3Pv?S+HS zv}V39{51udy*fcu>L!h1sFosaigF1la-|mfDCd4*eo25kx^^aj1I{a%O=1+oU^!|G zBRpsSg-dE{;F<=n2Z=VG$=>9P4s{)$TDsig_;~Y9Xt)7ZtO#@5c@=s}dNAX<4gYCI zlw~QXne4ySJz?)aT=l-HVU7$kM?>gwBs5+F?p0?f>fJ22A1(H|B9*|6QRa5ShYu)DH_JDKOU7-z?-) z0VK*H_bD;B;JWo_4x9xBkmY)C4C|yjNqq>ZARqS-Hg*BPa}gWp>H&z~*5p_Y`D*$5 z^Qec_y#698*ortZjR`M$%$9f9Q#4FSU{SE3dC#*-kPHiG3hg#WHuxoAnm8QrIX?K@ zBAcOJk4$B5!joJ@fH=m3$;omJla6?|baW(AQVJ;<@x0*O;U;G|DgRUf{ed?Gybb}f zm*fe|&g*V8pzY&Kd!jEpiw7RDeXpuEUUeH_?Qdw11LQu70$BIEH z8u+Z~MWaAd0%kwbe3_w9nljQ3v(wirm*vi&!~2{v#mlhe23#^y@@nGg^l@So_V94| zy7Na=9@|~FW&cs3w%ctX^Z(+#T7MJZS5qC|6?BLLgr}Z1obpU=U)%@rj;fXXPM^#W zTxrk$nlFeIS;FvnVeh_pdpI#2I(Ygh0yf%7y!TW8fSfb1O(Wy~O z=kjiY7EnOe(*UL7Q2{0k!dvdxBRF77>$&dQK1Ayh`#tI6-_NIhphDwZR6Ugsl5dritnf~GZ+@$iAc_Gkr z-Gwe%m%(x2bV~ODj)gg+8RveYdYMtcx7S-$St%G(lv8;zS}V%;3v;`v6`BcuOt^<4m3k9IYa>9%$9jE$(^e?BJS6>id-ZuQ>7x24LZIuC;=Aw{-KUYmVe|Yr z86%z=lyK;s`BKmi%QTQJ0>t?nQ{RcN9T{gO>9M%LVAq*Qn6m+5hl%sPULT9Wj~C6;yGO)P|H8ul8YG! z>|y#~2|!!6)|mr5@mbM1d4`+UdfSAtVrt;i2%JAR)Ra}ta~X%kA#z zY6RMZ^5j5n6$c5ip&jtwL~@z$%^_J8FKEkyKQ*jTafVIHVj2qK(Par2oMJ1n`NoAwv6XK2*2EQKHAn)wSR|v_G^g24+_esApW|%*Vh&bPgQwzd~(E? ztB8w%*zES`<-2@3_e>H~qOSAty^1zH?UqF^zJmFMpn+n~miJx%qy8iJ3KUW%UhvR$6YAVzitb+Q1e@WREXdB2veANp8Qq35Zo`_zi-i>11LR znC#@B!0Gw~aSUPHX0{c^NQww8LdZzgF$D&M{9ThzCpG;0`?E3R>J$d-w%ZLks)bgU z26BE!;e#@rcyO>hzJ!2)6+_>vEv~CF26bKWv-2`F-W+SrR_fiTlIpOPMYiPZ1V2w z-$AyuRpwTJiy#JZ!dIYc=Hwo(Uo{ct@Z=$nFFrut@D04Na)Rpe*zUef!4v{LhJLPM zEzTn>EygJ=o>-QM8n%SXN!M?MsJ*lprnLAl)UPba#hzcS%ZjOG`_4w{#0H z-JK#WAa&Mv?mfSF9)7^yYtOajm}87N*RhQ?@2pqy*0gf5_&bVPg1sVYI&Ema`w^&+ zDNT2%%w;$b#J(4FW-n(Pm&*($13|lzIXM;g>gO{)z^`JQDJJrt2NJD_lP#>kQT4R5 zL(JcwPL~HW2iA0|B5B1y{*XM@F*db=)!4=7ka#Q{m#-l!v{p$@mS- zHw(alTx?;1bGL&O(+*r$ppk5N^)OmDzK?$LmWb?NHN<|9hUO5oeV<)z-+Eu&!z=`R z*8WPVES`Xz`uUwKb_(7e=N!-Gje#yrH#sscQn2k>LxL%78$pEB(#pzEH&*yY8h@1=@M(!(XfOE?GnjJ<~j2{N)Mh~v7=x{v}WBJb4ka*ulo=sby0Llp2; zBj6v9!XTuh!>leTX2B3onD4B_=5}86e(D4M5k8A`cGu}n(# zf@dPl^*IZSTlw+#0ZiSZyY&V=e^j8K5TQ_Z&{M?y4{U(K8)}HSJ92;@xgd5#SKV8V zqt}4QW2^V_Ax7mwz&9j>y8RP3mNIox2?ee#aJWR!Bz-k~k4Qt~`L`bh0t89C5EvZ> z#!?oBpGS^Lo9>{r`QEcL(vFP(?Oyl=Go&wzn53`9j$w3EtK0l02>mF5Dq{4~IVdE= zHCwoE_>c~o$2O8I6*v_&b~Ju~)B%%Gj1?&rAq7=evu}=SJGMTyv8kq0+>rsb3cAgL z^X06SHxlCF0#w#U8igw`s3VMR4EW}NW!95dj_wU@j?8;Ou7TDqV?edMti-wXhn5;r*?W*0hAvACchFKlMsY?O%Wvnc_#oLfKD89{10QSsoE3gFCFUX zfMf%HiA^x`3XK(kWicPeo_v9guk)m-qp?}?E6M^(0ezLXTN^E2$hN2zdX)k4?omg0n&8_ldkYURSko#N%QlJT9q;ZuoJD&qXF zOcBHRp6VMZ|M>^tjF7)&g&EpS4!Hixw6~K-ya6Q0;>RvEa|8wOHY_ z^@bc-fiz;$7HhBbRh52l`+X==6cpSV;e4*tb`hShq_5Y1{ExpZD$;3~9hikFaxpgq z+tXcOY)A=Vtcpj{FPwmiuBQIEZxk;%Ek*x<$Pfkq-z)D{zZDIZ>+6}74Mom31?|Wby;5piOQ?vv7|-)x7XvOmY~qSHvi8$%s@z;BZDPRa|F6eXL}&QNlAsAPtOx~9EpC*)&EI!aa0$rD@;l?3uPtUq$bid1*6p>U514moUm_##^gc5q^9M8Y1S_0F zkB!-!0XJZ%P5UUnCP`;0(CYHo_nci#B)MtE(nW&6P}MdV49PK=bn^h29eCL&H*Z1a ztop<$mlQD~jXlz!tC2{>uhF2YtdTmsJF;yQ&rHPQSW}-=T51Kb>n|M@x%TEgAXD#pI$-vxzQfLtVoIk<{1iXipb73#HcMyE4MVMt!;X8^oWB`wmR0wafqC8Y z&$%QFn;1VPxy|q!7&eF{W$j&~%mt$q_E$|RQf@rN{pTD`v`GbpX);tW+sbu}0ylB|$?2(VvGvbW=UUUTH~euV7Dk@m3O@7|q6IJi{P}3$hkjTr&6z+BUX&f}XDtCO z5+dI^bWDpkI>)_W>Rl9tg7zS_EIgoTF+#xW%jBk+G~0|&+0mlIagcNg=341iCEIFy z4F;BeD^6Kz>MUF>QP3_fX!shNPI{SYha*!I{$%)fos+kYQ((&H&%~Dv93PlQcQ-dp z5A~bt@oT14lEe|@j5?-RVpQwL4`QGRm!9e4w^>Yjs*^Z+Z8TXb>Ls*4#E~B+Im65_ zKXO3(jw;*Q+iZrqC~M(bt3A4(onTzm(Un4|1NGt+B_!4Iu+x!-J8lIw?kBwrCB^2@ z)%uLMGfi97@+rpTn3y?g8_=}=%?LMVO0b1*>&frHmJ*{ec7fcub<5LXEMtgyX zG@~%>I?LG=zYjcM)i-lA`fl|m=_AVBlka{Cky)K~=+Gd2>X@1hm#;AEwBy~9;;-%G zF+9{g>_`*4MC@7u{Ha`8Yz(gK-b8X_y)Rp+wOYwOm|^LQa;ouEIf^ux9p_n9<##yF zd+a!4jB=F~iL7bhj}iq2^Qa)vo})rm0`j9b z*4UIaotj?y1%KdUt4xI0LbSD^?baDhE`A%)fMDuBrMVoYn=aCFJva+BX76Yn@fB9o z)|f^MPH`pFUTEH-Zh8;C~pQGW6X-g}dO*r`xO(0NxK?#px<1RyBPK{v_&@ zG2`Z?7T+TZ3nU~Wl6h4pUSd}dH>@bBRvtk)nxw`@gfgz}S~?bshf);l3@L8I?<$oP zMqDyE0s{R@92Ob&TmHDpxJPHF)C9TV)bkaR-r`>2dq4RBY6{A7K4sFVhG@fj z>Hfd3Ul(Z>;4806KPIC}3z-tfMKCy)xtvLLt2NFrv*C)Y`)xNU`F~!3p!^fMwn>w& z;bV=RF~EI(V)(2t%1tCzoz~?U9WWHUvh`g6dw;LqLb|E9qt*DgA(H5{+n?%+_{w=? z_{R>%`%6<6$BEd!tBiLM?D@V5*6-0&U z&eg0oH1)KNo}FR$NYiYYUywB+`$t}Rj*$^ibuwHQYJT`5W6*?uqP@UWj-^^DwQ$JW z6}}hyXKfS(w;1{H&99x?D?LG}nS%khNQPu;Nf^(?LtcyzjGeM%$Hn&^h1{}`oRBg5 z11Uuwo~A+@u0C?r%7i4UU1p)+6qWQCnUFH3D@WtNuvf2;wXP=KRj2iuC0h2xjTzID zqB*yA=bG`Zy7Cm$w)=Werc7~Uj+nq&{Cn`a7`?K4w>Yz~BFjrm)7UWX%OJ^}R-#k6 z1<3!0FY>nrry)#?xU$p?jfBNk+gILvJe(4SiXLN{ToTH=0|&XZ1juZ{Toavpcp!VT z(BicFA)c_!dD|X__FA(H&5oj`o1jQ5kEo9_6+?GNQ-%mHzcSZ0hA+rBPbv27^;^|r zIr2w%RsMOL7 zkS6Jf2|=1dmnDflg>7Q!b^$;Imv-KTwTZayN9?qRf3KUrvf1V@esei2S$*F;@Ff)$ z0bXo#CghbKzyF_paRC%xgEI{rQxP7AHSt6PuZI{UGvR z8!KaTj8kNpk%p9jxya+NK>qjS>-m5o8v>iT$8N~$;qKsbiP-57YGq<8UC7urxVEId zPD*O*#1T_S7q@{~vtDm!+Ssztx8(SBEP_C}y5uwVuOxGZ%#~*wS{Pn)QrJP2+Sz|A zou>VE%~z%Cq{4G6a9Vi5H_jn)bL@(VZZR=3DRPZ6l8IhyJX67~UXUzzfoahImod23A#;M!5qbKNb^$&smcoF*}H-jNDuzt2sgB8<80GrSYT{3x~b zspQ`1-N2q%V$0OSZwFySTzOL`m!tvLLBe`f^;C|x`#jwAbJhY~sOJ#`I;#iN`!}0S zOHNC6{T-xWd;Z~;S&YpL@r9|Ve>vtLT~2P85zvQEt>-E=t@r}@o&U*@P1Nu_seZwZ zQ5J`eo?+*R6PnKCH8L}4Fm`Iz2pZGrBIo7%_O|sr@I{<&B&#qm=AZVvbTLIGm0LO+ zy<)*qkHK1$+BA|fFko}GSn^$ofokaP}#y*Ejy@s{n@NbK$a&EbrmxXKc z3Y5ck_lhpV{PfPFw$yFe*7f0wVD2Z!cW-(>*S{ktN6uQF`O-P8Ru0JwnB7#ukYuEW zK+eW8xW6BI>$)Z6aORW$PNt@`$FIJ*z0mO|GdgWr7{!~JV^EiroZ+l%B=nLlR;qNi zFi#cWNL>$s+S9&4cC2jhOkpe2pra} zswwKxLr=fwNbR|Fl-7!2|J{YeOdr)>^CuWPLt{q~%-TvbI~^2mQ@mFu6= ze9P0rPEr8)-7~{Cj#jb9FWleUn~Kl7seSnf`LVd^h#^@{4dDsQ)n~xvyOl^?%M)%n zbr1ddF7)TTR-SQ&WoV$iR(n(j)%)y;_qkK5@n#w>d>YLRh(Y8=E9^?ni>ID?3Wz4} zg?;Y%sxZ)nR7LluiS~V2hOSdvrlO_{%>g_qmD!+`7kopFjgc_1e|Pu%MJ5Gx&pPG% z#z#(P=LPXr9qP=n0*933f&}D+s;=;b9X`DF=T4BIK2eY!WZ#Myy-TAsEKflD?I8Dy zQ(mJ^d;RU(&%RdaCY6y*a|thn@|6K|1gkixmnQ6DX&V{huMuFv=$a%y*p`Fr*hB=u z4{#3dr2Lh;n+ZF!zg-3gy2&H%}@){TTn)tD#N)0FeY`ree1dgXK zCEiX;gXZ-KpZf0;ru=hCm)>g3&(kN5s!^vqvV~9i_(s)Gjp53EX3!W(3fP!RfA&K} z`ls0cxprxZJK$g5ROevu7S`C>FG9=@kjoTQn^xihYjpJmttos0=_0L({U7wB3QK;v zY(rbOg4u zaWk{uiluASwx7?DLrkXs>GPBH7bs`Bkv5N+xg?j*WoIAW*MnA0Vr%WwkR2&?bs7uv z^z2+D^397)*TvFL?4vB$Ex?fXtQ2s74q^Kx?(&uFYTL|+75281(Oy zbNd`UVZ~NG8UnP}tIc|+w4dtaSPVti8RUJ0NUQX^9$cZx06}CfgGCmgZD$TfeZ)O~G~$(LssCWBjRvJsXSy8RMe~yO{vGYUoEQ>tvr-Ib+oXak5j(y$o1FC z+C)i}J|!`#JA*wEIlvA-x3?#|Nw@*>lE#ZPD^tf7CL{ewn{NHtzBpCM^$WrsPfYAy zO@j`s5o~qFd26rZ;rpjYjLP6btB%f^;r3E$>oS?NjTm{{crIYz2(S2&%!t>PB&|28 z0ELPHdh7b;dh^QjlSMsUqY?v6FkT@TT^ zd%@eVu=i-eX1o&e8Z{`en(cjN*6f)ng!Qe&`Q-7}_x#fKQJ41CSU6p;d>f~0iBmN? z>L`0Qj?fVgmkz$khwb;U$pgXiXHEu} zSBu>2_=kz%N{aWAAB2Yfn739dQwNAbt!i_Ta2gjL2Fj_do^mt6StNtd#|GY`a#I@3{$ca) zbjzI_>_|2Zr}DDr`o!v&^4MrRP}h$#afkH9?K~0+5Mdgj|xb5>ZXlq z#@uOrcFjC;QZ0SG_nx0)=2Vv8pRtszT?NC6@NfbI&&NWomaE)6xcE~s9*hc9w#q3@ znchSq!)8Unw-CJAuG1EH*ouLTw0F#Fezh@gnLczxRsWdSPg>Xdx|{kf)e>iM81KE@ zA-a|hx^PK0X?IwDg>pPzaUCDXycR$6I^{$7InmDw-;|bFqntc;&mVeX$TIrPplupk z$@+JExT3Hk-o z>(JVQhPk}^UueN1e!QcVdw6Pno6ds6jXB6L2Rj1eF?D-+SW5%zEsWR{Z&6hk(pn$B ze~w$qKy6+Lq0r zj=`3QpKDka71mW-%REUQ>s|0cW-42JiYU@8?+fv#K}Y`Ig&c3WInqsIp45yo=5sOJ zC^M%xganX8{V5_n@LSib90`iIlCC4pfi@}S+p&sAv%T~sS#b^>H8DsY z7v(eo0x(8s+qPxKVDxL@=vF|*admLY!e%d2}szih=cXx%urIMa=qj=XwAoDqOBcZ_>RtbT-t}*qr z(~^<1Z}ZPFp<$~CfT$>KB&&xp&MerT*0+Az)A4R_Y0%n}DyvLzG_ey)DC7PS_PqNh zpc4i+qkVlc`uh>Kj%ml8zvWlv>XlPI`Rmmg=8?IaE-TkX3H$3oUi_P#hKOi;+snp; z_bS=eqN?Op%YO|^h~9n_vYdnej>bgS_E`{`=QOL9vM@yB=_4#Dss1+du63P+dfTrl zU`lV@`Ilf)xX@K?@CYwyNm5E97dMnS*OLeBDuFUU0b$b;6ny6U2Vf^Xd*Uu|(9r#S zu7np=$?@u9g;@0Y3C|Jr?bOt&F){|fbLKx( zlmG|z^a#qVV%<3gQV-jN0$(e}r^NBf6%U}sd(w$|TrVL?ivdzVzL2ima`1T_Ax(d` zF%bTsz^`YwU{BqEEYqk_?N3J>`hSOaDs@xP9Ne!N@MXS3Y(lM6;&s|k>Zz4ovll)N z-A`UKl~r*N{B`OS5Fc;%_gS1%LB|P4%I&;!fa0M{L~4V(H3y9KrW!pbaE@%i~Pgs7P&ar{+SOeLTbx5@z>8M%~9b zB8wW-lQZG(^FBU&%ZYEqte&ab-97+mz&9WE7at-o@4a~7ee&mPXl^+1@Vi>tH(+kg zo2wMK(@lh)lNzVap^P8X^1&XeQNCYXeSJPIZ^5(4xjZc1x5va5kv2HPIwF0qXt>6e z8dK81UH_J~FThc+rk1iE5C*UA{^45;F0xnWdu|j&E{C1c*CHs@Vv? z1HKjCFP>FEmAu%fr1uL1Jf_{U|5zTrzbJdczVMlrPqKBpwF)RP#(`%U3I=EUqgJi$IMP`5ByfS5BxsPk z@}>AX=En<@URL(b29YHUZc4T7<(7i<5(g6jWLi*+yIWuhKonW9y-On8H@+2*?2e-) zGVT0F20-2D;v#FNusdbQC}0+8cHPgH0(rlPv2w}pJq=KI2?@zo>UkDbQ3Rnvt}u zZ7Lm$GZLv-1jtp<4CLMqV}$*LU(d=mWzQY}BM^fOCck!g#vPh=sny7&K3()>PU;<= zimRy2q%)0`+n`r&v&y zZ4m!-zT24Z=56^mglWvz^_B%3ZkR~nq`i@Xn@&5gC1oN*^U3T;u;9ZzvpSaXOIFT` z%gTIxykkXjzva*HkybJmTd6cjK}zz3LfLfqU?84-obucZ*)-q0-&qlEq^Ivp4bcL^ zwQy=8X8o{Ar7O(1)za;SHn!%@Au0OnVT|Mtzzne1lH|mW?5OmRBo$ehf*?|b{wS0A zb+DykIF*oF&qF%EDL+4U^VYN}3RW}G*x*y>Ip6Pba~Iz)wpm*-6MwZzGXiYomxaaK zKhVNhqOQXb$d(Y1d>k{)ph?$>5%K2zc{oTDYURj>wQa3=H{AZLXaL8q{uU;-A=o=P z?+-i>nLy!b8<{_TNXJ76Bob1tq7vtoNZ7iOe>O9V zE|qIir51qo8tW57;wB=NS+l%>7lnEA%DLp~rY0FTWTVw5H!f9^O+E=kh`})ij-!zN z{56}Jy6nToX~T~DeDw_z;W-XE;t#d*)qi*H9}o8F1^Eyck6;#w`q&6aNeXnzvCdoG z9!I)dcfQc}2Wha^>Xf};6_bmmZA@UIQ%88|7nXDVcV<-H$0nZ}FO}t6_UHwFC?z_L zhsY6zN-GOLewwh7;6MYg|1S8U?^A}<>dCgZ;@4;X?3=Se>k*mRzm%EYN;x7>*`6I5 zLniiIYp;+=(*h`bi~l?ikF*8*q8;}nspzRg_uVSXZ*C%W^^Za(9Gg(jQpTS}TCd~Q z20I(Mp0Cd7UXhsQ!R5Uj{7YB>=|jgTv2XYQ8_ymXBl9#lvz*;Qb%AtC=4|7Ipbh0E zy0}u&{OXuJdf9GlWhsjspM>7@jY5iQIjx;(VycJp0E z6_f-8=X(B@7p>>aX{Tld@KcHIz7yZ_A#m?lbC098To#w;H17uQs6c#pl)*emOuIR! z{`O6o#1e%X!Incpgan%ee1j^iR&{j`;z*<8)6B%}k*cqy_=ql4!@7z~>eik%@c42D z$SM-8H95al&_zebcuWd-^zL5Jh&~bE=V(YSxcw0#mV&xb_>p~B8=~c!!9&rWsCD}T zw}@UMzgrLI#L^GDC=nQTLgZ`eo2b_Hiz@iESAp*sepBE@E??O|hI&jUMmXkd8|Y*J>2g)hGkN$>{9 zjJ~)e-AteZ>M>Yb5Co(5CTN;U_pvh2zgv>1MR%ogh;=vN?Egq?6YAykyt9}=x9YF0ve%Owr4nR zbz)qx*Wq_xEJHuXyI~`1%>`(BR~(b|fO7KL%rpAN`GC%ihx91@&YE)P2M-9*aagG~ zol`1^qLLbJ*QMjv=6!r6^x(kwxU_akDh#6)UChzQ$TA{;6ZK+uHZyqZ-$odY6VQj(VAP+J@i9{+Bv6qCxGE8xHTlE2zkR&|L`Uuzq3O@kn zk$Fj&(qtZ&7U9oWS=?gbbBt)xkjf8ii+l5CQ`|p6aE;n#OCi6%zeQ9{XYzkE`Z^(l z7uPq~_y;-71gZYC691?y8s%f+vk-7dI(G3yZ0yiz(y?&~tQ;XNZjWpP8@u|kt}p@d zX5zq!?{{ibzZ1`(EdUHoi*~cK1+s8tp#fvP)yKzf?h^go^?bCiNpJu71?GYJa709cZfH7pa_j*|@l?711)^T}r=pFO&f zgL+#3z`JM0q_=vZ4#aBV`fek(xWF5^SG|QuDih>p46>p9!+9_0He2fX#vl!+87i$l zS4tOi^cfqzg&5PRQXpuIg&h<){}$nI=jT^!1_a>StSGc2(=iE2WIL_W;5UhA;u*5m zGdt`F#`mrs=d*o4I%px`HjoQ##eGG*+|*23k;?q^TY}fqM4-$rNSHN338Jq4HaFuq z%j0S|{bgR)*qs4#*fv=y;1T~hJ$&Qi)cZpPDnvvSBw7}U^s;%{m~D9>~F${S$m zqA~vtbh(FjDb?gX5gTgFZ;usTpL;LLSrBAqS${&C=>HqUYWo?IZOWmgXYkIDZrhEo z_1D5$Jb|}q>X2wz>^dY&^7W>Q;PBWQ)}w*|PCAnz5s8KCj;nW7g;q>IqAumZsYE*! zMBT{cG}+CUsCY!YtLJRPXIPFqjIL)-B7E$Eob=<4`_oEt3iFX+8jeLaS_np@JZ|f+ zq<(uGZ9N@|q%kh4Saaj{-ERFTzSB;ux_q|xLNQhu*ZmYNgn#+)kncNww29RQst4G? zgF5e0#v%IKkffyY-QRI02RVgY{>&|LdD!v=CMdv03gB62*bLNXRXG;)G;p82?Rzhu zH0DTF*4O!o?ubKz3cnK}!o(4kbiU`&fK;zYdT<7nSw$-lQz-FmC_H=5RreofNobH^`mSf20R?ptdT7zVqu`Xr>O$&vpS z0KS7Ka83n}5ZIRl+p)xq7wx3PDhT)}kHTjq4vD8cPXD z$(ll=7!;yNdE|0+A4v5+H%hK@)Wc%mleRH@bzdeiu~@Z%SZd5RVzLqEG!gPm6xFD6 zwF@P{o&XS#+nA(+g~esA_iK755x>^pEuIujGHSFFD*n8jUzEL^B8k2Be3l~vrS_~z z%{&e%3H)1ty5CtnziAD`mKPRk!-aov55u=BMBZiLp51iiFNPWnJxfOrCS!DK& zG2*pCdyD|1jjx+oGM|l97juGJOkD+JH(-#*ayEU?|M+Bx@OyJP*SUG)sQ=v|#_huV zd%2{mX$UJ-AADRd*fh3kRIX5}H>jNQtxE^)3CIY)+=6RMp-ZoS=sFk6U*&MZLOEOS zw$LK__msaO# zvI|%lg)_=@mw^;R)aS38mgi>GVltz~9*@omGK^o}@Om}!3>qyioG0!9++@(Ar!)!xG04`CJbQA(Gs6^qD0Tm{-vm5!3Xc? zb!LZv0TUMoZW8VUBBA#zgRm{9+)~`!_x}!g>+Lkq<2mgFYVXUXhMb8TbYZ{mQKK}< z@5kmNdpMw;K&e3NX(EF8`d0>mX4F#L^q0;^S^2K-p$}B`KRMASB_BIhN#1Sq z@mb9j82y|icKHPrq>NAmPLl10m65$yg1nNUVgf=CU4I2tShn|E@+^krn{F;u0!xRE zfBTPWb^v!@>J62L`wixmqJ{c)aL1GHI@hStU0Uqm_^xhq_wmWX8C6X?5#ygGLm(Y_ znKWFDt+E#Fd4!07@3|X&GDfYF>#;i6t3tM*^s}w3Io$vqb2I91#a=6nKOV4wNra78 z!MvyLsT!KvD~pz{pJ;z3$%CcILFMZ4&Fi^5X5dyft2xW_L#i4&66ayp5rNh~^@`yVRl1=(NGxB=v6WZWlLl*|$LRWNxrH-WeHL z^-R)>)ccwQCt}*uREQkxrFa+DBnl)bJhMPenaXHzj^fmj-BnLHfH3@PqlKFLF`~wBv z|L+G6PS7`1k!&4}ke1fYx` zSWoy*1B;2FoZLlasWx!Yu&ru=*i}+?HPav3aW}R}fFGoZ6!b5~Y@ZnX{Sy|5&oLNB zi@!M0=Q6B{DHws_qWI*8o!s>`#ogs6SdH!9vZL#~kHapaKqKI7|< z@s5e$u+i{B@&)PFB9oMk!e0Q!Upx?!Om@|-NJuD?8aWXJ!GlCo(Ku*&v7^=5i%bZx2=$2TYhtU!`kDneJ7`vvv9FhW4MNYY{@v+fyyUs#h}a7)ge9#d~cjg zxs`s|sZ;#&(F}*^-Ei<rKGfUv;j%6%1!j47XsG{!D@b$Nv8q? z)`j^IGnczB!h-VdYs839&bOpQrluV7Oq&PdhMLgZLcxdt(KaP<6*uo-gWo1L120s7 zZoF+pX(3KFONo(*xz~eH#{Kj!Q+BbUf=*CtMRcaYYg04u@9Q+LAa^;)B%BC|dwWQr z(hk>QZ$_s9W11J(NC3i?&^c4THKF_MaIgQuU1rRlP9H?>T-x2fXWx`h_ZsDHX&9dl zSN5($I4E#G+r;xtA`=Jy`;kM?u**alNl|PygMXfM?ft*%>vltg8TDJ$*8s;2?0x3c zr`^15cEvN}$ToI1C(NXCuI(-{cAxzS^cU+$IjeG&#frKOBrymGoK7)TNy!2_`tkis z0B2dcF)fnRzB?z52j8H(LVb}R6$*CvSe8w1yt3Rx8MHAJ&_B*_0>bA&F?8rh8G{fE z=7J9e)t3p2O&8qD#31``5^!Cqx{u8OXJ<+4P@3SVs;cP}Y9C3P9~^+J$^7OGKA`@| z9)9BArRP3Y=l<(L`+Iv8=l^^Fex2URx8DBwi$5c`Bw=Xp;x1@TjMX0vAMafHB5zC zdB^P*v(z9hAkQTFjGw0r|55wxXg;$VbokzvZk*gc+=UrFKlq+kc5m*AboHpOf^wZRizR%UPbuwi9MJ|y>0DNzGIi<$_S@e2XPXW!1UvQ;_e_X#7Q zu~a%YGcP<>l!)aK0QwK}XdU*nO>abIY9c7o{`q*aWtup7r909M|4QeG!8j=eTX*#l z)}<7;tZdu4^{!pyisSJq_euMo4|6@y)?3<&e4|c>JkfxSmm9-_8=kI_vzHOg^qkCt z(_4p`1!&*E)qxY&rZ+z_QD&xXA+#kMBgf{#47aHm#@7Hfg@Ia|dKU3XT#*75h=<}8 zso6}sjH`ya7L97#jT}!|=wU?I(2gQ%Q&=7%>>iZqWsj4!Qb;DAI^PA;4E#JJ-t+l0 zTOU!TW$0v)XMDN-R+IiCOls8p;@)5TqB$UvXPwmU50sdj)2D#*(Ml6&&1wu6oy{BO z&gO{nP+kGg(C&YuWS5FB7b45rk1$OO{w{Hyj|D?;pbe<|q1i7~sNz1R{4bkvHrqQ>{ll~-IsCVO_SUk;aJ-@xfjFplDP2yU=0jTqqf`@ zmwu?-4=z$|WM+TlQFy*;(kTUSawekt4rQjQeCA`BeMf%wCQ?cMkN^0K$x((jE9|Q_ zUi^z@$(_mn4yVX6z@FsLY><$C{X{N0Y)D~P#l|Pp$GBi%@A@fDxl|)PC)?EPGr}4h z0U^O=_shx)v;RYhUu3`wlDs{<@hxFM>y1V8GbC&c+%a-oeYsw#`#7|5uW!HBIVM2n zE2`*$k3W@7iEA56qg(Ul1$aw=Qc5Kb^ABfQDol+h3xkLyEI6Z#!iK+!#$~aB7DE|m z0lZNIs4lIjnDact(%3xSZEqvLD%z@iXJUldIbhGk;z0s<(4d8Mvb2{b)RG{XhTdCx zA;5XEknZkPeOh6Ch9njzrQrhFX z=#zwQe`_^qG9LOGTLioy^U6~C*zZ>Mj14q+?sqtYPcF@rymoUZ<;aXC$a+5PIoDzm^>gJqEW+^(kVo~aGYItb0E2>Q{wXcV-NFK8i8 zi#mE0JKyCjDkD^jd%R&vNGa?F~i@0g2+46r;YYHn8{vv`jqD zi9CJw+Ya+XJ`h9kEvO8()U<4nvFkcop zpEU^+;eGF>hky!ZA|?{See}UAQH!l-e3U;uBifvR`2^2d$u_@7sbBHunYpLXluT*= z!be)qR)LX&Ni^cIgdXcs`0qwHkOr>PM|whfdh4~JH0zAPr$)DDSF`9uCLBjTASLhl zaylNr@t1~{mhzLP;rL|c$VTQ5D|x^I%=B-c#^qHhj*nd*o0hij&VR-wFE_lfzTS<; zTCzQx?kC;H>y1022ZP701deBY7UU$wV#wcMVA)k&sJiH^_K#upKavG`ABYnh-d8^3 z;}d7R7&-7!V~l23USM$f)XiExn4&V|n!s9}l_PAB6cr;HEgx(EQZNkc=%T78*@ zqgs*1=;mLU@AjNqkOXPqJUa;$>(b~J4yY@;jH#7=_O?;D(c|oC{PRio(>-aZT5sE( zcYe&7Y8HcPQ>rRe+%=u&%tr0s2s33;IBAzdL-S%Ou&h3h$(Z$fG!va zVq$G5iC7ly3Lz2B(cf%DPr`h1$M@!MU-6w%a4Zo6AnoYkR%u`T?u5Ut7_P!3VziO# z)OR2nGTTR}HHS`G;c%|od{(Q$vg5Jr1&HOPnzPyD?VNr#`O(NwI#f>p(IAp=!rQ%& zwki$|0T0^=hqAJ|nuh+&4gV-Gyd3nUy=kD6vGKQrcd>O@s(1aNX+Hn)5 zvFdGl_@6G^ZTM~Z7nYPq$uy3B^f+S|Kz7yPQk>Ej@3j-;Ows%Rx)Qr?3)T;?2*pF-W}o zx5&GZTb~h)C~g4wM(H~pRf7ftHQemPiY;eeWN+OK!F}!U{NeN}-XQXtuGW#=Yq>Q; z%It~D=Z|Dpj%K)P$Kw06{@b*7v@cLr!A4ns5#*qnIld;J?Ya%pfKEq#;>X9SCt}0r znJL(Lt@Ty$NKD~>-y)8V+GypjN+rR>xeK3Fz2h^lzdQ{n5jA^?wQ9EV>Brvx$$wJ8 zdS?;aF3ahYW}rNW@B3IGsIKOwD`K9_%?0sJc2|JR2bxFiwQ{u8b1%5wYx1OS6m9O8px4fy9?Z@IV86%NXo0;0|96wD{EbNNQ5o2%7J#{ z_Jq(jX{JgQVk8ZFV4d+Mjq6l22kIrgeR?mse|gW0#KjtH47^W1+-)SGty${JB)?@i zc@vYUNzvj_lBMxw0V{TyuGkrLii~0YDk=(WPt{TlEQG*brGOtR?2*eq)Y1+0`q`o> zX<>Y-6ZQi$A-6x-qO-9ibD?7XJ&Ka*+H|S(xKaOEk=OL~1^tgGNN=|$YW`sA28ndm zB2RB#!~}Cu8h7KjgDL=*O8#s$sb&zt@K0=f)o8T+n{VT0OBM4i)6jt^{Si2MRNO+6 zji_$nRHMvj@JYA>#U<70%a6OTArov`49T9R&Zu*2j!SlW(TIna&1o(h%F5_K9Nu#0 zcWjPWJ@y0eHqb0uuT`8T%~ZH?7#R7G{Bl%U$APg4JS1q<7~b2prTc1A-e&fV#=f0I zIuUrdsCF(WhwN$>ut3WiM1DbAyPmMl*Zst0%Z0ZEJ1V|Zx=@BXRZ|1lt9Jg)l~dtd zz}<2J2Xn%t*+rXPmJLU5?$c(?%0-(#F2kGx>^ZzsbriszY#j--swti>?m4#d+p3*H zcYnQdbr@11Xv?bzj+yRNYsWqL6;{K`^+V=mWuwi-7I#q*(wu!Ywm$8Y*#rLg=JoS` zx~m7W=P|&opxeF<_^|V8J^%Kfr%3Q5x3&)H&it>jLQJsY)+SpW<7E@hC$}**hU%d- z`E;nN_4OZPy>wAM6{&mpqiaB?h_w}p@@v2EeBAp^SH4U#xf@8uBiTrpEp7*Y0{uKv ztW#P;aJe&w@7JNtcMdL1LuGC9pI3B>pOwOcdZI?ySgFJTC-A4L>H=&7#3gBGad-XWC%UNb@gpa^75Oj^uNn0$iCPP4j`x#Fe z*JE}>fpWw#-naFqRM+tJZ>DKSf-uuF{ZL~9(ApsUcxOr_JxGJ>`XHEv0{@q|w?2xZ zjHbTB+Z9F4sRYH*<9K=~&x+6{Gqc66Nxzz;c|r;V;rNa@MJ8?LMB<1!A3&Gr{$S5@O^>9yot_->wfQC0Re- z-%)8MI{BGdzCIxR=uV@7Lw-IjJ-G5|`6=m&Bp_z=j|mon^uCYFtB%^nJ6c~BgQJ+~ z4eiIm$z;@vh&h&wxl?92V_{3{ZnM?_F$gX73e2UEbEkX!L* z7;n3^*5qDVA?L0P+%u!>f|`+g=4j}7gH68J{NQeV<*Wvn@aT~Bki&S%Ft8Sf(#;%Y z4c|33`0i@m%5XNNt$4f6_&@eoXDN8*W)nmPiO%e7>98w|pGqZCfmW`&zlQ#~qc{ca zz&o;Z?`4}mY;@8lmoBGV#A)1K}02p_7JM9fqqxKxN{mvE_W? zF5wU$g?JER*-%>E&M6?N9O<}OKD^?R-{~9p{HIczLJ_4ps<$RL{=t>2o+LGd`KH^w zPFDyu!ZF^q^{08)@M1qzo+tziQ2_GdRVnU~+`P{34$^;*e!r1;Z9Kv$z|qbA-f5Q? zLCn`$T~_cXRUbFV`Z!{*9m&4eD&oSkNQj$J^PHqGNJ?&HXP$BV+L-#44g=Egj;bms z1k=qP)hrc$hXpJEqOXLmTn)Ff-pLEmU3n9jwo;?G%w4GMnJfR}9+yQ$;B+Ze%8S@V z-|~{AMm6}uLLAGBtv}GzXs}$}Bsi({i9#knK4qcYuV{#LtOG(;TEl7i^iJX8{v`>G zDt~tj4-~*0S66Bb>Oio5FOO5bHkqQe`^)0DJz)1Qrx_uND_fbfB}kjk!^jv;9s|7= zSZ?j%E&7Ev*e+f+L)|S6UpLMu(^$dqG~T3W623wAUaMwsppK+54rc^*KMnB4MFYn4 zYX?vhR&~c}RT!>-T9$iywg-Ls0wz!}J$+M!>U$Al2Q&xdK7ss{l+FZ5b|(QoeDv3U ze*eSlHydnYLF8|L89Hy%qY@X>VCOU6--kKL5;(evzxIw*Gr(-msz_!ubK%QR=u^~3 z&Yy#CNyF~}7d1ndnC5h1eqovAA&_r5?YJyzSF1@cP&w}rj%w$ODn}qodT=<6 zaeQBdvFYuvhYaAM%|{uP3?2HYlWyq#k>?VuHJe>VJhLX5nc{(~XpI0tXz%bN_DQRvAgu{0kERJ$+n069+)7%(d9Q!B8|_|& z2VSX5Q_462OCbn784n^12EeVT6n~JvmF@I1MJ_h1o?Z$+RjIK_({c?Tc*DZhq?9$L z72BCMVQM2_fy`}xE#V=nvxiK%q3}keEw8>|WQMEadM#@ig{_Uu;R5pV zz&)4$BA0d=Jy@=Ge0PT7EKVVTQM2Y1STav~(j9SLwdQH2b~@lk-SEAdpcIOu`@Mx^ zspB7;Z;s5y&xfMaoU027QlRBYL@@~eDD5c}F50BFHQ$ehBU^43_4!)WkJ&-MY0@li z$h9>4y&N6ma>2}>%%0{YAFbk3Ui6O;jvhr=k*edt7mgg3!8P|x>NBDXx51~s((=$> z9&Im*)&CZ~t9qRIW#yIM%R>{-&=JF1vV11-$q>Lk38w(%OzfTDyu5w2z>2aDBsEp@ zbqyi@NzBGp55DvFJ2!T&h@#5kF}b|2D@Wg1NvYqWWRKeL9o|r&Y6FL4?Ty#(bK4p9 z^dq^5jAB!*djA)UJFd;cGF|3=t4|QQiow`wqX~~^S!t-hHH{{JyFsawFd<;{vvhPf zp6c`(2u<4y@(@3Q-g~nUmCC`NQi$5hSO_rPePXkx`C}d(8CbBJwJUU~W4lq3KYRO@ z*6nX0zf)j{i(rB2I9+ct1HxOps|3;GChGJfTN7qwOkqHfF3zWuW3H}kNjD~cOL=&a zh3a!`2WTOn>XntLBsNZRLRA43kzdGeNS9Q}@J*>-2gmR2qV8}(3?Dj5Pr+`$3*Mdj zW;Y|_vWQPj>eanIM(9uB#4aeaZ9P7)1g;-HV|pq~oqf_!Ghg7QU$7o7qoyTs<~zE2 zIOij#ty{rHfQegEP*zUQNdF(w-m)vMuIUC2Xk8qbB5R}gCJ`N)A0T9fzy#8MybnC>iPo$i;gr; zO{sTT2u4-u?L+UoK2IEFKSQx1a=$g^PPAyU04GG)c?!d)rBZ-MvGjGWzc~rw4^GXJ zAtulu-^PoR{MXRsa`LI#+MgX>7;5O;>U@(ITODb!oLUhE<`ypSG znXYUq0rt%%o+Haxoe~+Jv2JUW#mKmtCY^7MS~V8AOO4jSA!xq+1HS~2s@}r+rjx;J zLn$EKyNr8Nce4eGxPG~BfK@s8kE)I?h3{*+7U z3oR<1T1}1$p{UwqtCgze_r)DPWe7Flfy+C+kSZ!=0kA4ObK~Q7eDR_p&!6(rnq8Zy zWsj&^<1nw1NT3pe3@sH?!ow#VP5B!H9XQG2X*;(;GuBIF+$KEFNT zcz+sMYOli>6<; zQf1gcM3#^QWYUJ-b<9p#R;!q%vg+0lvVn=AeEG+!_!r;Z`FTpju>DK%v?%O9HZyXK zshbsH>lfJ=EE=#b>yPX4sAvzY?LK?L)J5brpC2oF>%+@DN$xda{qVtWO)_3TzSB~? zH^z(%tkQC6DYXO6QnpWP;th>kG%|>E7Yxvs$psAFf#_XG+>>IGr&e|3rK!8I-i78o zAnB-z>A*KS-*rQ&=7JIVit}hfFr`~#|H(RqLo|3o|J-Tn5b92W*=i;a2YI(%i+b-8 zTXr~bp8FToxYy%#d-XGSxr8<-1O*Y{g{AG_;OQbaaD(lIvUans(82;bkKhK8;Dz8U z6%NfIq>Xz_MwuIoQx3JwL9=J8+6O8D=QQWlM&%~HuR6%R0mvSx>ISi4IPsZ4Pao#dr z2bZy;YYv%PXDb-f;+Y~-}F1FHu)MC-iIhg zB@4F4in7Cs8rK(;XJP^*L|$}aUzUUmrWJL4TJh&@Z6w5T`7!ASXh*bSTkRL|C4~_4 zw14?hBN(J1RAb7l1S`UYpgmz+bCWTBbfc*N?c9~Q_KI>oD?!`i5xD5v zIgsFFp`W9}cjK7+rbG^qKzgWZDukrtL=#59Kya9AXajuJIfrNAFAPu>6T%bw1tZM4 za_8lG-mCB7{{6evpZK;m^gSGAq%9Wx=`~08CWTwCGN@WPlqmm@Q-YL4m1K-YMlGN1$iG3v6?6wprED>wk4EwRtl$ zd%hVz__Pet#|+Q?;KQM$$Dy><%=-P`%>Sze@MSEZGvc2hR!ziCSePfYHPK`K$9t&J zZImk_$U7OPlj%$~rR-J|t1_`4Rl?6WR`=yP1n(YI>+!Dbg%3gkQY(VLs2cyG)oEiX+eJO~C*`cxdGUA^IXQI-XQa z^FWkWLP-i9`Uri>#YP~nnm2c$3mYtKpv0j!d@m7x7#@zx)z#()$6Hgj6hURo1X~3g zk5(Z@`-CyOI8Kvm{{ZcLf-=_8I7VajV$NT-che76y;grFM>d$+znCvG_WBj&xz;X<$W!g)G@|7p3NJm;Oj?u;{C4<(Mk1=5 zrX5y{9a@Z=c+$?Qcv%!YLbZGJ=pv$5K?1v|ecbdWnPl4DZLYyLkm^&0^ zV-?+Oe!=$etz^7rQYZmiSo@gR|`0xvI4cyukd&zSd=yqT|0^^ZN$90}cjH!PViTwwID zkOX3-j)Xkox3adL0jc-A3QS&h;xQoIR!*w(kSTXzaUK;Wvtf^N{A5&QeS##srCZOg zordBp*$4k5s-o+5zP-VQp9nXLhmht@%Aqn=Ot8r(>T6HNulC1FHf zJQ_njht@CVer~F4aaO#aY8|$^san81P+bw=e!kgEWd13{JD}ebxr3Ih7#K|8i!Cy9 z-XhKMyk+O7B~wY#hj7mbCFmE@Y;IUz&RPigZJ|3nG#sJqX$K()AIOibVfkig4JVEI zu9C7=f;S~2%1bhRHc-_49qvTaOI;RzPn`!tQ1WS@C{v+Tn~1kJ*Pa` zoE~1Kp~?0EMevds8!-)+MMQyc<`#I6yHF~~vdm}o!f`?_nwh*evT$5>2?U0gR#gm9 z_%f*Y@sudQ^V!e}sLgQv@}thJY2>A5Cd0&Cn4Mk2#FH)bd7Z;Cp`E?<{nvTW z$l<8eF00uN_jKUXuN+{+u4fkf@Ga!7?*+~nTEXh&^1kl}5|Uj~q&-#)izxO`6g@)} z{h0hHDQO-pF?MrJulIcPT$fRvh-Ch6bGE4!Mq(_OFLlhQ#}`7SjMiTHux+{Ar_8E0ukPqDuDim;Jf9;ZQr<>$%O*6T<&M+2lax_aKL_wRimaD#=aubtT?wHg*~iKotZw=1 z4n|1K?u={^Sfk5vojH|S;g!J|tGn?R*nT(HYNSNOq~*JN1|1r;MnBxcL+H~GUnqUq z=c;St{NFi-uPC@_j-Fn%56$e90fAY7#Km~d%1_2TlS8e1l$3fF#G9k?9%=whr)|ab znBqnr8ljh8AbUA#kebQF5cIr1)I59q+u?UpUDe2;OuVNF4$oCmW_cg*M%)%NWErg)cI%G2Vckhm{*l3NRX5@8*}$MyFLP!7vIxc zp5k-@@tu_g2JS6(f`{dskw4bys&%&g*;zYiOe*m~Wn@Z;?8z2^W^j_x99{b@$G;7tbx>);0$RU^o(M)KaL~k`|1o&g|7*KAOy<0=dDw z$D~owk-PZ7S&4=2-A(fJo`NkeEh4aNIdxX9u!2nEuD=)3+OB6O%1-i6tP09VD|-@< znE29(75!;UeRwA*tX3Xr_e7BT7s3~l* z@&mDM+}XqdnJaHwYi|ffAc`;9_C~+;#de!=Ja#$BNrCjzoQ{oSKFeMYz%OoLfXDolArs_!;+i z1r1OoO3?8*XC1^W>^h^A%WkWO-XRcR_`4M?4w8T}soC5(FC<}`=%mxXK%1951x**> z&*l*#X<5;WZ_4nvOgkL5{u(tqA&)MUH;cqEVuZe@)tGK=Cv+U=2AU=kD%m1QSRcMf zCwh`N#aQ#e9_{jx{nk_LqvMgBpt5lI^Qd*Pq*SW0i}lkyIa?)oYG1z0Q{l9<1^p_8 zi@s+3*Mg+Q8(~L$FMfe#y=E#^?i%~MKPXGkF_{Rp0lBrf-d)j_;1c$fH(^Gp#Fs9# z+E|))mRZTSmL)xUL32W3Da?uV8YllcTDe>5ZQSw>CPjFFKlSU5l8aEJaQauevTkk7 zU~Zxy;0tGeI&nwBE_+dcg!{N_#*YdaH*{~jwU?mz(`SSp&=W5&U(GDOZM77IBrwY! zE|}`OJeaUTg1nraxKe;p+#m{SpzR@1NJcv3CEi|tB;tG?LWjseU@+?G_hBkFzzbZ# zNmbdtU1KzgK_lF!m;-ggB$@nC;}Ow zl@mM)V8(L$$b^avi3Ni2`O=B+2J|MWCEug#=L=Ql3cnD<=l9*7KMakH6UI3mD=ZKJ z_%EW>e!hs4H=Xa&8o$UD&g?_(Q&1+F@&Vd~2$858(goPO3?8Vr;5t(&Y#P$5w7&K- ziwm`I+e125b9|E0W@&!)mC8KTkqFcswepgmt!LO#A*76X+w#8MTGPwKcsA{n(DFl4 zxl%?qfM4nvJ*XuY8A5fM#--~+kGejS1w$vfzq0Vwc}PP)A0exjfK&%yrLUv#jmAl` zJNC`(CeDuH_#dw)UBX8<>TH3yBrM8580VYKX)BCr-c8M&vG_OBgcKY84xXD{`Su?N z!;{e36$4rihA*>QMJ1b|4~L2#$9sA&f20_;tyc->>2Jq>vTr|)q>ktd&d%KK0)FLbJz0bv#} z4;V7c(p+q=9Asfq#Y*|++tDzl)r5_^cu}Kq2W1J2*OX1OkxG1(VK2-!? zL;NNKW@4p-s}qSe`JZz?w>HDw$>~N#rYwYQJ;b#km*O}%ODFN;bV?y#LUMj%fTpq# zJ-(gNgfgjufuR1qkyDac-I5Lw=N6j|(YV`t@mssM#6Vad8~`j6*^8c&>sv}#-@S*D zwC)H|#keohI~rvt#%r(aO3+m<{)-z|3nt+u*jZF?wWcs=D2b%($X7JLWN5f12e~ERbW*185~y#qmJ2)QO3PjgYmI%jH3c`VP*&!4p}g*3~4`VG|&-wi*3gpN5I37zvND|AQ^L+EYHBX^hX{Xt9_D(JP^_ zow&;=SIxeOK;~k1D#pz?%Tc!-ALB<~bo4RW-zwfOyVG&BL72YW7jLwFUKxzuyVmWg zGhg7rrXfrw;B@c=i%Ao1ia|C8`_}8FLbfurq0n7o_BwlBS*{|D%a-zRn zK4@iUMjfCL%9St^ zmvB-t6;Jm@zheZtYbNMj*R$*6kI{_jF8)Y*6DH@5QNs=tu3e~E5qDE8A zw7848kuAKt#+J?sMnH!H*J4L;eDpuq8+R*FsL?OiAx56M3y&ivzs+$c^3ZNV(bdsrQPSt z0#UznOw>9dEFe@(7HqJMUnW6LFMMR9?PdI*3;v5}1pVeTuJF-Nu(Ncc>6a!tBL>oE zQe@Qu&}P%&7wRRVw2D)IVVS-j=UE0r)mt&_n6=^pygA zD(DQ^6vr6kgqSO>d+CS~6PwP7aGg?dZanZ;JZ{erks-=bZi+;K^Huuc+6uPLk@P72 z&JeX8fs0jLFLK1C{PkUAT(ZU|eyn41%^}*-W4jtduBSIy_BEnA@uH5anETh(oH^|V znuLY~Z$8@^{d)PeR$>0kGIKF_VazAgoR$zT>V~9Qd>}f{ zsA5|C|JsJzGK(EBOFNiK{T?d?%p8r7-=C`YV>Zvf@8@jarL8LqPNv0UY2~pa` z9q3M8fl~z&0{MnC)D9i_NH{_K`2fBU_X}Zs`7}Nwv`lA)?K2^=54@SQs5P}L_A!S~ zo%TCynpS$G5!{7TH}(s*a>&obKo`y8k8d?}blULyz7k*^0?%Y#uvcfPNx`RlleOqr z8z&=7THGR{sOO0f1|O*>c>0=WC)$0E7tO0#$FYv5%o|V3it_gu|MzAaJ~6*wYNtg% zKg6}@I_VTLmcle?_j7J_3BOE)5+=ec*vWW{!u79Um^%z_#;mG@XTjoHFYH#Kjt7|q&!mcv zoXLTdH1`9Hl9H=Y0%z)$MObj?f!?qC-IP=uCgUTM)|8alIbO2Njx!`fLD^LMVNuEX z=R1Ul--7%Jjg@#9q>)$!p=@o>1A$@RY`~n(?__O(WET{J9F1nrmi0-%VvP%B%)^?~ zh_+}sCRA!z{kP{93ENa+#;r!C#O2^tccz?{7gHYXcTSO zx8P1zlSWYBJdM5Dre6pwlF7ZAJs^3QIFxn>G)hj)6N0k%=a2R(R zs?Z1>yA;=|RNV4l5yqCQ%Kb9-{)1y6ib!Hl%mdEibq*PpJ(+$2CP5-YRCs){V*Mw$ z|FCh8#fkVR2`DfylZy`c&;4{Un7{Y@A_2h!{YYz`&$`$GMs{p!1q6)oFUEzXJJOxs z;1>*UcrRFCC>UF$G&Dtg|NCo{Q;2}Vu{7hEcqtn?o(VH~GM)7_Kv^21IL%sZaA9PNAEDE-noU?I0APuZdrTpi|eVN1_rYo0)6BP$uve9$Nu7kiP1pAP!$6do=Ko$rBE<|6knPVuN)O>>;7ZuyP>;Lx zx6=vryuClSO?*c^>e3*Tqs@3#l8iB(rqhzxJV^kN{u4MO^kBoc^Q=*RcJ8~^|LUKBMti+H%h z$2W;dgVK*Xqa`a_$w|x%JlXvcK+{Q1;UPUVHJYJni)_{5Hxb_=+eA zaFI4Hay^PE&Nujzt1;G)KUH;CK90FZ|IYd9`0|{C2Ig#6|J$d`lkjS_Bfn+(Al?&R2++oG^z5`;*h#|!+084QM8@{}uxhD4 ztX{8vf>=ML;aFxaI(VkL9e={oAoWsQsKlMxm(m-VltZIvu5csP5;F??Y+nnQ< zk1a2Xnv<^f72q7 zYhxssrlfvR7DK~GhCWA$MK?J}E|Y%xTFM5Qu(>*@R?}ON*XiKI@M{YKXDy%B{vu6S z*Ld0D>F-ieY1v-u`}l68t0}q2zjk8xJYz@wuD8#*%Ft!UNR=3?f9c@lZMGEFr%LbR zkfct#P0!^O+wzrIwy#Qiu6~6z#acq@B|YCee$QU0VMff{ z!RPS`K5EZfZTv`7f6U8UxPL5lueq*Hv;M%e{wbL3!DAiiN#p`XFZf{m4(<&31=C=9 z4wW?8ZT) zE~Exkj{Ox+OtLvTI)Pyn-Cwgp+0v#jZ{h=1uNNf$QVS15##ssvsNjP?w_=K;VRFeV zW-)9+YLjzc9Km3d^~KeJc2$b+ze_ot`t8`86v{0S0M>Au=9x^ktn8aZY+3C!uZ-7> zHUW9@z(38xLcfAh?^@#YXq($dyVfq9e$^HnP3C-+wiW*N7LQPao0ITdBrCx_so_b}=V06B%}4 zo#5jSytmiGiegte3B)$Fv0u?J3z=)+Kg%0@{n`?}WTeBEnHlF@{!tDN$6nRFVq({C z7gy)c%}n5tJJ;>oEO;|rqP^yQh2;0bhmLKM*B@NjWO;C5c|{LmI^Lh|(s9H4N-U@Y z{*e`Kb`;5uCGw?Aizqlkd;rf(l7bz1z~BxL=g2Ts2v{}td%MLg8`t(HI;e>|8N2A3 z?K5U~{ZwA?ahY)YQ0~ewyx{slAcLb}`IVfpI&eaOCEoMXITvRpW6K>wtJ`op=QA!w z;R4R|nC(h-yR4b$n5v%hffdaQi9j&$Wv5+8&v(ePJ=g zj>r)&#Fd4JC1dwb&<6>!2d*d-kN>)Yebz$0|>nE~@;=r59{3GU2 z&J1vUfP*y%fU$fSOA)=Do7Q()Ksuv)JUO!GVBF)!aHJCb@=KF?wN30F%u2nFF>R_B z?NIg~S|Hgy@zfns8Gt;Xnk144(e7u4)Edgd9UsFtxqvct1 zKeo}mQ+=tty$kLI2|t)Re%8$MiaIzBhq@$GKd`e+9T#LCBVneG@@z!&n8>};Ry)1s zFT>R-{Oa>j_Ybk){vTLRM(Qf_oE zwQL^7@?n3J)hfizH0S>8+biv9lkkchg-$LRU>R2IjxQ$EWX%&*SudpmZzJ&Ts60NVE%J6)KGUpyM`gp60=2EeMrpUwS4gZQ=w^X`2KbM66v`sTAl5 zb+6s36EJZ=9aX*xJijF`Dx1s|s8uRstoVy<_oc69mqwFFZXegcQU;(QM=_WPMpCiF zK~JJQt>e?V1j_3Jtj1LdXjqlA|-m5tn`eI zlX))t2C_oE^ss1ZkxL_=b2BISRFE!TeC6XYCb;>Mq4dL=5wm#(ZgQsG@+_UI-f%^b zZOVb_?ID}p*X6ybf*uCn;KAR`&PMmUG=Yf8;o#Q`RCS3v`bTW)k8WP+GV|#)i^I*% z#vLm{CYguwRQ-4UW3;=uSbvVoLzF=t!A%TGL;D9 zuKZWqWnIl^y3KyFw>_k2a!l3NH#m}qg}!@3NKc857aw_ac4EFhdTZ=?G}7A9t^<7@ zQh(v(J_(76PlGF66LBNR#8ZG9B9aLfXNBt`8bEm9^6brR)Wnly!l24n3do3*7N{`) z^VYVxnBN6jEXuFOoh*R#2Ptc9%C*K)lR%VwsH+;Cn62&o$6U6%;u`I!{C^D@6PJOp zP80A36uZz+z5PoW6M5SG~adGXXIz!@N0|z@Za@qCS zzD^{Awot|VS|Tm8+OfX!i~AVcH(>FX=4kI8LJNqSv@^t95y{aJVkUncIkdAcX%kW8 zz%Qw*$Z2B__}ThNpiXsyb$?A}zPzI$35XcuR_aniFAVZgxR#{8$T?1j>*MbkF$CTh z(@sCSz8{q}t7lOVP*IeJ`j!QDc7{U9Z>nz?R2=K0 z?)iTj;S~}(%G#nZR_gZtD0eh@FCxo?(RNi@kcviIxb=jDzCO)Ih~I8t5ULWayHl3S z!9oCBifJpUQcSmV%Z(I_-9VA;Cnw_C`>>o>V@cB55@${SqSm`gNm(v9+O(LgUydr5 zGhSE@mS)6E@~g&UK9w4wNg@&D%b8UOWW^61Tnp>s8nW8K#KcO=9oJwXBqO6a7{8QE z#KGj1Oc`i){CHtbE6qz?R$G@b^H(sniFD%q7Y&}z_L-!lWHz(P0c4bleh@f-tzm{F zB@aT3KhyDDZ6X44=y(YHd6%biS@s1yy@HqKX z{#Xa;!FQ8%inLgYM8Ub}0b)C|EwcvYFon9n=bDV`K371w!^O3%yVrTt8)(z(Hrtp= zo0XgmD;rZxs3I#GzgP&91=D1p$Cb|ItIVaU)L0P^9Ch7KD@a?Lt&jx?!1Ac&z z>?2VQH#BDZ3(aA{;{>gJ2dF@q`5PCzHFn@+;a_aeRxhJ*>#x091{ksOw!sg7oUIg-;lPUh+5koM1VgI{anI(01H1kPY!g5T*8 za?rJNe=_*BiR#ux2YuJ9J6@+W%`#&T-+w7hQ%)T1B3?^DdPPgo#i|au)%=9o@q@m z;Y$bxQ{=yfhk;Twk`>;lh~v}Y#p9vH*qYcK>AbOe8y&yjb22q%D|lEVBXU?yW@kf| z{%XnvFHJE=xUyuk*LK+QbO|fJJRvfM+VB_b`@Yf!$ueM8X?;noQnYObo-%IF*9Uri zA&xWVeQDhA&m{36U^%rsO_LDGWDzwp4SU2&(=bhO%`orC!O_Y_4@IJYDxZ|}w~^E{ z88^+Jg6eAQ3wP^s=?e5;$0<5kogvIDEpXmR^DR zmnzXtTh6Vc<+rQtI4Ai6$&2>3~({5$E?V;*V1-Sth-VA zXF^jX!UM2$>7H>A35aa`M!t5lvCE|o{Oc#h1r5u83zVKWB9Fe(6GYjC5HFh;=K%8n zUTwpmKg$lK$z4C}_-v%ah=@1^@H5GdQZEtfrWHjE4G;g=l~uJwRQh7JImKmBU$J%7 zlpcvj*IOL&W`@+OdCH&`2A(0Eg&g7~-r=Oq?6c%D$)EyD_*nOLE}%4|>+;nMbS{q$ z$5+q{?*!lX`G(*tK02~NZ)rRO^S?%CKpgCIq%2^rZ%0S_Z5>;~f8*O{M1r?(#huni zKT%SSWysQcXX4Qz7BY|TUEg3~@d48`-5kE?_=m>=%d1bi#7-+WJ;+^9r^QO}&83z@ z=ljVi_QA0F@Ddh8z)a|Ls&wCKNMG0|s#Lb{#Dy%vzVtm@{chi1;vj*8X|p}OEOWjy zV>8?Lh0pOS%k675rU)AiJk4Zg@oUCSGIDFEPW=UHHp!ySs>}PW9W7)0n$4P#iYV)Z|RE?(J@@hfXnAOI&j$P8Y-@u3ouB zWGd@_k%Ml%%p1yPg8>holGOmCIxN&^Owd-TtySu-4|a%i*hYpjk16|x_oGO5{X7*R zni@fYEqp$cB2~^wWoGGYUTkM8Xvb~CG+g?_`aMnb>R)RqpXSjIZ&gN((?%OxDqb%c zI0W!=ypK+{}t|EOf>U3Tl~_${^<=~_(Zt=Fb=mXB5dUgq9G5xP1htc<|5c1Cn~Mi z)16S(y&I{Hdh9Xi*cH%S*LL_TFX|1bT172D4mnB!8C@2btSX3LBB_aA3$mKDHLTWD z?yHs^Hi8^6Two+*QCY*W=tGYby-djkaju#pPKs-XEHkgrJ`Ce`}Z> z)oxwZZs65An3#BjE6rEtPc&mFpfPHg8tb40>vrub1OO!{n=zi`Z~q`k-zBHN`V9dl zqMg#PyK&Z%@0y%0Rv@$64QAeVyn7*l$lGTEFSa^F58l@5UA=Vl!~&_f0uQb<2*|$g zFNc!ci|<&5s^5Fg?yFL!grI~X_w>m5`j;AuQA|L z=Wj>(BJ&F}^gzwN$&b_od*y!QsY~)05w^^j=GziW_pe0swP1{b#5j;99&vdwZCQnk zgQ`Y0m$QG}VFXfhOX8B z)z$sv-R$>l_#Y{=_7TtitzP6;@4)!5QWnI?*$=ABbj*i1!ehs>`0E1J-a$-TDnI}Gz5kVZ$$m^%(d54&=UKBx8bm_+(& z7u7uMjaO#Wu(9SUUhk720;b^}L*QVE)-KuaFjR!F4qEY8p(E+_k2 z0yHTC3Wcrk6PeW6{YD-LJy{wWpbbmYF&85dkxVW1af_6CxNyx+L4sWOI0(aLY>N(1 zq_zjzzU*eQIANMI@KU97qmVv+yQO#a|Aw1pxl7~BVa@;G-b1i1Y zJMetHG~10I3AP?6d{pahVm>H5H4#se#CdYpYqhGA8yZqjQ_T`zD16acbCACg|0TcO9+|zA(;Rh z&#d>VoZQVpd>VQl63YBndLxqUG5T6Pa_QC&5lWpR0nX@9It#!lfAP- zY>ia+jze><{SSZGGXU=qMuI~L6O(#I+94nlT{rYw-pjgNfo>`)^NQ>wei$7U@pwXv zU|^;8^Tz=Q8z7wXgDYx#6I31bTAI7#De8Ojz1aiyH|D6iKV4s{hZNp!Qr)DtF#S`J zV=B0Eo1Ca3r=($*4U~a>=VBa7S!SOad_QgAvHwIQJ(L`wh1Q11-zHd>UWZO(hT6-a zPwF7@MLTT;wN9;AzlP9cK$(nUilFGj%94IF$E{;EDCqx^d~Sby~$su9rVozH77yVej}1uM;Zk7HmhvpMLi)DOie(zryJF=$&nl{Ixhe3fZJ?&nG#B82w!vuXTwI zCsu|to2x$3pFsM3n)Nhz=>ekdP)7sdu%|Buf8eDtE_4Ppgq#v6JgI$ZBJ;ugP9oH% z*vz$_mY(*M1Px9*8Lzr3H+-5@Bzi>rU|HxAva|8x?suPFhWwgzfeR1$2FJB#QWB{m zAgS_fbWN6enS1Qq%Vn?P@S%)3xT7&Y50eEjMBD)rNS6r5Ao$TJF%>2G-5emd(r@^5!Cp1lkC%VYMug_ASBpGZe= z7no2T8$?Ww;EQsR10lHp_ze>cLqKm`8_9L-d2Gsud8+s-a^R*sp=r%B=PHOf{unxnPL z54;`IWs~tWUdi&SQtH=L7#hGHAyQZX97n1T$L~c{x<6ycVh#p)3`Po6JIY&?iT0Qcn_@KfnpM=4z~NR5daet z{YV9?;uG>+L%p!uFd1@}km3W~0OgR%7$1@K*FRqT9#7>0+&p?Ty82n;>rHWzp zkoyKp&Un)4{|TDega`>lHI}k0H?~C;i)Naxz}VmJEamK1i`FhZOYNbrBxthUdQw1h z_Gg!RRa%POwykZyq<*>DbwFVUMikylvyOYU13rh@`2${<31yDRDQSJfhMDjEV$j;S%zqyX2`O_XckWo#`5(57~>t%quu_DvNe>U;hbyuWF?H!N3U93q3DNh$z5THUarE z@W!uBu!jIuBy_hpgS&bWS|r${XffYU*J}M{^R}f~2;VQZ@{zX#?~wZ$>hrJ_(GPJq z0VccB_&*wTo`Us&{t6k?vygjD$>;OCUtMR27rN!6y-TA+U>FxnQgso(|N6{quRgC{ zUX#!mx_6*1K4RPd4+}Ut=&HQ@C+4!(d)F5RVU7Ej|0T{d*GBB=v7>)hohB&U_#L|K zZGTSEtkYLkX>B6J3Qflv^t7~PW)rZqrkgRz`mGYgDD<3Dzic+Sf(x_(7xC180ruXQokQ|VbWtpYmw48HiIo6Yf{_8{r^nud7q zFQ4Nd+tJMT_NeEW@w^(EcyuRV-=9`-bkwkzUZx^av{sW)qajOS>uaXITv>TYwtQfPIUml0iwkA~>k|se9A=;A$--}HYn%{P2 zQdD)E8-HsYeNXFz7UtP{S7NlS0(V|e?k^MNqnyQ(Kp|gLE?RT~1d)7+E+#@PHr(!} zq3nQqobAv9uujG99|+Xn=962g&Z2L*jd5sNTJ5dHj1l5%NF}q!5;X_*P{q z_v%m2Zv>zP<;^*MnP@c)DC!}(zsS1vo;9=fwx&vZt7?<50BH|-otctzvuIh9tiwt9 zpBON?SXJ(jyR$)%ovHJ-(&lJdmE&W6PjJvwhJAyo?0U^qm1)`0jQ9R^o`Zdzlhmdp zMT2+UTa0BmYHG5BsJ>s67gLZ~;zJ(WA6g`!dX(VCitf6j@R@7&Oz6Qb(0jktEK=iSCfrw-*X2iBzu&IaK9u3~ z-F;bq`OS{ARdeC&mB6?B)7E*rR7w)_>y_2UcG3 zl8LJcBY?y}8w{&oj$A{M0SY?wX_JZ9pzmMr<9|>N<`+KGt{eRN+&>CH2k{+**IV0u z2oTuQFp)YPHqqg8nF<0Vl9~cjtg11s9^lV7T+oro7ZuqTm|3h30f~^@Qabz++9nOq zP}1aOwbiS6To#J_BE&IljHFwFuW1P>^c0dL^r^Mg*=WA+r}L$OIU;ZVjEDHq@XmK( zn}j|)v0Y`shtw#0v7hx~a#*?HRNg& z&G#cSCV?+~uBq&ViSVx&_u}TWN1^fRpnK2-N|T-Sv}@1l^oGau@?PMRmh^hS1@89K zWrTRQj}+44?!VKl%dT~o{nY8aePcI!@w8tpW)Gq`Qf+zrcArmc^>DG&qlP`+}+)R>kuRa8D@ez1O~Tn-t#L?-}GHS-K+MlTC1vd zHHj)?385I((yc z>N4=AIh@5j>3GCNuRqJ{AfKU~42SxiMDe?Reg77lE8mwFWmB`;SbvrrhW2lIAoR@} zYj`#ZZMgD#V|KWk0?l=dwBY-i5Q^ek$-pV#82o?E00%hO-GI^%nVs+UIfa+F^L$ zdalC_-e7^tit+C5&_ey951nRj;@?~5n4jwq7yJ%WZ}$8;UYkp0o92KA$hpOMJ(w?3 zP_mW%?3o(qSeoe2hGrgA|=+)T}-Tcm32q$=HQI0 z#3h@jT6v96y8Lhu`ABIA@ZR8}U>xMc8FTIfFb{Z??5YMjLEb>&h4Dd|GeH;LSej}P zI^}2aBQ)ysDESqWo}k@gz|BR~Urfn<%T$gW%a}GbFgw#(qj7^MfV12KcJ%6SJ`>K~ zQ+@R!azzE%NR`2EqYp>HTN0Kj4ic@h6D%(w zEkw*Qt1m+dsw!J=(1@X2SsJ(s9|7Uzzc-Hl_641T4`)PzYx_Wb&Ida9&Yic{FWSZ? zHOrMCvHeZ=82$SBXUNs<(?8Q^e%2Z)yi-Fcf5+y}+_SqwRnS%N%S6HDatXvLxMwo9z&Fa4 z;_^e9W~r=V%I=8%oOuK2UpjTZVAV_9e&PNg6**7~vphgoeE2h2>@Ga-ln!{48DmmJ zy2GH@)f7X!j9$Tmiw%ovK92?z5r3aqa!^^8F0OEuZ#}_LV(Gu0f17s#OF(Qu0Ir={ z2vcmoDC8q1aI})IfZb+!=hjNvjD)eWo7AumdvX;P=t262Ol`^Q?>=GcYnn_x<&htNX0TqnxQEqsD^+XlJXx1X`|o-`qI^_xnz4OrDiC zpT<@kt1F_mBNAT=)UV2%gCiG}Z3F`jXwUCP1>B$cb-y$$>z#Vt501a&4TwF6l~eFL z3Ayc}rayOt^=joE!F=q?l$jJ2Tk?D?k46y5`-hDVxOYX;W$X6yp2up4=*x;tKRoy< z8hzF#P#SUToi8$@sKLN1Vj^zzBH~%BT}+Sy2f18Oc2v{<@jtxLNQ-e6hY7}lU!Dh* zL({?H?Giv)3r!%q32O%oYZEwv6SY4`q2Ovu%?=0_DKv@g+5dd8C>Xv`X^HF zkJu-!JNa=p_}$M29L1V$ZK6~EbT{6-s9yIub?k7vn-5j}avB7i=N5mmDS(dSi{*VN z6UTTGzZgjvNCyAKf(lTM`|h_S8d1IEn%>!n?yu2NynNQr5Pey~?7wJpz6^ea=uX6j z?VEVxItMJD2JF_KU$mWX%!VEUIQx%i|DwjAb>wKWY_ZuSS;JcLM$bZ0^Qpr_bCvIEfa9oF}lJe+w?w{`h{{m%%&qy+tEePIii@V^YImj92$(k zgd*UhmzY?U`tPCJd58Ex7`+(WDCEjx&-NmN;Kl1TY*W`$UXC8YHS8j`blAppvzyAy zbjt2#NLi2ylNzb5!wkOwx?U=xQ*V=)aXB1VN7JdCO@_3k>11(R3Eez3Y#ko$bWy7D zcNe82`q)T#YW!Vp)-isaJyxo8N__htC$V(UxNRPgGyHh`Y+c|91NaH*fd^#?Q1WoD zgU$lmw*Tve^ycfY#9xQkfKUjc_>8T~<8ElAmgwfX)5pEw?Ye;xW#H>Z3pujbd6z+-dudP* zuQf39`@Gc$7gm}FWnVlBDk*_XU86MmHR?Vs#z#x{9*-4QjKD-|QXcKZEQe@?U!^fR z%Msjy9otGNBmq}L<9cNDw+Nip0f8cu!&Ix(%u^y(`L`vb3Kj=t;l zJf~CBd^zBJi4hri@VqR(6TaYpuE+huHK$-n`VR6I>3eyE+zur^?HoJ#qdGs5NOZgt zYh=dyPhuHSRhFgwyfsSG#A(hOQi|MWrTWwn9bmD!{q_ME=l`2-O+$ef%L_I{d`GQ2 ztLnbI!6&P~pv>#1I7T}y2&QUWI&H}zuC*@1z&4KT-hXpAdaFYF7M&z4{H6+@YEL?; zErWY1Op7TeMo|-P^66LHlG^gm z>7X1*+ydR$xO;DZ!ulnq9F2=|T_b-V<)yyusQW>!8aME^;Tf*p37#JH2<)xzALnx5 zN;0ZnI!D>qd}{w=+WEo__)4w0yK)=7uP2FOVzShdCEbP5J&w`g-DTiSN3IdS#HiNk zp@n$|OfY@*KB}H}7CYk+8PLNGf3H4z@Cce-?URfo&IDefi7k(-|r{L;gtVC#- z4NX^$_rP=ANp9}wtthofP#EN87~kz_r;6x~?E+BPQo{5#zz#7O>nSz-5%BZ&`9b7A zujy;zax_EudMHh^`w~er>Pia}y;0}KyxywTQZk}xF#-&Jk3fl+n@iY2xSqFZU;SF7 zZPTt%0=U!8-pG16p$})<|HoTHX?ixV?w%hbU^M8DH-p0QNS9dNfE(TZYjlnl+b6r7 zEKY@wxlaCbA?V6LbmiTpXii&Hw%mwRjbsnta7nC!N7s$YMjfl?(QZtDIv~y@B@n6U zjM|X#FD$r{`p!9c)HBjf_V42BA$K{ma`)PdoY!%)zj|z#WRC7Y=5Z-+c-(~09mmoP z-q2!VD?q-KSbLh`Gx5b62nI3Lr-sD6vK^i)HBK6x`@Xh1=d(?voE2~~!q+Cnq zQ{EnIL2Hf1POTXCJDQzbZ*-PxtNI5q%?eGUT+@Q9bFG-5oJB>=2SxZ8%w8C(z{Lrj z?o~EtaQfQ{65UV;%1c&$;yIPKD70?y{IsATw`)7S!}YaEUhv`Bf3i8wn#lHw@zsuI zeoX%Tq6wj_{*iw0uddpTA2&vk@UR(y*fv1Q{V zvWc+sowDV40-k}KzU@2gQbE=1T4&*@TjmY}Yew(h7kh8~Q5xMha3w9R*}^ z0Z++PQBU!29)6hBSya{R|2JrX)BFVQ%=UWpnH#0g+r5?RzcuVI@y@!zJ0}HYUR(3a z>Nk@!u&M1(xT!ED_3BK*T>j_AoQIgPY?vY5x!S()Xn|*eY_IW;2J1CBxO(qc*(x zD5Sky+?zHExDQ<(3B5mY768-l{#~4=G(9A=>3UJaOZ@F^29Lp{zVMY)jdk`>u}E)D zS*NAh9uZ)FCq{PPgtp>Y^+;W3Fk)1~SP*IuA<{h0o!;eI@|G#!Idoj%aw~Aq`TXWz zUM#n0AjMtVp!@5^?_)e(V~C(q+ZQ4$#XMrzLYm;L=ecn*0QFhx;h$ng>LEe5MqE++ z$$~8Aw>T%HzTyU79!5UAiIYG@-P~-LyKF~N|GNp?27-r~k4LQz=6XEqwHo+gj*n7| zzG@P)2V-Qez~kV#vYZra%h5IC{8dL31Dw6C`gSXDH#c*cOlmT*EW?>W$8=oiW9T{Z zKuxd#5V((cjt0aR#jebKaW7=$3*9HY;}}v91eJY_0A_PHeo(%YO3wV=4?ON)tf$jP zsxz)a6)!q(xZgir8)fYFT#hbNYTQUX9I?}0y`Zf0$76?-?L~)l>=yW=cr$Uom*s6s zN?*7nVh@XxOwb{b`v>#>qxFs4>~mm&bltP<55zX(JR$?Kk^fMeh`EFyzFO(xZHbb3 z6VMJG7HzjZPEO)zo$@6Wd+>7KzT(a>s2%?Z}r&HJC@u zs|B-(Jg(fNok8xD00Z0vwwcBT@Q8c9+1P^)jdGRV*?8X3jimq$lQ}j{F3=yHjN}`N z`1NO%5TkK$Gu8H*1?yp1Gih{7UbB(AC{`!_9p%FQD_YWf;)Q9|-C&jtZ1|{!BtnD^ zqB6fgjXm!XvXx^wSEuc`yhgh}MO?&;n)W;G@E3)e`pi;TO6x<5rm@=x zF*Pw*w)4k763dqL8gy&JLD;gVu&Fzv~`YJ|t%D(T{4i-$?a-{UIG$wX^>_rQNq zYNuHO7Ufl~+liU3;F^lwO8#7RF6nAEGQ#lu(^ec#FdQn5A1#O*sa1CT?gh;!c=7dDB$&c{$5*NnIOLi+Xc-Is8G_e=E) zS{2I7x6i%~L#l=O{ZihxUT-@uB|nPYD+*@QnpOfi#;@IEnNqpmecxb~g4lEeepRFL z(H(AgTrB-zb|YpgPL$((s@MF4LYNJl*>|B=pf*jfwFJecgpwWsf!NLpFt5i{tU z*f!iP9H5y)HAc3sNH36~G)d?yEMrFZB13|MqA3J!;V-^213*kZ(UmG|aD2wFR%p8) zGMhH?y;0T&$)c$u+?#Iy=%y;Cl~R!LigvgkZO>|*M+2p$P%Jnoy`_mqfwWY=E%}nl z_MYQ(kk}L-RQA^qj56=_#eTT-j|xZHXWNp}R!ZR?fNy*%m#|hfF$|a|Mif$mn?W2> zVh-oZwmBdz7A$TW4CN;3rS5cB-n{t8jhXq#2tAliFq#}Xbhr7jFRLh^s82?pcR22G zebR%O&aLz~i)?L)Q@=O4;V9eRt<22 z^9s1C=`P)KQpBv&idmNYS(Ok+?3voyjJe5nGLAU;6@Pb(^bp49zS&U&F-Ws&>!FA{ zIgx*;O++X_??>1`t$mLjiXt?ckw1?3euS$we#U43?T!Vy`boRY&9khK8jVki%xoP` zt^$8VO3$mNn4ejoY3z55kM3I7HSO1SZ5z{?p>HMa44X`43DR?({X-?OHEH0e zEME3((kT>?%q-j2BUF?iS^DCvThdZ15ji}wrZ!KdUeR8Z= zAYWs(T95nRO-u+*XbDc^j~gEt{}P(wQue$+k=$p6v)ikQSJ)2`Zx_<&A(dzRG~Xb} zFMiOe1~K_>_OcqBfz66fjm~oA;R>3k-2Hhm(pf^hq5HpLEO*y&qycNV))d#VL4Wqk zd`fehZF5ML-_JzR$h*RvHrcpD<#oVC5?T;vCg0`tbYNg{qP_zL4^$EAY8m;840U?; zb2G%BXFB)4fhouYu;$ zI8%<4Yq9cI_4g%Y#pYVn{sTPG+hV{d*1?g&PP$$-a=swLWbDxpSvTI7(Bal|Li>Ep zSt|9v;L#-3Z0m#LNmMfTr6N^>+@yweHnKQ&Uold(iX|jFN%mU{YQZiPLTm4D`;gUp zUd+s9RF8m_<*PmWFPK@pWapx&d}b}HY_zbm{~HJfd90u z&f;ZhvhXTZ5MjycL_r1TWWI@ZGm~B~U4V=7&*RQqK}&RDv6bXIWv$)K#g^OZ4c?^xj^G5p8WTi9Avg?1-Y~eOkKn zK3pmJ1AN|{K`hns=Oxtg`2N!O{OKSu07wUE_~s(!z0W6M{p}Z=Z}&y<7u;Su@BRaLHn z4DCA`)?E58hR>PqxaGv^A?wtLeoZZDOb?!pn*i4QP>@Wo3`{qN{s<rtGsc8 zSB$12h-I;VBi62qk!?J}Bg^ff-z$~1+|Y)K{X=@S*S{{H>iGyJT!2hJM+i>;uC!3q z-|U^iEdlr}J>|1}2c8CIq5J2MjQFbM5nF2(ek%T$2|GSdMt>0qL2ud;o&F7_T?;i# z8XcUScyET6g^C2xlX>I`{rc0*%K;E*>y_3}MV^&)er+yOf}7*;o3(__9UtSlh0{f; zOb~qP9?&Jtq!`^|u4>sCP9Mo3L+z*zldw*)Zy+Fv@z>=|(G0})L3UFocVOJ*5gcp~ zy!b_@S`gmWr-7=VJeplwntI5*A(fnvWr_kEH)K!#Fr@CzfhM(21^Z$ zee_yvuDA#dRH%Vs$ynO1VMNX*thZvT9Eu5#hkGz_#oDEk=48h3ffRYT8`o;LNFJIi zF+C_sjbpPGEryOEv6?Z0Bo?iFtniO?EnX}sP&l5KR44brE20+5!_L1-kfHVlk`jro zfiy1M2bsL#7CW16sR7kq@1xBrgg4f!H|lQ1t%3h+FEFrP;jDF+RyQp*-%UX` zVkl>QGEi$OF>-UlzCCRQ^^*DO^L9bW_FWhkr;G7Dbq;~9x1Q&^W1308Ew4UNmP*R6 zq-G5ykVQ3s2jbKSUz=x9g1@vRE}M6%(mBR;g*~=ZD0#1v6)X#hJ5OTiJ7>IqEE=Rr z)kDvA(`vPX!{dt7M#SvH)VOKOKNa*ApYb<1#dSoR)qiDR{T;DOO7rc_e$$~}{PP!8 zgXFl|R{M8F`^h^gLIVrx9~v(8ask2rRu{QRdg%kUR7^fNum*M3Kp)12}j>UFclCZ$q{4l|c*(fR3VbamR}# zHH{Bt@$o-?O4BLKeAL3tQ!@RGFUv%9Z$2whGfql1PM~~F&oJi(@C=eKzQU!H*)f)V z?~k`wByEB7k$rz_$Z0ORR1Yx-?d}M^+wOVh_C0vl24C@v_Ll`zP)YJq`=};ti=%&j zU$h%C*G!7@D5%ja+~u+LTztsDufh)AZ@Xpd{Ea9srtoG;VUDHS^Ya2X$^|7Ris zS>e8;jxMKnh_*Du$iJ`0NbMPV+Dm@Y$PmPHppF64FF)U3|0*5U5FR+9o01L|IZ@#xMzyq- zv6FETY!*47{ULmNRDjRbI)8fd+trZGLMDO@BY}30dxfq$Y#$L_rEDqFTzhnXR1etw! zBi#WOq!{-T8s9EPdEwq-;o**hRO~<9)$R*64A^-+wjqoe@My;@x=vPkI1<$lxf=rv zJoj>N7mSn)tr>c#qYj>Bi(ZpbNxG#Vc<#;-vw0zT4=D-AKr zvY127DpTIC+~!?tBlDKmwlbQv7`B9G5w!(mb~B}-*RkU{ei=*@CbL<%WPxfACbl0) z^jXB+R&1T13UNs9E7+|_{@l!RDz`+VX&NXUF{kCA} zIYELJhRV0g(v9)2w#MT29%&?~`rI&KL6Wi3N-<3aTOV^R4{@8n{Z3{#vkN-jMALTiWP>?PBp@pSldC9JT<>zUN z-DavFhEwS%N%T*xq}o4M3wNP6DaJa(*_NSp+;ebr$lGkq`wz)|Yxpb)a=4T$$So!e zg8V}F)~_J1QGOK-4^h4X>2}JdEr9BfIiow@s3|9%KKJA-Ube#7>#Ez^T1sN9OCXrz zqYT*k`^{uSu~WfUQcr(Q9`|5;mw*+#HS?wu0B)(&SM$_FS|BP2!J2Zs>MVK;Pw*md zYR`v|CGCCPSuCn-v==!$>-0Yjqrx*0mHQMvhvMDDYo6{dKMdDkqmB66W@42+ZOSdA zbMzoFH!BazK(7{u85SwU$ty8*bo3Rn?p@UnvQ^bt>#D_0#22IvB~F>izj`=yvYngs zeh7Y|`bTF=XFePp5w&iD<>NN6w5U9$uZ142dS<*d@?w9QnbIyLL7XoMBq4G@iPB`4 zCu1ML?v2Epqs-npw(dk#G#17XOg`71^DC0rRC>IU44qj>kO7bBb057+Launj`LvBw z;*|IvJ0zM-Ri7=RsVG#%1dP**(n&rkDTvT&{DlQ$XS zTHNyF9B3@oscd=Kkl-RlIB@3#@_eo`nD|DQ^CvR6h$wn>bstr>sMV{8Z_YrSC$77X z!uKw>a{XIJ!a5vVUrIQ(3vU`MNVA^;XnELwe;CrL$U=K-z`{J0GHRm2Imw)Ug!GDd zN90BWv}OF~mlvBG0zo&SzBl25RDYq^1_lv(8fKKrRw>_aRYs;AWRk(RB-L=`dSs)B zf9xoaiOM_TFvII(tRL9le;f-h1q{TH(&%80f&LQhylkkCF0pe?i<>*$)SSGVT_OeE zC|d)3=q^lFT==tnrDrs|fxSD8XWbb|sa3g1dK)#D!s4krqVa91O%YuJZBs7$&7@!t|=Z*62$~Tut2qOZI{Dc0K zcasJOyoL=L_#Gc*CS<@lo$Iw}{m%+Zbu543W{`)&byh`OHfr8vguu}_=<;--KZs56 z>+f~QeiuhS^*Z3{z3I<|cCPn&EC*#Qa86CniSWY2W9F46*2}VfjExYE-HUyvioRDt zLC_MvhN_GFTONF~m?xP*V1xP%ZfC9WQ_)2}Zqtl=4y6dKo5W9J*EQx`LEWsFILjxaz9gE=qa zwR_t6@d6VkQk90RnalL3>1**cFPn{!UK9p6D3Y&tTM@Vf;q5^KC~NS9D!jIF`HpOL z^>$IU#L2zX#<|#OU>qg)lO7vjn))k%o2?reQzl0qfI|)SsaF<**`bKXfBt}Kr*W~Q zl-SFrOnVEZkr! z)Of=aJ7n}Ihn^F**ZxWWj;4z@;QoRQjy@II`HF5>=WSU`(F43DMI+q|NG@Aj{om&dPLy+zlZ#Ac~s#^ z&PQn(@1l(TdaW8~SJy<~lb4e%uT3&|qd3IE=oE*-xTu&0YufpCcb;;92pc@^e63ih z-y+1y%1Te)V^foSAAO4&5)#r8gsI=?c2qGW3@Bl#BrZ1g(yN(SyLxSN z)Ae9s{;yLKk(>{0`NrDX8m#=}dZ#2^z+J_*4^UDjU?T4=EdD0jHrD~S5^|bmWoILy zpd=^x_j9GbbAGp(;>c~gz~uY%I5z{Z1U6vjUnAp%mCme)hE^MLQHDAAt3pbR`aNj}n)_Wpd1 zkIK-!1eW68y5Htwh*40;{W8l!%gO0YkDF*_yGZelamIv~me= zCIzm%npJZZ{sK>Yu!OsN6iGiKra-CD@6a;iZWi50m9M*n6iq_Gn9=^w>4d)McqB*Ypswg^?rez%{qCi4 zCEw}j&v=d0eVcTf{O3<{rb&T-prFY!zn1H5#=Bi$&u~q>7Z(qJ_$6|hDYW?9 z;o!OJw&1vfzd?xeYze&rK?l=NwT?e1HLlxC!FNm9vQQb}OF-%G5D*ODB4gH9 zQ;QR@rr=8u|Bly#c|M@JW*w;9HFxPd>^q4$7~$gjaU9cymt=3Is&8PR>3X}sTWGN- zhW5<#KU?{NbONa;qm#!P_9;`#6S)fq}6^l$oXdHK2HT^YktnwmebD{QS z0&nC9rp@JBMebx~At51te$T7p_2cH*`@0)w1cYHzNnnd__!8;^PPcj!8f1M*}eUls-3#cv<9n57I)j?%F2&` zjEZdFTBoL_2K3}Q@2s-6H&K+_w{DpQIzY4xZ4Bcm^3CZvwUG&LF7=K&^;_Ry3aa<9 z`|zP{p~+L*NSNTCrj(SGDTK=>aNXA>H3MGDmArbW2OW5uF#x(UHzNY`y1uk7^f{cX zbENj6dKetTL`L`_4PUjAni}=wv=oMfJ7n_i26SL8^Bs64N!>_ zQOtO{(P(PfHAK9qnR4)VFB2dF$oywe!K>Yoed3%B^I_w1p69!H`7kT?WU6W{ z^|iPc8_S>g+t_-CF`IvhD(Q>g85rk4PNSbCWRWwGd#|sr14}m(gj+TPBV)FL$4*fV z9xkqQ373GtT$WU6(*TY;A$SYrA~d$D%q&>n|J08e^|}q)G+JP+(fuUM$4*{8d?6oL zI~^jzm$@Y?9QTsimC&#-^g7<0M^BrJfwT^7Tf4+A&k0d|Sbz}|Z~n#3$|3(;rIneP zNxfX@^jGETGA_~x05JG6v}yt4bCQ^?vdYbe?Tq^XlFQE44eg{ew$RK(-@FEFufhN2 zcNbUmQk1De8DK4Ly*)kb*KH`6WaG(zE5JQ0Ha3<(d|_^GZZMVq=H@2(wlpVIVneHoe1Q@)~z=Gs1p`Y8UkX?3@fq*RjiS{Ej~}k#$vn2)p^XZ; zs)mrsTAUEz1#;T_Bt61C#KEum1G6M~spVF4L2|1u4b+;{`j)P{Q%5saB_o&;vMx)l zUx$a4#w?VTl?y%xoU|-!xw)MG~cU?b8 zj)?!tT6H{-kw=z0#%IuqP$zJIG9*0t1bE-2t)9oq_deIGIQ4ttzBhR4s>3q*qCiKeX|}^jEq8FMwDPSvea{FNw)k6;SP- z&5WP=QOj{!j{m}C{3LJ;qg?d4DO!MiS?_~B1o5v1VUT(Zyq)xVxVv}!Mm2BAMY!$FV`1ry3cQN3FJ6o@qZ0a z&}}rh+i~sM^7QruC3pdE`)rTJU?RD~3`iZTRjQhde&rJy3nA-0&RY_iXlF z4oFQ+b!0Z8>QcDPiAb+1L(m{-dAK`>v|XF8b2Rhy6&|vVMMF=l@_2hAp?8bHq^aEd z{<8Ha(E`3=_q?;spKPg01G%v^{=pjSS(nXJ*JG*i$si%b0#MX^dV1W)N=`<`jc#0=Ebmu8v40`o2?}It`J0L*e18;Kq>0$t$J)~W z;2?ClZq$1R26|BU^5h*m%pflgcf_9{r!bWW*qZV$8h za^*XKHP@IAhnTF5hu@G|laFpsh9>{~fk=(6Qb2+;BwvcgWx1#P&}?vF_GMRn;g0>^ zqVBf~N;bs9ig!*}jN++RyRFYXOdVYUOS0ULe&aJEl(%9s2m@Bq&2vl>BP|_m-X;~c zl4G<8yK(=#R%8yB%2eoea?naL@vSHY+cq0Bwyeg zyiKOWwm7`O438uVmE$HbRz0Fqj1-VQ7U)4E0`IRbY@QV9HC>C6Uk{Hd3R|loBK!ct zzj&Db*vzhY*Z_4%!pZGZ%9*)8iHEh){s%;r2uqF47#jupciTtdjkoh!Y23#`f#Hp6 ztTKepuZ#){Zj5s$JQ@%^-uJcL8%Re3Y3yamifiL4Y5Mhe?qy!rq@L$MzELZ#y3PmC zla5+Dr_1t?GE%{LD(neo3OQ7ym&y7cPL?r!6E;!N5Wc7&$I{RlZ5&xdgUWssS6wv{ zh7yc?DTesnYlKBE*Pvs1aK(w))c>U^xJGEX+q1puQ)^Z~zLe1GU^^~@T*UO1LM{dZ z=)iAox1wi6bs<&siWNLOH-2Ev;-aE;e2SKv`Gfo0P2q>81Mf)k)Y5#!)`w0);}u86 znX$#b%q4p(63KiNN(y$xjhr7Zko_8eT)`xTj*}N}yBJvhiK>5UD#0SDj@3vErTv40 z0bTDErD%8e;ow4ArD|RnyANZo+Q=8Eo<~Rv?|Pp3!~LD0prBAXD><<{xmGAD4OAqS zg1{YM`aO+_X_H=Dpg}u5)g(r;CR_M+~Ju zTXRV#rHK!cga>Zw4vT>x;lw;-{4QZFc;yHPS1dpxvv@V=THJDf4S>ikKKnPqi^?Kv zn{ve!)fp{me@xqZ%+G45OL6LY%dFz$K9`1iZDCtqF7F*UDGu7o% zx4Jq|_s{KOy42}-dwXxD``+JOEIx$WdaX{IrC0TmwAzY?b+1yD*H#C1w{YcdTS{m3 z>?C?GrBvf{IrbBT0hMYOT9PEWcdRXCH3C8%1F*PTv%}?%piTA8XIw?jLgHZtMYG}< zmW^baRB46MkmuyfzLy>3g~!hh!yA3CbA3JjsHw}#%Tr^&(2RF1hwzx*E=uU>wF&5P zKtUgZRgl{y)$b4PmzsZIvE!&2@zotB=$|+(2jG(}l82G^uOsPGb*j>ZR6g?)d0uG| z+P6wD@>Anuf4n1$`Pvm8SES%MK`}1kkJ4;(1Ue&v6D!NUZ=nQjJsSStdV33XeZ?;6 zIV=pw^M}@aCLvxFFUJM-=3`tR9ILzQv#TkX=dDWC(6UNaIW`<7VoDA$H?*7H-Fdu^ z0e9gw3-c0%vuIcE*6$SaHw$0>QP;1M!EK%8!hS)7{GdXwO<$2&GYffEiPWX6H;gVR zQY3UBfJ!7CeF@5{7<~5~pR1x?2_23aKZ5P+bhz+M%7S}}Y{V&0D0{@JrM-Hlq~`W$ zAZRSLtqkm~2R;`KtHkc^a(}nCvA0{0mQ=EA9v*Dg)}bK5@}FcaW(IMw97HmN8uB-O ztlQ{Ca`nkgN$LXw_XhVIU-ai;R!Pw_yjWT?U?a%VG3Zt4+aY$3)DLy~OhoKX0pLf$$b~`{MkSJC zt?(3ESao&vKr#5R;M}z>rA)K4KpIOS)%t*tdj4DH^Q-rNh=v3J&4p zG((cFn0!5Yc7@9Ya5IDYcYpMc5=@>TcdC&n(Gh3(piIh*gs9B z@wgW6&ugwQNYUWR{AhyZ*vDMc-w4pd>MRM8oMlOdrq1hdoR^ zH(5$)6#=r%8$Y1zK=m1TeU8HFuiM}Pk?LHpcl%7`xR!j@r5~A(^KL8@0CwXKnRKW_ z#ocH`yL?aS!0)HOfHnZKV^uuNBI$(AC@EC4^Epwu9L8n%q*v!)k4raTLLMSkEC|iP z`{@r?=~s&dfOQL!DPr&(AERy8I}u_lSzW^68HAD zpy^gcG9VJup&xKhOX_i7dgp=a@q zSd_2_2<)rkBunBtG4>Hh&aYLDykwjDo?Z+L^ph54OrcAIL7rom0iDoJo?{`M1{F}DwnTf-T?x81&#q0bTMzz9o|FNUgul?l+ywF-tB=*ZSjemqMJ zmE^?82`9BaN$%dnc$t(R%{~9HJ9OWl^km0?%=>i24+V3>h0?Z27Vvvg^Ot0cusR!>RxO#71@#ec zyQd`A^lk4*Q~l+TWxhN9mLrT)cv0Jw-)nA@ki+-x-8GCdQUeJYF2BRyO^%uq1y#?* z<^J~aQ#uT9>+ErNM}~sCMi-ZA8w%fK3AuwP8^B-Jra6}SS1FR*;0Uw z-KpSyUJH1YjqZQQ*|)Q}fIqKv)AHTIL;{UAPA1i%m)^^}Sqj0vsbZ2({Cd*c8ih(TP z^`t)Ouf+N?f4n&S)|JT+8$g@p*3N(qclM>_Ao3ihPC4UxbYeoAa3IjO=eYm9G%uEL zs4%8VcU^G*sNS=9C%nZ^i^%X zZ!`j)z(t{B{~I?p^_Q|wQ@NMC1^!Em87vhScvY^>nlE5?s=K zRKhQABVPILM94x=nI56{LOw?zG8_ruFDzRiOaSt| zkfcyK&DyJthkn!E2i(IXn~0P`Lx*%X$|F>7-b!rPkWbsdNBm{ zo>xP{B9WEOjvf`f+4>dnli_1LY-(ycH5Gf=q~nn|_$8ghy!_ezJgY~Iq z_U?2{Q9BL>6#Rt7P9m4xGDw3zUcvFa-IG@JiF^)EW_9&>qFGuQLj*j1x0)=bhGca+ z+R0to2nN~g`~_j@#^*9-Lzd+f6tw{~ z)viB&XlI~?r+HE@()}i8U&1@^>`5 zr13aZjUHYSThO|LLyj5>+(r5dHeX`)hGl0{HcywvW^(9Dr5tfSVANPy^Cq}3o_}X; zHeV-(uccLzV|wbg!K=|=Yo;QmS9J7|stRe6r4#(uIe zlxI9fN@-H28j=_)DVU#B23fv(DAe#5OY_*KXIzAX%@@GkzJ1=6>$((8KWkJRo>6C(0=$b{ldV`2AMslTedf%%ms= zx;US&$u9%HMBn3{(HpgDn(x4peBWumOHc@*Jk|6S1wpBCbm5%qN#-SDrc z+pm5&D0xa?2lj6bXy9^2DDE{Ni`a|OVEN?zRI6@0pRrO^Ri#o{JtM&p)*7nOZfKAa zgJe;MXlQbA>~V(o+mFS|HUpqrf$*Ll@qIHNkf?p${6l@?nApIpMAn4gy?%BZQjT1c3wxj?zg7Xx)ikXH1@ps_Yai8Us<+}jy0biJtN=f0nCpQ9d!QE~8a z6tQGLmUEnnhRyQeOKL3#_n8NN`I#k{RHwQ=+;{mloFuD}Oo#^UK$>}gYIJN&H3G_B zq*E6yMx@hAiYV~sF5Tvcbl%!b&X&xQ7De}d?v&%7I};-tTjog6tZ?J=WOqgc?&F|b zGEAaf1A2S1QlpRYjitZlLLA%$`!H_o zW6-^Q{R8^>85g~^ony(tIb+zadD8h>jH1>$;zO<)PJkG9B{x3fr9G67``+VYHVzSC zOU^(!Aiw#xnVA{Of6H7w^RNg^n^Z3`bJEN^=NJn~077;H>jc~Ln4B)1m0 zy=qcV79^xrUq`!y?xJlqZ$i1@e54ZSX;2-HJ3HR&1-@rZ;$$ES3H=+AKW-Ust z{>sRfh-3?}!yeCpdV6fX+#X7Fo8-;6o`f$Bb5`+NE(6qN8gGyLL`6lZR1Pjkv7tA3 zznLS#TQ~q(W`$}kTazde&y3Req|!V=%;)|jT^k<2-}v4hLtChb&3=O-ax0edmEIf0 zLJZhF5<@gLoE#jqWk)2+-3VhC(pE;Cn>zJHy^p@@n}mh9e_ODe#oFT9t2oc}RPe}z z*4h0<;FC(|#s9?pMq3o_HN2jfE&+t#AABpq^=9)&Wepa;!o^4yNzrTy9A8V`>STA? z(oO-CYRILNZlh&ILUn)$RkTy$Iv`9}8e^*CJzL+|r*K(bt)8Sm2u#}vC8ZW`G@%<) zkM`B#29R)Fdarz8+UJi^ka&9Jb_;ZxDrBNt?sr<^e;2$W96@5%lMH)Z$PO+qGiyxV zZ08ZEG)f@pL|;GI0$^}irHd{b?%K*`8xlEhi7pfNbfxqeM7ZUq%app7ul=P#-|?6| z*5lL*qu0KokiEfDi*~uVh*voD>^uB%QgNLj^{X`;eQ0g%M-P|j>$8_f=?|;q54HbL zu^ZrhB{}KBz`pO%ieI3}W?NeIwuUIq+N@b50d= znP^z#8Y+q)Hp!&k-mDwmUoVg#$bLP(CaFH2&I@o005A7^$OcV?=H1E%PfEwniyoqo zfCo&nKYUfG5kXGad{=8RvTVQLg+MeoQB1*xIiO?Y+t`^i)r!j6->2Lh6uRlIlpW!g z4AZqoUBt}r5EmuPZ9OB#S!-euk7>0(W2ZDY3J0YFT*lVz^042-Ci3~?rkpkWL=+H! zBX1cOGC6S*pekoyPm)h)s2@}0Mpu(&1V{L;57MQ6q4DMRWJP=o!ve!ZS#qbjAj~~o zTkrKp%WmyBV?zkEalUUf zLD=zTV0I{tA||ASgk_J>=3a^ln@hCf5SC`mnrX5J9=|=~=vaOQHZqpfwiqnqspC94#)^L%6WB088EN@``)eGEa=m@5U*~2 zpZwvn`;&5FN(zvm)wIVhs1te`0(K5wdKIriPl-OHppS<$6|;#nZQ9l?07tJ|3ll*f;EcF_tw7PSL2TE0SHSi{vsF< z=&)lDvWYYZa<9b38ZO5{)-w*{3J&kzU95|K*);_iob5l%KLkkjn3v5orev5l`*|Z# zTCI9HBRe!Gp;W1YQ~E2biJlUY{2}9$llVX}4N#TQQteUhG|5(B{0$?b+)r~@XvEuQ zhZ0=QIRg8Ink(@>kiawIpAf#PLD@u&Kg#LW)e8;I)FFl8$zJb={v>;TOS+UV&(8;# z_Xh*qke18uEe1xW2GrghT6WU9%pqIlo%lx^jgXK;iDJNX;@x7!?(Y^K=Kq1!(&GKz zBCKoBBuqG1wh^j{6UotwKv8Q0@qObG#+GWhEeetj$rVPd!WPPII2k?5|I26THJ z7Ls~6jh>?PMwW3wp?pnR~bT+hS>Vy4MA%;b8-QeJIjv#~2R+$nP$;Sz7w( z_6!a%eGU-|mb@Nr7G3#29Wxgf(L-Ubc3$JQ1XQD2_D~Z_%3r~G_h|Z;-~ORf8;bDd zha0P)0D*?OT=9;i*bBX`+`P3n<^(9+o$|KX)>d>EC20Ys9? zSFh)8YKpLrjdEN)292ANI)y3;fcPX%4_<+%mL8N941Y7^Qf4N-R`TkL3qIVg`R^yq zLSf&al^%pI{5zKQZ&&a?J%JZI#KgqXS>m^!nob1^D*VIs2l4TF}e~Bx3hEXr2ht#J%B{?G?V=9ml_>FDrQu6wB~mf zC!8?8ZNsaP;Z|_$k_@`A*3IMfAQU$`(EsRXj$x=42UJ3=g_auFj>YpjOU+`jVL z8sD3mPxn_q#AOP3pr)3!47qZ_I2WQ;Ks*CJW%32w4ceBOyVv+-If6F0X@fNL*19#T`+6$b&M5ae5| z-7wd|;V+zR=g$z)n83%AFuR6%mhv*w0iu6m^{cMtPNK-Oy2aAzZIT-WMrb;mvLVyL)11lD9*;>%2_H&KDnIF4DHC9Z6RDdW$uF(85 z-QtS@!R(?qF)eNF6Ia5qhufitgdAy**+i{F^lU8$C4cvMQ978_(P`+NsG5|Rk<+F| zIonqP5w{qP-UK9iV5yNs<^-sTu_2E57lRIAHbj<`SVy4WNPJt9Qfs>vL)FJ!aGq?d zUI7F|P;lzSW!K^l<5k=6*|#kcG;x~}fer6)q#C|5vdWXdnY1YD^dYA68;47}O`A|j zInAGPZfed9WT|79_VlQH!F9SpUBB;|!CU4G(x6+)Z7;dz#fSTg45eVPPv0-VEW^K8 zV#2@YqL?Mp)RE76M$7gM_cfYPeT88dipK*cE2++f{_LegD}gQtlyC+b8ud~Y3%{3X z%CtrVG^y*F8i$hRzLEHmK^&B7cqDpueA+*V;lPIdVyFpX5Ah??H8*i^*i9AlIgUx! zs6%?B({Qg%Rx33Ugugj1^wm0y^i^Ipu6@C>-uavVg<_z{`4&yjbFb=?g8ScWsHK&a zvPD&VF%~2GV0@>7M;`*7ckDw}L2SyP= z(%tFWrplN?vWwfFxp)o%=1!+Xv4xA~3r)Utpi_~WmPP~l)#nT}8Nh2z@di<10{JT6 z02^@S=#pC6(SN9a^e>0zy|~Z2>yb+WwTTxT<&9B#fe#N50!oy-GIRGK(<2U=k{k$( zR_N#jqvW9@&)wY}Rr~8?J55s-f$$y!Kv-JpoGYS?13R<=V_d46( zpKtd7Dt#I@UaPzIhJq=eKih`A6&Pvr`(*P3o~%knkd(2i4U8eCHoV0;Gx-Y^sMrF7 z0u@NQqlAEx*eH+-`mmEVU?Hx2zkhH)sKvYTR=Zm|@z|R0W=1C}B)7y}Bc%ZIVDXg$ z;h^5e%oCvC`y>Jfflepg3iZAzm`;<6SFvLZDqP>l zGo9}zr^f#%OB+Tu)K+)7SG28YHf9x`)S^wp>|WQ$FJewS7NZfQ{N~7_(U%=H&pZ<| zq=Grhs_XLF1G!u!ZCz({5!(#xmZ9u>(-lEt-;z#?7aF-ZbRyefUCg+besT>>m- ztd457ILbnbK!N-QDBaPP%l_6&L`qN@;Q+)C) zH_fA0ivS*4ml}y2#6`W=1DgDdGoN&KE!JA3)I#!D-GJ2Z_2diN>GI!?5w#BN<&|Rk zJP+0Pa^sJ6$S?Jti9R|)eJnZJ)g&f}U+iQ@u9kRxeI7*2!@~m@QE|6w)^QwoOSST8 z>gD{`+uv1s=`!5$HGhs9d4*pK;q$p!xjy^a>;>=JiczW_eCqiMlI2M+cN1D2wQuAC z_g*C*&-L-&VpH;eeZK@WZ|mObUp{>1C82>7OVz4$EF`Axtr@%_NwK1=;29e6p4y}! z2Id{`;4lDVe*5+4>2Rqd$!XlZDW`U>X7n=#vQ%f(x`iZZ3^RK7$s)`S zigahvad7dk;Hv?klJnGa9*GWI%a5(x^0Pk&niwWd00zqFrH;b#@OPhf$c4P7k|-mE zuFYqVjI1Ccv-|P>K8jaz2K4f58ivv%4pQ`H&IR5tyA~NT8J1 z);!*0Q^E~st-`u`mA(jjq5bLWG#%@^6H^JKu* zM->lx$@UX5Jnd-~S1}Elm5<$IJ<>Tx(Fg(`Zv(S`us+^n7KO=D9I}PV$ELPkToKP~ zB38U(`NsZtvt5;u(0mk|v71Z}%+FyJb`EZF@UPeu}jJYUs&heG0DeUGplfr-gK!KiM@!uhL{u{o+tU?MrjSO2Z*C?ahT+14^6HeL zKkh(`K8Bpa%RpIP3d+gN;cBauHhYrwM4n-)c2gnH8GE|UG50Nh^HI1htXvM{Ri_t6 zC3x>0zX+KSsrPAwSe(1}eE6suAVKqBxniHzP3GDE&zDxF%8buBac;}B4S*t>LT$iB zPr@(^UQ2rgszv6yR>nwyAZ}yg9xc~@N*eW8LkjVQSce*RR%oWpBQD)7b!wY>p7Tx3 zY)Q@q!BtPabEio}SW-OS0A7DeODX)FAp~Lp%EEV8apZ4g2!T`b6Uj$FmIgbxh>`MT z`lKd(PTP>wm>o`l0fVG53i zAd;yQNLam#%iNixH;Ta1v3vQ+QSIX;G4iyq@2| zDX7wC-iuA# z-zhI@P355NTY4z^F!)tTDrR&d)9ZRHy_%zqHCA9Xj59?R5lGAm+Y@Sh-`qK#fqbi| zW>{^A($dnZA1lw|(v}~=7Ws$IS(;8bgmfD;8VSoh1h|B@$DFbG9M*z4SKys#v2D3* zy5%rpoQ~<)$%yq*XrfIKHHww$7TADAoPJeBskdMMxh=7LEyr69tjMdcq;(c1wcdGB zT2QUnjG?9?;k8el{N&(7eSQNzc>hCMEIw;baQ+YBN$uFQwTs{^4;ME}@9V7&(${fBEhsEvb%bl?*?9V2(v;lr5qRKeSE=BH$kDZ%5 z)SLPn_H?MQ%lC!8POdnP5hC>C5ViIFtvzWp_8g1*6XA!7vv9r z$uy&nK*`Bvg7%~epJ7;T6#f>aKU$_w4WdZR1G5e<~S z5AT?nnc>vB&h@o}{?tIqDxDv15TD*@fKP&wkqUog?Rs1H% zbXu@XSPD~K!S58Gjs zAF1KyOyL|h2@EaJ*T_9S`pwsN`FzyP-A37LcXbUr^Hih2tdiv)hRv>4pyL;{AJKO} z;B0ei&3YdAq*z}W))gdlO7WkV_zxOmOrwHjmJ{T3#$X>{Tw^Sf{yw6)yKFyef?W;q zMz|w^a&X^z;{^x#KEd7_l%^+{2K0{{KzqUUPYz02>oNl&B0`%f>!|Qpij!q+P@3NA z&(}YtMk5w@^!LAqx6n$8{0`r$GCFSDNU|ync(kAMgGEKot>}-Z5~lLJ?-PNH>+1{a zi_-}15O!?(jL07GA#6m=-UHyRiu+^-Ae16K?{h;U5jRSi#4FV0xTZwR+w+`ufFVnd zY;!%Bh@&bOGCW?^ey1Rb-a8mLfwxxAg&7eZC>JC4G_<_t7kyJ7b7vhe05bni3kH^! zp{9q7GWNuT&1!m3Du-dh7sdkL8+;l9_!CG{qM3@g&i9+&Oe=vyf?&7q`zv}5!z+J| zlm7WrVBfvIwprY10_)&wkimpqIVEW2!aLD$% z9{s0ImkGVLZf!87VKzGcCZV(9 zuPR|iK*NZ5ll3n?2Uu@`1OrGAW!=5j=R~*xFP)I$sLb; z`+ISV1>3O!V;Q$M3>p>=^l^F>Dzxh|sfY>p%YS{~u3w=@qdeKeEs!M4j$s@5=ZQKV zKbWNwHAX%`52U+oClzMdd9WC=5i5SyoCl;pRh$El;ygZ0)^Nx8IWHS1mtXIjgo(k& zlB_5m5yAIv(wCapOpNlkr3uZg9?*`gK65f8BZop&i`w3RX>DK!f6?MUV>C3*D{{{z z^=6tpX#~Purc-05blUPJ1Oxr- zd?!c6AF-kY(2#KA$moEhnX}hnqc1GCz<3Psbark8=ZD`u)u$lguh@RWqQ4T(r^<3jJ6cPjI~opA&yrW!@843+dm78j;VK6{M3hq494L%%MR zY21`mN}o(ZLxUmjb?8*{(`MHwP|TbvDUQKT_017tR6i?L#Cew&81#DW0j5eD?Qyu^ z^IR>&l#M!%F1-I*DhggJz2Lm8CDux&=SMXL(5@Hs_3TEioPAzJwY0x?oiwTfdh}~F z7n%wE3gk&C73L<~6IXPvwF76-xMw2vv~BZIr?(FCy_Vtwv@Lb1+6iVCX2X}DN5toF zD*J^zqn8aiHk6n}uW?H2IUII>l$1o8J};12PT%!Zu@{Yoedyh3LlD~EC|1xkibV<; zK^j_WwX;pDdt+H_AV#L&FD<$=@D{L^~UR@ywo(O`PH%(S_Byn5<%BPpcg) zBi88X5OR{V1(FhwyuWpat17riJgoNZCBTfIfjH9N+H{wv$G&I`>LH7 zS*h0qul;}6OccB`9JgPj3A+@Kj;57wb~@jt;il_zUoX zO!%au_1xESt$ZGx0GRQWj|b1Tv$=jHP8>LTo{4@4@vG|-bTw}+u!v0^Q)Njr?Uj{h z5)-O*lwbBt^yDtGBNG}0pAS3jh4?)NYcV)eNr4hJB0h!~kZ!IzKwq9A6&5*DUeQw& z6)da9LPq=nNA4uL46CI$MhZHs20LwL#-fJ62aG0eA15&$0LE9I`%}<2Bo?qpz6i!# zzQ^(w+Xl-+1@vkP8>r}i#`ZAz>uXH2 z;W~mpo3LndYsA{)xg?uVf_uHj<1-EAL69GYI`4!+-zRJklI~Hp2P=FJL?c{MJ7Ual zxh`la-#~$vo0r?_Ei&BP_$~oA(O)7t>>aGoX!hHVMm*9Z%Q;Dg_gRLvwz4gQTdk7{t8_Jb-fq+9!{*M{}-=-X_MjPtrGTPt*h09h43(3@02K zK!&{v1(M5sn!Q}k^HZd6i0eTo8k$VPjgCddFsh$YyMEuTQtTfC@Ta2xIKw*20gbYp zskU`Ls^bV2Ve%^Qw)Gu_ni16~76v6=j{7|0VW$B+PT>m!#i;oDeya)~7-{E{~8E&lxZ$F4t@bgf#3 zz{`-uaQ(9Sr2_(S;d;;1JO+T@UEqgcJMzI3$HI5yx+83_xL{vF(mZL6ziLkk*mo(3 zpUAI>R?ju%j}6hKs)dIK2U|>BH&TtN{PO&Wf8}kG+0-4{R{4zx1<{jzE<@<6aBvw#Z3UT+4X&vATY z!^C||-Myjuv?%#ZO*iAzzf*NE_qAw45)DCFM-~@eI@QiL3@n z{X#JGvF4?F_7U3mZy~K*@<|!`nci@IOJB#gcP}_P0r?QhU#@;MLW7jnhDEtqn4I>YYr0FAx!fA5BOm-mEuPwsXX z62tPsAbvj#Nl1u`X81gSxj?@~#c9pgJd7O1)_Jcze)$g#P?}1^dmo;O1vfu0>z=~7 z*)|_1Y3tFCu& zBt)`brGjFO5(VlUbd;Hm3Y5ZX%Dt_<7XYOtmLt(+yM3@&pPxlD{SP<5)L?bHg|#AX19P1H)NM&zNr}CUpIo&Nl11@SXE#Cj19?%{i?Q(f)gTC~1XDoc>WgHp9kq9s!7T44Vce1n^TFdZzBIid4N zL<2)$roT9kFaQ44o8@5RPhv{v=hCREfa4fAcQAWyg1m6|OB|O;x&7czy)+Kl;R*9E zBq@_*?U)4cnlbd~tN7atxo|mPbjPkc2|Gm|>u41Mlt*n^)6ES$Z#ZR)d9j4a3f^G; zDX*pbf|ZJewn@K`j`uPK=y3zb=%^ptO#Nx<`rc~MR7n{;>1x-(L!v6zL)hLU_PyjTu;Stw8LVgFf>z$;`{^d1PEGf`oZ20)z8`d4XkFO9Jql^|Ozg zP9$O7Qa^}TX%5IIC6d2aU;_N`9CyW zWmHsu*HtiR>CT}WhE991q1{X1f;uDy1S8sL=|-7eIs`3$SNZD+ z%FC=uqZo&r9CsZ=gorWIu4a*0Tdi-uyz2^mmwWfc{xGr+`t8WvbOY=T5T?U1{PNKQ ztt+k~i^G4fgrlfCTSXTv8^1K0S;Oys+6AO1d9T46GMl=WuHJeuHuwlL+-h17A-@B_wOWcU!ZED-5wUTB!!Lz zM6UKa`>jvECY6xo`KK$IXYlWJ;XDAOk#F21@7>lc071?OX>f@+_o$qoD#t~|*1G7# z$bv1A4kjKWqSMVz)ghLbCD9$p=#46vx0V&cuZioHe;uUK+k56wIBK;WLUWp7n}VZuubo$Gg;l3rk# zl_xFt&1m)YA8%qBJm?iWcGt}h7Cn*ZGOEAu9b5#F=_qpnwffde6=`YaXRRC z0+RGKwJ=+P)^g6psm$M)?y04{D(gMalqO>EQclE}2SPI`Wi zKK%Hxv)$@`8pt>{NhgL=@}oZ168Y*FsPN)uduETf#&K)`kRMZBqcu4|rqanQGQaB} zBl!ZzXyZ1`#*4|=*qyZQ29gR#H#oDC0iZ|CmLQUf1cd$5TYj|oZ1pP`MnR-LB-oa= zQ)ViH>e-CnX_cVLT(iE@iyIrVJ2W_Yuh9H84%X`bu;u@r5mA=obJ?&=PZo*P{3RJ2 z@5gDLO;7y0AfTqaETG(35%(jsVu!G#ym1Y>U4CF*Z2Wq=kx2YkFTi|18!LJe0P&ev ze{L_?CQdV2=g~6>y;sS(rI|L*G`F7x5#(Z|NQyT3A)i ziFy4{>-qt4*x{91@lo-hw&&uJH4NEkX6q8LAIL#kXU`A+V?gb3VbLBgNDZ9=@2!P* zJ#W~o?ZwT@P7i~O6U9S~7&76(!Ki_*`nORSX7>7g@21Q)avG+4S9M9yn-nTrg%-Xu zz~l!u3N~ZDN&+b+d9oeocQmmheC3YAVwbxAEy901_%yJlWSY!tlQg@y+ACxs=|Dv$ zjtSk@Z@>6yXAWLn&XO|!su9tv?;8gVs%dfLO;9-)rD1?kE=KSnwi3x}#S|ytMVPCM zoT$0ot_wz;GMT4;lQF`S9PL}vJmvg*5=g>%pCf7M_cfY(#KJ!78~ux-vgL@kF#sZ_ zQ{f2Amu%>ka?fPve+uU66SA%P-Gb|rXEb@xLGMB zSX<|Z4L0}87b4DjBE0T=;MZ^s{1EugrI^D> zm_G*?f)qNKdge!(mggb9l;veMv*6uM1oE!3o*n~`H@ib!vQiRoo$G}Qw$g)Crf+s2 zlIaOyuF#9t@$l7=_%P}7UH@pL^J`X*)oxNXefH^tP$}C#MzZts^ZzZv;NW02fn%Sf zVv12r8hDfhRj1da!O}%=(@mWa5Gl=G9Ta>kV%A_FyJhHPRqCI;v@=?{t5=regq!@Y z=+{{1`CnPr>>AQkj0{Me*Jql~Ih1M0Y$?qz@Cci$7Q2}!ny;#by;BT*#prOSD?J~{ z1?fpaWCaC4L5+W<$`d&M;=%|5!1tNw>p+37b}0CJ?@66h&?MK`71HC2mdx_MakG5s zex2WE8~E+e9C=9pa#wz6wBKdX0>lYX(WdYJW&TACKqh3cH1&j?=HenqKyv&XG%&;S z10hU354ZSaa+`yl-$O>Z@S?-2mDW2yoIUwY`Sp*lZ&MInxcnF>qmQsT^ISajemGI) z#nJi+QI9_FmcpSx3KcMe3h5VX%e1lVz;~ zz(BV)FGi@c(|6{RqCC!`AE-`12EFuBP)yF&K?)zoR+Yi+i<^Sdgq1X^akr&>=)S_x zsd5nm<;#anffg%-b+i#Z?!<$b3IEGn?r?`K%cX?X8r;rjH+y;L-%8nAZftH_QsU?Geuk3gM=9$GcmD3g-G; zO;vSOb@-rVe9BP?=@h48>KH&l2Y<2Q>$Z5yFV`#S))-ojbdp{`9y|#g63zAR)I(&0Se*G(-Dn;&T2DW6Sad-TeBMEyv4Q$u2xi<_qY zdjWXBwD(1c4&m84!FHrfq3P%JrBMd*EBx87PJ<%!tt;PU`5DOKMZ>i-sFtd_T+YC_ zIkybUjR@^HI8)DPd1bseKwsw&V8bW5FCLRYFjq%snsLG@AXB+kt4est3*CrIctE~2 zZ(s{6*6(-+h@-szFCleyrplUVkQ!%jt*n8c{Ks432q!-R@`r`d`65MJb5kp6V|nS% z_EsmcQQwueOe;ZR^&ivabO1RZ^X(7Cb%9sG(+Ln}8k5pPF`CI(qj=@HuYmtE5V~|FXd-}Hfj-YqLmQ}!$FDV&^ zdE$v2Hkyy^?)8~@9*av;tFh*(!B{O$*g-@2p8nRY#P7J2FsBSS*3=0e$Xf3W%a9fV zsU=B_p9X`mH|>5Gx-fUHIL}Zn*LD`%f2hogbK#O5A9Ln*5|oyeWogX79Wb}a{wmshZRBg`kk;3sconeelRQF>1ln$vr5+#A@I%bX6MUTY;X(5%H>)_mwp zd7-ry49O=N6*8XT-*o@w!{N;7L=vXbhHX-PLk;DbCzMyyNAn`=_e9EL!;rBR6eaPp;HAILL+W-p)?4%7g>YP3X#C(_$U`$S%!YTiErn=nt#%?!?S# zfc+ZAVd*12sMf@OtDqf{T+S#BE zPoh0rIiC##mcl2OlSG?-RsQ)xT}K_;GWAsT$DW?2J{)5Aml(C-YXdiPaed}VKMQ;0 zEBd+5m1#^XVA1!tm)8HiK-)_yIttc~Hs+~W%(7At7ud{GxvENkA`lYD(8f^8x|{nr z&B6p8J6-6s3||KmJQZ*>n8I&Ye4)e-w0byxj@kmkl@nfPhaHT>p}?>jdMvU}+xZmY zb+j4Zrz)`|JCYeke3Z7%Sz+ct$5eT_EeMpm@gi2=dDc7`7Oh;CpYc1Rx)37UxASp= zvqWK>4h70l;5OW;`=o>6Z?iM6!#S=M=U-@%q*u2IFvA*pwah{$126bO%01|L^HM z!orG~G+;NUnuYC0oa$-_`$EbT??gCKj>1fw)6mG=vI0qoX( z9?G$m^4^7SpByWWu^qo@taZn|P@)4?yltsg12-&3j6|q0N(u6N_rg;dvc5#Pa3NTc zOO8w8*mH7_Q9RabPWPtgmcXsiMlrcE4oe|U{QgXX{S|!OzZbCh$`0hdrBASO73syO z$=<6xIDD~HRYTfRz*kC_J@k+F$*bz;Usr})S2s0x=TlMex~1nrwQQ$?rw7%6Gmk80 zj#VL@+W_jL2NTwCQZQ1)eMUC7FhfC|eFk3DnH)nkpW>g2hb4SU>pQH4AQ<c7EZ*U4GsqPo zppUL1pk%WdX$O}5()EuGh&K9R#{-o=Fm_x;_(OppIy>>wGO2?i6iO#{0DN|~%1aU< zc6`Bu)xX%!$BqU3PX$PypqM`yIfb_<`eBwa?Yl5XTEPsFty;F9WT-66W8F9&p_{1N zxOIHB@q1=nUA}vD?j(++t!`OfNINgKU&1;BjJ-5Y!qc?x$Q94lMtIb7Ljx}7jc|AU z*y~;H_n=zFPh4t)-7(k!JesvRVsC(-} z36{bQ-nV7fww1)pqE?pdqZynFU2st9QxIB{ zwo(r)1Z|a=Ly7~r2(M4V!&+bS15{AEMl;#wn9BAS9R*U3-oc-v2;o<2xAs~xfKkBG z15rRN4S8Ll=UI#UAPS&Y2g1^S&Ik`j9V`3E<^(NxzpvJd(Nb`*Q@we8DwRmUi%O|i z`_r)+kL2s++);d5Qj!w~&y=PDd8C;No6`squ;0@)!OvwyKUPmBIBk@mc`1bI5L&bl zb)b*gt?C*kGk;OD@U})LLG3%?o(g^1lI$`uHHEOM5~}X*0=^*wGu(5dpVeM`zFhV<_7C%_`;^9(VC4+lZ5jMwYx@eLirKlb-zvD0+}RbZhR%}@ zD}zzuV_AJ5$&_zo!n9~Lr0vz0>VqvHshpi>6jOR0GXkTtsGIwCLv@iRX zRTOrd)D1+u#U#nEER5gBDd%px22$8m_nF{sE{ z_LEEN&K;rqmgq2GdmD;GE5>O<(eX9IIXe#~xYP6}pPF$ce2;l8AuD=U5OD*jOk zBrU878}!r&NmL1k{)($?$m>6;gBok~_ME7-x+J0y55IVrn{Ljfcn*g#@Ipcmg|B#w z6+L?zT^5Sa-juZvk-Mw(H>}j)(XYNk-mlO4k+y3stOUBwaxxmerwA4-qD?hg;TwsV z0h_&Lfz;VXyiaZ^^<~)8WB#iYOkQq|8UFZ}^GGyl^0JNmX&X{0=pyqZB&F!>+7(*a zl2x#1?}Iuy5j41A5p?+bWSbcE<{CVAcp6IrwUp8b`ctpOVODVDWrbUh%-=|7fa3Pj z=0{EgC`94j*`3XXKAL6v?FJY->uoE)81N4B)_0vWTy7fycX-Ijr+;0#x&+U_v}CCI zB~`p%qWe3z;arrH>;RIWDxKIY09`Ek3kOYI zEL4stNDWrMiOvn|jfGW&=|Ygr(fajCeL>T{A|KSPL&3Xgq`hIrLoGwDKx9xD1PgP+ zhx;xyxbw_HlQeotfqrd;3xFE7DfJ{xtueYz&11VeTrHEiD2?GZz98bM(}DZO0jA8- zqR$A>+P*;MQ>Z~XF1n3kup+(9X) zWaPd0Z^zyrYiBm39m0nI7`$7qGRA4)F$mB)!k1>k%P3ZR0fOo29nfGYU^kbRzb^US zCO7p823rYx{~43iNOzwhdYp%k5X+on`(S|V2Yna+ACSKR>#BMH#vKqW9Y-vGiQhTv z7_7SRMlBbxwmigU`sK>npXkz3$;<&WqX{!K++uI_do@j${)6_w^@EYX`PBF(569Qz zp7t8Rp9O;*R0f->YS<1ySPJ+T#qR|ZZ$eJn?JQfv-hD6TbU(T@v#A`rC;k>hzzlw8 zy1=%OEie4A%K0FPaA!bmn7@*+6Z629>*;{J{5qkKk{?M!Q_&xqen<#g=^}}$DZlsC zm*1H#J=vc>xkge!O0Em*V2HTPtV3~~pBN44YfNiL zuT$(=+k_;G5j;vLtp@7S2h`q@0yRjPM{(HGOsZ5#2cKC0n z^zCU+y4IeK7Fdc}IImBuXOL2{>-);c6^iUd?|?5#>lPSG{ptnc91O{TDg-ydO;UgV z>d8YGs#yNfQ&6Jj-4WI=`h9_hLHGadm40HXsNz$S-3#PWClsnTm>^M=o~!s6gLpW+ z&)!(sT?LnS*0NH3X=Co3VrEMc(3K3;IxZUN@Qf=v;>TL{gEn-p`)FwrT_)g|>Ywla z1pL_y0C&m=Tc#|~#dgCEl}e&C5(s`TmQqJWdGg64O_ljh1#?^_+@He6T{T(DIpr<2 zglsv-*64k9{~CxwDVbvuvH6>WX$svpmV!FmfM!!b9ZSMo(hU|fQ&rW8T7GSHfnP!7 zmlhgin&`rt^qi}TYX1HsM_g^5KF&bhZ9F8`qUrr>Rx;NDad+zz!2N05ClX`Q8%@rf1Xlp%jbR|-e9n#Muu{e5YZX8D`sb$9O&s|`U2c6*6&MFkLOMAW>Ilrt z1?7eJ+!_!&5ZFfT8=`^lyy3)#|6Spqawq#ZJ0Tq&FREUN)AuUNIZ;2~4_%obu{GWH&6|tN5$i0qD6i=cyiuXCb1zqG6oW_k*W$ zDnr&B{l4`vk$Oz1odPw5`)}RPZN4nx<$gU3;dk>6p*Qim6nTb#yYsVkEa=U{m76j5 z_v!~vtgofs_O`*vOCK|VPD@A)?~OD-q2(l#FwBPzEzK67WdR~IE6YGCSJk^0aAylt zQPNPjs>p?Q%fy!!@S8<3l;vir;1j2)=SH}Hg!SO3=#{(`CY+?>YET{R=Eo{DKw$-Y zeRzX}P6u4SywMVj+)rZst6}x9p0|@tg*SD(DBonJ%U2RzjbyLSk{Q`k`dzv{Kz_}QCIicqIMZ!Nfi-` z%lzBU&7W8@475l&a$7XXLP5)R!PB-|K5 z;{5HFwrHDL4dLieUBptSrl?u=YtZh4J9)Tr{llzWS{8wv2`w=Iwo*^qKY_oE^Md6}^r+`za!eNXinA`Yv++P5=(JsFg7}ld3RewI}$V)8chuV*I56Hh#P zFak#Fw2HG2cDXiU<-0?MgrSFwI~8lR;tf$$*q3gg zxr%sLTj~3~CbEkcHg}Gg;FL^1{z|FPd_mL?=9i#%105yhv`cA@8vnb zK-zOPM>FGJ>Lko6$Z3rPp+3<0*zH=jW&v<-e}A;m5WT%HD(fvu7F6Bi*K4@YV5toB z&XfWt)yAA>h34>gt0|5Kx@+9w+3hmDF;%cQ2Cz0v{Mlv?PfbKB71~8 z|J4ij5mez1>Z!qrj-h<1!UtdJDEJjRpZPn9x45#cm*aIS7vZp_089BTd-#k#h#w{> z+(#=9Q5k}Jh}s3xeKJZLbZM;vCIh|dCAqi7y~)v3_y6SHTOk4H;0S2I@hv(W6agF$ zJ;5|%;&Q#*e5n9f##YVhT~GYkA6qkXBSuGqG)%L}Z<@j2ok!p{iZ@fQXh^UAQ|f+| z)0OdC>ka3&gHoXRoWKG=E0vH)Q0Mju(apOmlzCA(o6h3?`=GlG;|F?*__hemGJ(&4 znSu^%A2GjVpBOcjz>)7J=rGI!KY)@IZVWmdt;|r+x47Z3$Lti3Qja=1VCR|Qu7bCv zk2F57J3WBCtJ%E%2c-_zGA$NzF-KK(?6V=X*Y(KqpUPBZS8_?Oqs z|DzIM4p0BWpL0Urh)Oq_==@pmxI}+Hnre3s-B3@dgsF9DUOCt=FarV!p921*#&O7~ z5!lHnasGoc`O?(Cc;bywlK``4&}qA`Dw{z2#Q*IQywg1|DjdK{sZZaBCs}C4^+0P` z07;L1s(*!^&u(l*Jy9bw2-dF|>f7n~#`Z}+qcl@Iqv(u=1<~_WVyj;gLSi!0aP{e4 z`_2^ANN>wLVfaqEU9oOp%!S?&0|UeIzi;x~N|%d|jS7yeU(H+|-7EvxxEjuZ<%wPi ztOL2|=~x?aT9P_(-CJK?3G(?*ce-zsbb`UL&c^O3%8<^of}f;c&L(UXg5^V%A=5M>jc2`{#V zKc+=W3>5ujg}K%YA?f)jj^9#FOeom(N+g+1m)jeJv*YwY6?KJ_iO%mA8VWL@-*DV@ z8`3&Pf2F_HHEH}=_X{s&!3lQa5k{M+=zG%3_`Vl$+JRO-n?q9|td@d|#kqG-f);Lk z5I{0T3fTQvC>Kob9PmSGHKz`)n{@K;}A!wL}gs(8X^Ln zKZnYly%@5*>MP|wk0HiAHwvM2DB~g|9nZG~9lwPbE9zuCEbgYCdb3WtIG`iADu1n*fR<9d8d=`rV$eS1nGRt>s&|E-76d|f;70H;NX8CBaRmAy!>do{xSzl^ zC@TNE;|K!QFj~u+%=xAFUl~J%ASnaCT>CF;lC-x%rYF4RL#1FAmTDn@+=4CV{iF^< zlEl*7UErBAUdpbVmm0yx_R$woNJC+Yr4=3Xq`tU0qMwi+0+k`ao;B+KcyN>E~}&v56bZuSF+1NXp^ZoFiZQRYHKyl;`ulJX%8bflMV|i;nBQL{{h5 z_Xx4aWTz46rIXDRhXX4sOLYmrzgMak={Mj2(?akLY%UTl=0hj}I3~cE`Pz96OnzuZ z9SzlQyMaG$z!~hficQk6dnT^gPI5AG6~@FhHoB*!SY6kFUbqN7(KAS4sf#qhi9$2qeBG;}0P3s%2G+TKbi)7xujuHZwc%3UdC!;yF@03v=`G z!Z7)oKu;;4=C9xLjokdViTmfh&r)c>bL#sX$99;`Jl0E|FDtl& zJ0f4c56>Ck@P8%3E=i(0VE2^{R!0>+Ffb1f1IUF4e($5&cTv&rH~7Qd;8jm5 z`DPU$5WqB=YJNk6VkPE%0cS!rkTi?BvzW;ry%-_WUMnBxp2-SRzHjg#%>4*V<%v=k zH`TgX;^Nmw_tG;1fJoIKeL-QLSZ7w>Y6nvR&*6%#8J0|6L)%}=n4r=j_IMn1Y>qw4 zwD`y*TstC13`|U*AFSNm8RE_XqhdO#?paaW3+4uXCq4i$2xJE7NY6GKTmIFVChr=4DZ~fDJ9n4QD>s|(bE*zWZc`2O&r8DwbP22cmwr(j5V*%i zM|}P`)n(~1ImRI_c+Rrw9>QAs?|rWlPM_|yK}7wJ0U2_Rw7Z!u`d?1YuG-V=QT~nE zxb1*2RKgaElMFgM*iNmAOu8yFzz$~2^m&)|pFl%q-w1ol5S}AMo-xYrVB}q>q}~Iy z1EPxiBs+~oy>i0%3f~45NR28g(;VBNN`%c~!3Hm~FxXsLL=5T#H$hl21)|NU;RAcK z$R)Qyb0HIY!LGQRtZussWU!|z8#2)Z8P~x_K2gOB;MT%H>W`xwF^Jfm5Yr=e89nlI)o-d4J zgDBL4!GG)z46B!7g9HKT9XCbqV)R@J0(moHF}FwESTMxO)tAFeo|+Yzv=jJr_20jL zU(?KdpTa?z)GIMM6eM?z+}hkMyZVC1jHQD)iO&Nl^PM7TgDoW?rJN923fu6bJ=Mvh z;_+K)JIzYeJ=UQAJ{NpRsIN1kLe3p?I*Zz9B{+}3(ca*U-W!TwqUlYGly>fp(b?MB8gy;}PJFZd$*Ig&N)Y|ra!4nhCRPvjEwEauW0}dQja}banFs`s{D-soB>4-Hs?eoLe^)DKS|XxZ_q`hMn9eG1HWXm8Je6$OP+lyh}!guTDoBk$tzF`H-(o{r@_4OGQPzAP~QfY!FttF>se<=z;Ec zDK$Ev2}{cgUli|T79NvQ8t^bhB9Y*bh)iU5D%!x*x}w!`nFf88bl0@Qa)j5tO?MZb z&2qVeeV5Qfq9{FC3}3Z3e^&(fnupS9J{`E5ttYSjLDfs!-VULl2C&KYf|D(VN8F0sc)o1YUn3qm?xPH||{!G_H#>X1NaCIxyygH3!N{$$v)>sL1!Q>9VpNVQt~e7TRJj z6UWadpwjg8Z6)tKUHE`*yu;fv#y7Qpu6$i5_P@>xk%>3j$tOySTiqL<#`aSuq}Z+` z6a8c{1Uo|3-uUbZ)fC$f$HE#aG@2}N+k!*LcAnqfEoo_2DA_k`Cq4;{Jye?z4d#=K~@EtaYfA%%4N+9pK=LV^73!}dbxh1?*N<~ z4NMdv+@>ASnv&+v5PkHMpO-$a5xMho>N~Um+9Ruc#_;PEZTY$rn z3H&&Edv9o7Q5q=;9HBn}CtnRg(VmHALM5-bE>q*+`g}V_hUH<fn5%HFL&WE8C=dBF0bhtZLQF4(+4 zUbuSDnk6`eOuWo0zuzLRe_=ixZV12WW$vqnXod^kj2}xfVR5-L+*dX-V650i-R*)C z92#QWN8gG0n`U>ccwBEJBVd6VRPM1D7`-A0Qt1XF&pu?97+-pzig_-^=*_tyjBDVv z^VljJ;{fR5(KdU(sN0ue^Mk!G!ao-1oZKN`Zon4(1(FF`8F0HDYzrh7JP4EVi20-&p=jt*X^6(|Q~Zw&fU89$?*!taaAKp_ij zB{TV^kul4uV7Qr%6wMYG#T>}Gh-eS>UUP%tbbGid$JoT_nHd?(&)U()0aookgXVx8%4tVdh~g2p zb~h(s%2Ds|QA{!gbQF+L`zfjCTMM=RXV)ju{MvCa-*NZRr@`lTDbbFocQLI<2S>#*Wrfv07bg3?}G#!D_^uf zB(<|4aZ&J6s&JND?S)_i!b+zWjDaz}xAFF%0l|uxp2I`e>iE4-0`rUQeF^M2sC6$8 zUHKvu-O(}MHAYiW@uJX&u@Z5bmWsbBfI4O}{!lRSec8@B#!)x!VIU&GX#0-~50m4DWu^{~dftsfn^B(`0!tK?akjALxSsv13_LK~UkZjO`-EOVW)l|_Q zrP)J48&R_V79C`pntHbqpM#xF2L-GNU%)TU-T3SK_<{lm9gxB_aD-lu9fA*Y*(107 zgQbR#H9;3{_GSiFgV?lBF@HaV$<=r=8_dHgkK5o2fiK#jFR4h(wv-R|Q--dlWcjypk)i;a7mr1uQmrJ>mPo z^q&>e3*AN;3Q3;!IvINY5$X#Ul-XV&0LBKVKS@k?Zy2aliHEXMN>GI7<+j5tWbcX0 zy1dkLN67srJEAXu(n${x!&n*9$COAlv4}s-F5iH-Byxr82xahA-Xau3KJLsN=w+V@ zjMV`g+~eWneGAax1q=e$GwsXL23MHb)th&DUIGH3E^%A?t(Bh z4HbSawt}~SS*Y|P0FRA~90B!O|GhAA9l(IYbH+=^rRRg3SH$%Emz2w9o<&RyE}nM+ z8N7#stBM$$(o8(=#ra3Lq4T+-Wme2PQrxLnKoW;C#B$c5cwu_A#7PkXS!w?QXcJ|K z$WBBgFc}9|u1IO=wR;U9exgHNL>rrRV+=oU4cRk9J8&eERG+X!tG(Ea>mHA@TRjr7 zQMK0#=~IJJl2YMBHRX5F=NNYgx!6w`=SDyv=R1>iI)DFL4mMGsyFZj090%7R1~ztU zu^IMow}}s}TE*2GGnSL-v06Yr-nH!o=t7btbl@CR0mo)=$^w|;tJ8TFWH~;K zAduOLph1dwZfVjn1qEw>BTJC_uEdfC!tc{r5le z2=CuDzYpo8FO&SrMctUyX5A>L-6^iNXH;LC&fV9+jJm7~HL$Q~`c9ZN@S6dQo&)^2 zce*?zVsT3Pt4kOZZT+7Z3TMfA4-ze{s`&K}?NY=KQvnU-10+5}XP&v4r{_u3qX&DA z|H(Se_TQp15})YZ0=p?(rP4c*1cSLQWsKZ=RLB#b4g-mHYEL8P0J~2f0THb*VEY!0 zy7Ju0ed#Y9N;@2C6+J;1G69|D_j?e<92dphqHCeXBmIqt;}0n#bULuZVSyhQOstMxU?nM-;S`6Xm-M(o_3(z3 z2|FrU6i7x;Z?;nN)5(FxDt zCKPNOL<`42Sfjl@{DuBM*csXujI=6wr*Pfxf4l?ULLHrujXIhK?eOLaio0fmLg=(z zhqeicy>XcY{#&P%M|-$1ma@v@&haj2T9$n9_^)Z9XhkVJ2@d+NIj}Jgw_V0G5&A5s z4ca0xR_m4+4=v1{LSo`kqCo3XTV(KgG?>4Nol zifv02PqIE4%pDqveg4y`xa8_ZmDwK#%{Wk1SsTI_mSW;D^E2nt+I|<7Q&T>m7{h|V zMpmcH&*z0{8e90(cH?^G`P1O!1d$=hrDFhO%65+agT1OGw37=couh|E0~XE=IkN5$ z`cw}e$b&6=9!@fsjnhY$$C>a3q;ZfCZl$f=Eb6 zN#Qdy5%-bnRum{g1B5F1OTvq-5$s}iKnV#R{<7HWbpVJ}nf)kG$`qYigh$zs$q$xd zhz4@fcEx@;RF=g-7naspk6xge9+XTlqC?;BBoq??v`$P~#D5|hl<*k>ZP(INoe zF~?Pq93o9HJLzgv$)w9BYXjP@Ep2&D7O3S5xsP3BORmeIjiCOkDay%X3%vP6<{2}{ z(Prm&#ZC~aJ^4O8Z5~kgm2QgTX*xIf2kZirwj$EJ2bh2vo?cA&t1-ikwR2IM&mw!; zViko``vPaM+4k1bl4@K)Y#&u?!L4EDT(d5;olKYR@P_KbDpHi}zqBt+M;t z=PMpxBB3aONB4*R#s~n%(+Lj;YqI>|AQu6ye4l5L7CRJLkYV&@zn%U>N zo`X!5>9d*zmhXo*a9Hj*6lh`nIs@F%MJ`aWv44 zG}!DEeVH}De5Gb@fJ6K!w#cW{a2%TyhzP_)j>-7&Qw0NbdS?NMWaa030)rwDx6vU2 zaOmp`&cpQ47BSG6OjGrSCcvWys(1rGel!~n3!8sKzGaStf}VTe77S+GMHbr(A8@4= z^AJ_)1n?4cA^kjuvm^T=W4Ea$t;my*wT(uaj*=i>9$+mZ%&R z0{o-99BV=xYn5m@O3z@y4+WM{%g)q5jiE55ZbR*lYNU1WhPZ&^?~*f+pac_-6p&ks z2PE=~XtTA_>IsY2`-MSyz0Iv%v{39n9o5mv$^w&oi~keC5e;{#Q6QbHaK8C_l%M+T z9Q{~XRz>j-LgcH}>av3G$%5KR4LDS9y_t{?51_{{ZzGUy+Y7`+q4XOEZEoQ5tOcu- zF0>WE$UdMC0vuXhga+YQj2||PS%8G2Jy1jLkabGN)0GIY$ac^E7JV%xb#gxHZI~Gw zcRJi60SU1Q`tRg%gMB|@{N-ljlOtp8?ZL!MA}yv~(A(eS`G@=x%kn=l9X>UeGA0z- zgESw1{C!X&vI(LjY!j!ON`~Z=G8dL97-FU(jXI9o*9x$5=m|`ErByG;mm|{x8HE zX7Qa1>Lnik6vq)D$#TGM5(|B0wNz1d&+Qi8o7yrLfj9t}tEQF%nEfJci$|MMu`w^@l9afXRmP|2gs1TPYca!n5>EOz!igPveW+$1oU9|6@5$(Zz zFVtvs2p>oFUnctzFx890us%WXMv5Q31`UNX|2P&pWKc)u3BEqVsld`2+;sI z7Z-?bQ7%{FtLiZW3GMM%vM$Dv%k9d9?YH{K0GEc+#rFy~BuO?-9|=TD_$A0GwLHC)6f)mG ze`QbR41|o2SOYh1*@7>tuj1Xpp%asnO+X&e{}L#HUk?Ln74}&JjP0o_BcU!nD`$Q- zSU}(Y2*ELqYwr$ua_m0x?&Hc~HdvWhh50j8?Qrkmf-ew=(RaEfxsan`3;!90I9PLY zGcbow0&y+`mVI~}6Y^IV_2|H*bOW`Jv9iW8+%)8Yy5CuWg71JR6pDHDMi&dGWAL|& zkBqTBY@u5N_6)T1tV$c7l>WPG0nl%*Q+jno7jSR-`Q2uu@g2zV${fh=p-O$ph6Au6 z%mFwQ`8hB!u$^6=90gmHMnS-Fy1LRLmxpJ6sb+DpX*}LB^PxY!?)0u{_kjQ4VC^_lCaj>2d;jkVl(*t=X4em^i zBl$YRQT9y1cU&lsldb+D3sbm_xucKGUXO`Y%}NDLM4Fy;RGvB$B%ID&iue7CxzB_)l%Y_d%-0o6|baFpacsBiW6NhGPUp z`Y4Q?JvYRR*4DJXHsIM?q8-%_p!4QF?-)q7PNU;EuuF6w!=`*c{+1)~I=!E~NQUXu z4#cCoLqp{Hr)_*p!w$RI-Q+npZlinqrMuOa%NhcQ7OumY5_`0xEVjcH&cfqkzXyq* zAML+{#wQHMD<~SnW(_S*Hd`i31a8j0<|NL4%F4QO{iFWnJH7*upxzCSnw&&U8~djd z;>Zy+I-H&imZ?O^S)VC)3R_DuFp4xz*|Su6E^g^=Ic!LmcVq?^?%v<=Us z!WiFom;r_7#svls@&?O^r1gGL)e#rh4Oa^Z_dMlJxW03ktp5;da760#o`sUIy)234 z16^&_ljY^>aH3pK`+>CeG=}&DJlAH{PmFO19cAIw_y?Y^UxQ&kFz{6?fBt6U5=MGq z-{^Ten0E9*gPn^Z4qsVK7CwjI?cJaVTp@hC_kW}^CrHJvW|54?6iFPC{ypwhZ5rAl zoI_98E!;4~zi04%t)XD5o2noU_(OCophWQ7=x!_iN0RKfCXHzsPBbPi4l` z4Zu=;UYQHR^zGIrKfWNFG66=j+ciBMX|k z8RGHn(pG)Sd%e+pg7oXq{0-b zV;xq(l?Inkb=_7uka8Yc6D5Qdu}}?Fz?E@TuLGvio<9YBr42UJ>-G@^C~;xBpWJ+z zxLG#pyIOAv_#X;`{_Vc@u`1iom6?xzh{;n*so2n|W06qxGg zVe}MOS~X2gX_Et{)x`{o5(YGkpA+xQqO}hvYx!Jkd-hn%`4eX5`_u1%HTU66_Ex+W zUEkbn-3R`RS=D9JIJXLuN7~&&Q*lCD zDn93(jTW1e4jLE6n#l6Cil{0=vkH2B6%^c0YBs2~yPIt|2_qO?O&Y^iW%`YA4f0ck zO=HdF4)fX=^6+VC1%sZkV^A+)y7#>Mk`wW{7(YdE7ScSvKA!xN@r1(8bOW`|J39k? z7;9FDML^)QW^%s|WBFFK}@ z!YX)n9GW{~@Rz2@TjO=@IEydhp6P6}{du**H@*Q*1sUy!Z+>LbNCbFt-U~B6@gM^z z?;neNLKKm{$Z%LI?F+U{9>>jgRZm$8;PN7C(vTaTro6C^WeGGAZ?=uXFD_==&Szf3 zeDu)YFWxwRsVzXcZ&R0DvbNJkFb)0PY_&EwFW`Qx zV)!Lo{PU=;GbN@wKDszpYBu)V_!~m>3VKv<-xGa)3B6osuG^i1P5S&FPha5|Rrh_Z zBAwEm1B`SdQaa=a$VhjCNOy<800Pnt0uBn&-Q6uANOyO)#P81YeLwF%aL>Kxp0oE} z>+G|Z(sIY4`9BRI8{5K#Y3j8vq28VzA1gUjv{Z?|1mETO{pvGC=NKOow9bx|OI2mU zFEI(m32t;+G(6fuuz3uA2Gzw__=}-J7VX%8&*pYXW=iOXN{Wz2c)B<_8dzU&xISZ$ zj5;KzgkB3U+sjos%yHK?AOA}a4uR0$+rE^rW|R$kE~d`lZ(3($E>l;?)*-sP((?{a zH8(CnVY1pOg)i~vvBtN~1b*lM`uI(QP?%7F=h>cvDamAwyolBQE-Y2SNZ-~8Ey_-nW6?pNPm zN|QzB=M(9RnLHc7SCo;qO_ZZKQ(L>6=U@@DIzEnim>ITr0^i;rKQOOtOK7FNX^ipgySSy>(T$uINnm@t?1^x4x><9AE=V%URqQrxa6+@+8iI}wWjMENx_)4^TPP4IwVM(B z4txD5<>@??|7T3zWGejDnG_A)gzvW0uJ&AfK|2J-l1!MYqRT{vt|6FF388PwYZNSZ zViT{w7vC7CX(1l!{AwDN#F{)IB8xd~F}-!H?t8eoNp9Y4raWNe>r$2PwCjdX)|n%2 zOZ`JnbSB>E>PGy^{$S%^!}(vx#+?{nf)@s1-aFHUc!} zw=?@X{ijZ9Z`McO9d3wJ<$h{v4#AgdD0sE{a+Qd%C65HNNz`SASHPNYHI=$yh~tkc zaAMd{Ke5v8Eh1*&A+{PL&9N?p=rC(?Z%Ur})1?=(Jti1SJ^T`HLkWC_xFC_qea98$ zTJ!zdnD2DmBhJVp#`e%x%Ja<;;vIhUGH10~th(*Xw;vf5MaGjD4Ue_^@`zKKeEvWQ zhsauvgFWz2kcTqeB$_eO?yg)-OPHQg$Ey#qVU0R#&3A{J-nW`SSC(j5!zXXKg^=9o zH@*q(qL+l=*8wJC-1Ql z0_W4_Y;`f<(P!-ZxB&J}`Pprd4swwZ%hW|N(RhxVmCIoq7q_05Fx0e+BJzjLK`{;x zThI~CmG^HmSZMuZv^b}DIFdiPL z=MQ_uLKVtxOb}W2k>tDaJAK?fT z8EhVUAFt^^FUo$8pT2QTp*wAV0lmgy+C8htp=C8n3#s_7lvEsU?&m94->G^}+usrK zoLW|6J zovTxCiE{V=mOE>`uEn@Emb>HKU}q*6PCX25c_&3U?hE#QBgh4_&`(KlT5Rcz1PrVI(*N%?apMpuW@iTxM%{jtZVHW zw-ZJ-A^ijM!`hfo;;hfIo3eF?flEWfuri^9s$6?p{Xq1IXoxIV$tO-(a6Cy%Rmr?~ zo*KbIoiXPC)v$V|M;uH(^(J@a2Mt5!#z6&-B`&zQb$a zg%j(jQc6$#z2acR8-UxaidZkQLh!gd>4gS-+bY{w zEKQ46U|7$^tFD>e*)0dNaZ6RM7shi&pbE-;NbJ}9OAGiGO~E?thGa^6e?|r8=;=L17OK;3Pl2 z`HYS+fkmpENvG0Z)8(GMxtzcq%agr#g@#)XR)-Y^@WN|!b}`V0Rc9EF!(xk%gOo#q z-lmZ&PcI}jjRW7Dc1v2ej*vn|tl|fqInI`?oF^}o$DK>}YdqS6#_8YX6TZ;a%$l@< zr@S44^cDyfvE~U4jf5>!6m04U(ED$%UW`y6Ljd5u-P#&E7U?RP(8tY8s3dL)qPUmlv4+9G z=ScjYiGtktK7gSrC=3$qO1bCf_iu7c$>|m2^Blog$7n3BDh|0RHJQ;4o)H6=*JrzK z1vNEk^r@`w_}Lbu;1J&sU%dKPlDmT$u%6^%#85N4!n{Ik37hf}#XDo%H{bkuY@dqz z;%ol$f1?=gD%tFE(x8!mo5`)1w~p)^I-&mWj1-U+2VIt0b!Fp6Gz&o!ygfs!o}c#X zPCNRXde7z8ZFl_&zN-HHm`!wK2VL!(B_$r}kl|9@y^4t#`$C2oBJ|Rg(}FRE;N2DR^pzs9B`h`$XjWR=79!u5PJWTLh0<+W3zqz|S7$~F41gSpz?r+t?I z>|VOt6i&eS#Ex+MDYc{+>2gzUD0s~-JC&M*W5G%1NpOhMW;T&wvA-D?S%y%8 z7U)Ct)tV}U&sm?Az&0~kP!27ePhpkwU>w9(Q_@`L|9qpt!PwrGf|qbg;CAapm)P_} zV`!luvpK$Idcm&nx;HeUckEs2fpOA3;qyg;^Z`4R88JY3Tsg=643*5H%`3}qUch~T^RY|(xC z1Z^{WOLo$PFQ%5I%QB1SU!v61zx2M|ymN3BaK+awgiNQA3j8ixGwaY?oD_&VPI+yG zmMPLUsvZmiJiqf_J<+BCpqsk73?VDJ=BXF@%Eb?B`3|+eLt&;Cz&ptQ2qc3Shs!QC zl4TrzQfk`nijAa?^AvRT|MgbUrGV=^K4N&4W6=E45zO=r>qOO?w}GgL&9&0m4;ouIITuETk6mIxIn8S zU{NO#JtZ7*NGHpUjui`4C(K-szH3^u?5naQ%p@rkz zyo8;RiQsg8h#zwj`G2mPUr=IlfTAoEIKB;g;d2aP2z3Fqi~i&g+@Cg(no67i2^4%! z`GM*Z3~DG~0+XlA0(~d~(p)-$JHG*fOYaW>BN=K`;w%w1#*OPo6A)M7i6g<;o4H05 z6G|U19lDa?yF*PAP*jnv?2IC2Pz{t&c-}#Z`ZEXc)yH1VAjc(-qX`pq;|`keKdE%B zLnSO}pFh2;{icFqj|bz)C&_Fva`yIoQEz!nl|>cBkN^!On;?maAk6A?AArT=lS~q$ zeTmi5HzK8A%fUFWlX?yGLiXKEs7(T50f$V@tE!b_`)J=^C#Q8 zyJF zuOk?{BL2y(C*pN94(le5VrPsaSJ3$UqSNcynZPt?eA%zuuX@rp2jlt3R^I(QU=^oj zzeytmIv|TI}Ey_`o(`hm^N> zH@U6IV!V6o{5x}g{-;Gf5=>QFR#=b#3JD1T7J&k=2qYiYB;(+w+v9kA@EF}Z`9Swj z4D(zUfk;qOZd9PQ&&gLVqS3$6=b9ECVAU;QKF-)3Z12AAa7%LYBs=5jtr+ZXae5X* zTy0Wb!XrAJu!?}KCd*Rr08&Q+;5mWY8J`y#-Q&A9&Hwgu_z-a8dEwG%4<+1L$G{Q! zVDdT)JKIubG6|&{2Y+Tr>N-*CA;A6>6>>=hw9Aaz10FLb^Z1%;XKZJEQGN+ZeA&PL zl{6lPqr{K^8#QVzrmJ&qO1W|9ZQn;#ka6DbL?-4fF4Ia35h@B$>I_k8&9ewS9AUNW zyyextQZGyf`HqQo7@8LeL)?5mK0R)U4w_;U z{d<)odC~ASPk35D#3n-U_j-p)H9w*&D z<9$@tR}&WN;dDihg~pXj=EBKD7Q$$-6ULa}$jVm@&@lkxA;Zw#eg0qc_BdbqZ5?FX z%OD$g^y|Bg#S4SKOK%AQvqHcFUWWSfS0H@Vt%Oj?n<$z0?+;SL0WuBrLIBr>;^XYA z#nx&v;9txPdd;CSXS1(%AD({2GT%)WNVpk-74=vX1i8B<>s)US`-ii}95IB!$MLquh#spKh5e#X@G+*k z-a$=#e8lkHScCwbb_YujoX~5IwR7Gf=HRVkpmG2qUJj(%5^-Fygzz0{XOD|v)L+8C zKUZVO-2b}n2|nv@*Xo+=>+Tj;;8(_lL>-02f~z=vRDLO1dJ;gI{5+TjEZkNWwyt8} z1qDmjJ;K0_GXi$pWU(&PME74k_aCV~)lhkee5D_PK2D^<1^tM?&&VUu0hK?T0KbIm z_Z)1~6eTej!0aX4)^hC}iN^pb)g@0XdZ}ngA=XTMDUz3J27fw89|rjCap1i{13qKA zMv3rl){)Pe8g8J<8un!>NPn%$ySG?@(gosiA0jy5Qa^-J`0k7+;l|S6+!6o)yX}eK zL}ubsII#)n-HCceJ*ulr6}e#iR|j2h8YqWh3ot>s!F*4?y><-;6=0)4OB@M=l0$NB zt3uMUW4er_Pz%gI1q%aU8sn{d30Qkw(QGR&gb&ztD^rPGO95ZfiD4iG_9ioZc3#4b z>bn|8^6o6?C)gUViaJiK@dI@s%)I9mjjXf4IAQ=+eU=yF0mPCT}> zan+f_1bM|iqVXG>$RrnFxYIi7%6agb#?mN|4fr_tqO#^5n(gM6SA(OO$xh*);$pc_ zJHLM-WODqZOl8FaHRf1n3bQV$XTf{3iR`L84wWQ^^i}E@io)|hoe?)rhJu8^Yu8+zSfSzp?vnmrN@fNee*T-*uhWv+x6LZ<8jQ7)y)s*{{SDM z;$d!x4oyf%0P4!tFq9YuATqHkXM)091!JV%4))kUT4EJ;!LX8-*z^6%_m{DvG&j@#68J z_0gXCGY+Qt6EGK7=2bZg+@5CPC)P^K6a4#-w}jmWRDYlG_x`KBRI*hze=k7B39y3` zo(_S%tp;*!C4$XMekJR?!~VeIOt|R#@H&o1>FnRqqaXEWW_ZU>ptl%A#fi;<$psg$7r=Q+zn+S>Pzg9$79ljHMu7b zn4~j8P|NT@l>mxuqDFKZeI~L{tH22Ifs{|T{@eZ4=9pLP6#D9!bHd*O9y#gP5Aowh zNrr~A9%Ol(iwaRu`Q1+}EODXdmzO9JhzkJ-^;_xwk{BnKeU5UJL7LHN|2bL26w?U2<%LAT8b_A!X{00#Yy1R~mom9RV zAd0>(=<38vd%+C>kEevdHXqb;4ntcx^}RQiEo<)N0#e2-GH}hmH*OrvG@pGs3@OWQ zlOuGWca)?4oP!0V2*4qk^(Xf?M7}*OMf%b%nsLVk`Y_YHD4Qa)&sv{s0@jdL){^9E zC5{uX&gSn1*k%a{b0A?kzeH>Rk5MXU(`|1-8 zC=l%ci3=zp%Eg#xsU5*2DXM(-XpILpDpB+WPtP-p8g3eD+*y`-@~EG$l4p{JVVgBk zW#6Tna$|4u!Enr=TJeS`?w3@KG)@yF=pQ)Gh+14-;&a(RCrb}={t+l;AYg6)Q)|#6 z)ltUPF4~Hg0twV3GRzl542kJ#UK0nCq^tmtUSM5o-9&%dQ&h?p!SnFq25B9w;t@EC_(o7E{mpP3f~?i z%V?Q;9akYS1v*73Oa~|;(nZll1wz{BEkHh3oBFd1kgLgQX<5R8tdDJVV~#UVXyah; zWqsla;$RS$!Bn_Pz|3jy%0%0T)To&I`V}o8V`lJ&B+I>S6$GYD~G_9Bq+Za&P;>Fm9|q6M$4VFO29u0p!xY z!G~y-0PTdq1XQtg6YWtw53WkVzlfoY$l&$tiKA~4NrJ#Az_z59W!zVk6r@w;KCur5 zMsYZ+u!@_mb2O#?+>HYuS)gqSYNGwqVMT!o&JZm_*c}z=`!nYgi1&|L*z159k{XQ= zpY`lTdmjsMk_ci*<^pv+TWtGx2>{Oi{bVQc7=R^_W9q9*eDPnvCTj68l8(AnQ@;m9 z!bs7L#(?0oySE2jZBVQF45_PNR3v;l-X`&9%r#C+Upo+Z{04Byp&sn#^kI!(LY!DZ z9Xw8);tzJt6O!iw5|;-TnMFpe{UIY{WT!sMpn&5Tp|ji(iPj7{8I{8CCPV*EX~1_+ z_teH;VM@hmiMB(Wol3srkAMxcFA!b40s#-1HCx$R;kW=+ebu=qr@B**OUb#ce9B*PJ6xk+~T73gk+4T9$Ybjf2GM~ z0p`~@WG1sV&C$L;gLs$$Hz+UyU>1<>i}ODybGJYSWM1_3!-oM*u z6$T$DhzJg~$KDWz`(TqRb3-MuC2>Nn0`mV@?}AS1M|`<5C6E-H-~FDUbsCHRUjvC( zX&o}S9f%ODxZ`cFOnc_RCfc}BVpN%D&h*JUMd2~nttH=f6@-#S{0$I8b4=|EMWM zA(l`Ahyng4whd6J(HE&dhSn<%NKw2u(;%H)H<5CV`dS$3P?gWe(Az64V3`JL2hjEp zH6tuv$Hy-*S0xP(%}2i6nJmaJC@3h9U)?Mpp5U?~SS-&GWe92uQHjAp$QvEH_Vm9> zJGD|4*g)X0@*SX()=y6wr1Q73!hNeZ0Az$=-V~J^`@HjB8i3u!e6>4nv*{r$KdT%*40cx>~0O9M=pqF`sBA;X0uBQ~Wk5ej3m9FFUoxWRF9 zbWl=_x{o6eN+gbf|FHHEuMzv z;@1aGp1(CoB(Yt;g_o$&fu$hN30#jCf=UOqOmLYIELJ%dkMLQx$U`IBsjBrF&VRCF zLG^?i(EdJi9$8?g>c|ye3#N*bLajEjMoY)8=ltJeU zbU4q74U=V>c1r7Xd)S>!@@cZmm?4?Cs|$`fifT^pD0CIu@EY>pkm`4LTaudU>VC#2 z7oAjOElzLy?mNj`s<#Uu5kUzP(`lPoidF-B68YtVksyyJawU@}aGyfUS-s8nzhU)5 zN!n7W%6L5x0P0BaRI!Eni(?>5e#qRwv~v2lR{1l-Kf&L3%3Tj;Uz}%kOuU-cdP@kf zbm1sK-1r%eG~@+McD*BQv3Yw99GBf(Hl{;bOY0eRw$Csbz`rqeE>&}th&OTBp)Trj zPIYYbO=aFQF4}Ah&DjF|uuY<%@@G=6k5IQxw7VTt=XtngkZQEzb@<7OT)8QkR_+Lo zqTm58Pm=LOLIO@z&Eerez0+Xs9R9xd;lQAw--!Bwy1D?0Yxi5bS(*E`;99?Uxb2+e z{f_b)a(BICpp1;`%Ft~ftFw5EbG{(3_r_5DgKV<AbW!qimUWvz3);)(65s|Ea?x-E*Tvzb|#}3|Lsr4pn@OSK!P&efKOHHpI_{U z(whKQ6?trY>!S+|#1y?$+2A(l_uxxA{>^xe z;Tny(0E25(rB#aX*ZYkBCX(YDvdt5O*=o*VW+o07j&?<}iMI$5)@mwsI?9=s@V&_q zKAd4@6-+{KTd1fuforn@lc0o&sP&Q-R2@Y3gTW~*$@Tfo9!apx&ih1z--&$~O`oyP zP7*R-p1k_>+pr^wsG_KQ$naKI7yrC;ONvsWz;mOS)q|A>|7JpN^qknM2)%a1{|OIV z>^d6cVq7yHblvd)|)98wEl0`YtbV~sd4X+&2k9vx0~}C)oI^sTX?!&{2(*z z)6H?YURBpz^u0EMs4&5`;39%Gxu}Zq@oA?wc2Npq?;*81nF+Y?si=}nx4SLxbZp_| zfAZOrA9co=`S6dlvRGS5{%fhg4CzcjUFUAdFZh(vTFCZpbS<^dP^0+UfZ=s~v!#L9 z>uk0GMU>B_bQvSWY#8YZQXog*Hb@V$D+I7am3(lF%j3csay1S-9?Q7*SqrhqeMR8$ zcv;*eu488S+A&A0z{1s6zp4zT`nQTzuwZrDS>DPcLXj}3WK;R%O`kuR(!YQee0q)i|_eA zmlLI^U^))(7hCEhKqlo{$OvM@fV9j4UB~&KDiFf$sR8?h(PRs{?SFUcZX8U?7E;DO?R>-7~kwUV&`4+v`s0G>lG`F6jPYwU8m$%WGoqqMk?)u zPyEd<97vaoYc|GSsb(tl&3((?$!g(~1O6dw#s9TnM|V<1ThC_qbq?;^pWl?M2+{7@ zAnUrEZ$0*M-`^xX>>p3<=Ad{ikZ!J#vrM%H3-oXY_Dx(k@Bku{X=h|NCqFn`f136@ zZDW?$0+_|Ta!~NS>xZ~kes>=KO@$v)bO%&k@;Yva@A-ZjWT;T3J(~cqRbE+R{!T~i zitgoM>TA9L?&ht69!rtmZKswe)}a=I{tRMu4PhW5n`r`M-cMoIt+ivue7H3A46fYA z3#DZ1DjMNB9@WERDH}=uq=qXgKL+$ekFy_Q8Mo10JA`*!;3Q(II-6xh z5h#5WCA?MDFaGOq^!%^j{WrIylf=Bl>}ULVE=9y}*LGYmL-k9SjqOm<4Rj+;;In$o zEPS-!>$8UT-b#m^T_hhNLU^hrC#w5?%d-FN^>)+)T(+`C{)HcDN~eK%T{hc#)}E5q z;Xu>gXgez2Qm`*4rvM6d%x{-4@(wt!GH@}`Ozgj*0YNOKI7A@Dhmi|F9TeL`vipw6o&Mi}<9bxEMKw6xWJBuW{boRlS;$BHc* zc;fx(rc{h?K)fw}`|4s788y{bA)>{u>Na z21zK6u*RxzfXEtvP$t!q$P41u$0vfLDl3|Nst_$=%gTme6nuQ#A-*TqN#$M99Pp%) z*e;}!OIQ4VJqG~4)dDm^7!Z?P7MKI=Rlp9MI#4`%V+iz-M+r>S!aJi7s)Tvr z%RRMnZbc(i*?~w6)saIQ+D`>8IGp_)EJoVJv43K38}hj!^-Icx8Ik$;<~&d8L@0A8 zEZN!P(4R<6tLn-U9sy<(tNq9u4i2a5(75eVDdksp3vZTUd)~d}H?f?pDH)!?I}aWi zrXJ|SoBTUT9KxZba4KTk;&nOSvO@9b{AhT&_^dCIU-{Ah?{_=bh*aa}okK%rqO{{4 ziu|OL{4@Q|fzy3eq%; zy*cwG2s2diadEqnBeN)CT5UHfFnw+R)_S9K8kMIlM;P{sA#YHSPI-C8K6 za3BmVY4-knb1W&Lw}cP8MZscI>DFs<&Lao@q2!K>2fo)X&OX_jx>#NE7x_2YL3}?F zv~}}%H}W_He4;Go@t7PPMWn1(?J9d?FR$X@WT?>PO)=jGmQ}YUky@Iip74WIb6{wq z#MB<6HVeLd!(aD_CvJKeWdcA03WOr>!_nO60{N)}&JU;J>Lsh4FS6S^`VQc6{c0}+ z4%TPYfF~cmi|l(kKkbDNP9@B}2M=e6CZhte5w;54QDP((^qWdk=KTUOydGK!8pJoZ z?3L7?22n+_kqN2S+2Y%E;rk*thQe__XOK9_+e~wH3tn1nJIr7fzE4(q$y#6(=R#K0 zjc3cMK}vO81LL~AI+!xRB$5J!#G9~!0yc=_oHTlmr6=j_faevvFf(EF(NgGnz*5djPX4PRB@WMg zxt^-zD8GOa3w~g+FV3Ni8kO@ee?QPNiK+dsOeHC>h4QKm126j5GV)J;>_ozl^L zj^J9RQ~IUhmV#adsPwSn?YnDpzC&%R$KB5R%Priv>IZQIG%?ItF#vGecCyxs*{!8c zj8f&}<9&2KJjo`cj3{mAQ8T=nKlyQ;TYW2`y$=hi5PpHL#mUx)Z^k64PUMfSIXVjn zizUs zVE?ZgycbxdQ{Fp&ayXE0K=O(j4{~x|!+ff#%7IT z_L0bbqdTD~f!a0-9NVqd`t8+LAd|g7>)l|hBKVm`J#`3^kLy*J5t|KtIEI+y+|<9_ z9o5+zzaW_Gcd69XIZ`}PkSlgN#);0)bXgq-^Y&^C^Nwr9WwxT~hXHBto;?_a7L~Tp zp~E@z>N!jXtQxY|;99Bjv@F*AJ-*=DDjT}6a4tso{Jb7=QGK=m+#X^3M?KMt<{!4% z^$SO@!ceRYx3TGFYU?x*IL+@HC6;S30tW;cKm59|-t%@yBvB@>U`Plk+?twnpL(vx zVG66Qio%>JI@j3~#5ON@F<_bZq)xZ~$*aSPmhV^3jIM7x*3B<6vVp66XOc4`NcoF8 zhm~g|XXj}1Q zc|o3l{h2OpXM8Ua)miQ@hK#1B<|RLJ8v#-Sh`NvZ$y{6XP42$6b2f|vUCoP)?uVnZ z?qt`a2ET*(s!&M6$`*2+jN`+$dJ0YK*Sz3^LJpo_{sdVtO7fmUV~T(MZVdB)OwPwMJ zN|m;4F5CCe)0M>BBOyyc{{;UfqAp6dro+Cd0fBsu(fAjL0tZb{QqX%SHy$Oj?){1i zt`-m$HcG08ap`WU_52jYvQFwk&%>Z9ZB;F>Loo$kYOik}GYiVL0^DEu|&i-GTAT*^<6qmtf<>j#Zm@DYXs zF1+d5Kv9ywFL|LVDFg0si)hKE#q!0KetJ0$St5gN>tZd|e$?y-e&kwWs#VsMjX;4e zvvr>bHSnrk>Nsb6tzrojfWXw5m!IS9aQ?9Jq)y?WiAPA-?169CE5YCIxD$2?U*^Ej z>~?q62C(!iuDdp$>h;|^Na+W{_UCH3vEPV<@_h$d3}MuJ_HExM0_vx5PqQLNo(I(v z@m^o5viaG%V}|lo{n%0avqAWm(`HpGmv`OMcne%&35fc0^~wofxObzlP3cskN%dLi zcUDg#Czkrc7Q1%F;l^}AMGtFZ-8n=`^f-*!c#iGYlgv!^+pGrv(0B| ziwZ5p4zGw<2Kur{Z!@J3_E68G5}MZ-=9ZzV`6-?4l^h=e`kaGyj?=wQ1kd>pBWysR z@bvLHYjb$b;ZU%NW6I<4+esHBh6un61DpmL?8HYZ-d%N-M%5CpT}cu|t!+<;?l zDQfy5nuCA0f%aRRN7=8Ep;E8yNU##WL*O7K93lo=Gst=A6kKxct>5#9 z_yo7?&FL6QxISC5c{kPQHl$ykr0x#{=CXb}J_?)yQlVg*P3|?$L#MyqK)8S<0rFzL zey5g(C>f(0a;rC#rS1vCCg(YHh_AF6JKHd}CzmNo^@f`~SntMqVnShJ7Za+$ujWj6 z+URz`NSsa?M;^tzwJ@%K<4;nA6-ui$9c0g+b4cS{xj`^6x@kqTdnZvjmREtpxKS=C zHXfP^V*!$FJysJ{sO~CPwRN#f)S$<_R6my0aDoh&AE?T>f$*v|eW39=SXhHX=BYz} zs_2h5V3m9|($5uG=54)n{v3mR_d#b7qP;xS3VY%QEoL!brij(m?LHBo=&|5h`y~w^ z6CG%=WSrC~i7BhK@rK-f->au#B7cEl{+;W$xZ5KCf;y1{FLH6)%&%;h%5R&}0&m4C zT%^kOMCfGxAf6_LFegWQ8M7OChu-4t4G^pDmhm6x5nmdM$Rl!0N;U+p3TpZ)J*}|4 z3krv+-y%x=nu@s$n|xcO7}o5)yThqO?IY(1tE_StH%_twF^h z$rvJJ?Jkzv3I!Hmi_?97k8~gycHo{l#~&8|)Kq@=0n)+j+#F{2g_II` z1hdMvXo}0+7e2qx`$65>W%h{SCR;!!=ke%`45MXbfsaspoCA@pX+lttQFbzPk0?|38S+n@s5Yj~S5DCl&hp?_T2r z>}K3+!uV$P)($6CkPO%|=2zG4hp$`JS$4}XAo^{RmkZUCK&37wB;Ng!_{rcie{MUs zSwFH&bDZ_YW3fl1(}lJ#fXzSK1IMcHj+bFNnX2G(k~(YR+e~pU@+BFUqhehlhJ+7C z9xVDB7xH4IB?J?&4QGjZR|5WD>n?-Ip?v*>*yhVr*zv-VRUkbf6b7J9#{U(U;-m?5 z0AhXKTlAQyCvnXFi<~DH@LDRQf!Bfh^K5Az_BO1Z|*-`r2G$-#;iXs*USR`C4R@szH zuV%U~aK7Lk%o{WzXE`jpVqHx!8pJdY+1(vDZ3%m}tdTQ1ZlCD9p_C%8qsr%WjxsBG zKQ3v0fd#DI;VemIunMhc$oI)Or(YmK^EAS+-m9a|+DNCfp43PHcy}#Iiy2jy?M{Bu zm07cKMjPA_D6DjWP!v@kDu;L^eW;&&ZB*^no1LN=yi*HY=9Big>_dF+M7TWo>MK3l z!w}qXV1a<`T5dLr41kY)V`|ETs57r3k%BQv_!mPAk(j5}rrCJ&HJp##`lG;Vk~uK7 z^A_VPi(Wqdfa-a2TDPK_j8fBV^`t>%JriZS3j|yl*nvW1`mR+f1=T>*_Ud?lp9gX5 zA*QVl5CNaB7QLhWp1pW=NyE|49tJTCGR|u`tY4GUywkvaF<@k@YRY3oBokB+Doa?E zew4D`Hu2}nduRj#=dR~6b|$GR=yq=%Up#|FRRJszfXwDbW5B900alG^-&w8@)@Q^N zQ3})4(ZgqUgxQ(dcH@Ar^<%4PZ5gcWCszv4vXc7^%(r!Qx9%V!ZdlRBEW)Ic_g zpiXvdbWSF*z=lxN)ntnJjDDwV!VK?g*it?}wf zC1d;_ToEheEM#^-9m)fpWJ{piKUyf%pp*St-mv^h@0f!A@qHifeDD16#9=gie?Y3d;0NX_UH$pcp`u4Yw`Sc7}}1a zZ<{^o^F;hY%;bXyTn~n(F9^kv0bt<{?H~8t{xn;kD5*~RStCzwijW3e4CScy!k)bd z-RRCRO$jfg2qp@DLm%@OsqEwdNI~pKw{IN2|3Q=)E|)7n zgWQ@qy{4<4+0T-A)owDBZQ4&8Nn+AU*nyJZV{P=l&e=dL{uQ)1mg;C$a* zZgLE7nIS8+11T;t7l=q-5RdgkBsvYmWkNLcqdF%96>4`m%mT@+}>< z@&ib7QXrt+x!EyM{G+(~Y4U)7s%(-{y?$rE*-Hb!ZCMr@%bdQ+_g|6adZI-K=a1r) z9GU74TP9-3V-(34!R>z5Ve$Y|is`iyO9#e{;zq!wQdG;me{#QPP1JEJQqWX9_HHaXuf z_jQud^WKOb0Z6d-AwN_4=C~7IBSHc1Mj87P7 z96(hqi~$NTJVb6#l83p3w=T(8X~s{ryKO-8kj(w)FA8nI;zTzT`mU;WzNEY0Q7zl1=NR z&Hg%K*XlaRGCz^bG%qal4m=e289iFXa9Zu)>|FssQhL!u+w68W>05z=nhWY182kGQ zah@(z%)f|SKE2BZQ1drBS`%`VdP+Q~2Q@otgwe-&W$t9=EG)bCgD<9ux=>Uz(N(JV|Fw z2>4iwzcr~d$NY9f$GQ+)6Cy?A)jU8jAW*Cb%r`b`H0!-z_8Wh`s)}EBD^tSf1mTtf zX~Gsp_zO%y1~1kF^VpHxygNAj1!CmFS^&^7*|nvL|75DQWP9E;jj0b8eC@? zNAP|^xRdT*+s=G}ZC2RQU}yX_s0_>N^)HCsM49v(DrT^l_pLg|%2Gz2sFowE7^9h>_WL)GTDLp6xm&+Pt)qvRU99wkcB zPI0LXDr7uV<*@`xl?Fe8ESU!5yc?f-IGvw!upI2gAydYz9bLq%s1O+*3F0L&R?aCH-MAq{xUXYU3pxxT$xOGgKa>O-Bq zu!5AZEwz$rw|*6Ov5-NtL}Zju;-`wl5@v~AJN&lGVT0B&wZ*D!MIka+LB^%mXGI6p zWn!1prtoZ${cdUYBJq=Wh+*~@r6fG1s5K!RP3D9hIk0oE1CMsB!)tXe8@>ufWyb6I z`MfBp)b}*N1XJ7k+5!w8@JB@zb1&t|$-2n^)IBy2_Xg`#KU*GF3<1M-oSS$JCOK_V+0J5Rz(dLpL*~vm>ZbFr|YX+5Tiw$65~QQkJdvWQZ>W2%8Et zUyq~m-$Oop_z?T|6)@IyyyOiL#F!*9#a!WZ$5u+vkM+MZ8D8OtbS^!mEwo#}!Nhu& zBC_Fk#Xzu4sJid#0i{#Ak&p&qNGYYe zyK@MoyG5kCQ@TV-x&@DAB%sOe zsT5h2=ch|!%gLY|z#mL}+h4W7cMV58_1NKkSx5+yxU-QzlGS1&y8kO_*N{$Jhu;8% zdnP69_3If%mVOUSo7`~^LzA80l8#B_tOep=svFbU!AS&N#|5E7)`!pHKbxZmxl@%l zs9SuV4J-2TZ&9Jo_Yo^oM0tzIH|3mu`Ftz&!Ksx&nd$QPdhRS6{5`>tWJ|pg8RIGv zq>qX*E&W8IQIg5Fihb0}UEv07hWJfa7eu(jZ`kbKqF%EH<<-*hS#qyKmwc%56%+hj z%~-Bp@dvL&4>!!Qk-H0oYRKIuaYzE;9B9GyeR>BDy+RO8@h4W>stm>!f?KvXgL@pB zta-se?k531Q33*0`#xza)@&2sF2P7cI-TsZkBzhe_w%)E_>k+gz14m=G*V619FsB@pINX`-J}lG#XCTd>Pxln$+g;w>c&!QWmA~y0y;MAIT2sW4-UIc zJ%+UB!Y%HyZTXlZc#+tZp->#Vqhp28Jyd3#=N!Mmp8cP4ZM$6Wo@rA+6mi~1S6NG>0Ct?ztH zMEudOlw(kv+(3~fRRg#n{ZWqbXNwWlS>+M*-6A|Bt zf2vsZvh#vJ85=)dZAtWu>MtO%l(7u zdZuPS^+}~lvu1UJ)nfgiNGit_8#0`SOF2|&EJ>97(3*ER)}f&jZP16{bca4Q z)$l|XwD_@9BAK(O;B^5B6~q+j=HTOi<1ylIyeFi)?TQOCH~zgU zhN&*n+)QJ58&5!an`rkoPpHYx#(h9&ghcyQvbU?*!Q9l`K)ehnSYpk@wJRDrL*WGP zynFpFGvr^pEtRN~(aU@%!E8NXOE$q^Uuc#p{VLyR#YCrwqrLq0&4C?WG)OD*`IE%7 z$+lo1^!(gfA0tMV0O0tdDVEbPcT!jO!I0N30so2ClblG%1eC>u(q+WOQMlx9T?qUz z>o_Xx7DM?`*!*k(DjTTAB_(6ETIQB$G6V~! zdPH?m!P+h_ztws`DeC>CURnsV{zO@s5)8j^*tP>q_vfnTdhz-dzQCoQcifkirpL9& z=l|Eqlmwrs;5yhiN-!1j0_&wCa~`P`GZM5Qj1ki3J{PoS4~1$H)m1S#sCCROu|$sL z=OI5T;^vRGHfpa(m<R#5$~w!HsM7b`3_Ac4NLY1M-~ zf3FNR)jJ;;OE}_@bx0>;Y|7jiTF-?&DvXDPVxlNZTr7(T&)tiC`rpYCp{k@j(uSp!uKKPR z(W!OH%Wu9%218#SlNsz)TpGX%uoJeRR9BM7?<&DYSY5Z%lCRTu>0(*0_&Y|<%65Of z!OsVM@K6;E+)-yu9<;#uUL;!V~Ne z4D}(P%A~L+l`ex^Cn!B^Uq1bj1_B?LA89@R6drxAH^PJ`X1e%yI^U&EaQghy59u_{ zI!+zSa&w{%a;hyR%~zC*3Q6a6DkZy z>KpX9dApNpS(}X~!Emp6Y4X07hKdore$cPwm5H{m6_Cbk4OO9m-xt0x2Tf|=@cLd{ zDj%R4TcCS6cg7ELDriB=j~4CgVW?iL0938s&nBMY3*tG&_<%JZ1CY>+1dAs#6y)hNYEsS^}_eVWbKQ zx1#c{TUK$Jzn@NICJxW$na)$BoSof%eL8Uv#*O9Y1-YwOcR_RaO7E!{%we->m=T$5 zed%sUY_;jiSR@$?0~DT#uaA^2z#g)xxb#*ybo~hbSydLSZfe&wjNEr*y$No?I;F&-x>8h-Wk};Z1XLW(9(Umm82 z`=332uU4#{Q`ml%VbW+cH%scZq($l`!xXJs$qi3CMgg(eaQ=g8iC=$KKM#Py8gAqs zM7SDc07ai_;4oB$2)@Ag7kLzeQznA0{$YZw=c~FV3A-rj<@9hNSS~qca4%SAqv8hP zM}9(+rS(&w7V~Lrln_Ps)OX2@fJ9u!;rg`MW4sVAz85)pp77N2h4o(m^RQ)N%Nmnr#q5FnDiEb@+1vbxFqr2a* z1*smNVKcD0-II#%wf912aPFVsH*^r6D7ik$)5%`fA85wqJaK0n=ekd0geewGt zC`Pn&_Ao$P*5lZ>Mn)Zk?l;N`Y`E!5B@jIA>Ld0+Dowe2VL!6~l_IX@aZxaFvDZucyGyJwCCC@APAgzV;= zzU78XSH0z-_}gs6kYuB~`G_`P`ZcTX_6-E14m`66+D6OE`(`PPjoJ?5TcmGdS&B?+ z0e8oC32?X^kUEw%p!q%%l2+)L6?39^$D8$F ztRjpz-p_Fm^Yn>w+v@i-%Lo!ZK1(>SQv7cNL^|$l%H}Zf^s_1dD2^y8=46w-&&>O( zRw}-{`8IFg4ilk)*S!B8caNHny6`KJPyi3V1Wm9%?<~k&3Kg~E zFUUX$cp<0xx3m6ATd`ozL$DzKc}g9DjW8M7b-R_EIf+%-@15_`7R7_y`nS~+Z-CSG ztV(>8=SM81&tYCf{0SJq>FPWv<{3~FP%oOp3(f9sF>&XwZB+!N1E5N_SEE*AI5=Ht zv1ps-1f^6oN`ADq6wJ|r6SrO;qv~ked)%xJ>7jEQh0A-K-+PrqjUY9Xs0MQ@aXZ$g z$nEhBJm7I&6*{uus_LH!CS#}BaLnMk;YThzw6V8s!o8v6YR#gox`oZc%i6j1mq+9A zaRnC(F&Eh@hsNrw*_qP4DKwg+$|`ZDLLIfm5ookts*9K$8wH0kQK4JskXhX+h0Yrh zr%|){e}~+-`HBuIh$s2D0aN7GRopJ0)Diw<&lESUT%N0P=c7JFTqHyRHBg-JU)22X z#reg&%v382r8FkL4OV+j7b8>u>AH}ElxND@}PZf-_e@^#o)4R=LZhJ#3N z`?>VKpT^{G?hysi^*$0zBC*d`cNgb_A)q~zL~t6gcyE!Pj2;LysCchZRs9YP)`zR$ zZSQ|jLMN6;F_g}DRfJ26a^$R_*(g<|!laakizawgD+M&LnL??`4Z-3gWk=hu#;qDu zQ#$l{$go?ovDI|{-Y~?P87BU~k4qV*hA#jElLb82Z26MPL1;sf|H5WYk55Ce+-N^i z^&FnK9@ZcI#m$~YztG%!$BpJ4U_k+>4l2;$?=+O-ffb>P!^WXtw`kl5DMlC%dEc*B z>y}OWX+E7pZ^FNyafNlzH@*Y5ird4!x*FY`rwO@_Ii`DYy5K(1>L5-N3A8W7b*xAr z(i0IAqxEYl8Q!^WWY|k!(eSG=>|CsMxGMMOff7Oyj2bpn0ve^?+LuHDf=+V}bjGlo=@3hf_ z1eDG#fBv4F0+-+=jRF0DCef`ps?bXuSUd1SHCA7w4+Kv~YKiI=cb(rIx~V@K=YK`% zQJ7$IP%a_d>t)%ZQ@)$^95j_1K%SMn7E9oL(s{8;h68KlEk%a!`r#P!GX=uWW8OD?j;Btn^Q5%8l zZ@FA4+J2k?8lc+gl?;zZCmQ@afo&WIk^ITFU;M_Ku9R&r#f|{qLU^?YzbxA32VU+! zydd_1*TxmSz1H{sKXhyPZHMg)rjI`xze&MUdrPuOa>sroph(CAgm zx2VVi&YiaVw8@LpKrYxr_~#bu&^zRo6MsVFYmJUZi=v8Dpz6^=4IP{g3c6`9x#JZ# z<3`I|3Z||flFYbtyUpkgOMU&6CYXH)U3{ZX7qp8hEWRRE8C)djl}9Nca@2nZ=bpd6 z_+}`!n>9+A!1=EM?p{^3Egdy2rQ`)~D%Xp%5r0-I*W;rn4Y{3e_QTO^bPETESXH}< z@=5u8N2QfF1g8sjK)MjThz0*jf+-y|S+n13ik?3$oN}n!beqyk@UHhD!r%g z46W4lYXPDT0=pY9!>{S0oLz$qazM{Jc$ZcG=c`A6^O6G|YCjwf{12#y03BQYbJQQ* z0e=Be8bf?ri&^(SRzln9QVcbV6%Rxx!jul%xMhY&WOY=ELEG9|;)`#5ThoUhNI!Nv z;FbHYsj)5m1G5|(FWmqVxDhEdvzYHjH0zjRvh=ERC(dquRtGn71-ky<%l!lkUFZm$ zOWp0OkAb#$7RaVE6q&BS_2dxd`r!7Ij7X4zO%l+mql=8OBPffn5wMeq>;uzWI>=@!L14fty!dxFgm{>RHJKPmz-)@*r^|F`#)FHgu5Ep zImJ{(ZD-sozHVfn;?3tN8}wB`&;|PmSnnw7z?RV9{<>%RiZ@!9+P)pwLz=p#XYl)E`M9cd} zT@4Xl%IQgQZF%4@jC>6QlpziXj6}0KRj=hdAC1H$CLhK(&ohPlwo`xMMat4A8sWj? z{jg4_IFq3HzuB%tlQmvZebN{Ir^p*%3;nvl*S8f+3v_0sDIJvwPT$No7JF0}Umf$U z0>{=B_~qO}pQQW7YLF{hA@$%sfM62b`^K%xGg)q!F^4i^t&xZ7Yd@-;047*xg`x8- z`!}3|$V*g6cuYhpl@eg?9ox9}vml$tDHJrLv}NXTGlbIb8Lz?1Jw2 zW&T2)wF(i4Su8h;xes~(d+VEJKc}o1GuSgA#D3k(8CQd`@kNgs;3ceK8bkVB6EEc0 zG-L^SNiY+Ket8JeihWWJdbAeCyYya3v@|Cv37oI6EacjE0SW>)k4l>43^)aGaC^S- z(JW1&4C19B;lfLO=s@8>Ly$;s)b7OvydJ_kIy#CQSs7C{+u{JfUow|Geim=al>s;i zcqORS$Uy{TUjKZOv%9}uy_TM<9};!RK^W2r@T-CN5T}dE z7-Ono-AW+O$RA#-U$!TdlK7C)QK6UmS|po5d`>mc%by`_Q*X>F6_)1OiH6Y#fGE_o z1J+Vy9tJ$g4|AWd?!WwkZfU8BgK6m5fYABI>kUQ$ph`{KvtBmb_QX#8vkYg#_h>mu z&(eAo_&gX0U>BE3Fq>f+7Cf4Z7^k<<%ln*!$v9-F2{8k~GgC%y;b++WKI|7E=;1vd zrv%L8bDfXY8CjtQQ4e{Z>!DQQ-JGM~N`4nS%Ead$9K02G28iSohJTE(THyQ}5Usy5 z;L#9>1w%6{j*i2nd-$>qPu1($5aT)`f|m{``nz1wSF|^-a=i8UoruqTjcEE{CQu>vGAq;e&8`feU>j(*Vfl z%CU zlYbt1beXDnN_D%V4-KXzi}~Mi0Eoel%!z!%RW-^_!~ld4OZ3b-d*unwkZCHg!+_NP zOYK$NjGXWYM`jKYrmD^Cha8 zmO$|TbS%A>+d0b90kD_BQ>v4P9vQF*kd9cTYEi|fkEg{Eu*5T30)nAScs;}_R9)uf z3`#Pi0C_Iq`$6&3Zr^QdnUsA&is>TF@v1H08)d*ndt1Jl&cGQ{lxQw`t!a)M@@ zdR6?`FRJ}=6vDZ81!79K4Lwpf6i6Uvy*fS)p^xIjJ$vF|_((fx>N6-Lw`&?x{4s^+ z=HD>U%MEv6#Xr!30G9sg6Fq^DK8sG{q|UI$-iULZe@C_9d-adp7~;C5=+7c?#WTzW zjWcXfuhU!wBX+&BW)H4>+%y(3%s^MyYD83*0V7ez6&~?n-x)A9b;q#59X_|coI|Gh zWa9vhFUNP+HO?}rLHr5GMWoml1h3B}UMIutpRgTNDQqLt%UEkmLJhRU8+6$6s%ej9L(9I-EUFHY~QxLs@`O3*NRlh%v`2NY%1EHs!k{ z_*q#M80V^Iu0IFimV5;3(E6R2^b%a!*n+;1U?S;UF4@oh70!NYc62sxjqYDLYRajL zM04zX#ju$!%US^LyrH3QS(b^6Ag~zi#Tq^A_9@Bd@Z9hmD&l{)=Pr ziX}lNxm>vBgu&;f7>$gnqEEpzP>MH98s_3&C!vQZhX>(^a!r*#H>VhzuoFjaw!pkh zJ8aOO8#X(2+wtK?0>ub=^C(r$zCx@04TgU%Q#TL>nN7#3S`C#ZHH&-pePv@+NF3bm z+ox}?-Mk>pnjJn9W+q5ATd4)8;o(0&FmnxcgYJ%aRl8grtKUz?-3*wCO4Qxu@yHIm z8@ckExWYxxm14=8^tAAYPN;NqL~WNSala5ud>%{)1hUV9p*pTS*?$e#EJ;g~K4JSZ z{Tw{w4wmA*m%EFWfJTgX` zX%G?;lIH{pSfY-U?_7=RCa?NxrYWUydxF=&G?uQ12uXzg4(XgGJvM>tr}OH->T3ut zZxyGvrynfge|l78aB4M3hx3!M{$c+}+d#Ef%5~WL>##Z)HmHVh9{=E+zm%%z{&Trm zKODtE9P82lL^5Lq>Hgwo^)^QX7i2~Djrb3rL(E9@5?7S1=?Q);akB*5E&J+)yw?;Is9(&7624rdpTgWVUt<*p|^gOtF z&B@xEk0^sbkI5yGFb!b+Wc-HU3V8d`J#9c{Q_XY9YK{qc9kvN-lf<=+8%kfZ$C z^*Y`G88?{oM2g9kaFE-!l>XVQ?&wb9-bo0qbT3UE8@@XyvV_G{t!hgThE!HA|y6(SbgNEFjH>A@$@^nS}a4hRW z8#rvVw+Je%v-w2-S9AG^^5!eB{`f`QNb$C{8fyN?K2zQkf$dKHez4?}CKxJ6(6hKk z1%UN5HqqDonUDD{wSv-2o2Oolb|B~M?CzrV+rW6<=T}SMoeA4kIKK1W|AqE|MTu%Q zxG6nR zMb!=BzizdgX9A&(EuCvNJS<%nHcoAyyr@E*>@S)>VfNxiKE`#_1v-*1&s^5@r@qL@ zV8#}VIPNo3rm^2`Y|@~}u@$mKuN&ngPUYD8wjGz6;rTigW@TkHuz2d};A^cd2YX@v ztFLkG>gwL+s@9c0TgK;ccP;p1cS?x&!$DPC+$&1#-ZJzUH*|Gmb!5mLCM1V)kC9#d zEf?h4ydiFH)1&PX+%71Ncr(1f4mOiZrj?d>#KLa>YH;gy$?IFUcHMWrBiUQNgT!M# zeGb!(M3Tb&F5*0irQ0FxX;UfCT5G;$wdsv*Um}4J=tW=q&P2|mg`s>av^?uAS$>H7 zF-{l_%!cYiGQu~i_M5-3IJPD-$o=T~WQSHXrSY9X=e9v6YEg9M->j~itXoRNEw}qL z#@LQdSy3PFhrKrgmKe`|)K3VylIc)Gp2O^V4EcHmv!z8t=DURX&CGn3te33R2|XFS zo$MJPlRD}vS5rD~kscmz+l|eW<2Q|)X2MBjNg>}Pl9FOmp9B`Cy{tOu7YPfLrK`j57;Z6h=HAnXbf~#E5cod-F-K=@}{z$FONDl&W z?(#2I{D96}Sd@g8M45^9V=Ecm`>ZY_vBpM-uK*J0@qt)tDY=+{1 zvbyvN2aL!Wr-24yXHVhC3(+;rX!?|1;ya-t>?8S0w_s#>?Xr=<9H05){ruytNd!ma zw{^_~(n=FKn!V%IO@xSGyHC>M1u7WRsTE%q;xw%*kSN1Qr~;Z9n;<%dib*Qa$(ALM`& z=&ba!L#TCT-O1%MVBjm-jb(9|{4nIOz&UZV!?gN-33P4ul6AXJzzYH9Hsv30toNSs z5yr&pc6+dt^*OA4ZEa0cv3Mqwah1j4YAOYG#;#|uqYS2e(*k%)(xemzFAV1yt;wZOCLeqE1 zyH3foWN{Qof5A6hMA#C@6+H33U`2sIz^Jwf1=1zvc<(jUkWoGcrAs4}RV%z}f+aeYKt*X?UDe_UyGkJ2Sb*xf(SFN>Z`k)B`1n9n_4eTNQ-hwA^9BV8h!l$>(< z$fGxlm9+<%BO*3WK((c;mZ{rypa5ofl3&fE%W)X1ETkA)S@{->d{4Z(^Hm=fu4%Um z11M9V19I2ieG8+G&YZLi##A_4q$TxDs^d-Se{XwpJ@{IAiD>pk3Vy^^!$Cu#%$nZ~ zUhE8Vo;9j%2Lp`g?A4mh_3Ob}1=l*a-#mvgLa z+2{K#(M5J1r|yn`@da73jtZnj;D+*^OGSFAU}P8qv<{ z!_oaK^HF!@x2iA5>OS2B3zhlykgCh`hBDL9MY0JC)H8Y#i&t zQE6^3)m4Ckz7dH_B~ej@$ig1wrYuCU3AD#x+aGsO-}4V1g3Plkd@+uZgNk8(T?EN+JDQW zOUE|MY=wsCj-z z7I7_I_J(kDZ0MG%DT#LE0Og+7R}_>K{Qfii&y46(d5x*=W_aSFF~_XcUvy3UPV_3B z+1$xzn+e#8@QE=t-wP>O{b&n;1QbUVkIMeg)eV;D#(LnW8p&V31K?Rbs=NA>EQyfc zq>-e!?*Z#YpnfsisG=*|yX!CBf=Qvt2#_PG?#YB~H>cgj3|m1;+Fw)W>(lz=11(D3 zlg!0UNAmIUD5Fk0pb_grckUny#>sqGB;<6>y~e3ZxXkc)5^X?lET1$lG6W$ zSyN}C{GEJ~NR5{}ofSa{35=8CM4kEU#}dm)K7=AV$ZV;^^l2#Ckjr~c&Mf&Hmb4s- z@|8x1T-mNNnpVSBx3d2p>>n7WueA1$@1o~V;3=(bS4oBvqpNWo18PMv@v~U79x9cF z_%2R<1(ccg=B{oY2&B60u4q)h>~mzn=@7#O+3Mpti;PaHM#NKF%9l%u*;u#onP1NR zOok*Y2Mp?;(M6JjZ^x7#W^H}YFYZf-IdY=PX}?Oy0h^Ib13M4%;q@=gg-`aLIF1ff zpC&BNb{spI5x*u{M&oHtP5mj8iy`!9F3Z)_lgoY6Oq|tkreu&y8kk=v_BtWkFV|3$ zU#G%dt(+>Jq9POb=gFHMS)axTdKVS*&QMXFC@-Iz_?t@qO}AJp+bB-coQbvw)j7)HU!tVKyYN=t<; z?6W-BVG=~aicIywP``)k>~5YW$Hq=5B7~XFGaqr9TG+8m$ zS2*^xwG5Ob2a1KIxAHq01-hYJpSCywXOxiaO{Na^ZCvjiXN47;R?Q7y`w#9W(LX2@ z>KJ?f*A>wG_L*-B=b%}XnwQXd6Ic6sbzLV)2LH?ECi@)Emyy|AS&C{c$6P_V>gZ|{ zCIm>%arU4cib94t=bPxn2`jr|3pe|c6iMM&;8VKLvR_oU@}H`zEs0|**jU+1JmVw_ zS6M;c|K0ib+&cS}zpYt7t6}WjgWWPg^r$Pd5@k%Nj!TBC#KWyvLH3hDfuVP3PZ5=# zst+*SR6kyH;TZ{(&X|U{6_#uWl)7hzvb^p3f>}CKT1u8nq3HUssNC871j1amri1>y zHs7UEo5d~6!kVb0l(1>}mkY5_bX^7{{OQL%R*{A9jNlTFV&GHgp=Q|9-FEwgilw!$ z)LyhIDk}0klO@gi1)rS!{gTA5b#5$k$I`@Em@IATN5#>Y_O5{7b1IY7=C zP^o$3#C$f|dI2|6lGg4iNt(lpADdHjArvCt!l~F+W61eg;=(y}s*UYwWSjD6?|iaMFvD&57j#ce>pIBeiEw6Q=d{1rHi3n(`2g6O2MVu-<3C zFiCI8Lv%>bOowY!RZ+b`h3=!(?R2ch8Qr^)R8+7&FWbj2A0orr+eCh0yqc^wBk6Xt z3f7l0ATnFz3SX_bN)opo?SJ{oty6BHDV+8(pqkz#dPcmaQda#{f`C5dV||!%$M2<- zlXf%&S<*7@Vns!*2(?h;+nSK&l()q_n|2INsJpCs>pDH*8TIqa`RY5eP4Zy3%UAE1 z*c3ldBRYFAJ+sLQawcOX$;v|u>U8;cP+rXk?Bnhi9rX?BR6lE^kT$B9kDnWR?lH!- zaOzvKf&KI0zosniE(QNyISPO5=E-AKEs9NozAG-s+QsVn+gvT-I%Or#h+pI`oQVW# zDK=pfG|Y>%2sHvR-H)JiMn_7*3X{yCvk(8qNuzgygKVWSq_I7nWRbFbx#pzCC}pg` zM)VGRpvK`ikd%+E6&>bT5xxA}ESa;$eMK^vbiF(%fj$%nNOs4^6+3R8VU{4oL)+@& zCrGQr)ClI&h-$3cOj37uHT#Rkg6lGZhMWu~9zuF|~Z`ke3(+iKLvD zDgCa5C=So4bJw@C)VAr(@bglYT!vPj#M8zKew)k$mA9GAUz!ERZL>=fyhQQQD>bDZ zvV~8l=d28V+e4cBd()tY#RU`FP($pbS!cTmHcQ)p@j_cGYi=+}Peb920EtsUwOinM zn*0EI%G@g&m>nuX^du1y-I<}hhD_l`is8f=QOOXI6M#+rxb(ARf$uiq`P!y%3L zr^NV1)0rNScQ`9{KPGUn6zR>M^|L#(&GHaYooR+k#m#>?ujs^CUFcC-(ti%azM?#G zp#d|WHby)Iagf?-Jya=q-*KM`=Za^ct<31)c?Ezp&&MCqnb;3%{!rRzi}Zf+e@?}t zpha-PK_dFwJ@(GTXCECzJ|quZK5C2{~k-GEz^ zJ_S)(yEri3psb{eFqAvi1XbBoq*P}C3T?`>q83B{)9d}R0njj9)%b$~`;Dk3Gk1zI z>48FA$#g5$rNyzu)^{JiY-kIUw`P6DCHk$rpU|DWsl9Xe3%O7_tAio>B1}#cbcVx= zNtUq$@ssKAKVyc-8W~X_B9_vRZfPUinS7W{obj zkSd-B1I0o|b+R%8NNX0n4ZeMfOt{abhwdKYp?PQCW@n4@go?~mAA|Pob4bW(T0aRm z7ufa!n*kTTBkLc`uVi7Lxrx~qD&icI|857a(?wEjx#@b2YN%?JhxBN?WBuLXQ#^Ar z22p1yXvX6AD(vlD2&DANvQ6d|$zmpq6H{4;aii@#ypb2J_B691W8IsS8TB%n&X>)w zjuRV(SQs}4;Gz#O%1L!qCxkmDqsM87I`aQPZq*PlX2CUD1B+<*j{#CYcyPeCWQ1z&j-29*+bi%sxHF;tB6l-m9C zsae8`GzkhWx`={PXZJFKBE>cY>duynIhmJ^_7uyXXOT7Jstr7Fqk7lXI3K#d*|B(k zG4ye%Kt!4`l3amKZU6pv@;mbqZZ(Zf9Wi@&S}Ps(Kf3V?>CW~wmkNi3C&0%_VvF2Y zb!t$*iJrkR3;3!OfBi8Dn&LGohKYxc%t>4CN>Ux2o;}v*Jf!<0rw4JD^~OJY8lGrO z0X9%<`tw`S=uS=HaWg9d6N&Jyr%=HOv$$Gvi9PsH0HfoFGZj)5LuGvPQ@b$0+wyZl zIHP8Nzq9gTthYKnGj)vJk1r-Zr}u-G&KfB3P`S7;5?Ed}jzNX;N5NW6sF=Qt)=J}B z?hU^eHNLmqG)2NQgQTJ(W~ z`0t%UCDSm7Ie3mKWJ&veU*Q|=5mBb03DxoH39YX46QQBN(!SMduYzf|r>(0`hJF=? z+<2OJBgY9Cg?)Fn7cp`#i{B*~_@hWINQ&V5WxSM+FBHuCxs&e%U}Hs)vXys$GVW6e z`z6`ZC01B0b+1T$RNl;!{#hgEDvA1le^s^{PvW;-+6WDA0Z6&okAB z+;hl1rkzcI8KFu-DC)@G`^9PD90+NL0mOumxESmiGNzan4nZQr#35z5h2k@Jr$@tP{0+k>y;Xsx>bWNZVcZs+lYDHJa-X3TGGo6n4U7@ zq}9Q5=nxR}PwCX&glCkwk*V((=b3)0W=@x;?NnnC)+a5&@%7sD=lnJ&nX;!|KAXvh z0|Em4N|+E;W_7*U&Z}=+D%L2&N!qys$8Lf!wb5X4)|6plBaq3K`IpZto_M7;s1A=> zO^3dJ61nV8U?09_4l@(eBB;+0%#Ek^f8i_kUfu*mgC`sQG3jcpCc|&KzbcoSBsMaW z2#+BiHggKUaq|X)76E4hluDN29M;IUOC1CVd12MLCog9=r#^2I>CKs~+O9ar4TtnH zG9Ea3pZ^^c{4IvAZpDemARQq^=cdl)AuqCI^(DPNLm)M#aLnzqf3eYo4tid-W!*Dw zF0C5nVT$!f5!Cj(;h9|bo%4{JMGq#Dlh`0;l>54}Uu7=)LpAaSxe$cB_qLL0kJr?X z7NA)bQ_c~VbIVX*#0hXlbgJa@XxAk{N0F#iFeM3dcl6avD}VXywaBd3q1ih!*^KlO zyuxTqOjFMvXV%;>b>=$0q>&WmzI<8i=ISCA2Xittf+?K?`?nT_p%@xF-b>sflFUz# zT%7}|jM*eRj7JC+Wj(M$fD#o7i?*baQGIe3)xsk*ndP)q@hzP`sEEnc)@T z8Z$404?(u)DdwWoBbz(djFM~WiU@G{YvXKK((@X#uML3cxM_a&a?V2bU!R*EXS zW#r~MPCp0V1HRSsM1b@(q9(z?@E62xZg72aoj)PGm}j=%S$hn}1DDpx5FjDR3Ys(R zkBjBLeq)y7SzV8wwS7do`tV6a&Ng zmU6H+)VZn4L*cysYGQV+1qLB>h>K9swfYTu`pLkJ=Va&a_6X=-^__DMnZE5Nvicewz)kGUmXIu`I<@!p(Drn>6vTjBg-y^p)G}H1A{PyF<{lY$@i=o1%~WnP}uzUYYS$p275whF}K0 zw46`<12{fC!pp8uGf(At6S=!^G{W7_x$KL9GrzM7xVd-+?0VuES;qFhc(UNdsg%;# zusc2UX@2V&(m?A?x29IJ6c;gCbzIzT* zMI2mHy~lt63<`^q`p|8Bx3*0oLxWLJqg%N1Z)VVj_Xt7s**f89nM=f6@#)iIl)%yf zR>?Gr!C2l4vF9+{xIqcG7GbDmZ2<&;kbzpHjkSI#*qQnJD(C88A4(KawC2Vgf-v0R2xBJ@fvardK>RzI9Mss*{ zw>I>}%QSjQBfZ55Wk}%E2F)3th5$)$Y=lhDk%ND+6K8WRXII=hqG_LE5Xp<7pS)qw!v zWBhUs2}v<5dHM6Ijed1siYVA3J?~5GPOWtbnTgBkJ%SBcY44Q$u%Nflg!# zE*hbSu9Y=0d^z?4q_S))^HMDvzvojBNA|8PB#A$mEp@OVe7iSY5_eq5psvsre7zus zI#K&9t~7HZH!C~f-!#$}TedVPl^m49NEpnYx8;U>Q+>a<@0O`Jj(zLzG0DXR>eT$$ zbhQ-+@ZJ&E%FJhzLnxY@^UKAiUZH5shTD0M8t6NDv5gQ2H|d2+(zZ)W3mqs-#Ji}M zYZzB5wxqg0AUahSe6;1057B4K{Gpk40tI8x=>|nq(%?XDVsf>=iU3fB-Oxb835~#T7ut$SwRsmM+Wc zq+|kp?ii5f0BcSF4^-iyNfGc*aL&CYOV~0OHR;eT%G_Zu$+UWDa(dlvTu+aU$;r?A zBBK>dPE%&|`7$Osq9+;`+KIPE5sHHR-Qfm6iW#iwonD5nEo^=dxXDJKf7BOMaLnUp zJfw7yK!HqZ$+>x7wXLthgRHOX{k3z!h&tcuheJ{bW{KVqEL2=9m!1ndtUoh!x2y!@ zbSk6&$JA9vMfp8%lr9AprMqik>6S)d=|*y;LAtxyrMnve0R;sSkP=wBMM^?IQt1xC z?+bo@=luTOb9TUUu}b>Z5%4HX>c8a{9*Y#pdTirfhz9$j0s+a1 zIs6jJzIkd}V!r#wyrR4K^XmXc8KdZ{oI_=FF_4SFTW)SmGHIje%_blIuk(RSjhsR} zL)er=9~o)KaK6xm4CM0PGw=}W#{zNpU7nkst$c#()1#iZ7DsF zNoM$3`KFBMN_p9(I5;#}qyM}9L#Kko>Olj3x4PQrX3v&yA4xSbY_(S%`?cLI5HhU( z_e6c4bZQ#)Hx00t%{=1obH?=OSK#x5o%~LQlI@>j7N2j143w_JLig68-=Pl*8(+jh z8Hp`{;R+v~qm?#DZ%WL7A4kDcy_!CnQEN9{QGx3*#o}t0-k(5B-YT zGz4Lw^L=-Vtno$f+;I_VcEOu{(eOA|(I=tm_Vxl#17(Bl>K~z_O6|*HI)h9K0*(f( ztM348e4Jon9see<363&;JnnWYyZ#jbjgxDB%>_>$RnhdWB~%aIcq3H;v}4&)ZG;cz zSvtQiUAYCBHK4I@wWR9c-IB_%w#k1d-_b3-!N<1X{t64leVce<9aMNBSFcL|WKKXs zo?Pa(PM1?A9?F+@3V}St{6C(;qU1Nj=}5`~M%T(DZh|k{3PvHkE9T}ifPf+f$l=3r ziWMjOod*2G^{ZYsO?}5f!I9*iSkDZ;%*=fk25i;c!>!&6!mm8rP*993tZoL3q}hP|!~yFG?k!7R^3S zw2*>Lqre4jrL~~0A|%>pOg}9Hx=aCQAQLDUmOf9 z!>vk&+{Ywl0Pr9<<|oH58NyBrdaz~U1f5>x`VLAE+kt=iVCi3#uI&Aa8s$xbo=*b9 zI|c-dcRE8*Ta-|LVNc>DeUJq}4U?{}lam^wAJY8+qWpyC$6W1?w9#&N%%3?8qMR^- z5Tp~42}5^D6x_GQxLL-dvbUru4P`tvkM&9RQ}wSzeLD0@{_(@#q$Z?4^=x}kDaG%6V7+W$vjN;u{mbU>-ZnIpA@_R8+P(l6Ek;}ETsCU#V{t`jDf{5?8XC}%WI}u_ zBIBO;w)TAe_`^X01}L4^yRtXHIJWYOsZy)3IDDQTr7eQ~V6DN0^3Hsc$?>z>zQ41# zU3ooaXeXq$XP^AYpBk1Y<1GZ*dM!@s2|>|em`gfpmi6wRCw|}bU55n zrR0AgRa?}d@mj0$?p*HV+>LTznGaW2k{%0rYzeR(cF9fbTsF^6o1jy}5{pcGHOWA4 z7qRz=WS-jQhpBY%qCSd?hZR$*GSQ@M6>Pzpcb8*V)PaF8_8m8O_HEzw-<>vWxVW$H z-@o5XrgQ^;oQv=+PVz}iPENZ2IBq+0@vL|FX0m9aKht*JA_wnGVhRf}52Jg~`2_h`$MiKiKem8;X= zHaX89Wbo3a4iI#sQY|n&r3qHsL*NM-sIpT=n@(kA?U{CZVfS{P$6?+t}$s*z?&f#Fq?S@BoCtU;MZI? z?{g%lm~ubue02yEbdZ{X+xWUp?7zf_SnQFP&lsRmoy3`on-?ul8$;)Es5@3B*mHa< z*3QzRJDBgMg%!4(V!mn&Ra~e^x8nSr?1VYyiWT_Fjae0sg?mtVQW)nw&{P}z_ZneA zmo6tAI$qK4ZrAB@*<<=N(n-+XIYH>v9FvKznM18%PT+(qay6<)lpQjO1O|$R2$!B$k%!ny^hs?0>cCZFh@$v} ziw|%4BP?$rA?KR}Q%&O3!&wK4Y)AHWkB%q?VjL%D+FGBR}$qE?bM0YN-p z##yd7SUG|SyGCRRjNugD+lSD}8u!6u%l|oS73hH-1Cy2l*bqZ-J5eGmxh`RWS2G%5Q9*@w>)q=1e2K~zT z-Udd(Bel3GErg?OOsjx1F1Q)fM0O9G`5Jc=&yb!4PrkiEBsRLeFY>^?Q~?j@mk5Tl z-JRe^dmVp+V6)X}ntI~k2>53&x66otHyIonNGP7Vjj4SYkTAa47Dt8la6U8 z0h6y#%9s-13$i$KE2(i#4K09H>adwdOO48j1qULteRh-{n`MU*jIw}`2kEr|=-T&d z3)qsSS#^%-)zA~?h+uip{d&mxB1~$;a%<Fh1y{( zxpmlzC{ch*UF*+5*DpN%3X+8G!QdwFp3P6NIupsv5wK75~}Q|Y5IXA-`N?x*>B8(*o9$|5kV&rDeh5>?hm#VF11v(zNo z+GB!HWNIrR*hm-QfOc16b2ilWn_Xv6I3pG-2Z7&6#kAjC(fXNtAeZ%_>aKj9O758u zdK1Mb=xTOhZZ{7q%NR^j9cbfZqkNPnE_79$FvHUlKR8E2P!S|9eEb+Aug%ezP(CxQ z=IpG;mmh<`ug^y43i^9t zY>c}IC|y1@4^GyLnvebw=Osy3n=*p*c4zE%XW=L77cC6&tF2Pxd(-~XrZ^L<{Z}Ic z;LJt=C1Vcc<>=|^98;*R!_tk_gFS_C=EINHHjvpbO1!CR$)FFm#L=iM0}V?tKO@tY zpy}0rNIok!2Zo}7eg-k+W7)1nuwqd}{!ul~CaWeGMZQEH#5)K4{AV&?=Oqn8lpAB* zDz7OWxSt=U=|)F`L#a1OvgafetF-z758UDbX3`X&>NFFX?ejrp>DA#?Qj_bl05+A> znUdzWT4$M&pyvlgStQN@&BsTkTcJJ8SqV){zLOc3E{)+E7REB90v>);n#94ELuLj3 z_nG;kHNetBo6Wd2GuIwMfs%|2!4~45O6kZ_g0RhMHR5TcY{1 zjQPiT@q`i_mLQ8YUy0V7RCj`U8#ZiSr}FR>ghsS21fh}Slf#FPC*r~z*9TjZ8?SQ_ zcH!Nr^`LqwebfBiiWUot+@i}7{HX|7&{nGG61nmP z``~J#xV*~pC39ihnmZjV8#&(O7>01K$iuP65h;eRy1ol5hgr&8Onb$W76hIdLZ?a4 z01yiZfZ}FwjSX4<1n*2b8D(0!{<$^#+vsh}Lr9}+_0f~Z{<4U$WxeIb z0>G<>#EdcOtyM8nO4#u_GEZt$4&SpjZ?$Et((tYii02Gm7mjcQu zUvXKM!^q4jTPUK&`B0>UcRE`{1kF=yfC|_rGVtEi@ds0(lHYfCebshz?xw{PNX9EYt_# zc^bM;qJKJA2<9_W93}~TiSE*Blf!#p^&Z&8co~^YCbuq)H6bCJ2_Gq8My8E-OOY}U zUY_=JYGK@=bA?m3B!Hgms4F}R)oEzbv@9|?b=`p_u-Un?p~l6$Y=bPHU+FQy(ND2F zGuJCiScNJ7;>nVmb^ zUU;}t8Gz|8OA-B3du6H{RbI1Sp~aZ=0z~(;4qp7U;lgHe*<_?gSBa4&tm>cbCrm@eH0( zzil&fy`_XfAF=2dMS2S`CfI!UD{MXJ!bOfNGiulZzp1}Ft&<*lC;e989YakqrM#CC zaYU%sQr?_Tgb#aJ3XLKO7LyV^i<~BMt0=<=08}#j3(H)a3*d)`Kppt$&C)2$jQQ6ehA~k2gKx9-1}5~o&)P)P^o0W80?xv zN?k8DM+}TbUw8I8IdT6Nx$U{8w8Ur+RLF!OrV_K>t$!K}xbXK~2_B;>W|^-p)V@wF z-ys&_oMDG2to!jQ3L$GP^!#QTxHdf=s}Hx{)eTONI()mw2T1awJ;5epRt<`pI1v7rH6N=*!t|qK>{e@ry8*uiIJA^K zrw0HO#!d3m4+*i#e9A6g^OD*EuB4fkI*-|&WkK8O8X&iKv6TxWUZ7`9WUOiB`Pjom`&r z^A}grku9`*pLSA&cXo(uAY?2BGT_ZvGK?+<#ptyJv*}m@@Ni>)R1N!lH$K>P@TD4$ z>nJijOe!Ibex=WEXv>CHJeF;eG3stkc2+qi3UK_~3$H055uW(#7+v)j2|b^fRn{UH zaa6KdX9yDnT8Qy;y7xOo1mu|uc25QN6CnhqBC{;sdrfX}3`gw;KEdk1O(#S%%C3w% zl1^GP^EX4pF?AvX)5dkI++@;UQ^bps=g#94k4DhT7859JcLMRw#qD`V@UL|nR-wix zT~2}wNqmPPpY)Yn+m@T^Rbr=B;edE$1mm#3Zs+C&1_AZ%Zi?7UVxo&2HAz9l&guu! zxi^+63_%1Z)>X)&c$QA2ug=gnSccRn|0+OqcX&Ub3venOyS?@hrHcECimF0J@RMd~ z-_W(K8=Ee`)^|d~(oKdaqQ@h``9WKf36bJdn0tmc_UeEYFEx!dt@y$sop%j2^)g%> z>?o9L+5N5IgE*F&$?P0!97iXzS@Zc8n8XC%@Gk7v!<13{(E!A9cdBe2#m9JnKfAq^ zgtX4B+o93zY`Q-b0ZmNh^9D=zQp}YZjFVg7j#hHu96Fxqw}}r+HFdPf@8w10-mUC~ z`~Y1O+ZqguNByC|D~&4N$zhUbPqzKXc%s z75HwD!3;*$H9XX?R|fFw;5Dg0W;4trLv6=zvnsv1t)ueOXz*<#Ig&x?>i|nMMA%oa zsij%zpIy_Zon;36%7Wz0Crt$p+vdn2wkiD*^}Vm2(daWJ=e^fCz4Zc(JdSuC4)}=sH&hF&JS)u%s%( zypGvqYn#q%(tvK}J zg|~&B$C~|tncqjOc>xv$q)=VyiO>UqAC2GR$wfuz2&Q1ugg=&ixmt)H1NJ`HzF|Ln zTYJVM>8st;FwNraB_!w~SMa2hNs}0%NF3Q<9oU)};=vEaE91#DKZ3V8LV+Z}vF}eh&#)k3qu7raOOTddw3NPrnF83rFQE`QOgE* zbYgwX8Iz1%B2{Z-Y3zkt1O^6v0kHx1JZ;Dd=40ziSca)quYRVlm7xUIq2EYm@gFRz zI%s(eZsAvOm?J)91Yr+rQWMvl>hdhj(p2!yVa% z@IQC4zZr@2h57udtiTXYcnBQL+@%v{SQA8BaXVD|_mrQiM>B2d&{re6(Q}uj5inDi zbPXSM^#fI=f+;7G(zKbo0Bd2Ji+cs$$}B!R_X#tTQFFmoKwRrD-vkzfxEU>V6L2`I zQ5$EbfAaxwt{MJP=~0@+5_P9Cpgy?Y$-B51VFAgP*$$ob<*O%tl#JV>vHU(~qeV#F zCi8PV&JVIgF(e~FENhHVLL!fbuk!2*Q+n^uvADwYwTNXcVPblUHyPfoQ9uZSV9xj?{P<~rx(CL4?LsAgRG z-iF0()~oPlnjA&&UE&=gUuq8P6cBld#jdH@1W_xlv8_0ks!JpQF^i8Fh>WwM^f?H_ z+fU$XNsEhUDww6n`K%z$0gMXJT_OZ?aVClFZcrxli*?<++S;u6HC>d`va&3}nG}ESceCSas#ZsrDXL<|?~SAjd24X{ z`WYQmo>;#QQuFLs)5|Vu4D8E_WIUi_Uim&j7sZi?CARD9Rv|L^h0s^dXQrXL*gVOR zQ!kd9^Y*6s^A95E0>?b3E;9?Ul4ye zBZQlicu&KXzjJfFOxh>0Qd%X4af`g@Cs1c3?h05ZT#>1k-y8n+TbMo(%f?=yE*TMZ zneuxD4Mc-;*4~iCl*AWrZ~}yqe(b`X?PVe=cz5M|zO?%UpE}?`8YcWULo;LaILSN~o#s<5`;L5sIfoH$x z1`A^q5p?^pXrO%sIt$j6p+2&8fK@DN4om%|EGUcj_pZ0`pFPQ=vSWpHjEb7kM zm^YXUjW|1x0Nq0J$=S<9(r?7DBr9;sn(8Kw$SO7+a_zy2ajEoP8V)+;#BAiLeWc?W zNONC5C_VW0s8HY}^(MeLUCymbC;fUO*S2vv!j8A_;v4@fgL|M101BH-7>2}}A-HsbP*$n|#wt~iRziC5R_nsHhQ=E*?yADuxw;x%XA=ndo>GsiQKmmZ8( z>q93QsYBn)zqu&csXfMKHYEOYKD)lV4s+7C4$Ha9#pU8RcX=4#?3_&sJa1J%mvFa} z@9XPj@tT6LS-MAHp=7rroVrWw3BZM`Q)wN6CHRDuBbpuJx{S)8d#|rUF%%k(x)c}mCOyl#=Da$HcT!lU&#>QVMU^&b0EQ8mfyDyWh#g;6E?V zSR6D7G@^?3@3OX2+0UHs)>$ep=Nqgt>shIG(r+VR}jGD_o_66w#Q!N_tJn4x2)Sby*QJh3R=JtlK03)DDukNwf zd&!pt(rV{~(Svo>C1(Argf#`=md@NDH7{hm2K+xM`>q1-5|KCaq$($iWmv7i6*xJc z;M_4Vhn}4?x{;(8HYaOMCdx)tP&L*PALHsG-{ba!A|vLgRH39tf%mM^jiL26#jw7`5?EoRY5)g@zkIq}~kQ9tHS;-}*zkRLnR1nMp^yU>0Fem9c_E_C)m zuab+>%w3>$%1mRN6M~ldg(d5bw4g6~z81l(;_ZK7BpTt`ZQj9fR$qAIxb+XN?#7Np zg_IPL`fB^QmzpKY4@AmI%~!v^sIg6{SE&lFS7|+77eBPk@gk9dmJ;=rXu2uRcv4RI z^fZ3ih-n^pa~4%a)QwYUo+F-Em2Llxo`n3v7Qn}R^r9xNN|CDt#r7yb?hhj%jsD9z zTmdvAr8;8$N}h>uHp`k}MC2vOSwN^(a*GGXz)y%EG~S!76Gckm4a&a!3~U>YLw@5nv!$q8oB{8ZGHO&he2)ft+055URcg zplaN{0ls3Q63ePoKm;z=UXu|o+RbRj<<(9x`EKhv$MhpQ%Q5-mB2busN)trM(zz+> z>QYW%MF3%thbjZL5;05FH+A(e1OUO{i2oqi=y865V#L0IBdGgl;xoyTd*8Wqd)5f* zZt#1;G{De>Df+6hFiTF_mRZL5H=n>9Q~VfM)e^3xJJnKS((?u*`qg+{Kb5?uiyQ;N zM!jL(1bCC>?KcYYLi52R>~e&c0Lg!G|GV9%Mv~lELb2$ui@Uye!ub0`vhp}Mi}d>d znsN$Bgi1DlGXap^Xr=u2DQ9cZf%dW#OK--bbFH$G#F9=ezZXzVT}ZYfQ$&k?)zJbK zOj#LUo4QnHR>B)V0lt{WWA^QjWvRGB*(deCUj~JuL`>O6khUMjJIC4HpZ<>PmX4o= z$q&+AAL7t#dxcdgt6@EydfAEHd>pq!L<384q$|&l$H#MYd4qu$Ud!_k@;oJiAx!oZ z;5x1Sm)KH1iag^(c(zO9t)>Ckm|3rBNZgNjQ}b-xt`wWHl;^F(aK#U#+3is#1Nl8T z-o>qO>2$`l*ASeUBazU&4?4c}Sy`Vjz#i-^uMg(R5IB%0J1fazwWgi37||6qb`|Av z77;3BSnk<)a|UlSm>WhhFVH641Vx`Dx-H!(vlEUR2l*0B<6h=oZ1iSD@E#u<2t@a22cJxN9j&3m2`8l5S|u-8co zK%pWYCMG6B{#{wuJTNeybmfI@% zwUdr*=%}(RjumUCc3QYZGiEu3edxvR+yMBf0tD6Fs}ushs2u*(t^7U`M{nlebV~km4&EO@lp0ul*c%{SK-jC@KAKbZn!j$FnVt}U}ccVW#j3pDU zI2k8BJ7k4exodP(6urOTch8@LWF?-;Tad>eH0imv(3TFsxcdURL33qpIlwJ=gK$am zsmtb95EjN$pQ4dZVbnxwVLY05vPpI%Ci-Ca=AgkihIDl@8;BCXOyM~)0JHA%l`X!A zCj31C5YKr7&!#5dM_ynwu@1H`I~XkEST%KeNWHMX)0{3@dPX`@xj~UUnrWZ;0WFDX%H| z6jAeHXGcIFAlYG!!|~v5AT)m3faX?C z7%MqpM&{#;vGVig39RXNO-nD&{fBFCn1QbdZRE15qms0j32?-gys-bA+Uso956;Jd zC?O|bnD%O5VqRQQtWG>x|E9IECW!yYUZblT^ZIOAOKOI>a7F+}!%`S7WrTFUzIz?!uqGf3|?;p&*#S(56NK1}l)W{eS}w$5LvZqrzz-pSH#F z&95)>u!t;L(_LxtsH!)AX!*Z%2w`a>BDk6uPd4qf4VHikIL37?@4-J%mJv$_E|}08 zX8f)mj~LSSgGlZ;i+k+4FXwCEMFWPIfHbX4nMi~VTZWHNbPE1O;)Pdbj*_Zs{b+Vv z1e}E|@v)_7*umf}^&y&$Zn_mrcxk>z8eeYKZY(w44=j=2(3U(#Ap4D}6HVXURrOzC z*0~YmYlU>y2Pn)3==J$;C-s5+P&<-(efy{j2#$^i&|FVm{T5L z+az3-JCMFn@p2#_hlcXvy%fLq-+%sWJ|mG&9ywopYl2t~Z6YM#^B1|lE_*_EJeP#a`(^Kg#K^3&donzzP;R^_3EBV3P zi3SABfDZyaoUjL9FZ9aS3`<=+Z7VaACI8|RKZlbz43CP7Nm)XKH!bYdLoD7lnC~moCws%Kc(GqCq-b6FqKb7Pavo) z>G+W*1f%)pVYu6HMyxeCdIBHYX7{B}_+6z&k)*(L2Dg@u|H7iXivEv?LYZXIS{JTD zP(PVUx=;+_SdgY4jBZ?~f(5}2b2&Bt+m%Wb!7{sBKyBsdkM0lHZ0K14# zBF_sD}vl6}qR0v*WCwh$eSz&YucTnF9s0Z%r=>6Y>IkxV+mK!HBl^&evYHv9XX2k&gc zXWn^7`of@=0vB*cbi_?M;gLHjHH)7r<>A|dw@c_7Ojt8|dTYjOf2lM7ZgwZoSiS9novdnWFf-B%F1f^p3^(= zlYsebetoDs#TB90P&Yqis7j>o_Ce*0tRFnG#@D!OO9;a;+CW!e#?o&YI-9A@`J+{? zSGimSrga<{O^J_GKGcy8cLxsYYc^X9@UjBLf}QuSRC}s0@-8|2AXF`vl-hsi1LR-y z4$NdE>L%QikRd7Ds(sBBYut|>AC3d=H>PbNmh{A2i<@JL$TD(w-=xZ>1wsb`^>27t zISP2|FhWdE)0LIc1lAa2YD~lqI=&M=YbP2IO&bjp^=JEW`h9Jln-{@qQ~?6PV?Yu2 zpS=%>fpMf8M6PMvMjJTsXd_(O#c1$#suCq|hX7aw{F5NH^aQnQ7?485z@~Zazwa;RY z5%yUP58*?J>FGsij1w&b6zq;(3GMJWV!(^DNu|QDsdXlsi=@GvuTxkSsf>(0E|BkA zT7Dz$cQPR%0r0mZ8x^fao!8%0klt}ijB-Ri16_+>GE8>NN^s6Q}06;>SE)C51r557_%bIfoLJ2z3?%04g^;qYh1kt5w3t+raGJzk^COek_EbB-aHMlDRoVv{c z>Yd5Ct*$BK4AR>(=fBgS`)_ymOdwJtUZK4HdFKzuv1&jlffY6mM^D6<0e=~{ss}*S zb;sFx(JL&><&$Q|t`;*f-fEE(2M|C_Y4AK3|6JwRIA%0xj>G|Y!hkR5E`SJ;9uYP) z=6DsJAIY}kX#t_6zvrC`{)wW7fJCA)H-1vDV0mPup~oY|7|VXp8Up#&{$Q@mdRy!6 zLh!4KWhXmH$Vm%pSI=egT6EK5O!B*GG(Hiu*S$uMn3`k%RbTNBsmXF)&<3{XG>KU0 zTNjm8oruq=jQs-z~?oJb#t{h29{oAwRHBYCLAXgIK19{V-KE-j4lQXVuHfxe}&WtXKLdePIU(V;h-oFL@M7{0*?$M+zSuux#oWT!`3@%S;>-TK?%PmL)WTER7Njd;he!sB zb4Yyb+o*|iM;hV9Fv^ceA@K;p>4$__x2TPc8lOo}H1p#e0a~xsN;GY&re|2dAAQvV z%AZerei~VYwV2H+Rlrw(I%{6^zv|gZ#j`+rL&?e>EXmJx#M7QY_JBh>A@OTR3uUhC zL3Ebj%vHi9aYUtM3hB4MCWCp;@lqI9iYOz!P1}f;O>rec{;08cSDcYrMI# zOWrya)JG7u7`MJDjk#AT*;heK0#OAh zKTKr2>!U(J^_S@ML`K4Esj5!lSe z*=&kXw_@s8NdyO9DpPKIUT*I3!u_$#SBoZP-ahvEFV%y?Sg5G}`Lia0@eJmk|H$%~Y{YLVjvcXi6xU~m8yNwszAII174NMX>wLy<$ z90C}`ULI`2@PND}pO?UENwJect+bNmqjZSXjX%RugCu#}o0q{*Z2WFGQ0$CdL1`XW zV=6E;lh>Ab&@n;OO>;9r*rWu-5<{-uuePd?SS8 zTdx*UwiSv3_A^N@KK1yTBrlo{ z=p|%D>l&k+nR_WodD$W9%AX6z(SejxJTl6FL*+d97^mjl+obq)Ki~d!Tx{msQ6rJa z+fD`mk(oCJl5vgpx4HaVUqn?bIUn2+In-45ES!qj6%j-ZpNeVt=l1wrZ4Qmtmy1S` zVudiAz0ibrWa7L93*z~Gm#vU*r81e@ku*UiJILENM;+VrnWWaM*hN67w9|#28W2{w zQwDrGcIIqa!D!ByzJ{1ge{0ey&$Eio!kZnN|IAf9yJ5RF)Q~5Zcwx9KI~1Eyo`T!s zf>eeo7e}sAK%*JpmWDBIwlL5*+g(C!sRsBs%a5Rv3mG!R= zMa$mdAUoM{M^UyzKj|msg9?9=1*+*YKy&+Sw*zAr)gf44a-yuu9&|nqN+O-c71<{yZh8UceRk}|n$nbpC{a0(_o~#E z^|H&mFQHQI{M|>v_>hME=ZBU;2E156NDMH^w@rLVS|vJ|fzoeHvI>eF#ifK68Ss*CWK0p;&2$(5Or2n%he93Ki;j|<*h=6z z$F}1*Es5y%H-NTrZJ5*`LifuLklYWy&o_X90f-ewVZMx`2ektBQ2ceE3L;6SfVmtv z&t{p~N(AEt$czw+g}|HdC&PIMF5Z3ZX+Q?9@n!t73`$p+Ta_BRI9d|u+_Lnx)W?sp z^W%Cd5E+chS!pr?n$t6>3W+N(a><5ihNx=&+AH(>uXi`|m2|IwsylO6Ljt#$pqW76 z+pAzNmVR(glF5+)-0qWUVZjH`p3_@U;u^2GCExb8$WxzFb2C6+X1Dg0HTR_|Pb7kl z`?C!LHNpf(EfSAKcY`j@`w;-F!)-*P0-> z45*19!xV1=br@Q7xD!A0Mfz3{OsXxbAq zfL{Yd<|gL}m~qh=Vhq2lEm%_NqwbnK4m$5y?mHks&{2F;&<5HfepjCwq#0v53|dd9 zlUOdd0xvVWR7+5d>#Rb`nUQGzLnj!C+^*rT@|B6L(WqJ%GhI?jR%& z+CektBXqltupQ+8v1mf>6^@TO%wnvg8+baUe*?KAghQ+h9dC~}lDZ24Hw{Wm#?4@_ zB_V3}$LJ2X&jHjJ$tGc!a&eA3ubfqX&0-7b`AZMIK7P4%)w#!5F>fwT&Q$PbJzXfc zGtxepl=ug5>GU9EUx@)p&0Spl=9QpjCM;f|Tj+juj!sTQ-Q9~8OwU&4pKf>>dihfs zF~O+xCP4?{3SLTbUIX($>^RBHjYO-Zq3NL~{7l&l-2jxMEc-6z6%y*=C9IC4V@1#X zSUMS1=pl|zZ>}hwh*wzwxGXigCfnH;b^Jm9VrdEtSpbrZcCve4Gr&^F7{wtwYtg+a zc!gWZ*lf(R ztk>P4eb@datVHT9dFMK1Vc9?li#MYK0JF9vo+sG=UvQ{UDtTZ{VOpt=Sb2QA{5XK` zKCry6`r9(EhI0`BRL;E4llz8<l8an5Fom0ta3cWJPdPUu!8&Fs_#Sqe|JBBDN;slZEl_(vF=9)Tv8oGydLAmfKQ0|5zhWzhjVhtr0l{$8UEGt&t*b9=!vCX*n zXcEs@WcGZ~kgkdN5e9;V3jeyop01M-s@09sGMB}USd){|+;bMFW%mn^q+%(Jl)^QI4PTQGxc^9NZ4Pq9sxe&!m2+4_n7Ot2UDnN zeF#01m$D~d$;^(q^)}nbQtA7dt_wDHdBcD*Pv?!YC@A{O!>-85yRvhcp^6kn&sOlkxde)>DnTj}M5h@vuZe&4(@c z>Z$xF`17o+nXgHgs_Tniq&QVi**8?Rbo{vFa=yAqVAenVdll5Uq>NWT2lbqPV9dVe z!+n}0Uo5uMv;T8r4=nHEYl)hXMf4%-xKE`?{8^vz){7wxYviqcYsgrio}a$@Y1stf zA7SzpjIHLWXMHPP6@``&*#6;cVHnzcqLhzW^L!So?O5WEVdeUJvVM1;P|*y0cRzgOrg! zE9cv#G5^k2TQ0Pc3Clkzl|)go_;b|2@zqwBm;ywocN5XCCJTwe&1UQyq?bd0%BTq) zWs+U|Udrs7MW(bYOC?dq88yt&3_uKMtV_%u%Q;lBAG}K=e(^=a%09PgWG4a(Lqn{Ui%{GmeVaB)^M&p)$BN`c>K&`m{2jz zfp6gGb@yIOl#06pab|A|PJEqorzNYoGmqWK4QD6=pS0|HV68~1l9}FIGFg9lcBoVl z9ni$4f#LBz(Z0}(yl3xIO|<8yp_2Y<`LBd0oMK1kG;-e9Wjuj2Te0oXX0nM=^q9FT6Y~bca z=D7id?%5Oa{?1Ps4m_QE?=!vE#CP2CMR?)GrLCE2>2M2s`zkshe$&9n^I1h8U7+fO z6vkxSd89*Et;o)IgQ-4dQuXsM_rXdfv*wT6Ss~lxbIEcOev7=l-*?-`y@M8U1DTZS zu9Tm(|80M=tz_quMXG#g3w*w<<)Tx~>cFuVOK;hgvjw&F{l$U;fZDOY*xZCJx|nHq zWj`+@jw#INm#v>o9bs+xLHqVX@)+!j_2*%r1k&ZOheQYv7X#SU)qll9Min?jp1K5998;2t2vZp%IRC>-7e!Lww$7wby z=|sz%Up1lQuI0%&@foF}=q0Ty2W>M#C`CQq{M#^~L+S@z)W?}{e5VEy^#t#zFl49B znpTy3ZKqzwfi!Gc)uJbIQ%cuEm&bCz zE5gr2Ppbu=6eK>^PhC)R@mzeBccGLZa?~WWuBc(>7}l}C3*tX1l9PYdQYK_Xxp%m& zc`3Hod~oootg$BMo3WP#xMd^UfPbrL`r~A4BG+&I+z&GF3CM&}@&*)?mh-g{UHawA z27l+d@sPv#(i}$;Pw%Iqg4K`* zv1#D(^t+GHt4C$eIcvrZdy%}K+FJ8EJ621HCGBTg(M7m;R>%0z7oM9FO~aGB$G`4R z`Z7INj!{%%0+I;~@k1r)ks&wxS^aZsl&8tNw*isbI$mVa%3I|nR_tvQ7kglgb(znIwRS=;Ig;G@y5McHC)B2cV^LG)hLEm z@Ab3c0Dc{J%k=;PAf|&2dQWph;{Db&8xzjcXA*Sr7-rVS@3%s4j%F+V01s(0LC<=Q z)5vl*A-lWw-ni+7XOm4WIG(^ob^61M+~4$K$wIeFwF1Jno~q-`hb6XZYVlW{Iq$2J zEi|-8Im7oHO=G5pQ#!IPhzRAQoOno-DWgwOR3YBpN|uVuPYSdTV2NM3&p+>Y2ReD| ztXq|HzPB^U6n;Vq6zF7$TtRSbCDtxep$8vS`1wmfl`zI3KZhC&t&pE4k6*F62?Rk_(VZ^*6do$s@S0gqVtsK2~dxB^mn_9mUF-jqMp_is}5Y6<1- zkq`~NWN^%wJW`x{^}Xc=-tM`O1c+rV|2ry;ODF6Ob8$GP%Jg&qRX7}1FgX5BTfw)$ zk~PScXd2QxSF5wKwtMos0M-(Hr~&?~Oozd@B%a@?d3)ZwUto0Du^v9Q?OOwJksYEcuPoi>P7to=u4-Q(W$u2s@k#T{Im=prXdvvZI~Z?BVXQ z#LCB{f9nn>E~Xm?%R_EP^nEWr@E#Hft+5T_6Ik8QnYg(7;0s-~z2pJ|3E-pmLwt!P zZc00~wtaFXJ!g%DSe7Sm+TJpMN%j}wn3%GNS<~6cp+KL8yL=LHE%HVL0*0(6Jy)7&T~zI#k8qA$M#;M+-wLcxHoEKFDz- zd6=FlAR2!Hzj5iRyhn>HR;O9>9L~MC%rYn7?tilh1Q2iihNgH@Op0Dx5AogAYCkfWN-@Bu9m+g@a#)68`Q9 zi804K@l>g@I;RzpHj-U!ZlkQ-s+heven8#A`)uUX{m^y)YGl)Oc4+Tn{VJD2b@E4k zPN8?s#xg1U9SP%Wc@%B9`=143TRC-@JNbP{d?u*(&q?rKn^)Ec>R8#@+Qxz|aTY2M zP#T9CcA|;+P-gXbK5!YwibE{{~PSJ!-&oHvsXtL@j#7-xW;|5?BPe2+FlG5bWh{j zoWVxfj0N||xE(j)1DSZV8553-K;_glN6x@@hhL{%FI_&zpMUQg_@x+p>ajl?Q#BFW zbcJ_+$kv^hPQY`T!aXUzvZ;ZPM!Yvn$;_zS5I2jj|7CO8;7P^cHZ^MIcYbycq-5S` zzo#9;Jp%Iu-NfA<8wt19MZ$Y}MT&g~T;lil6Qn$0k~zjSm?yP8&hSoZWPuq-gz|Rj zhoet%cJ2P*R4zw>Wqz;66uSIGn*Q>~R(^WKelq%0{@0LutAjDGXM=^^HoyA{xJG zkSia>iY+Xh2(MxC8naNBatAAIS4Xyj7S0Fx{0WOq(;dlK&(v{y(`p`nIz4nhfI?x0 z$6m$yqd*hM(CD1DT#K=%RootJ<(%v+CZT**I9JjeA~^&n%@u*izV35p?whbN18?`G zoJgS=%70(nQ&1UxuvD_#n%}ue2-UfzqHh_?0^d>YkTGlKJO?4RI5e zP$y0m`Ab5S^TtSe(>#0s%$^T{f1Jc~EZ`M=rMA#1A&FT%mkK2jIe)VBkKeV_97zow zx&oQ4D8vznI5OXV+R^n|zP^A}2#_iA6w*@xOmMK4mk9KACd0XPcTd*ZgjCdeiK3>X zJDw3}6wLGETWyCLEZX;pmmLRwqTc!3U%GAfjm)qKwgF z9lJ7wbxtI|Ni>LSflll&+_$`(8=`zMyZU=GO#!tjD?}_Ay(JQ#nP)Z3`V;IbP1%iS zX16$`VnMMQ{GR2T4)e z^H&_>|2{M@E3(?jk`~O_d*L{v-0}&)wc+87%4oFxc?@Ux5uKF~tg*E#4Hdn$inJk< zAB?LV9krx44cH%0`}zj?%deF;va5zZ_k8wpJrumvJ09ny{HK zY`e+)7U3NHs_FDMc!BDwZT4p&J2Tob{DBgukdFZ@bk@Gk~O z7<(XMy71N7Udu1g0Vd`A?^vEH%^LP_2^}uERZ>B)4T?l}4Sca}PX>)91Y@Z%VwqRU zxPIyOXg#D6%BI!w%q3m)CQT*gY2(&&#AH2F#qHI8XgE!)Da{l-ISMe%R1>1Wh9}D$ z;82mMGyP&NX)p68W$&Q%oj(Hh3qtvF3)3ph%+g`4U|*JW8NH3Yy8Tgf zXA9IZ3ov7G3KVet=#yH(zqd}D46Pq|Ll*v6><2xRJ(r}S_CnF@N)488KTWQ z#IASQc``%-DQxlRw&x$wM|6B?S!H7W!e5psCd#Jd#kVxC?I-Fz>|sY%$@t`W-0r@m z2{eRc$)^s(}%LQVJF(r);SnRi9cEsZS9ls=am{f`Xp$&`~6WJ*7r>v zPkA+0*xv|aP{4H9O18BEwKvqz&@gNN_k0rdym(pnEZ*{1vsXSuySCMc#GR({jG%CD zeFGmdp@N&ySOpL)m!ysXjRIC*lZim zKG2jMhk`vu6-Tr36IuBP?w0(guRdV-QY~EhdUvxq_`QE@~(L+0 z&5Pt5MkJe$t&M{0PzuEEPqw(do-lT+%9SmJ}b*W>gz9b}R? zebvbgpqmGr<^e#mUnefK*XRsHyNprk0UkI*Oq@6oG+yIyVF2)Q3zP=t}`iaZDW+W3C%HtR${z@Utdeyj- zWOBfyN&yW2f%gWI7V1Eiz?)jgSiPNLF%$lqeE`I2EVE)bBwmx|;tc#o>fgLZ@RW<%f zq8;6u9haZ4N3qq~FmpK=K?NTzj}Iwm_1T3_)bFVE)myikT{i_oo|RyV6z6}wqH#}; zcW|BUe9@i9fX8gB8BbdRdAz;u^a1;`w@@1^fOSYfEJv zrPgmME4KI$gfRgUq~!^-_*Fxjbe=OQibVN|M)~sm93UIvzIgjT+e&H|EL!G-lqV+- zl_D-B+V6I00-Ar=hH~j4oj${!&m92X-nOETclDsZ(_iai%b&RqBr3MQxc7AOX>1-d zjMzh!yqE4fm4EyzfORt;Rh|w~Ak-Gd>1p*^W08ta(sXwboz(tiL9Jxh=rIiPfjDjx zvaZ2VXXq|X@M4_yr6tbStDUd4HM=Rwc!B}{Ij`IO|6L}SzokHEDV?+~n_gTrqGhv3 zs;{o+^CE>E(UHw=tQLK5hy`zOxzc{2x7FytOA;RE-S?BTR;e=wf^Zup=+tn4ooQ!f zaty$)Jn9!)NLE<40&1q)<1KMxD~0nRd0<`NZ=F|TCZCH?j-i1avkN9WW(-m3QIp|K z&l9*!ZCSS204%mlACm0&zr}+c=SP#j9MEMTYBu!06YP82((hGIA8JVKOkm0XI!qGk zM~O0TaF}3IhrwKOz`Wcf_xcqTb*;J0;Wz%_S&9(y<73MiX^vkb-0xbpvtJOWYIK7xh5RD+ z_&oh)?!i#D6EBRj1$mabG-ea+e0~c31cq*{}!n zG(3(eNbNUvGQQlgs=W_3ctd1}SJ{kQWtIA8n5KJo-h}V-A&Jgd&!DtBdZR3r*w})8 zFG%AHgY39oAMes1c9m|+?^H6OL#AHWh5R;*1?&-!dhJ(_1usu69F*|CVb739x`VqQ z79Bdd*!zVsp9@3cQG`d8$M;GceX)rlRkj2ec6=jCG#x;-YTq5mhA4brKrfbD4KUBe zDyhrH&OzNW#&p5mW=~DByd<^Ih_taf@#84oXWmNe^V{;w)*VGU3p1AS_fy0dClUSr z+Fi*MpPY<0`j?*>@*H#%#6i`0*RqI1&E7cP91a5-ajY7*j52`w&j_Zn$AjQVr z$wjwoYAs5rg_IRVQ&GS5MI1#^&F!5N_Ij`ssoT+b7RKK>Z&aT1e?VJS<=guRSx|oy z8Zh^cBa|MzZmbb=*i7$?6Ht?$XGRvddLKXmU&z1wSO!wpcqV;V)@bc zx$cyJa4KLKpTswV@=0*+KvxU(%A->%_PgP*-Z|>wdtAe-gURNd{;8Fx^3|wv;A03m z!!)>8W}!_Y!y|M0#t{0jWQ1dTg08<;Qwey9A6sy&ieHdjUlnq(s;kLSF{PD8eJOOM|KFuv?E<nP2E#)4TV82iCG#|3~Y>P4I zx0u@$c)I9VnFa@J=8b3H_ppy#5Z+%<&Z-yo)@_pqK1GJXFeaOu(N|EieO7ROHh1l> z(&`(Up*6 z!Ete^9=H37GLxVGgl5ei{=rC+$RI(edJ!5#C{a_ep$FQFcDzPEi7^G!+=lsiWF&D}k6P9I8 z8#^<5lV#;nnOx?kt?HXxV|Qmb)9)=D88NflI6@Jy=g>?3P;GKU#V0oTTR60031lH| zy(E$ORDhVPj3BR|fY|}yQR zSy7+LTd7v;72Sijk68tDwWUWpf=NmDy;Y%HBfrS(D*3-pF;gyP5oqobn} z0K;62;Hia#-C>ZvpE@mdQC%yOElu=6chZmq(Rir_OxiGyYsDquJNL^^8t3irZqrSw zlZT|1+JjF5dm6W1VJtbTpS!dr10M@iwHNKz!g&|3chuGI;*zQU$}?<@P?;C~TQ0L_ zOis4<`X|;Vwi-v$QcZ(KFvNp-Wtaq2n}_w|Ii*v($Xiw-9=mV<9hk>)Xidn22&2|K zwIOkZjN4qNXkuv#VsF=J7H04P4YXGi``mfUnF8uW=uZ8B1NzXva;SeBZDK?jhkC<$FtvUbjy;PUr0 z4>~7%i%?taytt;Vv8`(|@c`kz1{@e$fvQu^9;W*x<*NNkPB16~ULZJy3f=hIMATY%cm!3?fvKmp+)+-y}&;|KZ0;H0Ce9UJ*yC%CW?hN0x z&}X)kbG~yP!F~%ph&h93aZ5V>@-}$6AV0(6KfA!7>SLRikqPZd;6(($m-}rZ$)8># z7pUiuI7!>%a96L0 zJPtauT6JsNIN&4qDFY}V{2J4ZzwcIn8$>FJM+axE4F3)Tu>==x1SZX1b9Mp1ZjmXTD zDvK#@OWVV2AUEJH2x}irSi)Eos)!LG>rtz}X9VFNh(&}S{K2Yt(*Y#JkjNc{@bbl_Mebly?zhD>?Ci}XBfRQxolMB--mo9gXq zg_)rD88$RYNd+2do}!Zb*_xW+r{?hmt&dql?Tb%O)~UdvQ3oNrQwTvFbQ0B7lnD0p zTz)kee@?^S*w|pn^~FPhwBo93i=xT}XkRm}g8G+E!heN}IqGXbhJHQa3&?S{G*R!Lh~+w`z9B9(@xJLhn!(1}q%ANS>^l%M$FBb_GBzTA)4 z`{*dfknx|%A6wd*C~!L-%AHn>vl+A7)_9h!xUh!R3=JBPVz>W7Ad&sQ@)|?&7mfnC z^<|$k;q-oeZTl-4zoA`p!NfpEWBgS(2BHi`gBZ`7Ri5PtkFY&?=bT1(OA~_epp*t-w~WxD1Nq+* zzr*mq<4e?ag9=KQ$&Q8yu8bCpN|V2Ho*Kvnot7><)PGflX}a*RI}1CVq~ru;6ph z%0k`R+oMFdh&fUTx)Hp)eFW8xfEP!^Obv4Hfk%^zOQMtk7UsvQ>wzXda_w&~Ipjf9>vz3Tmntt1eQUz|5uhTbFpJqETU{Hf3( z7l6;DP4fbq1P%Z+(xyDo*P>VfzlL_xj%Q;$$3$zseZGwTvb~%5FH- z=<;?$W%x6o3xFX#X;hW%zuO&fLOK-adGv{d%d^Nx5cdK~=mA!-JM@peCslI_C1!^T zy8HW))x}#~+${Ol>8yT*Ne?K#D)h^FOe`b9y_HEVbzokEBThMPYe|*9@GwnQ+ut|s z6~@Z{3&@Pl2m59efi5k#^GQmgeF1Ds5&VFI67!d>_I=)e3vUr->F6@JEBLCRr%#d?&Tyr50k z_^epT&zyt6Di{$9>D4K#Wgt0vAednWon(dn{BP@^eDb8!qWUb5F?=~uZxv}3_+~fW z_g0t5%=DqONW5j;bn7^SyHU{P$NIewQtPjj7M)B_1K9F2%QNv~Y+|c0@_Fz=K^}HSiub7b-*CkV zScHTWi8y4c4R!Xi!l}}9avJ}>@7NSWY8Gtmwf!L}v*|J_ zHzx-!mdF%Tnv{G4A#iKJPUy3fF? zcR}zzVcnF(yZ`-LdUAx!ypK4&Kj>4@d9L>&X_4*%cy9iN-NVW;lO(dvWpt3hTFwF% z&al3Pw1L#HxTSqNGL1glb0)&xukHu+K|DWVrby3?cCGA2bWm(g=rGy~G6u_s7?7%& zQz#(<2ge%K%LrD91xsJBJ5>J_MJe3w3-UvPJ?DF;Igzo8+nI0XhLCZ z3JXdM&`F&}v~>Db)i~!C+iU}=-Qd2O{>bJ_*-Z(2Vb3cv!y_&)+S3E>Ca8mxeGVTH zS`ezvxASN!x>qlZYzxGAM&=crhbwJymd(h`XtC^R@j|&5Jx(7HVE}lY)Nxt=%)7Gm zVGXK^^r^5T;Ju2J3-UzggV;ND+(MX^Jl5K3uELMm5~zrZ{NucsT|=av-$QDp8k0#g zx5||_)>b2^0*ku`G$s9b@j}1PnNUp*1p8uKd?{u(o3h}dJWECZgEiyJ;0-J0iIXUh zp)cEAJ8)*0H6Aw&fo25p*8$}%z&KzJZ=IVAq861ZCP7bRr zzi8#yu(4xWR{5|99&py{Mv+*4`R&T@48#cDJF3#E5RyWikHq^ez;8s>Uh87W{HgS631{VEic`h2B9n& zUsmkhX>(L7iN@Np!X{VA0zafR`TzK`hjO*=f@^PYZlT8V>%}4|5Up6stu(V zNz6@~94n@%rkCkFI@59CqilCQ_(K!i)^x1=E{1ZGl1*vuLC`Qtq9SIU<4mFTq1OiX zqj5b2K}Q69-!8k(1w-<%{^uw=(1~h9^O<<3HqPC&tpN6^JXZNcqXKZg^t4=M@uH@- zpimZcV>EBk(Ifa|K@HCP5X;}sT2ox509K%I6!(bx@@Vhp<9m;D_Dp-lC{a|KTyPoA zCbSMmW0~X#>X1Hj-_)-i2rkN+(I0Zfe3Esolr3M(#}ZObpK}hNz#2Oh){HvpcHP+Fx9d+e;nAqN%iA`q2K^ z-HRtxuo|_->cCCZ+emxkSMo7Aq;e$DqfZe9vfy>S-icvPaHqzRx_WHZwVME+6~mt@ zrhBQ%Z3C-Im!>_gzY}?Lgacpuo&m4_R^dH{Yvc5LDdKY%?@N~?T9DT%!#%9LeOS3# zjoj3!dxIiIw$#;(THANjdk|B3BZJ1K7mJh(4vxnYox25;gA>yW@{|H%p4UrexkBg)K+i`!t+h)QfYh4i@1nOCKVZt%AMZrwxTm z)cU1nESO9ifJ$;+L$jhn8OGWgooY)<)|sW^d}Q;!%4 zklP9ty&fn^Try*fVbR%3mLkcf?ecp_USPJeFDYJJ&_CIcB_`o|LllAN_z>V2Ah!H) zd)V!d1iX;jDNu)B@Bovh623f1g#yv&M%Y203TZK3fYv=mq-?hIE*Xm0UkIwC7(Ub+ z(&P1g%jnRvOuP~`Sw-t5|D=aAvsfX2G(eVgy0-ht*Tlg{X*rUOSZDACj^`AcnHY? zlRx|+(+uqOXKP@z=7<|{nkRd~yAj+0&0^Rp`|}c=`A|vqN%CBw`7F!)U0)C^*i0jNPtlk zHnb+FEgj=Hp=o*#s*#rB5&vRO%ia3h%l%n(6AOzMbwyKrWYt)LK33l;$OOJ~Rm9E{ zi$T08?7S><#dIGRrZ!W< zL<4yP3y0IUsJ4gcIOp#x#->6+2xEZ(eF3h6LxRCHAuFuiM5ndhx3y@(G0*(}b354B z*qx$ay%Q1N{5LxeOiF$gp0b7S5sqsLIyopTxViI(sXv@Y{eFMT#E;-VL6Y)kD_xY7 z-02brvPGC#{jZsMGVwpyxG;Gc*CA_^9DzeP3T|?YeR$kUf9^=6?ptchD*np3Nb^G| z)u)6xlVFEmFJb)#jgyE6k6iIOps&RFS6!1qdSrmG8IV4Wj2^UX+}^LhGuizm7N`WC z#6KTD^4=5{PS%+CPyS^xOI5gvYnS|0n-}yjA`g#zOk%s z1*O|w8nv)hy^16-oJTY#8K+W?sQ?0pyU0Zl5+C1Msi~8CE*C(SyeaKZdOvy5xsR$c zN#T8Ip2}7Op?*MdvXu)?yI$GY+o9rkmdK>CrXl8&)f3v#$8>=m0ad}Y{IDUBLP$=F9~*bV1vrTGTa*f=po&qxrWqK5Rm zur-khTd>)IQYt~lUv5zNt-VwS+dy&>8(p959q!Ho9`xIhKy!6H08@0SUnT9oC3U>D zJEe!1VIv|PEb+p@t5uaUpHK#}pw?Q?euVpGtv~>?Q+uxm5|>KGSbRoJ4WEu5!+)o# zNT+kDCzR;`=O(KaBOoI#{P|{Dp*|sHJ00n@^h!jawdNQnB>Q)`Vz1&IE_2J47*<;} z#KZh_4Bko(D@$alZqV_o-s*%jizH1rMm5J_a*T+f9Z|lQtM_8FCnt=4FU-+etdbYd z@?2lN{Hd*`rGvs+{r5SObbgOS!dVXSH@fj;WY>^y&pI%aqNO}uh4z0L4nB-VDoS8h zm>ZFv=DHRX$fd)U;ixN6T`9BMpb-`&$5DXO(}LrAR)retT)b`uYf}l-G(Pwi^o{JQ zJVyc-uOms$iXV8a?tQNAez8~Z3`PavD=p}FEIn;!NPw*3nV9SF7S0_^pmLaZi{nM< zSg?&x3J~jt>IDjp~uwSvQ-}D1$9|zGgv%VF&{=0;3)0_ zxq$@7sP)#mDnE5nxp`u3bzO%YQFqgmuE+|M#$xO_OcEQ+-?F^dgoNa*M~q{;$@oDt zvVs2Yi77TO*(r{QvRV_qi%zzEX0?A_C`Nv_y(yGhT!48abS*e{rjYE2L3w+(ID0`# z=}V1t)kP>Fp0V1)mi2XWN^Ge_WL`d}m(>wV^qp@(dUYxLd_0>*AoK-g^D6P7>sqwb zzms1Io^J7e1oWSf-{erywW+LOn^+&j{11O5PMT+vuqA#pyZyOk?yijc&H4iFrCcY% zdn!mY5)F~JM`hkSKBR2DK1YRQd3@^IyH}Ym%+RGGl;(=S(e@<~Y?cmXu4ivw|5$p} z{A}KvEjpL?WmTTD@^4O_1TxlQ&8m$I_k;f)pQgd(!ThIMn{$Ck;Pd9%9Z~#LEG=ov z|41Z|1I4t$G7W(~{hnn^4Xz?fBQiIS*K$T#O5|sksxh3LYz90!D%1_FgC?VYgdXWg z?~$OxkWb(!POFAq^C>M;u={JIuq}*1^={u0x=_<3$<_pFs#q2+*5+Ly@(T!f-0s&- z{(Az&r+`0iweU-G(g`#l?N&7r;na$HF~B1ke02>jePWNN6mZ$bR-^V};9$J`I~ z8!46+4k-UT-Nm%&5Z^ANnwku1L(ki`it&W88LUdV@S?U4ig@s1K2%Uay4RL12$SC> zw<8}d-F@@k&8tB-r1IR0T*y)tnt$M{zvVQ*E+<3rhmGEBF5nF>PlVoVBL5W@~zINsdpem~+81HQ8H^->j$|t|0;| zjT(EL0ah~Pn9Pk!zVHg+VqE;#DtSqLR98nWzb;bD5@grx&OgL*K5KN$f8J-kLG{+VhT`j++(9Zl_x)^;L-YBGXF|xLx z$BmYUzVELWkDWM;ut0%qvm-gTJs^377IRZ&;J^z5q=} z5X@>3VB`s4V%8^H9?lyV&P(a|uElh8RZv*VIm;&EVA-OHD&>&P?QIit3;bb|H$(C& zc!>4iPdXBQCdOL+5zl~i#<^44D=(isXvhj|2o=6%$0ExqxN1mIUETg>MkvsSg(9y; zu+MDpE6MbnBu>B3M5q5-iaNuK<|1iI1kkm!Mks4}a4WHgc{&O11=rQyc!vC`mflY@ z?;#rO3I#$S&a822Gt*{E)3Qip#aOJ6=>13mz@qgO{CI=xZxGt%*FXEde2m6cqQrDd z-(XhtEksQD3TdF$m&8Jp;|(JQn@vv=LI_kHY<>rr>yQBv-?OJhBLK5ol(7E00)CeR zA`%j6)^b#pYJ&leOjYAVEM{f-7XnhW^V?=;>U@Bu9d`I~t&li1+rkJDGPRiwZ+b09pux(+^K`p*WT2y~Q3CyU0gWz)3k^<| z81R$`J`hCMqGKt#ACv5xyp8Zo`-jd7>107t`qRaw;Q=KRt1qrY#K_amuZL)W9cm49 zrEw7hy60;2GJ@Cp>i2qBqANTe>P!WaS()RUz0~^M!@C38_>c|eHjZtv*5U$=D@sJI z$>an1ZTm-G{6OA~BqOlT@(|A$Zcu@Eg=AS=EHqDr>Hjky0p+t~e zdga7}#`96M2z`)wc_FucM1+h1Ss<%5rZYn|^fF#7$481BlqIMj)_)(%ObvTc&uK2! zUOgO>MkDd+bi0h76yE-gkINmsPms+Xj+HYyOV&AG=kJl|BK+)&h=!2RT0t4;Cb|aL zSz4B?|GaI-OJR?VWK$GhmfwTkIrAAvYTCw$8``KEYOI0v)^1NE`tHzI1Qg^ij>K47{U$tsZu{1nm-UDbCF~`did@RoUx^R7rec zU9v2q6y~2+c(KH7Z4UtxM#s|N-*3ac6ezb}eMc>HYc11W`D^mcD&F@ujU0*7w=57g zRB;ueu`J6_Wuh??EZzi(t3T>4l!n%f_(YVLd6vD5M1-RH z+AAPo8PMgjkgM#OU&u*0=CIVA6F+a1IJyd^6IpaC0G}w`)H%yrt;hjv!1iDA|#`r43PC^^Ld3BRv z0_;eS>0)#Y5VX&RDlAl)m{?)0;&Et#K^k5?deK7wX-8%{d<>NCEC#DxGjq3X*&Ff|x^ccmgv0$En-QGfz`|d=E z0ls2|#lHOZY1K5W6CZmov#8ungN_OfK(&e7XUBG*?NQ++_XPqCY??lA-Zj4N!;4hv ziz7huz{+~iQ|gT4b-s7QGI&(}t9p=-+Ag)X^x70fAG7F-MwCKI zEEEpWtx6_s6u93q%U`ezZWpc7y=#`P&k;dZcBvrB%b_d_%<1P{Lqfq@pSe|P^i#x&!L$ylC3C1W=!vwo16`(PK> z-}Wz3Q98bEpNYwbuu-gJb{sxvybx9COTT*Udhtp~`0=1?Cs$6!AN+E%np`6IUD`^b zpC`vmq8vVLl@M7XDOzR9ik7I~Kez*KUdpnB`%AM7#Pg}Rr4e_q^n zzO@xNm|x%{k66vCV{yfw=qLJ-HX5yyk`Ut4UCB7`%oTW;sPA95R8#84Jy!S^Siz6a ztoO~w8w zmRK9=Ri(N^Ynp+bEL>a{Ko%q$0VXMn4i2X7bdaChYKld2?GyI3BmpAaDWj~IGgMLT zwo&l^A=<3S=PxD7Fc+yX@leqRTiPm2rYryDvV8kSq_-C>_p=^Cr!C&swleT~?~j;> zeTL!pda4y#iEVb4N?!ET_R9b{3vdz{2yk*s8d&1@hGVI=&GoNk!m^!^;7`cVXQ4-3=*MqNJ2K)++XJ3~- zMl$K~9=v>L4b|;aFzsbL68ubiGQCG5bma3Cc=|gSJeI4+r2Uy^+iN*4#jsiIQ9bQ# z)s4T4_|nNy`;HA%Wsk`JOY#Bs1;U$_FkgAuATTiMI!@!G;I0KC$eH@w@ykuKv%~jB zRS9V~D1B&f@Ier%G_550`o;$$T|YmNB$ z_-bqyo4p?&2x0UULG~}=S$+)$!gyI&L_k^4{L4c3lBY42rg0*A$%m~|A~pLkiazlS z_S1M6c!F$c^1J;Qe9sY87HaAz8Yfy++>#APYJ?Oo2?ZINhcGc^!c!u{xmf7#Nrcm zU!Nql`~olqShoNkvxw)?b)xrmqG5%!p+3?d{N7%}uRb1H0B6oMa>$%xbypj)ql#A< zD_HKBEe%W%!uXD+$dacWLnDVmtnK$}Tbu^--bTFDrbU9y64##=9mG&T#Cyq^zei8*pL`C-0s zbf>=N#MA1X=Hsr{oG>Ef0M+XMm%^cS*r8Zb+ZI^LmYbNVm2(&;E{wX`=0728=;}$J zP{azpSkd;ka89#8OlX5@q8#@y6A#<*mPwOmiC}}L zTsS!Wi&QN6IW%g(IM4FK-C2-u-I?#{WSJ%fsOtDZ@Ktact&397O&BgmQY%#|JK0dP zzOL4dEH66%!IjtENB7&!hr+s_S)oxAsveRKG-d`%xt#GE9VSRJ+cO%ub2h8ycFMly zoHf1Z`8RRnlayF~Z;7r3Up+V&j<_d7Z?^Nft!F6v*q}Z}$;{n6D3h#RmIAvg z3%LhYT1&iQK1?#6iWa4&cNjQ2hpeb7!jfWNXg8|z(?-<`Ff1e@&eb43hlAU@sJAxX z=*e~Jpaw~UhR3J*8EzdeEpq0)X?M#nW09I1^lH#Vjj}Si9ep6k&kHHh5>NL3Mr2Z9 z6C6eBhm5~pcbrg7=IKs@EIvM53O`(}f(!3RVT1X)2pA|padz!XM&}zlt4z~U2BRfm z|Ic~vs7F6`mpEi}RH6=$!2&l+{$i3B7yb{nPW!(1ql>*)r#C4N&S|MpBqy5Ra2rb) z^$~P#M#ydH-RtC4B;xvrh;Y)IrNJ^!CkvH4lCR{Lcmd!&rc6@n2W%ogCm(Wg@@GJp z%}xy8V2 z{_bb_^ehIxft{JDyW-R+WZlbn-{pwa*vyyH!W3rls0u7Le1^W0Z{~q$8RmL%W z%40@C%_4_r9`aoz9X@W>h^Me^zX{e-g#NHWNs8~$SJ2O2;{;Z zwQCQA!6KqsqGW#Cx!*C>Y zS2Jr<^b96tChi%GHpoZDE#fwlXe3ZM+MycB7%KHzl-806lz&^_)>TRP{`1J z*k*Jrg5YDRUL?7oJ-@)&*Yfl8o78o;MuQn9eDWWU5BE=-0B>(^Wdv#%83!Bo({xre z@`x+ta)&oH5-b)!LQL|ZTe`{$LeuRR- zk%1nPN2Z(-mOY#}R5P{oI*$>{hs-)%Un@z54pz!=YiH-?qP7LxMs)_b4M2f96uuu5 z#zlFK6`2z(_gVM#;LCUHik6Fws!Dr^HGf!CyHQ3{_-3T#G?B6eSlZdb$WYRm2!DRU zx#1O${Su+fjzKpdqm7}Ou8Ym0J_z53=&ogiL&CVxBjGm7*2b{_cpOTGJ;rRawYFup zRR4#vcZ|;KiTZ|PCyg36w%NwEZ8x@U+qR9yHXEZ+lO~OA`#I_VzTfqHc|N>dSF^5_ zoONc;%$_}a|F#xEKMR166707hrXrqavkLha7y{5%!n{0MC57GXU0?99Z9vLPy-kRSgIOVRE%`NJ=^@_@K{UHtNPcPtsX109XByXoOYe~zA1eED>8pLT_bn;}qUTv-h9Bm=OS5`_ zxp6+-*Irfhmn1;-2TF3EcU~W9g#gk4_d_~R0BR`Ek-3pnLdgj9D&_Z8-G1<)a-?x8 zCkyDbeGr&d0D6Iq!MVHTF?c|GR%8Dsu;j>bGTu$g?{FC-qG?kWk zI%q%0rAT%K$4S$uYi566S3W_^sgR)t(vIsr&7~f#1_7gHW&)#z;(M5F4@YxP%Nb0f zTU*OeSuIEiX{u?GbToS9l@7?%eOPyBWn%#)N0-5Q_E=2lXVP+GQ%9OCx*1S_g12Lq z>F4Q~{y9)4SAR~VTg6n>Qp!LxmIsOqrXSlh>vGL;dSM;xL$L<28~NgDwfw_BTyOfC z7Qi&blC>r?%6m{oSiN1!e=ivyj~%G#dMyi zAZXLn&JyYvsbP&miej9*Ylm;u1Y(y>TvyY#wHo z)@GV{f6{wD?tVV2{DSe{%Ws$TdK`8oQDbjP*yd3k!}t?3Sv!7Zj>B-v0U#8pMo0-7 zKzD{8xQfBSk%^U#mNL~hp8$!!9H;`8$$$svyL5bxZkNX`gU@9o&Ocy9U-M+G&C$px zXs{4&&Ccwb>s}jPy-b?U*dzUTz4DR@<&}5?=E(mLi!JC+E%6#`MH2h>5b(xHUF#~z z6+dxD#=ajbS1xGTv=u{r80#SH%zzc$@_i)6p^f{NDrz=rzKA7!bH=9NWG&Cb6aRvq=>%u1avWzJ9NaYg{PWGZRB zD6y=sH)ZRc7#tiNP(@X&_dq_JF(3dm7hSE@5@H~}#bj(>Rrpwit!Etr6f`R?qG8VG z-)k)}pHQ$zV8wV6$^l#g8aj?ffYFp(`$XF&6d`9Q4Z-XsHoI-~xU?T7OLPLg{7Ou?I5YkRn0g8APD z0VV$$-LFjmPZ&3qNYx&IkC-Tc4^`0uaIXwtPD6CC<_AG^4`|^6qF<*$Jg}HIqiAUv|%o7nH>p)oP8bp zq0hIDi){Z5ig$T4FK7F^5eUdf1s4*}`zd2Tw5>lgvr?>h;0U0^L9G!{;5aNddQd#2 zwwvRH0xR&lQIT3c9V z!_J>7`jM#-R5WH(tfC;4a-@sa5MWE%9gQTx!ikb4tyk)er*nAzhZ^pWazEBy2-8T{WVBNX`X z7k=@+nI#3F&xmH#Zvr?LIZS`G02N|wP?kCMI)ZfW^T-8d3`fyB^U164`;gjaA@se? z7pY%f+*_xYNu;-&E`~!B$N-z9m`htl~u%xwWhhzy`?fAo<@7v?P@53f^mkeQ$d=gPm=kr-dVq#*6N_mX~ zE2EkPraAd<{4S|vD@_cViGoK+8VW2sx#GmpLdFA7p>GO{!^W4(S}UTfFN1@F4M5ZA zwxwnIOTZHX0O4n6XWf8(&KLt3C_qy`mF`VmT7Jh`czH2{o~ZbmLhz+r8BPww>(%#h z7qj!t=k3vy8~UQwjXbZ;)yJp1wsu;zc(_+-K%%#moW732jx{evP4X)=NW?1Lg5Mt? z&W&*Lw%AjsV%)gQhzAIn+wi{6mW9cu6oN7T_69^U-QM2D$D{njVjqAu6c{PS{^gr> zs?#qzVZ{yhDLxDyoP@~Mq!Qkt)bSP49I9lWy|{$dAXO- z>LqsZltp)1pOt&4F(S0IyabC|;sOgm?{HauT@()&f=q*Uo;W$;7ymM1#?Itn!<3YH zN4)zLMZV?c4dZhFnu|%|W*rH^tj3vk)+_*xwu4nT9_(jiV6b^y+p`Eugl-H&bc%3C zNQ^+2ESbQB?|QEf6k}{l`_72sWO0saHFqh`Z)b-Pa9C%wRdUGiP+fO`{uDV5`wHm+ z$IUQWf@7Po@%y*O_2jopQ;Q6fN!~yn`A2^JD$r+yPoHF%4)@XxC-N2N?-Koje{1s8 zBcRb(P*lf2i`FJR8&VIeFVyF{=Z8 z{&<>rOSTbA*<8(6$ozMa3?uMOyH-_Sf9CpzhC;59U~dz9dlVBwOQB#kjSv&p1;L>K zAth7fIw677bt#zD;eODMR9Bv6g`|SGRa_tZKc47 zr)SAAPqugCBoLc!HR2~kR@cyY1e%cESbqAqTsy#bpNqf#=9n!>i(V{Ulc^@ub^MVY zsWzAnx^?)@DlQ~VX%@DxWQX^V=vud!X~Oh3n53vPBCk}n@w_I zso~BVV{#$-gp{I64B0Dw)yo$jOR%WfPT63wx_-8~IeC;Rl%9Ss);(li!Ej=n zydx*(9hw2%x$n9AZJ8!fyFm%_PXgHSIt1fVa zyM|nq_wD-xwI2iUQUU}Fvgi~1<6&v8UASE}?R0D}uRg+4zIRAy36@~7s2wV!Ze&2B z-*$elaPcpB=)@DBgA8s;HrqA~r9ExdnD zlqpA-m^{`AaK^6r4q-%`1IhZvof5{O@-(2QQ`zH2NVEd8*s*xTAPy1}8+-dibgdt{Kx<{y|C_eum+1#qvH3k>_Nb&Tp5$QI#yRav|_;p7D>5tyQ7t zv!&6R6?qk;i-C(sy~7LeW_G{7d1fOEQjQ@DzC9f?1kDZ^&U%4Kap1TWBw3L1Q;B8H zcd&BIU@j{6^)Zby$=^1~`1VZ*COu@$=@G}n^xtc~2D=k%CCT!e#3S|TI5O+WQ>9jn zlG)J}Gr+%t4j#L7>L#_%48k`O*suVHpgqi|ao~L0a6wq>wLXYTUfQcS0`*2`D8T5> z=}%d>?=lQu5Hk()&=0CZ<;(jBB3tMJkR?EzSX1Z1M=C#G9`uupe?qLP!#L7+RH7E0Aql+g_N*F~moU{>3#f=N!`iGxaeotOh)Fr`;p0?}(L+hLP zIf^;~9^OIGJipZ6;bACVVXq9;1{}4C{h@011$AaXY$GUcS%H_N2@?w_P24J3oUOGL zR#@y)v;FW0MkxqGfj8UUHSGE#ZC)LNM6O)1Ha!0%CMLGw`|b_!)e+E6oXE)26L(&s zT}Fo}gP3}=w* zz4@FHV&VBsV-hqr88#hDg9O|5OmX3b0_ToFhDlhsyw5b+6g>&&#H3lH+`sKJUGHL2 zM!cJ}7b>GiZe?(l8?=&Is#H;+Is50Y<`w+~LfX3j!|phn093(WWx`8KvXeaGSwOBZ z?!-&K-odI$Z^2vpx5Pl$A+g*yc5^r(9Ju6eId`aK4;j=&eZVp4kr8x;#bQ16?d;_1 zA)wSKUU=7jn*4F+W*r)39g5qdWRv52y}7us%cNn8BeY-DyFp9`-!1N;2tJKg`yOk> zO{_EAxyPCk{$Q^MnWM5Hd>f9*}Vyptybg_*UU%r({c# zxLKMn(o_r2qj6CAvc2E2DhCbgnwr>H>y7{dojwR8WYRavGm=!i<;{uZL+^Xo^*z)% z8Yk@-YNpPM#*_7je}#<4Mnx670dASU(xSS62xF`ya<+GJ3gR+#cjw5RmP+AAO}Kg{ z6jsc!JDNckD*MI#xRWR(Bosr#W;eA(fQ%px)(e&u5p=eG#B!qV(3V44LcikUc$rs+ z7l^-*oSeM9{TnBSNdBH&yVOMEAm6jw$V&BrssL}kiledd!H0d^C zy_NR8B>Y^r^3Kf69B@T=liIT3^BnkzcX?%HHWQ907f{K8yjc79H}95JYe1b_(BHL# zF(fmNv~*`wgTd$L2BFI|1j26apMY{zkkXMm-vzs0@3at_ypO9}bb&+00jO>w3b%o&FyzW?t`e2$2Yo97 zx{Gj&OhCQf!~Zl?@A}=r$|MhGS@Fwfv|gJQV}F02X~)gk`F8Ey&{T_^C^R(m`1rUL z{NH_DM25Y2WA;^4o zpXO$ADRnt60%I=<7$C?_y8O-jgSNlhP7`WR!fz<+e?j%e%2T3G-C|n7ir^r;?%v!e z+v38ktgQ`BhIcfAK1V_Oyh+q7c9$m_mQlUuc5z)u6T;{0RA7#NL3 zN-X$^pIH9yXIOqzeh|=nWEdoV@e7bw*!Voo-dAX7SI^$wztO85cdu`u+h?8|-g1uO z7DgjMOc=7IqM(nDRNGnKoAuy9U;yvhxyryMBzSIczwl!MeS0eNY1T? zH#^?WyK0{ZNSwizO9xPCELhMVxu7{lqPA9-;G9n(ch-=K{Pn7%IL)w*9Y5Ci@Go(y zA&A7}qZfwYgh_*JsS}Q3zA>>M0lxD3JaJ;x~Ud$RS6HnxCx-s9%!BbEhs8 zi9aoxexKjx>_dXQ2jXSv(qi0t@FYu?FI?@ikxje)jJ-kYj~`7o)T~ai_N{Y;&WI2; z!0R2+Fzz^A&$O5ZI}ucukkGP6CMPKM_HLylnL-R+8qvZ1ib8BcXvdjl8Wt=7kb3G-CLzP>tL195s~*Tl4qC5C1B#$o zHz{hkVO`lVXEl5Fq{;K^n?sx1Gzf^3zckOgM;Csy=<9;%dXNx74t~SS*IVo)Ltbx& zp`e#k!-F6W{MgrILy)*%RZGX4cFSh04sF`Z=|)lJ(?Z9gspG}2J^zj4#ruBylMy3w z_u8G);l`uur&0YMo9X=qXb^_I_A`s7BPY&sWyx!@mx!)d-kH2f(?Ob^E_5aORKx*! z$v-cTq#&ehG28Nr^XK>GFD!{a2e<8qmt%d&PhC7Yv)|zL2tWt{Cq!N!9M!HFYlSj3 z>jS{D9e?QmJW&_RmL@`j^l{-Km6)qmE{KzE+4|0}+C6N~lkhA=^^&zJBJAT8WBKuI zd315c2njSNUD0^DA{6d?8L@xxhUA9?WiM*nv7(nbE;i4|Y1E0rC8>lTPVVzhmJ!3& z*@!>b5no&9p+`chYAuh5`J0FJ)NDP+Dx-N`y>xw+LviBC>$UMdZA|u;Ka3fqH}jkA z7CW${fO1l?UI!1#G5jfDqPQ$>0QRY++WJQ4$&?hY7C%leX?kw{q4~LWke32Z#O6id%6M? zhI9#fz#7d!el}6dFq^3m&%+Hd#oW4kPl+KczYc8Wm{G!_pi(MS@cwBvZtpA zN);yV+UD9`e7_8Fd)`@H1DpW7O2188wsgKvf5xUIP+8WLSuZIw%|yIoKnuB@4=%EQS+>AGSD08_TpS?)1}y+s?s%#8e4~dC3qiA5 zHEt~3>T5Z^#5223VH$hPMwe#`2Rn!#B{;~%+v~GfEPnLJ_IN5or~%fAo+5t&Qi2b! z<8on|N0(1pAr=Tfu;uEs7(c!CfcOpIm@M}&!bG%b&xv*O^%$c!*#3Lb58c|t#|Z$K z<;<3Cf0RCJd7SvxbR<{3SIQDmzF;Bt9Uc5*EkGD_JJY1eCB`XJ#}D^dinY(iui6MQ zqJ^-Bf(+aa=ZXtCBS1kurdec0YMP(eK6~gCpq%h1eSMPt$K!Ng_1YJAh}-+g$&vfN zX(m$06;Mi6hyiTfqD!@Z&6Rw$uD8$f<$vgYK(1Uk>I;Mh8j}E*Bdj8o5pynPs9E+xiZ8vs2-BvrI zhq8)=qn;jMLWBSw&F%B@0KngBHQGN-8U%<>rI>(F9eif7=g2VDo=%>L>Yf zW!^nXsDG=PHfgeb*}8iA=FRJPxiz$*7vcVVclzJo*kNjQyV?QzfUfaRuWv@o?vGcy zdqCLM$Dsec_6aM$-e~9{k{r|KAUO@CwNPYv}*`jUNw=?_OcLoX9T- zVMTynaKUwl4SkC1A6J15=Gt^{6#F*+o(swp@+q}_wKfLD|R+Ie65$Un9#BtC4 zsnUC+x@ol;WwxGnIL$mG#Gv*3IWQMof3N2FshePAw#+>z+)PKUGG<$U@0vUNYCTds zs;*4)7#f%pz^EV(a+cL)NeN*=$XV?*k?+eb;IWeZlyHC1ijZaat@YtZ-4F#-7!}a- z{VCD)Um`umOAjZnZW*mi0K=7%&ww3`V;OxvMHzOm1d)m^>%uc7Jxp|RF zhCES2OUu*8NA{fwg$g4Q5J@^ZI#Z@)Wo34-3m|Nu$$h0$Q?klY>+9=r!^6W-OaOX{ zLPtkuOeMCwFq~A{(9i%cc>rJ}{N-U`VJXbS#EJ!}shC`{4$jWOE88zGYcYvHb?JS| z4+Tj9eR6UV8wVR3cEHZej56=;&Sm3XOG}H#p}eAEjOrVpYyw_gE-tRx+S)@?wAl!Z z)#dPTSQ~|Lb!X=$Dg36!#s~D7-d=w35EBy<;xSa!X^seUTU!P>Oeb%^1i~0Bn|m)r z4*!pktG74Zyys_6fEF*WsF5eY!1+Rehh@L=w6L(SQ{w}I z`8_?QM2c8bQ&WLyMMp=+ynL>zlkWwzKOPH9%WLnR!a|a~&CN|l1i2vCX!?V@I}Dk9z#`^169v}AE50}?EbOnOM&8KC2&shKz#!V) z%?+zutKG1DXH!#hAwkbNEj_(x&~X_PRP7EUf;~GTjIG(my}jx!41-l?L;RH8PGv=9 zCCl*NLQ7SYMEU>Xz_LQA10@$67@Y}O@cfY#b3!M6F2tZWvr>O~@l#f0 z9Gc&jb?VY0!i`BN@mB@xur?kN32SR>%k~MtTBm*e`jvN!6nXaMrtu5K;raPULp`7z z$0T|^PpxYNk3<_Ow4Us#2BwdkvTr%3Wc&W>_8&)<=^g?t8v>o{)Nx@$3R}@ z4g})M^2Ll^x7Q;LPMO^x4d`&oyB>HgoSOmv=OYh93_esrEWjp0f*+SK5`i6;n1ji3 zwEKOD2PbI<*RMfY21(|jii-GT-H=ewN<6J!tbvj>5;GQ)vOlO#{OvBa)6LjNRmD^b z3mzW)K`!m}rcf=*QPkYP|3_hYIV|6HN(x3YvLT2ok-@--tWAfGSklF1p_sJW#hJa# zKoF=Ej(U!cwXrT9E_^d)+caMB5dX5*4t>xmOeSh`iPt1I9qbrVW-iOWC1kU@PFUHF7~Lj5du-u6MFO7 z3P>%)C5+?~G!+68!*dc21j2#z2&Av(biAeT;6gY@yt;M#?FU1p^qj9dCvMW}0R()D zkg78!GMT@45s0uhB17SGaO%<~D=weCNJ0?2UhZ%=^q9ryTQuZ&5*odKA~%1dVj;u^ zKg5oU^1nfV!N6iBP zqCo?Wa0E%tx-3#;7?`cGBw;8r8%m1&hmB+>5BHsvV|!lKr`fAVB?8aCjo*iZg#=db zt!O2xHh|#fa&K6{3&H_3I5~n<{Ngt@6<0mSM=f|0QaaYO#=#%6_OXUk$o3Nd9|8E_ zo53m9`LG6nJ7!!0_?S`L(06h0Jyw-HpKYy7uRE?jl!(?YS$guoeT6u|r^J(oJ?we` z9D!~)iwg^|Tw_uZwLKSW?^9V$t+$Y|_?K!1ASzbYbXsGIgoGdlV#|O5tn$HL{SK(W z=eMOtYRIi^@6VaVrF~h?i($)iSL`*rARWkXw%s~9! zVzeCR`g+ExpXShL#k7#bzz4w?ppWv1E|7*QskPPIGQ)OyGxqXC6#99 zpP29X&UU)1Mc+}zsX%|yOCLIU@qFH+Hjmx!3c|g63331E)t^vSkhlHG+xOtjaw$Wx zpU5DOau|smAbrkN%HKoi8!NCbc8?o9@2}^vGh=h#uPFu#7@--qS;F|rk0)zqXSg9g(#*~iZKH<$=D z97YPvhv4aXX7~PWu1%~tDF%CX5Q$u8i~;%w@i+R7Nd(Zi%bbTmXZ|)x-1|YXPmXe( zUY<8&oPB8%_p>Vit@?LrsX)|q%=zyc5E+uG=iN$(P&xUm1YBVxh6yLj_<)+Pz^ErhO zL=Y*a)<~<_N&(iM=D{k`wlg?5xEV7pKl2lhw=La|a5n4g>znWW{2>P=NaT`Kiy6Am zMp6EfjaX&N^+=S*@?YdhLA)jTYr*F{`Z_(n$cyeb2ci_Q02eg10p+&rgTnC?*EzcN zfCFl5eij5L1BJkRba_@0aq2FqIqfc{xWQgIm+f%+52Y8ol}^}C>)tO1C;}bjD*5s- zyAfr&dyRry_<&fHN?K7eTc4Z81)4K(wlJdWa=bvqs@+Y=V z0u!iIB$UgggsdnldjN_oDEG^Uv_=5!iFBQ2MGl#>A)a`$WCf{CH`mE(m#(J@R@jkU zY92fdWhcXkzZys6OZG***^Lb9w*l-4=~T zh6*^*FGzA=ZzMCbv9PgGg%!fyLS3xU;qtgSAn7<9mX`&q9+SAqw7Cfj0$6*l@l3}8 zhaIG}ujYDzL+QMG?+Q5N&3Y%O;SlYEJ#SBz$#FIYK;+Ls(SVWUYR9@`!`8u+P^@k$ zeTw@uPtIE3pc;&%XCy6Tz_22r8G>I{Dp>Ipz7OC}UBC}zOd?AArK6=qGoe3Q0RPL7 z6Sg?1-t{oO!)D0*2ky(ruhbggtk)L^Qeb{H;C!x7sr*&r|Dy)O+YxKSl50v2Hh3m7 z^saME2gW*dBSV33}&{EgA2C_m*D49(pCXmAa>p&l*kCk6Fx{7cvydV@iGXXJ{H;k zGJHR#^|O5*Z8!=YDqwx*gRP1wYfz~4Jx6$JQA3!Eo&kJNu7E1lJLpw61u(tKtD zR~`8{&110ICrnk0&LdxLJ-ZJiZ2|^~3cwal6yqs$*MKxZFpkgU{whaSGy1%fktdi2y$VMCd^UHb!F3qz-Zd)^_Z z`G_X)YDh8_C86m|1&bCA8V<3aB}@W>Lx5pV*yNc9n^&%V`paEwoL|nKecc(m-L>d1pRc?7RgDB7&V;g06vC? zG=)w}ly5GMQm9oui`V=2DX-qcjfEuDpRZxUhQ5j7bGH#NTjDu=Cw{tY#_3OCOWAv~ z0eM;j7d|~D9x6kHV}w?;8MOY?l;O;jM@hm0=+Zd)i~LFpwY(k#aC{xtJ?9)z&FHM9 zgRfTljlz}V(>`}BoQkKx0EcfxovWY+-@-{JcDYcj!#CgrNSsh8ND_x3 zij@+FFZ=Ra2`|UfdXHlTB9U>wMm-=sR%T{Hepx7)Izi1kG@1Q2+9QO?17(tQ zw1k|TTtpA#rxd`?j%ee6)~3F*VBB#wIF`L{Z}^cO2pUV}wVx>|->L*#kb4{^OdOUi z5K|7!GV}dqpKl&k3W#~wjEBqoYHi5G-$8iFCS1^UgVN9dwFP5!7s9^vlkp}#Ze)l{ z%qt_JgPnf&>}(2!Y>~rZ_6SBm1)bG{RaH%vz;pM`nTF5#-UnJ8A!ef)GQKyTpU{T% zqSby|Hk%Q40z zE?aA1XBpw&djSZOMSnsV!rsh4CkgR*r;3Ckkx79Pe28d#ig+6&hhtMTbgx3aiR#Qi zuXd~;B?MEA!4u3vStjDT9@H8hHWOtR0|O$#t;4cY8u26|uZuotpkhiyc77aM>)+WW zVd6uQcK0Ge^wI5`cr#PPwjsjrJ2W0ye2M!0dq7(OjT;L@e)9nC$vEj8n?#T3bU^73~>iamLl$ZR9?m`xQNx z4@-~T%ar#wpvRGWe{aa|wJPb<66OFQBEJAxCecp`(@TM*ErtgI6|=NZE)s&GKJp<; zh&~5Ke1F?`&y3MQHGYB^yB12*n>erp?U9;! zGjv6jxfT~tKkuDpG1TY-QhNG_>bC@;o@S;$Rlp&Ap83q?Mw4KMdR)-q9&~6l1u77x zi0&i_mIzrA7C;S`A<#nVM%qUM|KkYCh)D)Tr~*rMNLprWt_UwR=`?|UU4C9!iOuol zVD)Pir}NS&+jWy1sNErop4d#lJ9uhWBRvG{p^$WWlVPt5)T2?Vj z>DI9+2|PjwrM0g6?I6m)3?r5-yyTon^`Mgq?ZxP$4aanGt!0%>m3`GsTt%%%mG=n< zuf_)A4~kY&0TvfnNNPWjBdt&~dHuY3fjz=F%)s6<4j5$)CK%Qs!nJQ;3QVKYNRsCg z2>lC?hRErGCqfY~QrAPH8yO|uZ`Zl!r*_1EGBtw;&yHyqx zCvCOBdPA{w;ZGH3j#|I{p|&Iza3=d6Ha#Q89U>gCD$VL8tXQx~qL^i*D&|j$szk6! zhMKB?WqePSN?UR)8^J?+j-KRE|4e>FVmy(wALxKS(*Q&0+H%^(%QJ1Im)g1kNFp}^oE zOg7UUd4uIrO-?K&SU7VKP(7ClHT=g}@4C#hZA2Ieq3qg}(W0LZs_7G9%mIS^7K|Bb z!_luqjn7JWpd!JTV*IjrpxKC5u>eY{JjJ(_*e7cbvGYn&Mgwf~1c(%eJ%m*RNz8JT zn_g7l^fo=+=t!>)EwafMBMreNI(>WmwApe%6T1#SFqOi#B-`fTCZr;w zD%wswu1ZfPAt@&n*fzZ3P3@AbS9eUG)QYcMc`Oi71O2#TDEG-j9_ogWO!U(htstQ+ z#9W}_h3bsXCuWjjM5a-rQhZX^BY_aC!9#%zbCdu_js`KFuor=5V-vZ;dbKKbf9=P2 zF+zoq-tEkd7ZXDA?AhwEow&{1Z$Zo>l-gRZu{EOszCLR0+s4zgIk zx-A&@(ridwY|!E|-nm^o(8)cV+*!Rqcqj4MY?4+**KiV)G%@Z38~n=yHM_MTOYnBy zIb>xmc6*}>NS&u}GTn50Guw)DY6d>nlbM?1McOn@dwy>j7g0{A6?Mz9%U112juj!T z%uPb}R(CWowkJ7r#1$CuOa~Sgb?(OIW<&k?k9-$+-ajxORV0U_akq!>BMO!k)dEv; z-_SNZpVmn(4y$xnU4=(_BesZx=rxZ0ekp&Js%RVA{8}BjU2-hv%F4!wbWt&5 zlfo?lV=4n)3cX1hpdL#CYpUdr8=5rBJbWm?J`R@c5%-s^eOMc+@Qsih8(jib@(Yi6 z*lZv_RR#1PG;#hA{PQ#vV%X@7iOM){3tp$tb8|R$|;M zHuteiYIlkO1t^CPQ*_6v69gvlwWr#4T& zeb-l-IgjP~VLp+@B*%R@2xO%QiMbG50;OGgtk>PfiLT31mjY|aw*7*oJJPRj2>;+2{h;>)SEG>C z)%`RU%rUB8vgmG9>U<;+u$0%)fe&$4292Uvq$hn;0_`u#p+A**UIU%)1u_Xk#Q5h} z(0jHRdKcRe`QQf(5qnNinwE^GXUAIyyuUDZf4)$tI>HZu8v=U>t%SC3B7z<#;Q++ICp38i`#rOQ=CZQ8DVf@Zzjjq8 zE)`yAGQyqZllA(|<9Ao>6n~kAd9!qX9m=!b5)Q{b?&p&Rpg0rLmkpjRpi~lCr-+BX zFE{$$Zhx)Q(Uf=UIGE#~x!^*mmH{xdi^r;_-qD046iF7GC(%AIM^M-mWE(8#q^-tG z4e^8^sE|ez*-sTWG{(9@pRUG&6@2Au&OV{CMA1m9v%Lu9(cWNDAxi#YNMT0iU5W9dmd`P3M`19(@nKOI>O^P2cFec*24O1aU_rui#33!*vY;41&A%-dw-lh zd>~gKclH10Pm8?T5Ysn>T|3@Y3buZjPO!!#5>rLOwAsAw5RGO9gj4dt3~_x6QdkaP=oiv6U^ zr;7}d4uK6TGdc$e%fd@HwyC3(cAV18a!j%`3ct?#4;=dR1-f>~wif(S*(DViu19S; z!EGFY(5wRA+dWrhOEyZzxm?JXEGQHvo1XKAoxjs7h zL1&t2#EhQ;#8@#Q(3?3>PY9;S2NCPL==m(tnyl%}lE@r^APN+v5cZRX^cpUglJdXs zlJ=mSdBmgInt&jicc3VEUSXDSx-x|HUl|#hs5p-?m{I8ZfD&tnU!@CJtkc_gLfD}2 z(cm3}g{z{yI6~Nc`MiWhTYk3iv(BZasNoi_rDt89%@oCF-aGiex>gry#q<=Vbev5* zu#(#rNOGNoCjX|C>^eFLA--wXLw~hy_fXIg(a>(|E-M3s0u(X&NcLgsbqd+=+#nBgGP*z?!!zEl0l7W`e z6Ddc)`@?GrVVUNM`3LNuR@3PmnP9XRAlvqvwqV%#syfO3I9ne?07S-X52SIQi*Rz5_2B1dMd0O zWrJy~v7SvUR3=Y>a|^P*^8BXvq~9uvZ|eBGrlDjP3{oR ztQJFu>)-DX?jH%Tx5*cj$P368Ab>I#m6$irh_(863&zch)ko>jE`@#Byp10-b3}CE zKOnI-i1^aR4TRXFr4O;Y@z|hyzDB1_Al@1ct)&Y=vtsV;65gjWMWR_S4-lF0oAkg& zSW9bnkNV3bit3^)J#0I)A^*7gsPqS9^C7V}y71xqn_J zSJB1z1xhDmt|2FNQ6EOWB7ITvc@(V#J_k^{@fbx0~^=~@C!*#O! z5E_imhMr2^x~k+w$m3{lGqR8h`cKO=GD4H{pYYBLOZu%mz zo`6V5elLa)-^xoxO)p)ZZp?lRE0!zFyQCT!>%s`(sIfRaVj<}bsWK;Jt2g+nURF=W|X-bwb}X_Heh5`auYh5O3k z(HQ@-8$6*hB0C-{^>+RKi~KOKOV2K_2CO&)NqBfsmqs0~XKHc5E?f&<&mBTy<*`V( zXH?iI^%T9=BehqSZp^~&S0BFP&lLrP-I#Y62B#OIS-vRzxCwA<#*nn@_|c!^2uux2pFHLtE*uw9*_0j ze-mtZGA(maP*9w$iUCU)%=g+`hfl{?xi=jW0!cRR01q@mo%xg3Ef6>`XnA12M{%xC zpTiq$KRPG;dmcF4vzpB=avNGbK0N;|n#okw&(fbWc*X!}jagwEhIlp_&e1~SOAiA5 zjKB0Nke-a?msxhaCAa&ko!RmRRb=yDH2GD8X;%tQoEC1fmRe>hTYUu zRqx2UG0)H7N6xvY!N9%Yt`c`Kuv8TC$^|sE*sW3DkezC3d0g}=yq#OBb^6#LJ|Bx< zf2_(_*0js=4}<>}i;{uCRH2ou?`lEhgX4AzS&&9-Rs$qs-JZJ3N*Jj$tl0`EL%@8D z0th?r+Kb`!v#^=-IL?63)(w(jNCSF6&9YaF{R^bVBMNmewR71ZAzf)8zttQ31amUU z&n)R|Wjwgo;0-{R#J*wvj&UnUX;yM0#NB2|1D@cn0bqv0hJMeGG{`XeqKwH$R77LQ z>)!V|KFxw5l6-H-;lc&C$|A$tEMiEC`Kz8FbmWeoaF-Pm2cw^x0iSL{5$_n8A?i-Wjl8Cm^=*`W;pAJbDZvp(Sn30yFES!UjGD=P zaPD~eYS+>;kRVB?a{MuNH{e24a?z>(IDG}Z526aCIV-UH`+%3|m-ShZ|50-= zR{(JFveewy6H`pby*GeY`uT05cJCg&PUZxal3&(NHm$+8D9F&hhfPPkkA(-^79f1E z>3Ape_QeFtw0u(zDj>yc%!l(cO1R1W0Z}!|UREKfayA4Fo0-^Fo6hD9X!V0tlqoWM zF?>H@HyJ*z*@H%JAiQ|9^(RnI{q!GaL1`Kgq{HH(CdMO=B+Km6juIip!2eoWtASQcRluCCISHl zN?|uv=-0|~DPR`jCoq;#;QfEfH059wLKp#P6eBnZf{XrR@|p9>!}*j6QeH$0Q+tVo+w*qd>?KWQTh03&Go-1nW!w^^`!rNh-$MJ0Jxpc9KwMN1cM0rvO& zpH&-=s~w%2BnCt&_-pLY;k^G@Se-R}2)sh&>e3*+5uyRat|>WnmerqTkx(G+f?>kw{>Mf{L0CXP75DM+F|Fzsn;{hgL#&RCctKft z#Psn`nBvbnd&;RP2v%hPQ0u+-z=ZX!+xfO>bmMU%9vq#2UaUr!G1Pu^rV7&-Shjfe zKYz4eMoD7jC(rB@LVozZ`wZt3i5I5+TT-ac@%GD2_A=C%Eqa~zqg|dZe}&Xr+;VKp zu|cJzlw74E$)yr_{g=rvJi1J$vNmIv_H%vLcO95AK?vA*?YvIHM5m_2M*@4ddxiQ6 z)A@{v@#m+aEzefEP9yK}Wp~f%w8as`O-88Ro58CQxs)lt}-W>bT8m6#Lj-8MsY zt2U2obwUSJj&t8$=0iU*B83%559ISJPSOWHxq{ja z)9v!HZAGPcsQR|a1Ad`(c6@)L)p&u;)w<(S$@NdnXM;!+&S3$R1P99xxm}=#p@F_> zmuBHY5y>3%kz$%+j3J^f6M>QnEO>Y)If=xUF)eMb_rZ>7EWTjc=px&=+EgZ+Wq;bN z5GOL5qK<07GD=V^VSupG=U;QphaK@`Em8w{2U!yc2y`}8HF#ft7+)n1VCu0!3Kib} z`LWrz>UvcZZHmwBV|GnGIA2r>xgyeg>caPOG2qQ%o$Iy*8@pdnL?EsYsIhh5UnP0_ zFk`QjT+c_8Pv|OZ+FYihu(!oxaeg8F1n&?1KSX^~cwKGR_0u-CZQEvJ+qP}nww*L- zY};02YbTA(CQb9Nyx+lpwy$d+?6vm1?};(z9HVw`Psy9FQjdU~(B$GOnwi12wuWG5 zhsW+=+^nf=yWRJ6AcvE`xxgnoBlmBOlqnsy5BTRvV)hMpdI1rBNTzj}h+z)`i$>#I zX!CeMho9{qY{;eD^m95YmFvweljkxw+;oQT(o+EB9S-+hT1HIDAFLJ$EG(0np5rRs zs**6~DpLx?g#EhmSQUT072O8MsIV(o`uSfougNW^A&t;kX?X)npl|+ry#O0oOH0c| zF>$o9oE9}7#q-5Zej-y4UO>Q?7 z!|em~9wvB|e^c*d0F$n`7)tWaJD2al9W~mR_LGCbVKdzVEx|KTFIazG^CpLq{l4@h@nrDi@f7z|_SE;Z_H=(? z;zh^%r4JKtOT(opped>;t*O{V87pS9V~49g#JhqC4*3-WG@n_fh(!pPOZ-;xLK@3T^^~g%Y9)U{5}JKAX>lv0iQ$_h^2uXwer{To~948qY@|Ed@u&iy{pltT8#Gd%j%%Vs?n~ zoLSfzo&m-nUp^nx)&Uy_CVp08zAg4B?U=fLy&}(r0ox z{HD`}HX&P=)Jdx;5m~1~GPUfRknozqCeN=10z=#dyQx=D>le&|tcn9AuLDVn3HfwV zVEB}Qe#0$oIfLVfHEc!5TYUqNIFTTGbAkd3*vg$fs;NY<_`TTz3JM>AWfYZMsw_pW zB41%-wMz{}Mf7&J3UG1^82VHls!mfCYbORp!K&z_X&mVg)gPFpac+*L{VMg=|Ele5 zG6;Lz?vLXMUe8LNAKTUyBqutY9lPd0<`Y6{YRdrshwE*`bwa>j(A}MLI$poPw^GE) z-BTa8H`%@eAmnfKOxRPAb%$3*CkM|`@V3PehF!@*jmF6!yKQ5f(X(y2s!cly4J0+} zFM+3)6>i`tPXvm5J}<*nqnd_>#Q!WOtgem`Gf26J^u;1sk_-W+BuLUuUPb9f_2p1F zA@@8PPzs?>4*V*Gl4$}fRO>hN_nnZnQVAN-%1-U@YSy5cWu`z-a9yFhnTYTz4M-Z+?b%w^dm}nF6f+V@*gO_q zoQ7s|{*H{1abuKykzj}8^4Ef@Fixis+ft6ws6AuZ3&pqW2dci|dYVQmQ>}k{A&BLk z9)(mQp1=SPc7$!5vOnNH@k=q9d?XoMr@WsNy?d7qRBxEE_g(xj+)5xk3=2_S=~`=o zN{=vPkC~4jxuO7Uh9OpYG?F}FD$TN1PEKnguoFj3DS5py^*e3KW?o>OM3Pw(E0q#B z3^LQurgoCw8<2+NKAJH>w(UNi6!AlH8YEy;R$0gu02w0$hmkF6IOmZVYphcdW^NDe zL-k%{S+L5f##soAyUazFt2=OnbeMMOnGu+>l;5wuD}~?8IQXYH^=EA>s1pID{Z$c< zhy^tZJ$+?nS!Azjee=z>h`vI&fG5=$7T*$+``TVd$|!c!kE*L(pL2@@Jm04xRD`Np z(8^9GXK24kb0-;%R3RcPYNLmK8$^B*@waR(lJe^6zY_}n$=yvapXC0+HL{-98qM%r zK(%n^M;VKS0Rx7Dem9>SPOOdvV{cCL6OCBW|Me!w=lNpI0~8*o!KlsV7oBCawJeN& z^TsA8NA*Pl4eSlaaVvQ*RrFBc1P`mu0x%z2pL-4ccx%tL|@KZjo_;ou7 z@OZ!gnJlZzd%rq)`mpb17q!nH@B0`dKm z9>&QJ}mkHxP!4JPVqu4s>=1sHT(^&xSD&Cj? zYTNO)+3EJ8LmqF06I{Z)=8tWAx(V90ys@gNQZmgV|C&)&ObkWHC~$Z$;7+1WB7i|A zZenK~Hs~F`9BoP-`Y->P8?l zi`cJt0=x;RfdT!?BjebH6ccm$#UhBy@ z7dyp~O-vQIU_;VO*AyZaVJjp9!*8d_ZF`XGu8$<4q*ez7@;Y)5#OWZT?u3V4)cvk~4#)l~g7DoNem5}J5@k73Gy zdI&t^CISbct6P#=mwjli8%)|MR+9 zT3Z_{SsGhRG6E5#!tA>RQEjjd8^dB&w!QuHW~)zRhITgt{mk(U9K_wi(8zk0+Mf#BQa%jk)CURkfWo@>9ymI$6JG^QKTB zjq`7%o?eJcAR)uEH=^%EeJl(ag;VfD>3gf2MJ*)fkP3-K zL}Et;qPCUOE`RQw+{rbEO_F2Nt2QRaW6)%z&QWvC^0os(Eu9na#gSlO)L_)9f~m#TQytslj7mg^Z1ATh)|nVP!?P?}owar0K^FLb~y)s2-6m zkDJ11CF25zh64YK6$ghX$w*o%;BrXRDERUZ|6C_Md3Q4OE{i-q{&zT#iT#^!DN`sE zf;M7{dJ29QgH!t5n|<3`z+D6078L-$f(T zZvX;1+-Qc^`|q(%1^t=|aG_aqK=xSv@K|Di6)BpmP4l=y%&pMYEctt{sJv9HKBE-8 z%}WXmeO-2F8Oby1l!Cjcd2ssSuG{uU^9?dR0tIOA-cxxUEo2X+d6Nvs+Jm>C;?ONo}O zjO;sr&S7aZn`}@1B%F6^Ks)sMBdVyE*W-5!BQN8{{A72rvo_R_@)L3z%Op<2G1s`i z<1f7`kXM9QVnN1M6w&M`6~h?;LzS`L%8JPX^pK-c7f3vSuxe$6OavEIjQ#6iMO9Ec z!q7?zR-8qcoI8sh9C>SFZc!`p7`*U@DmW}?v~%R1$(ifd`gcpqY;J$ozb9G@GniH_ zJppdNKq0b(7$H`RWjz3S#rx$CaoWXPZWnL3BfHv)L6!?Wo_*Fp&?t=ozl*k)laa6< zz2_G!(jL!O)4#{mk7=V8Q(W`^Ff<0J$KgP+{Zc{qUw?{QK*iIe;}P>n=Pl=4V+eHU;tu#7F9dN_4Wsz=A{>1eGQ zX?l)m3`uqTTMRR&YP1`s@&sGmRu}aHnPI~yK{|^NE2~2KQkIgep*h8p1n20MY1%v{ zG^6MvuhIzkJP!pQe}4uLtauuolto8fWbT1nDvkVby^^9_vS^+hRYvXM2Rrf}q@>R;rmpSZ8 zOHFN2Ois^n{l&bvRE#VItAP=;RTW)jC$%t>?moSeC|`}pGMZVIk=(U_Me*qqp+IIC zu$SjLyro`~cX06(!&i2)sGS(b(A9p|5Hg%{6gmi%pYkJCmKh;$Gn~7*{5~8pU+z2z z`%DN0#AW|o>Cpz&{DwCD&%hFEzL^nA7&e9`^fKBL2hw{-?*#`rxGL7RtyKN z!Am!;EkpRk6@Npl&f-pj`9xszBnVwG5 zr+kn`YELbLD$=^7ucf_J-)ve6PJ+F^uw|=afvv1@8mq$sOiqI58buG#5r{^U zr3wf0K<%^OrcZx7?0>`j`?J7HQQ=-}U^hcFZ98Y>ajmf#nBocec-wVCka=rnA$I4K zuSCfB;>(OLu8`kt^VW$D^(xkfA_Im+8t2|RwCUg+=qC;$2s&X?3fC@omT_)$d^v#P z&@SK7g-tW01s}65GPXWOqj^6rhf|vtgH5YJ!y`d%V#JF0lr2)7;uTFL-cujrT7s~A zKxydH)IJMFXlT9(iP*B{%mc?1(0z+tDPoZxl0%j*9!DQ_M>i`BzgTa!S9BpYc0$pH za;%ocX8$_Dc%!R34f~xxAxKE_>~iXY_-_q?PWs*becyfF_1ZI7zMosz@LM#4zn^Q%INC3?_N4ex{;WMqY&#!m6gNMETYPe#>bJHssp!EBsk)Y zY|O^Ziu;iDuTwwwkfP|VXh8JwP3(6-+E^N$t=poUO!Fh85t zW)}{WebTkHX{8}n)pc)LVkL)1a^_lE!l)tgQ_Iez<et~R@d{ysnJ_YqvmAXsWeZ%+Q8lD4H)$yf@WqrdW`h+XORNch*GHNuG3=Q5NG z4xrD_Bi~GdQV%6CWb}p&JxZ1xl^b_WTS&q3X<}%FWC0l8<3~+kh$RMbAn5t z;GRXcP(q^pO@@1r+s2#?4AAjNenFx$MQ?5CQsy22ohnE2N9Q)R=7@RaYm!sC%q7i> zWk@~?*HtaDpml`yuJPpZNpIUq}{pGCLYkH3HyWB2xp&p5u0{Ymr>v3vOhdKrN1qx&A=0q91cVPcL| zPFwDsoyiYwk!Oa#o-j2g8u(lY_~x0%6XunV!E`E1s0_`XtLHcr5h@?BtDoLQvWO-- zIL28~QCCmT(a+At{)osc+LJ6O+*AG08Z0ubh%>rh7w}$nIp=_41_g*Y&tXOIamML8 zyNb%}<<2HoWFgZBWB)Ri_h{V>qIX}^a)cew1LH*5lEIOIefzm2Oh(f930`0zlS{R(1xK3pS5U{M9+_jBmVqEEUHcgKoP5~iV%!y(dG(>@MzCPpcMsBI zy6hWPgJ2Ml6VjYs0P17Ax1k)s&8H{`OmL;XSw1B9(9<_4$6UrQ*QR1@Av((R>wV#b z*utHR9T1T#6-(5nDi5=?5th2pD2A(i5NXp*;9h|a3xxVAGJbVZ6e54ImEDcaQx+U( zy9XT8e4iJx0xnb-Fij81WVAlBiH;gstVGxIS2aCCC4*5`@b_MJ*yBOR)Qb*1voLTf zFx2eYxDGuXbpxBu1_nm2^YjBQrEp0Iysa)}p@FFOA1H4$TmWs#=luV8XYFsJ^l%1Y+QA?V}V+>8{JO~Q&`;+Eiv;Z%}pBZigasLN>9jv}zO)(GSipUSP)f6<;9efMD} zOc&NB!O~gssqqtTvHRIc{GB{>yWoZT=A&fA0)?bR%Wp*5cG%R2%3^DdqxS!+>@13M@_8RU0uE(KS^Zpqpb5j~(Pj%86VhAZZOvfX6y zxf3lIGnwQLHpR|8E@;2Uu<4zZc)k>Cl=^j&LYd&v*v|(JLSHo69}N3=>-*r{IpeLC zrB$z{GBvZ_53nbXx5!@G%$t*M4V>F{Av!KP57bs2b-m0W#3P_p5>GSp?n90;qvf*f zSL*l=4=^{D=+RX8o+Pt`92#EnWQ(O-HrvD#IPmzw6e&ie{kWkRUh6!t`dyxX4$v=> zMdi>;g^(`lnr`UnC9Syit*M&`fNhRy#?here@oHhcKkM%lPhJZ68no`kkLTt{e=@fNS-CKR3AV%8jH* zUJB+k%+Q!Pr}N|%XQSqIlSIMy${Q)0>>=vLjjXEN(IsM##(~kX>28S0_`IEx&7qo6 zu_AHK%=2h2@98pSPtP5C^6D%|-3z&qCOEe$zNU5Lp${Qos2M|4Gi}^i{gF2B9@_Jb zOY`$LQ3}4n*6)C12vE(!XlEtT4ZV}e;LL%Meq{+XXsE^wgZ1gXO1?)%gsYify5CBc z{+;)kH&`I5#C0kdFsAQ(9S&H|`gE%3a%qiftS zdP_%U9hAS6_E!)rYAwVWp~0obrHEJqh|U#=@{5Ll#K-9Fmd{bxvEf%Xj+AQC^5})- z?2eme6@%ZTKJ>>oaht!gjV_80B4}^BUEb0XQ^p%rJJSH><@d-^9j=^&id$K^sP-KQ zGbizd%T?PPK|AOEW7do$G=w_6?!AeSH2GEk$0E|$5ET`Ll{SndNz(FqTnFpe;UOW- zw|D!D%_Kr0a+uh4?E$6X>R?dPNTD?@IHUmzs2*U9!OgG$ECNv3nB!4EE_W_y-RMJ= z7fZ~Z(M9(j%|Fr8BX@6&75PL;l6B@Gj0V}LF^!ROUTX4qn2S(R)hiQ63wIL-t7@<< z#r~n&AA8!3MM4dUC!m6QQAU2#uJ3@5j-!h9o>~|K?C`6SVE?}0!KK{ziE(ga$u{1q3$6vySxgYb4Z;q!6T!<(ygagL0f@*+26m_3bMDn8sGX@UpQuIl(wf(3 zniYVWyc00Z2s%s>qD1!IJ@i~RDgb796-tGSMdtbKs1!<%8v>bL$6ew>poMJ8r+W$w z2aRLKGj|BxBO3wm6}&$Od~l*a7ps>6jQY&@Ozmewx`~QWpsW|TJ&X9QD8yPwKEA!9n#> zTWW0po*yWaEoiRD?f(OII3tjBd(xr`G)>+4P&?(FvHK;?4vav#eu`vy+2+=r9IkUN zt94$t|As~jK0+ewE%3GwAc6ZXTAT*YRXHu^+tLvXVkz0%Gr@}Z9NKHG9s?}a``mNQ z9EfVBz0K0-kBU&Clp-ALLvDH%w6xWV z79}BkKarTh5E?udc<%7z(_fnWd>JxUfp6{pFDLjug-RUc#>Eo@H;WMv_FdjK18^5( zPusp*kh}?>7d?rqsjWoxfJ~W$(#_P-nLFrPja<)6#cZ|pVq_7aq8-jxfpQM0iY3m{ z4g7U1&=zut|-3X648>9cs~-871Kfjwwwl z!*t7I<|*0g0XpW@3A&^h^Yr(uX02kJEb_{1tzy$`vjG@6vIF`7u8UoNaL(uF{Kn&d z`EC9)GP8X59t;tkoNxL-)#ME9TaS3oo2MNSRsQM5a_Zza6ZiCDV5rAU*W0kQSlZu z@wZ|vF~n|${K}M~`G?Fdby_d{)G)5h7O3c>co^Q41%<}RBid(v!J}`DHAAv)>dTi@ zN*r+*l=aQ*O4Ew*QB@+nNMq{ixd-sC8-jLP;Zmu@xxnsL^(;VXTTja*;~JDj?#^T$ zWtXUxOrn+8K0e5i;_nQ?d#BRo7 z5wSFeb?N{mcl-TW{c<{aBa4?q*Q@jP_28CgSOgNiV*+Ec* zcc+JaCzJvO=s!XsAT!I4ysHadNmdw{`E^zhJ+QFbFNFHj*dnTBsMLxagF;S8n!%TZ z6bT9p0U$R3r0Rj}Z+>-k3<~UP5Yr0NvUYW)w1dRv%KfZw2rjao$05WsRio`q9BJIL zCka_CECS%cmi6v0B2OqqWYbB zSxx6|(&?@2{&&N%GT4q`UEG_0J*y%P)^HJ{3JP$*4~!RE%F3nVMh(6L|J9)|!E6NBj|E14{-KIyEo6L2YWFT&+;el#-Z-bQs)Mtdvr*q*C90*X_o9)G_-ds< zBVAD~^cwn1FBm5Huo0P+$r4Izz}68lBjrA*e8M>dP)h1O~A)< z05IZ0ZE5E1?J4;2M&rY`I34vZ;j#~#&{iVp0ZQTlCvcnh;iLq1f2Kb_>T1%1znJ^6q1au`<_^_7s4g$$OCooo^rMLER# zGlE7nyN`+mJY>k`Q4?gXJ9!?ZY1nF+0sh+e0JXpnZ_oM1ksKL{ly3!IBiTWfFd|<(|ENX2*fuuS z-Q(ELOI*h4`;yaMo3_#eB@Ui4#7Dv2k8~8l%_&5>>%v>1oF=^lxLjV#MOJ^O{hBZhbsG_+#z;kvUa}}mo3b{F z+h9Gl-6Yh{cwEXoz~u{Un6{Zk0f+r&?&I%V?9gzT<~toLFjR5?yEWLfp&a?|G&VeG zKZ44C>j9=(e*f1}St6kUy(>ma*~wrhTztTz7sE(so|GTIt?NUxne0eA2?3WtwAm>z zNnygDDl=&C?=Ayy*Fb$8_hF~bl~0`_y=(_@6EBB}u4rmHagl8BYZqa^gcJwCC-)Jr zFYKA#yl`)O6B!=9ta$wUfQL3^9y{=~kU_rR5s+hjk zp1X}5O>o)C3%8l;b=X;?-c!k|=YD`lZn^9#uE1l3!fB1HqV=9U%kqBkt*jruI4Fxk z?!@b0R_ClwLR`f(R;WVJPkaxS!_blIpoy9Hd)n@0^}wbB(K1vJbeu4T$I9mvOXFAU z2w*1kO|=Zj2gre3f`0T%-cxh8jRZ*&k3r%HEHC0PX1Cp4D`{vAla3Guyq^^NyqWt_ zM8auH#C7kU-?b8YSlrjX)fmyt1OaPfS2Q}A`!YFm9@$*3TbVA+`NT zUb;6S{}A!l-VrtSBD)1|6q`S)-*G2{fg6MCBN4|}-k@gh`0+y}x|{@oI4zd?mPa+0 z(9u)V`f|d^%OFRFzHn;GaXp-wJN|0d-;4%>ouGF3Q6g3Pu*15txQ&kgaY;or<1%>F zAb=kYCaa!BjVXWP`Y~1w;wCNwIMcb&woc!m%(;z}QS@6AJ8q-PMQfhMzwV^ZFm!B} z?CpXOsH>x21j&u)MsO?@UaszpXEuZ?>qmg8?UVtNV1Fj8ADyzrv2jVV6zfpN{)qI~ zs6Yv#aXyS$AOZ@uq7SAsokI~)n}_hWfHN`uNkOlmk@H+E>j|3+|)I5kQXSxmjnue zKOoOI{v{dgXWLZg?clp|cbsl}H2})nslYSi`q^^?%TkDlWrRXSH+oq~ zff7agw&{fGqv{*=)^q^-115%Fg6ls|Gh`UpcrY$3*W=-gQ(`;y7pz-BCtFG0CP)aS z`oRp-_v^1sxiF_J>WBXX0XEzJ`qv~LzE6-dYku(`#LTjx47=Fk<01OWPOM|_{ zHHQBeP`>~29~Eez!Lk+^tV|jO29Mlup;x{)d2(as^azTgvJlfZJkvpW5U6=oSd;PqeL6F~=0FB#bR%5z=C zx6as+cNRjg!<`rf9f!or9MsZK^cdQQqFv7Kc>QrtE7K1@wto?c38myOTIKFcESa}tg zk|n^_}^@%uJIvexA}Kq=nB)8FqiW=*J!SzNW`;&3AjCE^O8E|`!afADc{d%zP(i7;rrM18 z#MdK_?c~`6GN#>-7l{z?dOnQGJUx@E$!|Tp=7zau%`87K!|%5Da3?Vl)P~+Jzl=9- zQFY~{L! zV#T##-_0Ow1xyN+iHWZJx>@YEu<~WWD6-y%VbY31#tZjOwGo`#u!5>Hjd-z3V-VerAkB*ux~ow0q13{5WgVrd0}gqs1ZEL!VSf$w1ZEC7^x{2_UiPX2T8 z&&?2`$~(W-ExXGt8xU&O8zCzl}}@U%xSl+s+q*Rt0Tlf*>q?Uj*Ok|Q2VPo z4m(|RAZrH8y>OfW-KJgl*qb;>QkQjYf=kzJSxq(I^Ut?$--j42s-0dCC5d93D4e^V zp3Q32^mURF?!5%(%+l*D--elZOU6?c>-~|q83p#`zL)F`z8{7QAKW!d?uZkr+i|yO zIp#MupN3-|pXYg;S-`(lf?mi9LfHsFJPHU*Q>wlS_J4sT*-UO1ibbPWML`0-f7}&U zK%JUjOG!KaU+?MN*JwCnGrQXHOh@khIBoYDWX)E`?@~bqQj{wi+AM|J$2m54tlc7& zCygu6HnHSMA%rBK#eZK4dByT( z<$Pw)4Zh%cp z|ll21w- z<>wed+4apmiLrvif{aWBWAdH8c52IS(cO~47VU-aDrP5uMsU0=I=!^EwwBTFR7TZt ztR~HBG!|Pn0$b!;cUr~8t!$L#H(YT2wzm!VV@!o7dbW3*xP)4RGJ#qV!tYAUa*DFgjbIvHAN6{lPu#|byQ-%9ZZ++B?EWU7pTz9 z@%DaDbwU6~!k|88a74p~EK+NVU`F^>%rKhD)3iY;WnqM00z*&II3(r-+jO2PSTTwb zdi(AqE23U)R4dXo>k?Puk=gI$1|RiJT<$(B0eUD+c9Y-L*L8PCmS)103s4XBzt7oK zY{8%VoY!x6J6A9JRxRtx;}AE>S_=B*<9>~!mPEZoit5aLnrJ({Jl2u>Lt0n99KW2X zoD>6-5rncRp2!Nywg_;hE znQd&qTU&q$UibntV4)JSTQhMR7$4Hu>Cl&hS@GUTb-US2(qryur~DEecfTCO$bnh( zN~B(4B_f05WnEsjXojZ!ukX`1&9$-aKjQ=&Jy#xnhCizbH2v;`$K(QtPguV0A7vOY zSegmPU;q`%FVC|4))hp8&i7D3H;@@FEES8rvgxD;_kN9j)D$#3d7cZm*5+?3<8TkY z<51xs40<#hHm&e12J9O*QIV6;FwLgu;cO=b5(WuuNb7Ongzdb{dh`x)J&@y!E_+j; zAY=b`Yo<-{3m?{G4AqracYPEyW*Aco?JkHhDycQ2DDW|#)Fq^fAN}w_dhAa!P4=U> z?L+4y$&?!|1K);#oatSCB?&P|;djW-%kX z0auY{*FpgwDDD?j>er{QmXc%W7)p7@TRvq-c_x2+OT%cxQ>MM!)&!2hDqNqKM ziEhGLR4bm%)tV_$U_>i)L=C@9$&lkrVu$MdA89M=KYb~%9l_DZI3XI`JRa3b@yhty zgUtjpxChETNMB;b)ijP;*A%Xcp&++sDxAY|SADVk|qi#FMJo;iIrp8wP6k z?{ChC@bFB8CQ5}vlb^JBbImUIBe&sDw6I7IPQGGS%b}*EqrOD1m7RWUhtAmx$(D9d zB=lnC{YQssBccr9=GHx(xw11iR}VDM5n#&` zxNphJ%_C$@3fKnfp7GY*?m07aGSHO7)T%A@Q8*lL$c5Mob*HWKl!@36D7aH_FTjsA z)Z91EGw21fOO&{Q#KlENCHwT|v%8Ve_t)&SG~zo@p8TtK0*RM>Gfnk*zPV4PA!#1J zU#U|=FU6^n`i@H^|Mdp+UGe)aWL$Jr`fIF)!4U&x>VWrlv}1}&FzRFq zs!cU?E%J!%C{w2vIhCJaqf12UcKT6;N*Sa;NWgVAT5&;prhJD zhmYWDEfwFK9DX;`*lD0)g+gCA*RKxbme_B4#ZS-4B!}LG(dI1G9zX7kFL4MjZl~LGJdUtJki_l|s3Q&7e*ZqeKrNIA~x_Z7$*{AFM z^idT};xb!dbF*%30WDPUTWNPu_a&bup6TbQGi=qqvoaX*5A!MSzFl_)N>t{do?hDr z9amF|R5DF8of64EYdD;(VDA+t7x5G^;L;?>J$klaz_d%TF>pRFnFId$a(o4IoF}QH zj>5|2X2us8bDlmPc#NU20J+m!`Xq^m%W?t)8SvpFwd|wAByiOshMcZk zS@zXtA2h74LfL_wYR!XC6lZ<&2hW4-FWETS1vh`|G8IuN(UMN~A#ND8n{TvF-cDDnum* z6&aC8I%Q zK~xBZF1kj@Zct5k`g&j%sp>y@D(@drX^J3sUO*7!C(EZ%op!vAZyDvZ4@Fsde^kE& zbAW!=6TYLJn5mJ|9=MAIQ5XOB?D-uTIcjx(U}ds4zhv^8F@*CMW+Sy!+LwtgHSp)o zOzkikJ@5J%hylajwEnIq9|!D7*@t*iB(HzIF~A2XvFuHV{%5G7N#i#LJYxX ztDOnn113n6q*GyEf8bH|%yNUF8T0(B!EhuEd7jp7Si%N=o9HvUedo=$TXiIFIB<+U z=@Y0EhO+&-(zd{TtU!J5YVcgJn{TON4emN>^lfS*>;fpXg-v_ImeD6)`w2Po6aB{6 zH{oX62>l-ZEvnNmB8p4>T>M1z4N8(liD*#?-Nxk1aJ+$TE=0olP28&4f)pvYxJo_M zbSCbSj$beo@8qe3n#~u?u28;W`bX*w zMfWqfk{=gQEcnMdwVzd1m3x2sr;DAQ94AeI_ymiGU=hyK)ZbvX{YVDEL^Y=zo$;@5r-=o&p@P_bfvt^E~tHEb z`EIi7JW6Z<30coi`XN_MfN&B>Lz=SH$-l~(0sU;+MPh8b?vLN+k8@{5dK$P>%$mAt zx+*o?BdF(SRp>St1-d8`&#E2_ln;da$Knh>H`rGVht+;+$agiybpm-$jf=3ET-REO z@z3Z?j%rxl^lJPclmT0(^|3=hOTWVP^S!p*R`p`PW$}%P?2QE1+U|jui5V^>%?&o| zX(7eK`rcBrTDhnMGfE-X+>rn3>=*b~4ht>Vwm}cZ&f7+EE^PhK=?Fd7k!U@VUcdXo zD?L`?Q@7?k-PmjwvwFFrlTLKd2dEHZpiz9?4*M`Yf|d2omvlMa5FU4ZVE!&b$gj%`hEbR6)X}oj97N;vu;lb5zJ($4oVs9H~I3i0WG(Of4 zwtYRiVi?Hz^k1{MtsI^sRs>~%Z!!(Vr?Z`6?3?DAww3v%+=jdgXPS_~s;$C*3&mkd z#ZAT6NX1h1)nKa;NxA7jCPE?$<%gXFcSu#2GmvNlwXrq1;z6YIQdnq74Ash&WvUzT zpS*P<{dQb!x{hMb0(Q`{Z0kdvcFWmM!FTF3nRB6+?Q4GzK$n`8Rng4Kc3ENmm1v*E zS3wo$#)LRSh2K$G@f-_#?=qb}y5@^1Gwll4cD!kSjNZfa3Y$A@t0uLmDI7CGUGHn< zWfeZqk)89qa)}*EO&8s+{f^Vf%bxOmUGg_VdUje6WAa{Fn4`V$7w}%yE1AI+cw8=9 z5ZfL3vNIlgC{0@>6uW&8bO(NeF03pqg5Hx6$sRKo(n^|H)c1b+^36+zqsTDGP4OwF zYo9@~mhS6`8tP~=m_r{PYF+tdM~lT8wOQz+)cTKMh9zPx6rGg1>*&}#cf4=ixFIPy zO^v@6{o$qZRO%dxV{b3EW#Klk%vze%&xKQ`oD2Ae~o1wL6)o!xuld(9=e9mFUg z8+{v1FJAqr>NL*gc4-_FUO>}oquk;r#TNhi(d2Q-5Qq&S`KDVcx^NSYsYT?29eQkC3YpYurS=(XUF4fqp zQ!y7q-gXgh)wa!dp#Bdpl1Cl}_z!v;8=ZaL=E@R?CnG`@ECcfA`Ppd;y>HKlJ1Ns* zuAn;!R2GHOP}6CZ)KjHPowN5<)Hzz&Pn0a$Y;9cSTiKOibgKHr0^1PDmj>*y%oFOu zv3LFy_;jfZ_GhtLXp&3hrxN!9{Pafug>k<*ME&~DPbTK-H&fIot$)kxh@FO~_KF?5 z-hzwgTm_F-A|qc!+@5uoZpM#>tDqI60Q$sAr7$pI7!NdYC^!`Dii=oJzg6+CwN}Ht zXC?&xNzkDq!+dq^tmzpUb9ua+e5KJuwYnX5YbFWX=rK45@*LB;^<1nQyLA;lm5?u? zLhu>*Q^i+SKUC$FBOB9I$f0_g)VP`Z-wbEgaUng&TG=}i*>592>*_<#Pk{#)p)2w) zO%n`5IglSIVL?q6bB&_$eAFVk-JVKVnwi#jDungFp-fCIj9ayAz>D@{l357vM${Xt zhvYW&ln5OiwkPOW0y}>+mN8fv()^GGm8YeW`z%IcDlA(5G)7ncf`F!$lH?|K$VAf$ zKIYW>dRAprr4Hr`>ZGn5mf>Ui)&B?er{Z4}qsV0x0 zCjW=PwGZk>oDy$yCDqOU(;5=zmB&|=YUyR0FQ5U;VYurDNKhq{n8C z5Uh8wRg=_lTH0e^b$yJ9^DGjs#1-!j<1$QTDq1diqs0D0TM7`T`@Wt6ZsK8apH36( z7JwE6p0`|VY;0QXVnicdTn2sxE}gWTgLi=u?OBWQI_am6x-9YU8zO#9v-zPWZ@WLw z3i{xCJzi@aRpVY?8RqRk*3yL-i}(k*i_F@6{m)Pr-OsXyc^adrJ1LbICocTNq)ci5 z=RXaF=QZ6(iLstvCy`T2zqAj(l8fAt*PCvtbxp1KCo}R=nRB>GMe*v((Ef#vD`KFg zVE*M>n6?{RGAkQ~_S0}>$_PU_Nq<~UY{+$HjMr;j${um!)HNQT7lLyaQQ&3o@1J|R z$l-EB6O(V^tT+Gp1Ky7iXxEQ9p(KbiON8hQ9$H4XD1ydd+3h)C*_Zh7IaTGah*agP z;45?8GpmJu!pD82R@wM%X8RVF$d;S0pRaI=Tzw#$dAcC6B95y4l4x3|lT;(67J2aI z|21a1O!=p=f_rd&4FTT3cQroZ8n3X_F>Sb6aKDn@>^z@lBBO|_>es=!s?~p;WNdaX z-*5{ehF@&HzAtGIPslbU777o(Bv}yI{}ZBr!T;4j-nvw=dJb?X$7y9=_kHwYsl^hl ztgb2)2z;`U2?E`-dN6hA(tS(C*BI}(hvG1tn+|$G-SQ~R^Kzd_;iFIkyf;xRRe5@e znYaJf*jGkH{dH}lgrp!MB}k{_5Q0dGLpMV=4ALbfD2>t`f}}%tBQ4$1Idq6LNGc%j zng9K~?|ZNHtmj_Om-%qkZ_e3gpMCb;r><){n-VA0RIL#4xXb6X_1gh?oxpDis90ca z6|(SNme{(ZjU8VzZ&{caPY-EM1Q;eQZS7Yy1j~=ZxBj$Fad8PmgnOq7yr6Gr*r4hT zS#&QJ>?0FBjDJVbGafF8eamkZYR6Wn(5N8w@KE?NZ%t@tPg7P;Zlsb&xl31;oQKDn z8F)#PimC&gN5?gMQQc_ z_rU@50c`2g|M{kE*j!6S@^@IWl2lq)Mh{IGO1&C@mA|wb&;3$gliVQEH)}DYY%Xw& ziO#b4Tk*VAUj14@w$!*Dys+s$Ot!x|2Fl6I#)Jm|2Kze}zB&iOqfGMr`^Q3%0aOI{ z6AYRd79Wz@tXUlFol^zoG_n+>O+zI&rK>D?Yf8uLSrS@A=Cp%85%qDj%)0A4>To$oodB z-TCH^+jK3`j}}D~(RV?+7MMLgIjKn*h4qd%N21@bQ-&+0iBwVgA~9JPQZM}yj$F_3 zhQO5L*z=DWY)5@N3QfkRVEPThaRPo?xGh@wr0m(Ftx*Oa>TUJE5JpsT*kIDZLtbaR z?XiP=ILCWoX%*!Z>iQYhJo3?8G0IC>UtXNvc%?3U@KnM+sGkf=yD6+ON2E)wmz^;s z7Z+z(G}V#+k2z%Olj&4wId|z9DPG{kZLxNFRm_7f387T?ru3eShw48=5NsV%#&;Q3 z_r?i1a>GhdB0diuD71XaalK}Jbf+i{8ebwA9p>Ab(YDE(rr}lpHrmvXOkwnLdJX@O z?s{P;UoxVy#0(`YSXfDtqh0VaYBjAm@RGXkBo=M;Jm74I<4&>@u~Ct3^&1fzq8{U& zVJbA+iK~FuY5HhWefd}f@jx}Ffz>fteKp0B z&N3;Ma>k4PDi{&41Ay@odt@ zow#4oh$xtB*}#Y0i26UpvA8&;Z@n0dKEQ4PZ#W0+cOWe-7Jp#9=!n86~pN&w77KjLKpgzKSUNFoau}U6aq>K|CTqFg9trsGzs^?0$uCIIDK&7*#Fg+8o!t1eIAhhY1ep7Kpr z=V{7VNeH{(P9uxPW>EIbo4o{fmeV2M`~hqHC2q;-tT#R49*WZ&RM>Fn`ugKN3W_Ci z#=~FSx0!g}L3b9uaX?X~heAdo_sp7UX}P{rO*1f?naa?c^xNmV9&R~}8~UPSo1;!2u$`8t3BGPDCUD-upE)r`;#9^q*)z)v_61Xn$J^TzJF!kpBzU8 z+Q`Dg=5E=@a;UX9(R!>YoLH0QB#;z!_;`i{4@=6wL~_MzN{cD6xR)m@p$nXzJQ&`$ zhcwgdxdj6v1K-T4eA*m*|0h!9I-mEuY`H)EITG!fzqdj4o0lMy`?vaZ)uUMM0;0in z`PL)98Ds1YdbR0(H@Q!_&Vzv}*O`e+eT6Zj*4bkFVT$F|D-!S=sen_gNbUi;*^e0C z6EN==N0pLJ1i><&yWw&SMLvF}bt{X&0TwW=?_2 z8U?oQM5vwZi*ylP1}4f$trb%?JLe(+WDyQJ3e0&>31yUk*Q*KsVleaFajAGe*}`9w zpSoy0@7jq4&}>ypRg)PtcH%~r{pZOOg>1-kx-EWc3LLqp(GgUPz1FFP>ssoZ0SZwa zGqeC&!0b)7fP<|X=r(zJ>gpAhcZm!SjSNa0$kR=PjqD2+U5V^pZF#i&KL{^os5HD9 z>7GO9i%-|N4qse`mov|4q6{hk?ecE(N{PvnJ99xnI zeZwksm{~Y=FCqvjS>XL^uOuQ!5>4`#_;MM|jbSbbNg6%X@$+jui7w!uWOUQF`h?s2tbaLuzJsb31ZMKSEL54d5n z4V66Ne=ivnpwqP2F8qhBR}NIofN@;Ih2Mn!Kz4LOc6MY)R_9}xJJ+jWF7_}w_#4KWPE@o}f^xTDT*w}g&L7kjCG7v%HCA_|X)g9KxS z5uF*fo7uom3H?rAPDST6oEW zV0w56K=tpa;xI*PRiZWi``y-c>;6fcnc?`V={VEPVRrY&2rYiT!<*c0e)amB* zFb^`>83jjmt9cUTgH5L}B=N<87gdVtaZZzl{UD9{kh^gZ8N{hj7~!U(QF&lppsB1d zQK+e`oa53V*p*F5K;TLIL@}>J0x{<2|2$l33{391*O`y7m4}(57GVamPzp(9? zDwEGh4vNC~@b+a~GD)vmCo!S;xGN{CNL_+%VN4MSf#q-b*IKSBc5HA-d+PQ9NZO}h ziZPT|4*?^)e!4xO-;R_ou^TU~uA6KB{?YrI#@~M#jMb3FPb`3?vg^ zfohvrYoiOOKSwiD5=1KNv+-^EZU`Y&TnswZ34+l6%EH*ui41$kZZj6 z@V=?ibwhbT4*NziE)G3JuF+}ruA>_mHqKA&NWlAREks#?|FzOuSbPZDk*-&f>m9)G z1g4De_Do{0oFxq~_498BeG0k#_Ua!I*K}R2FTCK%!WUl05^L<1tl+_=W znT}hy7i7q$Da+@U7kU4cj(`<>X%$0~2uCPYt2hzj`S?N@vw%5vOVJ-m04>Jl@OI=&$t+lKL)FLUsx z`u5%R$-m}5=Ng1eGWmamw&QW6=p+ZZh%7r~o&JcYbfRLRl_3fU(Om-+L(Mff0kl|yV^pGElNUFqR7#Co zxH}p645p>IA7>vFl5UA^#=GJqP6T>)aUT;ban2-lwErgHv@W6~7I0eTY zCp}zZAaOdMx9yNH>Hp%pKcql;$1tu?>MkbV1onCX3`?Qyx!zD2R5IIX4}ojl+gX%d zXrUt@NhF=|ZO9zU(K{pAbx#|_8{t%c3LJ!5{})Vkd91R)%izTCT{kCu(R-OPyNQJZ z+pD?4(xO>~Cw5OOL9Sk0mVcqKsX4lNqc3H+?0qO|G-fV2K%`x6wC~>3f!384{JSnC z8RO#DVg~fi1e>cIpPJElr$TivU-5J_&Fn?=`x_3%wmr)%skjfgI3g{ciSoB4y=4z> zA8SuvcnV@9siUDi=&J8Pr86~P_r6^_*22+J%yI&cu6C(_VIK|IBS35x~Ra^j4%T12{l@am6ylQl1ahw`c&ko1mD^+oU z>p1Xul08QV59h#32gfoZn5p@AVxS_E$A?LgG_3G@RGA|8}uqkkCbBi)W zkR|Zs3)i7O7x{&UJ654s+_4pAo+kXsR+mY3PucL_0ciDR|K9L~)%d=SjsPCNqx1)V zJ`^fQ*-fW8)>6TXHyU%?RX_Z^Xg4A&rw@eD-Pl?m9NkuWuw=Qxt|-6FG@l!Jzu4N? zU}T|=JI^buZ;<;)b{Jnsio1{QK%tLC!5IQ6lt>|w#2~?xWX6n@tI%O?5AXveUAXMD zxOya*`iQ*k93_S;PM6b#R|l|h(GC3HJ{%Gf65ldfuJ+GvZsYe`%o*0L$*pt^@%ouD z>uT)Euadsf-R;fe+2ks&t3Say%_l}fD>H6eGHkZ@MY84UG%q@upCRQuVtC5U{yZ_> z6^+!M@ZPCO`%xF^P~6=b*T5|!6HqHE#wUabaCRq`qypRg?T7nGc<>d#8np|xF^$v8 zeBFQb_b1b)&-~7>3#K_k*$MZ)HfoIO*Ck_N=*BqmPv?S3Sm*5NR@GgXxr%+jql3Ms ztKrYj`20*U&;|zw9iT5cEckCkWoPI7beK6khdnhI91aVO^_0WLKA36ve^O%n8!(aC ztBg&Y@O8=e_6EOBj}^VH!eiyzoweCVD^-fV>4Al*_g@VTis#MXCUBG{ZuLD%vO4c^MnZcsSZ7><00Z z*w?irA0DZgav8U#0q*y&Y2C>4w_|pK;oM6-;q5>0i3R0xdx|`V@oH?k{r3lv7wX>i ze~jOFyVR%cU33SE^sqd(-e5B$*efte3r=-u6XNR;1M$;tP>K~bTbQHL^X?_XdGcnM zF9bQGq({8u4xaBQ_{|o5qL`m?jF->+S5{Dqf(RwB+U3Pp9QmdJf%ZJqeTdN92mSluH(%! zflerQ6e?Xe21<5Rmb=0NgLF5x?XCCDGXxtprEzdDsV^>FS?`-_IwfwYDmC0blw)fH zEZlbCFImxhqiI;8?8SPcUp+GSdi}6rA|%x;;D_<=G)it6?tUM|pLH?Bh^LJiI|{Ls zixET8VaYlEx>}sMdu4Ksp2urDJ2qOPXlQ6nI5pLtP4Q!%88R-;WR8x12@HVhi{d0Z zBE}^K$5?0IT(q!!-u}wT5`lYA&sQYu`~u+DQqU&&0}}8c-XF@HdJ-=T)VZyh0@0PJ9BIH1_jPy%&=*1^~Zan zZhFe+KRiVu6Z)22Amon>R`^L6q5x=$g`XW z>I{f6zHmN$?iEMQDO_wx7AJeNYE5UVd!{0OlK|`;zY3rjHBb=b*7U9IXT0VoXEY$Z zme8K^hR6#t@GTZKwdAj%bk61TgZLGd8i`?p3)Al1Ac)hSQ|mSIsjnO-`CBGMc`wI) z;YMyx1t5*$42i7XB;CH#ySBBbu8q7tq@YQWMW_~s>B;&hMSgSazO$t4<;FayY)Ev1sYPM#P3Q3NF)XBlfmRg5!UH8|c-xm?IL+dhic@E3)nZRPrHS46HhasQu!DBZTTjHIEaA7hd59wu;?&5 z&qT|{=iuV%aaN=foLf{k_qxcp@t{p@ROOa)nvPJ+PqrwRna^~&BJ`zktcz#Ymz5X1 z>&t<|6H>pN1hZ|I^M_9nik_;n1pnTzUxuKe`8CI&(j|WEfHevN=7X~-nQ}|az@Wt? zjbYFD$YpO8nZuMSPL`{<5+KV2c@EJ8WyR zOppKYwp52MSW7GMO3Jkxjkmf_K(}vCWbpb~<*a`PdWvx7SX#`>&9Y=VIJuwQ{G$UM zLqj(*M~~DiVcGA%55K>Je30zOP=gT=->(iWTBJ?hq17U*`T0|G(Rn2t6p$08t`$V#XAvUx|J%CTX z_@`)ahM+v@9*kGsY|dVoV1y}EG@CJMd)xX-hWiQ+bRKX7W3Gi@JPt4#7bh0BmNw+o zRX0;+V`~Y{5hAQDB9y|z87!jUG*uc0s7GmM_ds(xy1LsI{BxE12m^51HP-QdQTm z`}m-`@_I|6HqHHBfY6VvEnb!f+4y#S;OV;*)rSfHOFmy7*hIF~+k;O_ONa#Q*0SKB zkIQH!a&d3PKj&D_>&CktEHr@g7BS$!{Muj7Tr^S;IMX30)@C~Tx-zCa*qF~!Mc6M* ze4}yeG+am!UCw{6f8&F=4V_J09vZ@To@F=j{VSZQw4q5$8P@;zGTXwIGe=?&x>6fY z#L37}{6q|NqoStf6ijz_Qpf0j(u6;^xes2?gow!MBs3jav&vwqP)bsr2MePIK`NY4 zd|S?*5lb`A%)PGile^fa0(zh5$)XD;wNa$d11P0mquDRhNw5Zsz<6ghc_J8maAk(HqGWXEvrQalUh>zaB*fX6*E zUv52RXx_f_8dyPFU}3{)X}o1j79n-syYTb4AH)K+ z(+cAe4n}yPH?4Tqz~yL^zNskja(3oL8i2b0Z?vWNh%Otk!nzV53=Gmhyl2BOcbx#X zu03Aw4qbfw^BU|~4g$SwfXCvzYqJL@0WCT2D;EwA58N>Yj}uWJK78z!m`?XvNRR>~NAdENBD$pqt)Uhe3F`GxU!9VZ7oMAY$p~BsF9wmSuh~B4L6Q zQS}~F?Vtw1#L1w^eR$Z4HTM;%BcV1bdimrek~VkT5l|l7Uilz{iS(VgAspB9y*ZoF zl?4954kt#aN3=C|mq#Q*_R)Gx5oz2;dgy8Agj5GM|CJxxr;Z>~D~(U9`dS2_ey4w8 zBcFi4D}z2O5Si{18(+z5)*OXuP%6}QhWIl23b1=h^Q~2sZ|XXO+Qn|K-_Qkl7Z0an zPnF(3zItkUgXsD?Py#ty7G)78Ph}4mMn|xgbQ=#14`{-m5 zZtiph-YD;e^G_;+maqn*EVxth16+^*2aCkLy#23uNUi3uo82KL%aUW>kXUV>LpcZ~ zPMw2Z_d}HzvB0yj4nA9cho~*HB67@viyqChVIALJt@L2icYYS!4-2xiJ6viJ41Nos z9+v=5rGC8w9MyxPExSOZksC_M;AWf}a!;@)#(?p4wpQe*BjK5$+i8Y++x2^uT0MJf zYc?WqA^H9r5&+_rGRXs`4K(6|5xeI1NP1}1e_j|fXrq7>kfSY*^$T>JTI9PLKxdu{L{GR_+G%be$i=)$6>Q3{KjYN?O$;UjePC9 zphp|4y2>Gg!p_2+OG`@*NcXp&*KR^y7ETn+Q)fm%C+{{kH3?wDD@ZnI`=?9w$#CH= zg`SILA~`$+{ds^x;*373bRbSXmvK_W<6r?Ci+uR_Q2B+T zByoJ!^#!6I!+GMC(%03}Cxx*1o+(}~$r{KcASA^4axpQKqt%TxQbUW{jrvhpNn?He z#r8x##7Pa1x9<#toT^k7*T*KZp#W`rq?()$<8eX4ZpD}4YUdSZg_*|YrQJJ|3e z;QqnJcSG9oyF!ky5wDGd;ZtS1Nl7pj6&2KaV)DWE#P;DKHwi9Ssq41+yzh&E_9WEs zS4QVqa;0djHbg;U!PfOs^B8SHJLK`>$0FY6CC3Yew#ceJt&`M_Gi?n$F$52MN=mTy zdp=KbQ3)le6+&?Yl+ztyxj$c9#1UoR+afD?P(H#~U@7 z{^PT}*I zQ-7Pi;DP>tge4B9BrPA*&FyYB{=pL9o16wP7k5fKI74!H)U^y1O#^6SJ~KV#097ST z0!VLb==$4?KU*cY->p2K7Ys3Z?;B3csv_$)sb4(A$A+t-Tdde-tA;=kJ-WM9R#oG{ z+{MZtWlh82Q;Um>l0>Q~XY7}F27>}(w zIK{`ueXn_eWdSSIW1KL3=D1|1SOpJVsQMsyOBWWC$Tc>CfBulvwE;^cKch~vdbV(JoF$Rk4i|-1^nVXxV zY^Xpaw;S1DP_`Gr{G)-yaZuz}%^_Pn=+xQSnKjWsmct9LQ!C(Q2N+46KR?ze77Q+w z)jiu9$wW=JiZH&^yu3UheK98@wtl^b<-zg=UU0|cWCB(;{!Rpb0ztsHuUdLZOyMTG zsej7l7BbjD8^Ooyxn$9{b!kwg%9~$SK}!{8eUi>P1Tg+DWb7U z$VPDdQwn($NIMFq6ua}`l4y!_u_9wq(u8QOP^AHTu2dcm@fMi|`2Z^E^TSO|Pv;!A z`Z8uU*NtSNP~sG==Fzw-26u0$l=an7~p}Qex?Lh+mSkIQB!d&EZpF|41;2 z{{+g2*xujgBy~jAQ9}^1WHnO@2b34|0~Qwti-CcGltB=kTHvJ!X~aqtzm!!M(!uO| zxu5E54Wpr=u1U9&q9RFneK!`?Qmfs4XBfL{cGyy&xxTJ zBapi-_Xmo+y}T^4Gt<&0VW`x@FKv@;*eao*J;KubrAu}LE{k&7<7(dsGkB>H2&RVs1!+WwH)leZiDwUD{5&gMiIjrg<)cb>fPM4{io>BAF-e03YE zc4QeL#_|08{HM`9aj2~P+umMD^Jx0NJWLArlAtAjRYQ+J%aFUF_Fn@Ey^>Cl3+nVS zlFH?(?+_-z;p;xd*(G|3?QV0{I2pokEPJD3utmQkz-UTt4o9-9NDX3-mgKmc-C_}Y9OObg!}>F(`)1%gjGxXXF8+DRks z^AnC5CbWkSAG$zRer*l{dW|^soVAxqo{^D}Gi8QXXS>N|97F?X5Q*a4+*dc8?{sS; zO2<(DQN`@(?S*%?+98vNud0IEA|jwZ(mvkDnZ#vonN!2)Kpx3{MW#=)|c z+1k@n2c<#@rK^#(eFLt1`7Sfw-)@#>0jgMo^74h{U}JlFdU|$tc5LkU(0$Jj!;c&T z&19z?4L>KHMDf?M`9k;CH_EW#A+Y*AsyX;RhJ^uCRc{U3|}o2>ss t7yhmIf8B+D>+t`!3;*8Xf9t|g6%9j#=;-O*(^Qly<3X&*D1V}J2FeuVeVk$5&pdjFN0f7gu*f%db!@wZb zSc!@%NsEe-DLFfsTiKeyz(_@^l2;k?ijaY~i?Yq{r0r(pVYJyLU}t+I zhu5&^MI^2xhwOxmDou z%Y3PQmi*NH&FXUnmRA%8GmH}5AR-?kC-K%sX}yd1pEoejsleljH{;;6JUQF~lrO%P z!FQ@l0^NwJz83FjDSl&ak;6c+P$hpO1U{0)v3+m$twRlquMJD2g?>25?eAV{rQCcDOUR;4q^AA4fFkif87rU$~<#I^|1+ zb0>-PuN|yRTuK^(NlY7JQ69JKw1~cQli8n$(D{ewgG<+}QVYWoes6jX{xPvi|GGm} zlW<5lNzK;o#LadxC=-90wMQ;7gT^vGq>Fqw!D>Gv&w5}ic+4nK4Z)rwxel+o54mpAY-SC%VTFp%mcROsG(E=H~Xo@2~Q{GX- zusdwa^v$cj{rv+4SxSgxEQnzY+|mU}&wrYSrCkem-$xS>0!O}zfyJc?aV3M7?Ut#= z*$fe>MmYqTGcEuP8WFzi$d7a`kfh)t&x`$7>ZwZ#*Zn|04mBC~mLW3+R z%^}EVVj_uLREX%56-l5%yfO)br1yoG&2g9HRf(f`MB(AaCcjw~@C4a&W8(aD$3(|)$C%S>RtYt-eN5sgaxoGoZYRc?)H#VZVIr#dBrNH0Dhm}b zeOO(pnus-(J{3PjJLRWeJRcCweQN`=WtquI$qi|4J_)KO)6rll4vIu4*M>OW13BBEA@@eXSynu6Xs4W0m%-n zzv+)CcbZ6Iui#!OzKZX$4s#CsgyexOfo&C?8ciO(7oCNL#$cdKq|(EPPv^yWmVBOU zojk&bG6v0L9{$u{^sQuif_VadkE?||M_w@>cLHs)b(eBbX7K%>^59VNP>Les&0AG{n~Ng?T7D6-|6~I)Zy<=ZyS7rCG{ya`J^Tn#!60y$RI%nFuTg|+MZ8DwuH}Y?EJ2yK)yE69__q6Nu z_B;l$7X@YY%N#4LTdlgIc(m?q1`#Uiyg9c=veicuC@C*LN;5Zall}?4ynbf7%wj z;6`{xh;|ru1aOOG+lBR5|rIKQH<>?i}|Y(;r7H8Tx2>M)E6o`d+$T z>TS&*hk4$4V|%)JF?vaQr+EpUji0SQu;0esF5Fk1+THZtzq+-%X&ss|a+$w6L=W(J zR{x6&qJv$BHG@@zlLz$$*$F!)28_k$Np|0N_pGHtp*^Vc=;vHhtn6%;X?IO``4>Yw zg2>-r>*CMgDf)e&bBFe>CV~Y|^n**3!Fm!}OS(9!|}YeV^bUy)aQf zZGW(0*JRgY*S@IVIEzh>vxS9n2w50!`_%m1Xy-v+)?J^zfxdD{et~IuSrbERLZ@7_ z<=dr=wzIZkv!s`5n0H@)bb^nkkNuI`;-XfWvbNTpS+3D)JHu-Ewspw<9|Apj_u=mg zr3)juT7uIjnu~@_&x^3@K^-mCEy!2bS62wrX!dr2goP-*5jZ3*UULVIHU-+I>X-#( zrw}d*{_{UOx4AwE@I*&k{X8?Cde5GHhzn7{=A~X<7gDm$vW7OcHaF7GpNQ=g>}dVp zK5uo=AE|DYq$oP@i}HN(Fn_cinICsoeyDJHbb%w5_2G6|Rfxq8y>~M1I7T8M6FA(YTE}jKk2ptxGUbyWwuNhwAmNp^e zGi*i^!@$7iSgC2bYRSv-m^#=o8-H*xF=O_$a|FmO3=E$q5Ae~>%+;98)6Ul3g~yYh z;-5QsfX^?NSt!WbN*^G>XnVp%HLI8=3jEv9ugE^0in8g1)4*bPW zVd?7X$iu?o;o-sT!N%<1Y{BxDo12@3^&QK*cTB(?OfFvbuEw5B_AZqF8svY+5i@f! zb+&SJwQ{g0dl}c*#KFy#pMv5=(7%8FHBU27tN%!{cln=X0Sjb#`G(~!Gb_u##|9qd zd%4P^WaVjQt0iV-XJ+pL$PjqX{+92b`~RPB{v+|fp49%&lbjqJ|NZ2Dee*w0^0B-u z;J+61uig6RDzIGwNPH~+-g*HfgZ_yc+))8 z{%0lbZC|>9oMksTlngOc2&oe+avQcPNF^j9MVF61$vYQl1@BSq)VRddEZsn@{c$?$ zDfc8e_RaE2`|@J@V!O}D1^1r)&G7H6liy42IbKE6(&AK95C|wZkc{kKZ%_?L9csmj zjKwQhVIe3K4F1;}J6H@cIqHAz`R7dtkAh6b2oJTzRr^1;fnk+FW~l$yc;S#p47~6V zW__Ih9qVPtWT6bW{|F_6gpz~4fWz1GWYhjHxztMA|DM^4RO84%x*%h&-3hb*o*XbW z?*Fe-OER9b*sBG$2#gr?iB?g?z<}gvu~E?n8w*QGSy?$oQ(GHRc_w>}1<;lVR zJ{WAg75q=<(5aq1Fu9Zlx`w!ERBaxw(14=K1ea<~!W4e}%OVSK4{a%+0N< z{ysfSu62i4jpYeX70IRk>GciV*Wdm(=s zt*03@8GM(LLQS~rm$>A~LshuEFD;{EVm5Ga1^#)GC=Sq2JP8T90u&+unw!^c^Q^hn zX|Tmt*VIHXEG3hM5)#UOqLKfi{oUM(<&X#o@nyDa8o+E_4}L~11qaGQj2cfi5(JCU z1a1Qb?lv)bTz3=YnVLHnD)n0@v@LSPcX9&+a{R96Yh`!;lBbXWW)b#c792|x+QMCI zpp=x9%k>D-i7bZ>X=GgH!suwE(O747+@R1Q9Ti{SHs-3Oe{8%9 z5m@nVs4^5E97IN@WN4@ugTwUY6*7(`5*d~-xeYWB1Q9>ouc#`%7~xHzprj^91|#M+Iarc1BAmCF7ffOgv)d%2a7vt`}_f!U^s3zJ7h< z;UQ6o3kC-ziU=ilB@!s?#geVz!_M8cpARx#{$?As{M`Pzd9!>O($(v^(&okPajaKE zT1RMGW(b&yFL3Je6eB~0p^hvd$in08M#3bfBHwzt60>sBH+pLBc$LK;%Dh*CZv`?j z{(PZ(d))erSfh+pWssDFj)gxSO+lek@x0njq0{&!9Fw-JV?FfRdhBn-=oN~Zw!S2` zr~0(Am->;%Go#Jk+!+G{!?!OcSDlrALn+}g^DXQM13}LZRRuOyI=# zx-1pVlE-)5UmffvNs{Ex8u&0-;`1y}52)xw6slHT+ih_4v2c^qSniTmm5yWe^n8>V zWTfN0;&JEWGImJp-i&6f%;P<73JFIeC1KYqGzLrwqWEIKqfTiC5p(pZEWBo>kTncjmeZwmY(5>yoo-X8I5eK{h7$M~@~ zSz==v!4)d<58Qx3zs-0P)+Zla|k`q2jSOj&Xw~-rhU_M11x(`|!c?*`Bks1k5`=q81rju6t={1Dm*U*dSy6C*d=$dv4Q)juDoDvfwdM^~K$PB)Ow+-#TW;aF z+MkwHg&?316h1{b&$W6uV2|uXP#)sE+6o3hkqZ^j9Wf^rMIxCa56JPpX|Fg7k|FT5 zFqYYlz0cvpGcy)0rkUBaN}5Psd2xKla%vTQ=)<|JC$R zAjWOq0+CKhe2ikL(d@biA|m2cDU?EYaIVI*OuyBAeZp_Aglx_8WzL@hih!IFbJPpo{ zNfg9y4OK#-Rmhfly1#Nsj-`ktgDSlEQiTF0KQ}&*<73m``va@-FXE{`qYsHJ;*O*- z!;4j2ljm%-LFKPfre-+CqT>*DKTZ1}YRmOxtmX6B%)B{r+s?31S#0=|h&6H{d{3hF za>(ASOk|Sf#dLk7mfd}UxVAPveUjrii7m9&0A&V*szf&QQdRDR8b-RoHIEIrfsf+_ zlDR5KXC(1-FQ>`~4M4z!kcue=NHw}pDQ=;+&uKS8O8Xq5JGWwN)Y-V}b(6uucokj1 zXQ=aby@c86hPqE_TkTAS2)uB4axzxWF_}A(#pq{wh%V&|8<`;oFwRX&Mm{*u7<_%S zD5~T$ZpAOkmdQhDzaNv0^sLN2XbFG9hTO*|+#dEqb4P^iFicA| z8?nkAxP-CQ-BvrT%f7UXq>Rwdp^F)84KcUIGI!jX>`xTM3`uDIzy@bW0KQ{{5HpER z4(fR^%(>T3=y1thw0rb$UJ|S@L!d z2{U>4&&IUtp=S!tQcG!FbbOiS#`8IY#fgLnc{ZzYa52=t`4@F^YU(zcoQeh%qWiMp zi}`8s2*^R@$3pbvxKrbbFD*_#&rbJ#_@0 zFo;RFVJt<{Kw7uao`XpyH2R9u)D>;`nuUgE!j)fTj2JRSSA^UUoEz{-6vh7s-r`g4;jau-0VJc0Ml zlF(`_SfXbGmthVyeLH_m3!%|#*ZEl3shXU}CT$)r=F-F68YJ(H3){gJT}z#XpOG`J z%ZKDl@e%Txw|?F5TVvom=L;En+N$(x5(eegh^@aG2by<3eu%aFiDt9}T%nGhNGHRm zo?xNK7w#E}`qgzv8^U+LTj08rACAUz6zm~`u z^@}z|VjW_{D2jwBRu!iygRs=JRiVzwB270+Z@0G7l;rI~zS-@o$Gf`E5w`)}y3BMS z-rLq$9}3}p*~(V(G*ko(*g~JygUZ(3lYr;eJ@W^%!t&*;e6WKexiAbQIdygn8JTk; z-cP(3Hp5ARM!(Qj#wnBl65Qz0!Nb$fygu?IUdP`^x2CQ7<;#~kB{n68U*Gb>U5nbuDA8kKflmX^e$Dz=txxC| z_x>VFU?*X9lq0eXR*B3WTy#dF<1JAlrcNs*nh*K}LZuRXz8mF0^ZP-Gg#qqCe{t7N zQ$?ch)|HX*_noj6h0exbX}K)P@MjklX>)_3Ova` zmOE+D6)&m{Z+HXyM4<{%3?<_)Vvi-^$zpjMXUP>LP<{+>Wb=6&CccxA!StauNGO5h zR9w}-`tIfd1cFq{mdfk6V0N&EJ&%xsZ$lh(XOxcomuUBHg^}Zo1 z9F@47KE!2bq-b~7vNh||{i~on0D6qZ^3uXZQG%#tQ^&+{^~Jc5-plB#HzW`;<4NSG zV#eWM`wOqJgHbDp>nv6m^ZL$skKi{%zYelGPxeukI^3widpK%Et7nTGqKc4*?$qQ= zHM>|GrQbFz+Ea#Rqho+YPyj86+KCkj3JV*Z{pn-37$FK~i&Q3B!KN~`9cG%K(y zGsH>6s%NM6!REdXyP(X1^Tux&|0MCJ~0*@p0ZM5TmR*P2=q^yq$NP zH^M0eP&rFY=m_xr6Yg7PwvtmB0KnUHubNq~rc*N6=>`F+)ySiB3#A6NdYlwXf1(** z?~OpYB5n28%w3%Q2h6?2I9W_$fZTC+j69ReiDGMeo8Ti84NtIrnoHz)AP-2f3x zd!fY9v9Wb+{$)zgYGgpOMgDB9rY=xEFH&0onmId-K9zYyQL#vpYkt^Cp-unFg( z{~a%})|IqzdBQm}aTZM=>fB@V6i*sQzFFpg3i+ORX1lbQ$D zm~FA&sC*^)9#4BiJwpHw{|OyRJ@%`BvX&buC^M6Q3CjKlmLNa2@@VgIkFvCh;bU|h zFO<+q#uGR{6p0v$Q}lOK?$Zv%>bbT4I8*v$Ky;r|F5DwBL~Ee)vFu$HyAeQs_n*a(#RF9thAJDL|2) z$z^}!Z}vSuCgXp#u^jC-(P^_rvs<>wStfJFeBS2l9B+%-*hoozLj~c2ypTqAJc?)+ z^rna7*1h})5)(u`badg2jEt!YO_sM97UVQ?`O!j!Dlk57T+;k0q{&$##>W8n6(91@ zEr0EPFeCpRw+(PXB5qAZhRk9Byy2o|MiOa(s~gq4Py3qAI%^$!P!)_A3_O)y z`kWe!p#6Po0zrSiZ-$*K7WFwiZeM^CQ*r6=&F>s3gbZ2<5i8w#%lB01OyWcf0!9M( zZ+^*V@96$m{0#*mG3(hE|9udl#AAdD;#~2he7fm;zS8D*hZ%??q(#b8EChm0vS13X z$`W1=FyVm1O}FXg%+4ay8BKo(Ww4y!?OI53_MysA6FT1A2@l{bU6&K1x`Kq(!f*}7 zdU$WGk>3Ym(#VlKU__F_gC+rtZIa_Z_SnrG{;VoiyhKxaswmaxEl6fhR( zhme+EHgl?yiEf)Q9Nd?`_S@A8Rvu&_;#ZrW6jiLtqiXD(N+EXlhD7 zzqlyN%L`N}%^Q*^Gu-(!)fzIcGO{Vj&;hW}i9vaUY3BTZckaha8K3>GwVAlu1309u zgu8eF6ZamFJPyYPrRlrlx8H4N3HZbbjj5I>aBR*aP_wA^q5U2l{J3G73qcOaf(D8- z`8~J~4i8VqOE=e2#;?`+A0yEnRX9W-4elPXG>l&_Q5b#|IO)|m1=t9$bfQ(R5@Lun zu>I_a*;vT@U})1v1LBYb^m7jcA9HXj zkH{kR>#rhlMt4lU=wS?!H_sQj&tvto1~v^y^t6!d7l*8>^fSv*Yz@fOu{*8_1^4vj zZx(uHa#=A%s1Kp=*v_%yIH=NiYE#Ie#Fwr|(NjUdn6P}m$wrxeQ^%VBn6EYtd7r?2 zKKj$yV@XJXv|Ck8N4(0fC8gn*ehugBXN1vp0{?Y-_B&58NoHqsrJBVsaL}nZ%!-HJ zD=6LY=l9vKaQxq_zp_ovgQ?VO{+Re(3rnbA7qOEVVnkvhU}8Xk0vE#3rB0NP8YUT8 zsFuQamnthcj^Yxo4Ekc8RalbiuOn*{6(LS8-1P>qf=qFR!Df=6Fl5|`FXAzCPk5Y# zgb$XuPB6nC(7RE|Oezr(K?Nia_R>kYV~Z~N&zb z9eZ>Zgu`Dngg1C-5I9nSlH!wPLNUO$5-_k@H;41R_FEtEwUhI(x(SLM;Cp)TsJVjJ z1wrvjl1>)KJaWBg*s8TioaBH~KtUUCmFqfeko;y!*f{92x+HoYfAEF*k)<`+1hqCa z9koO`oJYRiPn-X2pw*Ogy_H6QL%eYw@O%@X6Wgz8=%?vbtv0cz zBn&e`7H~IYIJdmF*iIZrGN-<=bF7ihjTDaS=n@R#GCNULhRK4X%(WATK_g1{NDmnP zHOXf;GI`17!Q?orG1(%z=U3v6=(;m)y0?Vbt}d`eiseA*C#Llo@C1|5*o?7Qm@BLj zfEBWmJUSlTFMF&GBO#&qQc&tlE@_7-2=~Pu2G%)CAQ~HGPD1M8=zxVH!zx~kPV!yR zkiN)BZERTbXA$8}&f%;w4A&{rTFAsK`0TxwIkGitlHcoF|Z7B{vceq&U`DtNcbLj6P=0)>2orsxKJS|N8zI z++(>>?bWfJX|tOU@Mww*WX9YO11w)MVU`J1mzDS+srIR*<4XLYvII{IK^xmD)!egi z!twl;mis#AY&6KoV)hJu>l<=mGA&3Kb2YbDX34NurvG;3tK$W09S^$B1Pz_D`W=*U z1qw$BA@a7AN?~Wz9mVP^Xnq7`dlGgYLddvtNaWz>5 z;T1EgJJp<->V2@VRABx6Ty7y5oZpd12BibDuCku6K4*R^@mk0(*|Yd(b;WKGy$?~n z6ZIR$KXBPaU!u9xmWfiPl8lDJ*av80Ecr1ZThbgA=p`GzHI(*UCP96Gb+)wRbi0na z3j2uB+P{9w;!!D{RIphbmbxt@mokhgJHH>rvn(%;3yMGN0ks11_vPrL_Npk-4v9Q9ELG%yn67~`(96md7ttm#%evAO;{qS?rw5gjOLqe=^wF=?*(G`1I1K#!ITVx`B-G_* zkGn6#U}9o|j)Ee1e}BJj8S6McT62A?n5;_(=7NKqJjh5ge61HBA3vN#2KoiOjho&| zG$_X}P1F0wsT@uE^W3f!_78!$cpOb7f8*wLfu6rjZEe{jJO^)j&5DF}$;jf#^Vw1- zFwr2k^R;2&ukm}F8>Eyaq;H;FWsnorwx>19R_j?j>b_w9o@6W>Cg8Lu>ihA7y-G#^ z8AKidgVm*8p@BZj*i`TRIdkEJsxJzzt*jYFvKAo2Nr&_(d?hft2A85yx zH)tn(gvnS~65g?~X-lfS1XRz%s&ot=(=ZA(h!I(oTZ69l1=CK=P`qkuYa_E1Q*;|o z5kcKzFa}+YpdggIB&g)o)fIcb1%JH*W$UI!?CMHL-{t1wL228dXFmlIawm|B%ft`F zu9YG_76M4VN9-plD-f(Fcom5AzJA1&+gqgIjjRf8MUHeQ+Mb7h{|&kS>a^}~q6i=y zcu3^&(fL$BIZHtjMusHbH~-dn0Ik^?9lk$yct4()m##vVk;g-Xw8UeP;~YCxZ6aXh zF%=aTzY#NZeh~1Xbtlxbu3F%$mk9DHSP_XA8`iUnym&qc4#77X0(XF5pCRJ}|J}KZ z#&LQ@qp-sT0A1lOG7wN(yu6wvxUsb~vY;AYK^(1({&tiGE1edwiv&HZk=Xv)ILZf+QG7h zf??qxM!08-4xQ9|UsICRCuiEXYmM+M-+k3O6Y?1gKMRpi*X04(mf{W~L^$Tzlu{Bh((F&42QQpV&Usf18= zCnAES63Tk{a~4DF^A}`?%%_bQye!sie`5re#o8c*Q4Ys9CQE<~!4Jm;PiUjFG{LmMT&EyV~1>{2P?&Jjr zePYnlxr=G_-LA>r?fb*^J+)no6b#Co1%CIGB2vx)Dy(?$=sgTzqoI#EIm6|s4evA} z%!1;`+`$iS0%f4a+8lG@x&JQT~66$$1t$AgiQ-SYE{E*V>xQ_-?;K^iFBN5a>v+>jN?g`$ff<+?{29WCO{w&dkI#HhKCXFL%p}HK z!%KhqV)n`_Doqyk9$3nz0RIJ4C*rE7NLj&9&-b*n5z{NBf34mKFs3Ks)~7AthqkZ9 ze*MJW#Hbv8FMpUW2IlQamr@y+(5RzwgMh9n1Dm6{W13^QW1C~SdPq0~WKEBZ2+9xY0?=b%U#c)Vm!nRR z7N=@jt{VSv1+^n_U380qXz5YW*~;eneN~PG4?nmpF4lE)7Q=a!qBXcG+3M-xX7=4& zmjo&rT-3F_h)*9k9%s!;_3=KTFDbIaf?KF}VLeKCy7BCGo&mAdN?5PDd(xFP>P2VT z->a$sWuO4K?02(l9HCw6rse*UaqMjp{E5+%FKk^wfuoBr0wjTFh3einVsDY!21IhzsrS9cLLvewjRpArRq8E4?|eFP*xO1o zM9t2d_{ap%KTG7VDpq;uT&}xNyQQY2>BCakAYLSMM64b;-E$pfD>Ht^3!xH)?)jW6 zT>to`zP`RteNiQGCUi$c&OepBo)F5EY^615;P;m@1O5ApziXSbuy6AB^7d$J02@#u! znC%|1NSDiV8;GkETf_RA*6tLp3cePl6%y zdO}EcPgwOoV%$cRQL|39V!P6X^{pzA=f8*YviToJJ<-|8xtO^0~6Q^ZD7O1ve3-E8Ds5AU-cu5%@L1p3GDXV?&oHa0s)u!L!wgK2SjM{HD|&_sObl=ilYx1Pui{z1VxpW<} zz&VfBtoe(yw6w-G8~>mUwehxCOhK3X{0Ia`zWvxoH8N8FyhFq!c}{-;J){zGcp|Z}r8ZrWO0%SNip9 zAu>x_B3BaZTnbXbf6gIv?HE*CE>>dq$pnsCW3E1ga@da~p8d+bBNLRIo<4V3V6*CS zudJ?KwkWtZdr7CCHonDKjk-u(@uT;3kA0rfDY}#$rlMf0D^_1=jxaNjDxUyO`$`Xf zw64J|C$|pxu*mz()o#PPVJw2 z)srhoE zxn)#M{p@c?_t2dGpbqaV==1JHyg3iAAaq>&`BOjb3)p$=HJ{=`!jg%FN6-^b#SB+YS414$9E+6gHngc(Q=`5J_@BWqJWt8?5Q}s#Pu4z z$rz%dGWyO*z-lL(M7^&!$y=6TE4w(8qgt7fWf(;8;Wcki<_(!MGtElTUh>#StDUP# z_{I%rz%q_{HLM%(gW7#=YIUGKLO62a8K^0{xYDr+MQ4-`du+Y|5gUAezGEP~b-bT^ zf5-bUC0%fj;W$C*aJ!%4H0gHS^5zXX?>pLrgV=HY-B?&FTlAQim_13s`=lReA1KXP z3h08a|1j1sMhYn?pjNmO=|Z#A^+m!EAusFflTB@+CqnZy4x@nZRWYiRH9!-6yl}=^qUXr)b~};!6?HaM7UCd&x;s85l{vJBa0Z>=Ko?sf369v%+caxzg4wsi~;a%9cHvk)TB&ua^VIZ43JKuGru>oBxNTjdT>#T3l zc`lujzB7p>sdTuQnKM^bMhBX5*!^9%0)8g^<11oG^8=_}XN%6urnd^nw$GE?g7l9O zu!1T^@#W}$-J>cFhh+!`2>1bcp<$Mx9hjF|abRGo`B!nH-f)z!NQ+ec)wiKh2|~(Y zf0>PD73c@aHzRI6*l6NEsJHn)c{4D%S%iN0iE_v7x?PwGxF(0UaP8~ER+GQ@maepw zvHzSoXY)zHo5g6t7FG!cl;+bXtSY2*k%VO#e?ukBM&?Tk8s7Vq?vWud}!-DYR%qlNkyBgRem;Os@sWNMVA|u6)`$aJxa2g zEEXCWHm=*h(H>@;l7;E(tYr1<&U zg;;=f8tuiOd_3%&F8;XCs-BQARW%wt{uL1yf3@C3Dl^mJ_fT5g9|QZvfcm{&1W_V_ zv#`L=U(}bRT)XIwaQ>emo^UrxRLA#UOOfJOMe@1Az5T40%dzzZeIR}B3fR_+_h|+1 z5FcO-tMr@gUjvvDw@$qzECyqU0n{%l^EX6}om8Q%Tjj;=MNtRS?U;Rib!si>Sa*VG zEBUsee2m=QFu-15ejEw-d$;ovvfGpuTid|d5QbkT{y{ntMg0la91FdV`wNG_53=u4 zOlVuL)a*x@o#zd5COQmXwhkT9dYfM^&|g~HX6!~wh#!1?MhiHBdIX-n|J@e5|D)%Q2Q!!o zi<%V-|CXpFuqhBt@UeQmQbJq;kD2n-CHg5&L%{_vsj+S(V5gbS-X2rh&FwDXMr{HccxeUQ}i zYawAJpX32&iGsteS8tALqpDZa!T0=b;t>&rKJGc^r`>Gf%PzJd?F_>;M-CvBwb0~5 zDK2>t9EH#tU~g}jEX0{$fcHzl=h{|Pa4ZSkn3Jw@aAQ#pF?J&)-6FsF#0B;4L|r$9MBH~P{Ol!@!VVR7g1zs-Br=%BgfGum%T zg$sTdweYYGB<1+}ym;1|!P=O+S!lU=&A211Y9o8UchT;{{$`LnaC!Hx%IPZ5_3Gzd zF-H;af#q@-;D`$S3u~hsJp$GPU-3GU`=BQpO8K0nEIf&=wH#Cy03C0W^^P6{a-2|! zS3@?JIU;SuX8XcZm3A2XXV3oPva5Hr!MYj zD$XOmzLwIS^arXP>^>@_?q)Wi!tM(CZo zhQDC5uK0@MWq7Ch5kd>e@%<)4Oi-%f0$V&x@E1d`85nor&8_zz$pZCjSgj$E9@TPS zNeZJBW!CtlruTI5;2vQS_1Obbgx<1lhG5e^V!?JfpQE|&xj23enK*tOnKO2%3I@iW z90_U8mEW#E zex(!-3#<;wb6mfw$YP!~d0jc*6w+akCcpZ1RYKQedm<^=WGL%siaZSddUy)Nmw^8^ za0G85;UmV;o}tTn`#R(?AGBZbXV}K&uLZCdJc(SL0~E%TAPD|<;{oG8V31_qt>EK2 z+GSP1Q$}u;;zCW$JZp>o=ikG(LX%AWJ|8@q-zN_A)1nZ{)z9>&+QP?^_$fI!Mu0j-ll)>F!m`Azx*XjX-G6^QMSK5IR?D7L&^OQCB?c2Of@% zcoD7xyaq}S7))^a8Z_O$OXu<9%4JB(yLWPttEnhJervOGH1u}2xNp-hlHBp^@=df! z@vRbIOU)v49AavO+6r)m>ciTj4xTe8gSgZ0|5%-V@e`9A zVvb{Zj9t13FKKjQod{R;Y(8LntB@>I5}QHnTqhe}kYVawTamgf^j=K>UmWogF^P39 zu1l7sT?`2LOgUY~>)u#rVGaGMO58BQQRql-+YQ9Rq#o$*IAwEQCH%b7-z`O`u)dXP zL-peqk;`EEJT=0*D8~UWpj+#5g!g2QT1IP{5$N(qX}sXk)zFaeSa!qJWj%z6*A$j$ z=7n3zfp35@9`x*qVbVz^LeS-5Y+K*6BYJ~PA(W!d>apK^z%OJX%l4iOTA|=MLNKJ* z9@!KGbc|OEe>^Q$N$xr&a2UA4$q)uQRftEUdo}kXDfTAg-*YvKJAmQimP{VNoc<2rogWw)yMxqBgBbZzG%a zO2uPuw6B*FnbVLp*j=DjJwN^O?-UHswluQh!_1yEWnkLG4|z9_xShAJd|*o&q6%Cx zeYw}zB9LUuxomqj;9#*wWYhN3YgSwt6A4Sm*H9E4HXL=RneV#vbC<4;KibEn8$g8= z)=}-etO#73oj-7nA*W{R8gwjh_k~G9StDSA{r!RJ)nQMX+)0%PWruI(0S+$|7j++BjZLvVK|XmAhSxJ!ZsC%C)21PJc#7TkjC zx9{iFd;U|@uHJjuoYxp@?%m%^8@DJ10NIXu5b9T#y1D^aXqn>XY$Go0?#zu)#H^H> z-8>vGdBkDMX6xqz@Y9!RCE4Lb9OIW(&WmhZbE7|T@&7~jG&IZdiOxD4+lbV7BV(%z zz?VBo7%rm_5XktzVlcdeSCj&jTbHnLTFpMeyaPRKo5d=_3aumzL__}kZkY{@0|%45 zB{=Va$>HC!`$_pSYjeil`}l4w%^MGVpjh zF@7I8z#E(eimjJ!f_p#45y_arfg8$E>;kG5m{uloDZz1rzM!`RhDODBzyQ(d_YhzrkgH-tLg#IJ zRj#yms$Z@#Af~VU^+KVW0q=e*U4HEWXkn%{z>(Z(DtO-F3;edU*98!HRF|>z!b^VM zb!un{>R8tOW-sYri#SkHVd$*|*-xGyfz{vqDMq$O2?d4})55$FgsYHM$W+LqJ1_DT zvur!#!_=T<=I!*mAd>W5;(p)=1IF0kCAPy4L^ALg(9c*dWc`^fg(W=Eg(=SvmRN^6 z4SS7Z!IOa2g&<8wR%`UV!E3eiS|!V1My!V@uE$szYq4~qHno<7PgSUe z#tIrlKOcz$)tdCejEs){EAMn-WRf#!iS@#Kie49?e1z0N-w}_8fxd|Eo)X}TWB(l51-0Ba8W#k%>00ISSTw@1crdS1`SFeP)`@X zK_V9h_C(jU*h)VT1>ax(HQ3D3XxaE~QnGQTw#Z2Npnq^J#}y_9?fkk8h(U?ADAq*a zmPkd3I})kz>fcnML^nC8k~x3!5KWZ?5n-hXb_krzAy5eZ8~X&ZP>J|&0usy&8KwG< z^aI74uqYBPWOcTO^Un%gi6fp0lgW{JqTW1o@KK+RGR`s5ETWOsh;+-Qt`fbqg@V0< z+eucb4h6#a8opAbpdk(nNl%BE9#y2Hpr9O8HgA|+Apt4u1N)qq^K>j(av@85OJsn4@nU&CTF#cK>Wfm|83wzx22bM(B}Bo9m#yVfCE1L&OplM7m3`GlHr8rg>N{|DrTAZ7qA#R zZc2(&g48b7_YiY1_x7|{Zfxq(+A})dVbXUXaCRA%&+`)7fMsVydE#`k0mI*WMTX>2 zT;R8gCHpxpUzH&X9NzVG%!q{F4=r~EK%5}Cr5MV~)b5wiIMT&tXInk<|F+KGB=3t- zbuLUfH|iN3d7PS;;Of}s&E+&`UA-}O_LI5x#!JPjm0I6mVR|rly(zZPUnC$g75y{U zge#54Bpc$UYn6xnR2D?T)XQjlDS;?=iv$dZ5%1CS3 zj2>T4p|5%ni?a%JFnGGU_s;0lyOY*zBzuVbdxSJHzrT%1ziH?5@#_9OvoWbgA7`x>xwl+_`+%!G zGi{D{>K$534fDq+sb~E;u7Qb6dkL8ICW+2Z;lVu-x8d&AA>5~e;_kO-(ou+xh?H!q zd>Af=0KRntU_VYe{pm7EJvAi$KK$MGtK5C+1gR`(GpVD;iPisY`Y)kt*s(d{MO`wx zT!#;`5XQ8bsQ(c8Z#a44xLGb3yW0!duei@CuH)+3OPbvDa7IP#m9n@{o%)b@$v#!d z@PZ)fh%Z<10R>_38$X_%l8Lb8GDSkhC|)_#bT#dkDMe_Qa^2E2xJ3+C>faGH=VhOG z4FfyYp#J}2K;+_hRX5l2ceuXD-H)h0cQnoiRAFay6svV=gPQD?`*zT@X@IH8eb4@w z=L48W8pkfvQu)|Ck_y(x{mXpt!xt`FE3siP%!pY0FG|5wA?F<``&H&U{p{&0f4mlG z5oJ&Zqfb=kYh|-RR7szApx{tx%T0BHMa@PP&gGTW_Wt&) zsiZO~VmV$&_^E`Ed>|T+Gr~q)XVWRD&UHX+fazfP_*S} zS%~{$ZvNrZF%jr|J5mM7w53&&;*0?T^FX zQtLVJ1r@uPJ?Lzw7L>{Bo(eZdn~OClzCM3EEGqvV?f#z&U}Jan?FHbs@&J@opejHK z^UzHri!5SRT3!nT>yc{%?K^&SEAH)(x*LM`_ z@k~u6s!md+py&(ujg2m^H3#e5I-wj>byNpbN>zOuo|8o@cq#+}5T$8Onn;Um82r*y z4#}XTE&xoy?eNf<->X5vCxMlzw4m&mzpV6GthfJ2HE4t`x#Ie>mD}f{v4*BOo=#$W zOF@GkrPs~(Hy$aeQdZWySzwcY$;rDHtP83^8E$M(dh|T@^`i8)tmJFa!Wnt0fnf+1o zsE+D)xO6&Zd7R6l!zezrif2>HU-(R46G~*qtJBU3>=;GJ>Pjboe~suyvP7 z!JuwT_xZR~ZI~CvUIV?}e8`V+b@1z*0f49sOJ${xpup|5rd(9%Ifq1x9wsLb29fyu z_9rK_WU&WQS+_v)4yJOP?eSIw*B<}d4`ONd~&1JPh9kw zfS6d(=l)6f_?{Z~^t44_VdHq@&!4;&-sjz>2FG3hXP$~r6+GqEuW|ian$))-DCpA- zW`m|5Z3{OB-k2C>+C*K7w!#JtOBtCF-b?9p4q`G_JSW3;8 zQ<3QBpB=7I5QeG4($9S&^qT(Vv}9V1QHv6&&9`=~%W24UljEkaKQ!^g!ZE>WR94U0 zn!%_Yio4|erTt$QYRug*_d#-kcUOQ2@df(hppTI6b++ES^>$DBYHz}Nt>Kq^X&O~_ z$@nY=1PWN-Wp2lLJ~cP25hO%{Ww=adX^bHCh;>d|QG6|&8e-1$v20Ce0=7a%YPPnY z&DmM&Rb^$rhy^?z)fVB-Df_(dPNlS6c^Ao2kZS#|`gv z8=HLCRr}G&KZhBko2^GSQ#a4mzvaBTBGzHcfRRwL{-ZRCcgb^5$!dTkzBri@dhZ7( zpc@X>>i)KM*}Gn-H@H@Ksb7LwPS&YjM?F+#pmTh3VzWCKYv8f^nD7z71LC3fbsuec zVuwx6W8|dN;ryx3TgV4S#0;t0Vixb>1Uj93H;8UYpeKCh=^-z+=Qw zW*tbaKy1_I9)Si;4IXreJEDex@M$)xi6!Q81@fCU2b(P-mH5lg9=|54%yY}Yun)u;jCK3dKIW| z%P5ZvaXzKPH2_^}IK6c<>nQ%iw^xI7oUMOsE-MCjpKMLdP)Q-+_%y%<--YvE{dj)< zG42fX#|brtEC*5m5fZ2g5KXNX$(1U^DDcgj`oMNT_)mY@c#J0`5{VlyOw0lhw;g`I zg#P_G48L}}IgZub@d&9ZQekNPWpa>3O)$87k;5Qw<0h%q$(ok}nLGj$`{&|f*A^eT< zxm_PiR~|gIUAsHI5u-FGtYR%`-H)S-a$CONftiZz8KyYJ$DKUWGsFYKTL3^c?gNv~ z)Q!th7d|zcUHFFYP>#!0Y(WuG$NRUk z+GE{Uq*I;9z2TThzx*j8OO(#!4FK|%K;rQ2NJck8?L|xLG0eBSLxd-h5-M*sN*Obk z6%$OUu-yM}>|zG4V$Jd{{UIvx!1p|ceXHU*$!ehj$!DZ>?2qM8J8u7Vb^n*3_Y}!4 z$?ADfgA%&M%s_Faxi1uX`GSphxV(WAz4*0x!@GQQlh%mH>5rl+j3I}L5*Ci?V(T|; z84Lv!@67t2@M?2@9k$Kab|_QJMe6W#%6yl&7(+Rt(>$BLI3-1Hs}KrXsS2@m_&GGN ztGmsGpVff=qse;zQ!oF{_u|_~b5SsotM!j1I2V)aXoT$UnpX*5=>S9zzfTjx1qlA! z$yGpW&;o-mjkVc;KWZXtYBj-&SGNT~mivXHBj_MuMX_um*Ta-dm^DAPK|}&zV$?5T z(e%Pb;}Z@&FyyFdCQ}%cSE5)!oCp~vsn$GVNVW~3b?wZICo&$G6_n_vhGu@=zp##F z(2%h*M6C4dhEi(QZsHlV; zT>=PBLkt`oGu1cFZ!4faMuMRk59~~P_`6eUE1ae|G>cO}7_j8-qn}!XwTnq2xCc6e`lm6&WWQvJch0V=0xFFZ-u>jpkrJWQ-;4^IOZTL=_-D%e`Jzs<$o2D$fBPk4jJ*3j1Kipfm=#jlF+T=$~ic2;{#&0bV!7n2{v z1yCl{FFlUv?q(CwsA&~BTcMRZWw3FstEA5W>orH+AJgPar4pGWQQDXwlrIm9-EY6q z(a#DDd!(&R0|qn|%D)~TWl`USL)#>cpS|yz{hGt~H|YquntPkqHikp11F&h#Yl2m& z8cV{JR4WXtR8-63-`>4#+n5XFLrSUbM0!A)iH{qe>EPzinPAW5)#9S{Mz`hjOs6Z+ z)7dS~;i+>cV*7G$(dZnO+hkP-4%zU3gwV`(|90vR{s&6D)1MS)&yr9Aq{>3KNy@@( zRKI1uI_Kz&L0gLRLbFtAkvI$7BZvsVX>XYPQzXgGgY!TO0k1aMe_BV4`|;}Bvee?7 zf7HYWXRhJ2whdor>2%zXfp7vk36*y(x?C`wY`{&np^MTyTM)u#2!l&PD9UGe8I@qI zqTpRlBj@!uQMhQc%*^+wp-eJZ948s!*6gM47rI|FhlkNl#iE{?@5d+DHulE?dNX~Ear`b` z8488o5qN7V31O>yn_4ID{3f^6n{T0^Hi)9QD@qVdF;g~opg4g@&Jx?d@^@S7?>LdAGbue4V-}AN}ArT$=otDl4{0}_Q zh{pyUw$*v0d{yAQVIBu39^?TdQB6%eKLDeJ4!@jL7HQ;CNAyt3e8Zf_b)yT=AvNf0 z`&7pE<<@#qSa%qx*e|G<(1Ov)P=wbM&}e3a2PI`n%ooVr&b~>&Si=oE1OA=QD_5M}CfYgne35zjLthAsua{gAj-@+va7Kz9Zc=usgS*Qz_R) z#jN?6(N$wZ^bj(SN#SUJVt*5=UC~g_JAh8SVhX4;3uFAbU zlxpN1NsME^BI|hy!z~U0r?3$o%&Z#Q6-O}`kr_B-WMzdAcPa}% z4ouJ}l@rPIPESu48`fXLUbDs@=U7@KH_eB-2j2Ej|94cW=ZyGyhgEy#LCVCvsvw)n zSYDDB&~e>(4aJ>p2uDNmSNS*}&R?3Bt{Gb)dE$#@e9-z8pg+)V_LxstyYp8k!j?+Q z3WK_*BQOOg&`c=e;(g33jLq9-W5Z2VD!^Kg*ixUxK89G1d=i>|FaZ1PXv2L%`& zT-6_6zKQs0&2U6xXx>j7^_}ie)s>Mbk%-0Xz6#%ilf1_cu zW$exM**5UtWN|+pl_XICt91F30}?pO7UsCuH6>n(mubFWwB;J|l{bJ#U)ykB-Ou6b z!gp6Ar%q5EKo7zvg-KtP0#e8tYHDWRZdIU$%3CZ{lCqT2{-#|R1oeg8e&KRf7d~IZ z?-GEVH2t0Z;aF`xVqDSyMPi}hVe5@>Jg

    hL_mTLY*0P07v;TV2#Aq(ON`W^&|q>ZGQXccOcNxh zu+E$OnKFr25y&;jxC8cUOX=)%X%SJ_1PV9A3*2!*_^d`_-)(^kwl+aSJ^yS7JvYtw z*WXh*cDq%SH%E&;L?R;r#3114AyZG@xS|R=LL>dQhn1x@ZtM?aBaz(orD|ZozdT4| z3YZ$o?DKDZ+q_v#ja-rZp8rTuBAyH>9q0Us#&3}?Y!EPY(;rjnwJ#%LCo)zu^+9!j zVyHgTDTIon-kU?S+VMu>;pDVdvd)W029!U%Wi-$KsU6jTtw1?vQjZFi*MeV-Tk3XI zXL%i+Z@uO<$}^0^c?D!n`87fRjJD3>Opo8Gr#T;ek*21mCZX$L2gP{ZbTeK>Nn_aC zxso5=gWr^-`#HJxls5t)!b#ObowNvFL_8lXh`n;x=Cq`Hndl5x6TDLUnyd!34aPd3 zt2KlX7|<;tK?3v}=jFMd-!}p9lP2e8lj6ItH|<{^uH*Zjf5b~zLX~#8W9MXB4|e|? z-p(Vf=*6EIl4^1oWUyYKoOipNF(LL_7ykDGITZ#O{}DoqbyJ^Iyqr<}SMjVc<8m_< z(z>O`iD*#Iq#?)z@k{Pma~M3~;>+@0`-8AIGcx+TY?*^U7RXiAq0Z3v{PptD-`VO! zCP`f8%QPDT-u=Vx2V1-*-lRD;Na;^$ z4el)L-ORJk@!z5!zwVJE4n?MB@%7*rq-^{>hd)<&MUo1_86G7i(uTr{JG^VnBLc0Q z>bNG0&UHI&i`S3yHe~{Q8F6|K^4%ZWoSL(ou)8Ayoozb@v~8-l(5AFa@8wp3ncuFjbxgV+dRSVIe!+Yx7X}_3V&- z`moiWRxM2$w3GC@8HEOzTE;zz(dN%&3?3O6di$6tDl=A65E=x#i8t}^M1oTG6NG|s%2RFCPN6+r1zX2eU8_W zDi97Qmk8``59ECtS8Iy*G!lwSXxR7@@-6Do_J$nM)ZsJ&;Sh!KT#1as@^lm>E1aG8 zSnwVCTIX5(@aDNQ876{_%|qZUbEB+XIM$2=sb8J|Jt9hi5L!ovR&wYV++iYRY0+! zaCz`ga*26h6sOnd^1D3Cl|Hm2X#$!g%J(xTqMlzfa`xF~U4(g`=FwSpD&T@ws0Oi7 zpZFU7ny`nDUkU2pf0+7oLD;MOL(od zqB|@`Kk&On{9Wd+aCGW=s62NK=5Gqck?o3YcL%H^43W=-`bi4qS3t?5M!W5zSiQlw z{*5k3WzPivp}G5Y+$psNw#D_Yk|Fi9c4z`oZ%lyyZ|iZTiKCG+ z1^6g5&ha6x*A>c-_=o=ez57R=3#Iw?=K6t4?7z`-=>ofCP@&ISH_q}rsF>t(FCMY3 z!E1&+gOpV&P@u4RY1olF4G+pS(j4g+OgsFcaXifh%Pi{(k)*dFpl4k8>1o!nIzx0_ zfI0)6$xv7KbHLMV4q|V1#t);2v}8u@nJmu@o2L>4A%LP)zW!RS|-!t z(^92_#PV_clFcBv=EFoJ3Ogi7?S@EeUuCnzI4e+txRr) z`D6<4wx5HoI?lf3!$+V(%XvtKx>O$aJIpl=Ds zm^R~hbURS(*}vUqd@a>l<|fSZXMi1^l!WGl`8g;cd*m2DZ5L~@6YUuz$93P`tdP&B8E7-W)9*mkH|m5GwFNj4jvxpmyqX1%N?U+NSZQ}C zp0)y(g}jU0DA?P*V3kEA*#CYvGVCvGGjsVP+dCUZJouC4THIqCSK#9XsIOLFfjZm; zz4b!&!P*(_RsL*_;;<2`kA<`2{K|>q3n~QYbfp_|6elG^_V~`0|4_>1W*xTWI-Djs z36fvUo`m@pZ;%bet@$Q@Sw|$7;Rt%6khP~I-&mcT=gNoHu4TL$9xb=gS28u%yxv5B zsj(sys$pDr?Wbz{-+@piy$E$s@?XFnAl2)h8i>ScY)}rzAf*|={V#OK1$XsdAfLP! zqd5=C)aqIx8TRol1F-9)Bv$c0*`Gom5Fg~I%FvCuj(HaU=GzOq9d`d|X!2RNv2Ok) zY=j~9XM$*CBIVZLvcroA30rHob6x?cNo|O7utG7`oRJzF(*qob6)}Wv5|oi&V#qRod_s|oXcUZRU{W#-r~u8_@*7ix;zo-%twvRKG>5$EO> zaCQpqm%fE~lm_`a1Zy=L#dy`jqXh z<5#@3*MnHdNVH;H!W&pqj>i$-1IVP9QRAx#v2k!p0bA3h;f{w(0LGdyj95wlKv^>( zwQ%!RjKGYAkak&ZteVI|4`95<;>S*DLQTWHu&YI}CtrjiEK^hY{RusFJD zOl7hSGT#~DeyNsBcf_K#26RX%NQn^`Nl{+%Z(Zx^`bIZSg&iH4|5>@mlLq?jwGFYU zr!@O5DrrRZa(sPEF>fUSa*N+a)DC4hLHDoD@iRXDzXPI+Wsmj*oN|BhPz%qR` zv>pPH*oSvmHxh4LUl&yDnJ?&Y#AMcG_3v?~ij6P0sGe?Af9iGcJLF}L5Ih&#E@B$* zNSlA#MrbRj2sF2XH-0=++;uabkO(%37Jf= z-t{9rp(*~M1~q2;++?W&SvxxT6Nm?F?gYx58!%c{f$KZPg819=B-9h3P+tbT{S6RY z*e;4b|K#9|(}td!?1LL~_@YQm3Erqw-vRzns1%X1-$BR65;G}7PNC?2Z^B7H-Pl0+ z@l)x~O9{02@qVfAmgk%*`@!@ews^LjF}lFCZeG0sUk_Md$;tw=UN$N>%}85p+J;>E z0d|D;MezlSDecguZA@`_XC77FTexT-sbWHY5$KW1YCQ4%S3F95kTdQba3X3j7t^A} z!?FA7z-tWG$Mp@2=<{7b^Xbzkw)ONcye@e1sf^$o-Gzoo ziKS2(*4tk1U#)~6@io4tWcRS)PzOi{C)KuYtTA{iXzeU9~P?Rrd!licvk4EKj(`jW~5-;_;@Xk zzdQXvzU_5<%mnhRV&bihgTEzhnlvdj?D#%~%o$;n&lyE)Um%qVCR^4daAacz;&UD# z97HZBg{0-wKo9u3GrFG)tagqux`mCOod*v!80u4Qs@ABqnoh8ds9iCHp2`FgMHnQB zJ`aiO)gVC>GrWF&n&EF5ZNG-aLl4_so=5x|kc{zBE|)lj*3;K{l9zH;biG%(f@>?D7YpS=-9LTw z&(Q@HfzmMwRWQ)`g~&F$P)B`f{N9}@j+nQ=7BviZ>?FssTySwPNG$$zQ);!=oOPQ z?^q%|p2h-3^1j_>`K@Vz!*bU^Sm*|DytaAieb^on2h7ufLl>*^P309F^ZxEmK_iVZ zlv^rea>2NPh}M(e5JOyLbCY|hzq+Cg!JHPud@%OeNJ!wVy8pTZU(0qK=4uUuAKb*x zZkim>YM{l;_f-{&y*uGM=09d!ydLSB zwz3;%FtS@(+G!_T$OSEBh(@^VD*o679p!ZxgQN6cZaJj;^>*O?hn2>!sgBa&E`XzK z3R0_H0bF)bTP8zcUyNf`P`L`U0uLT-5vJ&eOnFJ(*5hfhdB6}O+C*1e=beoQCjF0D z@(DIVnQKnOyW!3QUWDV+s~rJp+G)mVRsa*uWl!@XO7|4K+;GS$3EOet8xcBEbD7DM z<&1KAviit3X($XugA6YoD|BGS{Pz%kqX~Syp3oqiiu>-BUI!8p+}X*)-UAE}<@cWd zRJrMer_Tf!S#1=(B*&wU_tSpL%+z2Ja-&~>3Zci#bdAlQK*spae#1NLTgYR`x6nsC z^Z_&+^MwzKbYa6Q*K-0VC3?%`E=cW7!|>k=luSZ0A)?K39hf#Ji`AZCJv0Su0Us=W zvD5FMf?DKEhLXIj5GyEu->r$S*z_ztMb*R8wW9@SFcXWtbb#~hJ|8HY%j=GyA3lZ> zy+$GF80nTT6ZKhMR@4gF?9{jgjVA$i_`vJ%wOWGeT|7YnLr0;{G0|#6-TkH2>GIo> z1{kJGXyUz1pO|o+0u0X%NZ7Z2$D7N5S3O-KDUDjjn8D-Ke+(iiBq8}i3gU0 zXiC6QN=5gYCe|#mBxxU<98Ie1VtpUB-#YobBnE#}`XCdsW;|hp?u<`1+l;^^iSfdR z)G4OXCj{vr3P?Gj*2z77Jw-kpZYw3Na>`FC;5~!B2yscjmUh3TEs+hiIZ80gDMiWr z27pb6iZLJVSyb7Hp6?H*cG?UOSzuIP`1UNRRpNsAD8Xiep`oD_B#*ldJ+?glF)vX--&CioVw*%vHWRUy;J$u68 z7khBq3}Ave%%T>sp0_k_N6voI)io?WM)z$7qS(AOS9& zg#qo%JDRlb@$wI*eOf|OP*!fvo$t{imoqWB@{s&$VbK9jS6WA6qN^f%nQ}%H`1&Kv z^KT7*9Kz6*c8&lbaXy!;F0rGNwu`yphlTrM@6mM^gv|@w5Wzf=OC%0`bo-}tar-Db zzc=~VI-&imy{2)^>XQ05g!?ap{Pkt)CJV6C2@)P>AQpqBXcx@}7#7pN*V1^%G=2N6 z8LhAGjHGcPd~#$va1%d24Y{x5Qct-{9CY`bX7vzQor72mn{%>A&K362PCfKngpbY+ z?|BpoSd;JRIAjRMh01u$bJMm$&Hrq_@_$7(b)46t+xszpQop{a%upP>&hP~Tw;QmN zGqRrHc<>z6`qMp6c6KMeS#1o|{9%}dl!8){bh~jP1SfJB{*ti#mXw(qPmQ4xEI{TX zf(C*e*G;bKwfvRM0Q6-q2}6cqjO4a)6KJ)$V&B!-2u10^vEGKV8XB=t594DiR|*b&s$-0~&97K3F> z#gB=3Gm&Sx%syU2JDFGT7`SPZT@%wrXWz{miN#N`EsGkHiTh~C%!V*z0+!DDN2@5M zIr&PoWs*s1NZr-=T%zR|kKVJ5Ki6FCO#$lZ>4>*1;){=yN71a=cVh`!TJiHTjGj1P z@fNqiKu*F!Bk^<5K%!u5U5T=?GCGzC!&*LoNE;GtP#6h=H^MXp=dBRSk17;*S)9X2 z(>eB*Qhpla+>YWr`!VavA4xhonGB0=bg40MoG1sYK@eRrb~i^e zZ5YR$`S!F!ubJH(q4+aPU3Aqos-z?8o^7YxsPoyctvP=g=NU8Zkchrfu_NW~a?`QG zzGLs-yF97G!WfdckkJ<(OOsPGl=$Gp4Gbk-gT7$Aon+)z1nA7Tfs#!LNGBD?^{ zBOM1m%ATPA3_Sh3(<7^$0_w$3yArXpNpru=ohgy$wMW;}y|uDZyzAk+_4gvOHDS+~ z6f?U-#SyZ-kiOYNm7vMtt{IU}ny!MPziw4Dkn?VUi)xBGj~khr=}aDf3egAjbR+@^ znp}>}FEjWG7?1fQ<{vPS@fF==(h3Is313O`#l^Nwf2X<_sjptXFZ*CT@RpVPJ(%cr z-aCvkRJmMqn)GbJG&w_MY=FtASgFWgM20h@Ww#Zf#nC!F&CR2Ffj?{=Zu;^$g=zWt z`~0|PHv88m+jF}t!}Wj9l^*|HV|*`Mzar#1;)*NJz#&46P=p=%4$)d*3P!B8KZO-mdfq_t(scdxG8Tza4x1n%N0gbF) z{jY=@llLcugbPugRPh8!z10s0#`4s7yUvo$rqI18TH=V-xE!;;O0?xTZxy0)_gb8) zU4G|xXdktDGw`d+z!g?JB+miTIfiJ@nVb!~#|#_G$9k@t#vjj9s#*$C0HFrMrGg*v z4;4dG8wO&-^^c3c4CJt+KahiWWoMGmM5OO-zplSrB?400?GH&3b&NqtN)dha+b|HO z)Pa@Sfw}50p*>F6{XH+fL>6hL;_(Z(OzH$=afxsDk%`61h+k_;RCOj#O{(`J0U1&r zL-ps{4}^okW)Ut%HH15%J$@}(f`66~T`UKLD8fc_hf}ico!a}XdJs)fyi6b#tU{`p z%~&~C0tcu?-JPwvbg(~TwQk;`ByKWR2ahJ&9DDjcUTlLu>C>=bw!lc4cUGWjuR_gS zm@lB~+Mo1dNUK~HdeOo>ykTRNf}(P%p1r`3+*~s3ZDbJM=Y}Dx=UtFelE!Px?4JcF z8r=nRHF;Wfk0)|ETqhwzooC3J@O+#H>LRED`qMABcG*RHh+;3-RC*&CX zYX_1I`aq18xIe|D+86)UB6c)_QkzWY)P1&PQ)VUq6L*mU3ZJ^d(OmaYey760Y82)G z+IJ@zP23@XP9(yjJ@fONpDHE}9YvhZZ`D{S4X19}XEu2V9s0%wt00xil@2GOuW=tC zuW28sTGxfA`e$io$t>pKvU&`^lyZt_i;-mO^!MG&cZn0uOW>j-|FnZTqN_;^g+iad zXzEN7PP(6+Nnm<#KJaXzWI~!5aYe^?$@!C57FB2oK2zAA3g1gX`j{#1gtrb{xzaj* zm}zN`nfKoK?+yL&QtKdv;P!4NON66;n>Q<@o+@`pb*0HjOeE*TH1P0FBt#$hfc1j- zz)zZvh)&^mxy#8*tNJbP7&@X@%r}NW_*8y64635C6&#Pej{%xIcWdoi#~5X?wx0v} zHG%2!K1=*2fuA3oopqk(uu~j2yYfBws^6xyhRj>w`KzzgMmTKkUI~-{rs!)UOBTK8 z=r*)n_?05+iQjo~N)zGY9QlUm=22PYg^D~{)AeTr1(^&n5$mf*n)$dSZgf?|#|2b> zNhdY*F(s9VhV{~ikLKucf;vQ-4`w;e_2Xw;0?2-9NFl3Ak`t>~$8{pz25H#vDO=xW zpCT2c?yj&wl0phmm_l|)z9YZUPW6KvMS|uO{09ElWBs~_oy1{D2kH#-DptX9(^odm@kh* zfO|k1*Dj~VH5FDruaMPQ;LKnV}KhSOptTYR_v47dD*0T74Tr zX343hUHf1Gr9815r$^&jtkuCsJ%UX=Ym#Qcc5YfU^fhs~5w6g)A;X zY*LFNqLA?!T{to6Y(y6fLhV7=W+cbBRq|jlxY$q2g4@wQwuhC`+FhI|?{4^VkY7={F0b}>p&W-v!1-&bj-6xqOI+ba_ zMTi32xG0oA!cQJJ$3FV>J2Z*R7 zKZqGZwz%OgSwP56pK~+~>)T9~gILwIK})YxaUIP=4>5zr?ee#3-+CI1BWAS2T5jmp z!AHE^w^P8P2Uhz1)1V{@tiv+InA04lh8y^%p6qfy*11I@ek6SuxKC?~XTnmyZZu>w zu@x1r;FA~IXW2;hUHK+jLtGVndRCr zkGrrVzD|?uApy-`Qy@Z4Db!Ssm-S{STyf7R%R(YUKxCFKvqrTDCLzQzq?s)Iip!Jo zSeTkH0AyNPC?y1u#9)(^&m}nz3P1QyHJQgq>F`wq2f;@V^KVi%0Xb)^guyM0*o7Ju zj3E{@9pAFew7C4Dx&>JtlIKimryPP;HEwbvVzPa~JOKD{~vN7Nm59#VfF+0TLxS9Yz` zScm+Gfd|r(Wqjx3+69G*G4IL)_8q$_rI<{)!9NAZ?&U6#n7dFsuw&yzJQOkw)_$-7 zpWu%}pNEym$Vg7VC$~IZ@OBi|@BQp*G7blo^qLHm1}av+rs$Ow3u1%33?>1q>XCBhYn2Zb*@-M9Px@ss*qeRcVgJ)aRn!r>8P_dah( z=ONi1&h_EhOG+|(I9*J;Y+py{b>L9A{_wkr4Qv4Z{oC-ejikx>S}QI-ZHl|TnyL&V zoHZ?{l9=l~J*Bs8nM=*{@W)U=eCo*pSx_4?jD1j!r^?7fR0DEKFv{V^H-a%>sn=%n zqV;*!d9^TpWNNV`CIjJP*&yMHeZITmg~`jyyBVg8N1WU(j~zm?=o6&hCWmka*cvOU zi~bt!-rS@axT~@;S=Ob9$ze?`xy0uA0+eGTYB#wWTS2;UKgCb{}Kp@Sh3U3N6 zaBPa!gRwA+aNG#UF_?$N5EPBTz{Q%P>A1gze#&MP@lqRPCzc?MRoU_)Dxsdy;GFyie0^Oe#AnZxwAM8z=k4P(Uo+I091UilE!waP+>qob-S*4UUG zpRe7HlO;1$mc<dmYB=w_9b=H^=C^yY$OT-&MQT^P zPZaluSIpdGuSuCaa4NiWXacbk$vwwUs_Y~qBn5jT65A{7$Cf0>Acp>Go5Ik7lvJE7 zg5Hb*v}>=N$(#3_EKjX+-#jdY({a)DOh-*E^?%R`cR+vhJjWhJ|! z*T}o~KP2ztN@fl3CZk{M%0zCR3!a8^FsPqg91W=(U}giRoh7!7<7 z^C@WQh5By#LX1UwFO9dau2 z9SvWahbnE%;ftnEKX-=ywO_;f`e63T?tOg5tl^=g2NzqLxVjMz^_|e@mj(bBP~3sYbZJc6fA7qYZzSP^{3@(xEUC`CIY-eVJD0)^XmR zEq+JhaB%aAwi2*E^S>!z4_NQlRbQ*b_?8j^Co|N*^~ZG33!c^~mtGKfHa&W)yMVTkkhXAe84U!NBSmd}@KndA;V?J>DV?gRF0Q5;4TRRCYok81gb(`Zf3DD_0I|FDu`^yB=?*#PUD z;)->ObbgI}oH<2UqSHhgLs>4Lw^b%gm4&@ey+XaR1^3)oPCp^1voO-<`Eh+RwzU9p z&3(|HJNfr$OAY`p58PzAqPwIz>wgFK;0k@*hMmPqqVu*G6RWXXCQ84*yrkM{3X6#- zd6j6sAfr1wrH7kx?HVC}H+a57f-r`lxk5)rKlKt)hFyHRy8AdxOiHo@tZtd%#fXie zDf>@m-dviUzh@5<+#&k@_HK+U9A$Iv`zyt(+cNB~{#UK4MML0olK?pp^-c%m_oByrZRzo9Bkdp3`3RzU=EUKu2+CeVUNlji3ECF+Qkw@`2+@?j{e5FS@Pgd!!i%$s zv39foAm(8n$XBrh*i6OEc=A8Yk$U@55K7~&#hlwZ!U!pHJ*02R_^pkR5U+Ct?R`D_ zt|KXMpV5^-I}5J6+$h(^IbBR+9C)y@Ym|Qnx};7uv4f%9lqq(;+#FCPov>9P_74s$fp0T97M8@+l(E9@@Q-ZMi{+$R z`@%fkxnwoCr2l0Bbb=mr@?KPmf<^kRa}B@{RQIU)-T@j<=gQNW6R^QUXY>3M=vuLy>js_ zP9%zj`+NOxn0#bN2Es1)*z2!W@{~ZPiCq|=kOl!8Z3@$XwZYDT9W9*6<+IkHR5L%| zzDPguahlc+z#I7ilx0pX!RC>R!lX^Ot`kf0z|hci~sU63lafZaGRSPp6K8BUe?r~rx_SL zeoIeyiNu#!Vef%Ifp?^Xe4Qs)BPT3lkE59rTlPVj z{L6Vb1ABh}RU!h6sPlYE_^B3b^0i?C59J?CF~iApCiRVG_J1OmfPcPTKolqMptC`f zL!KVc7CF}U4C95V1%jRoTZcM@asCdXn4YI&f!314sSwx^u61ayJwQrc&EjkdyEDUI zM}mpXuPcYJD(4cZmRrYA4x`@=QP}RP)g&gC*pK_cY-nq+6vl*e2nrTktKy3?^-%J~v)4L=XC+|E{^j%L7*!*>pxBM=oE6^Ef3fz#3zo z+}2_JHe$p3%hH?qp;^Oa<0Zo9!Su;+4rpx7ih*NS471NM!hpkP_^7^f87mz)p;}e#@W3-!U}1M6>e{Ma@-T z8hp_SHFs#l=VD0*NjB!agGZ|5$D_jmgnjyB>hZ-pHCCB-uXE3AY{W4!?CSUbl~ELu z+n))bv$V2obR8|m-;wCaH8p84Y%hxRR|QiePQ>^59w}niKo^ycbHc3MaZULE??xbN!yDRs z)vof#VxJ2E2C3+<3MDz4FL1zQLDRFc>zsB1<6Bb&`RS0SChr(6#H{?f|6P+Y)g`CN<_H=i#{u$-jG zfX<|Yp%xQLW#v^{VP8t7>%ICNEE67OLZQ{p4?T_FU)ejZboKG8idB0inl)ENG`od+ zZusQf$a`oREe(+GpapIj8kU~=^P-Elqq8U=7bQLVxO`i-3oQN5P5X~NEidy~!-nsc zlQpQ0fu+jf*T;?5P~uO8c3Sf(x|oOz!fsoWWw|rp-ppK!yKE4!Pa6%aF z#}nuUz7OH39tY!Di)1uOx!1wsIY|Hr+f=~{2rCdZw^ER@ctYB}1U>+9dGc2A>qD0 zg9dFDA4H+}Qg1y#W>X`nsbg&S6HIS70;OkU-IpOV$|XTE`<8oa=)E)e;b7Sc0}~_B!b;&?v8pTg zNl_sRxW?qS1N;ejDXL(W*~_tbDH#}6N>C|Hz`73_OE0t{JAxl%Do>x+g3ihw!s_?Q zF=dRb_g;m?hp%q*wMQ~K!!k@YKJ#XmHJ@98k`P_kzcJv6+$j-1BmHn8sPcD!%!1#4 zL4Glp0S#`xdB3PFgM`PN?Y!x+E(9T`pjh~a&Ze|BrA2YfRpK@rY9iaKuVD3f*JHJM z{;L=slP>i4`rN=AACK^rJ`9sHYI&5=U=ZKVaOmcRp;l!ZUkxPT?axLhg*0S5Xid3Y zaVuA;a@1travaOulE63Yq&%4r(M4lQ*7VCm78w6XX;DRP`MCRogI)r2ijzYOm~is2 zT}xQ{_JFmBY+KylY|7sjmce7q@P>VJum=--mXpHCa(#2LA-N7x(P429b&LIbOs5=; zmfl!9UlnW!^zWU@#8TJW|sUriEgXtVy9M!zdP-ajFf1Sj7fl{Tpnw%b~F zNpON(R#ws)){PNqPqm2;b)FodH}A-wSs^I+e8V^nyIhx0i@GR%bi6oOu8HV4E5=j@ z$@}Y3RvLZ&dWx*wC*6d(7wk>^mRsEoG|Q!M&vB=& zj`4lM;Hz+x;=s*%1OKWT9S_IsDqdz?n6rqhBFz&29Pos7oLBy5v07*J_%B=l*iE3T z!Qc6jHmv(Xv;KC}=+bkIC+4K5kw9dN5FGtb+lp7#t}@tA9>bu&vnp(0$6aIk#r>N* z_;oNV9UC9hj0y`y@Ovv3|C$&DYqFZCSv*fVwyw3>x4CiA>9&>ouXh5lf)7J_66OCd z4r)Wxv>)RTlOfl%4VS9Jv3YrcnL#HKh&wM|on(WaTI|CJiYE50RH@c%>I)t~mn|F> zc`3Bj+BBv?oq7SgF6CoxZ-PiwBX8fd66Y`_rLUB3Fw{*4xM$ z6qq;$r?K5VJQP6_c=!*;5!zodHn*~=9Gw-ZhG=N`PtG%{CoM{V>$yW_d zQ8hl?t{u0sh1HXKCjmh@L6=dn9$uvRG}~;R{#L#lY~a$@ubYhGbp^LmZ5W$v1KAtD z>S^;1U;yBClH=|I9lLX*<-$S3MO-UF#L1biUZp7nq?J`Vznp-45z8(Z$rP>`bHviI zGU2^IwNm>9<74oiXV;XMJ>jtc+SN$5H8J|s!G(}v#OiPaTn#4g4G@qy*J8VI3hcp@ zzHEC&!QFpTRt@jf(K{Z#m?U6|DnwS@!<}OF8H)+e9#QYlyjf(;_LW3upBqk&)DT-W_UIZkUJbysGueg zl^2}rAs(;`(czKEVUy+4x~EO03G>kU@zvDZgM-mdS9NY^!w z#ge6?lICz>6UkM^v)-H{x4(Nc=?JL%q^46Ft$+ME`Y&A zN1u(|Iv<=LrZB!Tfi6KMkS99fl!D!i1B95nL`Cll=qN=GiN1 z#mN^`0uOs`5?cC(5&|wT>F^Ydn=CFFOKD`C z+X&Wl2N5=i_yKNmNm|2XCI7py0~?x$=-M(Oad&T55Ghw*YomA zqw-wYe{qz5US&B&fEK(sPhTM0sS(xmG7m%WPT-YK0 zm%#@Rb>mvSD+)If-QMXnLoq6|PbIf+e*>#`cbJ=#)P-=Sww%MbV-)V{PgWEWy(t$D z-SN=Et%QIJ4hjN?bMB5Kd$WujCPVm*vs=o&TTXI%q!Xp>{rtZ(AO}ZHZxCpsFO|U( z_Pih1z`5AVuzdRuC+kQ!Wenc})R1d!N-xp}bc2GNP=jf{S>#ACb@mvpEoL3&@Jf_i z=7ypk*jbhzrw^I^%`ec{lt~b;50tce`?K>`UPIS01ojh=c4lvHPx|s-mrEreu(PGo z(nin#X|6D?w6868CP52zcLz0l*#*qT;Maf5nek*P@?;*si6!@0siOn6r&n5sxIi#z zxS|Si&v(Eone#*nR4@x$w*l=$=?0>(5L}N`rE>LQ^Pr4m4HwVX7okoFN_4(c*|vY; zSgIq?AWdgH#28;THOc+O3nPCxN-USU^=L(p53aY@*nork*%W)5fXA#XtS<_B_xNTE zPx=N2M!&)(;PYC}lP0w-z+=%udgxud3dTXjF{W3462EaNq2 zVZv%HC51jUz1*wM{66X4ZSoSH)1o&DyF~}i3~(@y*&veD(Fi#!u$sPHzMMa6YMrI) zz+k_Um^98>*zo=F3>_Q0+@Y%?r|rR^VoN&T$Yu~cU>`i-h^8f1v7u>o;*b@zm5@4N z*DPEPZ<0wrloU*Yo^+gTWQPfTNN8w|sa_iN{`uLBnuhN9FdT<0buNJmJ1=T5zQ8xh z0!K%XFQDmi;p=zcglW#7;A7y_Meo#O zw=zVWoOW=a0vfen4kV!cdT(v>y}?PsoEA=9&2ln(O_C>?Xa^ewyRm$VW+&NPnz z)Hhyl58p24I4Z$?OZ2p!AXk`Fcs3~+7!6uS2QD6J#d1Vu?`OP782G||@IMRbj%ei? zT|IxNl%#Ky)WX=*-WjWwwr;rij8AcnBQNL<2Dn2AN>F<@(`yGm-PV{zJ9zvBW zqZ*&Y4t)EGsl-SOV?hX1MMV!eluYr=pHZ^fS!yXq?mZ#mKUvME@w|ZeMb(waOMTP# zw~Q1-6+Wdp@bkxMQ!J*yC->tNs%8Tefm54+ENcdxx?8wohTuJ2OdG(sF)kg`a&{dG zkL4QEyX~{Nwot(BR$;f=pyO%e@R5!*8m)n@s+f8ja$!T(2`gaWzIf&$Fb#oD|Gej$ z)c)lHRYJi%EOj#JdFEKfOZh9i9CBz|Nl2Z6(a=RZ z{Ehp9Ny9*CuuCvFp*>|BKVxT@)=X2CJZugAomIEmqhC6L6pOMlzwb_!{G!x1o2=ux z{EpSNF~&kJISHJO%S(D-j3B(3hh6u|>2LC}H!0vj<C^E z>Ez25Y8}2WQYUhilewE z|6qH&$|W(Z+wq4Nso3qOqlJeAFU)%BTjNNofaY=VWLwk2gql#0{dzG`>HreTF@F945b49oJb^p_F^IABM1%t3 zYO^IL12(^cTZ1RK;&haFSc2C>8&Iae45H)-~Wt1iw*GvxIt7rb4&v*+RT;a2KBk&6aF($h2b;U8t|wA+@g>3=A9TcXNCVk zcVsiZ6OjMWZ@I?4;&Kx&XlKfeI%TKL7=D2*$sjU3(MUof&rBr=1->n}`5;*Qw5QYP zsuyhugu{wDYe`_4R4Dy_VRd)I&r<#kMdnc{1)xzuX<%eCn8o&*Sjt%H=hY(e9+FWl zcnRA;?=ojHhIVlvhN2sF^@dmG9@ve^^SrEC__{2jWn@gnoS*=J1J?9t$wGD&_)%f5 zUi3*uAoOPVYfSfRN3_?stm!?-dUOo@qOKOZ4S9yH+rY$K<0^DIZBn5oC!gC0m#(o)W3+nX14S}tX~*^a7n*)?KQ4s5FKL`&%w${kcp9i z03WBK9}+2;I`Zl8_g;=o2k?J6r|Pkp>?x{?OgW;68psjMe7gmFxBPO1OHuSE%!ZVN zt!BR>_P>PP3^kA`O$=-}hwrpR^m=p!T8<0u;q_Y%?>Byl`)z?!-pmTU?>{J53`N?X z4usrX(es5~coecXR6m`Sd?JL=3Z8BJ9w+>w&?BS7YWF8>@^XCc(uW`b4HhN36Oofg z*8pl?#A13EUFrb6)1MP1RwBFCoi~`uU`*7;_m2SMNgX!ro21p<``F{xB{}_p6(*UB za{hF=5rV`H6SS%^EIfRXBt4<~si5*0q!@~mi;vDp(E0EJSSxPb_U(p*<&_i?$G!5lVlsuWH;v$QqeHRF}E8TSgx9`R6dh~zq-JC z*Ni6%4pe}GAQAySyhF-I?qzUfnu;sze@{+hl#bSSQJc+MBazX(-e>^N zaCX^FU0GFgpxNm*wE|U*XrWYtlU4DiYn}t5tZ!=jo6JD1j9{nisbg=F@cTAo<1dC= z^NL`Tb)?35_h3uCd_&yMh30+Ab%DSnf5jnlyfkeW42tqoUG58L=36x$IG&3_JQ1g8 z^ay{@01*0qs{fs)To9NH`n1Im0}YTRR?H)?XL_hyjo4a4byj_efu28f8Zr(-Hi;cp z_92BfbrDpug6o?d_NH1FW{rM~&dkJ3ujCY^*#BitHx zOpHpWopm-($VI)qETX0!#pVz=(|>_Q4YLxFu>G&kDv0|cVX)fiEwxK z6%U}{S5c98RQ)OwgLUQe6liEeATq|d`!$zAq*R(Mvq$zN__U~H;5qq%a(g@&Ke0NV z|Lpnl$wR4estf@%u~dLY4y=o))`Dk-j$CJ#uPemi_r1B_4r-Atd}mY1k;*GD>n^~X z;dFX6#Nn~x6l*?7ve1*ETXFblKuLYk-n3(NY~#YAhs1e?pc^o)n?x}z+`?k~E?++n zokm{i26W&rlK97itBPc$n3!go72Q&~KDI@P<;CpgrmPpl8FIF{_iYy_g0`0e-3>xd z!WkJEF8hP9OMcgvM8~6UC((z^K1ly;_#Ia*8>fH{k#@c=J;RP{p&egvVH;RUN~Avw z|Gj2cAlU4JQbRNVcUo_LG_|)G*PW6hAef!+#)b&PT=$!N{N9rf zL0%D_70@TF8wet7V**#Pl)ND|(gr_p<+ASl@`3N}vB^^&n9(v>XF;lJ^-8mfjR;l- z`;UOx?M}b{$$INmcaBQ5;6sZrB}@8%Q%N}4x^@AS&j)#o*xEfuIS2Bq%+PnqIlAba z#1y)W2n5_eTz8h3qe2x->^l4MfDsJX=PUtm;R_wE7pfzHPnX)qNFuNd2FPtDBhJjQ z`gQYH0{Z$@fO)xY0{H5*r}xrsA&8=h(lHE!4}_52OIX&}@YGzs*;ZpL}~wE|gH$wx)W| zt#CybZ_Q4pKyRQ4EY0S-NgN^LqMUx`fAPSiUkOz=UUwhq?RG@!KrfqzRLOO z>E=9z)lh#L2YPcXlHW<0Cux1t!}E~4je(+WeI4xp8N54Pi_Y89{P;~*oUHApvtex) zr)hqIL3w|auRZeZAH)NPFeBalDZM-__k+L&*Yc|vP6oEMJOg^5e2MSqbDW!n=KE(h zl*D@VKR1g298l7MqwUTos%630Q54sC(t0J8;G5DEoS64SId54irjpIT_n z$%cM&46F}KqA$NbAEm=2bEj&-JFq5uGb_9VrBn?J6w2gtm~Vc%?!;>$l6{Nd^#JMr zFX)BA_Mv-ki=GB*$lhYdv{fgD50aZe6*;w#oJsfoTH!@b?See+4<}eS=*UZE=HSSP zikMi4Hb*N#TB=~{z*aK@CNi?%KY$j1rT?V@3HB6xN5*SnlWJvPa0(KodP7h@ZcU&g z*q^k5!xH&S$Sdsqa$N#AThi#!QmX)=TkTZzI-4cf(j4Lw*KN{jAl~KO?LunG9Lo7p zYo^IGG90GN6pzW<9gJEJBKws)~%Y#u=2>$yC-VQ3sr3 zj}h?43Q9}EZTUP*J+52VR@9&e_mpGLVOU}-JBerQqT%Ao06}5owxRfj++L3s<1;fF zoaLFBcrtC}W+jtLh3Yh`4xi=02sm6;2+hsSbMs_*vtc*Aay&1`u9h!Vptus-2}4n| ztJ_tVrVpLl;&huML3bk^wIwL2f)?qvNsd1`yL1L@xIbq zx?=Dv=hx^Gcr{@7%D=nhhu8t6`}{f!=?k81({`fu?H1cCsVpP&itQlB1r_ zS1oSGOGY*3Zb=NC@!ggIZ$2827DWj?jX__zgJ`2}$%zm_uXBc9`QHTIlN-(PRqUP` z$lYha(dqd(3yRE@NzIBym1`F*w$Q>maer8^1U2J)E3h&i-G7Gk!fS3GKUhXV{&Y=D z6})&ITc!^MIW-1yl|*FH=+*Szv|?kxb0TY1T@`h1&1?cjbDF|C-ZI3ke1L#kbr!wP z&re`)!>)ssR=09YDq`_RWsY)n@(#Eh!gwf~BP^F`tFWag0(L{{UgT1g|F>`7Ksu3r z9n_E0c=ZcU@G62KtE*G`NS^l5@N=t9AUE86gL#|^R~e@wDbkU1J5HI$LvoIvXG1}b zDZpg%X~Pv-Fu-v)(9^G-Ai4c#Sf&a9IqkHi=nO`M8M5yi%%UVOX&pN$EG-Sy_j@x- zV*fqe<@rEKM>kdXUsoQ@SW&Fo1yfpGImxnAt=3AJ)|*ZblR?20lUDL(y&#A*PnCit z>|R=O53r0k5C2jy6x>|}>X^{JcGtvGE9-j9(-sFAhzDZbTH{UBK#z}lauwbQ5> z(HSNfPjMAZ?xRNPyj^xm+je4jy?{tC^+t*mISh~-|_P7kXI3KTA)BqhoH_yDio{|ktKa~t-(woj`He)nk7^78Cl z%Zhs9Y9%AG>yJG_w0rKo{DP7Y=i{h2mkJ3+0dTO+V4V(V8Fic~jc!S6>saVSIqbQw zHvZ($^lspgO6Jb1)AUC64DM@d?}tnyDDkO+BTUIZUXj5hElziO1&)r6DrzbpZNNvu zQmB^bRCzAyL=-I$I?p~d_o7tvNmMqwy*Y%GTAm+Q%M|it#)yVZ@OR!y?rN@EHJmng z64@kN1QcYE?bO>~KK(pyrpG~_3rKgjZox`Wbek5Pfr1ixqn@w&2GnToz*uZtcK*85P!O1NP9t{ckHe``nOv=EIMt` ze+h1vW&0UrdD>9 z?c+Ex`hqNenwD&bbKQa8zb$Wf`&ms#k&jYvE)*zQ{dO0vNBcVnz{&~0jGYqRrvYo8 zBw5{suV{JBMMzZmTTtgHSIza06hVz2v?Dj@po-ZaUoX97zz5R2;1?QXV9PCEAKo$}}qjK35nx z7Bw)XEfc^PU8xeB7`-|M)Qo8WpQ!p-pvB~S4&A&u%gVW+ot-YPefj{TM_XNDMAeLn z$ifh+UU<96CLSu8vhqTO`(NVZ+}s+)y~oozkqUtrX0K!8ZOqBy4WQ?m7Bt+&2R$8d+lLf#SR32>t>s!MA2Z^x zUb!V9fkPt|H(Re{HW{5PR;ZBMDt0OPLVjNZexFz(5HLH%hkWkvOd?aW;WitxQq}6( zf76_B(>Rk7FI6xz?o4|hsBS+DMK@sKo2n^Ryak*1zeODgUjG1M6!HZ+Dk`Qmj!RK7 zu{pr6A>)Af`yFs`*jVpLQ~#&`qzyS+r{DbYPCe0}w@{|g>a`A-Zt2$1SfF&8#-Jkn z`C$5RC`l;iJc|1|g;_+G$^NX0=U0o+k^}Wc3sbTLDcIv-k^)>&ozowwny?G}X44>H zx~)VxIXPKaW35ueB_V$ip#WR5)@xlR+xJ7MO3F=!=(JWhn<}cZhoAMaz@!1PU(Sxc zyxK;-f7W@IH44?|_+-pC!XF0g2XryzqacYd2h&-5a!rswM`ut8@Jjp0yY?z;dX&oN zP_rte?+EBz;eR;w@6}^kYj=4t^*cS?{{E(e%>RS^9w;D601Ei*J}+yq7{$W`E6=Kx z1feA@!>V;dVtP8ZcAa5>6s{Wp)PX%*9|mK-{z9{3wM*PU1?@zJG2tH(0=V~4&nFs+ za=wjvD+v^ygkXgc#K5Mn?~D5M>J*GcJ=8UqS7>ZbgDkScL$Vq}SR1P~nAtHf2U6MJ zAn<)uLc74E4fzL$_ymIXns(uWy*)=U+~Jetbvj!(np1LCEt$3emwn#AzyR&~KYj|l z(^Yb|QZmmQ<~f03s+z51i%mR?OKhK}P}(hI>@s;OK5dGieS48p zE`i8D2dJ=CV<@a&6LTClefW?G_O#AoG+fxFz^NODPoCKk7v1uO;p+Sqy_brzN zIn3su&Ogv|{t@soo$r@!B5G6_I^bw%Xw{+L@C5v_0c0v4JS|Xl%?CrqsXX6iNN4az zAvFk*5cv!C>N}!i&_6TQC+H2>UKx)E^p%)l;r{@374$6JfOqmUz3A#ixG^n<6wFST zh=U{T-<1v@727<);n1y>ymg*}YIapezaIF*c&xTlKySG5?i-AF1>AoR{|50?Dy6gY zB{FhVzc4T`noLHJ#JH}vKS!c19KN-%aVTD`k^Fb?rfgy&_r2sL%Pypfn_l|5B1 zi+wH}FjJaefl zsKOxX1VQ^hoP>oe5&PwW-mAQl-^Wp@d3u5(k*bRZf~;YVwiNe%urdoNA;p|TUm7A4 zFc|b~io)_cA0zCA6vLRn#>o{KmxjN6dHd>!#GKg7xY5vbIs{2jm}O-119feQPp;!n z#zYbITK#I%tfIkOwz~_0{I-Q32j0q}y4)Do2A0)XHc2p=MDe3X&@0!phkv=EL@*JT zp5*kk_C}3~8wyk)Vx2VSQI2`k&<48|ve@OSvvlGn29a9_=orW&K|H`sOz6<4t8(I; zpre0uQj#h9hYrG_t!mt?1Y=+f$&9{k$5vij&~r?+B$*Br()q7?iAv=I{t(6q2G!a z5eaL2s1u^||E*3!mXRrxz^HF;N)#6pEtg5S*QtVaza^dgc8-gUE&T^28=!#@x~OQt z+57T3g$cQx4gGfdTEjqB8Z-z!2$wmbqQGaiUEIb_hvQoZx;*Xs-%kFpwoEHLZQwsx zg0l9^F0+JXk9n?VXid+%mDj@*N6MvQS|7(#*Ee_V5shmx04FH6`ih|o=BVImf`%z3mS<4-q2E)hz1sv-A(W!O%4 ztCJalC`f9Z1c9fh2b7q(mE}?_81UJgdlG}VsN$(sl&az~*Va^MK^rXFqij(QBKR3rr&|ipymu-tnWh{$;$0H&Py#nx$ z64#4m6k5NQ!Aexht^StX#H$>l-JPwtVI=vYl#RviZ@?;AQ`Xp(#PeS!&x)jiBVq=T zeEHceh7>`D&U&Yg8nNBWwZ_Q(7XZSIeBQ$?17uz-a3c-pGV}h{66r9@4n1eVToF=B zxW9Lba*HR)q7E=Vs-lIu4-5qiz^#=aelvLZc|P|MiJ-db>OWn{`e2fI!s~$?q_WFP zn<&3|d>haR8)Q+#`B{P{EAIegJ%pYlz-$jwmF60h$nZa<)e^$61oS&IdM^fzx}tX{ z_CklcqTu(WtQ0{-czg1Jh@9Va7scl&(+CUM)1Y^1h?Ub zZh&*6QEF-LHY6GfMCUKy)GyB4;T$hl+sVROm)q(|r|aRY8hd+4jf~3cwWkU&nv+Uq zF-{%27ea`kHE0`}DlwnQg`Hp-(#JfdwRC( zEbn6>V4Tm6u?)8lm;QWGY?iCSGU*Qj(_V|a{ULP>K~t6A{I7KwAS3>#j zahlQ*->|q{Pxh3pZ0_l-yJrV{+me8XJL(jpp8h73SD;0dLI_{TWHNy=`}q@7`ItTeM(V-3T?)?aSS*;Qay>Z#O@pm`$}ln=@#ovEp* zQNiVV4l{5+U2o~sgSd$guLG`#sTejaE~sDSZ)99xazv>-ZX}GZ9ts648|w_n;a4TE zNMNop#?sx@sHwT)!W}_;zR*60@As=!Sh5vv2qQp0~i!K3ge??{XFa{Z3K{PPW8HJh!a z+sUEhn3#NCk9Dr2MOVPS73IgaucPLt;Mx6t6vKQdBJO5G`nBIyxxF}TbCa8*U%h5Y z*umya*3`&Z<{g(^Mo~8wEE302ZxHj=y45EY3;neO^>^Lc?&b&<^rfJrtDG#JnJDS; z;!zKkiE$uE2*`u#spCdeO=T+c3m9;B*y2&uZ<{&i+F_}dRp~Afwrp;+NrovW0_jKx zxOQhi<*(+2sZkZK@N0Xl1+?cc~ z!%pvymIr!Cw$3HccJc-Z#gluOG65-TnWW_8|Cj#l6|UC}^k7mLWk{JV6MPZ=@F*a9 z2%O*yAIMg-YbES;Y{-|8|MF3s*^CLWNvqG4fVo_pyI7g?dbf8gs{2zvG+})6AcVO* zZlpo4zT!tBIvf#FTvrDLB)nfOYi#<5NPJqd4r+t35?+J|mi2Yb1S>$~ykfJfo!{dSe#AjFyUT_}I z9|0j&%kn)QL!pQh)BI1t{B(yNx4Pbn?2Q9k0xmcQpXbP3J^1HbNB9MJJ+ofqu zqEbJ2q|~V@*V5*2JcVX$X-c~bBZJGiRLa_0hb3pTbD&u6S`uP21f(i}M4E_y%8)*t zrJ}X7l)UzU1fp`an}Gxvz5?q@MYs?+I5_BOH^9Ykb$_`{AcYdS&(UQ7Cl(56HDK8P z_~lYnF1Ko(gEQhEfR+Ilca_~YZlr5zRU z65Y47{Zf{EemxQRD+O@Dx+bW-{0kxJH|vAuIVrhwKhjHoe@{#z5MdcMTUf~kr6uuj z^0r;m_c~m5MBlBA`z8A@X;}3;m25T>b#+sbuEAyN1vXBKE#n7come`eOn$wtVMp3I zi*X+4!NXyTXkP|QG)}xU;N-%fCTsaot4bcuiRQx*r>0bGcQ=#_*s~6fGa?M+sRQ;k z-%J&dxdZ@HKiml6`Fn?O;=zCgg3gDy^M}4iIlFu9sZY)KyeYdqX>KKwQiPNoYsK;L z{>XCZ`eURP3^a?W>Rp=a-CY=!^Q?~#pRCpqU07ZN9U&}kU6rWyW70#=2>l*M8MY0%hs|H<6PZio$)c zWPvtcTND(YhKAx*MzS+w7rRI+x7r^o^=|a1nEw{&^xu5qnt!WrD5}$^T=+dtF*XZo zU0n`{JGX)u-=UL!qY&=@LWKaggsxz?K@#>B)l=Z9KW@|+CtkcOqgg#VcB1h%RU zL)!${xEz3qycPD@QyY+;@iaZ^sYL|x-+b@iPy6?coiFhg=>)B8(p7&=fm;(foaG=z z*{vkzCIwVE!(+c$hH#j434NXMyMWf1qBhD2uPzc3&LV~U49LmU`ygvA$^d@hZzgt# zL)x}`hOwaU?~%;W&60O^5b@mt*<)84H?*pHqr^1?V1bt1Y0av7l2{kBlLQpAu@T|9 zTm91!lUPDR&v!6j`1tsb0DC&k$;s)oeuTie5)8Zl&NqC>d;g2d<;7KmuLd~ras{dh ziIJ346>lDZWFDG&uEG<}PGDJ4WnQx_s2bK!H!(3$7Kx1`JY|N3ODc?Kd7s2qOSBr8 z+7u#O+%At&tp)Vm`i%*jv#~cTt!Xi}7S8%NB5BH4%q z=CCG>WR`_1aUcUuMpQoMF6OUMLi4+Ho^pS2JSaHSsn^(kZ(@gjXm&Oe7?0a!J`hW> z0Lb|Nunfatcodr`IUE73VS%SL<4FuQV7Tk4lcemgkWRXB1Sb_w1cXua1aCaxT zyTd!rSM^ox57^zAIde|m-B)wEsvT*co(l8xB*+aNg>1Q?y6OS`9oh&9y0729aRXdx zVAJ+l&pCB2zN^9VQw4)oW$)z0=xTR3LY)T7SQ;RNLS!+v_eo>-1c+hjpp+KOk??rP zR^!UiR>Gjrd@eCsz;l8~v-lSa3|S|@6M8)l6JAg!tBb}MN~nfYJ1D8v!6iOu4nZov z;yx4hv^8QVE>e>lPA0Eyh$*20a>C+owN9KjGA>C|b~;Dk8)&(#O!!W_NV~ofCh(}0 z=V6x3rqM{#gx>eicHPZUJd&yctO-&A7Tze4^}E=a`G~F)Z6D1MxLi+aNK5d|&Ek|` zDxf+}0Ts*#NuAI6YPcf8ny;}2PfxzIwF2&0fCLVMGjwc_RtI_{RDt!JN69?S8`7=* zDU!3jbZAvRSI!klKIUj=S4+6dzB_;AV-o3VTtuIl_kUky1$%+%msr~?)kY+WOgK6< zkN^{|Js~A1+WcC|Dz@>*B17_hj?II=u1c5qMz8HHo?6|jGr{rlHoh}k7>UAF;8M<<=< zg#gN_*!Up+?ffpKW0uKpd`v(H<4Za$FEm zI+}eloL+-{ zcINAKVO>C{Ymve`OWFzdUr&&q@032r1aEYKrLL8;O`|dNo6AMK;)ABSt{(|}4>Fp2 z_2qV#mei$1rA{Gw@B=2W+yqxXt-Ay5Cc>OcKh;k9kdBg<4h|0R<$>AZf5&enOw9B5 z3>@_d;QZqlj)MPZ0sOKUv?2UJp_}W!(&Q{OO|3%c<(Qn1ueQ_H0b$ntak2KwFo ztReID{@{7jKnj)<#)p})U01&EWRLQUJYcVBc$E#o?yTM_QXz$dogFcMas)mTzU{}K z6ui;Ahq+Vy27qn6DS#pKpxLO>

    3J*y#|NE;Xv^| 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 Q#b{5_#L(Q}KH53qKb?Y;?f?J) From a21a12c758b0d92f5c87dfa6191f6d6b058b1236 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 17 Oct 2022 10:48:09 +0200 Subject: [PATCH 0882/1520] Streamline performance --- docs/performance.md | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/docs/performance.md b/docs/performance.md index 938654a0..5ad65620 100644 --- a/docs/performance.md +++ b/docs/performance.md @@ -1,23 +1,12 @@ # Performance -*structlog*'s default configuration tries to be as unsurprising to new developers as possible. -Some of the choices made come with an avoidable performance price tag -- although its impact is debatable. +Here are a few hints how to get the best performance out of *structlog* in production: -Here are a few hints how to get most out of *structlog* in production: - -1. Use a specific wrapper class instead of the generic one. - *structlog* comes with ones for the {doc}`standard-library` and for {doc}`twisted`: - - ```python - configure(wrapper_class=structlog.stdlib.BoundLogger) - ``` - - *structlog* also comes with native log levels that are based on the ones from the standard library (read: we've copy and pasted them), but don't involve `logging`'s dynamic machinery. - That makes them *much* faster with a very similar API. - You can use {func}`structlog.make_filtering_bound_logger()` to create one. +1. Use *structlog*'s native *BoundLogger* (created using {func}`structlog.make_filtering_bound_logger`) if you want to use level-based filtering. + `return None` is hard to beat. 2. Avoid (frequently) calling log methods on loggers you get back from {func}`structlog.get_logger` or {func}`structlog.wrap_logger`. - Since those functions are usually called in module scope and thus before you are able to configure them, they return a proxy that assembles the correct logger on demand. + Since those functions are usually called in module scope and thus before you are able to configure them, they return a proxy object that assembles the correct logger on demand. Create a local logger if you expect to log frequently without binding: @@ -29,6 +18,8 @@ Here are a few hints how to get most out of *structlog* in production: log.info("iterated", i=i) ``` + Since global scope lookups are expensive in Python, it's generally a good idea to copy frequently-used symbols into local scope. + 3. Set the *cache_logger_on_first_use* option to `True` so the aforementioned on-demand loggers will be assembled only once and cached for future uses: ```python From acfff83a99a91344519b3b27f7155bcee12e43e0 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 17 Oct 2022 10:53:16 +0200 Subject: [PATCH 0883/1520] No need to enumerate --- docs/performance.md | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/docs/performance.md b/docs/performance.md index 5ad65620..7f28370f 100644 --- a/docs/performance.md +++ b/docs/performance.md @@ -2,43 +2,44 @@ Here are a few hints how to get the best performance out of *structlog* in production: -1. Use *structlog*'s native *BoundLogger* (created using {func}`structlog.make_filtering_bound_logger`) if you want to use level-based filtering. - `return None` is hard to beat. +- Use *structlog*'s native *BoundLogger* (created using {func}`structlog.make_filtering_bound_logger`) if you want to use level-based filtering. + `return None` is hard to beat. -2. Avoid (frequently) calling log methods on loggers you get back from {func}`structlog.get_logger` or {func}`structlog.wrap_logger`. - Since those functions are usually called in module scope and thus before you are able to configure them, they return a proxy object that assembles the correct logger on demand. +- Avoid (frequently) calling log methods on loggers you get back from {func}`structlog.get_logger` or {func}`structlog.wrap_logger`. + Since those functions are usually called in module scope and thus before you are able to configure them, they return a proxy object that assembles the correct logger on demand. - Create a local logger if you expect to log frequently without binding: + Create a local logger if you expect to log frequently without binding: - ```python - logger = structlog.get_logger() - def f(): + ```python + logger = structlog.get_logger() + def f(): log = logger.bind() for i in range(1000000000): log.info("iterated", i=i) - ``` + ``` - Since global scope lookups are expensive in Python, it's generally a good idea to copy frequently-used symbols into local scope. + Since global scope lookups are expensive in Python, it's generally a good idea to copy frequently-used symbols into local scope. -3. Set the *cache_logger_on_first_use* option to `True` so the aforementioned on-demand loggers will be assembled only once and cached for future uses: +- Set the *cache_logger_on_first_use* option to `True` so the aforementioned on-demand loggers will be assembled only once and cached for future uses: - ```python - configure(cache_logger_on_first_use=True) - ``` + ```python + configure(cache_logger_on_first_use=True) + ``` - This has two drawbacks: + This has two drawbacks: - 1. Later calls of {func}`~structlog.configure` don't have any effect on already cached loggers -- that shouldn't matter outside of {doc}`testing ` though. - 2. The resulting bound logger is not pickleable. + 1. Later calls of {func}`~structlog.configure` don't have any effect on already cached loggers -- that shouldn't matter outside of {doc}`testing ` though. + 2. The resulting bound logger is not pickleable. Therefore, you can't set this option if you e.g. plan on passing loggers around using `multiprocessing`. -4. Avoid sending your log entries through the standard library if you can: its dynamic nature and flexibility make it a major bottleneck. - Instead use {class}`structlog.WriteLoggerFactory` or -- if your serializer returns bytes (e.g. [*orjson*]) -- {class}`structlog.BytesLoggerFactory`. +- Avoid sending your log entries through the standard library if you can: its dynamic nature and flexibility make it a major bottleneck. + Instead use {class}`structlog.WriteLoggerFactory` or -- if your serializer returns bytes (e.g. [*orjson*]) -- {class}`structlog.BytesLoggerFactory`. - You can still configure `logging` for packages that you don't control, but avoid it for your *own* log entries. + You can still configure `logging` for packages that you don't control, but avoid it for your *own* log entries. + +- Use a faster JSON serializer than the standard library. + Possible alternatives are among others are [*orjson*] or [*RapidJSON*]. -5. Use a faster JSON serializer than the standard library. - Possible alternatives are among others are [*orjson*] or [*RapidJSON*]. ## Example From 40240f754d8d1d26dd9732074091d956f8a9ea69 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 17 Oct 2022 11:00:37 +0200 Subject: [PATCH 0884/1520] Explain asyncio performance caveats --- docs/performance.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/performance.md b/docs/performance.md index 7f28370f..298a60dd 100644 --- a/docs/performance.md +++ b/docs/performance.md @@ -40,6 +40,12 @@ Here are a few hints how to get the best performance out of *structlog* in produ - Use a faster JSON serializer than the standard library. Possible alternatives are among others are [*orjson*] or [*RapidJSON*]. +- Be conscious about whether and how you use *structlog*'s *asyncio* support. + While it's true that moving log processing into separate threads prevents your application from hanging, it also comes with a performance cost. + + Decide judiciously whether or not you're willing to pay that price. + If your processor chain has a good and predictable performance without external dependencies (as it should), it might not be worth it. + ## Example From 93b5b479a8b3141630d56300a9e74dd6abb68503 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 17 Oct 2022 11:04:20 +0200 Subject: [PATCH 0885/1520] Frameworks deserves an own chapter --- docs/frameworks.md | 28 ++++++++++++++++++++++++++++ docs/index.md | 1 + docs/recipes.md | 29 ----------------------------- 3 files changed, 29 insertions(+), 29 deletions(-) create mode 100644 docs/frameworks.md diff --git a/docs/frameworks.md b/docs/frameworks.md new file mode 100644 index 00000000..fb54e71c --- /dev/null +++ b/docs/frameworks.md @@ -0,0 +1,28 @@ +# Integration with Frameworks + +To have consistent log output, it makes sense to configure *structlog* *before* any logging is done. +The best place to perform your configuration varies with applications and frameworks. +If you use standard library's logging, it makes sense to configure them next to each other. + + +## Django + +[*django-structlog*](https://pypi.org/project/django-structlog/) is a popular and well-maintained package that does all the heavy lifting. + + +## Flask + +See Flask's [Logging docs](https://flask.palletsprojects.com/en/latest/logging/). + +Generally speaking: put it *before* instantiating `flask.Flask`. + + +## Pyramid + +[Application constructor](https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/startup.html#the-startup-process>). + + +## Twisted + +The [plugin definition](https://docs.twisted.org/en/stable/core/howto/plugin.html) is the best place. +If your app is not a plugin, put it into your [tac file](https://docs.twisted.org/en/stable/core/howto/application.html). diff --git a/docs/index.md b/docs/index.md index 9eab6a7d..cdcda822 100644 --- a/docs/index.md +++ b/docs/index.md @@ -64,6 +64,7 @@ Dedicated support for the standard library and Twisted is shipped out-of-the-box ```{toctree} :maxdepth: 2 +frameworks standard-library twisted ``` diff --git a/docs/recipes.md b/docs/recipes.md index 5a9742e6..c59a8882 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -1,34 +1,5 @@ # Recipes -## Integration with Frameworks - -To have consistent log output, it makes sense to configure *structlog* *before* any logging is done. -The best place to perform your configuration varies with applications and frameworks. -If you use standard library's logging, it makes sense to configure them next to each other. - - -### Django - -[*django-structlog*](https://pypi.org/project/django-structlog/) is a popular and well-maintained package that does all the heavy lifting. - - -### Flask - -See Flask's [Logging docs](https://flask.palletsprojects.com/en/latest/logging/). - -Generally speaking: put it *before* instantiating `flask.Flask`. - - -### Pyramid - -[Application constructor](https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/startup.html#the-startup-process>). - - -### Twisted - -The [plugin definition](https://docs.twisted.org/en/stable/core/howto/plugin.html) is the best place. -If your app is not a plugin, put it into your [tac file](https://docs.twisted.org/en/stable/core/howto/application.html). - (custom-wrappers)= ## Custom Wrappers From 71012d2225e0fa0bda0aac89655e8d033d5e693f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 17 Oct 2022 11:23:25 +0200 Subject: [PATCH 0886/1520] Add a rename event recipe --- docs/api.rst | 9 --------- docs/recipes.md | 21 +++++++++++++++++++++ src/structlog/processors.py | 2 ++ 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index c5e4dfbe..d968dbe3 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -215,15 +215,6 @@ API Reference .. autoclass:: EventRenamer - So if you want your log message to be ``msg`` and use ``event`` for something custom: - - .. doctest:: - - >>> from structlog.processors import EventRenamer - >>> event_dict = {"event": "something happened", "_event": "our event!"} - >>> EventRenamer("msg", "_event")(None, None, event_dict) - {'msg': 'something happened', 'event': 'our event!'} - .. autofunction:: add_log_level .. autoclass:: UnicodeDecoder diff --git a/docs/recipes.md b/docs/recipes.md index c59a8882..726e565b 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -1,5 +1,26 @@ # Recipes +Thanks to the fact that *structlog* is entirely based on dictionaries and callables, the sky is the limit with what you an achieve. +In the beginning that can be daunting, so here a few examples of issues that have come up a few times. + + +(rename-event)= + +## Renaming the `event` Key + +The name of the event is hard-coded in *structlog* to `event`. +But that doesn't mean it has to be called that in your logs. + +With the {class}`structlog.processors.EventRenamer` processor you can for instance rename the log message to `msg` and use `event` for something custom, that you bind to `_event` in your code: + +```pycon +>>> from structlog.processors import EventRenamer +>>> event_dict = {"event": "something happened", "_event": "our event!"} +>>> EventRenamer("msg", "_event")(None, None, event_dict) +{'msg': 'something happened', 'event': 'our event!'} +``` + + (custom-wrappers)= ## Custom Wrappers diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 1a7116ca..6de68986 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -812,6 +812,8 @@ class EventRenamer: handled gracefully. .. versionadded:: 22.1 + + See also the :ref:`rename-event` recipe. """ def __init__(self, to: str, replace_by: str | None = None): From 442ae73bb97d67841b23db166fa2ffc591cba78a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 17 Oct 2022 13:27:16 +0200 Subject: [PATCH 0887/1520] Add fine-grained filtering recipe --- docs/recipes.md | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/docs/recipes.md b/docs/recipes.md index 726e565b..4ee6ab0c 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -21,6 +21,59 @@ With the {class}`structlog.processors.EventRenamer` processor you can for instan ``` +## Fine-Grained Log-Level Filtering + +*structlog*'s native log levels as provided by {func}`structlog.make_filtering_bound_logger` only know **one** log level – the one that is passed to `make_filtering_bound_logger()`. +Sometimes it can be useful to filter more strictly for certain modules or even functions. + +You can achieve that with the `~structlog.processors.CallsiteParameterAdder` processor and and your own one that acts on the data. + +Let's assume you have the following code: + +```python +logger = structlog.get_logger() + +def f(): + logger.info("f called") + +def g(): + logger.info("g called") + +f() +g() +``` + +And you don't want to see log entries from function `f`. +You add {class}`~structlog.processors.CallsiteParameterAdder` to the processor chain and then look at the `func_name` field in the *event dict*: + +```python +def filter_f(_, __, event_dict): + if event_dict["func_name"] == "f": + raise structlog.DropEvent + + return event_dict + +structlog.configure( + processors=[ + structlog.processors.CallsiteParameterAdder( + [structlog.processors.CallsiteParameter.FUNC_NAME] + ), + filter_f, + structlog.processors.KeyValueRenderer(), + ] +) +``` + +Running this gives you: + +``` +event='g called' func_name='g' +``` + +{class}`~structlog.processors.CallsiteParameterAdder` is *very* powerful in what info it can add, so your possibilities are limitless. +Pick the data you're interested in from the {class}`structlog.processors.CallsiteParameter` {class}`~enum.Enum`. + + (custom-wrappers)= ## Custom Wrappers From 26585392b3cef57df710f025047ccb7ee92be555 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 17 Oct 2022 13:34:22 +0200 Subject: [PATCH 0888/1520] Cross-references --- docs/recipes.md | 4 +++- src/structlog/_log_levels.py | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/recipes.md b/docs/recipes.md index 4ee6ab0c..fa8c9e56 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -1,8 +1,9 @@ # Recipes Thanks to the fact that *structlog* is entirely based on dictionaries and callables, the sky is the limit with what you an achieve. -In the beginning that can be daunting, so here a few examples of issues that have come up a few times. +In the beginning that can be daunting, so here are a few examples of tasks that have come up repeatedly. +Please note that recipes related to integration with frameworks have an [own chapter](frameworks.md). (rename-event)= @@ -20,6 +21,7 @@ With the {class}`structlog.processors.EventRenamer` processor you can for instan {'msg': 'something happened', 'event': 'our event!'} ``` +(finer-filtering)= ## Fine-Grained Log-Level Filtering diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index 0f9e8af5..04fe7db1 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -94,9 +94,11 @@ def make_filtering_bound_logger(min_level: int) -> type[FilteringBoundLogger]: - It's faster because once the logger is built at program start; it's a static class. - - For the same reason you can't change the log level once configured. - Use the dynamic approach of `standard-library` instead, if you need this + - For the same reason you can't change the log level once configured. Use + the dynamic approach of `standard-library` instead, if you need this feature. + - You *can* have (much) more fine-grained filtering by :ref:`writing a + simple processor `. :param min_level: The log level as an integer. You can use the constants from `logging` like ``logging.INFO`` or pass the values directly. See From a097422de20e2305603c05fb3d9cfde09af0d80c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 17 Oct 2022 13:36:48 +0200 Subject: [PATCH 0889/1520] Rephrase --- docs/recipes.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/recipes.md b/docs/recipes.md index fa8c9e56..ff025641 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -28,7 +28,7 @@ With the {class}`structlog.processors.EventRenamer` processor you can for instan *structlog*'s native log levels as provided by {func}`structlog.make_filtering_bound_logger` only know **one** log level – the one that is passed to `make_filtering_bound_logger()`. Sometimes it can be useful to filter more strictly for certain modules or even functions. -You can achieve that with the `~structlog.processors.CallsiteParameterAdder` processor and and your own one that acts on the data. +You can achieve that with by adding the {class}`~structlog.processors.CallsiteParameterAdder` processor and writing a simple own one that acts on the data you get: Let's assume you have the following code: @@ -50,7 +50,7 @@ You add {class}`~structlog.processors.CallsiteParameterAdder` to the processor c ```python def filter_f(_, __, event_dict): - if event_dict["func_name"] == "f": + if event_dict.get("func_name") == "f": raise structlog.DropEvent return event_dict @@ -60,7 +60,7 @@ structlog.configure( structlog.processors.CallsiteParameterAdder( [structlog.processors.CallsiteParameter.FUNC_NAME] ), - filter_f, + filter_f, # <-- your processor! structlog.processors.KeyValueRenderer(), ] ) From 9f0e20780ea46957b47ec7701308033cbc0e4809 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 17 Oct 2022 14:20:27 +0200 Subject: [PATCH 0890/1520] Add Pyramid Tween --- docs/frameworks.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/docs/frameworks.md b/docs/frameworks.md index fb54e71c..cecda40a 100644 --- a/docs/frameworks.md +++ b/docs/frameworks.md @@ -19,7 +19,27 @@ Generally speaking: put it *before* instantiating `flask.Flask`. ## Pyramid -[Application constructor](https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/startup.html#the-startup-process>). +Configure it in the [application constructor](https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/startup.html#the-startup-process). + +Here's an example for a *Pyramid* [*Tween*](https://kapeli.com/dash_share?docset_file=pyramid&docset_name=pyramid&path=narr/hooks.html%23registering-tweens&platform=pyramid) that stores various request-specific data into [*context variables*](contextvars.md): + +```python +@dataclass +class StructLogTween: + handler: Callable[[Request], Response] + registry: Registry + + def __call__(self, request: Request) -> Response: + structlog.contextvars.bind_contextvars( + peer=request.client_addr, + request_id=request.headers.get("X-Unique-ID", "NONE"), + user_agent=request.environ.get("HTTP_USER_AGENT", "UNKNOWN"), + user=request.authenticated_userid, + ) + + return self.handler(request) + +``` ## Twisted From 2db0203cd573b161b66986149262da3335295d8e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 17 Oct 2022 14:27:20 +0200 Subject: [PATCH 0891/1520] Scale screenshot to something more reasonable --- docs/_static/console_renderer.png | Bin 311775 -> 319196 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/_static/console_renderer.png b/docs/_static/console_renderer.png index 7ecf742dfa5257056beb2484a6d3efb8c847414e..c67f7c0528904b99b12dbfbe15d6dfec74fa6d1b 100644 GIT binary patch literal 319196 zcmaI71ymeC*DZ<%cL^5UU4rZ25*XYe1a}Lrfx+F~HNhdcyGw9)4ema?$#>s-_y6u% z@Ac|g-K(a$ySl6D)Y<#&6Ao08K|>}&hJu1ZlarNHg@Qs*hk}CLMnr&=#BuvjkNiXqb}9?N!XPQM;)<)tKd{##s=wQ-}YO7pB)c=aH$ZO%}91(lGz+3a^du zN!DqH#r^5>;rm6$&9&dfpGgGUTx9GFJq3U=wZhTy*3C1Kvtq|CxHO9~j2^i5<>Z$} z`RH$}*}e0&ilr3)UJrTPx!faJY{rJ6Rdj(ekz!k8 zdQF;x7warfnY?lv8S@EUuJzyBw!OlY754;0l?STa^#OsuMGi>_>pcqf@iy_sx{0sV?2fgM_!ilQ4#vyNq(01|y@N%T<+gh_Z?bg|=Etn?+c% z)^4Zdg<4f{wSpV*tUm%0X4+EcELRbVRIPtu8OFS>fb}{>|7W|URJbMfKU(ZM%O`-q zmgE#xxYOzYZ#9~^l2a_Em*B|VrLT!i-;ZYyF<;TnL)bPaT6&*h7jaKS_6pfca#MS2 z`I7d0e=>?{4A zwK?U>>T)q$JpSzi@pW);z6(0CYni@xwBk~|LWWY>77F8m?z0T8W$(r&2}Zpe$)U)0 zf3Qj5Zq~!l^-DjpI~Xh0`w&ZR{AM1bzZ++Bg)u0{OOi8?sKMvT~a2~uG?80 zI97<+tXwO0T9kImZb9JH`#z@&?t*IY;>-W&ILOC9E9Qm1o!FuI-SO!>2_{vZyeiA! z^SxQuc!}5P3urxw^<10Fd>nK3(J)EO1TGmeqY%$_V?|T2sH92GUq7BW!j+XRUdV<) zhwchp!Y5ZP8ZafLTD#52(X^!UYrb|GSI0UEMZ9=Pa=nM$e3|&mX0qw2(7NfP7Je|} z*zZW#pDH``0P}Q+pG>_ykETH{C%fZ zrawO+E{@#F%4+7fmD*30!Vt#_zqe;j3P+|afAEv@{j$Z_jgwI|f8iX8 z#v#FIXmd||{G}nJGK8akf00Z}mqSldzE+dZO~@t98T62IHRX>?DGoT(jptbivav>? z`9*ZNFIS)EV9su+yR}qC)P7^qj{R+|3E=2k{QDWy>@to`P@y*P{8N?3!|436_(-iZ z<`~CCCEwW#_NOShg0|?v6w%ztX6y?dBW6E5#SPxcLNaL2)Hpix!%2)p@f7TXLh)Cj zm_NCmI6N1dqO5$H6f{!WMkEX@L7T|?onC8hOhY=bgQcPm1IO`8`T$lSGmK%Y;a&h!42t>}e)V$D$#V zF#f2ymiqHluf z34XTm+zuuvay?ntv8W&+fD2d73_&$w1OW*(P?)qj*G}5XI{LJ*ky4Op-(ys{QFe^Z0lo2Cr+@hiA&q8~05^O@r zYJRf=Of2WgEFtP$N7j6QW|#K56sb4z)}R+0;1EHQl_4+tQ_^6BFm9h#3R#U{KV{RI z@KiKCkP*j`g`xBr`AX^LdY1HSm0Q11vBqKbW~seA)DK}9VsfWRq?VhnV7h-b5w*Ez z{!ug@Rc1hJ4lWM5lkg#W?!5tc2;Eqm`y4o|kW1wFN^`=*hjn|tug6FCx+G?Dnu1+8 zo&RL^62%2^`fS5&f1JuCjpKK#c)UQbjlBMPOZNQgGosTj+k9AtHx}Grtkh>@NKa+x zN$AAPql6~|q^dW&*uKwR+2Of_tON2%Vz@&!UdrUlHG+yB+374!= zC_MsMVidZIk*`j^OtQ7@z`$F!&G0WHe&nzu<37vY3KKH#`_}VmnrC8 zm2|U)Mh9P9g&DmTg1GZwVMt);k>5<*BkXk>$JY4>undz56O?K=scK`TB_6dm;@Niz zLh~7QyYoE~e;OjRkc}KkEFPHq*&Fh3v_EFLa+oXMlxg1||CLjOZh2JrQ(!OcQtGJ-^C7#k5L_a@u0 z;D}zAk~ZuDvN(;yg!PC{YyT(W2J2#^wdh3+hHq#jYeN2%FcZ$EFuf3lJ=JFM40z`~ zk%7#YJe##ceeIR>AtMAbn0E4EIWNP9u;$ej!$1A^>MlNTP}aRaKM=t%1M>qupXMMC znWhR8ps$6P2}We0%W@3VC$df2A>lad{sBAF>FYg9<}|=E8ywW1)A!V4adR*cee~n; zn-oDFXwfXyfObmgCQ9h}sIboEP>BOg3%QDrgr!+D$M4xHozpCWe7ZRhc@kR-(YPWU zhfdzjtr2K%bG0+j>qNww+Gw}B0*06jJQ9JDvyBeDG>l2&W^&9AJa#M8B^__~t21?G z3aech6sFW>+*l7_L~2rV{lGLpoPgO7 zpM8Em&JJqe=w+%Q?xGGrjzOP%y{c=nm5eWz9#qDDIzT|rZ&qDOo!$brRP$q%7Y|m| z@+I>T!$foJe-yv0APB^nT722?t}q#NJp?9{>)x0H!mBlZtRg$X7?*f$9f>>sypPpH zq&r`_tv`{KV}IW5w!(R}cMQ8^EpN1B4M!t(M%NF;=1tfd!O$59k?*s<#&7Z=bi`-76kL)qofqWQhPT@ z>>w*IAEAdIDTIFlrPJ(~PfbU+>Y2o-Ax~c@MOa-_M4fM&X2rYdQ}0M3gS;3g-n)7J z%EieE7vKB)>E^Iahe50g84&0C2i2M9xW29qwa%_66RLr=&!TM6l) zZBdgk&Y{}$fi>=%%6Fm&f|o(3SwOe>RFw&P^;3=foTL`$WpVE6eV6n)k?A-M1T&r9 zp@pE~ z@1`{Z@rQ-CuaeLoByne}ns*`qyahdojOAL@_$$hyZy>4x!%$2UzQP3_J?t)p25yc@xInS^l!oC16f>3L?ps|Mv6L|`YeBt z84-zMW?}PxB&fjk;y4=KhBOe!JCJ;ArUFblF=fn^QNZT<0O-v$nk+D4mce|g(r}sk zNhIZe8l&~l$M5OHKDooP64lA`A%q_v2iE_n(@a)X3pPn&DCAa8>?U=6t!xToQoL<_ zVdYf9G$_DP&vG5g7jI#6mh@2CB{C+Bq7Q&IyL6e#IAm+}Sqj@uQkKBv+`)^<1;BrN z@bjTV%ynPBYqe?VBFyE_1lQuLW3~>9Z}azcib`Vn>G7$I3-Y+YZZHHAO;SAY#f=4t z%|Y-If9ZMB$Nvp6|G~|S{BQjU#0*c#6ped}b-4VkZpUeB*q(sn9sIL)5s!xR*q|FHj~KLoQe|M9Ou|M+1}|+`iJ8Ui-yFS zz~y?2SQ7u&EAzKgm#gt4w!-c2+ZmSdc%nl=b&5%6lo%#kv&!3=6vUtjN1l7%&>*I= z8qe6i;2Gm8*{?&TQA>G4WD>xyup6YI&YHHraVTS(cXD=Tkr7O7%H`q4^Cf8zxr z?AP*z=phWDm^5@<0&?I9;Cf!dJ~c~v&^~w;U>7HZcfkL16 z!f>~_<;X-72k{XZOQHw?04MlQa2#-Wbv9`-gnZgRAn&tTSyZ|}Q z-Yd^{(9{bhaDH5|?pr{e*?~v}-ToY6Bkv?N-v8mgggepu_Hkmbqy@%N^2qFSstq#U z2SzX)1|J2i_S=>aslXX;RkfXC&)Rp~Y5H^Nw7OrgUUWR)e zGLIv3JU`$kGbnW9VN>RqqjT4uoIcyhX&opK5$C~>sJWNgw#QJDTb~m04$v zD2fQHANq9%8RwlR5P6Y3CRiktqAX5tx0)$;As+`(FA0GQo%A{LX}g=kKiG$um#)}t zku@n?0yhzE^fjHM5IgL@{X~fQF)i(0l0S$@o+@FyaKxDVsqGnGtkK7L(_^ z;dvNtr7V1hJGG6%h$w&F?zjbki~lf2wt(xkLdk$3@Jb3#hQ91$d)LZ(8-;YuNVE$` zRWG5*FZ&-i!$P%>!kC}~BOa`ee=QTjqAwQEDtw57e#QnC)n|vBTXp)ehBxX#aZuwl zWNayktnjV~<42RcQ*P$Xbv|9NASok; zDD{;_LNBruXkr(gsNO7b?ikX{`xd7Ha>eCCJ7Pp1A%zo{Nfr11M&0zaIO-LG#fq2w zf-T+I39SCUB3cSDRlrdkwQok(k*HXsCWPWWN#hZ*v2?b=6)yd*8JL<5E6G}ha++bb zYt4U>a7=8qD#GZ?#HFU9gv`r-_OP z81kGk9;DezuW@2yp;bP}Qg@hF4Po&>s+A&&9xeWz=JW>wukt|zfdGi->}0vr;1nEJ z*K=b5Z#Jy7_U&2^i~^Sor3K6%&zOia7Eua8?xNU$?RjkwaIafr4`FIWMFX5TF>TWq zNUr9U=19UN>XHhU<^8uEm5+kMlT1*B&n!6`m9zAJgAu2Z0Qi^49VJm)NL-htAu~dF zIi94P32>+H%k!dwu5O0y%5OQvLPgEyS_r4OU)i*QO(cF*Z$3c@w-Lr}+u2GP#a8xM z+%Rk%{)mdm2yqJWRv;)u-*SWvNB+GJL$o;8~cy- zSalKhzNZ!(NP0zPD*JvkE#By`$@&{Z^cCoJdxX`H*Q-n91Z5$c&6-^dI9oaAcZA2n zIXbtur7FXujq#@bHd6g629y&AUR~>jblw(ZRvSMDv7}2eut{bQHV3skt3r@wX#I}_ zGtj0&2l$PT4)5<=5C0D)DFGutLVMzKvWC2G2k7I3`ClJ<;lp66UV4$45aIfQW=smP zK49Vsag5=pJJuy>14o9(OtLXsC{Y+Eoj{x$Mq^g9j+AoI_h)NYR3S4rucpNiNNL?@ z6Nw@xjj+G_tHIW|+DSCuggip!zT66UA35`tuEId#CwI7lERf^B{fwlKNQ}~oKV}m# zRgl*hzChTm98kuP%Xt{Ty2$&h3&+`UX>N*iG|{#a#f9YG`EnU^L_pv)CYiH~%NgG} zUEnaO`x*tevs<wE{7IZgMi-Js7+hM$fGl7^Rpnn#`ndCdNEGJRFz8q9_0DTR}&s z)9zri5lA{@tj4&{M_h`C+mhU&^QmO|A73ysGP2!_76pNu0n>g@`vfiT;FlId$X#SU zc0q`{&>0hxe6Qtq{a-*D5~4I)rU5ZK&Q?@Js?E8ew@eUym?BOvg^El{8rDm|1Bk zl&X^A181q}q6j^qoqXYsEFN9Sy`+pL3)Q<#;!h1V4_2PnBh8W2C$%z_mP1@mF0yBf z1O!-Jc*m{}2Cs&XUw#VyA6>bG#8|Sn$T6>=a1`B&ov;wb09{FaE5`Z6SS1L7bff)xpExvS`5`No#=L>;=eY#i@n~*7Lv8MWj*` zGkEMW((WP5?MRhD8>Xh|{%G<)?4{G`({chMZdz+L(D}H7Lc-gb_m9|HlPrX| zDUnv=o_!%`*GGl1*ROD=dK}@6ju7ror@rJYmM>5iVB%-c`u&QOF^qX|0APq#m2yPN zI4O{z!EqNkMa_%Jvh+G+^#c(GFUWoV+h28_akJY|yriXTF7+Y^KQStILE5{FsR_)- z#Vu||j4fqO6(z{RNw(S z3ji3SC!b>RDPpF}Q zlV!qGhw+n31=<(*+s!?~ggGTZII{^p{$3vWz-U6Q!A;qN*_iaKEJgfqCg3ptu~PR5vui!3tw1x$BHmEs5Xln#c4i9Mqej&`o2bc>7ztZ?B1XDj!-N+v@7Kx0O0JA z)|h;T(6D%h;1*H#`!Nk1C7P$?!r4Z{Il44Uv#@cRg4k4ngAu4$2jOj?&nDock5rb~ z&X#W$!jy7fxTs>JhTk4L+MHH~YiSss@RG&=xW|4sUqTOogo2ubwj1;~_osmIxCM(G zoua&N&(|VOWx&QtWnd1I`?6|I<{=$HD7Ilmr0GO96@(tUyEy4mfMZ`kl|h+gxOQ2y z`9FN1Z`5VqmExx7=c&KjxgxCtB>)!c0}VT=FA*&g@QZM06hYXU7Vr?bT7X#;^J4O+ zKmuO2Y@ObgixU|CIbWxh#9F6UL;`(;BU21k?!yR?4$%?%lX%s!xY9zDWna3 zuB2L?|CXP*G*3n9h2FJ70L6Y3*JNDl52n7Z5NET}Tt9&yFV5hnLoWaK^ukG)pBp6& zzftP!hDit^tYsKu(w_v1DG`Y$8mmvuVvYt&U?l_;R`^j@4Tm=jcU!@(X6JpxV7gq` zMd_uNME72Efd|0&_C{aOm*=$#5fVbx_)T=D9V z*zI)>{me<8B9Ox^3Xc81ZJ|2QiT~H*;Ww7DI1~U?Bxu4vh69=DgZ2ReD;+$d!w5pSU3>6e3r-UXJlT zJr)G{=QvTQnj;mLMsWG{y9mK<5@K8-y34614#sZ@fUpB!bwmf94)GZ32lch6JEt9+ z`5u^^x@6yCoi_+*y6FET<0T0(=b8cKw7XK|LW9eT!YFZ?w9ZzBf@ zS8dnU%J95$9|UPFhb%0< zMiDHt!cCJAlNn7L$(^r-+mdj8EBd}%rxG1(ncQYt8>N3+LS0h)=KdD*-)xymC^E(Q zrr%5DG=$Dp4rda*ZC|QF8+C5^am!^fx#wXjF2#RZ2P_^xoPXFWG};rvw7f42H)m$IsbHrXfD9iiaT%PNU&y3X>32qEX-YOtpHG z4?mMO0&ecTI2|8}w~N2GIKS7v^OpVhcTRbwj3Nz|AIZzqBnkzTD-DVdPV ze7H=dut>F7p5{}zR3yH$bX>M0B((I8I#w?O_OKw8^aFuE*P5}2XaD(c|Kjmk&1PIW zA31`qzHQPqx{PhM5{ip~v1K)@pkA_-FQ>9=yzq$M&-vb6F4qp0Z+Ps&tPR#|{&DqP zgSu^lBu%-9Jcum259iWf;~{3oSA73{xvl(k!I&JXFPVAOnAxQ*Vr*PtMDN}y-Ku(4 zaZ+W}nEe&QsJkqRj!zZ!pCSXI=m?Z&wKNXCp=RcobZTIHc{m?E&Rl#Z&~(1t@nj|K z@}Z!sHjGh7?Wz%p@%GU_XsD!e?R)LBn7XBYbiRCyPts+{nflM2zT!avfzSix{IJ6& z|0#fi!d0)zRTn{o>Bw=_Yt8=I2oJTO>ojT5w~6pA{i&o*>k<~y039xDUAlO*>RQ^! zF5~X>t-;+h)J+cPfIwvDA??gBgZk2|Tm)^OO;UJ%4QTHkzddmXi#udi$y7%xeJCtD zX!CCfbJIVS6~D5?#9&kAxXL!ho~8&{BfVey(EZRUCP)~(ZPq9F1NHsWan{Ug3uDQ6 zC*<8_^~Lvl!?22*QlE=e9zOfL*H`BTk@Z`?qqg`5D=E9bXtlg2?JNIOPjG8vnJ`zg zZpfHBaV?%rO#Wd0_`OI1S1L&8W--G*S~^HYWq9j_4JzP)S&}Cy+QXm`MQlIr(4Wp>F;!p6NyNR=KMQ{AVAH>Xb|@4DJwyhUK4;PKutxlcF+ zjL>p_nrQiTR(ijuR7q@C#ua( z-`Ta3%?r1-y0*5H8?Ho-u-#^(GG<)l7Pe1TLfrVe>T1dIG+G=^lgB3av6}=nI4^!! zA^8W@qZ3XrP+H9LRxT2wdU|gsGYci^?(W6y9W3G`%I(4iboSguj)Rk*K_l~$e|RC0 zl12-^{(pymyGg2Vozemwf8_IE&fwVG&Nw%#p~m{(>Z-pOQ4N=4JZ%m-88wi zF@L!+`m zr2X3xi;oT>l?cwwHCo3xWn}Zov-^_94o&jX8;oM*@LN>8RLf@I#s$zzt@2i&^Zd@($w z%K4UK=FI~GDcAG0P&3u!WWmG>L9ahpz-+=ymV7D`hviRP6LjjTB#D>c+|tM8ZNZJV z8@N~$hn?N7sjIRr1n>hr!BjUH-}hX}ok#qk z@qxv6!(FK>VIj8GNCy^?9jzfU?cAC`QiUR%cN%KQHkSaz`ap~jZDL~b=cgJSDj_Eb zUAWwo!+MTh;F+G4HKeW0JG$=3G6V!77ZxV<^z@{srx$~WIv}c%?Td>kv7%`mIZ-BT zHC5H=1{*B|M|S%)zP}bV@DSlhfskRaYNb6w@9fOXG$iz}d72GdLnDV1e6e&;|8~Cg zzlJvI+xt1fV52aO?y9Coki`W72i~f(@afAOR(x#m_^b%Q1_X`sd)=(dM&h$P=2B8pzNXAWi&;D)q}A0EP|`3kj690?!8QlI zL(`Y}zk|nVME(*0bNS>H6{!!>V7p~jTOaX7zRhp;pF<=sA7M3qsgE$cLqFCH<{alP zQMuJZ2heu3P?lUdy~1|MX+#40U)wX@k9j&JpQ6S$emD2|K6>=qfs5cPcOyb)!a zZ3hW$%8V42T)z^rC__L;@BV!M9G9tFF6Z?t4oj@==#6;VH7)*U(+Gt!Q=A`A15*VB z1==p*8pC*X1=?&}$w1?Eoi?}1Pa-~LiFC@>%=J|-)iksrHFg&p9bWgR=^Ne`!V8P~ zU&?Aa{}FEP=WBl^GI=SSmr?eJ0Kpw(egS7q4x57)OA=;sfZ#|Ng%svLkQ;qJU*o?! zUFJIb#GZ*_gH7nN^awGOoBgGk(Yx}j1gXIA(>Xce$y~KA!KV3>9r(LeXPv^%XFyPn zkf!V`Et`~*_G-C+dDP(BZP4KRRi^b+jvaXNu^U|YQY_R$O|a8J~kD$ zcU4f<+f*qHa6@J#DgvoGnN}@z!i>)GZh5x_XlCGvN|{i}(6>sOrchHwiL~!n%RWM# z{cK6DAmMcW-toj=_x*d#y;5}aryf4jk*JK;eQPV}HR_3|%!(0?U2Yb)z>@x$#oMLu z3?iK2- zqh=fl(B*ihxZN2<9GD^M-+3^ZJ;ovg8PYL*oe=h{I3OSZ^+*0>w&1@wH%Ul?aUVjZ zQP-z!cgT0f_=>wT`0R-iGOp6*cGjFN_paON!@qx=8^mO1wL2J1#Qqhk+crajr|Gig zOOyEo(WupOo!P>(Gy#;wE%zNMY(I1)WN4SnmuuO)+@BE%dvWsu?Oyhw#vVEEk0K_e z9af;1lx1ZdNr2MrhHPK?Oh(FMKk|x!xj$I@@uVX`;u+@WWkHiZygXZiuNcmQPMk1C zfpHmUt7(OTty}I3bw5wos~$%ovqTCNNFe5WFrNM>+Q`lp7ZejK`W3A@TNe@x_PE1% zh6IEy%0ykDmc_=uvUw40%DA6eyk5yjjH*1?Z7iHE)l${Uh#n8J_OfW%Dv-Wl${eA3 zNccv6#W0Dj2@z}M69M;cMHBOq#~ZN((JRZ3sBJybwx>IEJRtyzYlTFgpst^JK=L`a z{UN~Pb3K%I5YUQxs*rs@obB7_CB>ajQ7Cm?O|ZoWsDnR+GH>!_(;vP?Ph9Vh z-JJe`yy)-@=Lzq-zcH~iC#AZ_#+7Z6U7gc7i~mZaL!ajhmj7H+%x6=g-K(QNRO?;- zWX{kDYb%X~Zl()q#4i+kv1Fn#XP6!pPe1Ry*s9yG=x#rI8{7}Y86B-bx_SY2e{sPIjUtpWPuQqXC_V{|r#JpCIkG1Ra-mRGJ(LB81`C62Rh_sV;8X4Ji`O&E7 zG_;g^vsBR+SZaHj*+Ki&3ETQ@=tqcyKR&3&jSCgF)HfHdO^uOPW{l8=I4DBi&$5D>hRVGuV&Qi z?|rRB4A`Hijpm+_l_=W_Esf?`K@2#Bg7BN)*!*N=3Ia-~*rogv7Md_tF={l**EhXMM!*ua@(24kt1R zR!C)k-TsO7o8#(7jiV4& z=3q%OYlSkLK-2u~zt;hELxw|sMI!IniSV#r%9ctA3Bsg7@^ss+TfFS1-9w#MR#P|!AFMDx zgXF2AQPGaWxV4q~A4liYkK!WP-yUWOzdJmaWzWL5Wkm@3EofRTy1E011ZK5&((da2_HCZj}w;W4rwL1f?_&{pZPhqhxn8iGRpa8d7%t@wpExi2 z9?jq1F~D>VlMtsL>f(97C%QNYO=-|_>PQvT9Ijd3XQY_#)Gj#KprF$aY%CI#y@mnD zC(3pc1B9E!k|J2~|MX;#@S=_(C}L`03MU&APSNM>+c$sEXhJ+HllgWa@F_DT1Q}qq zv?OKMwh_i{d!sR1BUfIseG+S#Yms|r_RHTQ@3os7;2d3PkHbhhWOWKjJ{i)|cap+n zR49l3qa;BCrFZk?lxAF9R_7+XML4z)C!n>^Jp~VRju2+IiQ8Ena6h^M5%(QEYO5X4 zclmu)M0N8#;Z~1|oCY3~+Y-EDy0NwUM*1?N)%~X@DX4=^UDUF;6)`dVs&yvte14Iv zL+8)bqLLsP64SYu(7it5^^am3?j7k1(5N@+d7s4igtEiCy@E`F<=$Ji9MZ>N&P$ox z+c1CjK8(gusyjPx&FcB8=kS{AIsc{H*lXYL?wtT5mss zkbpegdX@7XgJBkv5n>yM%hibh#h1L>z+rW4b}pz-*cTk4D%N@)=ZW|z-MP{M%_|Tg zDvU0y*ac#4roJ;y_HwL{?Wdd+R3N^JionkggUx@=xjwwOhy|9QR$?8L3lSp%q}Ji` z#kgQ=P@!a`A2C#Rcxzg?KjY_uT0RGeoWYqf<>G)6uDPN$v5CeQp(-9aE_`Jf&Jf2x zSi(N_>8l}y?caq;V&>3-?v2ht5#XRWnCYvxLb72|O7YA^EXKdYU#lHpP8H%ryWx35 z_-P+H?Cb5aJf^hc=nmRO!J0lY5wb=vFxT;VP&Av+8HgEvvy%581-T2I>uq%eITpqH zg8VVB7M^?a;R{Ij$snj7lpN^8aqqTd9O^gpiCk0gs850K{+7;DoHKZ&F3bdol$^En zvC-m8aH&)qeO7S=Vql)uQzrr@2Ifki9-*1uG0U=y*_ znN2aS!!Fnt*Iq~Xj`H}7hiSHd&~&-qn_unZvh~>~`};+s)hOm#E7$1PXzdu0)zUAG z^)v0@OpV~&R$ZdT=Sy)~4M>l2b6Bo7Rb`M>Tr5zyP{_<3u$M$T186o0FeR(*@SLpI zrdji9ElJlPD((&=o9oD~k1n|JIStc3KgJJZ85Rn!u|Is#d_g{8<}AoI;<+j0C;W5a zF2v?rot~Mb_q4xm*uN66bY<}9jD|5Y@_IJ&!&Pz_>$VnQnRukIUA}x8MohMCFW=q@ z#~Ot|u}J4IX?+08S88pAfmLd0b2!Lty5yQR$8RtY$*Fwc^qj#)w`JHchDQfX(PH{L#EdBmrvOn>a%(j3K8SV6qoMG zbAV6t*S)}Kw`#6MhIel6JAPNP-KmU-e)`oI$)zK`=aN=-geVEW@qQ|i&3T(uR{~=z z2i)Cz(hCn6%NA>QZ&BK%5XAf$S*qwgKM`rWwl6EK84o2I_^2iRU>7SdSLyU;@I&du z!KAqJ_w_$smR=PtJqRST?iKl*?Yde#8zv9GzkHT)aC(I4Jxx_MW1I+Vh>l(6m^{Uz zZ1dT{5#Fz!^v|5iOVNYf1z88@Z+BfZg2kK3;kZ@QA(*_MA_b+<5FkG?;eO% zLC6W@*Dgm0^|S7D{wx#gM{$Nza46A4FjQ@FiZpa#AHy$&$QQ%UBFe>mp8HC7=_t=BvW*LTyp7nzjO1Jy> z#Z}bzq|P8COh)wQ;^h*z?fv|@8fd<~ZG_%@#(Jp$pRHKEw;8m8p$RV{M#x%$-aE{! zi_jg+3626fccY=@Lkq77i1|Oy<{}_KDLIpqG~>B0kmbW98KH0+nI!6r!U60fDlZSHXl8x-M2C`^0f&ohG(V zlBygnYM6|q(d+FFR8oOJXvPIB#^*dg+V^MsbKa7;n4wQ`r7=J(o>U>xZcdXvi)bloJh)a!$nPDomMh=pxq&amKybd#JtsX;|9;#p^Cww)YzzQObiK#iSq6Wb) zwi=Bu1p6nAwN?Xmw_W2yic~?;Wl*M8jU0yqE%)p0o7rovA8>DWcPIn+yFHpABA*Fm z-vu`@KAbNB`+5!?pCMIzay6qk~0a`)2V^-swXTuh8`dFfHe;Cu@xuj)J_d@+ZL7 zo$%{WLe9K)*DoHaGy#jg!-gjZ5Y2YVT<$Al?4?DHXNj{nYde3%qL5Mr+DymOL1v=6 zPwAE8%URQ`I<9~2^JIh9{MqM4eUof<1|xZf^nGTqEu(m@Zoav z=`dF`2{Bok$cm(IDkJ^C&{sqEaR%jhVlVg*TO7UpDZO+S+9D@@@U+HPOD;JJ$X^iy zWMC6e|JWl!2WDq^9f?g~AA;n>2;3jj&2m7pyh_yJ9NR_P@%)W&mQ5BE5R(ea9f!KE zRaMOkKH+P2#d?F6xlh(yX3|JYrCWuqs(A&@yl28kUS1nXG@k6X6^-;|Ai^Voolft> zcE@H>tI4dK->FU;iC|7FMkhl9r(%$$hv!0KIMr>m<~sXRF3yAALwg8WEQL&2T!PR~ z2;)&Z9~#1)pI|d)Tf1P66hGiUvClQBtXJ6~wQT<0g!J!ai{c@``Sp^xn>KS4J;sR- z#R+!Oc!Q;FW=+eFcyb$4Oh1iXmw9;aE7~nW1UvDZ+|rCpxSqclS{@MWBd6i{Qtyv$ zD^8oVf*kOe0A#osgywM^J{#ve=VT4FJZ|7v{XO@T>aZm*o^(}8X%uj&3m8Dtfr9Pr zi8jppvD*Acxs@U~1n*j2bY!CRyJQ(05)27#--ZOZinnR7QO!4H|qf z)hb&C)o+cIOwJvmtQ~AFi}CaW_?R03^<)Bn4pzWKoxkwcl}sZ4QbNERvnh(K^CJuq z27ZJhW&>_4_t!i6$e;x#<9oBGG9M_Wrb*MY^(SSeKX>h+|CK02g-+b&to-;OtM}U)rJshIXPnknUAs#!nyIF_DZ29z*UG03Zf{H&*|ajz{-n!)$v4+!uz}zJyAB4j+e=0#NlO`Pq_>|zCIVa3bfuBc*1m6J9HG9e@6i@|8A`@HMzx~1sVPYe*u zgx(v=3>hK-UZuq7S3N|H`&m}*4UO<8cwgadrAfEz`qlt2SzuC*4RTdQ%zUs&69gVyl_<=kA@a?(kRqt>v{-J@(nGteM zpLqy2!EdHeC$cidq!IIl8|)!4NZYt+^3TR3T-AIz`GO%r|K%6=dWpKtb2}un!QuU^ zde+|P$(iVr%Mm8II>1mX+tVtZT*|G2m13r5dk)Nk*TY%4a*+y>m!q}23VA~E{JvJN zTq@l8ocvo#>Xqrm{N{j`h!N$yS-9in0!({$_jXa7tS>VDHwMS|&iRstpcHmWfU9F0 zlEUJoESh`(N$t$=oLoNc=2BAr>vphgQC#bNrjs&26sAvm(65{S6mc}^lw>v!B;>G_ z1f-pcn&%o$@f!F7TFs`)+my?`>qMHZW1Ud1e0t}*z~I&h$r`C{7qKeP|9!%L{1EyE zYGKm_n0Z1x%XrA#-)pGKPaxZXZncktiEydce?t2nU==U~okkA*h#wA1euht8IU${{ z^yQg{);_z)9>>ScmI8EYHcJujkX(oHhLZd%ECwIo z{dhI(z>NMKJfLF@nYi*gO6D3Q=j%yD``9HWmb23yP`1zuZSWz9JORcm`KlQq`8{x^ zV$Te`fe0$Ywg>^r`hQYw`Vm&5HOwqRBsVMP!y<%m1CYK{7cT%uW>sPw9Wj6v<)KiF z5E>=E^m)5(oHT&Vmv|e2{Jfgv`L{E6UY!UY`q`bQWb(T_8PAx31kG=W;j843A%EKq zN*o_b4olzDHa7*4F2gZu0s!oB&)y=0x!YMcg`+H#k|ih2`FT*{uH|c6{aLT17xUA& z8wG8V)46oVNX!$J9uebC%HUZh^%Vwjiz<zHa*`txX z5yV)w7M{PfRa2{jQW2&zX|r7u$e(`ncUuK;%>)lh`t?A?q1BWGZw>m&m8G>6QTUoo z9CDh$k;C35Pmox3YQ0~_3VpDLE&1`fA_1-wM%ps;FpX^J(Ob7& z8~MbxL+~LnX~ner)!&lpu78aH4V`HCz|-}o(mpSp`snvc6>*X!?+6L9IDcQD0g((O z+w-GyUb`$8IVhsD+^;{DWQMLNmaqO$t$IUzbl+Si9Q|#oI)!WpUP2nx;mHZMRgrG&BYq-%uNKr%$yzx zf;wakcbZlkcZ)Q-xVv0uP5R#ZX{9-`p&CTYRA&?+VIlI_r@9lRLtU@mGW07YJYV6oq@yS4u6ML%^u;@$nR@jNbEtJWcIF;+V) zuB8;u5Oj@I7Uic6VqK42u@O02r%F&$2+TOIx#$L77m@w+3U_-cw6S|xMUkqOb+*zy zJSTI%8W&CN{W-06N48CCW99$#C32q%`{IujnBM{l%a>hj(n?nyk~@RKftenZcat4s1{|s_Y?281jgFW-d--}n*OV~ z`_kknpSQCJkrdgKTcQ6K24C!EmRj98ed{gFcx~QkgRQB98D7L{@v(2_u6K-C$u@_x znHYvGl{WrHO6LKQKgpnLK3kT?LsL09&w5T1LV0_jN-z4g!1;!%RP^z)G#hjaIZ|FD zc8rNgF;3n5q+Se;vQ5uliIaHfxv)*iXrj%Ny^UihX!ADCtd_#3z3BXWYloR6MW=Q4 z8BiQ#LjKa}YS-S)$y(E-CE*@|#S^psi<;Iv>P;8D>hh>J4oze1z5WOO{4dq${+PcR zNF`-$QNWJF-?(Ui&tKYVB~tp_Ci1{q(*;ZSwSxKCV?X=pKjL?glf4>qtIh_V&Iz}A zIbv9nR4nGvcolOXcZsMeP7Eu!HGE>^a!LF{<~~Oxqt+o~@b@YC&V0%NJ|4tlteli} zPt6z3TjDgu*`iL$v{UoeJSo(Vo6L+c-v;;{^GueasU9ifa^D?Rqz;T=CB3HD2mE2C z!Te!MZz(CH=(7ha;d=b=6qP&vFen!gb&x{yzdK53DB$51tRGlp=a|h?BDcADB66(o zvjP6D9~arl>97m&ZsVACBp=}ZJA#Cpgu@U*5@*^|Vn45(S*tWY$kp3(0b zfJm#;tQ!T}*j`;2j&5XZh;AF%9a&Q^*o47HMZ^)#p!?BiE@lq4+<39EaLfQvlO%Fh zAF>?>4;Np%9ilz_Z;y!y&}UqIX{*lt%}GZ;O@>`9q$7UC%WRA@)No9bt zuh_Vv^U@`w5Ekq&_&zzAGAI6;`?(EuOu=rn6e)ibu{u?vq%Zqx$vZ`$d<#Me;_gVt zEjFyP5=Nz!drH=m2`Q#vItZc+Vrcle(s4xr4yJ@)tndrfy@e^kaGx*V<2(w@k&vufNeX1_I{Liio*vx_&M*!#RV4R z4PTlCmAiNd*fr|=JlXOiEE@%kW-%Z?oNNvFY&G~JOt+VE96!Ne7Gpc=LHdMY_*nl0kk>dex7?UQ3T28+gu_ykVEi}()T-1sb_3yIqI)kXVH&m7QJoUoPWdLOnJ}Lw8$pchB80P_&|cvQ#EoW#GK4 zWv-|mx#_jp)tm~~Y|9*7+Wvm=@5!6F%{0Jmyk>9yRDQ>C;eR5v0(}*ubdNb}L-ok3 zq^>4Z%VnqGf^mpz89QEr3a;SRivg66#WN6=c2o!PhjskOF>W$tfXi;=s@~ski7X-fykCD^78b54?SSpH#7xOmKZwHm#621;Tn+W z-x#nL#EuR%I>3}lw9&WN!XV}%6D|YirfqPRxB;|?CIMy-S=f)UFJJE7(a9OkUZ+Zd zwLsXU4$CrH{&p(I-eJdnI!G20(Gn4>vuW}eG3+J#t0x892(3lxq-A|9B9qz=Da-MA z?W`CTNkpttvnMgqe)$cX4`BJx)n9#m1K|{Sn7Q2kDwjvN=@+(b{%?4`eN&-r;{lTR zd_1#1+sDo2R)9sEW)NWy6Ym{#`~!S-XBTp>^Tg~hCS;vuU6X+51XPId4#x6qMVdb3 zrQbiK1N>9}=E!LfvaX{tgiZb~M_ynO>{ticL*%H^#egK#*j?pbf74ll3c$e+UgW=b zYB&|gHE11}KZ?z+?f2RzA%GbcA&eHgJ(J(CW8|#^= zi~+|6-JQW1r5Wee@`1+6#j(r7#bT*X%G0QBGGa^a3(W@2m&xUo7>STL_1l7q#PrTc zZ=+#Oaa$~(qD=IZmQXlhe(rTrkN0K*34!}(1SYY4`EPppv&%u>^r}stY%Tcy`}Vo# z)b){T-bNu|Qr`=td_m@qT)+LPjf&_*QwP%AM`re-u2&PHOESvb_ecK<@9t;RjkT}e zfwlUPHI~7e`O55j2lm|f1VwsdYSHbj?p=J=;;oN^<(Jp$gU{aXfeCH(E2NVKRfasw9HIGO(OEJs?g}vr zM7OIroIgR{DS0&O$|gM6w@v$flwJd^mWkzmx->6LDPSIL3-FOj4~QR>WFWby`aUSa z@bhUqY6`_SS9?6OE}9pyi4}X?E0Z>nsC9y0ZW+lmBA#)~I!E+^Dn+-Vi6ptMg zRv;!K3}`+ch#5lw9R>k#ypvgrL$Ej2jwb;NZjN^YJp2-*=0c&Y4qKx|v^GANY0(rX+4v^gCX0e?Y2 z#&nnB?@G}at)f5ski1vMW|nX_y&GGmoG4DvYh(?6txdGcu%>56P% zgDhmZXO*7GS&#*n?H^;W%~NsxoXZJ9hRZQ?+70sM&b4HUUlL3AECYgO=YZ|A@opJu zA}J~;lv7&$yYicapQ!>~w{)4laMz~INTruXmfpj@3?eX-me*T+-;9KFr!r6%mTcK^ z!6Mv{Vsb7!MZ-OC*b!N$MyoSr!6Z&b>&%q^8yVN9<0lbt<$Zr7WG&bm<|k)etzy)Q z)!i?kVu`|J!y>-NFyB%(tr@eOlShtcjJh`6Y2vSdwGu0km&RFhU9TMGlVwWLWM87< zBQ4W~vY$fthsH5V%mh>Oqfud9LRMbsD7MFX+}sVf(E2#tW3W1iZPS_| zS5&alel^oAC6W#H({7WA4!DTB2sLz~){^e=pOo_P_j+Ia@ic1L!(y>bnBL`W48-^R ze5^2pI2@*x27U6eEBhI}!B&8&3t|e(_zGc}Wbg6G;6vT*=!tktkHovZdo*CyQqr_? z7Z7F;^XWjvNB{?|WRKW8`PkJoq;S!VQHg#=4L(j{KcxfyT(Ru%$ws z2Q77D$4Z2|;1z}rpmgbEn^tfs49yjw_wV=w<4rCBsEv(MCAptg^fx*t3{&!LEv;tL z8)dcPH#8@+>wMn6hS3?dWo zriY{5fVzn_DHn_V0zRX6Y>`3;LBwe+8+y^u>;VB!GFc{zkKuflo$I{pZ0B-`QiibJ zu~@LyY{^}32*r!sP9W3}mzb&PhLZ&|Nm}Nkn=;P!Ulp0{XjgH&l3HG=BeFR<7wcC{ z?N9tu5Gk)$u)$w5*tkhFmGJh^!TBU*>5xrdyxk@HVk3$AzT78_xyaf$#?*nDx~=L7 z2$=;e;+7VZc(mi(GrhY7_p`H1F`x#x5M+;6SuvNJYms%W82fL7lS2>wiBD@0#5(I@ z=H5rn%4OQ;-!Cy}!K;;`%iWHqpO+;(10l#NQMiq^AxIu#s3T|1RV8W{8{^Z0jj3`C zAp2$HS~&=EQMRh(v2lq>E$AFfo}BE9!{iqh?TW!T7LWb=#T9>KCGYLlJ45>Y(a;Fh z?u%(2r>&AiSH4U@_K*n_E%O}Mbq@%9rFL0YRPFqX`)i8njmJ)G5(^cO@R(!T9-DH8z*0MAE^Qt5E{^UB`_g zQK>C5b1DI}OiDDY6r(9w?KNBEtQnJYb`h_v^gO4V!n0EpXT;5m)cr-N-1Zpl)?-Z6 z`n1t-+?a;_O4{+Th-Ed{_nb}Yvw!Ir8Y-Q(E7Or0d&EVSaE9sig}%xq+(JJ+Is?-w zY#~%PW7IfCeMPy>FE0`8VJiAxFBklV1fH!jmA$)v%`yJoKhZY0->7R)rQDZrUz4#b z@+{(q4cg27za%~&z;`Hw%DxRNV|HoOg`l_QO5ZnqcA7zyVK|H6uHLFc%_f9Oz-bMkxYky+ zTz>yh+RXjjcifF{2@k_8(D%j5zr%03GW5qpXfXROwaKre5eS*>->P4WvEXkD#$9st zdAj|JdBwGibXAIQAmihhgvOc!P?$u*uiF9Nt7v1~I$1>l^; ziWFcdp;Ft*B<^9HqCUKcrf>anC{+wrj>QLfkY^CA`oFRkO=XLJj)zq9!%`Xjs1M|- z+mINL#al@3I-O|8^5U$QlT0k&=Yc;`VEkN}JGr{MFiF6AC6~Jpk@z9`NnWQU^6Pgx z1#Fm-4bJ)6hA`ILj-fUx^RM$e}nALJk6 z8s6ZWpRp|_aHNDneApF{t244dOac>B;F4N1!+V8060O#`vr|kt$@5ITG4dBnK!+-E zC2<(v2JagHh5YrZ)c4P`u6KBUFkks#;BB|P6HWqj+IO3Kgd?{;Zm38_bMOJRG*%%j z>A|H8Pg#PG-{UlT>?|}e(*we6)dpBnK9ngKSIBvKS)1pB#$b>ot_9MrgJG|s4D_`t z@1!)gh?T8=iM+FBZ_F+4h~jKVmu1sxv(K+^&NPsI5f(m-nJps8`OMCq3uXssq(qmw zdr(-a`&_!a2Q`tvC%?81cL5`oZO2Bsa9N}oYbD!ifbm}y-+h!xS>9)-p^A#NjU#Da zsTIiOws+k5<(q}5(}ADx3bzTO6LkI+(X?z;4VZWWJ<$m4ZnZhz7_;U)Bol4N`EcFt z`FKfthTV?sORUpW)T%R)JigZ-Tf#K|3fe;y_0(wQJ!pm`&xwlm-BHdpU^1Uc%M?%B z$9N<|1~%6*DdzD`UTl0Ds4xN%0#G(-d9{?>^#H~OcpGe8>0QhJ^7lTONS7m5z%bC> zRH9Ty;`&J6PU4A7oJe3peU|Tj36$5!t=b7#zTM8CwI!g!iWM`?awFCO`8aK$N~N5BKmGm7ijt>EAY=j?<%a(9>-d|Hz*x=$YpCwg z7dow!2W)r4I+)Uppp@B;WuHOR%c;=DS$oXBi{6l@8RVDTJ9;ukBfq{tCQvrbYi7*W zqHaQ1K%)PrP!6qDXxM-8#>){4;Ay)F$-)Vl$#_**+N-nsWityZOcgMfX-uo7r0;l9 zEGrYzSb^)c;8U`(h99b)$TFkfs3wDfC4*xfDKM;lppy1#Y{Mr8>vvg|(pk-bxZm8T z;=>OFn~b?1;y1)x6&pG6MdwGLDfCx3^e{<*vHILMmIH>EoJfV`plC#e{? zTP%J;uur}(bHW@xZsNJV)Fn#*y=fP^NV*s-FPdy-ZdIjDj$qLD?iRL-tm9WUtf=!b zaNeFc%^KUb-cc6WzO29gCq`Iwfq&%Je03NGxgFm*Mk6;)L;b__~=K15j1qN{nC4CWI5x5Nz9WU(vk^x~E z5Jb}tEL>>8Z;?iyn06KM@*!ZA#F7Mc z+Y3R)Tq|ZG3XXGcW-2q&(+UPbNG)#IZ}iUw-%{$}LW7 z7wX8JCl`Had>O(f5Z6cDckTZE3h!Axy>8?AfHjNbyJDxJ-#kg#9l~b|8GK{Dog6P| z-fDmDe(7$d5;)Ofu6Fq8W5kKJ-d?*PQexWg6N9wc!>|Xiums)$MowrBaxDvq92s;FH-&X2AOreJcz1Y zS(7hpQaomQv(`SQ8gPmlToA*{sf)sWCG#E+ z^dzSK0{G;(#lCC2io6JEP@~faOmw2204E8=F_T(a>*^ly2z`6MlkJEevv9aupLM}X zZo13-Zv&LlVWCl;b?T-BRd?snxB5#vun#FcAJp6hAttwRd>bvuUXD(#rq*>y5Njto zEg(M`pVTZ&thhd3ELWW1^FE_^Mfk+^h3=!$|VSdP0pnBm>ZjKZuZvJc5R;iq2VgSe=(nq+HR>ZB8dfu~3 zJlm!Dt<(*hduBsQcD94xwScL#Q^AITi_yw9@BVPlc|Jsr6%7z$tsV(g#DSx)o{qdH z(@lN9Fe&*-Fwdmg9@Wj|Te3-88R6zi7i#;x@@(uAXrq2k&RcCdN_>iYJlb%#ERlLb z)=`uN4g-AdP7iG+pDeGC>HO90y!WulUg^p^r5Hq@x`mtl^q^yAF~02r{;G?$FS3tf zj})Ul7KBw+Rh#ylI!wnaCg{V=tG!jg&LtB~?)SOL{g`4B^?v!sYV(4~WY{|W1Dwyo zwk}CWHN8@ZRwaR0`rJC|A_*a${N%byGg&b8Oc!P1qXmT`H<179&@@GEhA!yW0Z}Ia zh9=eB-eQV0@$jW5r!?W$!k?3N$|!qNnE-i$%fb)M=6gRvWtvc%Weo5XZ0ftHIDz91 z>B^>yK6k^feco%Leukt`x&uhRrAKzUzgl|Nf+~8_ejv_?*}M{jnTC$6v9uk44yZ6} zazs5<$d4Nir?I#?&x04c$epB~qmHMF*c|@5Bh&G&?%M2Lr}|sj+g4CKCNq zd!L?w_jiDCb_^6{Zq6{A?dkU0QddI(*+*2Bpa%t!EmLE%3%Tv>K86PX`-@x@BVg^n zxwC2Kw0(+`k^o@r?fk^MiR+{hM^`hOz{l~x-eey@#~VjSgE{#ij@}Ax4(mf8(7x|W zTRu%mLwt&HGz>eI7>gY3m0M*ILdQeU@Iu^etw8Qc!`2l{9m{kbV^6^N{3R@9`DdR;s?f0z zF47d{FUw)%mf<9FmBxgAcsX3SM0P~ouv_w6R4}uilU4r;WpAb02XH*j>BoNaKNM{ zQ0(Ae=E^G~P)uT2O>6wMtrcLFKzEQ1njKI^gzT}fm)1)VMZ)0v5PplFiowOO^JpRB z1?`}_IB&x4B>sd#Vfm(8F*BIb@Z}YkRG6L3E!wKR^Q|P4Y&N7y^3k74i*$9udiAH& zEAqiR0E%jBXs7~+d`KGmjrVsdsCw&QjhLDUF7eYaH4^LPlMl^Eh+8zt*3^McKgqNq zfJypGr9_CI_~abW4S|5{&l_0B21}%d;?MF+-@H=qenj(j8dcu*Jr6R)^v1WrL9D?X zNKI^T2WK@lI`Fo~-PVi^Lf^byn$4w8LQ{! zsYK8Ev0;;_6SY3rU}2fMg7>kz=G|sSw(Iv*q%7apXtpV|w~HZ`JxTDK1!AKpZwk=G zOcEWj?4^ne2%J}+tityZdh8i3Dxy(&vKDqPN|;I&$;wd6_OhTWLfmwDtiH3!S9iYD zNMjaK+^9*m#yHz(Cw+k4t>T%=ccPI^Bt4YT_%vJezSx6d^)bSxFEm7o#NLl7?4NCw zz*XBtF8cnfk@2=#PGUJOu?z-1gg>WB+)rg>3;e%w!yzy4|FUEI}JzK>&|1U0=K;$0^dHu0nqj7+wwv?N(;}Eq=#b zE}y#x`-9mnQq=#3|FYwoFoZf!^pwV;gQ-HH=s;X6XzRZj1jd}kHsG|4uaXeTJcxQN z#)a*`4D#Qu4jV}FuWU8R#!PX#{p_E52eXyr^mO81Rkiin=05;ass{bsTojm5IkG#D zz~yJm_1v}PAtwQ$f#3!$V=f9Wam?8#d2$Uts4UH~$01A1Dg0Q_#nKSk%#|KKxdRRMJB0doCMhcp{yYrsVl8 z=q0aG8y4lxFCBWJ7Wh}efVuxW34z;PXvUJVUtE|ad0wa&CL#$O;=6Hsm_p4?bSk?F zZ7-oyZqugv{lu$b0+Ksh62V{6K^thK(B2wjcrpVCP7>La868((wwS)fexBaQm=yTR z3$R5AbC)hKBv0INToW>*xVfLVjClcZcrYCM@^ttG_1}4;#6uu0#n+o0K1mb>^sBUI z%TBKo@B1 z2H2UA+ad!xh!Zkf{1w*twBrVgeweWCr2XN)IQA#jO!Z~WN1@!jBcoVA3hG0_0nwi* z%#%F{M2`Qy0LBpkJm{$B4g#F@>l0PE&vig`XFvPvcgBtnfOgl{4e{L4AZ5?alKXjg zI)_BlOgVi5VObM5i0S>mDk0i#|8nn3f>Yb;epf;6mmQhr4jmuWfsrd0I9`BavsspWerQ6U2yq|D^f zR=hE8 zO0i`5mTmYh!{@?*MHUD|?WKcWdu+C1g*b=kEE!iai{ z+$hhdiNd>}&zUDvG(}K#VXle|6ssTKG?pCGt+U*{gxk&C!t$&*&xL!%`pNJ8U zk5%l`$*wh)u90gS@|QKjFm-eFU2+acN|e75SoKqnf7aj4N|^nKt(gM!*f%9)eQ+Fy zEcjO_4&~>%4N>bdr_o@Pw>!(ju-!HbQq>vM*4yj4bZx^tG9gl;Eu06{-GSJF9GGCV zp<}#z*E7Xf!e`NEb^p#2Tp|Wd8jI~sLw}GDEp=g+TW22It*K3SzsFUrgz_2FvqajX zhp*igQFt%z*MC*J58SuM%1Z%EwVJ|&i+r5{-e+_FtM8Nh)G5joCkB83KP90^s;IRz{p7KH{_zisJ$O%rpX8Or z`IrNm3wcU4Wru!HWNpD7xJ6HbAAoAD8q|n4y&p3ROrIO`U;be_~Lv z{uhj9t39p13j^h8w7>WeOpdpOK6F6qB?eO<8}jT6Yfrg8p~{WilXG zs`y{KQ;PldB4@4EhWm3w@y%-Ju)XWi>g3{|S~{}m*9+VSJ+-rabDO9ySSBN#=l(IT3Y)1 zbbC4Fbaq<%8XpYH1mBgeHv5#fC<_b+a?z03agz431kil2o8O-aY_1xZPHw5sSQ+z! z4$(ek*}DzKKyrnqY>TIHq67g!=gg zq8q1fiZXX*TLnR73U)!<;DwA2guPdwegk(l3)n1++k8tT7#!rXIk5_6E}(Zz6Wbw8 zX2}1B21J_@B}i@@^{2zVkMYV6KHjlCAVukZk_$LgJk*W-+hN_Us#YB9pGolk^G36e zej|ZM2Q)wKR-g*wTtrh<#el%`E!4hHz1{fJ$;vsnAnZ76O6AvT?b4LqH8LS-SrSOf z`SUzH)SuknE=+8i!k6$2bW@@+uZ!YSyiL*&FQD4K78^WnP$pQcx;WpUf}%I(jQt79 z!KW9E_2{IFN7v%f$!@^csXDXE`0=5Fh2W&?~mNXCD>!! zOKo<4X4xF;D|{MPBvXENy%N#z-XHPqF7bpnu|qBU+IF66ymcmAEe9wBG*kY9_(M`t z$-bqgGII{AtB>{N?AQ?D+ecUa`0exy6@J=HO&=Qe zHMM*84Kd?_6h6sf(Mc7GyR?t2whVw?Gp%|Sd1i}`gq6M_ml*ZsFj9afn9<1EPDk>Z ze(_o)`m3=gwxsX z|76nXf9UVU_srT%NLwnJKEyoX^hM`74NAo^B3K6pRPjfZv zjIK^Hz&-nwFLNddouY=6d1hyr`!vyrt7Ur`qMh`y6)JWvv-nk?Q+u zFaPVGh#M!2F0PElbF}m+EA+l?*{I-8)eh9Bv5$6p?V2K?|ERr9=xegu6ok_nLm3_r}K(!_=}Ws|tO< zhy*g1S;B%If0uL7H!5JakF_KGXbHp7CVv8?R@_4!SGe`ivc%u)sL{OTIpf~6KM3Zp z?IS@;(36IM4z2FZ(joWXW=V#bBev&fs~ZZeapKryTl}}={%Fl&vkHBWp`;g-BcKb5 zl?m#g9X31={Ovm3jQH7xp1KqU=3-*^3JIuuO8kKV8sdEF9uU7tL7_BYHQC1}HC8!_tZuyaZ;#%E- z{woIUTfJB~&HBcNCW7jDklLlfqWhE3u@l~}Eoa$p3=gYVh0Pz2xZu_4aFvPgh6)n0 z&428(?fJhx;?UB4K6=mFe_6S-{DZygQxNa>HM_KXPmgImM}Mky4Lf&dW=2&R;SgC0JNf zzfCIdWa^s)T|eE3I|uQPn)J>VWYA@%wy(7kiQUlD=_`a^tOetry>Gv#bcH3V$~wos zi&O|PdxaX;cro%Ae4+R*{!1HCKsNn;P-E|@uC_J-`#SuGEoibVo_mP6?OI-d>G?RE z;Tb{Dx9m80Pb$r@w#fc(dZHiRr@6MGQVu3Vv~uGl53T{XCHHEqGC^pW#`=iX;DnZMn|>kNL4dX+tcETF^k zz>higkHIXXgi3m)d~{B;cx^)pr*e;Jrn~++{69xpqmq*D|tUeuXAAHoJr>{ z&e{co6+TN)Zw$?t@TmOc`JaYw)u(2;bmwLnn4Q8C%x`66BS01n=huj<9`2*7=wDED zgpJ>f_NOaB4;bmz0>3ccmJxD4QC1P-S~e1*zDk15O@zuvnnHEV^-8bc03nrLNXL7DF( zxbr3y=tIXPq4=MSVtZdo&6sutFIvl1L7s!9Z}KDZ#Y#9hT27?*3;$fnf(dT_Ibbi6 zD1AT0&q|N24qu^`3VZV=nno(-&OB^jUfr1TgS7_5w>yR~D08OA2S}o@1K#Eh71sR- zX>Hll(sbZaFFf#Kt_?)@_bc~Y0Y06U-dW?l2ojf${#}@s&r@CeDJ+e#`u3m9Pw@c_ z=XNWx-CN50L$;?{^Xg-Y`Dp0TD$T6;R`Upynji1dcl2!iDOz|xuYz=ivt;VCAw;lG zq4@<)B{oje>{6WiV6lu`5#%HbGev^tw!Pj{mM@N^5^5QyIRBb-e$#n(=R;9T z^wrHDoVOP+^XPekk z^jCJfemm0hrC2ec)BOV`t?WP|3;!6KUi-h(K8Mw;m3p&d>h#@pQB z5HOH5ueOvN@~~X?x{7Dwy&6g5&LVVQ-P)-0-o}XkxWeFI-3}CcTHUnd__Vz)9WjNm zgdOLi@dcAN;-pHyrWff!@)3z>`JE}^O@4s%QmEe^O4ghgw?_UIsu12x554@0JeOAc zm@qdab^Zg*w~bXr{q~4jlYG9PPWS};NJ25+q5Q|v%F24=Xy4SE8xthqdcz_DBppV{ zv0o?WT3yG=QmymWaicU{t*!gtg+;5wTziM`ub#Y2m<4HlkbvxdkZy1@BrCY zlM}QIj8%`wg*lIdwaPCrpHBcqRvRBCPV}09_CB+9eb*3^w)kdJ7=uz# zZ$0jUNeMC`mu8UE3s3HM03l!e|DP+JFEej5z+Q+chbi~q!%E$LUyc>df_zy@E-zv- z@XH}7@;L)C{$zuNkqHM;5U&agyO&@dTo-mf?Vqql@YqI4P^-T0>SS~u^1qKoK47s* zW9IToy)yb%JDg^Pf);Xjtovr>Lrwrlw*B~H^gqaB@vE9<#Zd}c80apO7FO0CpOjTX z{#F_@Zul#<1o!@i%bnmbR0a(}&$tcuz&(<%>NC9(2(8HNhVxf%!jZV#pOQRsg)CaQ zNV}q6(NrRYLXd_85izV!-}1|TD3(e|xkqH*?^2vs{rWZT=H^EDDgBd=txAHZv3^1} z{r?U=h47gl`6Q22i*R#1ry@gK@j&GR(0GC4+s0&pvLh0wQSZ9>9tm?xN5XQtsQnJP z467|dkQA%Ic_ubCwn9m%j|$eil*$}q0{#CG6Rc$uc^{U2t(nINB!+4(53hdI=lv`& z-g7l(Ru-vbzq)B4#p=i&wcnpEska&;S!(vK;)4IDHj@`6H z5`})osG68$T_Tp|UMGj(kdn`BYRFSrAz|yk@u-Ald8vIj`9(x1CgwB!dKXuAiF zv&EqfCu@IobaZ+tEB&I8rx(Ittrl&yvt!_kU7$lu_+fFUwmzVO)d6zwG~2FS@OP~q z_4{+(uv6SyejHjD5}Z7ereCC%SzcV+@AA(Bu{eVydG{?X#EJN4Y8JWgj`p^#JT2AQ zb%}2-N~q<$Gj5_Z3p|*upcpY%g%i}98-_^9TL!uu)qH%nuAq)ZTi|oPVT}|?r^M;ueuB*dMDN;; z%)c_Az0%`kRAFUL_b;Dj?uXtyhV+?1CG-y;A9#Q<)!a{3% z1aF6DL9g`vkPyr7r}IcNDmC|d_v;#vER@c7WuC*dZ5er;+ALqcYuqAi!%29`QuUZa z((gYZ{V4KR+{eWD%{qcmE4h%N+(|q?cAlk(o*CE{)q2ZhZ>aNQdW=aL+0t6Ufn3*V zRQGi#(fG3n^Fh#3jgeBb-ocIR-Oh0133K`_CKWUGpJ#^L}aB zA<|Z+Ub{?Z;dV6!fAtk3v7(--U>1@p`w7WC9gb9N52l?S%M$GeFDO}D3EO;!^YAKw#qxQ+? ze;>lVkLKpQD#do1o);~jj}|S(?_>VL1?CvC-ODq|^vs@-mUR!iaaVD}RJ|uNx~AJm zJ1lDlA@QRa&!Uupl2*Jlzq$Sd6Rj^%(j6yn8ftl#UWCMi_F)N!F&-yQ9|flL#TrNz z)LK7I9Vs#uV@~>Vjip#Fe+$K@aYEi_r1fZLjDBLX_EC9fv?ASPu4WCLf$*Lv63>BZ z_bOjR-Q4i$MkL1~k-DfkN9zS4isqjjx|`KCzjV0y<NV5(dZEd+b zp=U2emSV85#Wks^zj>Gwl5RLniCnW!1^nUW>@AqXa_Zvd%z@7p#OhgF;<~kirVGsn zoFb(T$D2F~nC8+bvY0>=#n>ELTj^z7Z|~G0s$MdhWio5-n;v6~23KAG<(10&)~e$M zarK(4)z+Acy>VQXVu@Mzrm>Pm9qs1QS?}lBQiLbI7KyWo;5|oYKSNx(ZT70{#oTIjAN7#kvJ1kwW`uu27on?`()gzB+%B5jC1>ML z;O&s<>}s@bKo$Ru)%=@`SxX>qp*Ju|^L;HktMk#_yYdC^a_x8@xMBc}q?|&Pz+)AA z)7n6w&VDEc+aGrW?PraH0)fmwz`B?J5*i8|Gv$`hS3hlnFtmz!(W#4HUB}VKh)y=D z6Lc!&OlokS5HcmVColDg!7MX~XvTBZxSWGZkT#V-dv>Ka$17GM!j;X&H2(F!bq1Ew z^^45Jo?ELB*M1$v#$F4I`e$x5N`V(kB+aC;DbDBKVDiTH)4rx5T)~mB7F;csZ$3r)B zkl)B)_6r6kJy^epcj*8`Opx?&)b}q7diidag!(7sOEGtt`TM8BQ_g_N|*YrfT65v9CX)WH6AZ|;tAo`NnjA(!8t4|9{{$AcG0fW_&F+>!hDp_%FVN7 zuC`ZtS1;O(B+Osgx1k0f9yh(V%|Tgo+y80@B*?_ij6$}$_`cwzu9ECcAl7RvyUXCI z4URQ^yl8F;xm9XrT<_I^`@0-(-!wxT%Y%gLE_WMuMI+HJ*7n4%m(NRqNy|prS*X%0 z`lIQnWM3mXPk$IX0o`B{=YjWb!Wdo9#iJR##!IEa2%+%1v4@+7^RXh4qd&p%Rb!7_ z_}MOC2?RO2lKCe2|ig`bE|<8DYHXC+K3^?ZXNd zfQ&Qe_hDA^5+F%ekpEQVURlLy^^0a3(ORd;-tEutNp|hOS1|{+=M3FH6CNFqDz~Ta zL}w)(Kc|g|EmT(_Kkt*__7|li@CD%@i_(h;?iP>@lRRG%h8)uKTaXTj9}OXLiW5xK z%+eIdIJa6@|K&th`SoYkRLXhtG8`L<=eq7I8RcfWWO!Ni7^E5qOlrxt@S*XX)=-oP zqWzR1b~PXDPB+#*{+9GRaRC5e^CKzGN(?|+2Q&k!T-?h9yXL$CI7m`Cu5axGVQ76f zo+h?5r4BT&KC~$~Eqna1{=hv8h@B}NwH%e&#r~x&h&}}U3tj>`kL<740O11Rf9ZV=71>A4q2A0HHley0 ztT8@?))qBzc|17U_!T}p!6+A@6b(_53atmwa=HX01bSQTFMF^(xZX=3euLC7D+(%AmLFUY4{!1VsG} zKL4FKRUhD}8<7*J+}kj0Asc(zy05J6m5{4W+SiCIlLD$pBPdGQgi zNZ1slNTbg`I1*r!mKl5rnU@%hNNUJ9*I6?ZG8Hbbkd2|F@Ojk0C_pbNAOB!-bN*P- zkLFfB8*@CJDZd)6KCE6*Q}A+Gj1rbkvsk1O7+^(LhPM`M4HRkJU&xN_sCZ zl6t~yrV7Y?@*oHB1L-^v{?yHKOEs;{hRCi^pDZIS%lG5<8@S%&92+twevo_c7`5*jGUDM*pDK^Qf{>(K* zdlWTkMe7l&R={e={nEB1cd(=LyDo0=8;%`Ep|rPXph}*z*BUI`a~>3HW~+Rrfc_)r zLDXuNjo~D%ia{sx-{U;rTGWq{c9-`9M}R@z>s4{%P0Q!)P$jf2^4I={8P^F zdyeylb%^j-Qdb64y=LOKz7<4L$2XMV)ZQ9i0?^`Biq}{2+?0R-R=cX zIM@4ATrN&KlBT!+zd)~^a9UODXVu?!zOZY!&Wy7TEXTI@ztj#NX*!&&wdV_T;`Sq9 z4y-mMF!@|GVCTknJlgWFllQrlZK{Q>N`dE{pacRUb{{?Ow1hqm$a1K?cd|>+=OKE- zWxg=Ud%u~?eCb>bZyWIHD!t!5nxU*@_w(QCvKw}4=GS(-@w*t+oK%}>J}pO5F88zD zdzh!PX7YZs zyzy@0UHN@bw^zUN%(U`nNPBOCYD`t$(MylK`RctR)fNRlS$g#H;kd^H-Y&!aO4E|( zUYfCZocQk%GP{Y;^T~0()yeUqaGAcM)?S@WVGrrF->X~smFeECOs&q7A_-@LyXvn4 zJ0CKtO1)s9thpuF`#rE*lfmORQ&;MiUt>c<{|M&5YE&*v} zl!CxeS{M?WAR;{^6(mJkO1g%CNOwt#z@)oNP`X4)x$Jx%# z&VBCt`MjRjbv+wxO9X%_?_w7u4&*)U;@rEA#8P*26x{5eSWU=IOvwhx*|l1^{EkI^ zQ<9eFj(P3y_LlyCi?cKp!8WNkv(yMO)4u&$C)fGtSC;QbhWlQ3lSM{Bq)hCl{aCR2 zh2ncYxjs4@#aAlL+E=Y@>(zyQj7Ux*A>BU_}SBiev>}(epW&GE%+*I&EN9ES=y9%l>{ZJE8QpG#Jo<` zQBMT+34&k*vmn!7rhmDTzK{$FE~FG>bx~RDt$WiXnG3S)UG7+w)QiJ(g)$(|Jp75G zWuP**=Yh;!qhfSjj8-#Cb7p>{4x7xPwN9L$WwN9UN}(c8H~mL_|5(TbK^Fe zJkaf=O0s-@)hX0ejsFMwct#?0S}L>ZwGN~o*Z`(ij7b*M5DfpSuf0lqtj81s(D^#M zhZr3GGHV+@+^~I9H{!v5?kJmSP``SbNyS`*+tus5`GDTcEm;;`5-peVk7?to$Ay9Q z2HWl|W2PGudH;bu`W-`Ma>m-BwV84ihh5je2dMwi9#*aBBnnxf+BX z=0QY6!@m>!o(D~$WK?lt4gZ;zxcpu>x*Ie`jwy@l9lp?eGFS_RSuT-0I_WSj1M)(& zdZPsSrI%Irg9si^L?RbMti#@>5?YuYBfH`Y>}VGII>)Jd-D35mut%%&6YU|H#bTSM zh@V$)%V3!&&A;1wX9=@*uT$IUcOZHZ{^0pvXUPAhGc2*^k4tSX1rb=Uj_g?MK-`4R z7&J5X`l2xrALqLh_F-Q;D2o<1XZXjnkHaRnh^MaWBQDoh{4YNJC`kIRA;rTWF0+G9 z?UcHJ>%^R+0`4DK1pU=t=ebulMVtRAX|cz2e+Ggs-#q!}o~yY_{4CbzIP6dhN$Au$y9;brFmT~IS_*9JD?a`n2lfsOdlKsi% zHtSbhNQtr?Yp8uJa_eytjuRDS5f+^~OjAoJKjjbR=l%YN7zL54QrcyIn~322LxsZwqC336swzRKwq6GVm51z3ZVzM z)3fmQpuyjCuO)A-{#>Q&y0)myeK1cgZH+e*!9K-c+k;X9+X%M5`Km{nJ!I$6Qf_OP zRuk0J9XZJXxC%qwdHh~r(2JlY6zk5%gE6(B$H(8!hChn%TVK!L1gSxdt~H+6t_QG# zPGxDAg%|7lGb(zb1)vJW zF|+bJDCw<0;e)oD4Ng>=Q*;lSB|vtkQA+5jPd(S`VI3DY@ZnrNbQ0$F{ftWQn!`R_ z-3v074wRN3jX@IA_?XXe42YSu{O;yd`!aiRITEKfCVXk{c60siiY}?TINnt*u<^RD z%OFeEL+ihI@*w7xo?4$e1Q(X_@1;pcnePwUurU3Y^2BLlj{!=n$F}^Vzb{AZwFg67 ze7&fwEQ7Q>W8)^8578Yj?B>H9*PPmat_AOIh9d8=>Nk>H_Xn$GG)B zA_pkQ@0*iZS4)R9t0h9%uJP)X(8D{Z$YX$kzuO8;XsE16xP7P9_$^N#i4hCto03KsGJv&#)93*mp7G8@2)uL zcPQb21kw17!x+A*qwn!PmW-YAjY1JOT&2Fb-%Synh8aIE?EE@~82<_OOK? zbjH-r$(La0$QZ5={-m!(JjZ)2;%EM$-^`lCn4Hzkphdd^d;xg7L6?r7u%1-tbSem_ z{5{0Wn=6LyBv)<{P;2$W^5k!G0D)(Or0e?lt;T}-*Y{C(zmB-20$3P!RDxoP0|=Pk z(uNVn6ei6vh5 z)hbuef8&hw+znqx(pa~UZ@~Dtq}{8<$TBB2rzSoKdx%WZt^2LVNI&QLN`nf$A!l-1 z+J+WZc3dqruX7?FIeY)#8YQDEwP20<@Q+}M1UZ#ik~Xdrjmd6NvE-)McHLdZ$#Cd7 z)hh5k%TH!&U#GR}>X$kX3C%-EV4#bsN?xjr{m=3QgFRCvL z@2W>i#mF?zd_EoLLPcW!5^Q2s3q66aqkF2Mm!@-=aizQFG}ePZ%&rxQ;(GU6)Zj)PHdh3*7ahbV3a7?j%~fmh#IG;V+NH?AZY zvtcD`+Eq^*z)=IS0MNY)%~UnXj(ypm{wwn~oKBe#jrG z;XClTe*zIX{A(OV}lRPH2AFNy~^EU~_PatTdbj`^E&|Kf$jb1n7Q zUp6-KU(OB~lSH%}D#akX2mE>B0y@dp=wN(ajAroQrw|nf;wmdS_FdwroD6)*nF#hq zLFd8W=ktPYTG=j&ZW_^eEPs2coY#Lr*PMYz-h_Wj6aJLdik4i4(+%}LK?V3>fI|uN zcU7Q4JjZG(QfYJZ{LBEVQpV~;#k%_I>qvIpGQSFh91tEjDx*Il7|(!qs1I>Gxzkql9fS1PRpN@O_E`h?>lpa z>$B%2;%_}M`XTfz##1&LLT zIy}#Zn)yI6^a@UWJc^D!^fR7xn~F{4`wOeB6!kV!o|!Iopt1z7-Ydm&;^!G&$hfSi ziinqs7jvJksRYCtiP-(`LRI%4hz8Ou98ixH9 zQN5S!h#gABP%7dNbM?jkpMDou_K`%EX_ zm?d*_llHakRc>}17HlzV`TYylHT|r(3D-8#FjqL2KUbn9?XEuZC08E)Q{hS*U{5yx z@fMT#3aNGW9`rD5xb5fh;pCWb$FIIBya429SkoX~j@zg9Zj{ZG$8-Odi(J7ek zR9K&4>Xt;Btguew#m9$pR8*8fo197!#G(RpfC)}_!4*XuaeC-nxBNmoGn^O+Suy2k9gtZM47u+SSLq%nXzVB0WH@$Y^AjH6G{poF@#lIN{b zvu;tGX!dn3+}tU_V0M6+Mx4dru@C>k#dd+9zJLi5uIMp=(=w1xy9`jPhlqD1L5mj5 zt|lK{wdSLBqG&9CglebakM8_*55YFsWK6lSNxn6~ER^*@R>CUmZChRRCaL50eMHEE zc9L1a(NBWKpL!R6!U5^3R+lfZx(sCYxTlLK)a`XzRVEq$On^t*}RO(Kk8oI#Eu_xGm)4)+Wc$*^k|PF{@u~7{lVm ztz82{KN7D1KGivQR{K3pep-E!@hT3%(p!@+Jjfc!Gw&$%_D>)=Sn(Uqr_$_Oqm!$> zdKguD;VnIdP4{KL1_cg{e9H){^h~$~BJ1W#-r0dr2r!su*UC>^M#z{T>F%xi|4DO* zHH3vRN=*XwSV7+n)PMFMSoa@ZdA%}JPwyEZ)^MTqTGMz08oWqh{TO1^WuZ2?cpGk4 zv9Nl%O0$Lp2;KV`?qX-KN6z%J7x5!c3!#<@Pgm0Ls~@}Sj&8;Uvs7=Et8r9Sk8xnL ziBc?SWG*3;GPWRTlw==UpCu=MVAmX1z%~e3Cy&n79=)^fOmpJyoX618V7 zEw_Vid<<1h2AhoNmjC7OUqDi+bL;}7hgWiqf(epi@Qa! zWGG=q3|5TI2vQGIGi^lOh7DDFESw1~vw(<7>jsXRG1F48R|21-jg!R4UqL>@GUPVC ztfz&@ua}PWcAeJ_{vWtX24>=7qSw2pWEE^~q4YfNgk2?&F6`Icsn)Br(=m1aYfPG5 z+Wyin*W4K%{6It}M){=qwTBs99?=BowC89jV?pz3HaXJ3?s?U4loB+a1+iuE-W7 zjKBQ4!vY+{zq3$2%Z%Zwd4=iT=Z9P?1&^EW8I(|sUW>nFm9jC3stq4lYt&HpOEh2({xiM!y#0Pb+7xpLdvCu*~TYDviOV5VJii~adBoT9x> zcUJ9UIF=N-fsHe9An7k?XM)^9D7{YxP_57WEqlsirQyZa@J5&I$A-z(?t*r)^BC50 z&UZEyD2KU)^tUXI5`3}o#g0mEBf`fYgG1ao*NDUXXmIeld4}l=2vmxhsKZS@L(pt* zux(*y3<$-!_IyMn>-+-G+Sc$7U~1iqm-c*6RPEU3Y$uNr=1*B~R+Q{a9 z*~udV6Tea88BU1efi7q6iL=&^_-a4O6&K>hHf{)uDX)JjICJK~h9RZCLFph{-D|Hz zjI-l3DeT5+XeoGbxt&HRbS_a>Il!TE`j*B!ngc34>G-w39J7W)SikIZ4`67~Xoc=e1i7|Q%PJ4(q$VxzeSZj98F|G7azaV(Qd@ilFpp9A9F}=& z<=eU*xynVw|{QnUk4l75@*K10Wtq723)SGOBocsq*6fiO2^$~;R>Nv*Drq@2Hl z&>Sm2-X9yN!=Zd z|10Y@sD)iKMD8L8CX>PUvW^(}v~xu{<#rz92jh3!yA>w+yZuNd`}NrzTXzGk*sq?E z=~%plh22#)s+0?zd8+RhIuO~$@91`}pqyW0>|r*dFWmh}aQ+DJYkYUnSRA{$-g}j6 zuPl#Hp?zOhX@;O$0cL@2Mw}_U$Q}ki1Elc&)7*>dtiJ_eh^3x=?e~*Rb-sYkA?|KQ z=m~?crcuMK;(aDquh@1*PvI`tW33AA#GhvGQ#oBqyrCb)4#!*E>pOg6m}mpETrCPW zE+GL!jSos9Rvm5~35dz6v@G0_-uJbR3_T7p;7WGvapjcJ3MKY)U6r2TWdERYKfxtu z_gTMiEE)iIdyk+ecb+Kk&VFJko&N(t8J|!7FrjgC>3d_5)6C)%oo^a!Ek0k{fP&W| ztWhTw>27yEkBh+g!ifgS36Sax8q|{2h*M!)`S;stX~yLMBTs%$S9e6Xl9zS1I)&7d3g6i-;VXxN>fD8lq%DiK*mzIzah# z$Wa!x!wQp!jWGuwMY=8xW6z4g^u5Tzc1B=0^ULUKY#i#Y@34^WQU+J$$FtT3GS&@Hh)yQb&3&wZQv@zjS=vWG0oo}~eyyY{aY=6Cam8B<6K`{Suz zlhb7QO{JWKpS>`GT4E1c5Q72eA`51t&qsoAEdfL%24!ds05kkOG7dXum{Z4Q;5Xqq z=wm4Ud*B5W{`c*AUEN(`oRKezqq}$jeUChH*wM%jp z)7NJs&pd!c6sL8^@zt71H4-wqkd3FeX)z1UTuw|>QG*}Vp1zL(eS)X;D=}cp+A-!Z zWyNbwo;J^A^E8r&6xvenUwD0V7Y(U3yLVPO9QayZJ{r8$8r6|Q%V=Oo zkv}0DT`#t)2YMRgoDdwlT&i1}g?2KZx<9Gz;wQSDA8_-!^^0;-lwB?C_a)<6h`?Rb z0e{}BC+r1_kkGlXfwL?{F?9|_RZ9!ag%Ct4B=vaVc9f1Bb+d}HxG$KMKH_`k)%=b5 zY-12SdjPx@jFpQK2crUaZ%narrW^PvQ3MI}71RvnW zLn7{m9O&NRu0|Jg{%ha3+}#Pvdns=$VEm%`FIT6W9acxA9q_zfakA$_MT`-4u!HO`pu*WOyiH&bU$5RChR*7F-3eTq4z(_NP?HnK6L!Qgfm?WS z$@F0Vw3bVo>&uxbReGBf?(56nN7{!U1Pi16C5~I;t(hP&T0XdLP*3Wf7Rkew#NDwg zjYQ|(^bUv8PA&7_r1QCalNrmV5@C_?W+Moy$B_$yZdDYj@2+Ef6mEL6OZsK%J`8ua z-TaTmAx#F4&@LSclc`Zl77tVET&R#7^_}PP*+{6q+aVe2p!E{*L$mXH?Sy(&4a7o# z2=PVBJaWwCtFbkBn0~!WFpG}ZF@PN0JF}}xi*sp^l%P}1qRQF_aS%@ycMzvY3E4Vk zhCg;UDbERb6s-128b*{1(4V_=@Xqyc2fG^1_5R_P?u=0<7&EwgU^~k5Wf6sr)QXRp z|EJpFt2KWwf>gbh?karvX+@AwM^D6-5y^^=JdhbijM)CfD*Kj-xmo*ygXJGkpgO=k z@1zF+&WG=iAerFn?RVhKUXJr1aJ^z78F+96B}40WY7SsN4XnGxR_`Q{M-*E25PtlZ zH(X7k@TqQ?+J=~G&_SspA30ch$@_kxW%6$^_y9AwILl3~67~y}9S)J0xm@yBs{Xp1 z%)`PXpv{3GcF_ee=gPnZnZbc$K%YPEqt!KfgJI$<8bJLlS;Qxh z#3+wd#p0&Vs?n>e^(KnAEpO_b%{xz#vsHhzWJlO8H6bthYVBrUG`ocwxnENu%>FNC z3@2h2w|~n}Vn2jKtN$65k>xnM8Y^Th{kEh2zWLSX5>D94qXL!kI>o|U@O&vdO1&DA zixmyS*my1+%*~glA3+k|!_SzgeksCJr&g#**mu6qQQ5)^HIPdw8AQXjAmtU4wZPR(ebQj-=$k)YFWU4%MTLtYVXV z;RF%B1|eoJ=v1g2E*Kn{1xBbjQ!!smNAN$O4WObscNDe7@opr`30Z|ZCL@!tH)0`gSnbbVB`p%?!cY!1u%aMv|$t5@(dr;cvLx&hEm8bikWTCk5%1!pV9I7 zhTFU{!1QnAbq9tUo}dV zYlce_G!ATwmOpJ=5L2uQdxHF5PozBm^P%NRjIWOUn+4!Uv_XAFuF6FutnY3>0lpwFz{xmP!p{CVBC zM_jFkf!_=^Utc+!bfqCoFsCg5aP$44n}aVwcb57e)h@hM)w3Sdp45v3_>=AKS`wJ6sOioe41rsMwRp0KPM)UY*x-EFg4V`;-5J8iFUL^GW3h3%k zObwRJ3I1CC@X(NDW+Na9n;a$`n~5#bMnByO)XR~WTWOOxRN)G!(?%&@`Ro1nK3sef zBUm`EH>s5~_`K|f?4k@|N=Dy3W%L^2Kwy0~G5Gzl{Fg+`YHaj2KIBx))`Gf_O4V?V z=`^@anOV{V^#C(fqTm$nMF(r%+ppuBq<{$Rying>Hh9KaJx=~)Qm;gJUE;ieOSOYM zr_Q2}>f=wTO>CV_96@^`Rc=)MF|uBA`IL_$V<)4l)$eLyd>Yat`25Bl->E)x2C-+EEA4rs-RLB9>>Btf$z-a~2vT_JDfwyz7I)!+N-U1-WqIwWT1W=|M z5zLeH$!SV_VTMpiP=Dz?m|RrV=e^Td^98^hv?oo!8T1dSo?o+3SZChToSz5uahxx} zcd(WmVc?P`f>+J9)g1heI01ixWdF$4%0ed$p0%jD{aBszcixq7XW(}c!XDYlE8>#~G?glV{yLJg(9 zd&<^o60#Cc7g1_KeIn-ER~-~uyh66_6v?tl5L-EctKrq>osH1tPf0l;9rEy#-EJwOvp8A zvFCOFeiqZ+Jm4d+uqZ@C)jjH}W!HIHofdCAcLzWs$|n)TM{AwGC$KS0eARq{8O=`= zf;PN1?iT@kCHy^(-hO!}bmkEtaOPujaBZp2x?y7X7{K5O9O8sj4VVd5IfdTKh?N5fQ|P$*?O8M@NOS&TZ6>n&7Nd+tCl5#Lof3>$aO^t}eo)3*g`uzv#ffqwWPZu$=FZ_ib497jVdbM$4v?w>|YPwh;pch*LdzPbQJ-Na0=f9HS+};h=7m&iC zEw3+}@IH*HbQiuA(Rro+wMfS~R5S_`oT>S4M1x&>IVrJVnHfCEi-_F7Wa{PDf4x~O z@rq>(ygL0Rvc5HP9*}{5#^77Rf%{su!`Zp}S1^|J*WkNTRPf_`_^~lDcS4*pQflD3 zPsEgWA??{kZ>`+n)tby0)snv7uIRQ2r(`2Snluhk%}WDPjzn%~QGs-M zHE)MM@}l~sQ2`1-*8Dbr2NC2&P3MP#Fg-AiR-fo@b)2L7bB47&dE;E+)eZ$XVncPC zJ;wvuvWT7N+{a=+OgAjbxVhPq>H%1~t0;$90_>*(!MCZHdFD5I?Z}hsP!k-Z>iCvr zE@Z-*mycr$Dki}X&T_}9kI+;;y4K1Df7%F@_@%HCv(6Q<7o44OAI)^(I7N4*|KC~% zKGr{nY>9mYiC-$!6s}LG-0MtbbVCpo^TtzR`2Q*5g24Pca&v2rQ(Dd zcfHXWtD`ZrIWMgVb+jYb>w@)(CmZw%dm%h1Snf4a+kp5ThMt5)0J-WkC;U-u4#l|o z`8F+UA*ELp)-zTzp4RLe#%_x{68tt?mF+chr{UF%QV;0R=+|JqHT2eCbjH-xb;9pA zE^8c9)PsF}AA;%f)}SS65yquyv0esw>%;|{fRi+Obnl13UIOj-A_wep44t$ZS?27 zSg=a?C|=Qe_(ZgsG4Ebwmdjl|IUiFNw2wKD_Rsg64YQ%UDkmNT==*If{ltT8P`G02 zB0eU}kD)Ni7eu{M#0O6(2%Y%!glzcVL-Ga0eD~);CDa|kqmXsmHkdmKv3`B%)hW9e zfL%-zcQ2hIFU^EYe5$_7_5Kq!rE(zXIS4$eoCUQ%7UQ^ zwW-?+AEU^wUlop_<`FQQtlpS527Cc9;7SOo^5(d+zx;p_<2;3v)cVKMKLh$rk^@`P zSrhFL8ofx*eq*c5Flm#@0Qmrp5HkJF+=Nj2%)lF;Smpg?dNs!pD$ij850=+v&=kFp zede>p$C^gJ#mpY=3HjyqCJ1$Q-CfB~dy4BjT>Rh%rjO_gtDSTCw{5})G=S#n!B z)sBB}6Mqk(iD({AYI7*bC~j6C&2Hi*Q?74Tt%(a(7@jSDeEBS&aJO1}(!(6F5&x``AG$8A8CACYmu*kM3iZ-m zgpHVkx+(dMoCfl#lP@!sGIW+vxM!Nj);!V6 zEU~P6bAyzY`{^C8veiaQaVvwRKwdVLXy&#oJ3=I`9qT^Ixl7WQ(bF%68eXkhWn1M& z`JWn_j=}hiw)WRP2^4PxxBf)An_}zk% z@RM+9=6f307VdGVHo&DtPYiF|KJRsYfY%SgPm$p=p@j|o+G`+cm>`){lPEU<+h$-9 zdEu?~x2t-LM?|NoGov%(h>uKKzMicnhi%G$?RnmSSueB1-_hDB$jvx}oVo4DYq zY|>FAYkuym9^sf_57(e$lap?05x^rL^1E8-odOeJ)!7>XI;Y0$;|VV7??e8R3`nCe zd$H#r6?(GhaehR|m)`4KAt{gwdXvz3xA(}kEJJ*)iCxKwBo4G*gi3Hrsm#9kLyIOp z^-=KL#NDbY00W=Z-Eld|B7PtIV(w}6MqvDMh2~eUD7y zA^X~xMdyhH?FvHMQg2vdkkUQ(!G!NAEhPQ)sZ^H&Lu}0lQmQ9sN%()Q&zO1IX14S* z8c3h=szEp7I<bNg!A5xMSr^gGRD64rs5>0?hd6h44$e2pnUTlGulS!_LG9 zFB{&SpFd7~Zr4C(t$c{kCdc_D_9?yeh)h;yA65U4Ch9!DHhFg5oU55wWY*O47j!DW zf`IFG>tEsiLs$hKZ7{C-LoFA0cAP!0c*9%iO&R9VA9~}U3b>)bPHjVt=7(X5%Cn-Y zt^4l%4;Fb|701p#5?s%8hvq6$_SA)ohpH)_T+}vV;d6fb6W?$uv9gkj(&r6lcv?*3 zvmZ6MDkn1DeM0~dKrsk!h40kF?{x*Kq4!;*7>2%8%+POM$lPG59ax*{zqQLbduv8 zYTa$78vomZ$iN0AuXk*e`Kv7J`A?yzjVVQ@iD8rWTiXd;$sr+(sf=N|8H|g?tX^Ft z!?s26s_ul-bgNl)&sWgX%o>@Psgx;g%CB$c1ojg|?^g%;6WUQi9^7l|h4D9$rPPH> z^nr1yR4HwAAR>(2e)Ox2Un|3LE=%A@xVl?kmcwTBeqYvAZ15w{ zY1Sue4uVc*by7UmK!~6e1yeT@N4H+EdtrZF?fK1w9j}1w|B$PaVA z+Q!*KeG)L}Tb4h}d@o?Sf9{!w;tw7#%6f7N9-mehGd(VREhfhPC;I!7Si{(zC9j+D ziZ+3~UyVXxgQJ>EU`2nON&w&FJ>40*a=1)DXxpPV<{Mkp44aL_;5QBG`b$=s_Qjrh zQsvawqIt@hct`?~%KMZjUV~kCnMv8Yn&nntVeYy2f|Z~QS#E3CSl2;ptPV%IN*5mP zb(#BzJvnbd2oZ^`yNc2^6#$>tXN3d3V?Q8%wh4VRT8$Q&A9JOhBO;$ewQTB!pN5n&>bk_sZtQ zHxL_Qh?u-{zAnLwly7OG_O3gKSBM#7BW{R$5Dc>bHyf)R$d|OK@>{Xh>*WW-GTXAb zgOjmE=-;AfO2ms<5v#+De9+OmRjEZA0B;}Qv+I5|alc}Ifwpy1r6cI!lIybT*tx2v z)v)0J0W~BfQMdFFx2o30D+Ba%82|BdoKH}5M}6DcN#_dWT6xiGphj7e$RHrPVx1e# zl?clDtNrmq{13dMrAK&sql9y?ht%liiL!p40=FeuG!Ni(Q~F(FF$2JnlC%T{N{H^Qwa-xK1XYhV6e{Kyd2OW@A$`t5<`C8 zc;mY8-3hXMcBF51H6n;g4|ngVYtx?VUrozy#rzO^wrY8OU+;~qyYSq!tBt{Q14rw` ziGJrv1jMW7>Ev+eted8%+X18#P-WmzlWd#7R@ zsLeD{$hv;jK{B~>?(=SI^ORILjkbc}y!i-CAn}4qPqUbc!>4y+ESw7g(gu{HcsH`T+jyApK^0T)b z0e4N_-CSe`{+vyHXLcI%B&JpB!^>hUm1uX3s1ZT24BeGHBBvLB-`fRgHrzTVzTFi; z`bdwni~L32qr7le!*`Q^Jas-{(jFN<&`a|fF2+`g#%^u<8~6S8!mNO7efHO{1?Eks zD@9g(v*_lQei%LB4^1q<c zPS_=q_a-u%Ry%|mm8z$35E;d|%f5i-R$R_~w5mUy){9+X6a7%uD3Wag%c?}6^oLC6 zkGylnz7Bc=Krlv7c&UEMtk~|prwC&WDnJJ<^a-piTMwnnpYrS^$m{qcnexYw9?`NM zeaYt!hIH3-GZ1=8osF-(qMpUv*B)s5T^m!}l7U~Bo$ojMQz!o))*tH8Y93yjh~dDa z-=AOb{!Dje9CTRSZeCFzY7Tj+td%9ub19paCA&WT_gfj7V2L>m^X!4K6UU_J+uGZTs*k3)B+J}7T&%_8o-c%Qmz_vhTpTdiGaG%QfbiB3yChXEyc z5bqQYGU*q0*dIVy9A9|np832)Cj=<{BT)bMn97 zn~daGrk*91jk?mnO41SAtxbC zu3w2`v9>|jpk}1}jIe@pU3rE46KK!@n|5E|noLH3YirV|?6T=0YX*PyRnm+$&WK=t z1XHf-8_>vIl84G%8Y4{o-tyhn@HyXQehGQO!{ZaO!KodCHmzQtwicWr?psd5bJk3LX194Xa(3lpCjJ)rN^vn= z#t%(H@$1NDf7Ud5TTcOUH1~|Jbuc*X3YU@5|A|NJc~RW0qDyl9HQdV(PT|qB>#H8A z35!V@o~VzQd-b54no3ws^g)=_)?;6-o0*ZI8;k-~5d{wud_XP#(Yn}ZBDBLpi`X`0 zvA4*yf#dEQ>33NnxC#eoK~PqzEcAOlf`*>q9nhXcuxkkyn?7o%b z4kU{2eJwH39lme1-CwBZ`%g*#3TeA-NZ8M>2TWjngWgMB-Q)yjuQj0FblRUB1+X9H z5**O>(IdgVinuJhgF>s#;kZe*Ad7*i(q98y%klkRr>TB?Rzs4yV~&n2@!@Euk;c9V zv-=L}Ngc7==&9UeEujDYn-6EmTTR}w)8uu~0lOT9=|QKAi@C?l1D7u{p>NH(!_Tcz zHj(|hKeL}aNP)A4u3b5rWw|d+YN-Zl(##!JK?58Qj_>9|2WUxkKXLMeiW7Vh6*CMJ zZQBVhYxIh&zzF;IO9BmOn}D*zy#j-%f$K|cHueXV#>Vij zo37%xUq7!-vpP;A=;8SW)aQyz72awVm#+m%ZtSnt*LF@?@w2VOG5udfX;(BxhBX-9 zBsi6R6QmH8Af;v&-KMn6%?nQ_-PTWJ_-txNo=c*8QZLvid1*k!6O~nI>&emC$51+FKPBYuL)%>`~SKeH8$J2(u8we|-+J=|8oWjK2A$ ztcS%uFZKsJ_yV}$K*9+m_j5ZgSf7U&(~$szsStwcaKfbl|9w~h3i7slI%>>THy*$m zN;nrmkP%T0gYiypoUv<8$G+IZrPD@|b27r|+;E@MRn0?nuJl~D4lDfV4F29$jC(W^z;~+ng(vZX3sde z2~bRoiHTvOArmWa-kDKRQTct~8Fhqb&)tI(E@eJg8K)54?|I5)j6be_Q*bwSKnjmz z62_PrW3T2@@uz!F!iR>2n%diAGBY!qT3e&S!^6FOeIp0nGU)4DXWCVXE2Y=eOnB3h zw7B}tsgGGqs+Cm;Q|iByyc^T+bT_Uq;r!zAk`0YUi-4pQ5tQJ$%-f26%%v+upxTRiezE({!NoDNTYtOo)B$9p1Q0iF`P2gSw3lfQf^ z2@NGdL`d`=jq&jC09fzG?ky~%Y+!ux4+I5OcXoCZ1qB5Wbb$WS<18Ts1=E3nfu-ZJ zC*6pDp>dh)paR;T+zNQJcO)o&eB(x!!X!jeG8xjKr4#4%_&$VRrajPf zxm_DSt`3lnJ&(;}PLN$gJ4X^8Sb$h-*JxFhsG;xjU!ixNK~@+2^Jmn?X7`p%RA#X6 z%*|nOad9neZIj*IA4OkENlQ;nOjsTU$I6u{1Yn}di_r>u7Z;_0H#9SGT)71IIzw$P z|Kp{;!QakuG2&2Y<@veC$mpoOpPw<|(X=!*nWv82JiU55vb~K=PpYqfoKxX?$U0e% z>gZ@|d$=nnArazpe)0E0T)#QU!^_JLb7O!kFCS4jwzU3##`*EvTg=M{-Ukn!6OO_d z0C5Bpy!h1ARLRGW3r9z_2nTPkv$6p6UVZ;NKAv}R;b{q=DJd=04Giq~T2O%N_RI6o z*H7u~?M0+-UB5OlncUd;_9Zhjm^;vdv`F2_>CrI)&Nx;rDJGWR+xy%g?#cQaiTi+| z$B!TH?(FEOs#3yb^X`!L17T@tX{T?#a}aHm)YQBrSXaYr7}vqWD0fd!snYX-r_IgH z8z^^Zt#xi}EbX)CmX;R!T%gwO!NI17RK-*Aqc(4St*1|c?ct)VM7@L=Uy4M2UYc20 z0OgIG(Y1d&K6ceNG!zmRJ}hr$J3e(rjXh*xWz~hgqg0YGmvc$#a2*w{m5`Sod1&bZ zd50d`jI&d$#Adb^6+JNch|OZA;kp^kis#3zGj-a~rUM&ecYagMKBj5C0dzeh(_>~wziqabM%#CHchv~*g_?$jB$gzb=Ldd1 zB!pNV3filPe1kC;xVH6X<|6diDQ~ zfVWDdY~}{thI)EcPf`tIY~Q~93DfAhCj<%RXA^=2S^9qwgz3coh!;dkM(KX=Uz z4i8@vGqbQTtb^+!KYxbX*$JBGeA(IF{=7#9^95$L1xq{_KR&LOl9C$s=!=%ft#4_u z&&w=b!&t89D7h7TrZbLy$$T_8FpxibCfpu!RfNI#c1Yt?v|S&GHC&EXbc;umzl-&e zk&(GdYj1Ul6&k1^yBVo7tg%ihk=w9-x4ms7A|WC1LFANH;`;WG=JjeFnzBWH{= zM%p-g@3q$4bImD_>Lw66q%J#ps8~?=e&b*nuvhnN01H2vG9NS=)z0oy9YNS;8)!9KU>M;4CQQdU=sgv7oOK#iR zo!-tc?|f#nXVZJo@{pYskRwN*Tmk_)p_Kqy1`#ruGg!@rAln=zj+2T+th|PWV+_Dr ze9PhQDzBXHL$e~C`vLoNN$mxs?+QTb?lke#q>T(DbhtvG!bvJ{K>*PLNfbWi%TC(7&_a7p@C7HXWPeoCaPo0xtS8uA zo!BJ+`L}>(vpyA2ZrE(_9xj-%x=znzsU7?aWQbtnV(FM%W!Gy&eFVClZz{UgdiQ<# zU7bg0OO&NE?cpGMaK&T_pd@&QQ{g^TLwDWmT5NV-o6iA~JTp0awePz(5l9 z)7$&73Z9huV~acbt0vP__2#S{M?J4xlE}5Ax@)5r@QXMPzs64P_&TlbK*WZG%Hjgn zx8amo{eZb_kUQ@b`hw|4Hu1Q4?)X<;O)#DY(tY*7+I{nl1mxTQc%YH=CMF!T=Oocf zpbD^Z_ttb{PwP=qo}QI*11+n7m;q3uiti~V8H7A_Lq?Tgv>`uFdqIo7E&NBa_oe{g zkHChG_a7Bi0dfHI=@DxQ0RZQur1nUc@}<)@(3LL?0^KoZ*)0_U(5J2bl=ia!59#B~pO*ubmvm&EwUfpx=LJ9) zYc~oJR{Ln6*kwxf>MiPDH3TukE;zR-#tyM4a9 zyn`2xyK~RCi48w1W{q+d-{xFM!n++MvU@=t|7Mm=npU{?{8y=1wpk!L2$?;CwK@Fu z@kk91$h@~kH#dh?{6c|>B|OA~;ZLwz&5djH)BTT40(KmE>4i%E|Fue5vR=;KC3-In z&8jn0X({1hNSH8Ln1T*Z+)`O0=&i9ARbO$UAk4Uk??YmzHEV%uLELI{^!{p)ADq{z-RrTwB)I?h%f9*1)({$KGS4@E({hTib{00&TV35X zvgyVDh#eK2_DMI#TkbZq83I1=l_DS^7-h54lX_t2`dp~Q^`Wqg$b(m%HJ7sc50S?Y z;R^XTq^V1FGw)6#gdTE>Yi5>yN}O!*;6tsQ{^4;#i$-Zmow?HY#uE7)3d@|x;Qye6 zZ%`>J?v=i39jNEf!dRs;Y^HSwWvFBp6i@iH9C{RTQS9fas>~ALSXBKpOV1m;zUk2z zcj}-vtl65ycYzc&b61w1im)u#X@LB`i+A3z*HJaQ z2lj|tz{$1N7hZBNW_6?Xv?|)rk-<(OBzsFzj$crIZL@kx!aYn^ko)_U|ZEJ^Oue`_o(w^r|ZZ7$mYg)u1-_ zZ0#6L!E<-=r$t1AR$@j^dUjMv`=HKv1E%j+x>4_6VX9QFL2cK3b+DOeXC~570dj;^ zTvVPNN7nujL%pA>gi^k*%uK#Sqy`8lP9YvF|I*_ZFbC3W zGJJF<0}Y3T-Lw5X_#3CAycBt7`7@tfT;YzzOF>)3CyCp>gS-=YGE)Nbl&0Ah<1spL zmO>>N1^k=xxi)~}H+QVJJuDM|5QpFBAl!{{UNWkCOhEj+i$!Oi@iq6K#@9^rfMT9w_6s^wg8zWBT6 zm=(L8*AA9>Z7j7T3SFd1h3N5ptvfXgbCeb-4qjR3v#y(Jm)!pWB6npKJo@YiC&!3u z{o0tC{6v{BH9MI?Z_U+6NsdnSp?syfV$tvWi)}hG>$FH-EJPTvT-(tF%~2li+OJr$ z_^0d;j}`j_=pD1g@3P_);$+DYjObnEJSpRu&h58^GZyImxwgai*|-31$~k-7#X zOnIJp{FD@cnpnd=LXR0aaOmc`XR;t67c*Hyf+x_ ze=-C_d0^UBLqgd_P-L3)#c6jfu)TQPiz7c#UEt%&W+Enp7|ouHSykN{1kQS7gSYo>EqGrc7{DfcByG`(JINTgB#;?FBoG$qx&ex&cHl2{}RL9n0 zQGxl-CU$+Ag)9D9FlDnSQuA%Gv~}9T#NqE9D-#YKI!9(pSL{oMR0?IYsY+h4ZMC?9 zCPlMnO?L1+fr*bOTr0hJ1p7WFM9ok-lv#kAclV>G3RXVcAds-#&~Z|?VzJ7qPqzLV z@(a7>quJPe3(|QG|8&~HW;9FKQ(qb5(>ojX?w}DdNQ3HHA!3xl;cu9)Blt7Lv;ppJ zycd7G9W?QMy1uh5Xqe0(4)>>hpUN3o3fqrR-gV?vevs)Z^?tPfw6552HUr&Suz2&n zgXC~edu&tn^x}RLx2sghxg z!H(ghYi_GEtlQsxLK}fA2YFKowkFcWo!!UUyY9GFj4JGHV4cHQbd>2#7oRr8ME`B>KPiEs3VwWD?x%M^i%u;kWl~e)yix9wh9Wi?fe{(}D~H zXgyl?ZAAP6Jmnci1$wSDE%<-W=thVsO_tyHdmXzyo~#@=NI(_#cesbp|F& z8%seN?SoCpEzNY_- zU2EWt$~y*o&zM{pHTu;I6~S4QyOVCciF~F!Qy25H>0K*oRFr6e5!eR~;{^PkJbz=V zZGER?D5nJmJHH;oq`CDG<*e8WhnSP0~cu5 zCUsR@D}&YqFLulT^PkcwTn=bL?&?SDc6d9d2+adhbqW)qIz%R1=j2lQ&jwu;2Ub*- zv5aS{Csh-S93fKuz&J)gJKl@>Q5vmy7km88ljy3WD{FPl($Wx#o~_S`Hjwq=Kuj6` zW4u^JN~;mP{~=`k-ho&Li_z+1(97Fu$lL2j6S8luk&SHec@p)x$=d?no%8&NV?`6{ z=nqxqBVdJN27~YqhS#{bmU!M5o+@EsYgsQVpa3Qr{&#cC{O=ZQ;AULg7Q9*I+a6r$}2(Gi16?<)DoTn_IA$7>abHclsLrMa18X9sMW(#J*dKiQhay3OX6km*~FMd z0A+qggf3eXD)*SN=nF?KOXW;?oSK|eiNfAna2V&Bv($=GlVH!_kS8E$RXq(3d`kR$ z)m1H(e1)F0J^B8rIzDSZqia($tQ&?}rKQbVD@4oYwOsOnA7!^OEUn8me7X3+Y^Go) zvpQ`~;$gyf7S3@>2+gf^18}gHAJDevXpI;A-nFGwyz6tfq8^+!v+?s$B#)JNiPx!D zU&&Q{r7FkK@v6TnLG!wIeASDkd8Ku~j`&Qm&5M{OCCzS9WuYs@)9Zineor<0`+Wy^J*p_~ zUG(wZGc5B`t6-`f`(f+`zZ1tnSA7(h_`Ha81(q!!I=Fieqwpy82@!dPM^1XjlbVkT zbk#3L!857@Er$mGJI6N(AK)wUdgR5)XB2!<9Ma6D#D{uF6T`i}SyffWy95ULBm*_A ze%v%`RszoJ0|pJNrKG!yfkvzj}W)TLBdt&DmC>gp18(z18)!r8y>K2@rA^P9wwSs@5A z@IH0peS{aBb@}V1JO`7n!#?gXDjOL2fVW;nzCbs>M%)aoGu~U+q zfJM3Ir`BMp&t0?1!%D}mXvHIPJC=UKYV=I1i3%7Z4tZq_S=%%Yx!AB>dO&b6%5wv0 z(TWdPF<;=Tdn~OY=b3&EUeT+r-irxwR>6fp_d4Tqa5SC2eAi5n7kn-d$hMHGVxIpD!E18XL*4$OBZ$_|n-P9fd)Y9VJhIvjMw0D*Zq=-%X~5uD2+Q<2Fa(g=-hn zFjv_Pb;7mn)f`JZ6HDGcFL#iy!JNF|PNhIeoc`QNLi>G&8oR85tC&|`USyxuM3tmj z2NQFMYt25MPIx$Ut3H1Rje0N1qEmmu3)_5Oq8%$C^^Ugt*!Nvf`T#I&kNi99P5 zEh9urmWUdwaL9>S_@$bYP#m02_=mvNH_VHN27>>q*f&u$OWxso!RG|}s&`YcbF5W> zk}aIBLotRrPbHDnq15H=oAY~#cLn;D)@`ch?ss1^3S*(vu@&&^W%38mW5a5l?`Wn~ z<+UL=a}XyynfwkVIPyRC0P*E|?r0Y9p+d7eHNS0ucT_ z+Jf(QGte4z>s8dm9+zNdP%r<%$zM01ks7W^YDEuR1$-fxp2nxfE#8$b6h6>>i0CV= zS+>Q{izkF!-s?^ndO|LZ6M=tySJKz{Ha>T3r6JgDOxaA6YjGr)Q!8FyCMVpW@uo~> z+6Cz?ZCY!}?JMx@GTo8Su9(Hv!0YxQQdBIG=}cx*Y-X)3Z4uKMZ5I_YdF}YAu}k%1zm9ex*75gX7hC&edkyJv#9bJJFJ3w}OvAYsuMyN3`Pq z7ghbQi*;i7K#&ZG_9I*;pYI`n6A<-u^%@hK_nir|C_H;o-VbX|GU@1YK_x(~_H_td zQynka(b}1X8DNmCB z&`7JeNx{Uz*50i$&2BGTd2`+J=694D~cQC>!J5?zBLzOi>RqAM-%!uEW z)D9N=o^d47aVqrjJU0~!C&Pp24^TLR@*9Zrn^^pD{Ae`s)arl2-jVd`t8CJmrUBY7 zu^w!T;`;0sb#4nI!P*sBg@}Jm{ex?Izz&0%@7bc^^Qn?eW!nFI8y=SIS|oG92$p+# zuYvDYw}9VoFYwS0Bq;2K8?a@^0lJpPMS8fys+QT4nT2#DaPI^uS-eyt5%AzWZW_d? z=lN$(MbmJ)9Fk~uuF z(~V!1PtEJ7VqUp4|HMCnIEoFm4NA5Q&C4Q52N>(v0leJLVMj+*s!5P}dajJZ?cfu0 zk-i{ua!4q1c;jy!2$yT6e>a0PA7GoLL~7rrc{khX+^gmh2|>6IIn{M7Sg_DVfeN&C zGMr6M_(EL z5X#Hl5Wur!7&;|7lHF)Um580>686|Hoyko0s&+av)%{Tq|~#(^`^7pkPDFjsdgs^A1YF+ z(ui>mr{nvzpj-_HCc?(;=o|~^#X}U#&pA} zG3#0MP-sb?dTn1`vi|0pNxzE3R?EV!=^Ld5+p`XRMAqTBE9z;`mR$w6!w2Xr2@(MB zTbEL$+OGcm3Gl@IiB_AyUu8nqv;+T9@UlBz93;_ikQL;1=o`GT;5d}vmRy-tjAFNj z6X%1ogie9l6ITW57X=uA?o@TO>W+O9??w!iDph%5(`bO%iIq;Alm}l)AnE1f4p&+% z+upWX$ZFV)w4wgj1Yirz9b?{k8^PBC5(ES)D($@2b>-IyqCv;-Zd&&rc9ByGnm#q1 z5;SA#@a1ceMbVAri>y31)q74x-) z9+T~O@q!yxJgB@o-O}-z3-3@jG9b^g}R)LTl3o7k_XrTAiyY?kB7Z*Kv8_XrX z{t_wtoY&!zN_PO4WI?XOq7@t9R>y~rP2~&|#_)hE<3_pB-dkOdO9`3oQzN9qv-YIu z4Ty9C54bm`eHT3(EFjwCr-@YzryGq5jO>i`FSryf@%r7^(5td8Egj7>y!&a{^#6(2 zi0}`_|28z%1=?sOI%Ln`8S|^cYC>9m4Ef}=sr61%lZggpQL5dZNiz|roC`E=*D-CYL4 zI&oNQSESrO{$Vd--*%mctY^kX4tFe@=lhtT&E`Bghp}wtPaeBkKoe}#=*bTgb-U4- zuwDlYA#UauB&;sM=gn74_w#gcDHqZrIiN{fN!l}(Lg(+VSNxO*p`8LqUA?;wp-7b8 ziyScWP^lV=?NO{aDA>)~n~$k(`KcAjmlyww(O_RPb6SxBB>5Q?wEn#UZF^eNHWWiX z&)@OBekyoIwb9rMb&=oVr=WFAD>8F$FdC?EV)YLndGw*)-K|``rw(dV7U9o=;Tm+* zECc0DOsYo2!oDX|X{9hF4}13$6Q1`~KFarqa}I}65_%|8J-FuPH7NNEw9zWbXMeE4 zxE5wn&7k+Ue}`FgjtLK zkN!Yb2fX|5894WB#D;%$`Y0Qxvi#vc)3GbzG&!wRkn*=O(D>qK#L-;VUXTk;wET;Y ze}$F~(o!~*K8+xXD6?C~$72P741-RviyC z1S($3lW;-;l)BA6X61*-Diqhl20{_RrdZ zJEuDHQf1=|max#cX*<{zxV+M@ZF^W`N`5BTDai%$kAsQ@Jx<%fVgJU}<>%kxy`Bhs z4b=Z#!<#AsKt4Ra`tJ18XK3wTTQB|wlXAEj`*lZ3D{=#z4s zunigZbqnh9tg1;|IjlvL1{16_ZUHu8w%nEjX6WA%J!HIOaYT3pmSn z@($y5`|w{Ye&E`ROi_qlPMg}n#x|0;qxkD_$NkQ=!*%(+4I1EVc^mOWP3p?fRTc?y zy(lEc{|7XmmyljZ`ILBV0isW<6S!C2dK;y6M&<_I?m?&UjoV%>mnuct#kwfOc-NJ+ zZZlhkJLPaGLYyfvz8#vFzTM#sQUOS4lX=i{3Y1@UoPl^&nKl<*4?Ksa z2(7n2mdn#PEFwvi{}HE1J=lV(=K+} z1st=Y%Wc#DJns`{pi;(zb^*>^)H0f?M+gxAL)(z21ii1)t7&&l1LiRni|ByNP61l1 zVJFNvW3uT3-&g}e%pQd>zA$EI4iDXqbC$bNam$gMw!PegAmzvKJB(9%?x=~Aah?^^ zw7UhmFu+GzS^dS02w8w{)Gw&AclvTNN5mC8b?5En2R>*|36$%J+%v88u6u)}`;qDx z(m(I53iVr)^^+7GRK1@KO>Dxnf1Y&51jaW=bmVDTe3m5#mm%Y9a7&6Kv=CwaW)kwI z>(>!h&+M-Lxp#Rl7Qofv)t|+mbYX3;C36vS7X1p5JkEzG1_v9`-l@=;_p)}CTIzsv zZc|a&H#o%aDoA1s=p^03_?Bl6D}uHgc+Aa1-2YJH)-IN!W_^vMZuhq^xlI`Xl)dJQ ziF#)h47j~d^xyo_&uq|Cd2PGz9SPQVEAl>ed{h*{quSomc3(7qBY(TDJ&!6h$q&0=R4h_i(*APcQu{w?B1~os?N8nv&FB#ZcvI!@gpHqpM>sq8*&t=9!lst~Q?COR zj3NruLsPoo5rUti=X5HDF%4+vu}nw!Y!OW7TFNhfZ=K?|p#S&?Fm@O}84)g_>%q3v z*|TEPS5-#UuHScmd5}e-&X7 zZvF5f7puKqA{d%{{(0g#BO{~!LfV4QBwD@rQgzthapq?xej}Uv82$GQ{ThdD8lJmJ z!|e4RiZU6?HKu!Fn}f-xqGAb$3a|QVs-9P$nxb{x#a^M3#c!XOCXYz8n3$HWZ*G>C zeewQGejI{=ZC}2zvyE@LP#E41+<9)go*M8hUdYhN^yRS3nTl5D0R`!k0VUV;K)Qd$ zKIQfe4_kg1aiK8~2}>Q!w#(uz%^O=phoDAMP4V49bN}HuhlbK!`x{yF{72N`Wn7Q` z-|kQR=jP_cySuy166=djE(Z9^`MQLJ?H#jMd)TSnlap6;`)R?_Wug6nM}~K)NS~mg zL3K^-PKoKg;m03F8raxGcF)hrvIj6PNED+ev%gbrvk= z%^m)jfW5%I7oHU2O^~e+rIy8$UVLXT)~G}sw-9J`sq&)zH}C0)qEdoq;L5h#tC_}E zCb~YH1wY+MR@Zau_5Zn8q4o&nc-3urw?lFHtYgEy^A*caBV5?OF3D=Bzj%xP9-7MK z7}iByn)~id!}XHdN~?Zt2rv3=zbTiUhLL4OX0z)Yw}?l-oXJBmCtJM!C-Yiw73YJ+ zIB%xJOdPbJ39_uhTN6^KZMz=XxrnNPKowuqRQ4A)!82of`#h5EZbhC}^y`@_`^)mt z0^PFKR%>Z#>6C!iZlfI^1bNYZ(h$_;1<#=R$yVrBjR#MDj>cR+ zNf((Ot8*CkP_`L=ZalG(x%7QN)cpClS+i6a!QjGY* zcIjp4#bo2&CZ~XUamRZclCrutCZPqfrZR#X|j8){0pSklKn5G`qB^$iMA5sWu@ z_;9k;#rOofVD@u`;r0S^9*egIXM2j*7SSO;_F~5synqhTDmGSf%Vw=QDXEKkGP&H%Z|(`zgJ? zp*fC@j+~hr6s;|Bao5*DV=r4B7eT%+=Z(A=ySlsY&zu$H=aU?*d(u0$(qxR#d*j6k z2fQpSEcWybSN@8@m!Z|NG{Fo_*s2hcnLDyRmht`F(?4zr^@FpH3}F|#nZJH|AiaOJ z>b4ta(~FbLvd5#2_7soBi$a28|1&=bA5WTs&fk*ey-_Ti)KrB{ z%kgOg(uU-0{vR4Ui`nh}9{jfqZO>X1Ux%qKWVdaghIA5RH{H_g3zblYbQI}4)<_kBUC7IOX zGeSvn0*F2v3`+eIZbq>5C%=0*{37uXrce^}y*;L=^=fp(mlX@t|h+8elqBowK zLh1c+$>|=tvfgc4b3!w8>bu*uJmug^|2qeS$J*y4AA7gqulJwVxh6e`V~6mPb<^|} zG(j=1QQ4|WZ&wj5Aqc}h2R#=g!EfUagr4Pa5bmnp)a!aZ`Tao(A2%26d(Q~OEcFpyDuqDwal)$2!s*v zIC(*t>F3aO9%p|{sJC+14LQ%nauQRYI_7&=P%rvfrR_(;e#Z0D^{v|p=w-Y%|34^o zIaLrH`VDETR{#mjbcT9Q23!`BeZ6Z>{?l={sv`V!uBV~XjpSq;JdF*bpsAu*{t&nu zB}=U0cLZkcpDeWa(O3tPUW<)>)F&V!5!J88g@bx&gAydrz@W#ZhKp=^EqXS|31#%T z(Qt;m6gkoBs6E)}Bbxm2A!##j_SybCTkqyVm5PXp{IAg+YYWs^9vi!N*zb6UIMQHt zFThj}@~wC5+jHV4-dEj~!FeCeZ@+MfY|q-@h7$t#!FT(QKt-6HrYaVAkQm@4eI_q9vPwk!ErR zar>=r4B3^3mqVt_=}t;CJMS0ei6PR#s-FG&{kCDjwszFu$>dVb6k|`&Byb7Xd2v~l zz>gSxsr^A5iwJAWYS_&A6cU?G)3j%9Vn5PjE|r!&YA1YUI;ZS@SvgI=o4!%>@LTZ# zH|))RpdQWIPnf9sy97aR><&5A|H?>++%D1H>WCfnJKj*ez$uOwz=4J${d_rBB^FE%blKM((K{snMr@h@pf0FhMoqeA%Xp^)eB@Y?P@G_VIul!*T13SCh>B)j*1vcC7!pa_cyc z>U%!H{gG-BxBk7avgZ6+z$FX686JBIw7eVJ<0zN%*pVz{b$7Ijsz5Habs*rCik6vH z;@glwpymOiKqk31AJq8{-^e~sfCvx0_)z3cyEBt4ctlaVoI?wmM1YWmqoP zmB%vj4we*5+BWvLDaP%p4#tiDG#~SF=Z8pC!Ks&5AKG1*E+9jYzfFTlzZ5?*c>`Pf zY+*YR52#By5a7=U% zH=7G3%Z;`GEvOofgC&le(=U(Qgv>)>*>7+uOMw(F*SrqUsU?km*R(xK4 zl5qDi)pNVLvGe&&b?Z(hGa%!^7j*m;I6wD8GW|S3cl9rS(Ozcb8-9I@z~;xnVK*%x zu$+LTWK$V8d>giC*dE&|lzdbt%Ts^6?* zgnhQD(n{c2>>`ekbQ$Gi(DO^Cji{6!kBJEQgPXs60XlUtjgh-RQN)9NO_RJfQWR&p z@hedKW|;MZRfyid06s|MyC*}bH2|$bSBJ|Unjvc-R>g`^`;2c!V}w&(yRW18;$)l6 zBr&vH>u$%XcInx}$_FjI3B1LIV=j^WBCjG2ydnYD2mSQiBSRxX!*d)0DK)yd#>mgh zC_co-9^B}O-d(^1RuT1t;3eUIAcPmM%Gjk=6v+Y7X;U0*m*b!sJ}q5{4*k1yjQOx^z; zfibRDyUX7_83eS?7y_%&?1X+e~KJy8)IdfdeiO%doDF{~9ER^EM_* z&H9YQ?208E_BAoBJ@f_0qq(XX!Ja~2`3Rt#dO<|CtkR&LbQc-kz%kgs31h8P7sQRq z4Obi?UJt>(=&fhU#>B>dh58hn2kq_!muk`7I)2Q^3oUNve@LERF zeLi7BG(sl;dQ$6+j$+5$=D`FJ9+V_L!=|mYmko1IM{NoG%QVEN{C3gv!}Tmy@joYlvqh#r7uyRhb2-Hp!1uL~1wI?7#6EAWPqwtonX~{L>_C*SC{?7$YrfcQCE`8C{Qu-a0PFxp zGTJwNP8Y>-PXO<4Y2PlCJ$kUu_x+kFZw9}~UCA*ckp92&72$6E1o%e8*}q^T8-VW) z<11nvt(a+$y%s+?u!vns`CEWg>l1ArjP(M6WUA{gZBCgRH9}Dm#1D8AnTV!?RuciJn#S$=u>>4nc$t&X<~|7n)|mWs=2yeNB!FIUy( z?iqwk0$j@PQ?g!)zR1aZ628%q`7xm>ELXdwTy@c>su~FH#J{{Ozu)yy!Nascz5zh|B0l79lHZHs#);f6LmY)t?*mu^cn{TijO%6 zCOc9;%R>X{6?1P>8Cdf+oJ-yP#PzfG)yvE8$MqSb_k`g$b|5DJ1VB79Z~0s9vd1TY zft)1Yx`5M|e0Zbfc-|EE$$1v!x$&%Tc7Kn2*B$LAJ>carHnh>j`kXtlr|Q4QJ`}5~ z`HcP>%c?}d6J6)CU{q0^TQ7$&_AnbEHkygs#KUr)nU%b=L$7O`m&{n)XoJy1bf|(U zS%PuBg2GJw`7;w{!NTI&qwQ|Yb{RhBb3#Ryvft`FejMlXuUFQ!st7sBF%J6XMoXpc zw@QV8?1eJVGZ25PUhw;O>Sc9;j|+Fg+2x?uqbDM@g$=?HwERLd_8xk}i4J-OkLX@S zD-31VnoNM35^ZoP-f4_8Mlat$$GA5en1l7|v}Ovwi)mfl=6Ad11lt?>O3i#Ty|Y5n z3Q+;>(CD90>*D~<#2&xN1lRC~RHJ{sS`nJWAuj&CNky=k71d|y4G6Wl{K`<|%MLs< z(SWQyI(Q6tcT@oaO-O&!vw5Nfvd=GXWc5&|6&GguyPt8O{wsR_n^Mvimy>bV&`Hfv zC_t+3{WMpbY9I}G&6qi)qF~|FQRJ$9@5-9JOWw2_#NoU}X&qSMNe+VsC(oUd4Ys&< z1iEF+d%fFHPtHUyO$8wz<9yt!&HJJ@6eKjeesiI}g3r~md)nbQa9sQ0xd%9+I1o;g5CXuqs zakVa@gJ&SPtwht|vvEY7XS0e9oXT15d zd+JUtDvnk0;%g;V%8h!f_bK6|LokH=axFpn54Z9=!l}oi1MBaCw1mrzSPZcp`|YIa`gnlUWnbo z*3&3c6v4RrnQBx+YwEM-ufCC9h*>mFaZ*Hei-5o1z)q8432IC zv_G8t>c#+dh7$~E`<|2(7G8f#8C|0AEBpsfiOFcXUz3U`^`VcY#H#rKj-+f2^q)MA zUCoI}`>e)dd?$#nBFp<#tKSA~N7j8xvv`i6#(FJhDq#;MlfMn<0e{%vqk{%Kao{4R zRyf#-A?IFH5e18G-eMgg2E;qiYku^_eYY=xoLrII6KQ+WdDpWz9{)DTexi7#%u$WE zI1Zm2BGfz1W8v<72~HnCzHYH54B zJ5M7&)XJ}>bVa!t zx*Uyah2o!aIukOElD7(z3TJb7-aINe^7K&HgU1~DeKi-S2Uf6}^y6#ZpS&Jmbt_wc zPkCg`yFEAG@Y7>B&#gkudC101qdUk--V96vL{Jb~7vYk}yd|s8LV|88H7S*Q*rnWO z8<`B*zB6pI@{E)H3q9_|6jH92(sh$$nBnV;@hj03I;m#`=II5rUjtRYvFREh2%IV_ zI1EETL)%Yjv~Mp;@o*>$K~hshzL^s3UP{K#c=@X+ynM@Ltr27Q=nJ#=FZ;)(E>|D( zD)x4sTB1k0PoVDfEQ42H>IGAf?h{=mL|(d3rfr6&MW%}fv4ITkc|bCIB4$VEqOvko zCVnXW_^SV4+~G~0Qa`lE{|2$^@+ruTG3F@xV|)SrI5xeubxci`^#obwd8INm!&+mS zmppseN@j{}$7B7^mZDcSi*p!GS3eo|knF3O6V!?RD*L}Eyh*Jvk$dP%4!^-W4P8%+ zRavlx=)sYbhWC=K`yD2GyA5a_srEAm6_Nr2m5IWIi28?* z>i%*MxPnYt2rr+hg?(9E>FFU!!N;wH;J5#%A(r;)8y1;p)GkdnXsT)tns~bwx2Jw? zXkk1eU!P0Z#cSmRi=QGf*cZC(#|~Wh!JOVz#;07L-sVkkA^*H6h`qrbt%iTpx;>4& zeiAC~R)LgcxczHDTK(!(iKiy$)$gW&zYBD0NFp~b!>)TtsvWpfg~^HSw7o3LE%8>l za8W0-JcM5iG_*XCQ~a)&tSGA}=W_CO@z4E1?ySt_4q=%8Ss-EI`#^XY4N59NWwio` z{qW?t$I`q9cI0tmWHiJAKbIKP>Qc<(gHPJ}#JJp1>OwWy0j7{&&5fFb=iM zXyY4CR&#On#M2Uh1V)MW$oHysZn;~?IEqWj57pFvQSZBIL3X~S)PICzBpE4R%aKff z`?9{Hz|d;i^9H-{eCElD5_u3ewV5eVz@0wqnOo3^;nAIPmVK~xy5hycSKb!1220|H zFs-dmt8ME_(7o>w-{~HaKb=S3e1NnhDAhCe>9{|u{Xa~-cQ{*N|34lSMU5J*J*sw5 zRU`IjYZJTnDvFw^*sCa2t467 zg|!_vC#IVarn_<~e@g%`a!v#eNfTQ+6bv+qCpsNIYHAwwL`x7< z>;f3za%$9!o94f)bbOWV3avTyzx!6uU4$&Ks*&es&{h)BH`433X7w$Vfh-?U7tKk7 z$~(`hN9gqA#7H640!Ef#SMh5pkKKGJx(&12oSY0f1YMH-T;v_Qk!-u+Z@O-p_(2+v zf82c*yS2w19upw6(fFZ$J?^)|`XnAF;@Pf={rfAW@o0>z*J4wo@NdB;KrGY}Ds7!3 zEl#-fvcdDpjlewk%v1b6vHJ0k&`7~8zfcGEZO9&bxO&w}!GV7XR5i^0#&s(l91r`_ z#7U44M>c}aR?+zC{`2AXBcjmtl;1@gSt@nMQz|?T+LyI@$bET1>b)&>d=b{`DgPgw zwgW8@4-Vikgt>Mrom|4zm)*K^Sgda-Z6harDGbs@lEuX_{8Y( z!porjI(Wm~Ih(Lf=UnG>l-Aa%M#v>&^GaalDmxG8*WrKnkUQvfyt>iCoqw7Ub+ZUd zEbqrL_XHm-)yMp`nQ)s{C;up26V5gw(gr%Ogj`U5>b^B7Rsz~3qBRmLqE>v=M#-*C zNoz&XxR;zR)SWK9U8a~AnIHHB-`4~xSAAX6WmxtMF;T>?Z2udhOZqNq#gz^UkRe?P z$xz_GA2gbC*NXH`Y)uGu;IK#yo>Lnlp?fvO(anb3b{tDp82CoXVn2WBoBs2ak^J;i zBT;TDV4w5Aj6FNQ({-3LQDH1G2ksnRIfm^C!-jCHC|}~{JZrPY(RNlb3&QNMmlx!u z7+zW4a^ld2tJ?0^HpkS+UlWI?(&vgm2L~sF3n!pInnsBez~_1OwqNUVa$Ce#O^_~t zMmngnhj6Arj_-rj1wHMk$3-Mb6)Jg2q9;eb>#sFg-9egXhRl~XOSoxRsY3G@lmLYTr-c1R{oSadbkYI^iF@@GW|C0WT#K=au4&)TS<1NkBu$>|Ps{ zK-oC91mcck=2za=$Cj++mg30Or1?vw5(s;00*lmw8KwDC3=atAY-OEU4LaajYLMS_Z^Df>wO&u!nDUi1O#^9lt=*t-7Vgm{;hi5B;>Rg zhU-g&D&e%_1hOOt)4-S~$7#3giC>1(bZcEzKu`d}ir~ZTI%5 ztHcH-`p*v;B?_gT6K*I}?{P!ld_R*q-8DQ70s@Ld)a-if9Z>QHSZxIcpye>Dpamn; zzpEI#RG<6x*45grzg3zV$00V6BN^6#0>oqm`uefq+eSi%sahhfQSYcZ@0L<%dn;^_ z^>d<2Q3MCjUW_?&+4mJv^QhBfE2w)2G<&L1%har-x-xHz_m z0*Iex`t1rF$23Tr>ZVgtD{#`ke9HlR@Z-)|X$1M}2io@}hWapby4v!u(5@BKCb?-{ z9vr2?>l@*k+QFzGaDjpN=4@;N3qkfgW;=V+(?vfc_{p9}y98Ch_Rc)`=&MoJHVQh# zan1ky<6jrb@`LNJbqryjMSwS9jh z;-VRR>iOMJ|K=8#ABi8+bm>$+7%i{5%CiKrO6KI#8YY;Gbui-R9(U&oKSnGFj!abT zFN9Wp5%ao)#6IcmSRA8%_>d>M$dU@OvghDN20IZe_Lb;b%xv*H6wc{0Qk|By=mgKd zjLsl5@liLSfZ}~~^!NP6Ta~Gjb}u{B4xSNkT^WtFBDRTQ>mXH;IyW%u*e8wx#`Bwp zblsVWcgP-LVtpyppWd-c**W2uyLu#&=aY!7AM;Te(=YjU(dimvPwEeik~0kd%nA}l z)n|SsZP5l4M~Arfsa37E1TPRzbQ(4rb(!R!n#s>5fu($_SrmP#(#aolUuAa)?h5zH zz>7la z2Yxz|1@4cnotWo*Y|MZ*QE<9bh_P-HJY|4`1@i9_c8V6wUmuYa4SaIygb~T zLaVg)kO31R;jm;&?p)=I`U6I8IUKw$NI~LWPIU5Ra#f{waMQw@p%!2LE}rFZXWRy) z5HXN5Tec|<`NhV@DV#9pcsftdTln$<}YL8IUd8?PV4^bhDCwgx_;&VJ3u z`{zeM@*&wbhBcbJk&`FoECT9K&FON>5_T2=exqrwq!i5dcrHcp=59t7xrFU|hxN9- z8Y2HDivolH&ipQ(8T&cAh2;MG=kJF*7YmeCZ1rFF9d5uo0}4{g9Rlx>GXf2x==T(z zAvNq1qP6AE?P1v-X{yh4)0%v~OAnh7rr^({{<&S4Eg-PzHdl4}=!_R(_dqUkr0N?7e$Uw4Rd{s0h8n`^ zchU2;s}+{QT-48Vo}Qk+t#POX4;j2WbSt%?#Wmg3ZhUt^5{O%1J%X-X|8&aH&$(>C z2yceapAc>edMeW1!-gt6TM^GN2Z6ci?l+e%hiy7|(+G_i+eAD_3QfYW zpCb7|arGP`VY<4!L)#~9Py{rlJH>LS*Fe_D1?V;-v+ zLaeiu0JeW4d4FUE23SnGwYwaw-@hbV8ytHXC2ZdG=8F|?`6~MIo0$@iUk>=?7ru&u z25y`0eu<8W6}OCzgZYdUFLj^4V!a%d-U2q5u^Ut+O58E>AO-I%C+`tY=;835G|+-TNunN%Lj&$My)rDaWxc)Qw!ih--}I9R^bo)37KYiP0c zErjJ;TAonPB7tCru6%~Q@R+wke&R)&M6F76<88#}S&TwEB^dWkP^=Pp+Hr6`|Cbt6 z8-7oCTHQsSV)4a~9^Ni+@MV?D+D@)4gy_je7E{KvH|M6U#rAW$Rws4oCJRk?=agQW zd$U4jPoa=gppdS1yBHw7_=SERU0x(}nnrk3905PbrjiRLy{ydq_&FPEMS^tNNe*XE zlJ}oD$6@{KX44{89`yw>(K7+Hrzcsxa7$>tPQmwba)$OG0vcqAx51=WDN+_oz!f5v zM}Mqk^i_6is+56Yz-k?@tp=Tf~Y9DfH@q1^Ds? zJe%_JSCMH2%;~}iF47+od;%r2O}^=OiHzCuH63X6%dlFH{vbZ%S>2u!{#IZ>pqBcMR=S)-uuF8) zsGQ8GJB<|zs5vfz&VhUUAXzcfT?tG+`~-pvLJ^w(0e)Q;#kC0tU(jnJhz>i|>;nrM zl@jCFPUnkO@M!GPiU_{1hdzyi{7Zs0q3 zGdcNDPH(GmwB`-FKOt+l0BvK^FZWlW)y+)v(+k(BvIj8P8zV9d5VKd4kPu1r)$40V zTwZSArth>(yXRuXtZw^C5W0IMf@qeffH1lE(tHd^7#nV$CO~Gig(k=H@qJ`frwGLP zg>f(}DehwyEv+`MJ35jheRliYw88+#rRbH}PMDdJW1mOwMwP~DBJ!T%Hq)Q3hMFjz zB?#Sg1|IF$UEX3HW&NJhn&Q)pE{Z0)5Blwoe5R53+D>j?PA6Ga`|UW3*nFqymXd}p zy4!^^BI|jA%v*F4(MQ_8x&`TlgG2=D@d2UHs2;k*D~^a7LRofk zE4rIjlL>4=DHU(A>UOHwsi!Pdua)u9k=^6f^XCBMU z2GGHDpOHaw&z2P1WxnD zD{1_Nyq6*=CJu4@h;7`=bc_gk3wuRjEf&+uz!=oBg>A;j2 zB0_o|fl;&XMI;=&Wzl_m?!22$kiUk-pvEOJY+yx^&U=9XT2%E^Mfh-(;aGn0uJ7FY zpGINUCls!ce_9PmjIxNtkJ0sw<8~WLTkhzHxIVOoodGp;Q27@0>P`R1;a{sU%VxFK{?tgiXz~X zL55fir@cy<^sxlz6esH%^R~+HQIOUpb4jpqD@D+7+r~b&$%bmzjhJv4j3>^f2~?3O zT1qlOGes|6jM^9^Pd~BCmOhO}thcOKmKhj^$33ZHkmjsnB2IAo{yaj{cTq*#Y%iP) zZmaO(u~4oj)pWWLZwCx-cQ@{hpH>?#W*$z1G`l{2{$pch!{43d)okqu`Uw>-8Prtb zww_Z>1_fn@ll3@}U7)MEdU;Zl^zJY|n$BEWYQ{r4A)x}IhQ@lKnv7+OCMie$BhEO|>4kI&L<6j#sCoZ~nTSAEy z=wGzNFMRxO`a|~Nf$Rj>K2EB}Dt@_IL_0t$`syp_Q_RM7?}`;Bkic-f)%EhZd(4$< zC{=p%9gw$TnrXpO%_7J5A?(W^J|F(#j#Ch*z9nc(rT;imwc)dBQ|Rr2JFH$=i(~mY6Bied ztjLFu9C8QanJxrREdwG~^)p@T?=!>6v$RT8_D_#IiAZ&_w`7^2(xm~KL+#}h$AK@| zCn=VaW1`~t6WoLVf)cfcp&qD}&T=K`)hLn0itsq!0T(_~Qht4E=)<3xDPQMUBKO{e z@cGh|*@li~-#ymyxUYE1GvyaH)NUAd&|LjjGsI7iSIt@I#r3O%b`1X~XtHGab@0+Q z_2@S@1^LLP(qtPY<-BiJv;n)xiaOcUiPPGI)KAXeye2S&=-M&t@f*zo1U*#>pOh&V ztoyHgn^5_rkLc6k9x%OZ07H@x0`#Ij4N%;wvv4B1GZ2X$Ec~7TNXPe;9{9ho^cmtQ zP`C8|9o_9yjXso32LtYSCza78x)Y|Glc(cZV72o;dY?z-W)Jf`@49~4nF>JW!XuP* z3<=Z!`-V2T6+9_Cw;{fjiQW>8AY@qU?l_cpdGO~hslutPrY2&6PvH8Ge#&yCjY9e` ziZ0(YWfE1VR@Jt>+Xgh6&fu%_(*_zHZ~k5T5D1=$EqZkdzuvts)=!f3CiIkB*2e#_ zSFu<@N@JzsMdrz>P0DD#R}a}J?so7!;ZZD{Bdh}_aLqd`6+QFT2(#R(w-(O;3S$+I&qF6_qGzJ^~T< zlop@5be6F4i#`gWrTIX%3=gb*PWAbuEay|q%;bwKDSR#9QSi5#>@3{&UwLY81VPIT z#?__7yg!Nn0oiA^T3ja5)T_ewnHLtU}5d*mK1Ytk$FJ; zX!_nQSHe_xWlBs}Xd6aax4ciX^?F~PoY$eLSDvR}4n{>R$l8MrA6|U&@^R~)2iI@8 zOisn&Inw4}k5Herk-UVU?G@Ib{iWvRu#<8jpc9@S6k+O;BV#B?Vd1L)*|OI1 zQOYZzJn87UW#4-_uiXmrx?!uc!5Qm-?cMw|@}s#-$KWwxk68~EFqcKxj{G8X4~98q z|A!mR8;Z4Bgzn?6K$R#Gx+eE}+mt%dU3r^!*5w&a_sUy>i33+0Se(@+4QI0zG3sy7cD)4K>{9T^tN$Up*kI}d1(j|v`0#jpwhK|=_g zUFM+;0iMmyL4*dE2|x9yo-bpA6H)q=gPgTAkLMSzvMJ_R2Pc|}$IEr$Is}3# zn-+9<@@|R4C*cpS!nks&`7k%jZPi(0*@zm7=O-s6=E8il+Gl5DL2m~rG~LfSGn!Es zMB|&T!YEH+{4hjzoE-izJjzl4r>~SMgki#$zd6|6KJq>L`RTX(;|H^B%t`UNU$rR; z2#o-=xTg*iyhzX&3qTqyuZxo>+EY4)++v|q?F#Y5^RyNq1j~|<>Joe9{|BdbiDFWD zca1XB>Y0x}8lOl#h0)%76n%9WR-f@+CRDoamY^r$+qe9nqhR_Tp>jPD*wyhj0fL6V zY@wis3CyirhOqumLj!KH2!`od1E_ zIzRxBId0|w+D*CJ?|El8^B+&oDDCNy1#5HVP;$I*%y=KViQa!1Khrt}sWOlQJO@GTlEbf0wAk-23@2i6U68hY<%sSfibqC#?4FvpMSjObaoNMn(dMjm$U=*K zc3G#tzgfo%ltXg`uO0IlZwh~!%ARkL7ZPSpxs}q`LNI)(Fck&zEjO7|;LmbLeml#L zmXyV#v$u_)Tu`$3d~VB@h6Zc1IkuI%a7y5ls2c3@E(iEfNA*qtkQyH5f7QDzJz#QiLS%7frk5)aA^2aAiK+b2n92oDdh2o-M9X*i_ zMQ9y=eBi;f__1WSiDqk<6%KiR{3kV=q<8ZA>6^L2OQOR-E5h{V_v!erPd;~VqVf10 z5-+b5-V^qiCvYEOHAI8UR4~=B*9)I`pK$;`WIR$hM>K#c!6>hYghm57?aJ{;gZzH0 z$?@62R}2#=&EK^p^XoaO@erzlQe?M!0X%d6l=RCk0Yi8k(a05x;@|GNv4_oABQC8o zCSt9cLzgD-FSIOnzdriiNQ7o6J#E|-lNf2wPZi1Qg z8zR-2d?a#5e9d8*6*6y^bFs}{@Rtc*bWzq<5Ly8=oxwzi5ye7$rS2Gg2S<&IJI}tg ziv29`roj}oa+HUS+$EZZcHy2B*zGSE+h5Z>iUwjoL7%xR8}^UE?g2Vu%9KE}uR| zuSW**P{}>m_Ovhg0TtnJ!uHE1ov;8!Az;#Ks0>u<_MPk2|U^%Sq)%AuzX z32HW3sK%u?;z2KD|FI~svNua$L;wQZ%S(7oXrlQ)oN@u;9N>c{I6?OR(359^U)P(2|9cXpMN#4Ji4LY&kQ|q)9Am1T^TrOJy|hd)<>O{b4OKt=uOTAk*`% z7~dq`Dz-4EsgqbW{FNz!1ASIS!3=bYs>|* z(MT}-9%C8eGOyMuQJ(6o$>+;s&hEzVE0#gzNn>OejtS3Z?)`poqeGl3d zW;2p4eZ${lpl|sr(!`u}5hioDdE$~CD3^lP=mDmFH>0_Mv(*;&QT}k*CVJ3sbxG6e zylf((g3S+ghLOy~>IB?M72Ku)MSU zt9PYGexSpATO+|X>)939dpaqUv75v~zdNB2dq|-Ppr?Nz98S(N_*J~?z8k7V9_sRN zu8ihx55;RULnS7Z{=Bw;N(7VVy9eco9?|dm8Ru4m^jL3>KNeC05)}X%AIIe)152A^ z_>yY$&uODrWd9t&Rm^;$2=AQ$cTQYxp3ss!>T8! zG@@6Pl*Z}XJ#x48oe}{Bsb>lbo7Z>khh+%+tj*4}bEGbUdgdkMqkipMi?7GI+%I(_ z(AJ#o8jHH3{jR-AFvi+3V^L400unb9?+I)58&h;-NcOuP9f>Z{+N&~me4uvMi{gDN zE?sA9%Y?9JDU$6T+bz({*$*NN0^X`)=E4IS8q+nPvfL$w2M#a|2drOZp~HFB3k-9- zrsu2mRK`KbP+1mKta-27rJ>oh&^nh*m9ERU!4e<1A@oMym9RupN#SdDXuy`(t=y|&>x%cIYj`oVhVfl)~h+V}v#QW5_Dzf_CtxbnNE9DlTJkb3Bn@oXm zug8DGZ?F-pv+nhFn&xHOz-o>VEw|w8$97$(7VLRCU-%r-aJLzW<*64>Y%gBQ$ySYA zb!5%`Fi#b7nPDFxaKJQieQ8~69+Ke15s3-f%73(R;a=F@Q6<>uFqA}RG` zv7X*knW{6#=Nn1c+`z1g^t%5@f$&(s^-H=NXBXFy@mh4?$(}8n)EOiX<_f=P$H<6m z8k}eNhLQjF+?Q)U3G-duI@o*lrXvsH>F4HIUj#@0{*59w+)PSte^C9QdBtD0%Ok(j z5xM8?dDvQ(K!qD0G=8FzNJhc;G*3=P<(f>wbY$nhZ zwhC#THeoq{{krihE`p>kXoIKEuH3DzYo}nR3XArMTGyVhR*pj@rMq6texK7h2$NlI zpP9?qa&I=pCe$;iW>QTXi)QbH^GVM=M~d|Z#A}V1>61A$GsEP zhzb5Y4M_tIV6RRPhEZfE&v{gX8MgJB6WzB-}rPyS&Xu&##d7m=6-Fyl%Z>xGG0%W9SGn zzu9iw&5_E0!?mk6S0`&^p>;dUKH#fI`>-;@Q2CYwO`w*#h~WGEt212#RA!P?C-U|E zAT?Le>mST$xb(Bu`eQNN2!>3J+n?H;{d337$@pP^wq=Ulket0MK-v)9DD{C^aZ zPOLcBa1<|XPb?WJ@_N88=HcSNz{*jGDCO&K1ILZLmL}v$7!#Aoq4H;BXKRtv18jav zcMFE3U>9SyDO;)5?i;@z(;T#+eNkHBK)}S{O zET)-=fn0z4c;I^MABDHCFP0atR#i)i0%gU9izv$S81R6W^>}9Ut$z>k7`KE!eEv^6 z#GVIT7=EnE=DHQ=u-KcVU6G3S|HBJo*qQn6QRUzR;;)Y)sDn8-pUAAoazBKVS`Txq z{BPx&ELe=X#-s>_?R7|0Pc6z42sn1d9xMzab3lGu;2J#Y^xs|m-_|bSvuHzJyvf$B}wqssrkt2w546}%FnL>il4 z;G9|&@c-|Y;D2wYu@1ZAUgzNCxi`q+*0{JD`1^~(tW>_|m#*~i4-uK8d$ctTssCGL z6?n?WgLXkqC_;HSEcuauNE0?dAgsv452)P4SnzFoME$Y1Cu3{fxmV|?=ZIZf8Gnty|r6Iqu9kQ);DM8S}+3SnFS#^ z@N<)uSpclL{+|SYGk$pqF$Em@VD9b`<1)2?G26(OT0O4Y3o3GS9kV&iTrtPy*XRjt z=TH$-xHm7JFRZ-B<|}w!n!9vdUpg#L?m1tbA9>?FCGdd+mW^2M#8~bmxhILThb=EV z{Jr1e<0BIMSg?g1Llu;8h-=Yh{p7K)T=4ndZ!3ww?aXg0RI>ZuyewON96L_%(U-HF zDwj2ZQw2WF%aD)wp;!L$bcZekdzO$VAM~P3H+L9q_;oK)qJInV9hfY?{ z7k17YS62?OL6unjJ9%Vi{laNVPtuImjg&xWvdcA~F( zWx10;3pPvUlf;^%E_srHe^4MwIB|PVwSP~Knw55i#WXlC!)-vm%XOxrWg}6xC#!y? zBXskV+B$yiCv@UvvK9n_8lTQe4;4?I*!4ttQHLI<=EsYM>}VaKYs2Kb@Q?g_G58Jd z&qx2G(Fh{vZWyJxImDx6` zc_*2Dt-ZEhS^Lmhp!a-1qywauX~HokSN8PFKOw0Xg1|quU9Ui-@>iGJm)W(pP`7od zN}D8`>Of(vwm3{o5q@v)It<%V-CDwv&BXE~FwL^v1mP10CPM*XJMK6=`6#GDH$wrb_#} zBZzGI2zao>F!=dPnW>~hk9_#`E0{fDVp>C=n=_c9;m zpeZbB@F6ke;A{!3xA!2wz0J)T@17U4?GFEmy1B-Zj@Y2^8cQ9&-K{;4&8bGad$k4l z&4H+8%j2r-5X`bvmEv%efMID1l@2Lg01gctE30dm!Qrz>K&A~Xe$JzrznRSfpUYfl>)ZD=WFz1CQCzxwp!?@{4`+VG>Nh-8I+_{+t1Rv} z8*UG5*0gUS-*}H;kA4$oMYWoDDfD}xm@2w}qD@9}=Y^9BsX>S`{G(}<4a+D_Xw4;*c~<8rxxs2!SL zegU@vd)&dS&JBcewH?k&G}_#UYVU}Nd1MAWzX~1GTNmBK@m9_7gxqTi8T-$NBSBXD zY$XWwP5gAk=Ef(-XINnL@aOQ6Vg4mOsk;?Ygl}WM&Ox;$1>e%rd-Men%!{uCKn#>A zUhkaaqsja1iWAygDIE1=c8bq;O<~Msd4aB*2l$M1n~zB$`wn7$hnAqSQU{LM033GJ zlP{p;jkR@tsa}3wj@aGQc7D~sh4M8x=)u=Njo z18~KgqsM-uzNDF$~w0)muk(TH<#ur&_U7Dd*@Re=~ zgu~{lGng*tcZh0gH+bO4SWuq)tUcQIO`PiayhBm~DM#?n!1-Vvv+q)iwM)zZK_Uui z^oaoY!7MxN9aiZA)BN`g_vl4f;!a>P{;15KzH>V7>FGW`!AXMk``T1hu{gi8$;`$@ z*%Jjxg+oYYeN*_b8ZF4IH7sf)rO`GH#zv6gS}^&RXsxzoJ+5W#9Yx1VDTFFQ^`B)b zcJc3ZiUMYNJKzZKxg_zON6*=Ctlpe8Z=B@gf-i4G8UA-@NI&C!V}E3E9i@m9+s+Nt z)GC<#0h5ryx5?EZQ~JeTPxSaNQprA?(KKZHL=lLf)P3IGfNMb^-d)>`=|u)y?-?t` z%Q~;pRANOCVPzd9w!@=&Q|puE$N^E4F4}>s_8CR0@IF?5RL_vJ_k2?(%!;DyAoSXV z`0v~OWbSuX^4II<@J852&-m*&a1%vAijdbRaoMGwX$L(AbEv`ojIY<*z@V~f$cZ79 z;d=<1f&T2(ObXw+YOk*5-a}c@=1HFxe>|M|fa(&{0vRZ&gO7*E(nI4>lDvRV(tlUi zgXp^S0qK4X_??}+xaOc)raKcik3+5FWuf89C7LA-QVu+z-+VliH|Q09&GQV|v-qK*=(9O^&mCM4hL7&Qy`^~mgL;82e>jo=a=mS*nsv!N^iuN8 zJk9p72J7sV_g`*E%otAn|`-!u?n?tGDZL;QJ(5K-Nd(UxWEa@5vK)+YBEhp86 zZb=V@Wt?ZJV_?<9 zL8u8e4vDhts$c*m>n|!#)+y|bhw$|5cz>|;Wl&6&wl#HGX!WsD>|CTQiWQNV&z^Q~ zUzB+1rLi8~GOUYO%awuesGfbugb9WxF3IfJbVHY`)7 zmMdCwmsAT3pIq8dmaU!jwn5&G|oN&h=fGykbmEz|8*9nrDu8VT9Pb|gI6 zh+Ex+-|X{=ooLy_v#p$mk-XHOy%=|NkA~_Z1yZxS8cO{&wmMe8zb2*sPN>74Wa(IvON=^y;N^9Y5-2|EkKfPL9^JjXQ# zTJs+9v>?-JfX)IJorsesL(2KM-0@0z9D33D(o~*wS2KX#BgfZ~aRdC3t#}Qo@Q8?+rxWS3`V zT%+IWs5y-El3|@?U4S4>n-PUytrN|D$D0S&jMtCLR4%xT_}CVO2qr^(1Jp=ns2Sg*S_4|dKC=WF?jUUJwwD< zfq~%9rVJscMk4`@OD#KSLN75W(bFzpx@)pgD)H6W+gR@w{h>cZ$vs@-;nf!>$T?zK z*1#C{Kxm`Bo4c696P#^sf4wPK2XZgbd`sEp_meZVAmmIy$_$No=-MpuD>}@1c>g^N*(m5S!TjNg(QvS> zY8kgxVfBB8mjQfq&}}}b+ z547*wrM!D$D#f>H>i*m!P_k_<`;O5rW@D^_T2c{D651A1GG#Ayp~msK@7cQ}Q3op|FXIHw|xgoh{Jjsy+sCPjR|lJbI@q{DsW~TkH8XP#-r!R)3&13jdu9L)&POj03C9EsM1Rqr4+H-6C4mmX-9NaN`ajYIL z!kU<~6~G1nIEy12+g#I{-E!+QH#!%F9;H#Q+4}`qsd*aQy}gwNY2?k8@?_^!-qN2t zA~TvV$D1z3z28vt(K}}V>AF+Bx&AKl#LGzQcQI=1Q!pDFdppNtaYa_|%XU1ZWR^OcDq%_u z-2{)=*_bN#wo*GqyxJ~l^gbG?)_!sx0fj ze>o>mY})us{%~P816+Ykft3z>C+*=I3}N|h=m^^WPPGIBPkBOP0lp#Lm7wsiNBZMt z76HGU2pDwj;K8BH?RX-H4K*VXk5%H0qg8nwsE;VnNLw z6Ap0QfG=4aj8;&c&oD8}u*_x9GX>|W^u77^*T|cR)CYicVm2Zpywi`^X(}QPCA4}n z>J-bG9Hej_Iu3I{kAZ3FF#%LX>E2z=BiEQ!y+T3~toCwwyrjjcGO$zu0UZ&A$>sU4 zldYb(>~~q58nQV;YY+Y>@GCYmVPv*FYa=nsC>^jEsz_R;4XVfnMHt)<--AK8(=;t4F2*?nBrY>4RSm^0GE^hq(ry4#H zLe>9U8+T>_NH| zwNJ#`#d3@6Ex%udTJiJl{-e9bE~{5x^b(Iv<~(bH&!=OP!u1BMPfjWVz`0hHj0@tfQKK1xJZA2#9n{x&;J_?(ULM zx`%Y5(v8%lVU*;4AHL7?oZsgR{@P(6!w3>%pi(OYJS zWOg}UMURngvO7jNivzZN)JI0q9r|HBA|LC(`sCFm`s)=f?wIyFgPe^N{gk>AseQ82 zPsl6@W6AGJ#GTAObsVXH$mX>wA3#bGL+Ni=eXdSvNQm5xw%-mNY{4#_Eob>r(sWsY2iuobsLZ z2q@7F)i9oQD?h#5lQQM3x&W|xL|($Dr?M#fnFMI+h8i}3D;ONZZT0EtakrBL%3goF zH}+%ez5n$)U)%j8n#-7K!@Du7XTNeMv54^zvL+m#YjbPeQFtD z-R33MOqZwL_$g75YGQ@a46#4bJ^5M=>&fE!ii$y*B+cd?5i*b}fAp&sBMyy?dwq|U z_n2PfiVxSIg0h^#E=Rx9=v13{CrEJa(gbZr>9ROL@(0y~;VL5M#vmQwTG)RR8J9#4 zypSpJt=#-GoU5TEQc~L~ecRZ4(oeUM6L9!}r>6b4Py8x*H_f|wE@I>Kq~Nx1|FgJw zmNCr^CLHCGD|zF7GSo#7FY}aXQw83bg5Pfn+HG1#_5H>lkG0+dWv-TQPh1eNNPXP(wiY-$J{(UtZ+fVb#Ej-Bc6*YQ1k zb?@^A9)AH?9Qo!~x_ZVW#b|D-l#Vl7)Rq*0md`q47GloX^ymJjdyXpj=6I*DvVs4cG`p?ZcugWXntbD((v5E^JC^O$bM9mMUZd|d) zhLe&l!kV{DR--uUMSD%Xb$M6}TOFhsi3B?`n-a+#(_EwvTohx+D& z&h5f&aK;*Ge)BJyxc~0d_0w#sEaNqi=bi5r{>k6&0HApyxs@B81i#CjP~Yz&ky7Bj zpsNA;+Ow6}_S+(#nAoEjdBZmnE-w}&LbgvwKdhoPAdzBWAJ3T|-B})8j`#u&Sft0y zLE93gkv3fYjTm#GiDZ}0YI*8J7ORmq5&8nV&v-^Bk5XsW1NkPRc_Zoao8PCyHX7&VH6_u{1};5~Hk^osuU|6|yOjapALL z&AgxcoPxYM7?vlI)C>&>)jgI5qpxzueOEcmN*7}7FOaY$tp{(Ag~i3&XFGD`LJz77 zJJeyxvn&C~GKe2MttuA$BSZCy3-aRY7ufp^4BtOpZcp#irTw=W*WPaDxza>$#yF3A zNn4gvA+HyEfM!UpOI622+#hTPNpWh^3hcywNlH3lkIokgbJP{Sb}(pJQI`gLZX-yd z$j6o%unZ!;uG4IQ3OUQF;q%rRqau-n>>uFdoRG~pL{m=k=g z_i!e3k4+{=7{fzyCV-(GqY3bI}g?RjUDtAVVpb~|c#jt`WYu!OZwWIZ=0 zbH2KE$FSYTT~0oih+@`iyNm`g63KC&kw5$O9C!ZI+otDF{`e)Bz|hOgxGQfi#75F6 zbKIx8=qyCShB;DQZ+R+$9Q$HdnbamG4e79y+%9PCjk#2?Sr)sTDs)FSM}p@;PDUNi+TJ15MBch`gmwEeXZWia^UIM$uLh% z1oE&25MNl^eP+#lcA_rR#Um)6(NPYYaW5wS&+%9RlY+Fu>AfPS6aY>mF@e# zCHMQ_A2&i!i!TGm=f988(GBWVQ`GqEEK5^m2fd(2Em{uzcrNpJJTqW;7Cp^4=s@fm zZ4?JFy)MxxH^#F7*;SMOtc(}EA=3zOy)dNzm2+$yr&7fa4Kil~? zfquUd699Q)qCi5jQBZCl<#buN6|zNZFswCxcl{BOoNCGjmaub*!K7)mxj45Xker69 zi!)D|u~xj>h@xL!haFw*x3I^yj$e7ry6QEH+O{aMMv-+++P=hBi`2{T1kT({8G=+VCN;8Sy(%3c0YbVrlT=V4x0!XdOTUnn)mA4|Gqc)z zG1oC1*}n~5&V2qUq2{Q79{G3vUdrxU6?LZ^+2Dwwka`VfaB>y=JutLhuEgN3I$k828MZJX}dB(xX>jb?~b-{n+QQ+^Djl0k-sDQ@rGQbhsYVeqEz!W_i1`4NAVH-zEL?&uqY1!rvU& zW^PNN*-}7eHebt2kX4FMAELMY-uu!6>!E$N&B$>X+cJv+qhpmx$UX;XUPBB>OD+R; z`fIDub~-pG1q(GXBf~0Np$sJEAkUBDeAlf?9KDgpzV57sG9=I zYpiOTPrYX$rku~}hwepPTM=GfTl_ML2Cnv~=^!&#MsP?o^)>WY7&Pe|) z4?*r9S&)$pz!|v##BwlvpFXmA9Eg=*W}y(@jv`yp&ku#jNf0?EO%T%3u5t~-#XVm1 zz7yLm4UAtcR)ygZx9S4}b6YNviQlbYFP-!Lelm!i)urkPHbti-D=;K+@9V2PSm{5=ixE zl_@XoN}_I0Hvo6f$FJ3`!*!fs1jg(C0D_u42YgOfJ|PoAh2j32d1{ZVIdwVZ`>Fk; ziFvGgNo(4ldgyb(fc!(%MauQ zA-@>$Xg-|82BII9r6TRR-d+7UUB)6P%OTEG{0DY^321>RF|jfGV4p#UjHqARY{?R! z&;PcDjmjaCj*wkbOr9OF(*4{ z?!SVd9@k^}$}0z)ME3fLv}IMSe?Pdig!1KLoc*3jLUPS-ze&M3nl5-WPPv36$G>RZ zWF6BNd1gG|L;0>J^2ft&dJAqiU(-&A`~sLL%J~WRhx6rXgEu7D_w15i#$sD$LT1+h zJ*!W^r~~ga$cQhrzvys7kqu^JBsXWfG@OZz2kPoZP(0>az-~|=C)!uWcEKU?-7+_t zMaKy6ny;JUo_cn*WH?bAXV+ce@wttN5aIgg7AvVN^MUk0bi?_%l6V%b5^h3`C`x0QGW(Oq5LweIJ~&g8p$#oRX% z$&kw=R%&aOh#$$G2fywes8nnOc@kC^fY+5Q;oxs)lAtv344L!te0WfmmXPb7r6>5?r z$r3S*6j%ov^^Wvq|Gp#Ca!<2zv(~zyL-~KaJl`2cJ=0gKqYrQaC*RV}1NbTT9PsO5 z!PyLDvwt*xuOz!OAeVlqs-_2cm|g%k10MIWb~E3&D#^GPjikGkGPK8wisiFNQW$W= zbMU@f7k|-k^s- zTELd1GsG_v6~BQybxv%!GLwSAO$HF|La`NkMK($zWtgs79_H{MES(TFh^}WOULK1X zHB;9I;>R*Z3h{S%zRVmS;>?){$P2#GmhGo)S)E*dL`w)|o?<{50H~UhPF(?THy4`E^p9@=&B*iG?VopN~-3K13=6hnK>+cs{~UJ0H<86$^BYeha=#oBS^pHG0k80(-i<1q~z;MJy*WrCcd3D4%9PSo_a&&J+f8_lEX22-Di6gxV`L?&sM4F;?PiY+- zu~j~88KbA;7xT*uw~KjvenN6$@}?V8*AA*t0j7axRAB zP9|f`ZOuLkCvO=S z-Gu{=4;DAzk5RSv&yyr~VBFbBOiQ=L_maZj2suGEm3%)-Q?5RTFI@`_h~+~m%N8oa zH05%;BFzL2jY5n4of+xw!}9(~0hx59=Z?r_JBeGK$yf_I-7;+ZXmO)6hr_)l)om~+ zySvGy5x2v8XzFN>(N4Q3Z}K#B_t}-|c+LB_ImBIbpqs<|foYc}z+I5{n@GnYzf!Uo zk{U(CU~#pZ5Mmez&1v)u@l#new)^7;*fi7Fg@ zdrqoiuQM*?0}fj2#odNzvAAPKTivs12GYEk+7qF#L2-N7SYh1S_rJZIDF8y2G~L0V zjsj;nwgb~q}J$}60*Td(7vsty_Vhb2W| z)4>=<@Y8C@#4!#-QGDbzm7OBipC(66gWZKeG&!12Q1jujotcjOr?=CMjYe(?eOXf& z+zy9x8h2QFJs_F|acaI@bd54gPTMjaw$=&qbuAgc7Q)Tussn5=4zj1NQ?#w5tc}Lq?D%9QtiAETQvM zqOU##pbv-11hcaJ%Utxv)c?O*e~2yKWzk<6edjpjW0k=Qr|OtTxzdml3V34VQUUUK z-s0C4xGI?&Q?0Lb_VU~KIsQQSY!HA1ef`sLhecYhgb^__`h<^8 zJfT7s#W0cHS-qM;!u?49NV&kOqfb9|R+k#*(o_ z{B;Pox;_J1ov|MZK!Zfc;8-%;TzyP5WssQYG~uVLNEmMMu7x*mYFNjT3BIu|^j=o8 zpn_;}D(ErtD1<3rh50oNtnr7_hH>m`zrU?O-F%UX5SjCZ42H2Ww*)tB4@|M}EfgSy zf^G7M06s{p_KpBkkM(%I&Yy%l&7Kr4P$j7ocr)%3i+t%ca)(xz4cEE>2p+GI{$z!J zxfM%xN|`XK$@YKeG=pE9<21-Bclo{U1&*oOm*fyE zS7>gU+FrZ=0mwFw!pZjDjCD)G!NqwztujRLoN@MkTo$8w>s+ib$c3ZtaWi5;f3TkV z!6Zsn=Ie_fa^NN(CmbK$bysr%Q^u{epN=Pnu->JC4HVwB0wjAQ1`76bhHe+>w+G|T z1+gN^yevv;NeVs`bo)LkR+94Ee}}0=-auL5oEVBX5Z^MK7|WwJGuo2e&4#PoH(wd+ zzdN12mi7>m9|b zF&#gYC~orhV~`RgrK9xmp8coyx5MNGTEF?PqBho+iIqiN~iCic^#AI*Y zm0@uMG&9<@cWfsuh4OB7!KgYIwbx`RW~gc=@Xz}!xGqP~iBMVBCoJ?xCRHtVUWyE| z`33eUY>7-sf4UI!W*%YNtl3l@qLeh?nc_ZLvL1lSF~+uFY98_^M3XpN-{;n)^rHBA z+0RPv^NFsl;EH}knFr#Vsn^b;z5r?0+24IaH-9h)&7$>k|Nd;>Mc=TRAd z${HUIdMk)~>J6mVVe=A;v77j20v~+;CHqR%DeFLJDyOX8b*oUi1lq|e7 z*x#JkRwGEXkw&}#9djKku42blyav~xMclLO_VxK5v)gdg`&`=?@Dqd>o&iW~_ElXd zUZG&Y6OU|8*UvXU!?3rVs?F(_yoOy96;yJ|MnKR#etCPl)#91PI3LgO`W~8vteY_` z#uGc{ z#jnk(&vJDt&azv;!~Ls1XS^!?{4|j#5i60o&Q9x}j9NIPHk7Vyqai&ryR{3WYYGc` za-T_brSbt?Zf<^J$V_0Ap~;9&1y`W*v_af{_vx9c+9Zv<@=dO7wSLei?Dh7>O8&XJ_o0T1vd~|u z_t}JbX8t?H)*@l{TN|5#mFJmjdu8!maAk6pO>d54)|7Oe8_%EOHfhAkZvxYPI0UlBhm zald?&vSd+B{xJbV=3W|l)$gF7Mr6R9R|soz1#+ybN=RQn10w(ZUvsFOws5eN(g!dE znDS|seSc5My)r?;tzBoPoj}(RzJ#gpo}M#dRzG=@NcB&Vqzh1Jp;7^(EfUo3mhjN) zbUPvkNEtt^e)6NUU~^~PSkm96i-&!jo#L1h2z~d{(gNi-CXhDU9fWK5nj-{HrFdm3 zq=H&OohYs`RI@GW_SGKtKF?9a73ph@92!^^+%x*Gr5JQ*mLLvOj>~>@H$LDUG73f` znlM{Z4NF5RSVr#tc4PV>6aFlZL{b@||JC`ObPJg}+LcU1W~aEIPu9HWKb+GoDKyL} z+_BI{i!#umnm)j~sV6w(wJxXeXM}U45;K$!8=GOe=6#ivMhA&2h0T=2%AR`OtLzaw z+dDrZF$4RDGg|S<@|FR67Oj_+=Gf*I{cj5PtXqcx$hUaU6cAn(zjrnwKer;G81_aV z(|zzAxLd=8>=~FzQaO@#JnQy!#zwdt3H3fgc0FNoyAv!2kKQBuft6L~?ra zD$9(5V*9CO#UCu3lxt(Ln6pk;29`n62%o$WqrzioWH^5|yf{>IMtpz)MRUiUucv;KR6PZPuoJe^{;zPB@JT`7%}+)B|M#ene{^{<+AM#~h4-x93y#L6Jm z=R`pn(CQ@syZ+sFh^*x^r-3tno+`kw6(w5x3drIo2ekhepP(&PeaF3wMI3XEDH<=L zqLX~mhhkTF|Iy3dhX1foSfJ?>%9FJv}6Ve%rfYA9Q`R0 zC~1OvbK!%)(kZzsqL__*h-is%Uxan6GB7^6m(wWW5=P2tzSE{uG-S4XR?)NrO#fI{ zo7u5SN#Zy9=E~kgw2CSQa#AgC$GS5NJ_7mg*WSl_%nIuNWdCXo@z^S z6xv9#gF^ZeH}W!#)uu`)WG3;d5US+ z-$e5rN0OWP$(MB{?IOp%jCAfOV7k{9=8|(k?wx3G*h?c?H&5rx8r1(|wTVeGl}j>V z5V&aM=`A3xV5Forcp&yoyE)Y2ga3kvu7R)3Og?$>ef@I zN5KxrO<3WHVRIl$xIHC9ox`csQ0FyBhpjhllcw( z0wKqsge7t@&~=joByh?V_<}XA=VgS+dNj6C8RMvQgPwNeGg@g-@Aso6%Ai!ysTUT+ zbE@fVelj%B>^L*&tL6sq#qG^~$OzbV+$m$?{xlRWF;MMO@pZf1GD#fP;UDk zBQ0TfC?mcyM~X`^JkZ>fZjJKIwizU`0uiI9{5#+j+q>ASGBDs`b)j^)R%gq&0@F9s z(XYBB$w&2Z?zJ88ZD4SJks^b*MWmtW@9*ca%@sw|(hD--h$-QzC3`2AULQ!MCO&<4 zw(D+5uQBYD3sX(2*7i`<{f*;M+-{C+AfIdMQ0}CJ>9m29=_~)ms~a+@X&wF>{u625 zn`Pmt?`~BLTWCW~$GEsOVjArJNHzeR@N!DYxW-uiE`|zyt?2$;q4WlZ(x(xa=&Ad2 zu7qWw!l3AL9Cc5E?b-H6%cbyHhpY#S(3A!jN$D?ODFY`#H%;!hM<$ibL$h2Qoq}%! zK*f6WT5-RG@BwZmIzc+UWyhPdJKrPNYBX*CJby_*;w20>2EJ4z(4&^D*REQdpC5)+Z8n{FI$?G*g@zY1TYvY=vQ{QbIuLxSX;M+GcoO{C0 z4wg!(*wi87l4D$?dh?><8h^J;{-{^u%9%N7#)p_>eoaK4yl%UZ_WCkXl4H-$WxfEA zHYGVDIZeCRhjG7Q;M6vTHoXmAIn3inM`J5^lfZ*WV~&~?&4t(lZd)z~xYM_>sN3Ni z8TcjrC6*oOw;dC7wjHS{43C+!w)gbxqc85R=*-gPE8?eCG8@|k!hIf5F!hH-a?su1 z2Rbw4B)%8k2f(_z7rt^G^T9xJ64yXd`{3!;)C5BTq15;f{I+$->jdSJh0UY5wVVwV z$!|*@ggNeOY*tuy&bqI6N9NuiG`Nf1?|CQJ0Ge-)#Rb zzKHgHdwdD!3Ol;Jd=Gm(G!8^6nSANy1TEYArW{>XI`AByC`j|eK)((cgoG)AT686M z6jL>0k{E>ZkT>P02?c<6Oq1v-n-imPX!NhhFlx2)71mISirA3M7EU6r`xFw!N}BH@ z(ro=Tz!@~Wfb9%+=!v_*lk3GbBM_&km=KO*L-Vr*R%Xh`DI>QOG7$|KQM!Ti^sDR? z#BQtnt2vb3f5`>66nZhVk?rK#*)c0;z@9u232I~6QU_S}>%Hkh&8OqZo#DK|mS~vV zrnJ9n9Cs!9`K>pwl3XVwb(Sdg1%BbWW{(}qQR(O|mX!|n$0Jn*7s^`o-}+`(kBAc+ zaB4)JVJL(WI3@w6qeA5J(am;s+aX@u){Lp!7pIyI@z>*7>DLQrGBrSVRLjQk?mNJgU<5&?~#tYwEkHfKeb$Kgd4Nu7mv8aS!KK|Kv z!6%fb!To7%SWwEft?y{8;yJ&hqxNUhzdq4vWFj3H;8hGD*3ZFs~q3GYue- zG+ypS$~ZOAV>5y6A(4Q#bS~kX4bb=3tUBFyja!r=MRI#qbuO0tMm*iSjfwoB^+lIl zOcA#Qj&HyQoRpn{yOZ(gl+Y){PQ4d%Edn&w1Y|q2&a19LKi_QRg>&n8*r<1{0qS~W zoTPrIY9V9xvZ#hZ6x^42+U3PGn{1_frih7-V7=;koNt7 zZTCfSurlL7*RR=oHS?J8nAH;9`_G8c4{&Z00Uv>SzU@C`TB81{zU*{OWX$iBV<(sG z1NBqvZL^1DOzL^a$H4J28@5F_(0NfE;$^O_t@*qItd8Sn2$*&49*hKCy*~Z9EHWAH zwhVY^p)C1-LP3{=eKgZl3UQW&RlP{R#JXNt02Wi6c#F@RhQ#)36eBYD?{?Ra9qmcw zo-@2*jfh&_q3>C*#24#(qLan>qkY1p3+yp1;kv}R6w6x5Z?7fXrkOCA8s0*SQ((|x28h#$Di#+Qn-$8+uN@rM8JWPi_&;ye~q*OMz+Zt z;Zrw><9C?&l6j+FT1WXx8^7`J;-^oa1(E?+cuHu6k8P(Svsc{aM?i9*LCP zyN=rVXgFbv*QzS$>M!@i4$X5lOmcUD#eXSxyW7hMvD5-HHD}$$R#*xcNfmg0X)$(D zWjiy4G8vW9pa^=9%)VYCo4Ny?^%6#Rb4vi?X`0po3p-DZTQFTZNbtHU57 zG>GLrg&iZU2xLrotmtf4cO~#H|8FK>F(^}e1UpVeQ@<;qp%$tBdhrOKsJO*x;yg9y z)8RQ0?$uTf`Z1V9P$in+(tY9cnnmYUis?IHl{a62sGdO3-~w7Dfk_->sZ^V=MT;$R z)g2Wi6d%1bwe{$|foFVeYIDN>tDT;MTKi5Dru-!bro(2l)nwZ%S`#xMeNy81e( zGxH}LFcw&2?=w#E4ilKv3wqD_A?ChorN%LqXdNw2FIE%TweTwtUg=7PM?Nj^Uo*2e z;9M8$Cqj6UPm6u&~A8EMJh#a@LUeyb|Zi=Tr zsAf)iZu?oW0BWK4SEonM^_79EgEL%poc6?w5x0Kb>h_udBjkq~RT~ zfLplngEjDv;Qh*FC$^(|ksgKnF%Tf#`ujHL^y?nTN>WEsIf5XO`sq7o-0g!o1hkYT z|A~g3F&gm#rSPC`z;wSuW_LV$aySwK{UskmkJy7>B9Tg2AnB}W?TN4-k_qSOBDiK{ z=mz^sTLeDU!Fu)3r-Cu&HotvBV9^rV*?PjHE*9wm}C%=Ga>8O++cH9Mch_5*5E-$T>Rn0&)ldl0i0a_ zVi_N#2y9N})ufXcyRg>gu%O@NMjON|VF!D$H$TP7s58b^LrcWRqWrtcfcaM8WsaDY z*?DLT;-h`Ee=Xu^)P3D9Ednoj|1^W?oqw2Sq$ZjH82hC^AqE>JJ~S?gYX|4sZKUQ# z7wbEb5L8YF9Ts<9R}W?=j@>K+Z63ko>tgwPivabAiOW?Q#G!1(wq#nIEmx^Vaix&t zWA~Rba;}b>cx3Ki=jia*-|tUDS?wBX9v>MF-|SDOBO@8~Kq(=)4FHHV>&#>^+5f&S zt&p(edebhFy|BA{)Q1~U_Lv02`M1Q+EgN(!Lt*}$X3 z%iA!+BWLa;3S0|@SOn@YvwjHH$}7m`T^$CiB;0MF&Y~pqINQ$No!b1^S^Y8{+1mGA z4No@b4!%BDW+?rtjf&{4Cg_j14K)+{9vkBfp&@4K<{QZn2>Fb^oaiI zS(1Fn??*|P^u_cS-s46I6$prd0-p5Fq^tXr{RtogBm&j<=+yfF61Y}xh>x{4Yx?!$ z5pWnY6WK_}Q*Uuz@Iw}c$_`5jOpHLw=^{vSw3Zd3TgS5lTcJi-n+l&MI7Jl-G#R*T zGvaK99q4GjFRldMKcsA73Rh3B z%2&73qqrjeO{7Xs!nm&&pJ04@GMWgnn03=WM<5$oiQs@ADrab~|0;f1d(9&q7&*RS7o%l&bKIf5ywp`+HGmP{6ferFd6)LZgE_xJMp>p#z;0*7|$s$csGHb6xviku6Hw^+D3(QCW25Oq zqwmA43`0~Qj+9QKzxH$jU52gVGI*;lK8gYB8P4TaT?!p%ssMhAk?LdrH|*f{)=9_; zo%ugBs$8!p)9S@$Qa+`w%RqOrYx3LR4Uy*q)&lp2^w;|$;OJ+Z;@ao*B2r~9H(@)q z0X0+#QClvA0Jjat+D=xOr^Mk)=@VC zMxC@-x6gT71tjNF&y35=#(FoAJnr3Eyo4;AKs;1oh4P9gVt$yRy~mq@cJ=Y4*A+J? zQPZ6M2epperv>J0Er{Y!9-&oHAI+xc)nSA_Cfb^IU3lTA4x>>A#H zCrO6b97jOvpwRUX$n_ULX7uuY9>zB?%Z@Y+>_?J_BEtc!5%&9Qp@|TP1kAaheTwxA zw+8FQ&_Mye&UFUt`BnGHL^{!KS$GQ(P#bIp>;()UVlam{Jv1N@>-nVOw`)IN+yhiX zG&=f)bNVwmt)Gf>0wh>jM{jjRD7h74 zoixP$9Ep?9Ps|5B5yWve#-=cIs03<$M{@(#fV#~uB#tv@FBlHB(rSr`L)_A8P`Mp9 zbJa`le}H6EJp6&74gjI(IMmDiA$?RgOlO;J^v#m@hN5qE2q+Zf{apUnlbafqU#*VE z^weTv4GxM6Woex=Gwp6O+Kaq1jWamYMd5};e^%;T@!6?e=x1Qah7M&n??2P2v!#92CzY@%?+z$cpGC;-6ojk|%a*9fMhWTL-HW9C%B~5oC*C4iT2f za7djc&o|2K`lv4*e+xb-`5dhTAm}$~GQGO8F}_LPePvaSBg{&BYag)pEj6Ah>%%;4 zLdQ#&wte2d^!nI^tmWHmW!JU_dx;RseVJrGZWaTQa2yERiK$x$d-5acfed2FX;QWV z!o4PnoTR+q4!P4jRDd_zu$?_BJ{0#QNXkoJYU#lD;Mu9#~ z*%Nwd_EOjTcNORAkG5~fjWQ39gb#5OZ|6|kecc#PZa-LUQjCH zJnVeys*o$xKRzSuff~L!WN`D}={uR3wP0v40ti7NAx*^xQb*nRldYUvr=LlO)*m&s zUl03^1P9zrKG&drP005f(}P>Htr#lii2-I_CbDl++Q<1a@Aq9!5bH-*i*x6c>~o8A z8U(U(G9x@GJgcW8P^YL}36vyUyw>uzxwqZeT;@}Cbkxt)nhTMu$t(8}6^Ymhi@T(j z_ZaXQxTC8mWFt;lkAMTw}$7~e46YR zS%=Ng%SQp<-i0dSd~jBH&s>vmH=PAl+$^^ar_Z{`^|qozbl>>ASSN5OJzg;_(uBPZ z_FK2tRZ&;4xke-Ml&4zn40?-9*mslW+yVju^z1aQ zBC}lSHCo!;4zlje7k@om9x=C!Zx7&NuSWfob}}lgoc(Kp`CBOay7&5P(h{W(^LL;c%<*2=|b%U2MiF`Lc2$(?R`rn;?ciMLweScvZyh59`+)YHe zv6$7N-(jgx-*s`(Xrlf5NaF(=VOCN^uxxG#GZ`*3nvyg{^i8!0qCGgCb)lFo3^A}o zYwM5ken_gmZ((M*sdEZTknLh*-_yDOu=)oqXxy1@qFPbLW|EZKF?QZfT3Y(TbYI%x z^66-U&Jhi%oe6^fpbn85c-d$CKCK3>ni}Y=_TN=g%A&dXS8(+FgWj*4H`N!%2uA6Y zi^M9iCvs}L-!^(chPKg=NqbD0ue$kf;Apd+;_vpFiPQJp4Ni*2?d#5qYX6GBQOEuy-c+0a-UI!+dxm#qlep1+;gw{&W=4VK;U z+=!I;oC_e-l3evV8KRYNTY$70c8*7pE~qP;+;bg=BXtAg6>$u!d%Yf%so2G^0;j@2 zpEH5&le*#05LV8lZcPj=9QG@bk7$wigf)-f3l+4D+56aUMCFRLiDcL0O8mIo4iNBR z7u{~+4;g{&o=P}QXA#pI1+QFhp!P+Qf^2GsP%jg)&YOepCcZis<=UNO6#p{GFnDx7 zKZF|KOn|h6?~TEieOqp2Zcw5KN<57+5L9cIV%n)XZKB|c2kz=`ImCx`H+d7sy>*sF4QWk0$R!+T5H?*86(27X!Q+6+t=iGzY^h7Ln{f#&Rf)vM^H zsY91J5J;gTYo4&`@v&CMo1>C;)MW9%$;riy@Aq3?gvmVj2`(A;!%Hb-zurry80`P| zsV=174L;uJssqBM{O?UvgxyVdNPyT3KuJ~^>FMRE7Q;5|a2msQL!lS366|o`NwmdZ z*}VSu`Jhk-?Xpd}x+`&S^I)U>nPgHZ6V$4-bE7X&Kwn(judFCGc@-!`IG^ z-P_yyRY-{Z#l?m2AyQIYT>O=_b$+ni!&`9CC=;c2M*g#>7SbB03q<|0uyp;`xAD90 z+T(Lb2KDhS%#tiN*<)bh_`8VYg<7rxZ@>kz*#&HUe>)weJ?63%&hZQ&pu>GyAEou1-=;F6MK~r%#_GrKCRUl(Ocd0k8eDF=E)q zqDlc>i4*6Y9tK&NQgKB>XC5b>f(r8v3iWE7cYK4*-8y-oGd(-V3NSchD26t=2u+B@ zY;^hM%w3v4%Pn!RGM?E8irHX_vDx&CDd3E=d(cx@G2{l4-D?t}d6YnGKjt@xg<*BDWteed>GVx*1Cu`{FBm>Ifz{ z(ubMn#XpPB&x1_-N;u&|O;Ap@^k?r^Wi^WR^uA7$ydW|7cL!Be(WUsmN794>CS}`q z<;jNCqmf{E>ar`x$d(?}r^w1#r)m%WWKB%#UR{E`tGT^%Tbai;AwgKC+x3esy_gyC zGnzQn#gh(=v++HDm=+H%9NXrdX)H@7%PH_MPp$$}j-t6l<<$yFJ69V9IA}LYzJKa4 z9lKRvV(NRP`@V;HV=}9h>)zcgqffMF{&n>0>JN;F@E@VulHDI=efULBAC;O^;Ry{y z>6JhITy+pL3b`EKLW*tE8+}a+Z$!CECpBUQSe0(2F(~_CvnzL$2{Jv$Zhhka_n8A9 zzT8Xb)vKe&g}hpgZejA~tFOxssvUjir<+_BuQO+7L>3!e7K4GG&rKn$1GEyts)xg{ zic{Oy%fKAVBTm}eY9J=ab3DyyEL|jOO}850H!2w@29m$Dnyzc2uy8=8fD!*-5EH5Y|IqWqi z8Zm4EJuHnq^grmfMu38w`eHMWKFa9j4}&{gm>lSOF9Jx1jm*6$Yja4Z_m0;rnAIhz z!g%+80>%k!W&#?zT(yjWALmT8w-;_GZycxoFU_?=ikP~GQcm)UV<&$|e!rfb2xz-i z(^Mc`YpjH$bXJ|BGJU0<^I%=!0W43^N2HBCa;B0aB*d)^9C=FDE`ZTyFA4 zgv>E<6dZ z{P<_Aybv(qHA~!0RjMKFLo%3Z8QcP~&l;(@Td2Vd^cEm78&xhC9mJ&E8)!S~-0P%k z=706WzSU;U$Lsh}d+brrAjg%;>6-SV_G>xJ zPB@M2bziNBF~>QZav4mqRp`8oU3No~w)MYXi2Q1Hm$v@_DIB5qbO<>Ra9%% z3}VFIo7zf^8m0D%+BIuN?X7n08UFcv$NzkP_vD=9oSSo#d!N_yUeEh^y~1Iv@&CMa z@sjJkO8|t&e5+xTRvDS{wG5RSqm)<(X`aBA68$*eYj_N%TKr zPSNUvJJV+e){%U5->gh9bL4xA!2lky`HvJozPLLB!f1gn*x_;2x{OVP=_vQTR~3}L z5Ely7-7@9-u7oGV+#RC98SB3k$P{NDiM@%?HV?DwlAIouOEBRu5v_P|*duO^6_tZN z16MUzMd|0{=C}5wfodl7XJSCyRYTIsC|sfpipnkdA7s~&GCp~zhnHg zi0xWngxAfm)B)(_3fyYSc=3R)fnlgBV_Pyk|43x<7FHY6>$`P1%T_$tG^aNsYPFs` zpBeo9&-g|}u(#A3rT#k-Z=Ma_pp+5W~* z@xhwKG`hqE=h#O31()RR^ADJr4N1_)PgQA@`)sQYCQ-in?r#FscC>XC-{5tU&QIrv z+n8M@Gr04c&pM;=P%RkE^^5)H%N&eJWp4X?m9Bxig@4w>3ad^` z*&O`7VN{=-{QbGtzTSs-{S$$0Zev2jV7%(MaDd$oYP0&*lUi$QBOFT z3D;{Tq!LQ+B+P6XOm=L_5W)tKLxSOkgs-}c4q04aFh6^F(~29!LI2(1{6p%M{^#&Lv6r{s zD4LHLV#FISG&t=Ds4Ran&0ASqD)W$X-FaX}`->gR23dNO@0!lSj()7@ua|kvPWpyc z+0PR3U)?gH>2=yBv&^q^77*dbAH_?G7cXzkJ@#FtemsE&dOg>u%pD`nn?f2pG!~}q zWXERfkI0;xcx@G?_K$1Hnf|kx$w3`z%hwen6)QSEQ{0MW;q~-7?0%@8ggR)uCbr2u z9rB(!oBX<2=zY+*nSF%q1EjQGE-A|9#_ByGsvQ0ydR^TP1?swBkSv_=KKOJf1zI3JstQ8SMmKnmQ~}7TLK13JC=}A z=2$C2AM-J{K$3?8?Oq!1$eDzqGr`_vPy7j4AfPH0vc39iw+IGC_bXPTIE&NsqgJd} z(Ge30lPX}ng)=~b4$Gapz-%ZaxD!8*`i)<^M+Fb`!{mpZ!kJ~8=q|pESA%$5#nUomeVP2+J zo{QC{_`1oafWdB6v3p2VeDmxemvyI5KgG-b*yf|IM39H+~{IIgF+XJ zC(L-DswlLW{1nc2mq($Y`AG_q`Mqc7GAnJ(@KmN{1k#oMB1W<{Nq0n-w8cZ?GI-Bj z17dxTAh{TSF0!)q?A0Y!!y^8?3v}Gpa<%lpOc1Atr6%_*f>+`3cIoW$eU zdYWPtP7H`T+Q@Lc+NFm*uy>v%%MSwF#6(&VfdIkcIj$5+VZy6ZYfhE(*f#L>%DYpP z!%(d|n594G+7(gp54QSKv4Y0AJ}0BfCO$da5|mIuPqRm2zU*b7z=`9lol5+G-qXlu zG~-9N*9XSE(#`hhvg%QfO%eB=b{pUG{=z@B8Ox}*ME^gS!D1;;t&*+aHp;eMimB0z zqp;E=mrY}b;SbP)U4B>NF(l^V+fDJ$XHQweuRs;y5=qbW72{MC0&_mNC=E@qvj>xA9PMXg=!k8+= z4z=^$pjtU>+->8x?i%3=_(a@^b5b+BCMlPb8A)wzghWy^n8`{%ebUr3zeiUK6cvLP zjdyX~zSdzJ8*cvJ9@{yUXT4{5iDInI%p43G1h89h>PyXSFw^PSW z>-wX9rmZ=ljugz9X7fA8%S98hnZ>NTMoel7UzuxiZbxIs&-`J;bfd|wmWNNv-P%%> zJAA!EqJ{#&4S9DjK9Ja^J5ftk6^A9)DX7ow&5+Uw{E1x9;B=IEk^;jZBWYp{1sVxta&EHl zk+UH*&YM{tlJ$%CnaQZ?*OMglqz!;f0ItBe)3M_K5hY9;Vkv+ysz|#SM)Be4y=<;3 zq5z7xKPx6PBV1cv%QH?3G>8uJfbiT2v)**2|7*HVz%^l}>>@6({G(@$-nIA(nztYt zakU0&Pz@xIS!35bb=>0Do7ynKu4;y36@uX)NEY968#B~4hoP)1C_ZFZzU4l4zh6q6 zP)s6Or$@(IuGMR&XyzouQDP2r70CEA>&r}6ESltUsmr2-R?KL_zUlPjjOT66MCW4g zf!upGy=>&+?iIl;3`m?~szznzvH^{R3}z&5;7U8jE%T5;O?wOFQKR6%dQKXsYmB9i zto@cJjUIe5!sME2|FZ=YQAGNCvTjoJ>Ia$M>mk8jq6V`eCaWb!Xn(r0o9Q@z@x*dd zipM^AUbQ%+0qS?>0I%KTM>Tfx)3e8LAw0T6s?Afs7EoKKAaluw<1|}5ODLFLx^JdX zC_1DNm>O2>Ng~s9QsoLL^lm92>uKX1w7QJ*=Swb5sRD|$o7#+R6JcNG1h?5YZoUpf zT-Da)!zINHPon?iSJI2RVQeV$p3#4uXYMj+tfEMu_B&MHzPAT@Rp!I8o#R}P%c@0~ zpTiTV5DZ#iJn-75DUc1wB@I`hXK?`m8jKsxpSbLR!C^!lMw9#6BTB5q5G4i*iPy+J z)(PhJhvD2!%x1mo zed8Et1XYat5??S?F@#;}nIyeqc4hyqq|K)0tvY(uqGHU`HY{iAk~=}yH0mwFn}0{->Ld<#HTK^+)zgeY~b-5pb4MDKaT%$_ZvKrTtXZ&8njjhfA& z-h8wDD+4r>R_0W1JqMw26cLzUkVX75|mdw_xVu6&NaxZLMkMq+f_DZ znQ?Xa;%_IJgevg%gD0=OVCX$aFo|NrFJ~{62`%l0{idCWtJ!BRKb&OA*|NPhXm>6f zZf$cm#~(Si{GhTN58Yhr6H{|qX*=rY*=DHMG&}%uccnNbfgokeJ>euOX-^j^Qjx;r z2-ddKrahEf&g=%(b{#gWBF6I){x`jTPoeiJ@G{eN7*fnE5x?Qf5(3()&4o%YRe%CJ zhsT-Oq1uqLdUh>ixq$XV2=H23;~Kowk-|A*L}95RP@>tjRK4^~zL*Vy2PE5j!s|41 zl1O)mSqhABXNjBycS-aTS~8_GRV2%t&r$qvO!bS?a=$@KIDmfTG7S@6=K8pFP2HPz%CcJ>4n^~6YHeA7R8N{R^KhdN(Q6q?Nf0-?cSVLy4=91A)5LZFj3;I5sq6Il3K^jO#M$VZ2?W_DOKr zYyv>Cc&d$fRnV^`i9ZKbL~I=a&UmlB=eM{VE{L$Xd>1$1DfTpz3jJnStKM^5Y})(f zh4wOZRA5KfM?i}tUJ-?CiHfGXvdIK$vlLI;<_`@odnCBMx;sJ7Y{}@P13x3s=7`qK zQQm>i|BC_GhV~)d8-ABS6-xtgVN`5f%zR4B1M(k>afiTr`A{S@BF@~szK&h11@DKv z5t26$*GPmik9PuOgFFf&Lhim{$=UrjDZ4%qJply01u?3ay&1*kV`1zo6vB&#EKk7r zCin+Capo#1G_kfMefs%~zhZ5h+id0Z8tq>b1CoFE1IOIg=q((c5pi!6uCfw>ps1l( zHu^{}b;Gq2n%oDtIm-OSH5L5%AR$FBmV-~LUs^De&ftpSR*q2r%Vt%g(;?qL%j9$G znS?PmCql5EpWSuV8rkw7NYY+IPkbwr+JqSyxu2HUFW_$d4q|5|?YQKxfQi%{s54NSGBls&wS?F8g8g|C05=cT9aH=Zq*I`r`uk5T78%AFPmA&!j$ za+lzzy~jdbv9IF71z%;`+?tVaKLe>q3LuCK*20dWPDr??W-iRGYbFhyr9wDG19B~S zC5%{!TAkM{ov|7OQf?~#0;9fKxAp%{N&aKVMOce#ng@c#p<%3X9OSyMoRpahz~l7v z5WQJD#sWD@+|dXeEY(!W!7IGSeI6^pSK&CBPZYwrkc9uF(D&Fs*6PB=BK{b^<_1tL zvRQ)8Aa(u>m)lVzVb9hi1HL|~+-7J@tXULd1L=7aU5KYB{19C}iAxgeA4KMkO+9y# z|KogzO#J-#o@wOE`}8$rpQ-g$TzO#RTdxd$_jQM1tFr3FH6Y<|Ed>cHY`q3N%<;_j`ME#QQCd3 zVy9xx%IwqmO$dO>qA`2n&L*&*X|dH@`_fe=Pz`w#K`(@8b*<*TT1kDT0C|jc9hU%b zMTCeW9z^lz@|E^s<{tKX*Q}X_BP))8(4PRRgYfFw+!e=ih2Y$dpB5jo9U#F9*1CY? zzE0?Sm)793Cd}FF05%^K+SjkX!s>yIxVAffrqui2Xg=*hU_Z<;pkXHHO$iKue+3x^qdl(^E7CxXd1u{q8hVSgC{yeu5yD!$1i;+{fz z?|pp+0jVQz5<1zB@^I1F^qfe%{r(wIyH$vkUgO5A(hvz*ftUjLtyI9^%ws=*%6{li*q_(82* z@tM?HLr5^Q(EC1tO@Gc+@80W7$PiqHLyEAos_T3@yb+sNENKph38#Rwl*wSbT>c6vz`;s>Z2gZj84pXR@K zfA*S`(T(XO z!48Vn+uUwVai^nrc)P@O6BOL%dGwQmhsl>wNn401Oh#p@O_GSQqXevb@=&P$C+w^1 zKyO%`S(<|YIZLvuLgae$jvz+>0V;nS>dW+o3iG$$n*#5o#9fq2*;1e6*f$$C>@ z)93=b=RhOTmoHt!$`U-CPntnGLHp?8%{^w5zUcfG16Id9`jh6)5Q2PCXPX(QA2>Q# z2#)23=<=WMVJjhryC+h) z4(k7#sD|57W0!h*_`L%G9n%$lQmo)}cO6y;Xh)XKIGzqNGvz?cjvuHA)0j7V<+&@aAf=foX^JnfSqaKP z@GvDFpu;rbV=tH3b5bg){7D|^=atM5806kI2l;(28rO$Wau7~f2tJwgw{w$ryLEBb ztUe1_G|T%CkY1c^Me}u0rKTloM+|UT^26=|ON`U<$&kV#n0-iL&trIMemq67x~G+6 z^hD`E=G+c`P`iA5LXFQB5QFQ^H?+Zj+Y1k0KUCYP z2qsLDtMzna`2xfGsE6HivPlYN6_0`Tz=)>1pN7yI z*4>9iKd-TUnPeaLd@NDj>j!1i+BN2jCx>+vmB@rw+7hV>g#+asEXUX`fb-`N>%`3X zWyz0~TB*5#7aaHdtXT^T!mj4LvyEY(H&~jr((YIJO5(!EW7c8AgNAJ+{hE^RpS;j8 zQu-%TiOv-UJN}D+;c{smrL66j3*Jy$W^M7FSCso`AlKXSvy62uOo?0}|ITa;klT+9 zoPIK|6nbGcOQZn<*;`065$)vo9I1{njU-%T+m9d4@nf~=(uAI{Q>2~@h%UD|Ke(x| zyH5E(&fp0F6)9NiWSwzY_;5t}#iTt>9z+nbP4Rlhb=sM(t1&CNkD$xngcoYY8Tmf` zqWQV3ef<|JP)VPWTm31U@mgpxg}$;^0lzR_-e-&sBSbG1b$hi_i)$pq7f4(m_>83o z%;_s37$@2lY0Kl>JsoiSuK5_m7dJe<{MX+qR%R-V=*JW>_n{gmIqR@9R<|?Vo^&Ir zu9@0$h(h2CA5)0)3il{K((n4*dpF!?#%>pd6&7TsiucZy1CYB?{Fbxhl*oq+DsEEr ze9#3@L1UV-tgKi`1NK7YZt~7fhcOKvb2;uQywf_A*CwFXGyxZ{OnQEy4Y6d6k~ebs5^k=zthp)@37Qn>bVe=0eEzr_a9a3a{#8Fp5^L|rg@qC?vIT0U>!i`6yLb?ia zEp7zmEn(mW(4oX`SIloBp$T@YeK71W0Z(D9!!$dJK3ZvFepd=A=UJPcVWj{Shw$HfWyJ<2<*2jdbt3$daetA;1 zTl*I^PrgVzN4CdB2Cou~Ms_Ja1uCXL$;>p-fOn$>YVH zoqh4cJtFYT{>-eeJtOEv1N~r?-Gjyu9JU&89;+;ZDXP`W`Eot=A!~@lSF*q5j=lq; z@p7-@=Gc)qy*({#)KgZ^oUVs-R(piViE@l#!(fLv$UZ}Ft)=C4_5f%9SE;UX+54^s zV4H>t?;gB>_ifI3zk_Aj0*P4&!qua8r0S^dvpd|aHVg1Fxp(w08n*@L!el8~8h~7x zT$yYX#KKY@9g9pez6VF|AM)>NVGI5ADm66nabc)~$)QBKrrwVH8>TI@^Ici3C&d#8 zw%tr256H60Wu*F43Sugp)uj+9_eG$Kb&ve^YlT!lMfjSfR};yDv(Nl*rUOU(D$1pV z0BeE?WNTOn)U>*SlPQUvq*JY7O1FWpQ1;poif|qly6w~9R!aqdbI=7#5ixFZ+-oa> z(c1c!)8K(18m(!&fmyvJ55@V=t8}~Qs<+qk7Q0I8@4og9AOHGJ`m+3$eyC`zMbJQ( zXUI3Lf@d)^e?HX(Hi&XuRUXLWaJ=NQiq7J%H~U{d#8o^fzW{=L`$ezv8X9f@#j#{j z4Z!Ug#R{j9S`n)FH0u&Q{O)yAqcvMARv`s`-1T*6d4}zpi1Kt!G?lHs{m*sWG2+XP zV#v&6#^o8Hj(Y)xqOpe|kN56G_!pP_vhAa^vfnN{)zz*!yf-VUtkP3u6m;8XhycNv zTK$Y#UpGRQA3#}OYjO-t55v0{A~r=I_H5M2n7Ro|R|s}KBkxDKeF}Q;QwyoIb}myt z`^;#Eh^{}t&x;ypja4y2fwzy4gd>oSi;>l)*_hzXnA_$JA-}ea-={+VcUk{!_WeBx zexU|9?z8dRAMZcRzTa1{ya)CBiSeIKLE&ui?qHW$9p^k&#Mp@RpKk|gIhYdrh@he`5yhM*tpIcAiJ8=z1`eP zuh7caa+UkPe}GkJzuoCZX*h^84Vakx2;iKprRK}x15`2ipTxvAY_x@t05w<*KS zh{4R^f`XT#*2m=zcVP$fO~XH8n0~aP=LAFoyCWYyWQpQ$Si)O&N0ucPn>Exd+$hHD zA}PA|>PS`#?W*Xzgn6^5e0M7c_i!u5xvzkG z@>pE=@F!rmQ%R7(>U4RZe{*$d|D^6G43_D8_b}9J1lt7I9*IYV)83z^np3pwByN{4 zyR}$l=xZ$sz@B5)#>JrqaL+r`-@g|mOc$+&T134Uy^lTPFHhhiA=j(~qPdE($;f979D05Og{44V)oQR@!JR3?E7 zC8-%naB|B3^$q_KN~_wi7b7=)0VOm8VZrr}b|cGYPh?{Sw4*s|2S3>OrgUu`FD_y# z@9cpuad5B~YfoQ+B4!&_bLE7pYEfn-bIx%T{#VlSGiImWD?b0esyMg;NJ3hfZ)=_M zvhc-rx`&SsQfF^l4!()QrcSN2theyASH`xv_w4Buwyo=*7lT!~lUQA2)yUM(kKCt6 zSE4UgJraBx=S|Nm2bx40i*B#QEckx~>*~^Grm3*3of`SJh0l(hedzOI=dCPd*f3ge zLeESfH-yXiAI{7>$Tqt%7&J1#Z`-)7y1i!x9C=a?tS=vZ+$;V(pQ7Av_Cs)Z;KYJS zWc{iXbqocvAmegbksv5ghoG~n^@?wCDgb@0eAxNtzJuypunYV`$|R(UWkzsvCPYeC zLOS_TkI^#C%%@LN!M5NNPv@7Ck*RN~4^8dFq(vnn-@8WEf*ZUxld}b?DypXL5tC6$ zG0|joF|e&ReDJ(4Mi#yDQbdN6-ny;yxM5)LhfzBHK2uIUUml->&_R_WC$!lbv9RYB zeu-&d7i+&Vwocp`I*Oc^IXiPGt?jg?(BtnrTfH80@I>SRW9C2FQ@qf5y?vI{+mhs56z9JseH$dDbHv}X(D2PIx~HECGken)27YeI8>?1oO7_gS8Ol- zY0p&e-?#_Uq~%4K87B^c&pgT=sDrRg`8bY)>xUf^(%Bi=z4qTDFPa*7`1>DBQ0jTh zn3;$O28unuwkg_>zi2_|PZQV_xxSQTRIMeqO15*z1J&qXQc}wf9YnExKKwA#jJq`V z)yVw1LBs81VE)+g#$T`VxMTeiXQl%Q3Fu@bH`z7kGR*~I}{(dGk-f+R_|zM zBs4&Jr3o)e1+C82lwi&rYA<+(-*4A*knVl`(4R#gWf<7CI8Jc?BIC!R?|K^3F2|Ri zBlNruCS3HE{#+r3U?=CKEIQY+auaGGW|lP+l<`%$m;BGiMuU0#ey2C;bOMpA{n@Q7 znMoSPy$3WqoOKDuXO&{`>=Ys@ECLF2d2K@Id?R`PXq&HKOmK$`hNN+Qw2>pN!)~ zm*+6AtB}VczJl+7+?fYND5jc`q&=Y^eyx8wPY>zIU3_9E@Wx7UqZM({z^EMLQWe~qE|l$lPgj++rAzesipfKay|URwMN-7ERZ-h zp?c#z+Zkc#=Ufc!)^0x$w|@U7_$@E$OYTa`K~^P0ov3g1=fnj_gX^12XWRF#mAAE4 z_1Vk|SprTEpx)Pr-v6B?Lh{+e4_1c)grw6MI*xtWEb{a)MbKFXcEa@?wX20vj8Rn-oB$$yKp}7tgAR%vcAZwN3)Xx3>Q$J6d(9Pr3 z9dRHrLEd7~kuec>4_(*D@}q;Ol6EWPTPghHZr0HCM+3GtyjG1ei~`wdncb@tB2ijZ zEGyKs_9iJ+E2m|5jWX4|#qA~txaS4#3@x08xeuN0lbCG%#R zN-xT-#yzU8)^+I3O{&tYBSVRjmV8fwmq(t8vo+kB~u8l^0?p*J9xPOv%ZLwe#6h)gUvY;P~C| z<{ew*m^UMxLIJ|v(PeeqP=IwtDpF!*)sP`!6H))piRukVm<4@PtEJRoQ zD}AGM+VsLHj4u!Cgn#3^;hX(6y!RTXE!zrR!y=!xd{N9Z+)v3q@rK!-7aWFL6+Q6p zM^8E67Ee6hYGd@n=k(*wmz70%C+@h-u1tS?y^(|?h#rxeoR0oI-TY7~qX_onqB+xB zsh<7C>I4Rjo(8p{&|5ZcTG7vDwvUa3QbRMniX5<(41s2SE1+F+7F0#sY%hrAN9HW! zto~>|V$`Z>an(s&n%#BAE_%@(<}a4x7E`oFC~s*5jE21`>6{=@Idm#5I&0q+Hz=px zT%bh9Lv0S`E+Y)c=HW%5i|)!S_RzAr9u~{xn`tKX7%7JtO3Aa<8s(zy+ZmrDdig@Q z*Yp?9${yq;A8?ffOSFq(ddL+>iEE&esTFN^z+zr)JkqA?q25w)|L&yL=H|l<>;1vI zp1;e5hkhUCbSuOL5xreBQ(cXITm|AID@+?rPmN>C%&zMvdgE(n+Bq61*$9N z9W|nZr{7b((WqUlq7*5h^m>&Dk$1e!? zouN6;I(Ce3ucvgaKM$E4;67jP76EYY5)$i`at^>@C@kx%D2M$Xyu)t@t_0r^LVK)R zoK+Z{Uj$5V%A3@Alw(d84zOHr0|kUFf^9ZFjuF~Mbnt1Lvuyj3EhdG7o4FmPs2P0^ zYHLxm+_96;w?m&q?Wf9qGcXlv{PV%+``e)zvIM*Pzi{-zcFoPdE7o+^G@@Ix>3Zep z?b;_+E}-o}lXsiq-8+hnDooE*9`!7MPYqtQtL3?w)esurTJ?HW#FzA@)gAsWoL~GP zwe)G`qyw3;iKS8O56Qw6<)EX(W>wLG`HI@>hpEy5WFc8pKkINA1Yh_?sFB{ z_U|Ojqj5(E-mA(N{@|{F9MoLhV&jbMz`fh+R0cxGm#7q4V!fk_e$MK<5`C-!Cz@d1 zqXWhh-8`(;7=!c;&YKj*kx-MHB-pACHoO_sw6}vQB|2FdT z5SwLdlyUReV5G`W?|69s>x8F{m9q`{2*6&zAxd;X)@Hv(@I}*Sj-JHJ8@)5k{x^eQ zCZY+Vr)qaWA!oztmcGETjiG}pUqqUOF{-FX_qtuXl~88%ZmD}36OxIz*!B&+yEuA2ifT>NE<>tUkM?+x7htGD?DeuZ=E3 zVv{p&T`Fy_J6=NWb)Q`l9fp0(n8%>E^xG}sTBC?M3q?dO71OaBW`6n8$g5V;w5`+R z>(Se4bOF)FJ0r(~Jqh@46oQjE+`U%ddc#Wk%5N=!ih1*mzZw>O|G^`m_y$2&J^L>} zeiF_21fkM}fdmI+QQo~B+M~IWi=G_c<_ciudo-cm{zsLIw~>ef88sMryclW5{ED0^yeGRK@n@xQUP>X8{T)Te0Yi6{ z>G5wC4LktgudpTF8nd_`=M{UO9CL+&A)z}=qT!y3LJg&iZqd)flXEMDr*39;N zmm7N+>BRh(-1^5oJTdWZSn&yzKyaNxs5dnvjO2Z~+;Nf=%1Eobf1pYIv0m*|ZnPWz z7)&`V<=4WTT%#+KTo{0+MnJdgF!A;>>aLu@-z}CP64;M?hvqqGgy@ZZPN}FlYtPuZ zfAw(7@&Hs=zNcWhIMLm9IppUBiPAB~(U^Jcv`*_R0}s_=NNlS(nQw>~j+FoAaiM}* z3agrh_uTvYx7=;H-urHP=S*yIkz)g{F7UXiqxEQWRvA!w-SLQ3;PeXQgpVvWe&Pea%xct)^XPXB-(q%3i=LvlT^x$%5 zP9`G~#6O$GPS&q?+;-~y1?P2FMHYF^a%@veu9|BQ4|a9o)1r`H;l3kc|1p`Lp3m#} zM+BrGR8#`K$z-R@fH!LYF{M~AKWqM=JU!+4%5Agd(u|1F>KgJQ;^hlXYb0^5%S-*@ z7V6}Yo18n{cRZGU=ObY2qXS%B`S8WXYGvH(eHmOG|D^LuLk{1`4}OV0%(5KQI|n26 z`#X$uT&1LdhB&;z>&56kvQ=kHJ#RSup*~zkAVz`^IGXBL5lQ)K%ru<;=Vcg_Ydlo7 z@YEhxRvzDK3T=g_Z9*H5Kb9yXGiHNPj3P?Hva83J1Q7pSPCLu(A^_9=;9!+#A$*MU z$O>TC&zVdG#y#RNJ|kTk*D9OmCMRgv;*U6P=X2^8TEYi$p)FN`r6|T#LJfJUU&>7a zORB_Go4khkq%nsXC?IP*X{&r;8SZM+@T6mmJyn`WUD59K_#)^j(O-0qo4cd=IvmWs z6vP>Wq(UmMu(Kro(gKVG4#2EdzCYC}ELM#=(R;?y1c>x%RVEZ<@s7yvlgZiix}tx| z+!C2oy!pgBwx~6HzPa=d&GF;@Kytu~c>W4}hcL>~RI5ShFHhLmgUGv#eUD==)qF+A zL}4+Y*R{2br_PJIODVPwRuKF1yT)q#%y=h%yD&KJ*4GVB`T*XBoo!)H@Wg?7csWm3 z>Wc1iz<5gzLGBrp)z;(pg(?@C+%D}g)#SJE~xHIb}5y5<#5RF%JS_P&k(>|s^U zFvEG15d7slHQZ3GSu%Q_50^xa;Tu6(siN004*x|8(~+4fMdQhuKXfXDY2Y^YZEnJy z?2dLT$F;&6Wna_y$NmeEo#!uHCrc=OnQVFRhHJ03^Bb4~z=(RZRbAz-)Xx2-E5GA; zn|Ys{X?V=+=I5(+%*9oM`QF2l?H*G^Uz%8tOe=ih=JTI=BEi+HA^REw0M=||n_5U@&l_8ipf>bw@>z4lfNbiom&CC4b zv;gAxTPOK-1f~4?rr0ix`~xS*C(f<>Fp1uf@Z!H_8Aq?We7Sn$33T}L^|z~3ZIZz> zIVQC_8RTKMVmQPH#0@Vz{v)oC^uxhPS*TXZ^72xhHA2)lH- zBR`~|NjfEc$GIxKa&3WA>`le05O%IOAM}&tC+&K?&a-zvqrRDO`BSXP1k3GR=7*H& zerf$w%KEXr%!ay+Z-j;V>ke}{dBclXbIJ%#Vlb|+Z{&SJF;-`2{@qKHSwD(-7U4oN z@4wNf-+FRQvm7d)>M$$nT!kCa&a(+e-a#^FJfh+RBA_*Dc*)fv$=;8~h975EK7W&N z+SqpQKHvI78t!uDo$_%j-(49vVR12=-VvOj#>FAlTwdkZOLMn7(P;o_A&p2Z+i8F| zH2vML>nhyjle`)2r(tp}yPx(`p`qfEe$D@l2K^>?f>YhhWt=R|S1y|E6c}1%j04ne z!z9>lf5A;}Ajh!=i(NNqTYd-CUz_C`KGyvgaJyukeme;~&8UWzrv3WW)2r_z>73du z)v?5SFfkl%Ru zZ{ZI<$ay&D-o-S4pHg12U!V=o{b**!=2Pl8v<$$RiT_?&Vk3DE_r9pDd$!XH4|G_m zj@~WACUaayf;r)nkXG2?(Fdh=!;G!hv6NPk3jXRs0_U))8ZSlvWH^ERa%>xrO7Rqz z0W8~?!aSgKTn_03_!9?Y$ZKe~z5(Pyb5oBZUk@%e=IqmNRmqcYMX6cPYT(MYjEn?4 z!hkWSIoC~@UyC{wU$?YGRQCZXK~TNukCw3WbV_EAEWBYH?w*nj#h7lh?6AcFIxIDa zEZu7;R#N45_!F6K+2%qr_28T$bWNtnwC>cq-j%vISlItfp{g+e2wJKg+IfpI6B+Bw z=D$Aw_y}|)d;J)BLs@p3Zg0oO=w93w8RjqfApvt1Z@D1)RAW&ktMH}jZ`sXM%u#Ub zN8R;KfZ(c`n7`&Lp;|3U#dD)Axeb|V&i)e0V|&*@UkkE|=mV*1&kroI^N(&fhr?D48Q%aUsmMil-OT&L$qXX zgs(#1UqbMba~_N`{r#m0gJrvFWPZ-t`7Z068OAP}`iCfe_I1@>m z>|%;<3QgY}Ji-Fjr~7XWWyt&qw136wS?9xKDSmAnTbKin&FBP1nes&^-btAES1{%t zCE_wsQ$jt@@NvSSKUt4QWa>RXz7D!wyJ$%7HviOKc zT;%<&n~wK4HMx9bf$~7d#S|NEd@axUG&`FfurxIWs5kL|xs*wl@;!$p`Cr{PHaG;@ zheyQ4pc7nN9lpX`^O&7XadSF;?Z-J!1?au1!?zBJ22w+`A}I^m2P{y7}Ef zQZGln1Ma)YXrVeC`x+XXy`cFjEhcdM10$(WRKXbAnfm628TaPNV$4yJc_G)ffVVP$ z3X~TTj(2DGI`tsajR4ysGrxz>;oirMXBop+^RTUKJS%nu*%1~?Kg&Oj;aWP<@MTUI z@$6;DOF-kCxpx~1MCtin&pI~!+k5T)`KB;Kz_7Y}=#juVi9&7n>~kGnV^CetX|wez(>~j&smK!(b?VkwmXe zhwAT$1S1n(YH=*DWF@~EBfh+Bn~MyyCF!sbBbs;9@qMd&@B#g}X6vV@($PE4>n8!k z{>MeQdevsph&yP3n6cj=^Z8v@K!kx}Ezulchz*xJ=B^l+4EB$>Er?)!OWwJ|dU0!7 zAJpV%<(B>?Vf*hZNCB9riQnVlPh4#U)}qy`C#@OB}0DZgTxw*bHib8<#T?CCgP zXt<3fMh0@ejEU@%)6Hci@2&M->NNaN${FE^NN4)dCY!x_RL{I)tQF7aWAk7aH?Yl? zFP>`*SyBioMmYz{D_%>zK&p8yZr-|8svi)rUNOeu#R}~CmfS<16-82bb=$mflhCS( zxc<4IPqQGtdz^Q7etr8BNVTf=;Pn?-Q1Vf0O^{VZ-dM!ge}nHMvEJ1cu^5%)kpn67 z=gBwo!p;6_=@sovStt;tO4`tRcPuQ(eVAe3zgC4ydyqO84~S*JjjGYdw{QV!ONhZB z@gRRZi@Qx|SL)Grb(pk8#5n5RXoT>(0g+yNGYG4UT&$Y^*RO;1HjCRou9&{pMA=&e zyTKn5C|G#~NWAio&@+=on;EyI+acAy++1zX@by?Rre|v;#Q;BrE0t*IyK&;g7;jT5 ze8x}KxD=%qrc-IWdmEqG2OC8$|KU}DKFZL*a z_>aYXk#OzCgS;?SW)0*6=1ygv-+AX#zxp#VV}66x5^&7RCaGh4pnaTeBF2y2bgKvfXu0nIk`as;q4KMk&QDxxm9iGYd zvda2~RFuGl@Q#4~GeGg6G_+fMk3+Pu^pn(T)x?wk4wQ0gvYkr(DuoW&OX6=lWEh8R z%kNletk=JvAFl3d37}r$rm@TG%dQzY{JU&m^j+v?DNRG?DoPudU;>x+N#BMLS5v`u zfBs(&(lqUy$}l)yvVfladLXCEb!Di3|DvN5PW%0?1#%ovvnCOQYEHYJeO6sGMIO?` zvkJDZ=6}~ND5@_{{spHEUCnu$MUsox!P%8lt0T;Gd-LZZP)#N8nMNJL@Qlgzy8LLAd$z67R43>4E1D8VGw_}?MDv7R zzoG6nLQ%blpj737UgV6gJV6VXN*CSv8vAsnNdUI4tG#SkA(mErTktQ_`WVpmUUN&4 zA}*+XGA_;T?p?8lH1sjr5pU-nsN{fEGM{(4awJbsbca}<;N1Q@|9-5uW}7=v## zMh0ekA&oJW!_lrC8JT07!Ox7@l%(4071-bOJ)okQKvdfBimgv}`uEd1 z-`I#it!cDNkZmNN8N&k)#_YV3tH16mV8A8SFbkg&Jnlz$@;Ji&_=11a!o*9i@u3TC zAKlLFvAOoGKYqj@87nJZ80Xs@QA5h!%2}Ro0txG?@n$#5vN&kc;v$zJ3Ka9Z~Zee0{L1b|9(-BcS-rQ$<)0{TgKa$V5*2;Zbr(=k}1kHe&r z;?86}Zu`C7eH|Pst~SkBtINi)tSEZ#p_SzMJAP!ZDlS#WMf1Q)zk+`R9hs;$3m(e; z6EN98Pd=EFyE_J$up0|9I#X34bdV3dD*50>8Wsl_-^vfH2*0Aw4LC9ETFx9_epd{# zA`JAI-UH|5d!A`v^?`CPohD-9S-DAm!1*j_I9d98v9(fMVOTK^Tj5>5YXKv9fRLPz zDZ&QV@#@Y3%umqA{aITx_JCt2WtAsJb)?{~6OZcGO1Uyko~6L^ck{ajmTj^EKM!r# zjc}udUvaWM{1S1Z$!tMHdl_R+ZrIp1Baehh(5IDH?hhZIQ`!&G&jto*aohoNDNSnr4 z3XCFM6`z9MKj@fDfzM`gaS+)R1^;v7kda1OLBm1SZ+uP#c*jk2Ce4qX{XjV?51s+i zM*)R{)fjIG)vwOxL~CAQ#Zh;2VkHiPc@4{*YME1p?`oX0*Fo7yCqHhkcd3PFaQu6g>s*h9U6YW_j+mb zM^W)0wyZOOFy|PRCc52l{E*?jlc|1!tGMK+@cMt+mBN^r*|J>6!0LYL^0q%`|TL3gOoDolHj#@2;oa2NBB+c;>)Bk=4 zJhu_xtvlR&t`uIhi#6q>{y{0?__q5yE`O2LSbHK>t7Ytz0Dmp-nmhhI@E(ifa(18Y}*QNyyoYOSW;Hhez#1 z2+YhJ=&b+FquA1Vn`h+5%^qyWR^G;6}xuGpXl?8h-SaYMo|s0R!(I9Z+ko9 zc<#`TU_pOA6msq$MJ3*`{yz^xbV+|Q*w=04=W@08axrM-|DT$6A%=F?{uIMd1istU z^1DpNqh9a)WWGENBYSAS%N6}>cw5Tez#slp1?!n1>DEq>et9Rz>Jl!13(BsNXPa|J+R4OtSqP3;!Bm7)#1;$qX~?DqNL;xH7&&W=`g=oP8yh*^P@*NjbsIfPwg)(MN! zYK{P$G_q~Wt5Wu=?7@+Z7nuA3V_$!k==a^@j{+h^be6t_@YJ74=F;^5Nd5*QKDP~)xKS$qJOEzh znV1%3_NZNWs!g`QMmu|9kgpr?w4+h!CKzq>tpcv8S}OOCuMCtOO_BpaI_Dk_37LxL z9{PJ0d%_RxNtBU#uMmn;KU+xvu1Iqi1yB8(6+r31G6VFwrr!P58#OgIdOz`&unyRM zjcAQ(7Y;^3Pq0YZXhfVr9BDH+?@jMP-#YumD2V7@ks-PscjNy{Jl9uY=_huxqB!aL z_oY0p7(FgAGtiFz`=0RwF;r6kn}zH*m_Pic@dbdtNV?<@1NTUtYs>T@yz3hWKD83* zdY23E8JJvYRaIa%jB5b%8JB@)f^z!EzB2hNfMs27R@2)uA3d5Fw!F;2QOtt=rg?Tz z8Z9@xesl|OUcn@PANq!)==EN@MV1(0$Bmg<%e9~1VRhJk%Xbv|*{be~G9tBcGHyk3 zazXsJBVCrpZr>(w=IUAC0c*ePVC1i*BJoIm(RJ5fCRha~YyC!fxgBNkb^mghA#>#q z#zY0#_J1xIkt+fI`Oefk2Yw&OVDb0oAJZDG>)(rr8nSo44-zo1{To@o$WGQX!GMhRF&|2k;|pJH1-*v7IJV0}8VmGWFPM)#T2D)?D? zv!iy9$d%_O&pplaw@E*4O231F2n}1qMQmQ)l)4k1e4&%0Eck_YRS@}xvCq!NKHNM- z{+>ruGPU75+nKB3waXeScW^-I^|YUE#xK%M zGV&s;!yA=A1anu|!Sg$-Pt%jow6t}!(go!DG}u$f=3}+gpv3YbL~r@K$ki83xh@g= zivR}Qtd{??vyWDDEfK>+?XliraDuCa$^XBAou%-z6_qd8S&5|oU+KiiCoba$H>S*6 z?L%t5w!L3_s)TEBZk$|Cy{jw;ImZW(1PAxuI|EsD?K*Y#NC6hoCreZky3x@W{v~S| zQYAwe8a+Vu^-k?S7vD=O+bXxma1%erVG2mr_T1sVuG&}oshM!WXw4z7z@jwRQPNv+ zXUQz`;%{uL73=ROQ~BkU824YJqUrkAt(qJoOx||>W+p(KHF<`z42+Z3MoUhC$_38G zylFA@XTD!C1eJi|Pr&j6!V7&&6hn0R`+r?)O@4`%StNar66KlBEfj z2*;Z(`jb!hjjwAt1u4>-fW~|EUp{s~OgVXuzX3hdl-X$~};3qOKv;}P{2~&1hq$EY`$m_ciQUstyhn_#yvlBk} zvua*}gLGpdtV&7BBU_?qL;h2ozZewbS?G&#+AA|Ml<-l~!u50~hW2UTQQ&+1^Asqy zAuk8>ZS4A@c#*i;PPC+_P|DkdYuE&{A8D)pi09(|%xkJ>U-<0PMVIWu!-3(}& z{-|rcFG(z3Ki;$#F68_|Tc-b4AUU}E zQSKR}u$e=-F-YYIbk~&k5d^y6ynh0|i@qJ&&tcp~bViID?WRm=^N{3QP~X3 z=zraXP7Ql^v4{pRNB~(_zBo)eGeUO|wuA{8=qo0Qdl>Avn#VhXxwm@UeC)e{FMS`F z1bsOS3>zrO1} zST^)p5Fx{P51Rjnz0iJ+g6%QdEs9JN{jsI&=hp3x@_0{_TAFbjMmr4X!EI1cSHT9b zB`|I}{jKMD$dHB&YFE0xxwul)H{T8HeyBFf^u6;s?j>-^hTiT3x&1U2cwJ+Gb1~2+ zJU&;YACSOcgi0WOveHrNWvS*s0;Z25-z#f0AST&Xl zCg2gw3ZNUl`L{kwcbGkUcXpNU?r{VgHJuOksun2wvy=y7HkPk#5~xkDoqhHp$lTN^F=;L8*|4)VCSinW+W8)i+8xQP5&26Gr~&N z9dQQRc5^w}B$-Xrb*qe;1*31PoAuvneg^{nW6<_sx{Bf|^`6G60RW_>=)V7uu$o4F z>q-D8cPD(nB+q{gQwjk91s?#=eE%QM6ad(*f4sT>9ZD)&gFM<$uClY{Ex7^tg&sO` zwCuz~YV=_D*Y;JIju8nj>Eq8dp-g;EOzn)R2&rmHsgA#|OZURhKklIAnI_SN~p!-cyH&ZZAlsp<>l+UO9%z5e+zrx-HK)Imo z=J4%T3lYgLzeN?T4tdp{UYzm7QZXcum8L4bVPRLbVQZ%=_8(twBFy7?;WBeapCa3- zV5r|j7iBGovYKyhNt6vfR~d9B!_uSD7 zBQ`?my04`fJ@CW~^hUkBzi(y1CE0vJk7EseUv1q8rk|x2MQ`1zW^r3NJDd zNQ-Sxk#fdN{c(B8`AyuR;`+`{UN660#oIwkONOlm<$6bd65o%96yN*mfBi1TcVBMsKjBD%d7NFJ z^F_JL3Tl`BzRcFkAEnQc%UXpq$C=i?xX2W?FsmHg%jKM8QuHRx*X5%kfKEH#6WNRj zGK8cb?B&ruyRBkWaMXyWUR1$x4&1poqH_+$JN^52fGuIB-5s0r^8y3$-c_H03#L2e z^TU)Wxc|ug8#WuG3^}L-&}1=6yWyPG%%CvR`Bo08Y#PjxMp01`%7zz;#m^_|ET@(- zaCcStdlrUCD?DQha~S!)n#fGk*=aHPr;&btM!i?IR-+4f^mJ`BQ$pIas3m^E{zp8M z*W0eQgVU7~lA*cjR(uRjxFqCvcd!lCKnG^#=c#v|WxcuIMQnKFDb4JM)>p-d#UI#4 z|La{;Rs64$QQF@AMXtg`xt~Ikz`OiGsZ2|B;ZC9(HI(bQJ|fk5e}+ZaAQ|tg5&tyB z(wDrv&lpP(Cy$KG_Z+e(!?vLa+la5CQT7?saZL+69R{5D41zVPG$|J&=fnPh4+wvo zw~4YfRIRz2fP%lUx)(b+f1V~O$ncZOn|!%LKB_tP`z$uUn*qH$I+wg1xvw+tve=*T z2@r>W*r#gt?Il*f`J*W0c*p(x?x3R^o&Gp|$X-JRW*!r^+4FIkF1e(-CwX{SlImHd+aD0p587_|E3wddt!toQ5RXt`20 zF+{@WPK6mhxanZu%>h(8pFi%5yi`9v`pml%3on55J$JGqX5C%r$b-ws9Xi6(rqUR=h*Jw8+h4;Y=u^i z)oa=Nd}~jZ!&F_D>cDP$#hb2lBW=FYbR(rL7nwO)61D;ruzeINO+Rrs_$oou%4$PF zxjZJOqsshGIWU3Z3NuU_%V9#cHq3Gl%U$(WZ&;xFRb|_=$sY!GOON5bE7i;p7O{`1 zN15N@il`U^lWY1QD{Dqs9>a8jxumbbpJD`n5G%`x@x6dZaull8Yz;%^Q9z{Mqb9N? zDcEtc3A2v#V*+sGbs@N-)7z0Ok+a7xll}&huDkY$Yi-mbwUqjT!veMO zgf^pF&J?&Z0EQD`oR2|ep$G0*~&f3B%8nZoKi2ADf@tt(nRWeY=anYaivwRVT#w@aO^gP;Mf0xb%dMsE@9)|J(_>ipRJA}nG zf@qKM<(X}H*@DybQ*h0}X}9UWIBhW@ID)jnc(JO#187_!yU%5O>j@_~8&12h=>#<= z`D8h?<)@lg>Pm9LYu5+A@G%R)UmY&x3)36(6?nO8F_rV?3c{T%z+qFw zTvVtSH8BCrrIXFtubidN`*jEN;=pSq14gnaC6W6d0NLfxJ4)f|4_>P5uSN)7WU&f}4(_{Q9yuh*gHzbhR6n{FWW98(+U!beneWs?W#0YT*3mKQ z>TO2fXwc=wg_AjaadQ^@Fnh7+lNnkbmPeFf06K%^QxHB0h*@RrL-vSi&-lQaZFV;D zhV$m8_i@;f2Sfxi*^-xh%z>5m)FxwZ5K+3+GVM$M0-5fA; zQBEd4!5baWPu23;J+I>I-(Gg@r@~Y_!Z>Lo1~Ij=C`fbG1~v2g{p)V&vTfpzwhP)- z=-vIDw4LSLnxpRd!H3;8R?}_0(`Hsr!SBpqw5V;qTuYYISn@m@T#A1^$RK3=La3`X zVieK!BxP&6(9!Pn-c7AB{~CnU7_r&{mgx^~hyz~@9rX(1I9$=kDs;7M=>KPDwfV43 z){&?(TT+Q#zUMyIYyAZPT00xSTfFT6Kn5$(Ci5qQcX@Pr zy)0C6H=8sV%UI+1pl>@XQ^t*u5iE#yJSr_ywWHvC2|^(II~byUa6kp15>o@H=_z(j z%g~7F<1IB*vVKevSLIC@4BoA3l;PESQINgb1S1Wd1Eknu13nC$f5N|GE7rl>O!yJC zJgG2`br+u@88EO!E99(BbNm7Jb_-e@i#52F334)e+FCM^b5WOch|!YcrA-*ztK*9? z|1A9QD2e&_3AmTnD+f*R=D%G@vU@kgs+k+WTuOwt-W!K<(I|S@(_q zQ-dJ36`h=b(~Mf%@PkzFZP^p~Mj;nB0Y@PRdxFyhkH7f$;0sgr3vA+HFec^X+9rNh z%GyGqLO`0J*~j9Adpm7YZMy>oY?Wrht1p7LR`VT(w!i)9E2^ufJf23ZfJrmUOjqO-tLKVyHc92FOT0$w5@zr>);FC);X2W>0=&9-;2+U30j5 z;a(af6b=Eu)Avu#`e&Et{#$^Smb)O40wW2u8)EVGvlXmc{jUIt+&_ftx;wuIujzG9 zNcEFQ2%aFXiY_v_y4lmJ{ap1P9Ntxsj4=e zT9%eA)wdxpFyXQBLlx7^_}oL=2Cmx>2>7@7{A)e(`A=RvvKXT5@$A6PEVr0>lJ@|wl8&zrottio zp+XURj#!KR8f+dt9lUO-FCDivXehEwAiL}k?V#hH$F{XF@hIlkT$QBn@gS4C_GX9y zm>01>3lWrT=*k}IzZfkI?j3DxDTsFx4q-ztorV=HAY-WmfL|%H{+?CDrp)H+raz97 zZ-E~!jPSszt1D~T#^z#Dl$)Y8x2{u{%)2--V6J>SC9vH6TAtaVZ zwV%l--#|(F2J*@F`E5Y&pvPu75&IRA&|YWu-Vd)}-LmpC_lAIEbK7I-n}mx1s+Mfo zvXVs<0ya?EYA;@A`b`D*n6>16A)@#e?Fxy7ZDv~H;19{EvCR0b&*xcge@8eEp#{5; zTAF?~d%8qmCJodpnqbw-$cptOspiAME9R3~X;dd&bK3v>cHfwuwbY&dgNd-R3|yfe zyOXFuB~sf~sXq`RBD*ke_tHt!w-$I>PPuD3Lxtk)p`Od zDOkO3nP2mO*PM)u5<<`Mlsy}WlhNcFR3?!%_sy>V9;r9lYxwE(r3CeUwckRC-3$|55 z%q3g}F?%RwV*dDzKSL@nVPl;2x_EXDCWRUG{C)R|(Hq+~DDlp{q@yJzBzw`Faq98X zc4Zw8F@HC_L3L$5@RO1R9~8Qb2Lnx!K}R_R{H;zR9kpEWo`s%H1y#4kGEo>>j0; zLQScxpiX3mNG&k$?O)zxU#!yyi-i=sqh>sq@oNLK*YG;@Q`Cz+*Pb zBrmrC4^G_8fzNe`*Q6VmD%(H(<=MQW0$6s@-?A%xmd^;-s9*WTeoL4UWQs?fj*fpe z0~-Rg6XhCyFGi9YWMSb=KBt|QtoVe&_IJ`~lv(!GmzUT%TvU9${A04@y`A!5d&$13 z37`||Yy3A}0`~V+rpK&Z>ylE8K!)E>rXM8b=qgimmT~LOk53j~&OX^cSS2j@rH#Op zwsD&~A3M4luKz}DQB?`;U3K<#u!Fqy-Nb75tqwiHh$xuBdJ|D2!%k%q!!}9Oo7o61 z)lxz5m0tjMEa5lN%q`~az8gOKhZJtyzm4wa<4aT`Plx@wFwq6~^Z8pTq*oV<*{0~6 zSr5%(jms0Xu*~gl)!vsyMFmGksGd}A%WW|valt?w%!vdbc586iDB6DBUVr*^t^P?r zn7m7rCqp}o*v!y8x2Tl<3Xi)MbYTj9)krREh-#bkR_iFho#!$(CdJ$8e*M-F+c@;- z-)Fg}wq?5c$G8g~I;jq2bR3-Ov#T7_`x5-4)O+HuPc1^W`i=NAwr}&ZcG@Hdq1}w8 zflxy$@rvelb19*>q@F$UtLZhb7Ez>FELAd|_F7^OZ3;ZJeF2@b@)MhBBb)Q@GUpq~P=+`2g4*ONrZ&W&e#mFat~65cyc2ABBb9GY%z%omeg|&x9thdyk~B6V3qX7nBKoFAs;6s3HoMZ*FtvB47a%jT4nx_&AMRan%Pxs^?)|~;g{rg%dGL@YgDjx zeq{Bx+gWvVH(0KTSvG-3@b5)-an}h$6!?tMy2(4 z=Se+))qneK`+8EsZr9I95HS2Y%J;wlhT;>Any-Jn?r&+t2>3!B9q*7C?KpD@?<>@_ zLHrPtV74&8j1#;XvMwUQ+i?xkdpeX2W81LH9* z8G)L9`@RJ^oS^)-`p8KZU?x#L`m07eY9`f^Twv&1RXbDR)Mmjv9muojULNvBY1b%_ zZwF2@z~rrf&AS|Bu!aV#V)dRj2hgA&3-Ka`QkvNt+0C?zh_BU2_x!Y09sa~AQC>N0 z1y$<#i&OWKiZ>(?gr_RtX zU*U>1_eMgFU;Z-QGT$+_CPhou06y-xpt#gBlRvrI5(PEEEoD!4@pfj^HK#iv9ee7~ zXKK&Z4Vi7mFKmR-k~mz1tVc!|HwlG7>x0JdPRXZcBuP27JV>v$P%y;lk+G4z|b zMoO}AdpZ@Uyero)ge9*cx#`Jo;41N;e^vVJnIK=M1I#o^Q+TiJ$8R0PRWzpQb)-oIbf(*Fhn*&RyheAkyZM%6Z0AGZvS zzp-)=UNTp(P%GgK$vcS;K>ouG`BSC(ihL#L`0JqDlc5p^;=G$Nhsa=118(65eOvd! ztX(8&3ST;(=m2sr1(O^9%6rSk+@Ng9uMjS?Rac?M>&1dPjv~#w-{cv57u1)m`+3he zpTXr}XXuNJpO0}9W%wPo=YXR0-?DD>A=^QkcKHsBy`Md7QclY((omp<=(Krjjmt{?af#}Y_k(JS##k=-o+zqYe#Q||-C&vH) z0yD)mt&8zJACJTnN5USmNg2(H&+{J#TYR@<`zK7zQ~cUqkz6SoOMHVGX1p$=qf&qEdS53)qj>-OvqTp?!q=UR1Oe{*|$f$h)>2p z|721&%?lHbala^o#kzctGlp@%dJGW3 zKIzB}S}D5#+K%sxv<*-ml#?;X;wv z1RVaSk&3cE3Y36b<;sApg<0BUOE0H04HLkVt=(v@?shH73uC1m?AA}WP0oJmy=!&-D49bTE3mB*0#w^l-D|Lf40)$x-sAMF zP^jD@xlAA%Lc1}#zhQm*c^AXOMP}Z%iLI^HR{JJs2S(VwX=*X|FfXJyUYf^U8&1%dANj5ic4ve zx#R@00_hoVV1;Xtp?l zVYjZ(F8Q#&HC#AZeg>ZJfMLjq@TLP#3b)#~;4#=?6oGaiT!ZzzK>S9;C>>3Rj&zJ| zYfq6Kc&%!B;!#0zmdVOW}V+?sI>4!u1@|8|OOG!kb=aMC0sXu2SBk z&&wQeJOW0)|8%ix_dJIC!7GisN9XtMWQCVl>!(`M*#xO(W3uS@{AjN0sP zM|9d9KPqBiP6lfxcHB-=sfr(d?R{rKMv%9!u^fSdX-?KWO@4=87o@PGAJQPw?4k15 z4IGJI z{*_yl0yRGO`p)*@sfayRxM;KFXsbUiFeN-zrHNc^l-y>|!()$s=aDY)3;9|Z%0>PJ zczgS^F<*Wnuea-b|ICJUQQCilQHogMID~7+w~kmWoT5~o2eT(%TymqtF*c5)SG2T3 zGX||QMzUj*SnH2X{SJjF%r*!(uwiA~_$;Zy4T=KuFDy-}L#c}TKslshTclh?q#rg_ zmFboX`OUtVlo>QFAr-=YZe_}I-j1E2j%izsc#V$0=)1w2K-x`Q3a%j-I5{1JuhNga z+X@?0M4d!`l}4fj;q6w1zA=cHN^(I@6dI%G$^DThm9PZU+=ve0NE<$(|6R{;@!~mx zwfmp`b5E?@AUmXp=nZ*yT`*R2ur29FQam5W6$mWQmza#KC!kYo)d40f*PgzPk!%rC zU1adv7ZZiLe@Vex{0WG)&6I934;Z@;#jpbl?(H&$gcJbnfp+6Qmf~0VAr+5(RZN%Y zlg{Go6GXs|Y(()Q9Jxfu#)6UOawV9v$oLHf>{pU&_R(1+_6*Ps!q}r^yU*+I*|g>~ zIr8Qt;}1XqwOL0IPjPh5#9>p_taf^2!Lrxujt`(8Hj11!d39+Mr?2pTri8f4J7>17 z-SC(PO7+!V$zKjxppuli9+@qhwXU`Cm%q+vW-gj|wC?lwyXII1a%{&o{36lJE-$D3 zEEHmZ3WmXD6#PP3c*(R~@g4>&y7rHPCh*0%YbLRM7|ghIINOE=@?ivP1aCu?EWQg} zSd@xM$0=Tw->IMAdsSWBsj+-o6VW-5>FaUu8n*Nq*a!Yu^LypwN=N^LhQsi28nRaY z0y+SC$>F&}f%fo~pvCjN^*-ktEeq73(K#XI>=57Kh3ch??4s?5* zRB~lZYl=?oGZRoPGTLYfK$pCld328r*lmGSGe&ji#6r}{M%CVkYrb&?-JbX&zP?km zIb1I~FU^`*PSl0>7rMq^@aD^z%*MufMaHBOE@ip;SNoZ9i|B;I0TH?E8J6W_6|EP~ zv*lp84>R=LD)r|y6Hl2c5@z7lE)(M*yEoteJGG&@_!$H_b3CL#N}Gjy2#FPH=Zd4|tBirE!T0rUKLYkQYT-0ZOWW znyIK;_H-&RtgEjv{^bS)N~ZE)$Nb!(0K83|RO*?7mG>0!D*s{^PJUMks?FY4kzl7Q zFKWXZYCbj%HyB2ys%r}LL4wH+-D~)tZ@yfhjEOc-+N;;OHBaNTl`H(^m-0F2ZA%5o zhYD|GeP^eK{pYr%N?w(HNd9 zv%N%l$!iCkWQ3smcu0Ds@UyAI;f5+Q*yM7!=eRk>s(75!s3+_uMlnj%Ksws*+QHTx z;Y6zO{!wo@@V?Ji3CEiPR`-yGtnXO@neY`jJE(st@A5u80=pxQt@fN1O~eO$+6+v~ zKLfS{SqqYu$RfwYAD+y!an18npvstUwun;ktluAbwu4{e3D}6^mXJ=rkdyr&Jt);3 zFmpBD8o`xkCvF>es};#s#%q+UsFI&$bI{oOB4lUjjYesaf)RdJxUG?u)t(`d;Usjz z_pmg1n%9Ik8zVk{M`{MXz~GXjn7xjs6(6Du=4^@|3{)n1dWjUMnR}K~CJ{8O6SOf z|82ZB;h~rnPE+ic$&+Zg5JHHz>@4?=`US@!QKJNmZy$9_@iN#t^~^#I3JW@TpRUS5 z7`WketVsc`d;~vik_Cs#=QI#mh{|q$gK3^ga>(WjcMSJm0OpgJ2#fCSNyuD}9`YTm z7&~jJptR?s@thlaffYjdKFW-I#nwp$8!!7JoMAM(7tla6<_dIT6P`Sj$8H%7T>@SM z$0o9dTlMvqU*hkBFR%ouTY+ zyDVCmR5(EdnVD>^G_YHZk=jaL;9P)Q;VF`*+4^g0A6YE)cG(s$V=YgXZOnAPa(jUS zV<47D;)P3nOEuPCD{rwo)&<1j2WAEH1%b1VI;`X|n#vXI7z0l})i#f!_*}1z0%+@M zJ$l-kWR?of$)1(r{oaAazk=dfZOg4!;w5u2{S&quFrHywWGi$B4yv``I+UK@- zadtb#SN_>G?q<hA%4wYAWKnVkMlIg4fP2axNC5 zc1N1es(hNI840o$#(+1QSr4Ass&xdC!@(iag5gs?bVnc0bb~Akeu4M|lAJLEbEWm$ zpww`J9u|6)VSw5`L$)Yj6Y^){FIG<{)=Ot{nE_dq57ZD|YIZzESZRu|3i|x@Y0Cr2 zv%lRZKJ(Pps<{||cT*_!R=`qC@aqTykv}cVpKzU<-#dr40bJgT17J1zt!?-ufZA}4 zNEY!gL^{(LY1?s{AA4EImYEssHU06_pJeLFf_kI?OAC*Hb*;pfpNYw9m>XVD19~$J z$rsUV#@DrEN5D>A7vqUh)S&5jvG@6{k{cL?(r2Hao3=e^tau&aQm^EHc0veTDV@|q3~IX+I5 zKTQ>Nu)lituVhc`yuu!`I=pl3mM8465fUT)Z5C)0;;4hlO!U;(Elhos^S;dWw(Pu> z(;~kcx_L^QihSck1#Z%Zt~R*qY_i*4cLpzMLDRvbS!pHG6iv7Gc@_u!R>OF8D~TOY z+m?%rMXp-}2HC`0e(tCdmWvJh`?m+h>L`J+j7bY6Z(C(Dyt5mkHI?B)1v~93Ft$2* z8Y9j`;JehP`|B|8bND3ykbjmVq`K9w%G%a14Ll!WB_Ou}{^AVpsC9E=v)g>usvNG} zR7~c`dNcIdyLj7a!7W22dp*k!>K{IpU43YdG}*5UyCi%0D~7xNJ!s{SL;Cd2fM=|} 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

  • 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 \ No newline at end of file diff --git a/docs/_static/structlog_logo_horizontal.afdesign b/docs/_static/structlog_logo_horizontal.afdesign new file mode 100644 index 0000000000000000000000000000000000000000..fc38c6b636eef9efbd6cd503aac0f6bb6c7d155a GIT binary patch literal 58175 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
  • S);QQx4e%>xf6~}k=&fvuMBn_p7v6MoeexE|I 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 bo3CEIP55xeAeZxR{)oDYj&haK%ZUF0E(W(E literal 0 HcmV?d00001 diff --git a/docs/_static/structlog_logo_horizontal.svg b/docs/_static/structlog_logo_horizontal.svg new file mode 100644 index 00000000..0e562e8e --- /dev/null +++ b/docs/_static/structlog_logo_horizontal.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/_static/structlog_logo_small.png b/docs/_static/structlog_logo_small.png index 381dd90799568905d4f753c80d646a44a4df0cb2..54079f6b76456dea0d591654ad5c933d7e8b87d6 100644 GIT binary patch literal 22682 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%0D-KNI3edsf#Ro2U>;a>ag4(! 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 Z{{i4ITC)pm+3f%T002ovPDHLkV1nESQ#}9x diff --git a/docs/_static/structlog_logo_small_transparent.png b/docs/_static/structlog_logo_small_transparent.png deleted file mode 100644 index 2da2a22df5830cd499bb699d392f2122b3ad4798..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26266 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%0D8FIDD;UFU$Hw+0f!Flo#0!tLriLurW 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 structlog mascot

    From 15ed561dd6e952bf19ff20b691b3e371d145b99a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 6 Nov 2023 11:13:36 +0100 Subject: [PATCH 1124/1520] The h1 looks fine in GH UI --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 07142c35..c95e1356 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +# *structlog*: Structured Logging for Python +

    structlog: Structured Logging for Python From dfca14ba97412971b5805057bd550c13019e2cb9 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 6 Nov 2023 11:19:12 +0100 Subject: [PATCH 1125/1520] Update pre-commit --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b1ba940d..1ee3aedb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,8 +3,8 @@ ci: autoupdate_schedule: monthly default_language_version: - # Keep in-sync with .python-version - python: python3.11 + # Keep in-sync with .python-version-default + python: python3.12 repos: - repo: https://github.com/psf/black @@ -13,7 +13,7 @@ repos: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.3 + rev: v0.1.4 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From 057fe3693b0b06e7f3105658851f30f0130b5f41 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 7 Nov 2023 06:55:22 +0100 Subject: [PATCH 1126/1520] pre-commit's Python version doesn't matter anymore --- .pre-commit-config.yaml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1ee3aedb..55bdd7bc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,10 +2,6 @@ ci: autoupdate_schedule: monthly -default_language_version: - # Keep in-sync with .python-version-default - python: python3.12 - repos: - repo: https://github.com/psf/black rev: 23.10.1 From 3f8805c8d3933860993553ca2c243c56130bfef3 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 11 Nov 2023 11:29:00 +0100 Subject: [PATCH 1127/1520] docs: remove useless edit button --- .pre-commit-config.yaml | 4 ++-- docs/conf.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 55bdd7bc..bbfaceb6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,12 +4,12 @@ ci: repos: - repo: https://github.com/psf/black - rev: 23.10.1 + rev: 23.11.0 hooks: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.4 + rev: v0.1.5 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/docs/conf.py b/docs/conf.py index edb855fc..f62d66c6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -87,7 +87,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = "furo" -html_theme_options = {} +html_theme_options = {"top_of_page_button": None} html_logo = "_static/structlog_logo.svg" html_static_path = ["_static"] From 8d3eeb1d9a7f7d5e20d515df45fa7779223bbbba Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 13 Nov 2023 09:09:27 +0100 Subject: [PATCH 1128/1520] typing: fix for Mypy 1.7 --- src/structlog/_base.py | 2 +- src/structlog/processors.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/structlog/_base.py b/src/structlog/_base.py index 9fc6e7ce..eece99d7 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -176,7 +176,7 @@ def _process_event( if isinstance(event_dict, tuple): # In this case we assume that the last processor returned a tuple # of ``(args, kwargs)`` and pass it right through. - return event_dict # type: ignore[return-value] + return event_dict if isinstance(event_dict, dict): return (), event_dict diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 1faebfd8..351cb100 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -596,7 +596,7 @@ def _figure_out_exc_info(v: Any) -> ExcInfo: return (v.__class__, v, v.__traceback__) if isinstance(v, tuple): - return v # type: ignore[return-value] + return v if v: return sys.exc_info() # type: ignore[return-value] From 51f5d48d49ea946f1f73060b3dc066f11646c6e4 Mon Sep 17 00:00:00 2001 From: Ben Dickinson Date: Thu, 16 Nov 2023 06:17:20 +0000 Subject: [PATCH 1129/1520] Make stdlib.BoundLogger.exception call Logger.exception (#572) * Make stdlib.BoundLogger.exception call Logger.exception Also, fix inconsistent treatment of ProcessorFormatter's keep_exc_info and keep_stack_info args between structlog- and non-structlog-generated LogRecords * Fix 3.8 typing error and add test for coverage * Add regression test * Fix typos * Add changelog entry --------- Co-authored-by: Hynek Schlawack --- CHANGELOG.md | 4 ++ src/structlog/stdlib.py | 59 +++++++++++++++++---------- src/structlog/typing.py | 10 +++-- tests/test_stdlib.py | 88 +++++++++++++++++++++++++++++++++++------ 4 files changed, 127 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cbc966e4..9a12c8fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,10 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - `structlog.threadlocal.tmp_bind()` now also works with `BoundLoggerLazyProxy` (in other words: before anything is bound to a bound logger). +- stdlib: `structlog.stdlib.BoundLogger.exception()`'s handling of`LogRecord.exc_info` is now set consistent with `logging`. + [#571](https://github.com/hynek/structlog/issues/571) + [#572](https://github.com/hynek/structlog/issues/572) + ## [23.2.0](https://github.com/hynek/structlog/compare/23.1.0...23.2.0) - 2023-10-09 diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 0cac0354..9e82035e 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -16,9 +16,10 @@ import functools import logging import sys +import warnings from functools import partial -from typing import Any, Callable, Collection, Iterable, Sequence +from typing import Any, Callable, Collection, Dict, Iterable, Sequence, cast from . import _config from ._base import BoundLoggerBase @@ -27,7 +28,14 @@ from .contextvars import _ASYNC_CALLING_STACK, merge_contextvars from .exceptions import DropEvent from .processors import StackInfoRenderer -from .typing import Context, EventDict, ExcInfo, Processor, WrappedLogger +from .typing import ( + Context, + EventDict, + ExcInfo, + Processor, + ProcessorReturnValue, + WrappedLogger, +) __all__ = [ @@ -209,12 +217,11 @@ def exception( self, event: str | None = None, *args: Any, **kw: Any ) -> Any: """ - Process event and call `logging.Logger.error` with the result, - after setting ``exc_info`` to `True`. + Process event and call `logging.Logger.exception` with the result, + after setting ``exc_info`` to `True` if it's not already set. """ kw.setdefault("exc_info", True) - - return self.error(event, *args, **kw) + return self._proxy_to_logger("exception", event, *args, **kw) def log( self, level: int, event: str | None = None, *args: Any, **kw: Any @@ -1019,16 +1026,17 @@ def format(self, record: logging.LogRecord) -> str: logger = getattr(record, "_logger", _SENTINEL) meth_name = getattr(record, "_name", "__structlog_sentinel__") + ed: ProcessorReturnValue if logger is not _SENTINEL and meth_name != "__structlog_sentinel__": # Both attached by wrap_for_formatter if self.logger is not None: logger = self.logger - meth_name = record._name # type: ignore[attr-defined] + meth_name = cast(str, record._name) # type:ignore[attr-defined] # We need to copy because it's possible that the same record gets - # processed by multiple logging formatters. LogRecord.getMessage + # processed by multiple logging formatters. LogRecord.getMessage # would transform our dict into a str. - ed = record.msg.copy() # type: ignore[union-attr] + ed = cast(Dict[str, Any], record.msg).copy() ed["_record"] = record ed["_from_structlog"] = True else: @@ -1045,27 +1053,38 @@ def format(self, record: logging.LogRecord) -> str: record.args = () - # Add stack-related attributes to event_dict and unset them - # on the record copy so that the base implementation wouldn't - # append stacktraces to the output. + # Add stack-related attributes to the event dict if record.exc_info: ed["exc_info"] = record.exc_info if record.stack_info: ed["stack_info"] = record.stack_info - if not self.keep_exc_info: - record.exc_text = None - record.exc_info = None - if not self.keep_stack_info: - record.stack_info = None - # Non-structlog allows to run through a chain to prepare it for the # final processor (e.g. adding timestamps and log levels). for proc in self.foreign_pre_chain or (): - ed = proc(logger, meth_name, ed) + ed = cast(EventDict, proc(logger, meth_name, ed)) + + # If required, unset stack-related attributes on the record copy so + # that the base implementation doesn't append stacktraces to the + # output. + if not self.keep_exc_info: + record.exc_text = None + record.exc_info = None + if not self.keep_stack_info: + record.stack_info = None for p in self.processors: - ed = p(logger, meth_name, ed) + ed = p(logger, meth_name, cast(EventDict, ed)) + + if not isinstance(ed, str): + warnings.warn( + "The last processor in ProcessorFormatter.processors must " + f"return a string, but {self.processors[-1]} returned a " + f"{type(ed)} instead.", + category=RuntimeWarning, + stacklevel=1, + ) + ed = cast(str, ed) record.msg = ed diff --git a/src/structlog/typing.py b/src/structlog/typing.py index 66f6a7e0..c258e11f 100644 --- a/src/structlog/typing.py +++ b/src/structlog/typing.py @@ -60,11 +60,15 @@ .. versionadded:: 20.2.0 """ -Processor = Callable[ - [WrappedLogger, str, EventDict], - Union[Mapping[str, Any], str, bytes, bytearray, Tuple[Any, ...]], +ProcessorReturnValue = Union[ + Mapping[str, Any], str, bytes, bytearray, Tuple[Any, ...] ] """ +A value returned by a processor. +""" + +Processor = Callable[[WrappedLogger, str, EventDict], ProcessorReturnValue] +""" A callable that is part of the processor chain. See :doc:`processors`. diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 4e3c9f56..626b1a7c 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -12,7 +12,7 @@ import sys from io import StringIO -from typing import Any, Callable, Collection +from typing import Any, Callable, Collection, Dict import pytest import pytest_asyncio @@ -193,7 +193,8 @@ def test_passes_higher_levels(self): class TestBoundLogger: @pytest.mark.parametrize( - ("method_name"), ["debug", "info", "warning", "error", "critical"] + ("method_name"), + ["debug", "info", "warning", "error", "exception", "critical"], ) def test_proxies_to_correct_method(self, method_name): """ @@ -203,14 +204,6 @@ def test_proxies_to_correct_method(self, method_name): assert method_name == getattr(bl, method_name)("event") - def test_proxies_exception(self): - """ - BoundLogger.exception is proxied to Logger.error. - """ - bl = BoundLogger(ReturnLogger(), [return_method_name], {}) - - assert "error" == bl.exception("event") - def test_proxies_log(self): """ BoundLogger.exception.log() is proxied to the appropriate method. @@ -1123,6 +1116,79 @@ def test_remove_processors_meta(self): {"foo": "bar", "_record": "foo", "_from_structlog": True}, ) + def test_non_string_message_warning(self): + """ + A warning is raised if the last processor in + ProcessorFormatter.processors doesn't return a string. + """ + configure_logging(None) + logger = logging.getLogger() + + formatter = ProcessorFormatter( + processors=[lambda *args, **kwargs: {"foo": "bar"}], + ) + logger.handlers[0].setFormatter(formatter) + + with pytest.warns( + RuntimeWarning, + match="The last processor in ProcessorFormatter.processors must return a string", + ): + logger.info("baz") + + def test_logrecord_exc_info(self): + """ + LogRecord.exc_info is set consistently for structlog and non-structlog + log records. + """ + configure_logging(None) + + # This doesn't test ProcessorFormatter itself directly, but it's + # relevant to setups where ProcessorFormatter is used, i.e. where + # handlers will receive LogRecord objects that come from both structlog + # and non-structlog loggers. + + records: Dict[ # noqa: UP006 - dict isn't generic until Python 3.9 + str, logging.LogRecord + ] = {} + + class DummyHandler(logging.Handler): + def emit(self, record): + # Don't do anything; just store the record in the records dict + # by its message, so we can assert things about it. + if isinstance(record.msg, dict): + records[record.msg["event"]] = record + else: + records[record.msg] = record + + stdlib_logger = logging.getLogger() + structlog_logger = get_logger() + + # It doesn't matter which logger we add the handler to here. + stdlib_logger.addHandler(DummyHandler()) + + try: + raise Exception("foo") + except Exception: + stdlib_logger.exception("bar") + structlog_logger.exception("baz") + + stdlib_record = records.pop("bar") + + assert "bar" == stdlib_record.msg + assert stdlib_record.exc_info + assert Exception is stdlib_record.exc_info[0] + assert ("foo",) == stdlib_record.exc_info[1].args + + structlog_record = records.pop("baz") + + assert "baz" == structlog_record.msg["event"] + assert True is structlog_record.msg["exc_info"] + assert structlog_record.exc_info + assert Exception is structlog_record.exc_info[0] + assert ("foo",) == structlog_record.exc_info[1].args + + assert not records + @pytest_asyncio.fixture(name="abl") async def _abl(cl): @@ -1154,7 +1220,7 @@ async def test_correct_levels(self, abl, cl, stdlib_log_method): """ await getattr(abl.bind(foo="bar"), stdlib_log_method)("42") - aliases = {"exception": "error", "warn": "warning"} + aliases = {"warn": "warning"} alias = aliases.get(stdlib_log_method) expect = alias if alias else stdlib_log_method From 84abf88940ac49788566d6cf31267c2e4c3a44fb Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 20 Nov 2023 08:23:26 +0100 Subject: [PATCH 1130/1520] Silence dateutil-caused DeprecationWarning It's just coming from a test dependency. --- pyproject.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 2ca94640..a3773a18 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -67,7 +67,10 @@ raw-options = { local_scheme = "no-local-version" } addopts = ["-ra", "--strict-markers", "--strict-config"] testpaths = "tests" xfail_strict = true -filterwarnings = ["once::Warning"] +filterwarnings = [ + "once::Warning", + 'ignore:datetime.datetime.utcfromtimestamp\(\) is deprecated:DeprecationWarning:dateutil.tz', +] asyncio_mode = "auto" From 8c98f4c4a734a2b306d5b58cef7f7420795d19da Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 20 Nov 2023 09:23:30 +0100 Subject: [PATCH 1131/1520] All good things come to an end --- .github/sponsors/Sentry.svg | 1 - README.md | 4 ---- 2 files changed, 5 deletions(-) delete mode 100644 .github/sponsors/Sentry.svg diff --git a/.github/sponsors/Sentry.svg b/.github/sponsors/Sentry.svg deleted file mode 100644 index fdb774a0..00000000 --- a/.github/sponsors/Sentry.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/README.md b/README.md index c95e1356..382cbfc9 100644 --- a/README.md +++ b/README.md @@ -60,10 +60,6 @@ Especially those generously supporting us at the *The Organization* tier and hig - - - - From 6323d5fc54a5e5ff09eca7d8b912ab6ef9256992 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 20 Nov 2023 15:16:24 +0100 Subject: [PATCH 1132/1520] Run CI PRs against all branches --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f01595a..4e695c9c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,7 +5,6 @@ on: push: branches: [main] pull_request: - branches: [main] workflow_dispatch: env: From 448f1800ecb2f5b293b977b08fafe97b1ddb2fc5 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 21 Nov 2023 08:29:38 +0100 Subject: [PATCH 1133/1520] Add structlog.stdlib.ProcessorFormatter(use_get_message=True) (#550) * stdlib: add structlog.stdlib.ProcessorFormatter(use_get_message=True) Fixes #520 * Move changelog entry to next release * Fix added version * Typo * Add test * Cleanup --- CHANGELOG.md | 3 +++ src/structlog/stdlib.py | 11 ++++++++++- tests/test_stdlib.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a12c8fb..7a0e35cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - `structlog.threadlocal.tmp_bind()` now also works with `BoundLoggerLazyProxy` (in other words: before anything is bound to a bound logger). +- stdlib: `ProcessorFormatter` can now be told to not render the log record message using `getMessage` and just `str(record.msg)` instead. + [#550](https://github.com/hynek/structlog/issues/550) + - stdlib: `structlog.stdlib.BoundLogger.exception()`'s handling of`LogRecord.exc_info` is now set consistent with `logging`. [#571](https://github.com/hynek/structlog/issues/571) [#572](https://github.com/hynek/structlog/issues/572) diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 9e82035e..5e05e9bd 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -964,6 +964,10 @@ class ProcessorFormatter(logging.Formatter): This parameter exists for historic reasons. Please use *processors* instead. + use_get_message: + If True, use ``record.getMessage`` to get a fully rendered log + message, otherwise use ``str(record.msg)``. (default: True) + Raises: TypeError: If both or neither *processor* and *processors* are passed. @@ -976,6 +980,7 @@ class ProcessorFormatter(logging.Formatter): .. deprecated:: 21.3.0 *processor* (singular) in favor of *processors* (plural). Removal is not planned. + .. versionadded:: 23.3.0 *use_get_message* """ def __init__( @@ -987,6 +992,7 @@ def __init__( keep_stack_info: bool = False, logger: logging.Logger | None = None, pass_foreign_args: bool = False, + use_get_message: bool = True, *args: Any, **kwargs: Any, ) -> None: @@ -1011,6 +1017,7 @@ def __init__( self.keep_stack_info = keep_stack_info self.logger = logger self.pass_foreign_args = pass_foreign_args + self.use_get_message = use_get_message def format(self, record: logging.LogRecord) -> str: """ @@ -1043,7 +1050,9 @@ def format(self, record: logging.LogRecord) -> str: logger = self.logger meth_name = record.levelname.lower() ed = { - "event": record.getMessage(), + "event": record.getMessage() + if self.use_get_message + else str(record.msg), "_record": record, "_from_structlog": False, } diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 626b1a7c..569bbbd7 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -1189,6 +1189,34 @@ def emit(self, record): assert not records + def test_use_get_message_false(self): + """ + If use_get_message_is False, the event is obtained using + str(record.msg) instead of calling record.getMessage. That means + positional formatting is not performed. + """ + event_dicts = [] + + def capture(_, __, ed): + event_dicts.append(ed.copy()) + + return str(ed) + + proc = ProcessorFormatter(processors=[capture], use_get_message=False) + + record = logging.LogRecord( + "foo", + logging.INFO, + "path.py", + 42, + "le msg: %s", + ("keep separate",), + None, + ) + + assert proc.format(record) + assert "le msg: %s" == event_dicts[0]["event"] + @pytest_asyncio.fixture(name="abl") async def _abl(cl): From fefce6dda27f4cf5fc806d08134d515d8a05412f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 23 Nov 2023 07:38:24 +0100 Subject: [PATCH 1134/1520] Let's stand out --- .pre-commit-config.yaml | 2 +- docs/_static/custom.css | 17 +++++++++++++++++ docs/conf.py | 10 +++++++++- 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 docs/_static/custom.css diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bbfaceb6..63aabf49 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.5 + rev: v0.1.6 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/docs/_static/custom.css b/docs/_static/custom.css new file mode 100644 index 00000000..0667f788 --- /dev/null +++ b/docs/_static/custom.css @@ -0,0 +1,17 @@ +@import url('https://rsms.me/inter/inter.css'); +@font-face { + font-family: "BerkeleyMono"; + src: local("Berkeley Mono"), + url("https://assets.hynek.me/bm/BerkeleyMono-Regular.woff2") format("woff2"), + url("https://assets.hynek.me/bm/BerkeleyMono-Italic.woff2") format("woff2"), + url("https://assets.hynek.me/bm/BerkeleyMono-BoldItalic.woff2") format("woff2"), + url("https://assets.hynek.me/bm/BerkeleyMono-Bold.woff2") format("woff2"); + font-display: swap; +} + +:root { + font-feature-settings: 'liga' 1, 'calt' 1; /* fix for Chrome */ +} +@supports (font-variation-settings: normal) { + :root { font-family: InterVariable, sans-serif; } +} diff --git a/docs/conf.py b/docs/conf.py index f62d66c6..74e4be90 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -87,9 +87,17 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = "furo" -html_theme_options = {"top_of_page_button": None} +html_theme_options = { + "top_of_page_button": None, + "light_css_variables": { + "font-stack": "Inter,sans-serif", + "font-stack--monospace": "BerkeleyMono, MonoLisa, ui-monospace, " + "SFMono-Regular, Menlo, Consolas, Liberation Mono, monospace", + }, +} html_logo = "_static/structlog_logo.svg" html_static_path = ["_static"] +html_css_files = ["custom.css"] htmlhelp_basename = "structlogdoc" From 14065464677cfe2a515d2bb288c766ee2b4c72be Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 23 Nov 2023 07:51:53 +0100 Subject: [PATCH 1135/1520] Fix BM definition --- docs/_static/custom.css | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/docs/_static/custom.css b/docs/_static/custom.css index 0667f788..f34ce791 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -1,14 +1,42 @@ @import url('https://rsms.me/inter/inter.css'); + +/* Normal */ @font-face { font-family: "BerkeleyMono"; - src: local("Berkeley Mono"), - url("https://assets.hynek.me/bm/BerkeleyMono-Regular.woff2") format("woff2"), - url("https://assets.hynek.me/bm/BerkeleyMono-Italic.woff2") format("woff2"), - url("https://assets.hynek.me/bm/BerkeleyMono-BoldItalic.woff2") format("woff2"), - url("https://assets.hynek.me/bm/BerkeleyMono-Bold.woff2") format("woff2"); + src: url("https://assets.hynek.me/bm/BerkeleyMono-Regular.woff2") format("woff2"); font-display: swap; + font-style: normal; + font-weight: normal; } +/* Italic */ +@font-face { + font-family: "BerkeleyMono"; + src: url("https://assets.hynek.me/bm/BerkeleyMono-Italic.woff2") format("woff2"); + font-display: swap; + font-style: italic; + font-weight: normal; +} + +/* Bold Italic */ +@font-face { + font-family: "BerkeleyMono"; + src: url("https://assets.hynek.me/bm/BerkeleyMono-BoldItalic.woff2") format("woff2"); + font-display: swap; + font-style: italic; + font-weight: bold; +} + +/* Bold */ +@font-face { + font-family: "BerkeleyMono"; + src: url("https://assets.hynek.me/bm/BerkeleyMono-Bold.woff2") format("woff2"); + font-display: swap; + font-style: normal; + font-weight: bold; +} + + :root { font-feature-settings: 'liga' 1, 'calt' 1; /* fix for Chrome */ } From 821a000e583dd1542491f354ee9a5471acafc96f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 23 Nov 2023 08:14:50 +0100 Subject: [PATCH 1136/1520] Simplify BM --- docs/_static/custom.css | 37 +------------------------------------ 1 file changed, 1 insertion(+), 36 deletions(-) diff --git a/docs/_static/custom.css b/docs/_static/custom.css index f34ce791..72083fee 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -1,40 +1,5 @@ @import url('https://rsms.me/inter/inter.css'); - -/* Normal */ -@font-face { - font-family: "BerkeleyMono"; - src: url("https://assets.hynek.me/bm/BerkeleyMono-Regular.woff2") format("woff2"); - font-display: swap; - font-style: normal; - font-weight: normal; -} - -/* Italic */ -@font-face { - font-family: "BerkeleyMono"; - src: url("https://assets.hynek.me/bm/BerkeleyMono-Italic.woff2") format("woff2"); - font-display: swap; - font-style: italic; - font-weight: normal; -} - -/* Bold Italic */ -@font-face { - font-family: "BerkeleyMono"; - src: url("https://assets.hynek.me/bm/BerkeleyMono-BoldItalic.woff2") format("woff2"); - font-display: swap; - font-style: italic; - font-weight: bold; -} - -/* Bold */ -@font-face { - font-family: "BerkeleyMono"; - src: url("https://assets.hynek.me/bm/BerkeleyMono-Bold.woff2") format("woff2"); - font-display: swap; - font-style: normal; - font-weight: bold; -} +@import url('https://assets.hynek.me/css/bm.css'); :root { From e333d467231ec12f07bafafd10dc564c2427f7be Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 23 Nov 2023 08:34:32 +0100 Subject: [PATCH 1137/1520] docs: unbreak frontpage --- .github/sponsors/Sentry.svg | 1 + docs/conf.py | 4 +--- docs/exceptions.md | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) create mode 100644 .github/sponsors/Sentry.svg diff --git a/.github/sponsors/Sentry.svg b/.github/sponsors/Sentry.svg new file mode 100644 index 00000000..fdb774a0 --- /dev/null +++ b/.github/sponsors/Sentry.svg @@ -0,0 +1 @@ + diff --git a/docs/conf.py b/docs/conf.py index 74e4be90..c79b39f9 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -84,13 +84,11 @@ # -- Options for HTML output -------------------------------------------------- -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. html_theme = "furo" html_theme_options = { "top_of_page_button": None, "light_css_variables": { - "font-stack": "Inter,sans-serif", + "font-stack": "Inter, sans-serif", "font-stack--monospace": "BerkeleyMono, MonoLisa, ui-monospace, " "SFMono-Regular, Menlo, Consolas, Liberation Mono, monospace", }, diff --git a/docs/exceptions.md b/docs/exceptions.md index 329fe3b5..b7c5e4dc 100644 --- a/docs/exceptions.md +++ b/docs/exceptions.md @@ -1,6 +1,6 @@ # Exceptions -While you should use a proper crash reporter like our sponsor [Sentry](https://sentry.io) in production, *structlog* has helpers for formatting exceptions for humans and machines. +While you should use a proper crash reporter like [Sentry](https://sentry.io) in production, *structlog* has helpers for formatting exceptions for humans and machines. All *structog*'s exception features center around passing an `exc_info` key-value pair in the event dict. There are three possible behaviors depending on its value: From 0f93eef2d3d22f8ee8c82b81b5c401adea5db722 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 28 Nov 2023 13:29:48 +0100 Subject: [PATCH 1138/1520] Parameters is the official name, Arguments is just an alias https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html --- .github/CONTRIBUTING.md | 2 +- src/structlog/_base.py | 6 +++--- src/structlog/_config.py | 6 +++--- src/structlog/_frames.py | 2 +- src/structlog/_log_levels.py | 2 +- src/structlog/_output.py | 12 ++++++------ src/structlog/_utils.py | 2 +- src/structlog/dev.py | 4 ++-- src/structlog/processors.py | 22 +++++++++++----------- src/structlog/stdlib.py | 8 ++++---- src/structlog/testing.py | 2 +- src/structlog/threadlocal.py | 4 ++-- src/structlog/tracebacks.py | 4 ++-- src/structlog/twisted.py | 6 +++--- src/structlog/typing.py | 2 +- tests/test_processors.py | 8 ++++---- 16 files changed, 46 insertions(+), 46 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 86430411..1698e6f0 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -128,7 +128,7 @@ But it's way more comfortable to run it locally and catch avoidable errors befor """ Do something. - Arguments: + Parameters: x: A very important parameter. diff --git a/src/structlog/_base.py b/src/structlog/_base.py index eece99d7..78396831 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -123,7 +123,7 @@ def _process_event( Call it to combine your *event* and *context* into an event_dict and process using the processor chain. - Arguments: + Parameters: method_name: The name of the logger method. Is passed into the processors. @@ -197,7 +197,7 @@ def _proxy_to_logger( handling :exc:`structlog.DropEvent`, and finally calls *method_name* on :attr:`_logger` with the result. - Arguments: + Parameters: method_name: The name of the method that's going to get called. Technically @@ -232,7 +232,7 @@ def get_context(bound_logger: BindableLogger) -> Context: The type of *bound_logger* and the type returned depend on your configuration. - Arguments: + Parameters: bound_logger: The bound logger whose context you want. diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 0263b054..40cc09e1 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -114,7 +114,7 @@ def get_logger(*args: Any, **initial_values: Any) -> Any: >>> log.info("hello", x=42) y=23 x=42 event='hello' - Arguments: + Parameters: args: *Optional* positional arguments that are passed unmodified to the @@ -169,7 +169,7 @@ def wrap_logger( In other words: selective overwriting of the defaults while keeping some *is* possible. - Arguments: + Parameters: initial_values: Values that are used to pre-populate your contexts. @@ -217,7 +217,7 @@ def configure( Use `reset_defaults` to undo your changes. - Arguments: + Parameters: processors: The processor chain. See :doc:`processors` for details. diff --git a/src/structlog/_frames.py b/src/structlog/_frames.py index 51346d2f..cd96f33b 100644 --- a/src/structlog/_frames.py +++ b/src/structlog/_frames.py @@ -41,7 +41,7 @@ def _find_first_app_frame_and_name( """ Remove all intra-structlog calls and return the relevant app frame. - Arguments: + Parameters: additional_ignores: Additional names with which the first frame must not start. diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index be132fcb..7d1a005c 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -139,7 +139,7 @@ def make_filtering_bound_logger(min_level: int) -> type[FilteringBoundLogger]: - You *can* have (much) more fine-grained filtering by :ref:`writing a simple processor `. - Arguments: + Parameters: min_level: The log level as an integer. You can use the constants from diff --git a/src/structlog/_output.py b/src/structlog/_output.py index 4c5efbf4..e6fb2420 100644 --- a/src/structlog/_output.py +++ b/src/structlog/_output.py @@ -36,7 +36,7 @@ class PrintLogger: """ Print events into a file. - Arguments: + Parameters: file: File to print to. (default: `sys.stdout`) @@ -122,7 +122,7 @@ class PrintLoggerFactory: To be used with `structlog.configure`\ 's ``logger_factory``. - Arguments: + Parameters: file: File to print to. (default: `sys.stdout`) @@ -142,7 +142,7 @@ class WriteLogger: """ Write events into a file. - Arguments: + Parameters: file: File to print to. (default: `sys.stdout`) @@ -232,7 +232,7 @@ class WriteLoggerFactory: To be used with `structlog.configure`\ 's ``logger_factory``. - Arguments: + Parameters: file: File to print to. (default: `sys.stdout`) @@ -252,7 +252,7 @@ class BytesLogger: r""" Writes bytes into a file. - Arguments: + Parameters: file: File to print to. (default: `sys.stdout`\ ``.buffer``) Useful if you follow `current logging best practices @@ -336,7 +336,7 @@ class BytesLoggerFactory: To be used with `structlog.configure`\ 's ``logger_factory``. - Arguments: + Parameters: file: File to print to. (default: `sys.stdout`\ ``.buffer``) diff --git a/src/structlog/_utils.py b/src/structlog/_utils.py index f03aeaea..583006b8 100644 --- a/src/structlog/_utils.py +++ b/src/structlog/_utils.py @@ -20,7 +20,7 @@ def until_not_interrupted(f: Callable[..., Any], *args: Any, **kw: Any) -> Any: """ Retry until *f* succeeds or an exception that isn't caused by EINTR occurs. - Arguments: + Parameters: f: A callable like a function. diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 816f9cef..808da12d 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -275,7 +275,7 @@ class ConsoleRenderer: *after* the log line. If Rich_ or better-exceptions_ are present, in colors and with extra context. - Arguments: + Parameters: pad_event: Pad the event to this many characters. @@ -527,7 +527,7 @@ def get_default_level_styles(colors: bool = True) -> Any: my_styles["EVERYTHING_IS_ON_FIRE"] = my_styles["critical"] renderer = ConsoleRenderer(level_styles=my_styles) - Arguments: + Parameters: colors: Whether to use colorful styles. This must match the *colors* diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 351cb100..181dc6fc 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -63,7 +63,7 @@ class KeyValueRenderer: """ Render ``event_dict`` as a list of ``Key=repr(Value)`` pairs. - Arguments: + Parameters: sort_keys: Whether to sort keys when formatting. @@ -119,7 +119,7 @@ class LogfmtRenderer: .. _logfmt: https://brandur.org/logfmt - Arguments: + Parameters: sort_keys: Whether to sort keys when formatting. @@ -237,7 +237,7 @@ class UnicodeEncoder: """ Encode unicode values in ``event_dict``. - Arguments: + Parameters: encoding: Encoding to encode to (default: ``"utf-8"``). @@ -272,7 +272,7 @@ class UnicodeDecoder: """ Decode byte string values in ``event_dict``. - Arguments: + Parameters: encoding: Encoding to decode from (default: ``"utf-8"``). @@ -308,7 +308,7 @@ class JSONRenderer: """ Render the ``event_dict`` using ``serializer(event_dict, **dumps_kw)``. - Arguments: + Parameters: dumps_kw: Are passed unmodified to *serializer*. If *default* is passed, it @@ -385,7 +385,7 @@ class ExceptionRenderer: If there is no ``exc_info`` key, the *event_dict* is not touched. This behavior is analog to the one of the stdlib's logging. - Arguments: + Parameters: exception_formatter: A callable that is used to format the exception from the @@ -459,7 +459,7 @@ class TimeStamper: """ Add a timestamp to ``event_dict``. - Arguments: + Parameters: fmt: strftime format string, or ``"iso"`` for `ISO 8601 @@ -608,7 +608,7 @@ class ExceptionPrettyPrinter: """ Pretty print exceptions and remove them from the ``event_dict``. - Arguments: + Parameters: file: Target file for output (default: ``sys.stdout``). @@ -661,7 +661,7 @@ class StackInfoRenderer: involving an exception and works analogously to the *stack_info* argument of the Python standard library logging. - Arguments: + Parameters: additional_ignores: By default, stack frames coming from *structlog* are ignored. With @@ -745,7 +745,7 @@ class CallsiteParameterAdder: The keys used for callsite parameters in the event dictionary are the string values of `CallsiteParameter` enum members. - Arguments: + Parameters: parameters: A collection of `CallsiteParameter` values that should be added to @@ -880,7 +880,7 @@ class EventRenamer: some processors may rely on the presence and meaning of the ``event`` key. - Arguments: + Parameters: to: Rename ``event_dict["event"]`` to ``event_dict[to]`` diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 5e05e9bd..9fbe5c7e 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -63,7 +63,7 @@ def recreate_defaults(*, log_level: int | None = logging.NOTSET) -> None: As with vanilla defaults, the backwards-compatibility guarantees don't apply to the settings applied here. - Arguments: + Parameters: log_level: If `None`, don't configure standard library logging **at all**. @@ -655,7 +655,7 @@ class LoggerFactory: >>> from structlog.stdlib import LoggerFactory >>> configure(logger_factory=LoggerFactory()) - Arguments: + Parameters: ignore_frame_names: When guessing the name of a logger, skip frames whose names *start* @@ -814,7 +814,7 @@ class ExtraAdder: This processor can be used for adding data passed in the ``extra`` parameter of the `logging` module's log methods to the event dictionary. - Arguments: + Parameters: allow: An optional collection of attributes that, if present in @@ -906,7 +906,7 @@ class ProcessorFormatter(logging.Formatter): Please refer to :ref:`processor-formatter` for examples. - Arguments: + Parameters: foreign_pre_chain: If not `None`, it is used as a processor chain that is applied to diff --git a/src/structlog/testing.py b/src/structlog/testing.py index 8f5c093a..90c6b785 100644 --- a/src/structlog/testing.py +++ b/src/structlog/testing.py @@ -139,7 +139,7 @@ class CapturedCall(NamedTuple): Can also be unpacked like a tuple. - Arguments: + Parameters: method_name: The method name that got called. diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index a1cfd86b..b6b3c69b 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -83,7 +83,7 @@ def wrap_dict(dict_class: type[Context]) -> type[Context]: The wrapped class and used to keep global in the current thread. - Arguments: + Parameters: dict_class: Class used for keeping context. @@ -106,7 +106,7 @@ def as_immutable(logger: TLLogger) -> TLLogger: """ Extract the context from a thread local logger into an immutable logger. - Arguments: + Parameters: logger (structlog.typing.BindableLogger): A logger with *possibly* thread local state. diff --git a/src/structlog/tracebacks.py b/src/structlog/tracebacks.py index 5fbd5447..f5d13c8f 100644 --- a/src/structlog/tracebacks.py +++ b/src/structlog/tracebacks.py @@ -127,7 +127,7 @@ def extract( """ Extract traceback information. - Arguments: + Parameters: exc_type: Exception type. @@ -220,7 +220,7 @@ class ExceptionDictTransformer: These dictionaries are based on :class:`Stack` instances generated by :func:`extract()` and can be dumped to JSON. - Arguments: + Parameters: show_locals: Whether or not to include the values of a stack frame's local diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index 64f7b386..4f3f1abe 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -204,7 +204,7 @@ class PlainFileLogObserver: Great to just print JSON to stdout where you catch it with something like runit. - Arguments: + Parameters: file: File to print to. @@ -229,7 +229,7 @@ class JSONLogObserverWrapper: """ Wrap a log *observer* and render non-`JSONRenderer` entries to JSON. - Arguments: + Parameters: observer (ILogObserver): Twisted log observer to wrap. For example @@ -293,7 +293,7 @@ class EventAdapter: `_ behave as expected. - Arguments: + Parameters: dictRenderer: Renderer that is used for the actual log message. Please note that diff --git a/src/structlog/typing.py b/src/structlog/typing.py index c258e11f..217463a1 100644 --- a/src/structlog/typing.py +++ b/src/structlog/typing.py @@ -106,7 +106,7 @@ class ExceptionTransformer(Protocol): Used by `structlog.processors.format_exc_info()` and `structlog.processors.ExceptionPrettyPrinter`. - Arguments: + Parameters: exc_info: Is the exception tuple to format diff --git a/tests/test_processors.py b/tests/test_processors.py index 9317cc08..3d9a2870 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -1047,7 +1047,7 @@ def make_processor( supplied ``parameter_strings`` values and with the supplied ``additional_ignores`` values. - Arguments: + Parameters: parameter_strings: Strings for which corresponding ``CallsiteParameters`` should @@ -1077,7 +1077,7 @@ def filter_parameters( Returns a set containing all ``CallsiteParameter`` members with values that are in ``parameter_strings``. - Arguments: + Parameters: parameter_strings: The parameters strings for which corresponding @@ -1100,7 +1100,7 @@ def filter_parameter_dict( Returns a dictionary that is equivalent to ``input`` but with all keys not in ``parameter_strings`` removed. - Arguments: + Parameters: parameter_strings: The keys to keep in the dictionary, if this value is ``None`` @@ -1120,7 +1120,7 @@ def get_callsite_parameters(cls, offset: int = 1) -> dict[str, object]: This function creates dictionary of callsite parameters for the line that is ``offset`` lines after the invocation of this function. - Arguments: + Parameters: offset: The amount of lines after the invocation of this function that From 778e53e7a791febc3235460a302910e3e2f5c172 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 6 Dec 2023 12:52:55 +0100 Subject: [PATCH 1139/1520] pre-commit update --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 63aabf49..d5281d11 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.6 + rev: v0.1.7 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From fa489a3faaafbb3a4cb331972963c3f628e2443b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 6 Dec 2023 12:55:58 +0100 Subject: [PATCH 1140/1520] Fix changelog link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 382cbfc9..18be700b 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ The logs-loving beaver logo has been contributed by [Lynn Root](https://www.rogu - [**PyPI**](https://pypi.org/project/structlog/) - [**GitHub**](https://github.com/hynek/structlog) - [**Documentation**](https://www.structlog.org/) -- [**Changelog**](https://www.structlog.org/en/stable/changelog.html) +- [**Changelog**](https://github.com/hynek/structlog/tree/main/CHANGELOG.md) - [**Third-party Extensions**](https://github.com/hynek/structlog/wiki/Third-party-Extensions) From cd102d2e9990943a7507b2d9b7bd6e08ad209791 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 6 Dec 2023 13:06:13 +0100 Subject: [PATCH 1141/1520] Switch to sphinxext.opengraph --- docs/conf.py | 22 ++++------------------ pyproject.toml | 1 + 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index c79b39f9..f3ab0b3d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -22,6 +22,7 @@ "sphinx.ext.intersphinx", "sphinx.ext.viewcode", "sphinxcontrib.mermaid", + "sphinxext.opengraph", ] myst_enable_extensions = [ @@ -31,6 +32,9 @@ ] mermaid_init_js = "mermaid.initialize({startOnLoad:true,theme:'neutral'});" +ogp_image = "_static/structlog_logo.png" + + # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] @@ -99,24 +103,6 @@ htmlhelp_basename = "structlogdoc" -_logo = "https://www.structlog.org/en/latest/_static/structlog_logo.svg" -_descr = ( - "structlog makes logging in Python faster, less painful, and more " - "powerful by adding structure to your log entries." -) -_title = "structlog: Structured Logging for Python" -rst_epilog = f"""\ -.. meta:: - :property=og:type: website - :property=og:site_name: { _title } - :property=og:description: { _descr } - :property=og:author: Hynek Schlawack - :property=og:image: { _logo } - :twitter:title: { _title } - :twitter:image: { _logo } - :twitter:creator: @hynek -""" - latex_documents = [ ("index", "structlog.tex", "structlog Documentation", "Author", "manual") ] diff --git a/pyproject.toml b/pyproject.toml index a3773a18..6bb583ab 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,6 +53,7 @@ docs = [ "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", + "sphinxext-opengraph", "twisted", ] dev = ["structlog[tests,typing]"] From 8d1ca293dbdf47be57c814c138bc84e7b559a29b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 6 Dec 2023 14:09:02 +0100 Subject: [PATCH 1142/1520] Work around test runners patching sys.stdout/stderr --- tests/test_output.py | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/tests/test_output.py b/tests/test_output.py index 1854c572..82db52df 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -5,7 +5,6 @@ import copy import pickle -import sys from io import BytesIO, StringIO @@ -19,7 +18,7 @@ WriteLogger, WriteLoggerFactory, ) -from structlog._output import WRITE_LOCKS +from structlog._output import WRITE_LOCKS, stderr, stdout from .utils import stdlib_log_methods @@ -78,7 +77,7 @@ def test_stdlib_methods_support(self, logger_cls, method, sio): assert "hello" in sio.getvalue() - @pytest.mark.parametrize("file", [None, sys.stdout, sys.stderr]) + @pytest.mark.parametrize("file", [None, stdout, stderr]) @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL + 1)) def test_pickle(self, logger_cls, file, proto): """ @@ -141,6 +140,8 @@ def test_stdout_monkeypatch(self, monkeypatch, capsys): """ If stdout gets monkeypatched, the new instance receives the output. """ + import sys + p = PrintLogger() new_stdout = StringIO() monkeypatch.setattr(sys, "stdout", new_stdout) @@ -165,9 +166,9 @@ def test_passes_file(self): """ If a file is passed to the factory, it get passed on to the logger. """ - pl = PrintLoggerFactory(sys.stderr)() + pl = PrintLoggerFactory(stderr)() - assert sys.stderr is pl._file + assert stderr is pl._file def test_ignores_args(self): """ @@ -190,9 +191,9 @@ def test_passes_file(self): """ If a file is passed to the factory, it get passed on to the logger. """ - pl = WriteLoggerFactory(sys.stderr)() + pl = WriteLoggerFactory(stderr)() - assert sys.stderr is pl._file + assert stderr is pl._file def test_ignores_args(self): """ @@ -255,9 +256,7 @@ def test_stdlib_methods_support(self, method): assert b"hello" in sio.getvalue() - @pytest.mark.parametrize( - "file", [None, sys.stdout.buffer, sys.stderr.buffer] - ) + @pytest.mark.parametrize("file", [None, stdout.buffer, stderr.buffer]) @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL + 1)) def test_pickle(self, file, proto): """ @@ -324,9 +323,9 @@ def test_passes_file(self): """ If a file is passed to the factory, it get passed on to the logger. """ - pl = BytesLoggerFactory(sys.stderr)() + pl = BytesLoggerFactory(stderr)() - assert sys.stderr is pl._file + assert stderr is pl._file def test_ignores_args(self): """ From 0159b39a1555f7eb8b8be5b069ab6f6588d383f4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 27 Dec 2023 10:24:36 +0100 Subject: [PATCH 1143/1520] Get rid of link artifacts --- README.md | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 18be700b..9006f577 100644 --- a/README.md +++ b/README.md @@ -7,24 +7,12 @@

    - - Documentation - - - License: MIT / Apache 2.0 - - - - - - DOI - - - Supported Python versions of the current PyPI release. - - - Downloads per month - + Documentation + License: MIT / Apache 2.0 + + DOI + Supported Python versions of the current PyPI release. + Downloads per month

    Simple. Powerful. Fast. Pick three.

    From fe4cd562af43286644e6532184c3471da8e8dc8d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 29 Dec 2023 06:37:29 +0100 Subject: [PATCH 1144/1520] Avoid monkeypatching sys for frames tests It's software bankruptcy and breaks sysmon coverage. --- .pre-commit-config.yaml | 4 ++-- src/structlog/_frames.py | 13 +++++++---- tests/test_frames.py | 39 ++++++++++++++++---------------- tests/test_processors.py | 49 ++++++++++++---------------------------- tests/test_tracebacks.py | 6 +++++ tox.ini | 10 ++++---- 6 files changed, 56 insertions(+), 65 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d5281d11..196255d5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,12 +4,12 @@ ci: repos: - repo: https://github.com/psf/black - rev: 23.11.0 + rev: 23.12.1 hooks: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.7 + rev: v0.1.9 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/src/structlog/_frames.py b/src/structlog/_frames.py index cd96f33b..a7326eb6 100644 --- a/src/structlog/_frames.py +++ b/src/structlog/_frames.py @@ -10,6 +10,7 @@ from io import StringIO from types import FrameType +from typing import Callable from .contextvars import _ASYNC_CALLING_STACK from .typing import ExcInfo @@ -37,21 +38,25 @@ def _format_exception(exc_info: ExcInfo) -> str: def _find_first_app_frame_and_name( additional_ignores: list[str] | None = None, + *, + _getframe: Callable[[], FrameType] = sys._getframe, ) -> tuple[FrameType, str]: """ Remove all intra-structlog calls and return the relevant app frame. - Parameters: - + Args: additional_ignores: Additional names with which the first frame must not start. - Returns: + _getframe: + Callable to find current frame. Only for testing to avoid + monkeypatching of sys._getframe. + Returns: tuple of (frame, name) """ ignores = ["structlog"] + (additional_ignores or []) - f = _ASYNC_CALLING_STACK.get(sys._getframe()) + f = _ASYNC_CALLING_STACK.get(_getframe()) name = f.f_globals.get("__name__") or "?" while any(tuple(name.startswith(i) for i in ignores)): if f.f_back is None: diff --git a/tests/test_frames.py b/tests/test_frames.py index 00263d69..7eb1128d 100644 --- a/tests/test_frames.py +++ b/tests/test_frames.py @@ -9,8 +9,6 @@ from pretend import stub -import structlog._frames - from structlog._frames import ( _find_first_app_frame_and_name, _format_exception, @@ -19,68 +17,69 @@ class TestFindFirstAppFrameAndName: - def test_ignores_structlog_by_default(self, monkeypatch): + def test_ignores_structlog_by_default(self): """ No matter what you pass in, structlog frames get always ignored. """ f1 = stub(f_globals={"__name__": "test"}, f_back=None) f2 = stub(f_globals={"__name__": "structlog.blubb"}, f_back=f1) - monkeypatch.setattr(structlog._frames.sys, "_getframe", lambda: f2) - f, n = _find_first_app_frame_and_name() + + f, n = _find_first_app_frame_and_name(_getframe=lambda: f2) assert (f1, "test") == (f, n) - def test_ignoring_of_additional_frame_names_works(self, monkeypatch): + def test_ignoring_of_additional_frame_names_works(self): """ Additional names are properly ignored too. """ f1 = stub(f_globals={"__name__": "test"}, f_back=None) f2 = stub(f_globals={"__name__": "ignored.bar"}, f_back=f1) f3 = stub(f_globals={"__name__": "structlog.blubb"}, f_back=f2) - monkeypatch.setattr(structlog._frames.sys, "_getframe", lambda: f3) - f, n = _find_first_app_frame_and_name(additional_ignores=["ignored"]) + + f, n = _find_first_app_frame_and_name( + additional_ignores=["ignored"], _getframe=lambda: f3 + ) assert (f1, "test") == (f, n) - def test_tolerates_missing_name(self, monkeypatch): + def test_tolerates_missing_name(self): """ Use ``?`` if `f_globals` lacks a `__name__` key """ f1 = stub(f_globals={}, f_back=None) - monkeypatch.setattr(structlog._frames.sys, "_getframe", lambda: f1) - f, n = _find_first_app_frame_and_name() + + f, n = _find_first_app_frame_and_name(_getframe=lambda: f1) assert (f1, "?") == (f, n) - def test_tolerates_name_explicitly_None_oneframe(self, monkeypatch): + def test_tolerates_name_explicitly_None_oneframe(self): """ Use ``?`` if `f_globals` has a `None` valued `__name__` key """ f1 = stub(f_globals={"__name__": None}, f_back=None) - monkeypatch.setattr(structlog._frames.sys, "_getframe", lambda: f1) - f, n = _find_first_app_frame_and_name() + + f, n = _find_first_app_frame_and_name(_getframe=lambda: f1) assert (f1, "?") == (f, n) - def test_tolerates_name_explicitly_None_manyframe(self, monkeypatch): + def test_tolerates_name_explicitly_None_manyframe(self): """ Use ``?`` if `f_globals` has a `None` valued `__name__` key, multiple frames up. """ f1 = stub(f_globals={"__name__": None}, f_back=None) f2 = stub(f_globals={"__name__": "structlog.blubb"}, f_back=f1) - monkeypatch.setattr(structlog._frames.sys, "_getframe", lambda: f2) - f, n = _find_first_app_frame_and_name() + f, n = _find_first_app_frame_and_name(_getframe=lambda: f2) assert (f1, "?") == (f, n) - def test_tolerates_f_back_is_None(self, monkeypatch): + def test_tolerates_f_back_is_None(self): """ Use ``?`` if all frames are in ignored frames. """ f1 = stub(f_globals={"__name__": "structlog"}, f_back=None) - monkeypatch.setattr(structlog._frames.sys, "_getframe", lambda: f1) - f, n = _find_first_app_frame_and_name() + + f, n = _find_first_app_frame_and_name(_getframe=lambda: f1) assert (f1, "?") == (f, n) diff --git a/tests/test_processors.py b/tests/test_processors.py index 3d9a2870..02589192 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -865,23 +865,12 @@ def test_additional_ignores(self, monkeypatch: pytest.MonkeyPatch) -> None: processor = self.make_processor(None, additional_ignores) event_dict: EventDict = {"event": test_message} - # `functools.partial` is used instead of a lambda because a lambda will - # add an additional frame in a module that should not be ignored. - _sys_getframe = functools.partial(additional_frame, sys._getframe) - - # WARNING: The below three lines are sensitive to relative line numbers - # (i.e. the invocation of processor must be two lines after the - # invocation of get_callsite_parameters) and is order sensitive (i.e. - # monkeypatch.setattr must occur after get_callsite_parameters but - # before invocation of processor). - callsite_params = self.get_callsite_parameters(2) - monkeypatch.setattr(sys, "_getframe", value=_sys_getframe) + # Warning: the next two lines must appear exactly like this to make + # line numbers match. + callsite_params = self.get_callsite_parameters(1) actual = processor(None, None, event_dict) - expected = { - "event": test_message, - **callsite_params, - } + expected = {"event": test_message, **callsite_params} assert expected == actual @@ -941,10 +930,7 @@ def test_processor( callsite_params = self.filter_parameter_dict( callsite_params, parameter_strings ) - expected = { - "event": test_message, - **callsite_params, - } + expected = {"event": test_message, **callsite_params} assert expected == actual @@ -1029,10 +1015,7 @@ def test_e2e( for key, value in json.loads(string_io.getvalue()).items() if not key.startswith("_") } - expected = { - "event": test_message, - **callsite_params, - } + expected = {"event": test_message, **callsite_params} assert expected == actual @@ -1044,18 +1027,16 @@ def make_processor( ) -> CallsiteParameterAdder: """ Creates a ``CallsiteParameterAdder`` with parameters matching the - supplied ``parameter_strings`` values and with the supplied - ``additional_ignores`` values. - - Parameters: + supplied *parameter_strings* values and with the supplied + *additional_ignores* values. + Args: parameter_strings: Strings for which corresponding ``CallsiteParameters`` should be included in the resulting ``CallsiteParameterAdded``. additional_ignores: - - Used as ``additional_ignores`` for the resulting + Used as *additional_ignores* for the resulting ``CallsiteParameterAdded``. """ if parameter_strings is None: @@ -1097,11 +1078,10 @@ def filter_parameter_dict( cls, input: dict[str, object], parameter_strings: set[str] | None ) -> dict[str, object]: """ - Returns a dictionary that is equivalent to ``input`` but with all keys - not in ``parameter_strings`` removed. - - Parameters: + Returns a dictionary that is equivalent to *input* but with all keys + not in *parameter_strings* removed. + Args: parameter_strings: The keys to keep in the dictionary, if this value is ``None`` then all keys matching ``cls.parameter_strings`` are kept. @@ -1120,8 +1100,7 @@ def get_callsite_parameters(cls, offset: int = 1) -> dict[str, object]: This function creates dictionary of callsite parameters for the line that is ``offset`` lines after the invocation of this function. - Parameters: - + Args: offset: The amount of lines after the invocation of this function that callsite parameters should be generated for. diff --git a/tests/test_tracebacks.py b/tests/test_tracebacks.py index b3f762ea..71956b36 100644 --- a/tests/test_tracebacks.py +++ b/tests/test_tracebacks.py @@ -469,6 +469,12 @@ def bar(n): ) == frames[0] ) + + # If we run the tests under Python 3.12 with sysmon enabled, it inserts + # frames at the end. + if sys.version_info >= (3, 12): + frames = [f for f in frames if "coverage" not in f.filename] + # Depending on whether we invoke pytest directly or run tox, either "foo()" # or "bar()" is at the end of the stack. assert frames[-1] in [ diff --git a/tox.ini b/tox.ini index 36c773ac..8508b533 100644 --- a/tox.ini +++ b/tox.ini @@ -24,10 +24,12 @@ commands = # Run oldest and latest under Coverage. -[testenv:py3{8,11}-tests{,-colorama,-be,-rich}] +[testenv:py3{8,12}-tests{,-colorama,-be,-rich}] +set_env = + py312: COVERAGE_CORE=sysmon deps = coverage[toml] - py311: twisted + py312: twisted colorama: colorama rich: rich be: better-exceptions @@ -35,8 +37,8 @@ commands = coverage run -m pytest {posargs} [testenv:coverage-report] -# Keep in sync with .python-version -base_python = py311 +# Keep in sync with .python-version-default +base_python = py312 deps = coverage[toml] skip_install = true parallel_show_output = true From f336f509faa9320848acd3a49b32f642ab004088 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 29 Dec 2023 08:19:20 +0100 Subject: [PATCH 1145/1520] Add columns to ConsoleRenderer for more control how k/vs are formatted (#577) * dev: add columns to ConsoleRenderer for more control how k/vs are formatted * Add PR# * Wordsmith * update readme screenshot --- CHANGELOG.md | 13 + docs/_static/console_renderer.png | Bin 319191 -> 253716 bytes docs/api.rst | 6 + docs/console-output.md | 92 +++++-- show_off.py | 2 + src/structlog/dev.py | 394 +++++++++++++++++++++++------- src/structlog/stdlib.py | 19 +- tests/test_dev.py | 172 +++++++++---- tests/test_stdlib.py | 2 +- 9 files changed, 541 insertions(+), 159 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a0e35cf..36360ed1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,10 +17,23 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ### Added +- The colorful development logger is now even more configurable! + Choose freely your colors and the order of the key-value pairs! + Implement your own formatters for certain keys! + + Implementing the output on top of the new columns API has changed the default very slightly, but shouldn't be noticeable. + [#577](https://github.com/hynek/structlog/issues/577) + - Async log methods (those starting with an `a`) now also support the collection of callsite information using `structlog.processors.CallsiteParameterAdder`. [#565](https://github.com/hynek/structlog/issues/565) +### Changed + +- `structlog.stdlib.recreate_defaults()` now also adds `structlog.stdlib.add_logger_name` to the processors. + Check out the updated screenshot in the README! + + ### Fixed - The return value from `get_logger()` (a `BoundLoggerLazyProxy`) now passes `isinstance`-checks against `structlog.typing.BindableLogger` on Python 3.12. diff --git a/docs/_static/console_renderer.png b/docs/_static/console_renderer.png index 20a123e2dae0d20f42fdf9194234dcf395951d3f..df8e503d40c208856076cbdc904248c0713e0fdf 100644 GIT binary patch literal 253716 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%0A;^bx#j%Os@qHj*nb%&0Rvp3>~R~O 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

    FRVNH3=;KqvzMhKxUkR5+*kb_QtY8Dg|aPO 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

    - - - + - - - + - - - +

    From b756bdf0a8b3595808bf75bef805abe2ae3bdd43 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 29 Dec 2023 09:33:00 +0100 Subject: [PATCH 1148/1520] Actually avoid artifacts --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8b09286f..a86a1be9 100644 --- a/README.md +++ b/README.md @@ -40,11 +40,11 @@ The output format is just as flexible and *structlog* comes with support for JSO Especially those generously supporting us at the *The Organization* tier and higher:

    - + - + - +

    From 9767d82d9b41a1d2ea4aeec3096b7a7214217427 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 29 Dec 2023 09:34:35 +0100 Subject: [PATCH 1149/1520] what is happening GitHub --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index a86a1be9..49441583 100644 --- a/README.md +++ b/README.md @@ -41,9 +41,7 @@ Especially those generously supporting us at the *The Organization* tier and hig

    - -

    From d3150deee90de4b6595e015c5f35d748b1a614be Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 29 Dec 2023 10:05:08 +0100 Subject: [PATCH 1150/1520] It's args and kwargs --- .github/CONTRIBUTING.md | 8 +++----- src/structlog/_base.py | 14 +++----------- src/structlog/_config.py | 12 +++--------- src/structlog/_log_levels.py | 3 +-- src/structlog/_output.py | 17 ++++++----------- src/structlog/_utils.py | 15 +++++++++++---- src/structlog/processors.py | 34 +++++++++++----------------------- src/structlog/stdlib.py | 14 ++++---------- src/structlog/testing.py | 3 +-- src/structlog/threadlocal.py | 7 ++----- src/structlog/tracebacks.py | 6 ++---- src/structlog/twisted.py | 9 +++------ src/structlog/typing.py | 8 +++----- tests/test_processors.py | 3 +-- 14 files changed, 54 insertions(+), 99 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 1698e6f0..414ae2a8 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -128,13 +128,11 @@ But it's way more comfortable to run it locally and catch avoidable errors befor """ Do something. - Parameters: - - x: A very important parameter. + Args: + x: A very important parameter. Returns: - - A very important return value. + A very important return value. """ ``` - If you add or change public APIs, tag the docstring using `.. versionadded:: 16.0.0 WHAT` or `.. versionchanged:: 16.2.0 WHAT`. diff --git a/src/structlog/_base.py b/src/structlog/_base.py index 78396831..dc5873ce 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -79,7 +79,6 @@ def unbind(self, *keys: str) -> BoundLoggerBase: Return a new logger with *keys* removed from the context. Raises: - KeyError: If the key is not part of the context. """ bl = self.bind() @@ -123,8 +122,7 @@ def _process_event( Call it to combine your *event* and *context* into an event_dict and process using the processor chain. - Parameters: - + Args: method_name: The name of the logger method. Is passed into the processors. @@ -137,7 +135,6 @@ def _process_event( *event_kw* ``{"bar": 42}``. Raises: - structlog.DropEvent: if log entry should be dropped. ValueError: @@ -148,7 +145,6 @@ def _process_event( `tuple` of ``(*args, **kw)`` .. note:: - Despite underscore available to custom wrapper classes. See also `custom-wrappers`. @@ -197,8 +193,7 @@ def _proxy_to_logger( handling :exc:`structlog.DropEvent`, and finally calls *method_name* on :attr:`_logger` with the result. - Parameters: - + Args: method_name: The name of the method that's going to get called. Technically it should be identical to the method the user called because it @@ -213,7 +208,6 @@ def _proxy_to_logger( *event_kw* ``{"bar": 42}``. .. note:: - Despite underscore available to custom wrapper classes. See also `custom-wrappers`. @@ -232,12 +226,10 @@ def get_context(bound_logger: BindableLogger) -> Context: The type of *bound_logger* and the type returned depend on your configuration. - Parameters: - + Args: bound_logger: The bound logger whose context you want. Returns: - The *actual* context from *bound_logger*. It is *not* copied first. .. versionadded:: 20.2.0 diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 40cc09e1..1999b046 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -114,8 +114,7 @@ def get_logger(*args: Any, **initial_values: Any) -> Any: >>> log.info("hello", x=42) y=23 x=42 event='hello' - Parameters: - + Args: args: *Optional* positional arguments that are passed unmodified to the logger factory. Therefore it depends on the factory what they @@ -124,7 +123,6 @@ def get_logger(*args: Any, **initial_values: Any) -> Any: initial_values: Values that are used to pre-populate your contexts. Returns: - A proxy that creates a correctly configured bound logger when necessary. The type of that bound logger depends on your configuration and is `structlog.BoundLogger` by default. @@ -169,8 +167,7 @@ def wrap_logger( In other words: selective overwriting of the defaults while keeping some *is* possible. - Parameters: - + Args: initial_values: Values that are used to pre-populate your contexts. logger_factory_args: @@ -178,7 +175,6 @@ def wrap_logger( the logger factory if not `None`. Returns: - A proxy that creates a correctly configured bound logger when necessary. @@ -217,8 +213,7 @@ def configure( Use `reset_defaults` to undo your changes. - Parameters: - + Args: processors: The processor chain. See :doc:`processors` for details. wrapper_class: @@ -269,7 +264,6 @@ def configure_once( `configure_once` before. Raises: - RuntimeWarning: if repeated configuration is attempted. """ if not _CONFIG.is_configured: diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index 7d1a005c..a571d14c 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -139,8 +139,7 @@ def make_filtering_bound_logger(min_level: int) -> type[FilteringBoundLogger]: - You *can* have (much) more fine-grained filtering by :ref:`writing a simple processor `. - Parameters: - + Args: min_level: The log level as an integer. You can use the constants from `logging` like ``logging.INFO`` or pass the values directly. See diff --git a/src/structlog/_output.py b/src/structlog/_output.py index e6fb2420..c0aad4a5 100644 --- a/src/structlog/_output.py +++ b/src/structlog/_output.py @@ -36,8 +36,7 @@ class PrintLogger: """ Print events into a file. - Parameters: - + Args: file: File to print to. (default: `sys.stdout`) >>> from structlog import PrintLogger @@ -122,8 +121,7 @@ class PrintLoggerFactory: To be used with `structlog.configure`\ 's ``logger_factory``. - Parameters: - + Args: file: File to print to. (default: `sys.stdout`) Positional arguments are silently ignored. @@ -142,8 +140,7 @@ class WriteLogger: """ Write events into a file. - Parameters: - + Args: file: File to print to. (default: `sys.stdout`) >>> from structlog import WriteLogger @@ -232,8 +229,7 @@ class WriteLoggerFactory: To be used with `structlog.configure`\ 's ``logger_factory``. - Parameters: - + Args: file: File to print to. (default: `sys.stdout`) Positional arguments are silently ignored. @@ -252,7 +248,7 @@ class BytesLogger: r""" Writes bytes into a file. - Parameters: + Args: file: File to print to. (default: `sys.stdout`\ ``.buffer``) Useful if you follow `current logging best practices @@ -336,8 +332,7 @@ class BytesLoggerFactory: To be used with `structlog.configure`\ 's ``logger_factory``. - Parameters: - + Args: file: File to print to. (default: `sys.stdout`\ ``.buffer``) Positional arguments are silently ignored. diff --git a/src/structlog/_utils.py b/src/structlog/_utils.py index 583006b8..5bc8882f 100644 --- a/src/structlog/_utils.py +++ b/src/structlog/_utils.py @@ -13,20 +13,27 @@ import sys from contextlib import suppress -from typing import Any, Callable +from typing import Any, Callable, TypeVar -def until_not_interrupted(f: Callable[..., Any], *args: Any, **kw: Any) -> Any: +T = TypeVar("T") + + +def until_not_interrupted( + f: Callable[..., T], *args: object, **kw: object +) -> T: """ Retry until *f* succeeds or an exception that isn't caused by EINTR occurs. - Parameters: - + Args: f: A callable like a function. *args: Positional arguments for *f*. **kw: Keyword arguments for *f*. + + Returns: + Whatever *f* returns. """ while True: try: diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 181dc6fc..b95bee0c 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -63,8 +63,7 @@ class KeyValueRenderer: """ Render ``event_dict`` as a list of ``Key=repr(Value)`` pairs. - Parameters: - + Args: sort_keys: Whether to sort keys when formatting. key_order: @@ -119,8 +118,7 @@ class LogfmtRenderer: .. _logfmt: https://brandur.org/logfmt - Parameters: - + Args: sort_keys: Whether to sort keys when formatting. key_order: @@ -138,7 +136,6 @@ class LogfmtRenderer: ``flag=false``. Raises: - ValueError: If a key contains non printable or space characters. .. versionadded:: 21.5.0 @@ -237,8 +234,7 @@ class UnicodeEncoder: """ Encode unicode values in ``event_dict``. - Parameters: - + Args: encoding: Encoding to encode to (default: ``"utf-8"``). errors: @@ -272,8 +268,7 @@ class UnicodeDecoder: """ Decode byte string values in ``event_dict``. - Parameters: - + Args: encoding: Encoding to decode from (default: ``"utf-8"``). errors: How to cope with encoding errors (default: ``"replace"``). @@ -308,8 +303,7 @@ class JSONRenderer: """ Render the ``event_dict`` using ``serializer(event_dict, **dumps_kw)``. - Parameters: - + Args: dumps_kw: Are passed unmodified to *serializer*. If *default* is passed, it will disable support for ``__structlog__``-based serialization. @@ -385,8 +379,7 @@ class ExceptionRenderer: If there is no ``exc_info`` key, the *event_dict* is not touched. This behavior is analog to the one of the stdlib's logging. - Parameters: - + Args: exception_formatter: A callable that is used to format the exception from the ``exc_info`` field into the ``exception`` field. @@ -459,8 +452,7 @@ class TimeStamper: """ Add a timestamp to ``event_dict``. - Parameters: - + Args: fmt: strftime format string, or ``"iso"`` for `ISO 8601 `_, or `None` for a `UNIX @@ -608,8 +600,7 @@ class ExceptionPrettyPrinter: """ Pretty print exceptions and remove them from the ``event_dict``. - Parameters: - + Args: file: Target file for output (default: ``sys.stdout``). This processor is mostly for development and testing so you can read @@ -661,8 +652,7 @@ class StackInfoRenderer: involving an exception and works analogously to the *stack_info* argument of the Python standard library logging. - Parameters: - + Args: additional_ignores: By default, stack frames coming from *structlog* are ignored. With this argument you can add additional names that are ignored, before @@ -745,8 +735,7 @@ class CallsiteParameterAdder: The keys used for callsite parameters in the event dictionary are the string values of `CallsiteParameter` enum members. - Parameters: - + Args: parameters: A collection of `CallsiteParameter` values that should be added to the event dictionary. @@ -880,8 +869,7 @@ class EventRenamer: some processors may rely on the presence and meaning of the ``event`` key. - Parameters: - + Args: to: Rename ``event_dict["event"]`` to ``event_dict[to]`` replace_by: diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index f33c7484..a4f37247 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -74,8 +74,7 @@ def recreate_defaults(*, log_level: int | None = logging.NOTSET) -> None: configure it yourself. .. versionadded:: 22.1.0 - .. versionchanged:: 23.3.0 - Added `add_logger_name`. + .. versionchanged:: 23.3.0 Added `add_logger_name`. """ if log_level is not None: kw = {"force": True} @@ -160,7 +159,6 @@ def unbind(self, *keys: str) -> BoundLogger: Return a new logger with *keys* removed from the context. Raises: - KeyError: If the key is not part of the context. """ return super().unbind(*keys) # type: ignore[return-value] @@ -657,8 +655,7 @@ class LoggerFactory: >>> from structlog.stdlib import LoggerFactory >>> configure(logger_factory=LoggerFactory()) - Parameters: - + Args: ignore_frame_names: When guessing the name of a logger, skip frames whose names *start* with one of these. For example, in pyramid applications you'll @@ -816,8 +813,7 @@ class ExtraAdder: This processor can be used for adding data passed in the ``extra`` parameter of the `logging` module's log methods to the event dictionary. - Parameters: - + Args: allow: An optional collection of attributes that, if present in `logging.LogRecord` objects, will be copied to event dictionaries. @@ -908,8 +904,7 @@ class ProcessorFormatter(logging.Formatter): Please refer to :ref:`processor-formatter` for examples. - Parameters: - + Args: foreign_pre_chain: If not `None`, it is used as a processor chain that is applied to **non**-*structlog* log entries before the event dictionary is @@ -971,7 +966,6 @@ class ProcessorFormatter(logging.Formatter): message, otherwise use ``str(record.msg)``. (default: True) Raises: - TypeError: If both or neither *processor* and *processors* are passed. .. versionadded:: 17.1.0 diff --git a/src/structlog/testing.py b/src/structlog/testing.py index 90c6b785..94107bf6 100644 --- a/src/structlog/testing.py +++ b/src/structlog/testing.py @@ -139,8 +139,7 @@ class CapturedCall(NamedTuple): Can also be unpacked like a tuple. - Parameters: - + Args: method_name: The method name that got called. args: A tuple of the positional arguments. diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index b6b3c69b..c9e412e4 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -83,8 +83,7 @@ def wrap_dict(dict_class: type[Context]) -> type[Context]: The wrapped class and used to keep global in the current thread. - Parameters: - + Args: dict_class: Class used for keeping context. .. deprecated:: 22.1.0 @@ -106,13 +105,11 @@ def as_immutable(logger: TLLogger) -> TLLogger: """ Extract the context from a thread local logger into an immutable logger. - Parameters: - + Args: logger (structlog.typing.BindableLogger): A logger with *possibly* thread local state. Returns: - :class:`~structlog.BoundLogger` with an immutable context. .. deprecated:: 22.1.0 diff --git a/src/structlog/tracebacks.py b/src/structlog/tracebacks.py index f5d13c8f..76c6afc3 100644 --- a/src/structlog/tracebacks.py +++ b/src/structlog/tracebacks.py @@ -127,8 +127,7 @@ def extract( """ Extract traceback information. - Parameters: - + Args: exc_type: Exception type. exc_value: Exception value. @@ -220,8 +219,7 @@ class ExceptionDictTransformer: These dictionaries are based on :class:`Stack` instances generated by :func:`extract()` and can be dumped to JSON. - Parameters: - + Args: show_locals: Whether or not to include the values of a stack frame's local variables. diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index 4f3f1abe..f146eadd 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -204,8 +204,7 @@ class PlainFileLogObserver: Great to just print JSON to stdout where you catch it with something like runit. - Parameters: - + Args: file: File to print to. .. versionadded:: 0.2.0 @@ -229,8 +228,7 @@ class JSONLogObserverWrapper: """ Wrap a log *observer* and render non-`JSONRenderer` entries to JSON. - Parameters: - + Args: observer (ILogObserver): Twisted log observer to wrap. For example :class:`PlainFileObserver` or Twisted's stock `FileLogObserver @@ -293,8 +291,7 @@ class EventAdapter: `_ behave as expected. - Parameters: - + Args: dictRenderer: Renderer that is used for the actual log message. Please note that structlog comes with a dedicated `JSONRenderer`. diff --git a/src/structlog/typing.py b/src/structlog/typing.py index 217463a1..ed277847 100644 --- a/src/structlog/typing.py +++ b/src/structlog/typing.py @@ -106,14 +106,12 @@ class ExceptionTransformer(Protocol): Used by `structlog.processors.format_exc_info()` and `structlog.processors.ExceptionPrettyPrinter`. - Parameters: - + Args: exc_info: Is the exception tuple to format Returns: - - Anything that can be rendered by the last processor in your chain, - for example, a string or a JSON-serializable structure. + Anything that can be rendered by the last processor in your chain, for + example, a string or a JSON-serializable structure. .. versionadded:: 22.1.0 """ diff --git a/tests/test_processors.py b/tests/test_processors.py index 02589192..04eb6a85 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -1058,8 +1058,7 @@ def filter_parameters( Returns a set containing all ``CallsiteParameter`` members with values that are in ``parameter_strings``. - Parameters: - + Args: parameter_strings: The parameters strings for which corresponding ``CallsiteParameter`` members should be returned. If this value From 683c70f2d1a16ab3fc411cdb5e40dd4558054e2c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 29 Dec 2023 10:52:31 +0100 Subject: [PATCH 1151/1520] Move native loggers into a separate, named module --- src/structlog/__init__.py | 2 +- src/structlog/_config.py | 2 +- src/structlog/_log_levels.py | 215 +------------------------------- src/structlog/_native.py | 235 +++++++++++++++++++++++++++++++++++ 4 files changed, 238 insertions(+), 216 deletions(-) create mode 100644 src/structlog/_native.py diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 2ffe2c86..81d26d7c 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -29,7 +29,7 @@ wrap_logger, ) from structlog._generic import BoundLogger -from structlog._log_levels import make_filtering_bound_logger +from structlog._native import make_filtering_bound_logger from structlog._output import ( BytesLogger, BytesLoggerFactory, diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 1999b046..aa05fd06 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -15,7 +15,7 @@ from typing import Any, Callable, Iterable, Sequence, Type, cast -from ._log_levels import make_filtering_bound_logger +from ._native import make_filtering_bound_logger from ._output import PrintLoggerFactory from .contextvars import merge_contextvars from .dev import ConsoleRenderer, _has_colors, set_exc_info diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index a571d14c..fc6cd1b8 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -9,16 +9,9 @@ from __future__ import annotations -import asyncio -import contextvars import logging -import sys -from typing import Any, Callable - -from ._base import BoundLoggerBase -from .contextvars import _ASYNC_CALLING_STACK -from .typing import EventDict, FilteringBoundLogger +from .typing import EventDict # Adapted from the stdlib @@ -71,209 +64,3 @@ def add_log_level( event_dict["level"] = method_name return event_dict - - -def _nop(self: Any, event: str, *args: Any, **kw: Any) -> Any: - return None - - -async def _anop(self: Any, event: str, *args: Any, **kw: Any) -> Any: - return None - - -def exception( - self: FilteringBoundLogger, event: str, *args: Any, **kw: Any -) -> Any: - kw.setdefault("exc_info", True) - - return self.error(event, *args, **kw) - - -async def aexception( - self: FilteringBoundLogger, event: str, *args: Any, **kw: Any -) -> Any: - """ - .. versionchanged:: 23.3.0 - Callsite parameters are now also collected under asyncio. - """ - # Exception info has to be extracted this early, because it is no longer - # available once control is passed to the executor. - if kw.get("exc_info", True) is True: - kw["exc_info"] = sys.exc_info() - - scs_token = _ASYNC_CALLING_STACK.set(sys._getframe().f_back) # type: ignore[arg-type] - ctx = contextvars.copy_context() - try: - runner = await asyncio.get_running_loop().run_in_executor( - None, - lambda: ctx.run(lambda: self.error(event, *args, **kw)), - ) - finally: - _ASYNC_CALLING_STACK.reset(scs_token) - - return runner - - -def make_filtering_bound_logger(min_level: int) -> type[FilteringBoundLogger]: - """ - Create a new `FilteringBoundLogger` that only logs *min_level* or higher. - - The logger is optimized such that log levels below *min_level* only consist - of a ``return None``. - - All familiar log methods are present, with async variants of each that are - prefixed by an ``a``. Therefore, the async version of ``log.info("hello")`` - is ``await log.ainfo("hello")``. - - Additionally it has a ``log(self, level: int, **kw: Any)`` method to mirror - `logging.Logger.log` and `structlog.stdlib.BoundLogger.log`. - - Compared to using *structlog*'s standard library integration and the - `structlog.stdlib.filter_by_level` processor: - - - It's faster because once the logger is built at program start; it's a - static class. - - For the same reason you can't change the log level once configured. Use - the dynamic approach of `standard-library` instead, if you need this - feature. - - You *can* have (much) more fine-grained filtering by :ref:`writing a - simple processor `. - - Args: - min_level: - The log level as an integer. You can use the constants from - `logging` like ``logging.INFO`` or pass the values directly. See - `this table from the logging docs - `_ for - possible values. - - .. versionadded:: 20.2.0 - .. versionchanged:: 21.1.0 The returned loggers are now pickleable. - .. versionadded:: 20.1.0 The ``log()`` method. - .. versionadded:: 22.2.0 - Async variants ``alog()``, ``adebug()``, ``ainfo()``, and so forth. - """ - - return _LEVEL_TO_FILTERING_LOGGER[min_level] - - -def _make_filtering_bound_logger(min_level: int) -> type[FilteringBoundLogger]: - """ - Create a new `FilteringBoundLogger` that only logs *min_level* or higher. - - The logger is optimized such that log levels below *min_level* only consist - of a ``return None``. - """ - - def make_method( - level: int, - ) -> tuple[Callable[..., Any], Callable[..., Any]]: - if level < min_level: - return _nop, _anop - - name = _LEVEL_TO_NAME[level] - - def meth(self: Any, event: str, *args: Any, **kw: Any) -> Any: - if not args: - return self._proxy_to_logger(name, event, **kw) - - return self._proxy_to_logger(name, event % args, **kw) - - async def ameth(self: Any, event: str, *args: Any, **kw: Any) -> Any: - """ - .. versionchanged:: 23.3.0 - Callsite parameters are now also collected under asyncio. - """ - if args: - event = event % args - - scs_token = _ASYNC_CALLING_STACK.set(sys._getframe().f_back) # type: ignore[arg-type] - ctx = contextvars.copy_context() - try: - await asyncio.get_running_loop().run_in_executor( - None, - lambda: ctx.run( - lambda: self._proxy_to_logger(name, event, **kw) - ), - ) - finally: - _ASYNC_CALLING_STACK.reset(scs_token) - - meth.__name__ = name - ameth.__name__ = f"a{name}" - - return meth, ameth - - def log(self: Any, level: int, event: str, *args: Any, **kw: Any) -> Any: - if level < min_level: - return None - name = _LEVEL_TO_NAME[level] - - if not args: - return self._proxy_to_logger(name, event, **kw) - - return self._proxy_to_logger(name, event % args, **kw) - - async def alog( - self: Any, level: int, event: str, *args: Any, **kw: Any - ) -> Any: - """ - .. versionchanged:: 23.3.0 - Callsite parameters are now also collected under asyncio. - """ - if level < min_level: - return None - name = _LEVEL_TO_NAME[level] - if args: - event = event % args - - scs_token = _ASYNC_CALLING_STACK.set(sys._getframe().f_back) # type: ignore[arg-type] - ctx = contextvars.copy_context() - try: - runner = await asyncio.get_running_loop().run_in_executor( - None, - lambda: ctx.run( - lambda: self._proxy_to_logger(name, event, **kw) - ), - ) - finally: - _ASYNC_CALLING_STACK.reset(scs_token) - return runner - - meths: dict[str, Callable[..., Any]] = {"log": log, "alog": alog} - for lvl, name in _LEVEL_TO_NAME.items(): - meths[name], meths[f"a{name}"] = make_method(lvl) - - meths["exception"] = exception - meths["aexception"] = aexception - meths["fatal"] = meths["error"] - meths["afatal"] = meths["aerror"] - meths["warn"] = meths["warning"] - meths["awarn"] = meths["awarning"] - meths["msg"] = meths["info"] - meths["amsg"] = meths["ainfo"] - - return type( - "BoundLoggerFilteringAt%s" - % (_LEVEL_TO_NAME.get(min_level, "Notset").capitalize()), - (BoundLoggerBase,), - meths, - ) - - -# Pre-create all possible filters to make them pickleable. -BoundLoggerFilteringAtNotset = _make_filtering_bound_logger(NOTSET) -BoundLoggerFilteringAtDebug = _make_filtering_bound_logger(DEBUG) -BoundLoggerFilteringAtInfo = _make_filtering_bound_logger(INFO) -BoundLoggerFilteringAtWarning = _make_filtering_bound_logger(WARNING) -BoundLoggerFilteringAtError = _make_filtering_bound_logger(ERROR) -BoundLoggerFilteringAtCritical = _make_filtering_bound_logger(CRITICAL) - -_LEVEL_TO_FILTERING_LOGGER = { - CRITICAL: BoundLoggerFilteringAtCritical, - ERROR: BoundLoggerFilteringAtError, - WARNING: BoundLoggerFilteringAtWarning, - INFO: BoundLoggerFilteringAtInfo, - DEBUG: BoundLoggerFilteringAtDebug, - NOTSET: BoundLoggerFilteringAtNotset, -} diff --git a/src/structlog/_native.py b/src/structlog/_native.py new file mode 100644 index 00000000..13d54d37 --- /dev/null +++ b/src/structlog/_native.py @@ -0,0 +1,235 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the MIT License. See the LICENSE file in the root of this +# repository for complete details. + +""" +structlog's native high-performance loggers. +""" + +from __future__ import annotations + +import asyncio +import contextvars +import sys + +from typing import Any, Callable + +from ._base import BoundLoggerBase +from ._log_levels import ( + _LEVEL_TO_NAME, + CRITICAL, + DEBUG, + ERROR, + INFO, + NOTSET, + WARNING, +) +from .contextvars import _ASYNC_CALLING_STACK +from .typing import FilteringBoundLogger + + +def _nop(self: Any, event: str, *args: Any, **kw: Any) -> Any: + return None + + +async def _anop(self: Any, event: str, *args: Any, **kw: Any) -> Any: + return None + + +def exception( + self: FilteringBoundLogger, event: str, *args: Any, **kw: Any +) -> Any: + kw.setdefault("exc_info", True) + + return self.error(event, *args, **kw) + + +async def aexception( + self: FilteringBoundLogger, event: str, *args: Any, **kw: Any +) -> Any: + """ + .. versionchanged:: 23.3.0 + Callsite parameters are now also collected under asyncio. + """ + # Exception info has to be extracted this early, because it is no longer + # available once control is passed to the executor. + if kw.get("exc_info", True) is True: + kw["exc_info"] = sys.exc_info() + + scs_token = _ASYNC_CALLING_STACK.set(sys._getframe().f_back) # type: ignore[arg-type] + ctx = contextvars.copy_context() + try: + runner = await asyncio.get_running_loop().run_in_executor( + None, + lambda: ctx.run(lambda: self.error(event, *args, **kw)), + ) + finally: + _ASYNC_CALLING_STACK.reset(scs_token) + + return runner + + +def make_filtering_bound_logger(min_level: int) -> type[FilteringBoundLogger]: + """ + Create a new `FilteringBoundLogger` that only logs *min_level* or higher. + + The logger is optimized such that log levels below *min_level* only consist + of a ``return None``. + + All familiar log methods are present, with async variants of each that are + prefixed by an ``a``. Therefore, the async version of ``log.info("hello")`` + is ``await log.ainfo("hello")``. + + Additionally it has a ``log(self, level: int, **kw: Any)`` method to mirror + `logging.Logger.log` and `structlog.stdlib.BoundLogger.log`. + + Compared to using *structlog*'s standard library integration and the + `structlog.stdlib.filter_by_level` processor: + + - It's faster because once the logger is built at program start; it's a + static class. + - For the same reason you can't change the log level once configured. Use + the dynamic approach of `standard-library` instead, if you need this + feature. + - You *can* have (much) more fine-grained filtering by :ref:`writing a + simple processor `. + + Args: + min_level: + The log level as an integer. You can use the constants from + `logging` like ``logging.INFO`` or pass the values directly. See + `this table from the logging docs + `_ for + possible values. + + .. versionadded:: 20.2.0 + .. versionchanged:: 21.1.0 The returned loggers are now pickleable. + .. versionadded:: 20.1.0 The ``log()`` method. + .. versionadded:: 22.2.0 + Async variants ``alog()``, ``adebug()``, ``ainfo()``, and so forth. + """ + + return _LEVEL_TO_FILTERING_LOGGER[min_level] + + +def _make_filtering_bound_logger(min_level: int) -> type[FilteringBoundLogger]: + """ + Create a new `FilteringBoundLogger` that only logs *min_level* or higher. + + The logger is optimized such that log levels below *min_level* only consist + of a ``return None``. + """ + + def make_method( + level: int, + ) -> tuple[Callable[..., Any], Callable[..., Any]]: + if level < min_level: + return _nop, _anop + + name = _LEVEL_TO_NAME[level] + + def meth(self: Any, event: str, *args: Any, **kw: Any) -> Any: + if not args: + return self._proxy_to_logger(name, event, **kw) + + return self._proxy_to_logger(name, event % args, **kw) + + async def ameth(self: Any, event: str, *args: Any, **kw: Any) -> Any: + """ + .. versionchanged:: 23.3.0 + Callsite parameters are now also collected under asyncio. + """ + if args: + event = event % args + + scs_token = _ASYNC_CALLING_STACK.set(sys._getframe().f_back) # type: ignore[arg-type] + ctx = contextvars.copy_context() + try: + await asyncio.get_running_loop().run_in_executor( + None, + lambda: ctx.run( + lambda: self._proxy_to_logger(name, event, **kw) + ), + ) + finally: + _ASYNC_CALLING_STACK.reset(scs_token) + + meth.__name__ = name + ameth.__name__ = f"a{name}" + + return meth, ameth + + def log(self: Any, level: int, event: str, *args: Any, **kw: Any) -> Any: + if level < min_level: + return None + name = _LEVEL_TO_NAME[level] + + if not args: + return self._proxy_to_logger(name, event, **kw) + + return self._proxy_to_logger(name, event % args, **kw) + + async def alog( + self: Any, level: int, event: str, *args: Any, **kw: Any + ) -> Any: + """ + .. versionchanged:: 23.3.0 + Callsite parameters are now also collected under asyncio. + """ + if level < min_level: + return None + name = _LEVEL_TO_NAME[level] + if args: + event = event % args + + scs_token = _ASYNC_CALLING_STACK.set(sys._getframe().f_back) # type: ignore[arg-type] + ctx = contextvars.copy_context() + try: + runner = await asyncio.get_running_loop().run_in_executor( + None, + lambda: ctx.run( + lambda: self._proxy_to_logger(name, event, **kw) + ), + ) + finally: + _ASYNC_CALLING_STACK.reset(scs_token) + return runner + + meths: dict[str, Callable[..., Any]] = {"log": log, "alog": alog} + for lvl, name in _LEVEL_TO_NAME.items(): + meths[name], meths[f"a{name}"] = make_method(lvl) + + meths["exception"] = exception + meths["aexception"] = aexception + meths["fatal"] = meths["error"] + meths["afatal"] = meths["aerror"] + meths["warn"] = meths["warning"] + meths["awarn"] = meths["awarning"] + meths["msg"] = meths["info"] + meths["amsg"] = meths["ainfo"] + + return type( + "BoundLoggerFilteringAt%s" + % (_LEVEL_TO_NAME.get(min_level, "Notset").capitalize()), + (BoundLoggerBase,), + meths, + ) + + +# Pre-create all possible filters to make them pickleable. +BoundLoggerFilteringAtNotset = _make_filtering_bound_logger(NOTSET) +BoundLoggerFilteringAtDebug = _make_filtering_bound_logger(DEBUG) +BoundLoggerFilteringAtInfo = _make_filtering_bound_logger(INFO) +BoundLoggerFilteringAtWarning = _make_filtering_bound_logger(WARNING) +BoundLoggerFilteringAtError = _make_filtering_bound_logger(ERROR) +BoundLoggerFilteringAtCritical = _make_filtering_bound_logger(CRITICAL) + +_LEVEL_TO_FILTERING_LOGGER = { + CRITICAL: BoundLoggerFilteringAtCritical, + ERROR: BoundLoggerFilteringAtError, + WARNING: BoundLoggerFilteringAtWarning, + INFO: BoundLoggerFilteringAtInfo, + DEBUG: BoundLoggerFilteringAtDebug, + NOTSET: BoundLoggerFilteringAtNotset, +} From 189410845bd27fdecac69370842e5172463fba53 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 29 Dec 2023 11:12:33 +0100 Subject: [PATCH 1152/1520] No need for private variables in a private module --- src/structlog/_log_levels.py | 10 +++++++--- src/structlog/_native.py | 16 ++++++++-------- src/structlog/processors.py | 4 ++-- src/structlog/stdlib.py | 8 ++++---- tests/conftest.py | 4 ++-- tests/test_log_levels.py | 4 ++-- tests/test_stdlib.py | 4 ++-- tests/utils.py | 4 ++-- 8 files changed, 29 insertions(+), 25 deletions(-) diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index fc6cd1b8..bb7e67b8 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -24,7 +24,7 @@ DEBUG = 10 NOTSET = 0 -_NAME_TO_LEVEL = { +NAME_TO_LEVEL = { "critical": CRITICAL, "exception": ERROR, "error": ERROR, @@ -35,12 +35,16 @@ "notset": NOTSET, } -_LEVEL_TO_NAME = { +LEVEL_TO_NAME = { v: k - for k, v in _NAME_TO_LEVEL.items() + for k, v in NAME_TO_LEVEL.items() if k not in ("warn", "exception", "notset") } +# Keep around for backwards-compatability in case someone imported them. +_LEVEL_TO_NAME = LEVEL_TO_NAME +_NAME_TO_LEVEL = NAME_TO_LEVEL + def add_log_level( logger: logging.Logger, method_name: str, event_dict: EventDict diff --git a/src/structlog/_native.py b/src/structlog/_native.py index 13d54d37..e4dbdb11 100644 --- a/src/structlog/_native.py +++ b/src/structlog/_native.py @@ -17,11 +17,11 @@ from ._base import BoundLoggerBase from ._log_levels import ( - _LEVEL_TO_NAME, CRITICAL, DEBUG, ERROR, INFO, + LEVEL_TO_NAME, NOTSET, WARNING, ) @@ -110,7 +110,7 @@ def make_filtering_bound_logger(min_level: int) -> type[FilteringBoundLogger]: Async variants ``alog()``, ``adebug()``, ``ainfo()``, and so forth. """ - return _LEVEL_TO_FILTERING_LOGGER[min_level] + return LEVEL_TO_FILTERING_LOGGER[min_level] def _make_filtering_bound_logger(min_level: int) -> type[FilteringBoundLogger]: @@ -127,7 +127,7 @@ def make_method( if level < min_level: return _nop, _anop - name = _LEVEL_TO_NAME[level] + name = LEVEL_TO_NAME[level] def meth(self: Any, event: str, *args: Any, **kw: Any) -> Any: if not args: @@ -163,7 +163,7 @@ async def ameth(self: Any, event: str, *args: Any, **kw: Any) -> Any: def log(self: Any, level: int, event: str, *args: Any, **kw: Any) -> Any: if level < min_level: return None - name = _LEVEL_TO_NAME[level] + name = LEVEL_TO_NAME[level] if not args: return self._proxy_to_logger(name, event, **kw) @@ -179,7 +179,7 @@ async def alog( """ if level < min_level: return None - name = _LEVEL_TO_NAME[level] + name = LEVEL_TO_NAME[level] if args: event = event % args @@ -197,7 +197,7 @@ async def alog( return runner meths: dict[str, Callable[..., Any]] = {"log": log, "alog": alog} - for lvl, name in _LEVEL_TO_NAME.items(): + for lvl, name in LEVEL_TO_NAME.items(): meths[name], meths[f"a{name}"] = make_method(lvl) meths["exception"] = exception @@ -211,7 +211,7 @@ async def alog( return type( "BoundLoggerFilteringAt%s" - % (_LEVEL_TO_NAME.get(min_level, "Notset").capitalize()), + % (LEVEL_TO_NAME.get(min_level, "Notset").capitalize()), (BoundLoggerBase,), meths, ) @@ -225,7 +225,7 @@ async def alog( BoundLoggerFilteringAtError = _make_filtering_bound_logger(ERROR) BoundLoggerFilteringAtCritical = _make_filtering_bound_logger(CRITICAL) -_LEVEL_TO_FILTERING_LOGGER = { +LEVEL_TO_FILTERING_LOGGER = { CRITICAL: BoundLoggerFilteringAtCritical, ERROR: BoundLoggerFilteringAtError, WARNING: BoundLoggerFilteringAtWarning, diff --git a/src/structlog/processors.py b/src/structlog/processors.py index b95bee0c..3f25dfff 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -35,14 +35,14 @@ _format_exception, _format_stack, ) -from ._log_levels import _NAME_TO_LEVEL, add_log_level +from ._log_levels import NAME_TO_LEVEL, add_log_level from ._utils import get_processname from .tracebacks import ExceptionDictTransformer from .typing import EventDict, ExceptionTransformer, ExcInfo, WrappedLogger __all__ = [ - "_NAME_TO_LEVEL", # some people rely on it being here + "NAME_TO_LEVEL", # some people rely on it being here "add_log_level", "CallsiteParameter", "CallsiteParameterAdder", diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index a4f37247..27ab1f9d 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -24,7 +24,7 @@ from . import _config from ._base import BoundLoggerBase from ._frames import _find_first_app_frame_and_name, _format_stack -from ._log_levels import _LEVEL_TO_NAME, _NAME_TO_LEVEL, add_log_level +from ._log_levels import LEVEL_TO_NAME, NAME_TO_LEVEL, add_log_level from .contextvars import _ASYNC_CALLING_STACK, merge_contextvars from .exceptions import DropEvent from .processors import StackInfoRenderer @@ -230,7 +230,7 @@ def log( Process *event* and call the appropriate logging method depending on *level*. """ - return self._proxy_to_logger(_LEVEL_TO_NAME[level], event, *args, **kw) + return self._proxy_to_logger(LEVEL_TO_NAME[level], event, *args, **kw) fatal = critical @@ -757,7 +757,7 @@ def filter_by_level( ... DropEvent """ - if logger.isEnabledFor(_NAME_TO_LEVEL[method_name]): + if logger.isEnabledFor(NAME_TO_LEVEL[method_name]): return event_dict raise DropEvent @@ -781,7 +781,7 @@ def add_log_level_number( .. versionadded:: 18.2.0 """ - event_dict["level_number"] = _NAME_TO_LEVEL[method_name] + event_dict["level_number"] = NAME_TO_LEVEL[method_name] return event_dict diff --git a/tests/conftest.py b/tests/conftest.py index d68a7272..b2419c9f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -11,7 +11,7 @@ import structlog -from structlog._log_levels import _NAME_TO_LEVEL +from structlog._log_levels import NAME_TO_LEVEL from structlog.testing import CapturingLogger @@ -58,7 +58,7 @@ def __repr__(self): @pytest.fixture( name="stdlib_log_method", - params=[m for m in _NAME_TO_LEVEL if m != "notset"], + params=[m for m in NAME_TO_LEVEL if m != "notset"], ) def _stdlib_log_methods(request): return request.param diff --git a/tests/test_log_levels.py b/tests/test_log_levels.py index ade958e8..2dec4f08 100644 --- a/tests/test_log_levels.py +++ b/tests/test_log_levels.py @@ -9,7 +9,7 @@ import pytest from structlog import make_filtering_bound_logger -from structlog._log_levels import _LEVEL_TO_NAME +from structlog._log_levels import LEVEL_TO_NAME from structlog.contextvars import ( bind_contextvars, clear_contextvars, @@ -259,7 +259,7 @@ def test_exception_pass_exception(self, bl, cl): assert exc is cl.calls[0][2]["event"] - @pytest.mark.parametrize("level", tuple(_LEVEL_TO_NAME.keys())) + @pytest.mark.parametrize("level", tuple(LEVEL_TO_NAME.keys())) def test_pickle(self, level): """ FilteringBoundLogger are pickleable. diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 48c9f36f..f1ae444e 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -26,7 +26,7 @@ get_context, ) from structlog._config import _CONFIG -from structlog._log_levels import _NAME_TO_LEVEL, CRITICAL, WARN +from structlog._log_levels import CRITICAL, NAME_TO_LEVEL, WARN from structlog.dev import ConsoleRenderer from structlog.exceptions import DropEvent from structlog.processors import JSONRenderer, KeyValueRenderer @@ -469,7 +469,7 @@ def test_args_removed_if_empty(self): class TestAddLogLevelNumber: - @pytest.mark.parametrize(("level", "number"), _NAME_TO_LEVEL.items()) + @pytest.mark.parametrize(("level", "number"), NAME_TO_LEVEL.items()) def test_log_level_number_added(self, level, number): """ The log level number is added to the event dict. diff --git a/tests/utils.py b/tests/utils.py index 44b2b6ec..aa68ab46 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -7,10 +7,10 @@ Shared test utilities. """ -from structlog._log_levels import _NAME_TO_LEVEL +from structlog._log_levels import NAME_TO_LEVEL -stdlib_log_methods = [m for m in _NAME_TO_LEVEL if m != "notset"] +stdlib_log_methods = [m for m in NAME_TO_LEVEL if m != "notset"] class CustomError(Exception): From ecd29979c77dec29f1e59ef81d7c3839cde52fb0 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 29 Dec 2023 11:17:43 +0100 Subject: [PATCH 1153/1520] Add a glossary --- docs/glossary.md | 51 ++++++++++++++++++++++++++++++++++++++++++++++++ docs/index.md | 28 ++++++++++++++------------ 2 files changed, 66 insertions(+), 13 deletions(-) create mode 100644 docs/glossary.md diff --git a/docs/glossary.md b/docs/glossary.md new file mode 100644 index 00000000..2cd1ccd3 --- /dev/null +++ b/docs/glossary.md @@ -0,0 +1,51 @@ +# Glossary + +:::{glossary} + +Event Dictionary + Often abbreviated as *event dict*. + It's a dictionary that contains all the information that is logged, with the `event` key having the special role of being the name of the event. + + It's the result of the values bound to the {term}`bound logger`'s context and the key-value pairs passed to the logging method. + It is then passed through the {term}`processor` chain.. + +Bound logger + An instance of a {class}`structlog.typing.BindableLogger` that is returned by either {func}`structlog.get_logger` or the bind/unbind/new methods on it. + + As the name suggests, it's possible to bind key-value pairs to it -- this data is called the **context** of the logger. + + Its methods are the user's logging API and depend on the type of the bound logger. + The two most common implementations are {class}`structlog.BoundLogger` and {class}`structlog.stdlib.BoundLogger`. + + :::{seealso} + {doc}`bound-loggers` + ::: + +Native loggers + Loggers created using {func}`structlog.make_filtering_bound_logger` which includes the default configuration. + + These loggers are very fast and do **not** use the standard library. + +Wrapped Logger + The logger that is wrapped by *structlog* and that is responsible for the actual output. + + By default it's a {class}`structlog.PrintLogger` for native logging. + Another popular choice is {class}`logging.Logger` for standard library logging. + + :::{seealso} + {doc}`standard-library` + ::: + +Processor + A callable that is called on every log entry. + + It receives the return value of its predecessor as an argument and returns a new event dictionary. + This allows for composable transformations of the event dictionary. + + The result of the final processor is passed to the {term}`wrapped logger`. + + :::{seealso} + {doc}`processors` + ::: + +::: diff --git a/docs/index.md b/docs/index.md index a5baa8f1..639a1fce 100644 --- a/docs/index.md +++ b/docs/index.md @@ -27,6 +27,7 @@ why The first chapters teach you all you need to use *structlog* productively. They build gently on each other, so ideally, read them in order. +If anything seems confusing, don't hesitate to have a look at the {doc}`glossary`! ```{toctree} @@ -92,31 +93,32 @@ thread-local ``` -## API Reference +## Reference ```{toctree} :maxdepth: 2 api +glossary ``` -## Project Links +## Indices and tables -```{include} ../README.md -:start-after: "## Project Links" -``` +- {any}`genindex` +- {any}`modindex` +- {any}`glossary` -% stop Sphinx from complaining about orphaned docs, we link them elsewhere ```{toctree} -:hidden: true +:hidden: +:caption: Meta license +PyPI +GitHub +Changelog +Contributing +Security Policy +Funding ``` - - -## Indices and tables - -- {any}`genindex` -- {any}`modindex` From 8b667dd084c05f51e8939248b03a5ade1b678d18 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 29 Dec 2023 11:19:22 +0100 Subject: [PATCH 1154/1520] docs: move deprecated features behind reference --- docs/index.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/index.md b/docs/index.md index 639a1fce..f0725a37 100644 --- a/docs/index.md +++ b/docs/index.md @@ -84,22 +84,22 @@ performance ``` -## Deprecated Features +## Reference ```{toctree} -:maxdepth: 1 +:maxdepth: 2 -thread-local +api +glossary ``` -## Reference +## Deprecated Features ```{toctree} -:maxdepth: 2 +:maxdepth: 1 -api -glossary +thread-local ``` From 629a556301c1e78ef98db7ac2faca5c5ed58c8c4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 29 Dec 2023 11:24:11 +0100 Subject: [PATCH 1155/1520] typos --- docs/glossary.md | 2 +- docs/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/glossary.md b/docs/glossary.md index 2cd1ccd3..b0c4ed16 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -7,7 +7,7 @@ Event Dictionary It's a dictionary that contains all the information that is logged, with the `event` key having the special role of being the name of the event. It's the result of the values bound to the {term}`bound logger`'s context and the key-value pairs passed to the logging method. - It is then passed through the {term}`processor` chain.. + It is then passed through the {term}`processor` chain that can add, modify, and even remove key-value pairs. Bound logger An instance of a {class}`structlog.typing.BindableLogger` that is returned by either {func}`structlog.get_logger` or the bind/unbind/new methods on it. diff --git a/docs/index.md b/docs/index.md index f0725a37..2aa44a02 100644 --- a/docs/index.md +++ b/docs/index.md @@ -27,7 +27,7 @@ why The first chapters teach you all you need to use *structlog* productively. They build gently on each other, so ideally, read them in order. -If anything seems confusing, don't hesitate to have a look at the {doc}`glossary`! +If anything seems confusing, don't hesitate to have a look at our {doc}`glossary`! ```{toctree} From 3486f6055db08463890368ecaaf3040b99e32983 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 29 Dec 2023 11:25:24 +0100 Subject: [PATCH 1156/1520] Let's grow it --- docs/glossary.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/glossary.md b/docs/glossary.md index b0c4ed16..2d255838 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -1,5 +1,7 @@ # Glossary +Please feel free to [file an issue](https://github.com/hynek/structlog/issues) if you feel some important concept is missing here. + :::{glossary} Event Dictionary @@ -9,7 +11,7 @@ Event Dictionary It's the result of the values bound to the {term}`bound logger`'s context and the key-value pairs passed to the logging method. It is then passed through the {term}`processor` chain that can add, modify, and even remove key-value pairs. -Bound logger +Bound Logger An instance of a {class}`structlog.typing.BindableLogger` that is returned by either {func}`structlog.get_logger` or the bind/unbind/new methods on it. As the name suggests, it's possible to bind key-value pairs to it -- this data is called the **context** of the logger. @@ -21,7 +23,7 @@ Bound logger {doc}`bound-loggers` ::: -Native loggers +Native Loggers Loggers created using {func}`structlog.make_filtering_bound_logger` which includes the default configuration. These loggers are very fast and do **not** use the standard library. From 444e6d343a5b74011482c34cc08432a2ed1bc64d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 29 Dec 2023 14:19:56 +0100 Subject: [PATCH 1157/1520] Feel feel --- docs/glossary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/glossary.md b/docs/glossary.md index 2d255838..367d05bf 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -1,6 +1,6 @@ # Glossary -Please feel free to [file an issue](https://github.com/hynek/structlog/issues) if you feel some important concept is missing here. +Please feel free to [file an issue](https://github.com/hynek/structlog/issues) if you think some important concept is missing here. :::{glossary} From 0ea03fbaf1881999bdc96f28e0eeb32e042cc03e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 29 Dec 2023 14:31:28 +0100 Subject: [PATCH 1158/1520] docs/glossary: add context --- docs/getting-started.md | 4 ++-- docs/glossary.md | 12 +++++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 8059b86c..09ba20c0 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -72,7 +72,7 @@ log = structlog.get_logger() - For brevity and to enable doctests, all further examples in *structlog*'s documentation use the more simplistic {class}`~structlog.processors.KeyValueRenderer()` without timestamps. ::: -Here you go, structured logging! +There you go, structured logging! However, this alone wouldn't warrant its own package. @@ -107,7 +107,7 @@ At this point, you'll be tempted to write a closure like: ```python def log_closure(event): - log.info(event, user_agent=user_agent, peer_ip=peer_ip) + log.info(event, user_agent=user_agent, peer_ip=peer_ip) ``` inside of the view. diff --git a/docs/glossary.md b/docs/glossary.md index 367d05bf..3175ef48 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -14,15 +14,25 @@ Event Dictionary Bound Logger An instance of a {class}`structlog.typing.BindableLogger` that is returned by either {func}`structlog.get_logger` or the bind/unbind/new methods on it. - As the name suggests, it's possible to bind key-value pairs to it -- this data is called the **context** of the logger. + As the name suggests, it's possible to bind key-value pairs to it -- this data is called the {term}`context` of the logger. Its methods are the user's logging API and depend on the type of the bound logger. The two most common implementations are {class}`structlog.BoundLogger` and {class}`structlog.stdlib.BoundLogger`. + Bound loggers are **immutable**. + The context can only be modified by creating a new bound logger using its `bind()`and `unbind()` methods. + :::{seealso} {doc}`bound-loggers` ::: +Context + A dictionary of key-value pairs belonging to a {term}`bound logger`. + When a log entry is logged out, the context is the base for the event dictionary with the keyword arguments of the logging method call merged in. + + Bound loggers are **immutable**, so it's not possible to modify a context directly. + But you can create a new bound logger with a different context using its `bind()` and `unbind()` methods. + Native Loggers Loggers created using {func}`structlog.make_filtering_bound_logger` which includes the default configuration. From b9dac7c165157402e6e4cb95012d2c5f246ef4b8 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 29 Dec 2023 14:34:11 +0100 Subject: [PATCH 1159/1520] Link --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6443b631..f1f40aa4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,7 +31,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ### Changed - `structlog.stdlib.recreate_defaults()` now also adds `structlog.stdlib.add_logger_name` to the processors. - Check out the updated screenshot in the README! + Check out the [updated screenshot](https://raw.githubusercontent.com/hynek/structlog/main/docs/_static/console_renderer.png)! ### Fixed From 45ba1911648c99f2fdf275611fcb996a0cfb45c2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 29 Dec 2023 14:41:12 +0100 Subject: [PATCH 1160/1520] Prepare 23.3.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1f40aa4..db37e1f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ -## [Unreleased](https://github.com/hynek/structlog/compare/23.2.0...HEAD) +## [23.3.0](https://github.com/hynek/structlog/compare/23.2.0...23.3.0) - 2023-12-29 ### Added From b698679db9edc13b45ed120c0f91621ce0e6a90d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 29 Dec 2023 14:54:39 +0100 Subject: [PATCH 1161/1520] Start new development cycle --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index db37e1f6..5d717c44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ +## [Unreleased](https://github.com/hynek/structlog/compare/23.3.0...HEAD) + + ## [23.3.0](https://github.com/hynek/structlog/compare/23.2.0...23.3.0) - 2023-12-29 ### Added From b4528d23a9f2132f9ccb5904dfb96497be3273f7 Mon Sep 17 00:00:00 2001 From: Christopher Lane Date: Fri, 29 Dec 2023 10:40:52 -0500 Subject: [PATCH 1162/1520] Update exceptions.md (#578) Fix spelling of "structlog" on line 5. --- docs/exceptions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/exceptions.md b/docs/exceptions.md index b7c5e4dc..b32fcd86 100644 --- a/docs/exceptions.md +++ b/docs/exceptions.md @@ -2,7 +2,7 @@ While you should use a proper crash reporter like [Sentry](https://sentry.io) in production, *structlog* has helpers for formatting exceptions for humans and machines. -All *structog*'s exception features center around passing an `exc_info` key-value pair in the event dict. +All *structlog*'s exception features center around passing an `exc_info` key-value pair in the event dict. There are three possible behaviors depending on its value: 1. If the value is a tuple, render it as if it was returned by {func}`sys.exc_info`. From 3864f61de98554e6d8610c06386ffc46add179d8 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 31 Dec 2023 08:25:13 +0100 Subject: [PATCH 1163/1520] Use Markdown output for coverage --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4e695c9c..d7b0ef83 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -85,7 +85,7 @@ jobs: python -Im coverage html --skip-covered --skip-empty # Report and write to summary. - python -Im coverage report | sed 's/^/ /' >> $GITHUB_STEP_SUMMARY + python -Im coverage report --format=markdown >> $GITHUB_STEP_SUMMARY # Report again and fail if under 100%. python -Im coverage report --fail-under=100 From 312226a9f592d5311f9a9b87c852d3e134f2e170 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jan 2024 15:40:26 +0100 Subject: [PATCH 1164/1520] Bump actions/setup-python from 4 to 5 (#581) --- .github/workflows/build-docset.yml | 2 +- .github/workflows/ci.yml | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build-docset.yml b/.github/workflows/build-docset.yml index 0dfce69e..921e7d3e 100644 --- a/.github/workflows/build-docset.yml +++ b/.github/workflows/build-docset.yml @@ -20,7 +20,7 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 # get correct version - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: "3.10" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d7b0ef83..2ffce8ac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,7 +47,7 @@ jobs: name: Packages path: dist - run: tar xf dist/*.tar.gz --strip-components=1 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} allow-prereleases: true @@ -70,7 +70,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version-file: .python-version-default cache: pip @@ -109,7 +109,7 @@ jobs: name: Packages path: dist - run: tar xf dist/*.tar.gz --strip-components=1 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version-file: .python-version-default allow-prereleases: true @@ -130,7 +130,7 @@ jobs: name: Packages path: dist - run: tar xf dist/*.tar.gz --strip-components=1 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version-file: .python-version-default allow-prereleases: true @@ -150,7 +150,7 @@ jobs: name: Packages path: dist - run: tar xf dist/*.tar.gz --strip-components=1 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: # Keep in sync with tox.ini/docs & .readthedocs.yaml python-version: "3.11" @@ -168,7 +168,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version-file: .python-version-default cache: pip @@ -203,7 +203,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version-file: .python-version-default cache: pip From 0a2d521669d549c8757640ac38c762fa479a37d1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jan 2024 14:43:53 +0000 Subject: [PATCH 1165/1520] Bump github/codeql-action from 2 to 3 (#580) --- .github/workflows/codeql-analysis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index c0e6a208..68f325e6 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -27,12 +27,12 @@ jobs: uses: actions/checkout@v4 - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 From b9c1cb140856ac10f86ebfdc031e31bf67acffb9 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 2 Jan 2024 07:51:47 +0100 Subject: [PATCH 1166/1520] Adapt to upload/download@v4 --- .github/workflows/build-docset.yml | 4 ++-- .github/workflows/ci.yml | 21 +++++++++++---------- .github/workflows/pypi-package.yml | 6 +++--- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build-docset.yml b/.github/workflows/build-docset.yml index 921e7d3e..79366d6b 100644 --- a/.github/workflows/build-docset.yml +++ b/.github/workflows/build-docset.yml @@ -22,14 +22,14 @@ jobs: fetch-depth: 0 # get correct version - uses: actions/setup-python@v5 with: - python-version: "3.10" + python-version: "3.12" - run: pip install tox - run: tox -e docset - run: tar --exclude='.DS_Store' -cvzf structlog.tgz structlog.docset - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: docset path: structlog.tgz diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2ffce8ac..424b4b9c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: with: fetch-depth: 0 - - uses: hynek/build-and-inspect-python-package@v1 + - uses: hynek/build-and-inspect-python-package@v2 tests: name: Tests & API Mypy on ${{ matrix.python-version }} @@ -42,7 +42,7 @@ jobs: steps: - name: Download pre-built packages - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: Packages path: dist @@ -57,9 +57,9 @@ jobs: - run: python -Im tox run --installpkg dist/*.whl -f py$(echo ${{ matrix.python-version }} | tr -d .) - name: Upload coverage data - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: coverage-data + name: coverage-data-${{ matrix.python-version }} path: .coverage.* if-no-files-found: ignore @@ -75,9 +75,10 @@ jobs: python-version-file: .python-version-default cache: pip - run: python -Im pip install --upgrade coverage[toml] - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: - name: coverage-data + pattern: coverage-data-* + merge-multiple: true - name: Combine coverage & fail if it's <100%. run: | @@ -91,7 +92,7 @@ jobs: python -Im coverage report --fail-under=100 - name: Upload HTML report if check failed. - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: html-report path: htmlcov @@ -104,7 +105,7 @@ jobs: steps: - name: Download pre-built packages - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: Packages path: dist @@ -125,7 +126,7 @@ jobs: steps: - name: Download pre-built packages - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: Packages path: dist @@ -145,7 +146,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download pre-built packages - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: Packages path: dist diff --git a/.github/workflows/pypi-package.yml b/.github/workflows/pypi-package.yml index 63c6b784..f557727f 100644 --- a/.github/workflows/pypi-package.yml +++ b/.github/workflows/pypi-package.yml @@ -24,7 +24,7 @@ jobs: with: fetch-depth: 0 - - uses: hynek/build-and-inspect-python-package@v1 + - uses: hynek/build-and-inspect-python-package@v2 # Upload to Test PyPI on every commit on main. release-test-pypi: @@ -36,7 +36,7 @@ jobs: steps: - name: Download packages built by build-and-inspect-python-package - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: Packages path: dist @@ -56,7 +56,7 @@ jobs: steps: - name: Download packages built by build-and-inspect-python-package - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: Packages path: dist From d664dad422f1605f7131f6f7e217c11f6581d873 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 2 Jan 2024 07:55:07 +0100 Subject: [PATCH 1167/1520] Get rid of period in step name --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 424b4b9c..279fba2f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -64,7 +64,7 @@ jobs: if-no-files-found: ignore coverage: - name: Combine & check coverage. + name: Combine & check coverage needs: tests runs-on: ubuntu-latest From f981c0231b4b84373e4639fb819370f8b7417e24 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 2 Jan 2024 15:56:02 +0100 Subject: [PATCH 1168/1520] Build docs on 3.12 --- .github/workflows/ci.yml | 2 +- .readthedocs.yaml | 2 +- tox.ini | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 279fba2f..898a72e5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -154,7 +154,7 @@ jobs: - uses: actions/setup-python@v5 with: # Keep in sync with tox.ini/docs & .readthedocs.yaml - python-version: "3.11" + python-version: "3.12" cache: pip - run: python -Im pip install tox diff --git a/.readthedocs.yaml b/.readthedocs.yaml index f8c4c2ce..7b669cdc 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -5,7 +5,7 @@ build: os: ubuntu-22.04 tools: # Keep version in sync with tox.ini/docs and ci.yml/docs - python: "3.11" + python: "3.12" python: install: diff --git a/tox.ini b/tox.ini index 8508b533..608b6fdb 100644 --- a/tox.ini +++ b/tox.ini @@ -50,7 +50,7 @@ commands = [testenv:docs] # Keep base_python in sync with ci.yml/docs and .readthedocs.yaml. -base_python = py311 +base_python = py312 extras = docs commands = sphinx-build -n -T -W -b html -d {envtmpdir}/doctrees docs docs/_build/html From 2ce08063faa7b9b9cf1ec295cd4fa787b6669c3a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 3 Jan 2024 05:45:21 +0100 Subject: [PATCH 1169/1520] update ruff --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 196255d5..50998706 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.9 + rev: v0.1.11 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From 813bc14a2d0fdd0ea539a07ec44e134a6be7b0aa Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 3 Jan 2024 15:40:21 +0100 Subject: [PATCH 1170/1520] Return initial values from lazy logger proxy Instead of empty dict. --- CHANGELOG.md | 5 +++++ src/structlog/_config.py | 2 +- tests/test_config.py | 10 ++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d717c44..f7f9d5f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,11 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ## [Unreleased](https://github.com/hynek/structlog/compare/23.3.0...HEAD) +### Fixed + +- The lazy logger proxy returned by `structlog.get_logger()` now returns its initial values when asked for context. + When asked for context before binding for the first time, it returned an empty dictionary in 23.3.0. + ## [23.3.0](https://github.com/hynek/structlog/compare/23.2.0...23.3.0) - 2023-12-29 diff --git a/src/structlog/_config.py b/src/structlog/_config.py index aa05fd06..1bdcaa50 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -312,7 +312,7 @@ class BoundLoggerLazyProxy: # fulfill BindableLogger protocol without carrying accidental state @property def _context(self) -> dict[str, str]: - return {} + return self._initial_values def __init__( self, diff --git a/tests/test_config.py b/tests/test_config.py index f9a9f8eb..c45fc0f0 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -67,6 +67,16 @@ def test_lazy_logger_is_an_instance_of_bindable_logger(): assert isinstance(get_logger(), BindableLogger) +def test_lazy_logger_context_is_initial_values(): + """ + If a user asks for _context (e.g., using get_context) return + initial_values. + """ + logger = get_logger(context="a") + + assert {"context": "a"} == structlog.get_context(logger) + + def test_default_context_class(): """ Default context class is dict. From ac37281c66efe82f4dfc8f812ab91f391548fd6b Mon Sep 17 00:00:00 2001 From: Wilfried Huss <84843123+wilfried-huss@users.noreply.github.com> Date: Thu, 4 Jan 2024 10:25:15 +0100 Subject: [PATCH 1171/1520] don't ignore the width parameter in RichTracebackFormatter (#587) * don't ignore the width parameter in RichTracebackFormatter * format * add changelog entry * Update CHANGELOG.md Co-authored-by: Hynek Schlawack --------- Co-authored-by: Hynek Schlawack --- CHANGELOG.md | 3 +++ src/structlog/dev.py | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7f9d5f0..5dd033e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - The lazy logger proxy returned by `structlog.get_logger()` now returns its initial values when asked for context. When asked for context before binding for the first time, it returned an empty dictionary in 23.3.0. +- Don't ignore the `width` argument of `RichTracebackFormatter`. + [#587](https://github.com/hynek/structlog/issues/587) + ## [23.3.0](https://github.com/hynek/structlog/compare/23.2.0...23.3.0) - 2023-12-29 diff --git a/src/structlog/dev.py b/src/structlog/dev.py index e0125516..ce57e00e 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -365,7 +365,9 @@ def __call__(self, sio: TextIO, exc_info: ExcInfo) -> None: sio.write("\n") - Console(file=sio, color_system=self.color_system).print( + Console( + file=sio, color_system=self.color_system, width=self.width + ).print( Traceback.from_exception( *exc_info, show_locals=self.show_locals, From 0b7da2847cfe398a450a7f34c5f4586904e9df4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kim=20S=C3=A4ppi?= Date: Mon, 8 Jan 2024 08:55:07 +0200 Subject: [PATCH 1172/1520] Display "exception" logs as level "error" (#586) * Display "exception" logs as level "error" * Update CHANGELOG.md * Update src/structlog/_log_levels.py --------- Co-authored-by: Hynek Schlawack --- CHANGELOG.md | 4 ++++ src/structlog/_log_levels.py | 5 +++++ tests/test_stdlib.py | 9 ++++++--- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5dd033e2..85fb3e2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,10 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - The lazy logger proxy returned by `structlog.get_logger()` now returns its initial values when asked for context. When asked for context before binding for the first time, it returned an empty dictionary in 23.3.0. +- The displayed level name when using `structlog.stdlib.BoundLogger.exception()` is `"error"` instead of `"exception"`. + Fixes regression in 23.3.0. + [#584](https://github.com/hynek/structlog/issues/584) + - Don't ignore the `width` argument of `RichTracebackFormatter`. [#587](https://github.com/hynek/structlog/issues/587) diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index bb7e67b8..df1e81ab 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -60,10 +60,15 @@ def add_log_level( .. versionchanged:: 20.2.0 Importable from `structlog.processors` (additionally to `structlog.stdlib`). + .. versionchanged:: 24.1.0 + Added mapping from "exception" to "error" """ if method_name == "warn": # The stdlib has an alias method_name = "warning" + elif method_name == "exception": + # exception("") method is the same as error("", exc_info=True) + method_name = "error" event_dict["level"] = method_name diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index f1ae444e..1c690f1f 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -488,13 +488,16 @@ def test_log_level_added(self): assert "error" == event_dict["level"] - def test_log_level_alias_normalized(self): + @pytest.mark.parametrize( + ("alias", "normalized"), [("warn", "warning"), ("exception", "error")] + ) + def test_log_level_alias_normalized(self, alias, normalized): """ The normalized name of the log level is added to the event dict. """ - event_dict = add_log_level(None, "warn", {}) + event_dict = add_log_level(None, alias, {}) - assert "warning" == event_dict["level"] + assert normalized == event_dict["level"] @pytest.fixture(name="make_log_record") From f8eb4b9e49a124d419b7f3e8d8925f72ccf8360c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 8 Jan 2024 07:58:36 +0100 Subject: [PATCH 1173/1520] Underlines are highlighting enough --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85fb3e2a..83c02998 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file. -The format is based on [*Keep a Changelog*](https://keepachangelog.com/en/1.0.0/) and this project adheres to [*Calendar Versioning*](https://calver.org/). +The format is based on [Keep a Changelog](https://keepachangelog.com/) and this project adheres to [Calendar Versioning](https://calver.org/). The **first number** of the version is the year. The **second number** is incremented with each release, starting at 1 for each year. From b5900c632c8891b00ca1ead707913a1d1ba188e4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 8 Jan 2024 08:01:27 +0100 Subject: [PATCH 1174/1520] Fix CI coverage depends --- tox.ini | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index 608b6fdb..ca6b6344 100644 --- a/tox.ini +++ b/tox.ini @@ -24,6 +24,7 @@ commands = # Run oldest and latest under Coverage. +# Keep in-sync with coverage `depends below. [testenv:py3{8,12}-tests{,-colorama,-be,-rich}] set_env = py312: COVERAGE_CORE=sysmon @@ -37,12 +38,13 @@ commands = coverage run -m pytest {posargs} [testenv:coverage-report] -# Keep in sync with .python-version-default +# Keep in-sync with .python-version-default base_python = py312 deps = coverage[toml] skip_install = true parallel_show_output = true -depends = py3{8,11}-{tests,colorama,be,rich} +# Keep in-sync with test env definition above. +depends = py3{8,12}-{tests,colorama,be,rich} commands = coverage combine coverage report From d26d2ac6752823dd5a6f09b83f8a64c9225c6144 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 8 Jan 2024 08:05:46 +0100 Subject: [PATCH 1175/1520] Give job a name --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 898a72e5..b638c1e9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -177,8 +177,8 @@ jobs: - run: python -Im pip install -e .[dev] - run: python -Ic 'import structlog; print(structlog.__version__)' - # Ensure everything required is passing for branch protection. required-checks-pass: + name: Ensure everything required is passing for branch protection if: always() needs: From 6f3fc33fa112f277be4f10c2c52b2d0303fc4494 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 8 Jan 2024 10:45:50 +0100 Subject: [PATCH 1176/1520] Prepare 24.1.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83c02998..9157087c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ -## [Unreleased](https://github.com/hynek/structlog/compare/23.3.0...HEAD) +## [24.1.0](https://github.com/hynek/structlog/compare/23.3.0...24.1.0) - 2024-01-08 ### Fixed From 5899a037973a26f6f7ce82a06f55cc215ae06fed Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 8 Jan 2024 10:48:45 +0100 Subject: [PATCH 1177/1520] Start new development cycle --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9157087c..5d8f2b87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ +## [Unreleased](https://github.com/hynek/structlog/compare/24.1.0...HEAD) + + ## [24.1.0](https://github.com/hynek/structlog/compare/23.3.0...24.1.0) - 2024-01-08 ### Fixed From 4f114614877f55842674c078e2707a761b755fac Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 14 Jan 2024 07:33:33 +0100 Subject: [PATCH 1178/1520] Update contributing --- .github/CONTRIBUTING.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 414ae2a8..2f9e2263 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -69,7 +69,7 @@ $ git clone https://github.com/YOU/structlog.git > Yes, you can work on `main` in your fork and submit pull requests. > But this will *inevitably* lead to you not being able to synchronize your fork with upstream and having to start over. -Change into the newly created directory and after activating a virtual environment, install an editable version of *structlog* along with its tests and docs requirements: +Change into the newly created directory and after activating a virtual environment, install an editable version of *structlog* along with its tests requirements: ```console $ cd structlog @@ -85,14 +85,14 @@ $ python -m pytest When working on the documentation, use: -```bash +```console $ tox run -e docs-watch ``` ... to watch your files and automatically rebuild when a file changes. And use: -```bash +```console $ tox run -e docs ``` @@ -131,6 +131,10 @@ But it's way more comfortable to run it locally and catch avoidable errors befor Args: x: A very important parameter. + y: + Another important parameter but one that doesn't fit a line so + it already starts on the next one. + Returns: A very important return value. """ @@ -180,7 +184,7 @@ But it's way more comfortable to run it locally and catch avoidable errors befor ## Header of New Top Section - ### Header of New Section + ### Header of New Section First line of new section. ``` From 068b6a26c8f732f577910226f4db811ff3e64a4f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 14 Jan 2024 07:35:18 +0100 Subject: [PATCH 1179/1520] Take advantage of tox 4.12 --- .github/workflows/ci.yml | 3 ++- tox.ini | 4 ---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b638c1e9..6a644fb8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -208,6 +208,7 @@ jobs: with: python-version-file: .python-version-default cache: pip - - run: python -Im pip install tox + # tox 4.12.0 started passing FORCE_COLOR and NO_COLOR by default. + - run: python -Im pip install 'tox>=4.12.0' - run: python -Im tox run -f color diff --git a/tox.ini b/tox.ini index ca6b6344..8365d3a2 100644 --- a/tox.ini +++ b/tox.ini @@ -15,9 +15,6 @@ wheel_build_env = .pkg extras = tests: tests mypy: typing -pass_env = - FORCE_COLOR - NO_COLOR commands = tests: pytest {posargs} mypy: mypy tests/typing @@ -70,7 +67,6 @@ commands = src \ docs - [testenv:docs-linkcheck] base_python = {[testenv:docs]base_python} extras = {[testenv:docs]extras} From 1824bee74658d140544479404795a81d55d06c58 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 14 Jan 2024 09:58:04 +0100 Subject: [PATCH 1180/1520] Update docset --- .github/workflows/build-docset.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-docset.yml b/.github/workflows/build-docset.yml index 79366d6b..110532fe 100644 --- a/.github/workflows/build-docset.yml +++ b/.github/workflows/build-docset.yml @@ -10,8 +10,7 @@ env: PIP_DISABLE_PIP_VERSION_CHECK: 1 PIP_NO_PYTHON_VERSION_WARNING: 1 -permissions: - contents: read +permissions: {} jobs: docset: @@ -26,7 +25,7 @@ jobs: - run: pip install tox - - run: tox -e docset + - run: tox run -e docset - run: tar --exclude='.DS_Store' -cvzf structlog.tgz structlog.docset - uses: actions/upload-artifact@v4 From 8dfb2d7b82babd689578a46e25293e78d38c5930 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 14 Jan 2024 15:40:53 +0100 Subject: [PATCH 1181/1520] Make docset icons square --- docs/_static/docset-icon.png | Bin 677 -> 1145 bytes docs/_static/docset-icon@2x.png | Bin 1810 -> 2172 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/_static/docset-icon.png b/docs/_static/docset-icon.png index cf924770fa504b29c84318828183916e241097e0..d7e00f144fe37188714677c60925844ad6f4e199 100644 GIT binary patch delta 1137 zcmV-%1djWq1^Eb&7k>~41^@s6AM^iV00047X+uL$X=7sm0C?J!&@+G>2owh3Z*;bO z>*j3RMr;h%!?29X*mn9NDWf*F>uqCa5F4+0{z0&FOSCl?ewWs^eD?oezOU-uqi5Cq z9ReQnm|8Cni00DY{rm5qZW+gR2*B32D!<%YJRFPXq68km*MHG;Hc#MJ{5d$EuH=*O zOf)qhMqnA<%$5lf*jDKeypVTP^5lj5OeN2D{{IJpPoOG!RX*^lJetb35_}hRtu2Kp zAb>~WZCyH{2CvBZ-!HybXOL?>hPjBL(UKcz=2o~<7 z^KkxL&-58IBzU}c2}EIM*69Ca761SM32;bRa{vGi#D4$)4#WYKD-Ig~00P8GL_t(| z+DwrHkTYi-#(!^CG0%6O%~5UJ9<^h$W7inF8h2b{RNL0sF?Qo@F4^6_ljF0-`}`jW z&-4BO5(s1b?FfRC8(i`BlQl&M}*=;ni#oC&SqB zak<`ys|8ppH87J$**_V@UY(^;Di9qW-6UB4{b#Bz2R(I&3zLG+e*BTY(8Gjk(vWFkx@VWB<2v4HbYEdbd_~*A@Sy^5t znHnM}WfyZfR8?hoe4M)UZCNJAPMqMRT%1g%2!+F&A-??LGkpC1yC5g_`wkm2s4K3% zhHGxWYmmX`AHK&oUw)3JD5&y4s=D#cdwKlHXHfwdR%btgS3@ z;^ZmzA38iB=&%U^^nm}z0m>dwJ`;!rV@&V^h))3k_5(XRCSTHm00000NkvXXu0mjf Dyo@TZ delta 666 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 delta 1808 zcmV+r2k-d&5Rwj%7k?ZG0ssI2kDw}b00009a7bBm000id000id0mpBsWB>pL#7RU! zRCwC8RaIc?%+b}ZR+a@O#gLc+H#hYEWoBk(=9es zI@tD)8m!ym&Hz(?;8TK7R1!Inkroq^=}0E;=I8JH31?V5y3x=>B0|3JAv3wxW96N`K`|P9Wh}cFvnf4$_5)91R^y zA~=U_#c!&y7!AX}32?Uu+<$gbn-pvW58&fDGzheK+%l%RT)I^VkR3-^x~QqD@46!O zk$^;jXIOV>p|E_XJN-?7D?j_5=ybS|wYAi`gZBH5<+=c*=`q{Lw*|o9As3ohVd;XR zDiC5?R)2lqt$Enej4+k8>l@d9_lw)+B)9xCTTS!Y*Gj?$9H|~QT5e0`60JUougXX@7 zkwe2iQXhHm`?UvlY-XMf8Azsn;`PU(6wC5n?1;Scxrez$p~$|M_$mJLmliSM&& zw_R;pEz5I!Hd`z%l}o^RKvSmGiTI{U2fOEge-hxZx>LJx)xillmewLNs3e5 zj-y0buGA`S^B^Bfz=L5!5Q5I?sicw1jm?3P$*PGYaD_&Da?`dd-DaP9IHXq31b>HP zGGsXdFNAIyW~f)%yHEMx6KY@FBb}TU0IPL@_&VES6khV+c)v3lu#r*q)6Z$r*8#rTGrB~GCHwU z!1eO|?k^Q4gD?3U;6xwwT-E%e6d(8l*=I9 zOK1Lc;SYbPtgnHHPc1Ls>7MsmzWwcO*y(n6tF>yYd3euz+~Z+Sc#<)Z{+nlVyWIvd z8PLeXzz;yzzywTb5Ckx#<$viJB1s301`J7datdT$+1aKbc_LwqAje3-1Y@XBgpJlP zCdL3Ro;~xfH@~jiYK07pj=ot41{ajho?dv&*yPdz<1J^c{PeU{q8qo0FXCfq@gFn^)nVw=ELFvL6lTo zrvg?ca!-EZlgqPn;Qasp|9{{A`d1ke;ed1o1Beg>0Y)Yw%S0R+bOnoeOhpST{~s_4 zyG=->sHPjasfFp;`G3Ww#g&y)3yXzPDV@&9vV81Zo|%2Y%U=1|r#-V?t!}KZu3f*j zv3jGnv)w*CaC%)#gLFE*@PD@(;{Y1{-EV&V%pd-6YGL8@;&OR Date: Fri, 26 Jan 2024 08:15:05 +0100 Subject: [PATCH 1182/1520] Black 24 --- .pre-commit-config.yaml | 4 ++-- src/structlog/_config.py | 6 +++--- src/structlog/_output.py | 2 ++ src/structlog/contextvars.py | 6 +++--- src/structlog/testing.py | 1 + src/structlog/tracebacks.py | 14 ++++++++------ src/structlog/twisted.py | 5 +++-- src/structlog/typing.py | 15 +++++---------- 8 files changed, 27 insertions(+), 26 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 50998706..44c3c3ed 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,12 +4,12 @@ ci: repos: - repo: https://github.com/psf/black - rev: 23.12.1 + rev: 24.1.0 hooks: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.11 + rev: v0.1.14 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 1bdcaa50..bd6001bd 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -63,9 +63,9 @@ class _Configuration: default_processors: Iterable[Processor] = _BUILTIN_DEFAULT_PROCESSORS[:] default_context_class: type[Context] = _BUILTIN_DEFAULT_CONTEXT_CLASS default_wrapper_class: Any = _BUILTIN_DEFAULT_WRAPPER_CLASS - logger_factory: Callable[ - ..., WrappedLogger - ] = _BUILTIN_DEFAULT_LOGGER_FACTORY + logger_factory: Callable[..., WrappedLogger] = ( + _BUILTIN_DEFAULT_LOGGER_FACTORY + ) cache_logger_on_first_use: bool = _BUILTIN_CACHE_LOGGER_ON_FIRST_USE diff --git a/src/structlog/_output.py b/src/structlog/_output.py index c0aad4a5..548d5d3d 100644 --- a/src/structlog/_output.py +++ b/src/structlog/_output.py @@ -257,6 +257,7 @@ class BytesLogger: .. versionadded:: 20.2.0 """ + __slots__ = ("_file", "_write", "_flush", "_lock") def __init__(self, file: BinaryIO | None = None): @@ -339,6 +340,7 @@ class BytesLoggerFactory: .. versionadded:: 20.2.0 """ + __slots__ = ("_file",) def __init__(self, file: BinaryIO | None = None): diff --git a/src/structlog/contextvars.py b/src/structlog/contextvars.py index cc531889..6bc79d72 100644 --- a/src/structlog/contextvars.py +++ b/src/structlog/contextvars.py @@ -33,9 +33,9 @@ STRUCTLOG_KEY_PREFIX = "structlog_" STRUCTLOG_KEY_PREFIX_LEN = len(STRUCTLOG_KEY_PREFIX) -_ASYNC_CALLING_STACK: contextvars.ContextVar[ - FrameType -] = contextvars.ContextVar("_ASYNC_CALLING_STACK") +_ASYNC_CALLING_STACK: contextvars.ContextVar[FrameType] = ( + contextvars.ContextVar("_ASYNC_CALLING_STACK") +) # For proper isolation, we have to use a dict of ContextVars instead of a # single ContextVar with a dict. diff --git a/src/structlog/testing.py b/src/structlog/testing.py index 94107bf6..ba0c96f9 100644 --- a/src/structlog/testing.py +++ b/src/structlog/testing.py @@ -199,6 +199,7 @@ class CapturingLoggerFactory: .. versionadded:: 20.2.0 """ + logger: CapturingLogger def __init__(self) -> None: diff --git a/src/structlog/tracebacks.py b/src/structlog/tracebacks.py index 76c6afc3..83a40f27 100644 --- a/src/structlog/tracebacks.py +++ b/src/structlog/tracebacks.py @@ -177,12 +177,14 @@ def extract( filename=filename or "?", lineno=line_no, name=frame_summary.f_code.co_name, - locals={ - key: to_repr(value, max_string=locals_max_string) - for key, value in frame_summary.f_locals.items() - } - if show_locals - else None, + locals=( + { + key: to_repr(value, max_string=locals_max_string) + for key, value in frame_summary.f_locals.items() + } + if show_locals + else None + ), ) append(frame) diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index f146eadd..411555b1 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -303,8 +303,9 @@ class EventAdapter: def __init__( self, - dictRenderer: Callable[[WrappedLogger, str, EventDict], str] - | None = None, + dictRenderer: ( + Callable[[WrappedLogger, str, EventDict], str] | None + ) = None, ) -> None: self._dictRenderer = dictRenderer or _BUILTIN_DEFAULT_PROCESSORS[-1] diff --git a/src/structlog/typing.py b/src/structlog/typing.py index ed277847..8a07d60a 100644 --- a/src/structlog/typing.py +++ b/src/structlog/typing.py @@ -116,8 +116,7 @@ class ExceptionTransformer(Protocol): .. versionadded:: 22.1.0 """ - def __call__(self, exc_info: ExcInfo) -> Any: - ... + def __call__(self, exc_info: ExcInfo) -> Any: ... @runtime_checkable @@ -131,17 +130,13 @@ class BindableLogger(Protocol): _context: Context - def bind(self, **new_values: Any) -> BindableLogger: - ... + def bind(self, **new_values: Any) -> BindableLogger: ... - def unbind(self, *keys: str) -> BindableLogger: - ... + def unbind(self, *keys: str) -> BindableLogger: ... - def try_unbind(self, *keys: str) -> BindableLogger: - ... + def try_unbind(self, *keys: str) -> BindableLogger: ... - def new(self, **new_values: Any) -> BindableLogger: - ... + def new(self, **new_values: Any) -> BindableLogger: ... class FilteringBoundLogger(BindableLogger, Protocol): From b93037f2812e896fdd497e69ca854e42a39048f3 Mon Sep 17 00:00:00 2001 From: Georges Dubus Date: Mon, 29 Jan 2024 16:50:13 +0100 Subject: [PATCH 1183/1520] Escape newlines in LogfmtRenderer (#592) * Escape newlines in LogfmtRenderer * Update tests/test_processors.py --------- Co-authored-by: Hynek Schlawack --- CHANGELOG.md | 4 ++++ src/structlog/processors.py | 2 +- tests/test_processors.py | 10 ++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d8f2b87..20cacf5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ## [Unreleased](https://github.com/hynek/structlog/compare/24.1.0...HEAD) +### Changed + +- `structlog.processors.LogfmtRenderer` now escapes newlines. + [#592](https://github.com/hynek/structlog/pull/592) ## [24.1.0](https://github.com/hynek/structlog/compare/23.3.0...24.1.0) - 2024-01-08 diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 3f25dfff..b7c78055 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -170,7 +170,7 @@ def __call__( continue value = "true" if value else "false" - value = f"{value}".replace('"', '\\"') + value = f"{value}".replace('"', '\\"').replace("\n", "\\n") if " " in value or "=" in value: value = f'"{value}"' diff --git a/tests/test_processors.py b/tests/test_processors.py index 04eb6a85..9fd16787 100644 --- a/tests/test_processors.py +++ b/tests/test_processors.py @@ -290,6 +290,16 @@ def test_invalid_key(self): with pytest.raises(ValueError, match='Invalid key: "invalid key"'): LogfmtRenderer()(None, None, event_dict) + def test_newline_in_value(self): + """ + Newlines in values are escaped. + """ + event_dict = {"with_newline": "some\nvalue"} + + rv = LogfmtRenderer()(None, None, event_dict) + + assert r"with_newline=some\nvalue" == rv + class TestJSONRenderer: def test_renders_json(self, event_dict): From 3c2becd533e981dbd453b0769610453bc042b947 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 29 Jan 2024 16:54:19 +0100 Subject: [PATCH 1184/1520] Empty line --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20cacf5f..fd810dea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - `structlog.processors.LogfmtRenderer` now escapes newlines. [#592](https://github.com/hynek/structlog/pull/592) + ## [24.1.0](https://github.com/hynek/structlog/compare/23.3.0...24.1.0) - 2024-01-08 ### Fixed From 02fe6666e9ac084a6a2f8d6b0c05a1b995415c49 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Thu, 1 Feb 2024 14:58:14 +0900 Subject: [PATCH 1185/1520] fix doc rendering (#593) --- src/structlog/dev.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index ce57e00e..335e25b1 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -454,7 +454,7 @@ class ConsoleRenderer: passed. repr_native_str: - When `True`, `repr` is also applied to ``str``s. The ``event`` key + When `True`, `repr` is also applied to ``str`` s. The ``event`` key is *never* `repr` -ed. Ignored if *columns* are passed. level_styles: From 02a6b2410c187c89342e80711dfb65375c92b905 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 1 Feb 2024 06:59:12 +0100 Subject: [PATCH 1186/1520] Escape space --- src/structlog/dev.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 335e25b1..aa0fff83 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -421,7 +421,7 @@ def better_traceback(sio: TextIO, exc_info: ExcInfo) -> None: class ConsoleRenderer: - """ + r""" Render ``event_dict`` nicely aligned, possibly in colors, and ordered. If ``event_dict`` contains a true-ish ``exc_info`` key, it will be rendered @@ -454,8 +454,8 @@ class ConsoleRenderer: passed. repr_native_str: - When `True`, `repr` is also applied to ``str`` s. The ``event`` key - is *never* `repr` -ed. Ignored if *columns* are passed. + When `True`, `repr` is also applied to ``str``\ s. The ``event`` + key is *never* `repr` -ed. Ignored if *columns* are passed. level_styles: When present, use these styles for colors. This must be a dict from From e43f610c267737ecd3a637b65fc8509ae4b6d921 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 1 Feb 2024 07:04:58 +0100 Subject: [PATCH 1187/1520] Fix link to narrative console docs --- src/structlog/dev.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index aa0fff83..315e91c6 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -6,7 +6,7 @@ """ Helpers that make development with *structlog* more pleasant. -See also the narrative documentation in `development`. +See also the narrative documentation in `console-output`. """ from __future__ import annotations From e69584981cc20a93016ec6735c54e40035b59a99 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 1 Feb 2024 08:23:38 +0100 Subject: [PATCH 1188/1520] Markup --- docs/license.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/license.md b/docs/license.md index 12f6cf0d..718499c8 100644 --- a/docs/license.md +++ b/docs/license.md @@ -6,7 +6,7 @@ Any contribution intentionally submitted for inclusion in the work by you, as de --- -The reason for that is to be both protected against patent claims by own contributors and still allow the usage within GPLv2 software. For more legal details, see [this issue](https://github.com/pyca/cryptography/issues/1209) on the bug tracker of PyCA's `cryptography` project. +The reason for that is to be both protected against patent claims by own contributors and still allow the usage within GPLv2 software. For more legal details, see [this issue](https://github.com/pyca/cryptography/issues/1209) on the bug tracker of PyCA's *cryptography* project. The full license texts can be also found in the source code repository: From 98a49b7c98622fdaa8c86caec8b48a7c1974b9db Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 2 Feb 2024 07:40:46 +0100 Subject: [PATCH 1189/1520] Update Ruff --- .pre-commit-config.yaml | 4 ++-- pyproject.toml | 7 +++++-- tests/test_tracebacks.py | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 44c3c3ed..12dd3af4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,12 +4,12 @@ ci: repos: - repo: https://github.com/psf/black - rev: 24.1.0 + rev: 24.1.1 hooks: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.14 + rev: v0.2.0 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/pyproject.toml b/pyproject.toml index 6bb583ab..28c5d938 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -118,6 +118,8 @@ line-length = 79 [tool.ruff] src = ["src", "tests"] + +[tool.ruff.lint] select = ["ALL"] ignore = [ "A", # shadowing is fine @@ -149,11 +151,12 @@ ignore = [ "PTH", # pathlib can be slow, so no point to rewrite ] -[tool.ruff.per-file-ignores] +[tool.ruff.lint.per-file-ignores] "tests/*" = [ "B018", # "useless" expressions can be useful in tests "BLE", # tests have different rules around exceptions "EM", # tests have different rules around exceptions + "LOG001", # need to instantiate log messages in tests "PLC1901", # empty strings are falsey, but are less specific in tests "PT005", # we always add underscores and explicit name "RUF012", # no type hints in tests @@ -162,7 +165,7 @@ ignore = [ "TRY", # tests have different rules around exceptions ] -[tool.ruff.isort] +[tool.ruff.lint.isort] lines-between-types = 1 lines-after-imports = 2 diff --git a/tests/test_tracebacks.py b/tests/test_tracebacks.py index 71956b36..a41175cb 100644 --- a/tests/test_tracebacks.py +++ b/tests/test_tracebacks.py @@ -302,7 +302,7 @@ def test_syntax_error(): try: # raises SyntaxError: invalid syntax lineno = get_next_lineno() - eval("2 +* 2") # noqa: PGH001 + eval("2 +* 2") except SyntaxError as e: trace = tracebacks.extract(type(e), e, e.__traceback__) From 396720dfd2f33f5071b6e3c21467553579b79818 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 4 Feb 2024 12:49:55 +0100 Subject: [PATCH 1190/1520] Split up processor tests a bit --- pyproject.toml | 1 + tests/processors/__init__.py | 0 tests/{ => processors}/test_processors.py | 541 +-------------------- tests/processors/test_renderers.py | 558 ++++++++++++++++++++++ 4 files changed, 561 insertions(+), 539 deletions(-) create mode 100644 tests/processors/__init__.py rename tests/{ => processors}/test_processors.py (54%) create mode 100644 tests/processors/test_renderers.py diff --git a/pyproject.toml b/pyproject.toml index 28c5d938..37192a1e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -145,6 +145,7 @@ ignore = [ "T201", # prints are fine "TCH", # TYPE_CHECKING blocks break autodocs "TD", # we don't follow other people's todo style + "TID252", # Relative imports are fine "TRY003", # simple strings are fine "TRY004", # too many false negatives "TRY300", # else blocks are nice, but code-locality is nicer diff --git a/tests/processors/__init__.py b/tests/processors/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/test_processors.py b/tests/processors/test_processors.py similarity index 54% rename from tests/test_processors.py rename to tests/processors/test_processors.py index 9fd16787..865c1f7d 100644 --- a/tests/test_processors.py +++ b/tests/processors/test_processors.py @@ -5,14 +5,12 @@ from __future__ import annotations -import datetime import functools import inspect import itertools import json import logging import os -import pickle import sys import threading @@ -20,8 +18,6 @@ import pytest -from freezegun import freeze_time - import structlog from structlog import BoundLogger @@ -31,24 +27,17 @@ CallsiteParameterAdder, EventRenamer, ExceptionPrettyPrinter, - ExceptionRenderer, JSONRenderer, - KeyValueRenderer, - LogfmtRenderer, - MaybeTimeStamper, StackInfoRenderer, - TimeStamper, UnicodeDecoder, UnicodeEncoder, _figure_out_exc_info, - _json_fallback_handler, format_exc_info, ) from structlog.stdlib import ProcessorFormatter -from structlog.threadlocal import wrap_dict from structlog.typing import EventDict -from tests.additional_frame import additional_frame -from tests.utils import CustomError + +from ..additional_frame import additional_frame try: @@ -57,532 +46,6 @@ simplejson = None -class TestKeyValueRenderer: - def test_sort_keys(self, event_dict): - """ - Keys are sorted if sort_keys is set. - """ - rv = KeyValueRenderer(sort_keys=True)(None, None, event_dict) - - assert r"a= b=[3, 4] x=7 y='test' z=(1, 2)" == rv - - def test_order_complete(self, event_dict): - """ - Orders keys according to key_order. - """ - rv = KeyValueRenderer(key_order=["y", "b", "a", "z", "x"])( - None, None, event_dict - ) - - assert r"y='test' b=[3, 4] a= z=(1, 2) x=7" == rv - - def test_order_missing(self, event_dict): - """ - Missing keys get rendered as None. - """ - rv = KeyValueRenderer(key_order=["c", "y", "b", "a", "z", "x"])( - None, None, event_dict - ) - - assert r"c=None y='test' b=[3, 4] a= z=(1, 2) x=7" == rv - - def test_order_missing_dropped(self, event_dict): - """ - Missing keys get dropped - """ - rv = KeyValueRenderer( - key_order=["c", "y", "b", "a", "z", "x"], drop_missing=True - )(None, None, event_dict) - - assert r"y='test' b=[3, 4] a= z=(1, 2) x=7" == rv - - def test_order_extra(self, event_dict): - """ - Extra keys get sorted if sort_keys=True. - """ - event_dict["B"] = "B" - event_dict["A"] = "A" - - rv = KeyValueRenderer( - key_order=["c", "y", "b", "a", "z", "x"], sort_keys=True - )(None, None, event_dict) - - assert ( - r"c=None y='test' b=[3, 4] a= z=(1, 2) x=7 A='A' B='B'" - ) == rv - - def test_order_sorted_missing_dropped(self, event_dict): - """ - Keys get sorted if sort_keys=True and extras get dropped. - """ - event_dict["B"] = "B" - event_dict["A"] = "A" - - rv = KeyValueRenderer( - key_order=["c", "y", "b", "a", "z", "x"], - sort_keys=True, - drop_missing=True, - )(None, None, event_dict) - - assert r"y='test' b=[3, 4] a= z=(1, 2) x=7 A='A' B='B'" == rv - - def test_random_order(self, event_dict): - """ - No special ordering doesn't blow up. - """ - rv = KeyValueRenderer()(None, None, event_dict) - - assert isinstance(rv, str) - - @pytest.mark.parametrize("rns", [True, False]) - def test_repr_native_str(self, rns): - """ - repr_native_str=False doesn't repr on native strings. - """ - rv = KeyValueRenderer(repr_native_str=rns)( - None, None, {"event": "哈", "key": 42, "key2": "哈"} - ) - - cnt = rv.count("哈") - assert 2 == cnt - - -class TestLogfmtRenderer: - def test_sort_keys(self, event_dict): - """ - Keys are sorted if sort_keys is set. - """ - rv = LogfmtRenderer(sort_keys=True)(None, None, event_dict) - - assert r'a= b="[3, 4]" x=7 y=test z="(1, 2)"' == rv - - def test_order_complete(self, event_dict): - """ - Orders keys according to key_order. - """ - rv = LogfmtRenderer(key_order=["y", "b", "a", "z", "x"])( - None, None, event_dict - ) - - assert r'y=test b="[3, 4]" a= z="(1, 2)" x=7' == rv - - def test_order_missing(self, event_dict): - """ - Missing keys get rendered as None. - """ - rv = LogfmtRenderer(key_order=["c", "y", "b", "a", "z", "x"])( - None, None, event_dict - ) - - assert r'c= y=test b="[3, 4]" a= z="(1, 2)" x=7' == rv - - def test_order_missing_dropped(self, event_dict): - """ - Missing keys get dropped - """ - rv = LogfmtRenderer( - key_order=["c", "y", "b", "a", "z", "x"], drop_missing=True - )(None, None, event_dict) - - assert r'y=test b="[3, 4]" a= z="(1, 2)" x=7' == rv - - def test_order_extra(self, event_dict): - """ - Extra keys get sorted if sort_keys=True. - """ - event_dict["B"] = "B" - event_dict["A"] = "A" - - rv = LogfmtRenderer( - key_order=["c", "y", "b", "a", "z", "x"], sort_keys=True - )(None, None, event_dict) - - assert ( - r'c= y=test b="[3, 4]" a= z="(1, 2)" x=7 A=A B=B' - ) == rv - - def test_order_sorted_missing_dropped(self, event_dict): - """ - Keys get sorted if sort_keys=True and extras get dropped. - """ - event_dict["B"] = "B" - event_dict["A"] = "A" - - rv = LogfmtRenderer( - key_order=["c", "y", "b", "a", "z", "x"], - sort_keys=True, - drop_missing=True, - )(None, None, event_dict) - - assert r'y=test b="[3, 4]" a= z="(1, 2)" x=7 A=A B=B' == rv - - def test_random_order(self, event_dict): - """ - No special ordering doesn't blow up. - """ - rv = LogfmtRenderer()(None, None, event_dict) - - assert isinstance(rv, str) - - def test_empty_event_dict(self): - """ - Empty event dict renders as empty string. - """ - rv = LogfmtRenderer()(None, None, {}) - - assert "" == rv - - def test_bool_as_flag(self): - """ - If activated, render ``{"a": True}`` as ``a`` instead of ``a=true``. - """ - event_dict = {"a": True, "b": False} - - rv_abbrev = LogfmtRenderer(bool_as_flag=True)(None, None, event_dict) - assert r"a b=false" == rv_abbrev - - rv_no_abbrev = LogfmtRenderer(bool_as_flag=False)( - None, None, event_dict - ) - assert r"a=true b=false" == rv_no_abbrev - - def test_reference_format(self): - """ - Test rendering according to example at - https://pkg.go.dev/github.com/kr/logfmt - """ - event_dict = { - "foo": "bar", - "a": 14, - "baz": "hello kitty", - "cool%story": "bro", - "f": True, - "%^asdf": True, - } - - rv = LogfmtRenderer()(None, None, event_dict) - assert 'foo=bar a=14 baz="hello kitty" cool%story=bro f %^asdf' == rv - - def test_equal_sign_or_space_in_value(self): - """ - Values with equal signs are always quoted. - """ - event_dict = { - "without": "somevalue", - "withequal": "some=value", - "withspace": "some value", - } - - rv = LogfmtRenderer()(None, None, event_dict) - assert ( - r'without=somevalue withequal="some=value" withspace="some value"' - == rv - ) - - def test_invalid_key(self): - """ - Keys cannot contain space characters. - """ - event_dict = { - "invalid key": "somevalue", - } - - with pytest.raises(ValueError, match='Invalid key: "invalid key"'): - LogfmtRenderer()(None, None, event_dict) - - def test_newline_in_value(self): - """ - Newlines in values are escaped. - """ - event_dict = {"with_newline": "some\nvalue"} - - rv = LogfmtRenderer()(None, None, event_dict) - - assert r"with_newline=some\nvalue" == rv - - -class TestJSONRenderer: - def test_renders_json(self, event_dict): - """ - Renders a predictable JSON string. - """ - rv = JSONRenderer(sort_keys=True)(None, None, event_dict) - - assert ( - r'{"a": "", "b": [3, 4], "x": 7, ' - r'"y": "test", "z": ' - r"[1, 2]}" - ) == rv - - def test_FallbackEncoder_handles_ThreadLocalDictWrapped_dicts(self): - """ - Our fallback handling handles properly ThreadLocalDictWrapper values. - """ - with pytest.deprecated_call(): - d = wrap_dict(dict) - - s = json.dumps(d({"a": 42}), default=_json_fallback_handler) - - assert '{"a": 42}' == s - - def test_FallbackEncoder_falls_back(self): - """ - The fallback handler uses repr if it doesn't know the type. - """ - s = json.dumps( - {"date": datetime.date(1980, 3, 25)}, - default=_json_fallback_handler, - ) - - assert '{"date": "datetime.date(1980, 3, 25)"}' == s - - def test_serializer(self): - """ - A custom serializer is used if specified. - """ - jr = JSONRenderer(serializer=lambda obj, **kw: {"a": 42}) - obj = object() - - assert {"a": 42} == jr(None, None, obj) - - def test_custom_fallback(self): - """ - A custom fallback handler can be used. - """ - jr = JSONRenderer(default=lambda x: repr(x)[::-1]) - d = {"date": datetime.date(1980, 3, 25)} - - assert '{"date": ")52 ,3 ,0891(etad.emitetad"}' == jr(None, None, d) - - @pytest.mark.skipif(simplejson is None, reason="simplejson is missing.") - def test_simplejson(self, event_dict): - """ - Integration test with simplejson. - """ - jr = JSONRenderer(serializer=simplejson.dumps) - - assert { - "a": "", - "b": [3, 4], - "x": 7, - "y": "test", - "z": [1, 2], - } == json.loads(jr(None, None, event_dict)) - - -class TestTimeStamper: - def test_disallows_non_utc_unix_timestamps(self): - """ - A asking for a UNIX timestamp with a timezone that's not UTC raises a - ValueError. - """ - with pytest.raises( - ValueError, match="UNIX timestamps are always UTC." - ): - TimeStamper(utc=False) - - def test_inserts_utc_unix_timestamp_by_default(self): - """ - Per default a float UNIX timestamp is used. - """ - ts = TimeStamper() - d = ts(None, None, {}) - - # freezegun doesn't work with time.time. :( - assert isinstance(d["timestamp"], float) - - @freeze_time("1980-03-25 16:00:00") - def test_local(self): - """ - Timestamp in local timezone work. We can't add a timezone to the - string without additional libraries. - """ - ts = TimeStamper(fmt="iso", utc=False) - d = ts(None, None, {}) - - assert "1980-03-25T16:00:00" == d["timestamp"] - - @freeze_time("1980-03-25 16:00:00") - def test_formats(self): - """ - The fmt string is respected. - """ - ts = TimeStamper(fmt="%Y") - d = ts(None, None, {}) - - assert "1980" == d["timestamp"] - - @freeze_time("1980-03-25 16:00:00") - def test_adds_Z_to_iso(self): - """ - stdlib's isoformat is buggy, so we fix it. - """ - ts = TimeStamper(fmt="iso", utc=True) - d = ts(None, None, {}) - - assert "1980-03-25T16:00:00Z" == d["timestamp"] - - @freeze_time("1980-03-25 16:00:00") - def test_key_can_be_specified(self): - """ - Timestamp is stored with the specified key. - """ - ts = TimeStamper(fmt="%m", key="month") - d = ts(None, None, {}) - - assert "03" == d["month"] - - @freeze_time("1980-03-25 16:00:00") - @pytest.mark.parametrize("fmt", [None, "%Y"]) - @pytest.mark.parametrize("utc", [True, False]) - @pytest.mark.parametrize("key", [None, "other-key"]) - @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL + 1)) - def test_pickle(self, fmt, utc, key, proto): - """ - TimeStamper is serializable. - """ - # UNIX timestamps must be UTC. - if fmt is None and not utc: - pytest.skip() - - ts = TimeStamper() - - assert ts(None, None, {}) == pickle.loads(pickle.dumps(ts, proto))( - None, None, {} - ) - - def test_apply_freezegun_after_instantiation(self): - """ - Freezing time after instantiation of TimeStamper works. - """ - ts = TimeStamper(fmt="iso", utc=False) - - with freeze_time("1980-03-25 16:00:00", tz_offset=1): - d = ts(None, None, {}) - - assert "1980-03-25T17:00:00" == d["timestamp"] - - -class TestMaybeTimeStamper: - def test_overwrite(self): - """ - If there is a timestamp, leave it. - """ - mts = MaybeTimeStamper() - - assert {"timestamp": 42} == mts(None, None, {"timestamp": 42}) - - def test_none(self): - """ - If there is no timestamp, add one. - """ - mts = MaybeTimeStamper() - - assert "timestamp" in mts(None, None, {}) - - -class TestFormatExcInfo: - def test_custom_formatter(self): - """ - The exception formatter can be changed. - """ - formatter = ExceptionRenderer(lambda _: "There is no exception!") - - try: - raise CustomError("test") - except CustomError as e: - exc = e - - assert formatter(None, None, {"exc_info": exc}) == { - "exception": "There is no exception!" - } - - @pytest.mark.parametrize("ei", [False, None, ""]) - def test_nop(self, ei): - """ - If exc_info is falsey, only remove the key. - """ - assert {} == ExceptionRenderer()(None, None, {"exc_info": ei}) - - def test_nop_missing(self): - """ - If event dict doesn't contain exc_info, do nothing. - """ - assert {} == ExceptionRenderer()(None, None, {}) - - def test_formats_tuple(self): - """ - If exc_info is a tuple, it is used. - """ - formatter = ExceptionRenderer(lambda exc_info: exc_info) - d = formatter(None, None, {"exc_info": (None, None, 42)}) - - assert {"exception": (None, None, 42)} == d - - def test_gets_exc_info_on_bool(self): - """ - If exc_info is True, it is obtained using sys.exc_info(). - """ - # monkeypatching sys.exc_info makes currently pytest return 1 on - # success. - try: - raise ValueError("test") - except ValueError: - d = ExceptionRenderer()(None, None, {"exc_info": True}) - - assert "exc_info" not in d - assert 'raise ValueError("test")' in d["exception"] - assert "ValueError: test" in d["exception"] - - def test_exception(self): - """ - Passing exceptions as exc_info is valid. - """ - formatter = ExceptionRenderer(lambda exc_info: exc_info) - - try: - raise ValueError("test") - except ValueError as e: - exc = e - else: - pytest.fail("Exception not raised.") - - assert { - "exception": (ValueError, exc, exc.__traceback__) - } == formatter(None, None, {"exc_info": exc}) - - def test_exception_without_traceback(self): - """ - If an Exception is missing a traceback, render it anyway. - """ - rv = ExceptionRenderer()( - None, None, {"exc_info": Exception("no traceback!")} - ) - - assert {"exception": "Exception: no traceback!"} == rv - - def test_format_exception(self): - """ - "format_exception" is the "ExceptionRenderer" with default settings. - """ - try: - raise ValueError("test") - except ValueError as e: - a = format_exc_info(None, None, {"exc_info": e}) - b = ExceptionRenderer()(None, None, {"exc_info": e}) - - assert a == b - - @pytest.mark.parametrize("ei", [True, (None, None, None)]) - def test_no_exception(self, ei): - """ - A missing exception does not blow up. - """ - assert {"exception": "MISSING"} == format_exc_info( - None, None, {"exc_info": ei} - ) - - class TestUnicodeEncoder: def test_encodes(self): """ diff --git a/tests/processors/test_renderers.py b/tests/processors/test_renderers.py new file mode 100644 index 00000000..b3d6e51a --- /dev/null +++ b/tests/processors/test_renderers.py @@ -0,0 +1,558 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the MIT License. See the LICENSE file in the root of this +# repository for complete details. + +from __future__ import annotations + +import datetime +import json +import pickle + +import pytest + +from freezegun import freeze_time + +from structlog.processors import ( + ExceptionRenderer, + JSONRenderer, + KeyValueRenderer, + LogfmtRenderer, + MaybeTimeStamper, + TimeStamper, + _json_fallback_handler, + format_exc_info, +) +from structlog.threadlocal import wrap_dict + +from ..utils import CustomError + + +try: + import simplejson +except ImportError: + simplejson = None + + +class TestKeyValueRenderer: + def test_sort_keys(self, event_dict): + """ + Keys are sorted if sort_keys is set. + """ + rv = KeyValueRenderer(sort_keys=True)(None, None, event_dict) + + assert r"a= b=[3, 4] x=7 y='test' z=(1, 2)" == rv + + def test_order_complete(self, event_dict): + """ + Orders keys according to key_order. + """ + rv = KeyValueRenderer(key_order=["y", "b", "a", "z", "x"])( + None, None, event_dict + ) + + assert r"y='test' b=[3, 4] a= z=(1, 2) x=7" == rv + + def test_order_missing(self, event_dict): + """ + Missing keys get rendered as None. + """ + rv = KeyValueRenderer(key_order=["c", "y", "b", "a", "z", "x"])( + None, None, event_dict + ) + + assert r"c=None y='test' b=[3, 4] a= z=(1, 2) x=7" == rv + + def test_order_missing_dropped(self, event_dict): + """ + Missing keys get dropped + """ + rv = KeyValueRenderer( + key_order=["c", "y", "b", "a", "z", "x"], drop_missing=True + )(None, None, event_dict) + + assert r"y='test' b=[3, 4] a= z=(1, 2) x=7" == rv + + def test_order_extra(self, event_dict): + """ + Extra keys get sorted if sort_keys=True. + """ + event_dict["B"] = "B" + event_dict["A"] = "A" + + rv = KeyValueRenderer( + key_order=["c", "y", "b", "a", "z", "x"], sort_keys=True + )(None, None, event_dict) + + assert ( + r"c=None y='test' b=[3, 4] a= z=(1, 2) x=7 A='A' B='B'" + ) == rv + + def test_order_sorted_missing_dropped(self, event_dict): + """ + Keys get sorted if sort_keys=True and extras get dropped. + """ + event_dict["B"] = "B" + event_dict["A"] = "A" + + rv = KeyValueRenderer( + key_order=["c", "y", "b", "a", "z", "x"], + sort_keys=True, + drop_missing=True, + )(None, None, event_dict) + + assert r"y='test' b=[3, 4] a= z=(1, 2) x=7 A='A' B='B'" == rv + + def test_random_order(self, event_dict): + """ + No special ordering doesn't blow up. + """ + rv = KeyValueRenderer()(None, None, event_dict) + + assert isinstance(rv, str) + + @pytest.mark.parametrize("rns", [True, False]) + def test_repr_native_str(self, rns): + """ + repr_native_str=False doesn't repr on native strings. + """ + rv = KeyValueRenderer(repr_native_str=rns)( + None, None, {"event": "哈", "key": 42, "key2": "哈"} + ) + + cnt = rv.count("哈") + assert 2 == cnt + + +class TestLogfmtRenderer: + def test_sort_keys(self, event_dict): + """ + Keys are sorted if sort_keys is set. + """ + rv = LogfmtRenderer(sort_keys=True)(None, None, event_dict) + + assert r'a= b="[3, 4]" x=7 y=test z="(1, 2)"' == rv + + def test_order_complete(self, event_dict): + """ + Orders keys according to key_order. + """ + rv = LogfmtRenderer(key_order=["y", "b", "a", "z", "x"])( + None, None, event_dict + ) + + assert r'y=test b="[3, 4]" a= z="(1, 2)" x=7' == rv + + def test_order_missing(self, event_dict): + """ + Missing keys get rendered as None. + """ + rv = LogfmtRenderer(key_order=["c", "y", "b", "a", "z", "x"])( + None, None, event_dict + ) + + assert r'c= y=test b="[3, 4]" a= z="(1, 2)" x=7' == rv + + def test_order_missing_dropped(self, event_dict): + """ + Missing keys get dropped + """ + rv = LogfmtRenderer( + key_order=["c", "y", "b", "a", "z", "x"], drop_missing=True + )(None, None, event_dict) + + assert r'y=test b="[3, 4]" a= z="(1, 2)" x=7' == rv + + def test_order_extra(self, event_dict): + """ + Extra keys get sorted if sort_keys=True. + """ + event_dict["B"] = "B" + event_dict["A"] = "A" + + rv = LogfmtRenderer( + key_order=["c", "y", "b", "a", "z", "x"], sort_keys=True + )(None, None, event_dict) + + assert ( + r'c= y=test b="[3, 4]" a= z="(1, 2)" x=7 A=A B=B' + ) == rv + + def test_order_sorted_missing_dropped(self, event_dict): + """ + Keys get sorted if sort_keys=True and extras get dropped. + """ + event_dict["B"] = "B" + event_dict["A"] = "A" + + rv = LogfmtRenderer( + key_order=["c", "y", "b", "a", "z", "x"], + sort_keys=True, + drop_missing=True, + )(None, None, event_dict) + + assert r'y=test b="[3, 4]" a= z="(1, 2)" x=7 A=A B=B' == rv + + def test_random_order(self, event_dict): + """ + No special ordering doesn't blow up. + """ + rv = LogfmtRenderer()(None, None, event_dict) + + assert isinstance(rv, str) + + def test_empty_event_dict(self): + """ + Empty event dict renders as empty string. + """ + rv = LogfmtRenderer()(None, None, {}) + + assert "" == rv + + def test_bool_as_flag(self): + """ + If activated, render ``{"a": True}`` as ``a`` instead of ``a=true``. + """ + event_dict = {"a": True, "b": False} + + rv_abbrev = LogfmtRenderer(bool_as_flag=True)(None, None, event_dict) + assert r"a b=false" == rv_abbrev + + rv_no_abbrev = LogfmtRenderer(bool_as_flag=False)( + None, None, event_dict + ) + assert r"a=true b=false" == rv_no_abbrev + + def test_reference_format(self): + """ + Test rendering according to example at + https://pkg.go.dev/github.com/kr/logfmt + """ + event_dict = { + "foo": "bar", + "a": 14, + "baz": "hello kitty", + "cool%story": "bro", + "f": True, + "%^asdf": True, + } + + rv = LogfmtRenderer()(None, None, event_dict) + assert 'foo=bar a=14 baz="hello kitty" cool%story=bro f %^asdf' == rv + + def test_equal_sign_or_space_in_value(self): + """ + Values with equal signs are always quoted. + """ + event_dict = { + "without": "somevalue", + "withequal": "some=value", + "withspace": "some value", + } + + rv = LogfmtRenderer()(None, None, event_dict) + assert ( + r'without=somevalue withequal="some=value" withspace="some value"' + == rv + ) + + def test_invalid_key(self): + """ + Keys cannot contain space characters. + """ + event_dict = {"invalid key": "somevalue"} + + with pytest.raises(ValueError, match='Invalid key: "invalid key"'): + LogfmtRenderer()(None, None, event_dict) + + def test_newline_in_value(self): + """ + Newlines in values are escaped. + """ + event_dict = {"with_newline": "some\nvalue"} + + rv = LogfmtRenderer()(None, None, event_dict) + + assert r"with_newline=some\nvalue" == rv + + +class TestJSONRenderer: + def test_renders_json(self, event_dict): + """ + Renders a predictable JSON string. + """ + rv = JSONRenderer(sort_keys=True)(None, None, event_dict) + + assert ( + r'{"a": "", "b": [3, 4], "x": 7, ' + r'"y": "test", "z": ' + r"[1, 2]}" + ) == rv + + def test_FallbackEncoder_handles_ThreadLocalDictWrapped_dicts(self): + """ + Our fallback handling handles properly ThreadLocalDictWrapper values. + """ + with pytest.deprecated_call(): + d = wrap_dict(dict) + + s = json.dumps(d({"a": 42}), default=_json_fallback_handler) + + assert '{"a": 42}' == s + + def test_FallbackEncoder_falls_back(self): + """ + The fallback handler uses repr if it doesn't know the type. + """ + s = json.dumps( + {"date": datetime.date(1980, 3, 25)}, + default=_json_fallback_handler, + ) + + assert '{"date": "datetime.date(1980, 3, 25)"}' == s + + def test_serializer(self): + """ + A custom serializer is used if specified. + """ + jr = JSONRenderer(serializer=lambda obj, **kw: {"a": 42}) + obj = object() + + assert {"a": 42} == jr(None, None, obj) + + def test_custom_fallback(self): + """ + A custom fallback handler can be used. + """ + jr = JSONRenderer(default=lambda x: repr(x)[::-1]) + d = {"date": datetime.date(1980, 3, 25)} + + assert '{"date": ")52 ,3 ,0891(etad.emitetad"}' == jr(None, None, d) + + @pytest.mark.skipif(simplejson is None, reason="simplejson is missing.") + def test_simplejson(self, event_dict): + """ + Integration test with simplejson. + """ + jr = JSONRenderer(serializer=simplejson.dumps) + + assert { + "a": "", + "b": [3, 4], + "x": 7, + "y": "test", + "z": [1, 2], + } == json.loads(jr(None, None, event_dict)) + + +class TestTimeStamper: + def test_disallows_non_utc_unix_timestamps(self): + """ + A asking for a UNIX timestamp with a timezone that's not UTC raises a + ValueError. + """ + with pytest.raises( + ValueError, match="UNIX timestamps are always UTC." + ): + TimeStamper(utc=False) + + def test_inserts_utc_unix_timestamp_by_default(self): + """ + Per default a float UNIX timestamp is used. + """ + ts = TimeStamper() + d = ts(None, None, {}) + + # freezegun doesn't work with time.time. :( + assert isinstance(d["timestamp"], float) + + @freeze_time("1980-03-25 16:00:00") + def test_local(self): + """ + Timestamp in local timezone work. We can't add a timezone to the + string without additional libraries. + """ + ts = TimeStamper(fmt="iso", utc=False) + d = ts(None, None, {}) + + assert "1980-03-25T16:00:00" == d["timestamp"] + + @freeze_time("1980-03-25 16:00:00") + def test_formats(self): + """ + The fmt string is respected. + """ + ts = TimeStamper(fmt="%Y") + d = ts(None, None, {}) + + assert "1980" == d["timestamp"] + + @freeze_time("1980-03-25 16:00:00") + def test_adds_Z_to_iso(self): + """ + stdlib's isoformat is buggy, so we fix it. + """ + ts = TimeStamper(fmt="iso", utc=True) + d = ts(None, None, {}) + + assert "1980-03-25T16:00:00Z" == d["timestamp"] + + @freeze_time("1980-03-25 16:00:00") + def test_key_can_be_specified(self): + """ + Timestamp is stored with the specified key. + """ + ts = TimeStamper(fmt="%m", key="month") + d = ts(None, None, {}) + + assert "03" == d["month"] + + @freeze_time("1980-03-25 16:00:00") + @pytest.mark.parametrize("fmt", [None, "%Y"]) + @pytest.mark.parametrize("utc", [True, False]) + @pytest.mark.parametrize("key", [None, "other-key"]) + @pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL + 1)) + def test_pickle(self, fmt, utc, key, proto): + """ + TimeStamper is serializable. + """ + # UNIX timestamps must be UTC. + if fmt is None and not utc: + pytest.skip() + + ts = TimeStamper() + + assert ts(None, None, {}) == pickle.loads(pickle.dumps(ts, proto))( + None, None, {} + ) + + def test_apply_freezegun_after_instantiation(self): + """ + Freezing time after instantiation of TimeStamper works. + """ + ts = TimeStamper(fmt="iso", utc=False) + + with freeze_time("1980-03-25 16:00:00", tz_offset=1): + d = ts(None, None, {}) + + assert "1980-03-25T17:00:00" == d["timestamp"] + + +class TestMaybeTimeStamper: + def test_overwrite(self): + """ + If there is a timestamp, leave it. + """ + mts = MaybeTimeStamper() + + assert {"timestamp": 42} == mts(None, None, {"timestamp": 42}) + + def test_none(self): + """ + If there is no timestamp, add one. + """ + mts = MaybeTimeStamper() + + assert "timestamp" in mts(None, None, {}) + + +class TestFormatExcInfo: + def test_custom_formatter(self): + """ + The exception formatter can be changed. + """ + formatter = ExceptionRenderer(lambda _: "There is no exception!") + + try: + raise CustomError("test") + except CustomError as e: + exc = e + + assert formatter(None, None, {"exc_info": exc}) == { + "exception": "There is no exception!" + } + + @pytest.mark.parametrize("ei", [False, None, ""]) + def test_nop(self, ei): + """ + If exc_info is falsey, only remove the key. + """ + assert {} == ExceptionRenderer()(None, None, {"exc_info": ei}) + + def test_nop_missing(self): + """ + If event dict doesn't contain exc_info, do nothing. + """ + assert {} == ExceptionRenderer()(None, None, {}) + + def test_formats_tuple(self): + """ + If exc_info is a tuple, it is used. + """ + formatter = ExceptionRenderer(lambda exc_info: exc_info) + d = formatter(None, None, {"exc_info": (None, None, 42)}) + + assert {"exception": (None, None, 42)} == d + + def test_gets_exc_info_on_bool(self): + """ + If exc_info is True, it is obtained using sys.exc_info(). + """ + # monkeypatching sys.exc_info makes currently pytest return 1 on + # success. + try: + raise ValueError("test") + except ValueError: + d = ExceptionRenderer()(None, None, {"exc_info": True}) + + assert "exc_info" not in d + assert 'raise ValueError("test")' in d["exception"] + assert "ValueError: test" in d["exception"] + + def test_exception(self): + """ + Passing exceptions as exc_info is valid. + """ + formatter = ExceptionRenderer(lambda exc_info: exc_info) + + try: + raise ValueError("test") + except ValueError as e: + exc = e + else: + pytest.fail("Exception not raised.") + + assert { + "exception": (ValueError, exc, exc.__traceback__) + } == formatter(None, None, {"exc_info": exc}) + + def test_exception_without_traceback(self): + """ + If an Exception is missing a traceback, render it anyway. + """ + rv = ExceptionRenderer()( + None, None, {"exc_info": Exception("no traceback!")} + ) + + assert {"exception": "Exception: no traceback!"} == rv + + def test_format_exception(self): + """ + "format_exception" is the "ExceptionRenderer" with default settings. + """ + try: + raise ValueError("test") + except ValueError as e: + a = format_exc_info(None, None, {"exc_info": e}) + b = ExceptionRenderer()(None, None, {"exc_info": e}) + + assert a == b + + @pytest.mark.parametrize("ei", [True, (None, None, None)]) + def test_no_exception(self, ei): + """ + A missing exception does not blow up. + """ + assert {"exception": "MISSING"} == format_exc_info( + None, None, {"exc_info": ei} + ) From db834f532618e28d3fb68349a6d76af8493de541 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 5 Feb 2024 08:46:52 +0100 Subject: [PATCH 1191/1520] Fix docstring --- src/structlog/processors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/processors.py b/src/structlog/processors.py index b7c78055..ba87eb35 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -136,7 +136,7 @@ class LogfmtRenderer: ``flag=false``. Raises: - ValueError: If a key contains non printable or space characters. + ValueError: If a key contains non-printable or whitespace characters. .. versionadded:: 21.5.0 """ From 354ef534459cc3c1a12a21e402fffbaa3697a017 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 7 Feb 2024 11:08:38 +0100 Subject: [PATCH 1192/1520] Fix Logfmt escaping (#594) * logfmt: fix escaping of backslashes Fixes #511, closes #513 * Fix changelog * Add PR# * Update tests/processors/test_renderers.py Co-authored-by: Georges Dubus * Fix case of quotes in value --------- Co-authored-by: Georges Dubus --- CHANGELOG.md | 3 +++ src/structlog/processors.py | 11 +++++++++-- tests/processors/test_renderers.py | 27 +++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd810dea..9d3b8d5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - `structlog.processors.LogfmtRenderer` now escapes newlines. [#592](https://github.com/hynek/structlog/pull/592) +- `structlog.processors.LogfmtRenderer` now escapes backslashes and double quotes. + [#594](https://github.com/hynek/structlog/pull/594) + ## [24.1.0](https://github.com/hynek/structlog/compare/23.3.0...24.1.0) - 2024-01-08 diff --git a/src/structlog/processors.py b/src/structlog/processors.py index ba87eb35..e597eae4 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -170,9 +170,16 @@ def __call__( continue value = "true" if value else "false" - value = f"{value}".replace('"', '\\"').replace("\n", "\\n") + value = str(value) + backslashes_need_escaping = ( + " " in value or "=" in value or '"' in value + ) + if backslashes_need_escaping and "\\" in value: + value = value.replace("\\", "\\\\") + + value = value.replace('"', '\\"').replace("\n", "\\n") - if " " in value or "=" in value: + if backslashes_need_escaping: value = f'"{value}"' elements.append(f"{key}={value}") diff --git a/tests/processors/test_renderers.py b/tests/processors/test_renderers.py index b3d6e51a..8f225c80 100644 --- a/tests/processors/test_renderers.py +++ b/tests/processors/test_renderers.py @@ -275,6 +275,33 @@ def test_newline_in_value(self): assert r"with_newline=some\nvalue" == rv + @pytest.mark.parametrize( + ("raw", "escaped"), + [ + # Slash by itself does not need to be escaped. + (r"a\slash", r"a\slash"), + # A quote requires quoting, and escaping the quote. + ('a"quote', r'"a\"quote"'), + # If anything triggers quoting of the string, then the slash must + # be escaped. + ( + r'a\slash with space or a"quote', + r'"a\\slash with space or a\"quote"', + ), + ( + r"I want to render this \"string\" with logfmtrenderer", + r'"I want to render this \\\"string\\\" with logfmtrenderer"', + ), + ], + ) + def test_escaping(self, raw, escaped): + """ + Backslashes and quotes are escaped. + """ + rv = LogfmtRenderer()(None, None, {"key": raw}) + + assert f"key={escaped}" == rv + class TestJSONRenderer: def test_renders_json(self, event_dict): From 186d2eaf7a1d78cba940bd3e99277a538894a6f2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 17 Feb 2024 06:49:16 +0100 Subject: [PATCH 1193/1520] Pin interrogate to 3.11 --- .pre-commit-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 12dd3af4..64c9253d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,6 +18,7 @@ repos: rev: 1.5.0 hooks: - id: interrogate + language_version: python3.11 args: [tests] - repo: https://github.com/codespell-project/codespell From 555c3878a98e5b95986ca5cc36959d4eeaff8397 Mon Sep 17 00:00:00 2001 From: Bradley Stuart Kirton Date: Wed, 28 Feb 2024 14:17:41 +0200 Subject: [PATCH 1194/1520] docs: Update configuration documentation (#601) Update the structlog configure call in the configuration documentation to use an instance of LoggerFactory instead of the class definition. --- docs/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index 16820042..9c750d05 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -30,7 +30,7 @@ At any time, you can check whether and how *structlog* is configured using {func ```pycon >>> structlog.is_configured() False ->>> structlog.configure(logger_factory=structlog.stdlib.LoggerFactory) +>>> structlog.configure(logger_factory=structlog.stdlib.LoggerFactory()) >>> structlog.is_configured() True >>> cfg = structlog.get_config() From 6b82c5c98f1869abe6fc8f472387aca646ca4e45 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 5 Mar 2024 10:01:47 +0100 Subject: [PATCH 1195/1520] Use tox-uv in CI (#597) * Use tox-uv in CI * Vroom vroom dev env * Windows * Consistency --- .github/workflows/ci.yml | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6a644fb8..14e4c8a0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,7 +52,7 @@ jobs: python-version: ${{ matrix.python-version }} allow-prereleases: true cache: pip - - run: python -Im pip install tox + - run: python -Im pip install tox-uv - run: python -Im tox run --installpkg dist/*.whl -f py$(echo ${{ matrix.python-version }} | tr -d .) @@ -115,7 +115,7 @@ jobs: python-version-file: .python-version-default allow-prereleases: true cache: pip - - run: python -Im pip install tox + - run: python -Im pip install tox-uv - run: python -Im tox run --installpkg dist/*.whl -e mypy-pkg @@ -136,7 +136,7 @@ jobs: python-version-file: .python-version-default allow-prereleases: true cache: pip - - run: python -Im pip install tox + - run: python -Im pip install tox-uv - run: python -Im tox run --installpkg dist/*.whl -e pyright @@ -156,7 +156,7 @@ jobs: # Keep in sync with tox.ini/docs & .readthedocs.yaml python-version: "3.12" cache: pip - - run: python -Im pip install tox + - run: python -Im pip install tox-uv - run: python -Im tox run -e docs @@ -174,8 +174,14 @@ jobs: python-version-file: .python-version-default cache: pip - - run: python -Im pip install -e .[dev] - - run: python -Ic 'import structlog; print(structlog.__version__)' + - run: python -Im pip install uv + - run: uv venv + - run: uv pip install -e .[dev] + + - run: .venv/bin/python -Ic 'import structlog; print(structlog.__version__)' + if: runner.os != 'Windows' + - run: .\.venv\Scripts\python.exe -Ic 'import structlog; print(structlog.__version__)' + if: runner.os == 'Windows' required-checks-pass: name: Ensure everything required is passing for branch protection @@ -196,7 +202,6 @@ jobs: with: jobs: ${{ toJSON(needs) }} - colors: name: Visual check for color settings using env variables needs: build-package @@ -209,6 +214,6 @@ jobs: python-version-file: .python-version-default cache: pip # tox 4.12.0 started passing FORCE_COLOR and NO_COLOR by default. - - run: python -Im pip install 'tox>=4.12.0' + - run: python -Im pip install 'tox>=4.12.0' tox-uv - run: python -Im tox run -f color From 0a64815c04072d21d3f3f37c1b5b9239b6d3226b Mon Sep 17 00:00:00 2001 From: Alexander Demin Date: Tue, 5 Mar 2024 10:14:29 +0100 Subject: [PATCH 1196/1520] Add skip_level_padding to ConsoleRenderer (#599) * Add skip_level_padding to ConsoleRenderer * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Re-use existing width argument * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fix src/structlog/dev.py:545:9: PLR0915 * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fix accidentally duplicated "color_system" * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update src/structlog/dev.py * Update src/structlog/dev.py * Update src/structlog/dev.py --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Hynek Schlawack --- src/structlog/dev.py | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 315e91c6..b1175cd3 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -283,18 +283,29 @@ class LogLevelColumnFormatter: What to use to reset the style after the level name. Ignored if if *level_styles* is None. + width: + The width to pad the level to. If 0, no padding is done. + .. versionadded:: 23.3.0 + .. versionadded:: 24.2.0 *width* """ level_styles: dict[str, str] | None reset_style: str width: int - def __init__(self, level_styles: dict[str, str], reset_style: str) -> None: + def __init__( + self, + level_styles: dict[str, str], + reset_style: str, + width: int | None = None, + ) -> None: self.level_styles = level_styles if level_styles: - self.width = len( - max(self.level_styles.keys(), key=lambda e: len(e)) + self.width = ( + 0 + if width == 0 + else len(max(self.level_styles.keys(), key=lambda e: len(e))) ) self.reset_style = reset_style else: @@ -485,6 +496,10 @@ class ConsoleRenderer: rename it e.g. using `structlog.processors.EventRenamer`. Ignored if *columns* are passed. + pad_level: + Whether to pad log level with blanks to the longest amongst all + level label. + Requires the Colorama_ package if *colors* is `True` **on Windows**. Raises: @@ -524,9 +539,10 @@ class ConsoleRenderer: .. versionadded:: 22.1.0 *event_key* .. versionadded:: 23.2.0 *timestamp_key* .. versionadded:: 23.3.0 *columns* + .. versionadded:: 24.2.0 *pad_level* """ - def __init__( # noqa: PLR0912 + def __init__( # noqa: PLR0912, PLR0915 self, pad_event: int = _EVENT_WIDTH, colors: bool = _has_colors, @@ -538,6 +554,7 @@ def __init__( # noqa: PLR0912 event_key: str = "event", timestamp_key: str = "timestamp", columns: list[Column] | None = None, + pad_level: bool = True, ): self._exception_formatter = exception_formatter self._sort_keys = sort_keys @@ -645,6 +662,8 @@ def add_meaningless_arg(arg: str) -> None: postfix="]", ) + level_width = 0 if not pad_level else None + self._columns = [ Column( timestamp_key, @@ -658,7 +677,7 @@ def add_meaningless_arg(arg: str) -> None: Column( "level", LogLevelColumnFormatter( - level_to_color, reset_style=styles.reset + level_to_color, reset_style=styles.reset, width=level_width ), ), Column( From 04c4a6601adbd63b4334337bd65a0122cf26422b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 5 Mar 2024 10:15:51 +0100 Subject: [PATCH 1197/1520] Add changelog entry for #599 --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d3b8d5a..c2f8df48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,13 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ## [Unreleased](https://github.com/hynek/structlog/compare/24.1.0...HEAD) +### Added + +- It is now possible to disable log level-padding in `structlog.dev.LogLevelColumnFormatter` and `structlog.dev.ConsoleRenderer`. + [#599](https://github.com/hynek/structlog/pull/599) + + + ### Changed - `structlog.processors.LogfmtRenderer` now escapes newlines. @@ -24,6 +31,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ [#594](https://github.com/hynek/structlog/pull/594) + ## [24.1.0](https://github.com/hynek/structlog/compare/23.3.0...24.1.0) - 2024-01-08 ### Fixed From ac811aa6fc0a3744e21badc913204cd6fe0a46b1 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 11 Mar 2024 08:08:23 +0100 Subject: [PATCH 1198/1520] Make mypy pretty --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 37192a1e..53952998 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -173,6 +173,7 @@ lines-after-imports = 2 [tool.mypy] strict = true +pretty = true show_error_codes = true enable_error_code = ["ignore-without-code"] From f0c7e8c71eeb504829218b434bfb7774884bec5c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 11 Mar 2024 08:09:46 +0100 Subject: [PATCH 1199/1520] pre-commit autoupdate --- .pre-commit-config.yaml | 4 ++-- src/structlog/_base.py | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 64c9253d..9654fa4e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,12 +4,12 @@ ci: repos: - repo: https://github.com/psf/black - rev: 24.1.1 + rev: 24.2.0 hooks: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.2.0 + rev: v0.3.2 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/src/structlog/_base.py b/src/structlog/_base.py index dc5873ce..25f59277 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -51,9 +51,7 @@ def __init__( self._context = context def __repr__(self) -> str: - return "<{}(context={!r}, processors={!r})>".format( - self.__class__.__name__, self._context, self._processors - ) + return f"<{self.__class__.__name__}(context={self._context!r}, processors={self._processors!r})>" def __eq__(self, other: object) -> bool: try: From a62bbf6e41338b56f3a6e966d5fa00b0e0e929ea Mon Sep 17 00:00:00 2001 From: Eric Lunderberg Date: Thu, 14 Mar 2024 00:37:15 -0500 Subject: [PATCH 1200/1520] Allow CallsiteParameterAdder to be pickled (#603) * Allow CallsiteParameterAdder to be pickled Prior to this commit, the `CallsiteParameterAdder` object could not be pickled. As a result, structlog configurations could not be propagated to subprocesses using `pickle.dumps(structlog.get_config())`. This commit updates the handlers in `CallsiteParameterAdder._handlers` to be free functions, rather than lambda functions, so that all class members can be pickled. Closes #600 * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Updated changelog with link to PR * Update with type annotations, correct function naming conventions * Update tests/processors/test_processors.py --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Hynek Schlawack --- CHANGELOG.md | 2 + src/structlog/processors.py | 76 +++++++++++++++++++---------- tests/processors/test_processors.py | 9 ++++ 3 files changed, 60 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2f8df48..cf107bc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - It is now possible to disable log level-padding in `structlog.dev.LogLevelColumnFormatter` and `structlog.dev.ConsoleRenderer`. [#599](https://github.com/hynek/structlog/pull/599) +- The `structlog.processors.CallsiteParameterAdder` can now be pickled. + [#603](https://github.com/hynek/structlog/pull/603) ### Changed diff --git a/src/structlog/processors.py b/src/structlog/processors.py index e597eae4..ae873ce7 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -724,6 +724,46 @@ class CallsiteParameter(enum.Enum): PROCESS_NAME = "process_name" +def _get_callsite_pathname(module: str, frame_info: inspect.Traceback) -> Any: + return frame_info.filename + + +def _get_callsite_filename(module: str, frame_info: inspect.Traceback) -> Any: + return os.path.basename(frame_info.filename) + + +def _get_callsite_module(module: str, frame_info: inspect.Traceback) -> Any: + return os.path.splitext(os.path.basename(frame_info.filename))[0] + + +def _get_callsite_func_name(module: str, frame_info: inspect.Traceback) -> Any: + return frame_info.function + + +def _get_callsite_lineno(module: str, frame_info: inspect.Traceback) -> Any: + return frame_info.lineno + + +def _get_callsite_thread(module: str, frame_info: inspect.Traceback) -> Any: + return threading.get_ident() + + +def _get_callsite_thread_name( + module: str, frame_info: inspect.Traceback +) -> Any: + return threading.current_thread().name + + +def _get_callsite_process(module: str, frame_info: inspect.Traceback) -> Any: + return os.getpid() + + +def _get_callsite_process_name( + module: str, frame_info: inspect.Traceback +) -> Any: + return get_processname() + + class CallsiteParameterAdder: """ Adds parameters of the callsite that an event dictionary originated from to @@ -767,33 +807,15 @@ class CallsiteParameterAdder: _handlers: ClassVar[ dict[CallsiteParameter, Callable[[str, inspect.Traceback], Any]] ] = { - CallsiteParameter.PATHNAME: ( - lambda module, frame_info: frame_info.filename - ), - CallsiteParameter.FILENAME: ( - lambda module, frame_info: os.path.basename(frame_info.filename) - ), - CallsiteParameter.MODULE: ( - lambda module, frame_info: os.path.splitext( - os.path.basename(frame_info.filename) - )[0] - ), - CallsiteParameter.FUNC_NAME: ( - lambda module, frame_info: frame_info.function - ), - CallsiteParameter.LINENO: ( - lambda module, frame_info: frame_info.lineno - ), - CallsiteParameter.THREAD: ( - lambda module, frame_info: threading.get_ident() - ), - CallsiteParameter.THREAD_NAME: ( - lambda module, frame_info: threading.current_thread().name - ), - CallsiteParameter.PROCESS: (lambda module, frame_info: os.getpid()), - CallsiteParameter.PROCESS_NAME: ( - lambda module, frame_info: get_processname() - ), + CallsiteParameter.PATHNAME: _get_callsite_pathname, + CallsiteParameter.FILENAME: _get_callsite_filename, + CallsiteParameter.MODULE: _get_callsite_module, + CallsiteParameter.FUNC_NAME: _get_callsite_func_name, + CallsiteParameter.LINENO: _get_callsite_lineno, + CallsiteParameter.THREAD: _get_callsite_thread, + CallsiteParameter.THREAD_NAME: _get_callsite_thread_name, + CallsiteParameter.PROCESS: _get_callsite_process, + CallsiteParameter.PROCESS_NAME: _get_callsite_process_name, } _record_attribute_map: ClassVar[dict[CallsiteParameter, str]] = { CallsiteParameter.PATHNAME: "pathname", diff --git a/tests/processors/test_processors.py b/tests/processors/test_processors.py index 865c1f7d..cec06474 100644 --- a/tests/processors/test_processors.py +++ b/tests/processors/test_processors.py @@ -11,6 +11,7 @@ import json import logging import os +import pickle import sys import threading @@ -492,6 +493,14 @@ def test_e2e( assert expected == actual + def test_pickeable_callsite_parameter_adder(self) -> None: + """ + An instance of ``CallsiteParameterAdder`` can be pickled. This + functionality may be used to propagate structlog configurations to + subprocesses. + """ + pickle.dumps(CallsiteParameterAdder()) + @classmethod def make_processor( cls, From 6959f1d55568f9a743309c6824be32ca48e90192 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Wed, 27 Mar 2024 00:32:39 +0900 Subject: [PATCH 1201/1520] optimize CallsiteParameterAdder (#606) * optimize CallsiteParameterAdder CallsiteParameterAdder is slower than logging.Logger.findCaller() because findCaller() doesn't use inspect at all. This commit doesn't stop using inspect.getframeinfo(), but skips heavy code_context calculation. * update CHANGELOG * Do not use inspect in CallsiteParameterAdder * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fix type hint --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- CHANGELOG.md | 3 +++ src/structlog/processors.py | 41 ++++++++++++++++--------------------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf107bc7..9edf242b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - `structlog.processors.LogfmtRenderer` now escapes backslashes and double quotes. [#594](https://github.com/hynek/structlog/pull/594) +- `structlog.processors.CallsiteParameterAdder` has been optimized to be about 2x faster. + [#606](https://github.com/hynek/structlog/pull/606) + ## [24.1.0](https://github.com/hynek/structlog/compare/23.3.0...24.1.0) - 2024-01-08 diff --git a/src/structlog/processors.py b/src/structlog/processors.py index ae873ce7..65e6e00e 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -11,7 +11,6 @@ import datetime import enum -import inspect import json import logging import operator @@ -20,6 +19,7 @@ import threading import time +from types import FrameType from typing import ( Any, Callable, @@ -724,43 +724,39 @@ class CallsiteParameter(enum.Enum): PROCESS_NAME = "process_name" -def _get_callsite_pathname(module: str, frame_info: inspect.Traceback) -> Any: - return frame_info.filename +def _get_callsite_pathname(module: str, frame: FrameType) -> Any: + return frame.f_code.co_filename -def _get_callsite_filename(module: str, frame_info: inspect.Traceback) -> Any: - return os.path.basename(frame_info.filename) +def _get_callsite_filename(module: str, frame: FrameType) -> Any: + return os.path.basename(frame.f_code.co_filename) -def _get_callsite_module(module: str, frame_info: inspect.Traceback) -> Any: - return os.path.splitext(os.path.basename(frame_info.filename))[0] +def _get_callsite_module(module: str, frame: FrameType) -> Any: + return os.path.splitext(os.path.basename(frame.f_code.co_filename))[0] -def _get_callsite_func_name(module: str, frame_info: inspect.Traceback) -> Any: - return frame_info.function +def _get_callsite_func_name(module: str, frame: FrameType) -> Any: + return frame.f_code.co_name -def _get_callsite_lineno(module: str, frame_info: inspect.Traceback) -> Any: - return frame_info.lineno +def _get_callsite_lineno(module: str, frame: FrameType) -> Any: + return frame.f_lineno -def _get_callsite_thread(module: str, frame_info: inspect.Traceback) -> Any: +def _get_callsite_thread(module: str, frame: FrameType) -> Any: return threading.get_ident() -def _get_callsite_thread_name( - module: str, frame_info: inspect.Traceback -) -> Any: +def _get_callsite_thread_name(module: str, frame: FrameType) -> Any: return threading.current_thread().name -def _get_callsite_process(module: str, frame_info: inspect.Traceback) -> Any: +def _get_callsite_process(module: str, frame: FrameType) -> Any: return os.getpid() -def _get_callsite_process_name( - module: str, frame_info: inspect.Traceback -) -> Any: +def _get_callsite_process_name(module: str, frame: FrameType) -> Any: return get_processname() @@ -805,7 +801,7 @@ class CallsiteParameterAdder: """ _handlers: ClassVar[ - dict[CallsiteParameter, Callable[[str, inspect.Traceback], Any]] + dict[CallsiteParameter, Callable[[str, FrameType], Any]] ] = { CallsiteParameter.PATHNAME: _get_callsite_pathname, CallsiteParameter.FILENAME: _get_callsite_filename, @@ -849,7 +845,7 @@ def __init__( # module should not be logging using structlog. self._additional_ignores = ["logging", *additional_ignores] self._active_handlers: list[ - tuple[CallsiteParameter, Callable[[str, inspect.Traceback], Any]] + tuple[CallsiteParameter, Callable[[str, FrameType], Any]] ] = [] self._record_mappings: list[CallsiteParameterAdder._RecordMapping] = [] for parameter in parameters: @@ -879,9 +875,8 @@ def __call__( frame, module = _find_first_app_frame_and_name( additional_ignores=self._additional_ignores ) - frame_info = inspect.getframeinfo(frame) for parameter, handler in self._active_handlers: - event_dict[parameter.value] = handler(module, frame_info) + event_dict[parameter.value] = handler(module, frame) return event_dict From 8eb309ece3d3dc1e21751f9e5de344fbe962b14c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 27 Mar 2024 12:07:21 +0100 Subject: [PATCH 1202/1520] Dedup matrix creation with baipp v2.1 (#608) --- .github/workflows/ci.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 14e4c8a0..a59cf634 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,6 +25,10 @@ jobs: fetch-depth: 0 - uses: hynek/build-and-inspect-python-package@v2 + id: baipp + + outputs: + python-versions: ${{ steps.baipp.outputs.supported_python_classifiers_json_array }} tests: name: Tests & API Mypy on ${{ matrix.python-version }} @@ -33,12 +37,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: - - "3.8" - - "3.9" - - "3.10" - - "3.11" - - "3.12" + python-version: ${{ fromJson(needs.build-package.outputs.python-versions) }} steps: - name: Download pre-built packages From 9c44b249b930ec8cb3ded3d257437de77b4f2c74 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 1 Apr 2024 20:04:53 +0200 Subject: [PATCH 1203/1520] [pre-commit.ci] pre-commit autoupdate (#611) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/psf/black: 24.2.0 → 24.3.0](https://github.com/psf/black/compare/24.2.0...24.3.0) - [github.com/astral-sh/ruff-pre-commit: v0.3.2 → v0.3.4](https://github.com/astral-sh/ruff-pre-commit/compare/v0.3.2...v0.3.4) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9654fa4e..dfc6f55d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,12 +4,12 @@ ci: repos: - repo: https://github.com/psf/black - rev: 24.2.0 + rev: 24.3.0 hooks: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.3.2 + rev: v0.3.4 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From c34da0217f4b0cee642c1c56a5a76ed723ead3b2 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Tue, 2 Apr 2024 14:05:44 +0900 Subject: [PATCH 1204/1520] optimize `_find_first_app_frame_and_name` (#607) * optimize stdlib findCaller * use for-else instead of any(...) * use str.startswith(tuple) --------- Co-authored-by: Hynek Schlawack --- src/structlog/_frames.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/structlog/_frames.py b/src/structlog/_frames.py index a7326eb6..35c06eaa 100644 --- a/src/structlog/_frames.py +++ b/src/structlog/_frames.py @@ -55,10 +55,10 @@ def _find_first_app_frame_and_name( Returns: tuple of (frame, name) """ - ignores = ["structlog"] + (additional_ignores or []) + ignores = tuple(["structlog"] + (additional_ignores or [])) f = _ASYNC_CALLING_STACK.get(_getframe()) name = f.f_globals.get("__name__") or "?" - while any(tuple(name.startswith(i) for i in ignores)): + while name.startswith(ignores): if f.f_back is None: name = "?" break From f26afb0070f91a5be3c8ebe5cf0ebf1b044b2392 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Tue, 2 Apr 2024 16:29:59 +0900 Subject: [PATCH 1205/1520] add some note about logging configuration (#609) * add some note about logging configuration * use {note} * Minor adjustments --------- Co-authored-by: Hynek Schlawack --- docs/standard-library.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/standard-library.md b/docs/standard-library.md index dd857e4c..541fcdf6 100644 --- a/docs/standard-library.md +++ b/docs/standard-library.md @@ -144,6 +144,15 @@ The most straight-forward option is to configure standard library `logging` clos Since these are usually log entries from third parties that don't take advantage of *structlog*'s features, this is surprisingly often a perfectly adequate approach. For instance, if you log JSON in production, configure `logging` to use [*python-json-logger*] to make it print JSON too, and then tweak the configuration to match their outputs. +You can also use {class}`~structlog.stdlib.ProcessorFormatter` as a formatter for `logging` to get the same output for both *structlog* and `logging` log entries -- see [below](processor-formatter) for an example. + +:::{note} +If you want to use same file (for example, `sys.stdout` or `sys.stderr`) for both *structlog* and `logging.StreamHandler` output, you must use {class}`~structlog.WriteLogger` instead of {class}`~structlog.PrintLogger`. + +This is because {class}`~structlog.PrintLogger` uses `print(log, file=file, flush=True)` to write log, and `print` writes the `log` message and a newline ("\n") to the stream separately. +This can cause interleaving of log entries from *structlog* and `logging` loggers. +{class}`~structlog.WriteLogger` writes log entries atomically to the file (for example, `file.write(log+"\n")`). +::: ### Rendering Within *structlog* From a8526a0628dc257f896ca331f4a7d96777933f6c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 2 Apr 2024 09:37:46 +0200 Subject: [PATCH 1206/1520] Document direnv + uv --- .github/CONTRIBUTING.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 2f9e2263..2ae3ff1a 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -51,6 +51,15 @@ If you're using [*direnv*](https://direnv.net), you can automate the creation of layout python python$(cat .python-version-default) ``` +or, if you like [*uv*](https://github.com/astral-sh/uv): + +```bash +test -d .venv || uv venv --python python`cat .python-version-default` +. .venv/bin/activate +``` + +--- + [Create a fork](https://github.com/hynek/structlog/fork) of the *structlog* repository and clone it: ```console From 145645685533895927e539a8942028a4e35a6dee Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 2 Apr 2024 09:39:36 +0200 Subject: [PATCH 1207/1520] Use more legible syntax --- .github/CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 2ae3ff1a..2f519f82 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -54,7 +54,7 @@ layout python python$(cat .python-version-default) or, if you like [*uv*](https://github.com/astral-sh/uv): ```bash -test -d .venv || uv venv --python python`cat .python-version-default` +test -d .venv || uv venv --python python$(cat .python-version-default) . .venv/bin/activate ``` From 5abf7b5383472e178f6b9806fef0db108f615253 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Tue, 2 Apr 2024 22:57:52 +0900 Subject: [PATCH 1208/1520] remove `until_not_interrupted()` (#612) * remove until_not_interrupted Retry is not needed since Python 3.5. https://peps.python.org/pep-0475/ * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- src/structlog/_output.py | 12 +++++------ src/structlog/_utils.py | 31 +--------------------------- src/structlog/twisted.py | 6 ++---- tests/test_utils.py | 44 +--------------------------------------- 4 files changed, 9 insertions(+), 84 deletions(-) diff --git a/src/structlog/_output.py b/src/structlog/_output.py index 548d5d3d..f4ce3b7f 100644 --- a/src/structlog/_output.py +++ b/src/structlog/_output.py @@ -17,8 +17,6 @@ from sys import stderr, stdout from typing import IO, Any, BinaryIO, TextIO -from structlog._utils import until_not_interrupted - WRITE_LOCKS: dict[IO[Any], threading.Lock] = {} @@ -109,7 +107,7 @@ def msg(self, message: str) -> None: """ f = self._file if self._file is not stdout else None with self._lock: - until_not_interrupted(print, message, file=f, flush=True) + print(message, file=f, flush=True) log = debug = info = warn = warning = msg fatal = failure = err = error = critical = exception = msg @@ -216,8 +214,8 @@ def msg(self, message: str) -> None: Write and flush *message*. """ with self._lock: - until_not_interrupted(self._write, message + "\n") - until_not_interrupted(self._flush) + self._write(message + "\n") + self._flush() log = debug = info = warn = warning = msg fatal = failure = err = error = critical = exception = msg @@ -320,8 +318,8 @@ def msg(self, message: bytes) -> None: Write *message*. """ with self._lock: - until_not_interrupted(self._write, message + b"\n") - until_not_interrupted(self._flush) + self._write(message + b"\n") + self._flush() log = debug = info = warn = warning = msg fatal = failure = err = error = critical = exception = msg diff --git a/src/structlog/_utils.py b/src/structlog/_utils.py index 5bc8882f..9a41c257 100644 --- a/src/structlog/_utils.py +++ b/src/structlog/_utils.py @@ -9,39 +9,10 @@ from __future__ import annotations -import errno import sys from contextlib import suppress -from typing import Any, Callable, TypeVar - - -T = TypeVar("T") - - -def until_not_interrupted( - f: Callable[..., T], *args: object, **kw: object -) -> T: - """ - Retry until *f* succeeds or an exception that isn't caused by EINTR occurs. - - Args: - f: A callable like a function. - - *args: Positional arguments for *f*. - - **kw: Keyword arguments for *f*. - - Returns: - Whatever *f* returns. - """ - while True: - try: - return f(*args, **kw) - except OSError as e: # noqa: PERF203 - if e.args[0] == errno.EINTR: - continue - raise +from typing import Any def get_processname() -> str: diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index 411555b1..a4caf897 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -24,7 +24,6 @@ from ._base import BoundLoggerBase from ._config import _BUILTIN_DEFAULT_PROCESSORS -from ._utils import until_not_interrupted from .processors import JSONRenderer as GenericJSONRenderer from .typing import EventDict, WrappedLogger @@ -215,12 +214,11 @@ def __init__(self, file: TextIO) -> None: self._flush = file.flush def __call__(self, eventDict: EventDict) -> None: - until_not_interrupted( - self._write, + self._write( textFromEventDict(eventDict) # type: ignore[arg-type, operator] + "\n", ) - until_not_interrupted(self._flush) + self._flush() @implementer(ILogObserver) diff --git a/tests/test_utils.py b/tests/test_utils.py index 7ef508a0..63577fcf 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -3,54 +3,12 @@ # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. -import errno import multiprocessing import sys import pytest -from pretend import raiser - -from structlog._utils import get_processname, until_not_interrupted - - -class TestUntilNotInterrupted: - def test_passes_arguments_and_returns_return_value(self): - """ - until_not_interrupted() passes arguments to the wrapped function and - returns its return value. - """ - - def returner(*args, **kw): - assert (42,) == args - assert {"x": 23} == kw - - return "foo" - - assert "foo" == until_not_interrupted(returner, 42, x=23) - - def test_leaves_unrelated_exceptions_through(self): - """ - Exceptions that are not an EINTR OSError are not intercepted/retried. - """ - exc = IOError - with pytest.raises(exc): - until_not_interrupted(raiser(exc("not EINTR"))) - - def test_retries_on_EINTR(self): - """ - Wrapped functions that raise EINTR OSErrors are retried. - """ - calls = [0] - - def raise_on_first_three(): - if calls[0] < 3: - calls[0] += 1 - raise OSError(errno.EINTR) - - until_not_interrupted(raise_on_first_three) - - assert 3 == calls[0] +from structlog._utils import get_processname class TestGetProcessname: From 00fbc159fd5a3168fddad76833df143613b8468c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 6 Apr 2024 16:32:18 -0700 Subject: [PATCH 1209/1520] pre-commit autoupdate --- .pre-commit-config.yaml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index dfc6f55d..a80046f5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,16 +9,15 @@ repos: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.3.4 + rev: v0.3.5 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] - repo: https://github.com/econchick/interrogate - rev: 1.5.0 + rev: 1.6.0 hooks: - id: interrogate - language_version: python3.11 args: [tests] - repo: https://github.com/codespell-project/codespell @@ -28,7 +27,7 @@ repos: args: [-L, alog] - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v4.6.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer From d71e4704ec585522a28ad005fc180781821b85c2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 8 May 2024 10:37:27 +0200 Subject: [PATCH 1210/1520] [pre-commit.ci] pre-commit autoupdate (#616) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/psf/black: 24.3.0 → 24.4.2](https://github.com/psf/black/compare/24.3.0...24.4.2) - [github.com/astral-sh/ruff-pre-commit: v0.3.5 → v0.4.3](https://github.com/astral-sh/ruff-pre-commit/compare/v0.3.5...v0.4.3) - [github.com/econchick/interrogate: 1.6.0 → 1.7.0](https://github.com/econchick/interrogate/compare/1.6.0...1.7.0) * Fix furo warning * Replace % by f * Silence linter --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Hynek Schlawack --- .pre-commit-config.yaml | 6 +++--- docs/conf.py | 2 +- src/structlog/_native.py | 3 +-- tests/test_config.py | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a80046f5..7bf1a15f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,18 +4,18 @@ ci: repos: - repo: https://github.com/psf/black - rev: 24.3.0 + rev: 24.4.2 hooks: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.3.5 + rev: v0.4.3 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] - repo: https://github.com/econchick/interrogate - rev: 1.6.0 + rev: 1.7.0 hooks: - id: interrogate args: [tests] diff --git a/docs/conf.py b/docs/conf.py index f3ab0b3d..93eac7ff 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -90,7 +90,7 @@ html_theme = "furo" html_theme_options = { - "top_of_page_button": None, + "top_of_page_buttons": [], "light_css_variables": { "font-stack": "Inter, sans-serif", "font-stack--monospace": "BerkeleyMono, MonoLisa, ui-monospace, " diff --git a/src/structlog/_native.py b/src/structlog/_native.py index e4dbdb11..a96e6da2 100644 --- a/src/structlog/_native.py +++ b/src/structlog/_native.py @@ -210,8 +210,7 @@ async def alog( meths["amsg"] = meths["ainfo"] return type( - "BoundLoggerFilteringAt%s" - % (LEVEL_TO_NAME.get(min_level, "Notset").capitalize()), + f"BoundLoggerFilteringAt{LEVEL_TO_NAME.get(min_level, 'Notset').capitalize()}", (BoundLoggerBase,), meths, ) diff --git a/tests/test_config.py b/tests/test_config.py index c45fc0f0..cddcfd8b 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -51,7 +51,7 @@ def test_lazy_logger_is_not_detected_as_abstract_method(): See https://github.com/hynek/structlog/issues/229 """ - class Foo(metaclass=abc.ABCMeta): + class Foo(metaclass=abc.ABCMeta): # noqa: B024 log = structlog.get_logger() Foo() From fad46dec30e5be309f00041fa7c0995d02bc157a Mon Sep 17 00:00:00 2001 From: Peter Henry Date: Mon, 13 May 2024 02:53:05 -0400 Subject: [PATCH 1211/1520] Fix reference to undefined var `logger` in "Getting Started" example (#614) While following along with this "Getting Started" guide for the first time, I got sidetracked for several minutes by this `logger`. None of the example snippets earlier in this file assigned to a variable named `logger` (but they frequently assigned the result of `structlog.get_logger()` to a variable named `log`). I spent a bit poking around in the API reference to try and figure out which types define a `.bind()` method and whether they completely overlap with the types returned by `structlog.get_logger()`. Eventually I decided the specific variable name probably wasn't a super considered choice and I was overthinking things. Maybe this change could save someone time in the future. Co-authored-by: Hynek Schlawack --- docs/getting-started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 09ba20c0..86a60987 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -120,7 +120,7 @@ Let's have a look at a better approach: ```python def view(request): - log = logger.bind( + log = log.bind( user_agent=request.get("HTTP_USER_AGENT", "UNKNOWN"), peer_ip=request.client_addr, ) From 0a93f827f4bace552588b81c58c27f9c43ffe61e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 13 May 2024 09:21:56 +0200 Subject: [PATCH 1212/1520] update ruff --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7bf1a15f..6d7739a4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.4.3 + rev: v0.4.4 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From 1475ed94ffb6bb0d7dd71904fbea2898acf8f794 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 13 May 2024 17:47:24 +0200 Subject: [PATCH 1213/1520] stdlib: add callsite collection support for async methods (#618) * stdlib: add callsite collection support for async methods fixes #615 * Put change notices where people notice them --- CHANGELOG.md | 3 +++ src/structlog/stdlib.py | 20 ++++++++++++++------ tests/processors/test_processors.py | 17 ++++++++++++----- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9edf242b..645fffaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - The `structlog.processors.CallsiteParameterAdder` can now be pickled. [#603](https://github.com/hynek/structlog/pull/603) +- `structlog.processors.CallsiteParameterAdder` now also works with `structlog.stdlib.BoundLogger`'s non-standard async methods (`ainfo()`, and so forth) + [#618](https://github.com/hynek/structlog/pull/618) + ### Changed diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 27ab1f9d..ce64bd96 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -144,6 +144,10 @@ class BoundLogger(BoundLoggerBase): .. versionadded:: 23.1.0 Async variants `alog()`, `adebug()`, `ainfo()`, and so forth. + + .. versionchanged:: 24.2.0 + Callsite parameters are now also collected by + `structlog.processors.CallsiteParameterAdder` for async log methods. """ _logger: logging.Logger @@ -393,12 +397,16 @@ async def _dispatch_to_sync( """ Merge contextvars and log using the sync logger in a thread pool. """ + scs_token = _ASYNC_CALLING_STACK.set(sys._getframe().f_back.f_back) # type: ignore[union-attr, arg-type, unused-ignore] ctx = contextvars.copy_context() - await asyncio.get_running_loop().run_in_executor( - None, - lambda: ctx.run(lambda: meth(event, *args, **kw)), - ) + try: + await asyncio.get_running_loop().run_in_executor( + None, + lambda: ctx.run(lambda: meth(event, *args, **kw)), + ) + finally: + _ASYNC_CALLING_STACK.reset(scs_token) async def adebug(self, event: str, *args: Any, **kw: Any) -> None: """ @@ -499,6 +507,8 @@ class AsyncBoundLogger: .. versionchanged:: 20.2.0 fix _dispatch_to_sync contextvars usage .. deprecated:: 23.1.0 Use the regular `BoundLogger` with its a-prefixed methods instead. + .. versionchanged:: 23.3.0 + Callsite parameters are now also collected for async log methods. """ __slots__ = ("sync_bl", "_loop") @@ -594,8 +604,6 @@ async def _dispatch_to_sync( ) -> None: """ Merge contextvars and log using the sync logger in a thread pool. - .. versionchanged:: 23.3.0 - Callsite parameters are now also collected under asyncio. """ scs_token = _ASYNC_CALLING_STACK.set(sys._getframe().f_back.f_back) # type: ignore[union-attr, arg-type, unused-ignore] ctx = contextvars.copy_context() diff --git a/tests/processors/test_processors.py b/tests/processors/test_processors.py index cec06474..91443509 100644 --- a/tests/processors/test_processors.py +++ b/tests/processors/test_processors.py @@ -298,28 +298,35 @@ def test_all_parameters(self) -> None: assert self.parameter_strings == self.get_callsite_parameters().keys() @pytest.mark.asyncio() - async def test_async(self) -> None: + @pytest.mark.parametrize( + ("wrapper_class", "method_name"), + [ + (structlog.stdlib.BoundLogger, "ainfo"), + (structlog.stdlib.AsyncBoundLogger, "info"), + ], + ) + async def test_async(self, wrapper_class, method_name) -> None: """ Callsite information for async invocations are correct. """ string_io = StringIO() - class StingIOLogger(structlog.PrintLogger): + class StringIOLogger(structlog.PrintLogger): def __init__(self): super().__init__(file=string_io) processor = self.make_processor(None, ["concurrent", "threading"]) structlog.configure( processors=[processor, JSONRenderer()], - logger_factory=StingIOLogger, - wrapper_class=structlog.stdlib.AsyncBoundLogger, + logger_factory=StringIOLogger, + wrapper_class=wrapper_class, cache_logger_on_first_use=True, ) logger = structlog.stdlib.get_logger() callsite_params = self.get_callsite_parameters() - await logger.info("baz") + await getattr(logger, method_name)("baz") logger_params = json.loads(string_io.getvalue()) # These are different when running under async From 261f6c29d6a212725b1b649cac374c8ae0b6ca21 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 13 May 2024 17:48:50 +0200 Subject: [PATCH 1214/1520] Attest provenance --- .github/workflows/pypi-package.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/pypi-package.yml b/.github/workflows/pypi-package.yml index f557727f..3145bf1c 100644 --- a/.github/workflows/pypi-package.yml +++ b/.github/workflows/pypi-package.yml @@ -25,6 +25,8 @@ jobs: fetch-depth: 0 - uses: hynek/build-and-inspect-python-package@v2 + with: + attest-build-provenance-github: 'true' # Upload to Test PyPI on every commit on main. release-test-pypi: From 8f8d9751182caa12800e03b562a0528df50be8c3 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 13 May 2024 17:49:35 +0200 Subject: [PATCH 1215/1520] Add missing permission --- .github/workflows/pypi-package.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pypi-package.yml b/.github/workflows/pypi-package.yml index 3145bf1c..43093ce5 100644 --- a/.github/workflows/pypi-package.yml +++ b/.github/workflows/pypi-package.yml @@ -11,6 +11,7 @@ on: workflow_dispatch: permissions: + attestations: write contents: read id-token: write From e5ebcd978621c9382ba4ce10ea23dc9074dd5d0f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 25 May 2024 08:27:31 -0400 Subject: [PATCH 1216/1520] sponsors: add Klaviyo --- .github/sponsors/Klaviyo.svg | 6 ++++++ README.md | 1 + 2 files changed, 7 insertions(+) create mode 100644 .github/sponsors/Klaviyo.svg diff --git a/.github/sponsors/Klaviyo.svg b/.github/sponsors/Klaviyo.svg new file mode 100644 index 00000000..67125290 --- /dev/null +++ b/.github/sponsors/Klaviyo.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/README.md b/README.md index 49441583..a10fbda4 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ Especially those generously supporting us at the *The Organization* tier and hig

    +

    From 924f4c903fd494ec294e99d136f3989d4cd87069 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 25 May 2024 08:32:42 -0400 Subject: [PATCH 1217/1520] pre-commit update --- .github/CODE_OF_CONDUCT.md | 2 +- .pre-commit-config.yaml | 4 ++-- src/structlog/tracebacks.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md index 1d8ad183..348412b1 100644 --- a/.github/CODE_OF_CONDUCT.md +++ b/.github/CODE_OF_CONDUCT.md @@ -6,7 +6,7 @@ We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender -identity and expression, level of experience, education, socio-economic status, +identity and expression, level of experience, education, socioeconomic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation. diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6d7739a4..c30b706c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.4.4 + rev: v0.4.5 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] @@ -21,7 +21,7 @@ repos: args: [tests] - repo: https://github.com/codespell-project/codespell - rev: v2.2.6 + rev: v2.3.0 hooks: - id: codespell args: [-L, alog] diff --git a/src/structlog/tracebacks.py b/src/structlog/tracebacks.py index 83a40f27..d2d1221d 100644 --- a/src/structlog/tracebacks.py +++ b/src/structlog/tracebacks.py @@ -92,7 +92,7 @@ class Trace: def safe_str(_object: Any) -> str: - """Don't allow exceptions from __str__ to propegate.""" + """Don't allow exceptions from __str__ to propagate.""" try: return str(_object) except Exception as error: # noqa: BLE001 From 20c23be8d8fef60f437407f30111dc007c02f74e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 26 May 2024 21:19:43 +0200 Subject: [PATCH 1218/1520] Fix Klaviyo logo --- .github/sponsors/Klaviyo.svg | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.github/sponsors/Klaviyo.svg b/.github/sponsors/Klaviyo.svg index 67125290..6c7449bc 100644 --- a/.github/sponsors/Klaviyo.svg +++ b/.github/sponsors/Klaviyo.svg @@ -1,6 +1 @@ - - - - - - + From 592409ac7657ca3689a63a2d82777b9bbb80a241 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 27 May 2024 22:14:13 +0200 Subject: [PATCH 1219/1520] Ensure test order doesn't matter --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 53952998..ed9ec605 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,6 +41,7 @@ tests = [ "freezegun>=0.2.8", "pretend", "pytest-asyncio>=0.17", + "pytest-randomly", "pytest>=6.0", "simplejson", ] From 767ec8b9a196263bf9d8addcd4cb031433a49d4b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 27 May 2024 22:27:22 +0200 Subject: [PATCH 1220/1520] I swear it worked on my machine This reverts commit 592409ac7657ca3689a63a2d82777b9bbb80a241. --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ed9ec605..53952998 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,7 +41,6 @@ tests = [ "freezegun>=0.2.8", "pretend", "pytest-asyncio>=0.17", - "pytest-randomly", "pytest>=6.0", "simplejson", ] From b16e08f0c2989be813b666c62e633a70e59cfb42 Mon Sep 17 00:00:00 2001 From: Fraser <39111573+fraser-langton@users.noreply.github.com> Date: Tue, 28 May 2024 07:13:43 +1000 Subject: [PATCH 1221/1520] fixes bug in render_to_log_kwargs (#620) * fixes bug in render_to_log_kwargs * fix autoformatting * fix docstring * add PR link now it exists * fix docstring * Small fixes * Simplify asserts * Fix comment --------- Co-authored-by: Hynek Schlawack --- CHANGELOG.md | 6 +++ src/structlog/stdlib.py | 7 +++- tests/test_stdlib.py | 90 ++++++++++++++++++++++++++++++++++++----- 3 files changed, 92 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 645fffaf..c77e48fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,12 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ [#606](https://github.com/hynek/structlog/pull/606) +### Fixed + +- `structlog.stdlib.render_to_log_kwargs` now correctly passes stacklevel as a kwarg to stdlib logging. + [#619](https://github.com/hynek/structlog/pull/620) + + ## [24.1.0](https://github.com/hynek/structlog/compare/23.3.0...24.1.0) - 2024-01-08 diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index ce64bd96..dbb530f9 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -878,6 +878,7 @@ def render_to_log_kwargs( ) -> EventDict: """ Render ``event_dict`` into keyword arguments for `logging.log`. + See `logging.Logger`'s ``_log`` method for kwargs reference. The ``event`` field is translated into ``msg`` and the rest of the *event_dict* is added as ``extra``. @@ -886,15 +887,17 @@ def render_to_log_kwargs( .. versionadded:: 17.1.0 .. versionchanged:: 22.1.0 - ``exc_info``, ``stack_info``, and ``stackLevel`` are passed as proper + ``exc_info``, ``stack_info``, and ``stacklevel`` are passed as proper kwargs and not put into ``extra``. + .. versionchanged:: 24.2.0 + ``stackLevel`` corrected to ``stacklevel``. """ return { "msg": event_dict.pop("event"), "extra": event_dict, **{ kw: event_dict.pop(kw) - for kw in ("exc_info", "stack_info", "stackLevel") + for kw in ("exc_info", "stack_info", "stacklevel") if kw in event_dict }, } diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 1c690f1f..13a8e3b6 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -13,6 +13,7 @@ from io import StringIO from typing import Any, Callable, Collection, Dict +from unittest.mock import patch import pytest import pytest_asyncio @@ -24,6 +25,7 @@ ReturnLogger, configure, get_context, + wrap_logger, ) from structlog._config import _CONFIG from structlog._log_levels import CRITICAL, NAME_TO_LEVEL, WARN @@ -671,8 +673,18 @@ def _copy_allowed( } +@pytest.fixture(name="stdlib_logger") +def _stdlib_logger(): + logger = logging.getLogger("test_logger") + logger.setLevel(logging.DEBUG) + + yield logger + + logging.basicConfig() + + class TestRenderToLogKW: - def test_default(self): + def test_default(self, stdlib_logger): """ Translates `event` to `msg` and handles otherwise empty `event_dict`s. """ @@ -680,7 +692,13 @@ def test_default(self): assert {"msg": "message", "extra": {}} == d - def test_add_extra_event_dict(self, event_dict): + # now check stdlib logger likes those kwargs + with patch.object(stdlib_logger, "_log") as mock_log: + stdlib_logger.info(**d) + + mock_log.assert_called_once_with(logging.INFO, "message", (), extra={}) + + def test_add_extra_event_dict(self, event_dict, stdlib_logger): """ Adds all remaining data from `event_dict` into `extra`. """ @@ -689,9 +707,17 @@ def test_add_extra_event_dict(self, event_dict): assert {"msg": "message", "extra": event_dict} == d - def test_handles_special_kw(self, event_dict): + # now check stdlib logger likes those kwargs + with patch.object(stdlib_logger, "_log") as mock_log: + stdlib_logger.info(**d) + + mock_log.assert_called_once_with( + logging.INFO, "message", (), extra=event_dict + ) + + def test_handles_special_kw(self, event_dict, stdlib_logger): """ - "exc_info", "stack_info", and "stackLevel" aren't passed as extras. + "exc_info", "stack_info", and "stacklevel" aren't passed as extras. Cf. https://github.com/hynek/structlog/issues/424 """ @@ -700,22 +726,68 @@ def test_handles_special_kw(self, event_dict): event_dict["exc_info"] = True event_dict["stack_info"] = False - event_dict["stackLevel"] = 1 + event_dict["stacklevel"] = 1 + event_dict["stackLevel"] = 1 # not a reserved kw d = render_to_log_kwargs(None, None, event_dict) - - assert { + expected = { "msg": "message", "exc_info": True, "stack_info": False, - "stackLevel": 1, + "stacklevel": 1, "extra": { "b": [3, 4], "x": 7, "y": "test", "z": (1, 2), + "stackLevel": 1, }, - } == d + } + + assert expected == d + + # now check stdlib logger likes those kwargs + with patch.object(stdlib_logger, "_log") as mock_log: + stdlib_logger.info(**d) + + expected.pop("msg") + mock_log.assert_called_once_with( + logging.INFO, "message", (), **expected + ) + + def test_integration_special_kw(self, event_dict, stdlib_logger): + """ + render_to_log_kwargs with a wrapped logger calls the stdlib logger + correctly + + reserved stdlib keywords are in logging.Logger._log + https://github.com/python/cpython/blob/ae7b17673f29efe17b416cbcfbf43b5b3ff5977c/Lib/logging/__init__.py#L1632 + """ + expected = { + "msg": "message", + "exc_info": True, + "stack_info": False, + "stacklevel": 1, + "extra": {**event_dict}, + } + + event_dict["exc_info"] = True + event_dict["stack_info"] = False + event_dict["stacklevel"] = 1 + + struct_logger = wrap_logger( + stdlib_logger, + processors=[render_to_log_kwargs], + ) + + # now check struct logger passes those kwargs to stdlib + with patch.object(stdlib_logger, "_log") as mock_log: + struct_logger.info("message", **event_dict) + + expected.pop("msg") + mock_log.assert_called_once_with( + logging.INFO, "message", (), **expected + ) @pytest.fixture(name="configure_for_processor_formatter") From 78729a8ad6226eb2a2da2251b4feaf43c3eccdc9 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 27 May 2024 23:35:45 +0200 Subject: [PATCH 1222/1520] Prepare 24.2.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c77e48fa..46bc9eb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ -## [Unreleased](https://github.com/hynek/structlog/compare/24.1.0...HEAD) +## [24.2.0](https://github.com/hynek/structlog/compare/24.1.0...24.2.0) - 2024-05-27 ### Added From 812149f505d5658f14013fa5516fed8b9d201625 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 27 May 2024 23:39:36 +0200 Subject: [PATCH 1223/1520] Start new development cycle --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46bc9eb3..6def409c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ +## [Unreleased](https://github.com/hynek/structlog/compare/24.2.0...HEAD) + + ## [24.2.0](https://github.com/hynek/structlog/compare/24.1.0...24.2.0) - 2024-05-27 ### Added From 527f492fcdef65619ae1de9d4f9ec692ca64a81e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 18:02:13 -0400 Subject: [PATCH 1224/1520] [pre-commit.ci] pre-commit autoupdate (#624) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.4.5 → v0.4.7](https://github.com/astral-sh/ruff-pre-commit/compare/v0.4.5...v0.4.7) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c30b706c..28d00a13 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.4.5 + rev: v0.4.7 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From 6090ff665400201f2bfca0f72d5f3ae6e108c9a9 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 28 Jun 2024 09:53:20 +0200 Subject: [PATCH 1225/1520] Update Ruff --- .pre-commit-config.yaml | 2 +- src/structlog/dev.py | 2 +- tests/test_config.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 28d00a13..d7bac581 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.4.7 + rev: v0.5.0 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/src/structlog/dev.py b/src/structlog/dev.py index b1175cd3..5a27df66 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -73,7 +73,7 @@ def _pad(s: str, length: int) -> str: """ missing = length - len(s) - return s + " " * (missing if missing > 0 else 0) + return s + " " * (max(0, missing)) if colorama is not None: diff --git a/tests/test_config.py b/tests/test_config.py index cddcfd8b..a25388b1 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -437,7 +437,7 @@ def test_configure_once_issues_warning_on_repeated_call(self): configure_once() assert 1 == len(warns) - assert RuntimeWarning == warns[0].category + assert RuntimeWarning is warns[0].category assert "Repeated configuration attempted." == warns[0].message.args[0] def test_get_logger_configures_according_to_config(self): From e28bbfed55ee5ce5cbd777ea98b0e5287700fa00 Mon Sep 17 00:00:00 2001 From: Mounir Date: Sat, 13 Jul 2024 15:32:52 +0200 Subject: [PATCH 1226/1520] Map method name in capture_logs as well (#628) * Map method name in capture_logs as well * Added docstring * Updated changelog * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Add test case * Fix changelog * Fixes * Transplant comments --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Hynek Schlawack --- CHANGELOG.md | 5 +++++ src/structlog/_log_levels.py | 20 +++++++++++++------- src/structlog/testing.py | 7 ++++++- tests/test_testing.py | 31 +++++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6def409c..1884c3d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,11 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ## [Unreleased](https://github.com/hynek/structlog/compare/24.2.0...HEAD) +### Changed + +- `structlog.testing.capture_logs()` now maps the `exception` log level to `error` (as it's elsewhere). + [#628](https://github.com/hynek/structlog/pull/628) + ## [24.2.0](https://github.com/hynek/structlog/compare/24.1.0...24.2.0) - 2024-05-27 diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index df1e81ab..3b759f41 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -46,6 +46,18 @@ _NAME_TO_LEVEL = NAME_TO_LEVEL +def map_method_name(method_name: str) -> str: + # warn is just a deprecated alias in the stdlib. + if method_name == "warn": + return "warning" + + # Calling exception("") is the same as error("", exc_info=True) + if method_name == "exception": + return "error" + + return method_name + + def add_log_level( logger: logging.Logger, method_name: str, event_dict: EventDict ) -> EventDict: @@ -63,13 +75,7 @@ def add_log_level( .. versionchanged:: 24.1.0 Added mapping from "exception" to "error" """ - if method_name == "warn": - # The stdlib has an alias - method_name = "warning" - elif method_name == "exception": - # exception("") method is the same as error("", exc_info=True) - method_name = "error" - event_dict["level"] = method_name + event_dict["level"] = map_method_name(method_name) return event_dict diff --git a/src/structlog/testing.py b/src/structlog/testing.py index ba0c96f9..35ad87dd 100644 --- a/src/structlog/testing.py +++ b/src/structlog/testing.py @@ -17,6 +17,7 @@ from typing import Any, Generator, NamedTuple, NoReturn from ._config import configure, get_config +from ._log_levels import map_method_name from .exceptions import DropEvent from .typing import EventDict, WrappedLogger @@ -41,6 +42,10 @@ class LogCapture: :ivar List[structlog.typing.EventDict] entries: The captured log entries. .. versionadded:: 20.1.0 + + .. versionchanged:: 24.3.0 + Added mapping from "exception" to "error" + Added mapping from "warn" to "warning" """ entries: list[EventDict] @@ -51,7 +56,7 @@ def __init__(self) -> None: def __call__( self, _: WrappedLogger, method_name: str, event_dict: EventDict ) -> NoReturn: - event_dict["log_level"] = method_name + event_dict["log_level"] = map_method_name(method_name) self.entries.append(event_dict) raise DropEvent diff --git a/tests/test_testing.py b/tests/test_testing.py index 1283ddee..78d6246b 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -5,6 +5,8 @@ import pytest +import structlog + from structlog import get_config, get_logger, testing from structlog.testing import ( CapturedCall, @@ -85,6 +87,35 @@ def test_captures_bound_logers(self): } ] + def test_captures_log_level_mapping(self): + """ + exceptions and warn log levels are mapped like in regular loggers. + """ + structlog.configure( + processors=[ + structlog.stdlib.ProcessorFormatter.wrap_for_formatter, + ], + logger_factory=structlog.stdlib.LoggerFactory(), + wrapper_class=structlog.stdlib.BoundLogger, + ) + with testing.capture_logs() as logs: + get_logger().exception("hello", answer=42) + get_logger().warn("again", answer=23) + + assert [ + { + "event": "hello", + "answer": 42, + "exc_info": True, + "log_level": "error", + }, + { + "answer": 23, + "event": "again", + "log_level": "warning", + }, + ] == logs + class TestReturnLogger: # @pytest.mark.parametrize("method", stdlib_log_methods) From 3a76ee3c20c01803a5b4fe3e29d395ab02169739 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 13 Jul 2024 15:35:12 +0200 Subject: [PATCH 1227/1520] update ruff --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d7bac581..9e4668a8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.5.0 + rev: v0.5.1 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From 3c9b55b36dd9438b08f7bc2adedd22adafacaa72 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 13 Jul 2024 15:48:35 +0200 Subject: [PATCH 1228/1520] Add sections to main docs --- docs/_static/custom.css | 14 ++++++++++++-- docs/index.md | 16 +++++++++------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/docs/_static/custom.css b/docs/_static/custom.css index 72083fee..fc58887c 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -3,8 +3,18 @@ :root { - font-feature-settings: 'liga' 1, 'calt' 1; /* fix for Chrome */ + font-feature-settings: 'liga' 1, 'calt' 1; + /* fix for Chrome */ } + @supports (font-variation-settings: normal) { - :root { font-family: InterVariable, sans-serif; } + :root { + font-family: InterVariable, sans-serif; + } } + + +/* Hide ToC caption text within the main body (but leave them in the side-bar). */ +#furo-main-content span.caption-text { + display: none; +} \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index 2aa44a02..2b536058 100644 --- a/docs/index.md +++ b/docs/index.md @@ -32,6 +32,7 @@ If anything seems confusing, don't hesitate to have a look at our {doc}`glossary ```{toctree} :maxdepth: 2 +:caption: Basics getting-started bound-loggers @@ -48,6 +49,8 @@ exceptions ```{toctree} :maxdepth: 2 +:caption: Development Affordances + console-output testing typing @@ -63,6 +66,7 @@ Dedicated support for the standard library and Twisted is shipped out-of-the-box ```{toctree} :maxdepth: 2 +:caption: Integrations frameworks standard-library @@ -77,6 +81,7 @@ The following chapters deal with considerations of using *structlog* in the real ```{toctree} :maxdepth: 2 +:caption: In Practice recipes logging-best-practices @@ -88,9 +93,12 @@ performance ```{toctree} :maxdepth: 2 +:caption: Reference api glossary +genindex +modindex ``` @@ -98,18 +106,12 @@ glossary ```{toctree} :maxdepth: 1 +:caption: Deprecated Features thread-local ``` -## Indices and tables - -- {any}`genindex` -- {any}`modindex` -- {any}`glossary` - - ```{toctree} :hidden: :caption: Meta From 2759bb93c72d654493a3f261d9800b7b19e54ce6 Mon Sep 17 00:00:00 2001 From: Stefan Scherfke Date: Tue, 16 Jul 2024 14:47:15 +0200 Subject: [PATCH 1229/1520] Improve dict traceback (#627) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Improve dict traceback Port new features from Rich‘s traceback to make the structlog ones comparable again. * Add and fix tests * Fix docs and test coverage * Fix inaccuarcy in docs * Add versionadded info to changed API * Add changelog entry * Revert "assert result == expected" changes * Add "use_rich" argument * Update tests/test_tracebacks.py --------- Co-authored-by: Hynek Schlawack --- CHANGELOG.md | 14 ++- docs/api.rst | 2 +- docs/conf.py | 1 + src/structlog/tracebacks.py | 208 ++++++++++++++++++++++++++++++++---- tests/test_tracebacks.py | 159 ++++++++++++++++++++++----- 5 files changed, 337 insertions(+), 47 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1884c3d1..f6a3a58e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,12 +15,24 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ## [Unreleased](https://github.com/hynek/structlog/compare/24.2.0...HEAD) +### Added + +- Restore feature parity between `structlog.traceback.ExceptionDictTransformer` and Rich's traceback extractor: + + - When displaying locals, use Rich for formatting if it is available. + - When displaying locals, call `repr()` on strings, too (improves handling of `SecretStr` implementations). + - Add `locals_max_length` config option + - Add `locals_hide_sunder` config option + - Add `locals_hide_dunder` config option + - Add `suppress` config option + + [#627](https://github.com/hynek/structlog/pull/627) + ### Changed - `structlog.testing.capture_logs()` now maps the `exception` log level to `error` (as it's elsewhere). [#628](https://github.com/hynek/structlog/pull/628) - ## [24.2.0](https://github.com/hynek/structlog/compare/24.1.0...24.2.0) - 2024-05-27 ### Added diff --git a/docs/api.rst b/docs/api.rst index e027738d..99acb1cb 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -197,7 +197,7 @@ API Reference ... 1 / 0 ... except ZeroDivisionError: ... log.exception("Cannot compute!") - {"event": "Cannot compute!", "exception": [{"exc_type": "ZeroDivisionError", "exc_value": "division by zero", "syntax_error": null, "is_cause": false, "frames": [{"filename": "", "lineno": 2, "name": "", "line": "", "locals": {..., "var": "spam"}}]}]} + {"event": "Cannot compute!", "exception": [{"exc_type": "ZeroDivisionError", "exc_value": "division by zero", "syntax_error": null, "is_cause": false, "frames": [{"filename": "", "lineno": 2, "name": "", "locals": {..., "var": "'spam'"}}]}]} .. autoclass:: KeyValueRenderer diff --git a/docs/conf.py b/docs/conf.py index 93eac7ff..d95868f8 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -77,6 +77,7 @@ ("py:class", "WrappedLogger"), ("py:class", "structlog.threadlocal.TLLogger"), ("py:class", "structlog.typing.EventDict"), + ("py:class", "ModuleType"), ] # If true, '()' will be appended to :func: etc. cross-reference text. diff --git a/src/structlog/tracebacks.py b/src/structlog/tracebacks.py index d2d1221d..2331b2fa 100644 --- a/src/structlog/tracebacks.py +++ b/src/structlog/tracebacks.py @@ -6,7 +6,7 @@ """ Extract a structured traceback from an exception. -`Contributed by Will McGugan +Based on work by Will McGugan `_ from `rich.traceback `_. @@ -15,11 +15,19 @@ from __future__ import annotations import os +import os.path from dataclasses import asdict, dataclass, field from traceback import walk_tb -from types import TracebackType -from typing import Any, Tuple, Union +from types import ModuleType, TracebackType +from typing import Any, Iterable, Sequence, Tuple, Union + + +try: + import rich + import rich.pretty +except ImportError: + rich = None # type: ignore[assignment] from .typing import ExcInfo @@ -37,6 +45,7 @@ SHOW_LOCALS = True +LOCALS_MAX_LENGTH = 10 LOCALS_MAX_STRING = 80 MAX_FRAMES = 50 @@ -52,7 +61,6 @@ class Frame: filename: str lineno: int name: str - line: str = "" locals: dict[str, str] | None = None @@ -99,20 +107,65 @@ def safe_str(_object: Any) -> str: return f"" -def to_repr(obj: Any, max_string: int | None = None) -> str: - """Get repr string for an object, but catch errors.""" - if isinstance(obj, str): - obj_repr = obj +def to_repr( + obj: Any, + max_length: int | None = None, + max_string: int | None = None, + use_rich: bool = True, +) -> str: + """ + Get repr string for an object, but catch errors. + + :func:`repr()` is used for strings, too, so that secret wrappers that + inherit from :func:`str` and overwrite ``__repr__()`` are handled correctly + (i.e. secrets are not logged in plain text). + + Args: + obj: Object to get a string representation for. + + max_length: Maximum length of containers before abbreviating, or + ``None`` for no abbreviation. + + max_string: Maximum length of string before truncating, or ``None`` to + disable truncating. + + use_rich: If ``True`` (the default), use rich_ to compute the repr. + If ``False`` or if rich_ is not installed, fall back to a simpler + algorithm. + + Returns: + The string representation of *obj*. + + .. versionchanged:: 24.3.0 + Added *max_length* argument. Use :program:`rich` to render locals if it + is available. Call :func:`repr()` on strings in fallback + implementation. + """ + if use_rich and rich is not None: + # Let rich render the repr if it is available. + # It produces much better results for containers and dataclasses/attrs. + obj_repr = rich.pretty.traverse( + obj, max_length=max_length, max_string=max_string + ).render() else: + # Generate a (truncated) repr if rich is not available. + # Handle str/bytes differently to get better results for truncated + # representations. Also catch all errors, similarly to "safe_str()". try: - obj_repr = repr(obj) + if isinstance(obj, (str, bytes)): + if max_string is not None and len(obj) > max_string: + truncated = len(obj) - max_string + obj_repr = f"{obj[:max_string]!r}+{truncated}" + else: + obj_repr = repr(obj) + else: + obj_repr = repr(obj) + if max_string is not None and len(obj_repr) > max_string: + truncated = len(obj_repr) - max_string + obj_repr = f"{obj_repr[:max_string]!r}+{truncated}" except Exception as error: # noqa: BLE001 obj_repr = f"" - if max_string is not None and len(obj_repr) > max_string: - truncated = len(obj_repr) - max_string - obj_repr = f"{obj_repr[:max_string]!r}+{truncated}" - return obj_repr @@ -122,7 +175,11 @@ def extract( traceback: TracebackType | None, *, show_locals: bool = False, + locals_max_length: int = LOCALS_MAX_LENGTH, locals_max_string: int = LOCALS_MAX_STRING, + locals_hide_dunder: bool = True, + locals_hide_sunder: bool = False, + use_rich: bool = True, ) -> Trace: """ Extract traceback information. @@ -136,15 +193,34 @@ def extract( show_locals: Enable display of local variables. Defaults to False. + locals_max_length: + Maximum length of containers before abbreviating, or ``None`` for + no abbreviation. + locals_max_string: - Maximum length of string before truncating, or ``None`` to disable. + Maximum length of string before truncating, or ``None`` to disable + truncating. + + locals_hide_dunder: + Hide locals prefixed with double underscore. + Defaults to True. - max_frames: Maximum number of frames in each stack + locals_hide_sunder: + Hide locals prefixed with single underscore. + This implies hiding *locals_hide_dunder*. + Defaults to False. + + use_rich: If ``True`` (the default), use rich_ to compute the repr. + If ``False`` or if rich_ is not installed, fall back to a simpler + algorithm. Returns: A Trace instance with structured information about all exceptions. .. versionadded:: 22.1.0 + .. versionchanged:: 24.3.0 + Added *locals_max_length*, *locals_hide_sunder*, *locals_hide_dunder* + and *use_rich* arguments. """ stacks: list[Stack] = [] @@ -169,18 +245,43 @@ def extract( stacks.append(stack) append = stack.frames.append # pylint: disable=no-member + def get_locals( + iter_locals: Iterable[tuple[str, object]], + ) -> Iterable[tuple[str, object]]: + """Extract locals from an iterator of key pairs.""" + if not (locals_hide_dunder or locals_hide_sunder): + yield from iter_locals + return + for key, value in iter_locals: + if locals_hide_dunder and key.startswith("__"): + continue + if locals_hide_sunder and key.startswith("_"): + continue + yield key, value + for frame_summary, line_no in walk_tb(traceback): filename = frame_summary.f_code.co_filename if filename and not filename.startswith("<"): filename = os.path.abspath(filename) + # Rich has this, but we are not rich and like to keep all frames: + # if frame_summary.f_locals.get("_rich_traceback_omit", False): + # continue # noqa: ERA001 + frame = Frame( filename=filename or "?", lineno=line_no, name=frame_summary.f_code.co_name, locals=( { - key: to_repr(value, max_string=locals_max_string) - for key, value in frame_summary.f_locals.items() + key: to_repr( + value, + max_length=locals_max_length, + max_string=locals_max_string, + use_rich=use_rich, + ) + for key, value in get_locals( + frame_summary.f_locals.items() + ) } if show_locals else None @@ -226,9 +327,26 @@ class ExceptionDictTransformer: Whether or not to include the values of a stack frame's local variables. + locals_max_length: + Maximum length of containers before abbreviating, or ``None`` for + no abbreviation. + locals_max_string: - The maximum length after which long string representations are - truncated. + Maximum length of string before truncating, or ``None`` to disable + truncating. + + locals_hide_dunder: + Hide locals prefixed with double underscore. + Defaults to True. + + locals_hide_sunder: + Hide locals prefixed with single underscore. + This implies hiding *locals_hide_dunder*. + Defaults to False. + + suppress: + Optional sequence of modules or paths for which to suppress the + display of locals even if *show_locals* is ``True``. max_frames: Maximum number of frames in each stack. Frames are removed from @@ -237,17 +355,34 @@ class ExceptionDictTransformer: the exception actually happened. With larger web frameworks, this does not always work, so you should stick with the default. + use_rich: If ``True`` (the default), use rich_ to compute the repr of + locals. If ``False`` or if rich_ is not installed, fall back to + a simpler algorithm. + .. seealso:: :doc:`exceptions` for a broader explanation of *structlog*'s exception features. + + .. versionchanged:: 24.3.0 + Added *locals_max_length*, *locals_hide_sunder*, *locals_hide_dunder*, + *suppress* and *use_rich* arguments. """ def __init__( self, - show_locals: bool = True, + *, + show_locals: bool = SHOW_LOCALS, + locals_max_length: int = LOCALS_MAX_LENGTH, locals_max_string: int = LOCALS_MAX_STRING, + locals_hide_dunder: bool = True, + locals_hide_sunder: bool = False, + suppress: Iterable[str | ModuleType] = (), max_frames: int = MAX_FRAMES, + use_rich: bool = True, ) -> None: + if locals_max_length < 0: + msg = f'"locals_max_length" must be >= 0: {locals_max_length}' + raise ValueError(msg) if locals_max_string < 0: msg = f'"locals_max_string" must be >= 0: {locals_max_string}' raise ValueError(msg) @@ -255,14 +390,36 @@ def __init__( msg = f'"max_frames" must be >= 2: {max_frames}' raise ValueError(msg) self.show_locals = show_locals + self.locals_max_length = locals_max_length self.locals_max_string = locals_max_string + self.locals_hide_dunder = locals_hide_dunder + self.locals_hide_sunder = locals_hide_sunder + self.suppress: Sequence[str] = [] + for suppress_entity in suppress: + if not isinstance(suppress_entity, str): + if suppress_entity.__file__ is None: + msg = ( + f'"suppress" item {suppress_entity!r} must be a ' + f"module with '__file__' attribute" + ) + raise ValueError(msg) + path = os.path.dirname(suppress_entity.__file__) + else: + path = suppress_entity + path = os.path.normpath(os.path.abspath(path)) + self.suppress.append(path) self.max_frames = max_frames + self.use_rich = use_rich def __call__(self, exc_info: ExcInfo) -> list[dict[str, Any]]: trace = extract( *exc_info, show_locals=self.show_locals, + locals_max_length=self.locals_max_length, locals_max_string=self.locals_max_string, + locals_hide_dunder=self.locals_hide_dunder, + locals_hide_sunder=self.locals_hide_sunder, + use_rich=self.use_rich, ) for stack in trace.stacks: @@ -283,4 +440,13 @@ def __call__(self, exc_info: ExcInfo) -> list[dict[str, Any]]: *stack.frames[-half:], ] - return [asdict(stack) for stack in trace.stacks] + stacks = [asdict(stack) for stack in trace.stacks] + for stack_dict in stacks: + for frame_dict in stack_dict["frames"]: + if frame_dict["locals"] is None or any( + frame_dict["filename"].startswith(path) + for path in self.suppress + ): + del frame_dict["locals"] + + return stacks diff --git a/tests/test_tracebacks.py b/tests/test_tracebacks.py index a41175cb..2de04776 100644 --- a/tests/test_tracebacks.py +++ b/tests/test_tracebacks.py @@ -6,9 +6,11 @@ from __future__ import annotations import inspect +import json import sys from pathlib import Path +from types import ModuleType from typing import Any import pytest @@ -16,6 +18,20 @@ from structlog import tracebacks +class SecretStr(str): # noqa: SLOT000 + """ + Secrets representation as used in Typed Settings or Pydantic. + """ + + def __repr__(self) -> str: + return "*******" + + +@pytest.fixture(autouse=True) +def _unimport_rich(monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setattr(tracebacks, "rich", None) + + def get_next_lineno() -> int: return inspect.currentframe().f_back.f_lineno + 1 @@ -47,21 +63,59 @@ def __str__(self) -> str: ("data", "max_len", "expected"), [ (3, None, "3"), - ("spam", None, "spam"), + ("spam", None, "'spam'"), (b"spam", None, "b'spam'"), ("bacon", 3, "'bac'+2"), ("bacon", 4, "'baco'+1"), - ("bacon", 5, "bacon"), + ("bacon", 5, "'bacon'"), + (SecretStr("password"), None, "*******"), + (["spam", "eggs", "bacon"], 10, "\"['spam', '\"+15"), ], ) -def test_to_repr(data: Any, max_len: int | None, expected: str): +def test_to_repr(data: Any, max_len: int | None, expected: str) -> None: """ "to_repr()" returns the repr of an object, trimmed to max_len. """ assert expected == tracebacks.to_repr(data, max_string=max_len) -def test_to_repr_error(): +@pytest.mark.parametrize( + ("use_rich", "data", "max_len", "expected"), + [ + (True, 3, None, "3"), + (True, "spam", None, "'spam'"), + (True, b"spam", None, "b'spam'"), + (True, "bacon", 3, "'bac'+2"), + (True, "bacon", 5, "'bacon'"), + (True, SecretStr("password"), None, "*******"), + (True, ["spam", "eggs", "bacon"], 4, "['spam', 'eggs', 'baco'+1]"), + (False, "bacon", 3, "'bac'+2"), + (False, ["spam", "eggs", "bacon"], 4, '"[\'sp"+21'), + ], +) +def test_to_repr_rich( + use_rich: bool, + data: Any, + max_len: int | None, + expected: str, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """ + "to_repr()" uses Rich to get a nice repr if it is installed and if + "use_rich" is True. + """ + try: + import rich + except ImportError: + pytest.skip(reason="rich not installed") + + monkeypatch.setattr(tracebacks, "rich", rich) + assert expected == tracebacks.to_repr( + data, max_string=max_len, use_rich=use_rich + ) + + +def test_to_repr_error() -> None: """ "to_repr()" does not fail if __repr__() raises an exception. """ @@ -97,7 +151,6 @@ def test_simple_exception(): filename=__file__, lineno=lineno, name="test_simple_exception", - line="", locals=None, ), ], @@ -130,7 +183,6 @@ def test_raise_hide_cause(): filename=__file__, lineno=lineno, name="test_raise_hide_cause", - line="", locals=None, ), ], @@ -164,7 +216,6 @@ def test_raise_with_cause(): filename=__file__, lineno=lineno_2, name="test_raise_with_cause", - line="", locals=None, ), ], @@ -179,7 +230,6 @@ def test_raise_with_cause(): filename=__file__, lineno=lineno_1, name="test_raise_with_cause", - line="", locals=None, ), ], @@ -208,7 +258,6 @@ def test_raise_with_cause_no_tb(): filename=__file__, lineno=lineno, name="test_raise_with_cause_no_tb", - line="", locals=None, ), ], @@ -242,7 +291,6 @@ def test_raise_nested(): filename=__file__, lineno=lineno_2, name="test_raise_nested", - line="", locals=None, ), ], @@ -257,7 +305,6 @@ def test_raise_nested(): filename=__file__, lineno=lineno_1, name="test_raise_nested", - line="", locals=None, ), ], @@ -287,7 +334,6 @@ def test_raise_no_msg(): filename=__file__, lineno=lineno, name="test_raise_no_msg", - line="", locals=None, ), ], @@ -323,8 +369,6 @@ def test_syntax_error(): filename=__file__, lineno=lineno, name="test_syntax_error", - line="", - locals=None, ), ], ), @@ -352,14 +396,12 @@ def test_filename_with_bracket(): filename=__file__, lineno=lineno, name="test_filename_with_bracket", - line="", locals=None, ), tracebacks.Frame( filename="", lineno=1, name="", - line="", locals=None, ), ], @@ -388,14 +430,12 @@ def test_filename_not_a_file(): filename=__file__, lineno=lineno, name="test_filename_not_a_file", - line="", locals=None, ), tracebacks.Frame( filename=str(Path.cwd().joinpath("string")), lineno=1, name="", - line="", locals=None, ), ], @@ -509,9 +549,7 @@ def test_json_traceback(): "frames": [ { "filename": __file__, - "line": "", "lineno": lineno, - "locals": None, "name": "test_json_traceback", } ], @@ -540,7 +578,6 @@ def test_json_traceback_locals_max_string(): "frames": [ { "filename": __file__, - "line": "", "lineno": lineno, "locals": { "_var": "'spam'+8", @@ -594,28 +631,102 @@ def bacon(): if skipped_count: assert trace["frames"][skipped_idx] == { "filename": "", - "line": "", "lineno": -1, - "locals": None, "name": f"Skipped frames: {skipped_count}", } else: assert not any(f["lineno"] == -1 for f in trace["frames"]) +@pytest.mark.parametrize( + ("suppress", "file_no_locals"), + [ + pytest.param((__file__,), __file__, id="file"), + pytest.param((json,), json.__file__, id="json"), + ], +) +def test_json_tracebacks_suppress( + suppress: tuple[str | ModuleType, ...], + file_no_locals: str, + capsys: pytest.CaptureFixture, +) -> None: + """ + Console and JSON output look as expected + + This means also warnings are logged correctly. + """ + try: + try: + json.loads(42) # type: ignore[arg-type] + except Exception as e: + raise ValueError("error shown to users") from e + except ValueError as e: + format_json = tracebacks.ExceptionDictTransformer( + show_locals=True, suppress=suppress + ) + result = format_json((type(e), e, e.__traceback__)) + for stack in result: + for frame in stack["frames"]: + no_locals = frame["filename"] == file_no_locals + if no_locals: + assert "locals" not in frame + else: + assert "locals" in frame + + +@pytest.mark.parametrize( + ("hide_sunder", "hide_dunder", "expected"), + [ + (False, False, {"_spam", "__eggs"}), + (True, False, set()), # Also hides "__eggs", b/c it starts with "_"! + (False, True, {"_spam"}), + (True, True, set()), + ], +) +def test_json_tracebacks_skip_sunder_dunder( + hide_sunder: bool, hide_dunder: bool, expected: set[str] +) -> None: + """ + Local variables starting with "_" or "__" can be hidden from the locals + dict. + """ + + def func() -> None: + _spam = True + __eggs = 3 + 1 / 0 + + try: + func() + except ZeroDivisionError as e: + format_json = tracebacks.ExceptionDictTransformer( + show_locals=True, + locals_hide_sunder=hide_sunder, + locals_hide_dunder=hide_dunder, + ) + result = format_json((type(e), e, e.__traceback__)) + assert expected == set(result[0]["frames"][1]["locals"]) + + @pytest.mark.parametrize( "kwargs", [ + {"locals_max_length": -1}, {"locals_max_string": -1}, {"max_frames": -1}, {"max_frames": 0}, {"max_frames": 1}, + {"suppress": (json,)}, ], ) -def test_json_traceback_value_error(kwargs): +def test_json_traceback_value_error( + kwargs: dict[str, Any], monkeypatch: pytest.MonkeyPatch +) -> None: """ Wrong arguments to ExceptionDictTransformer raise a ValueError that contains the name of the argument.. """ + if "suppress" in kwargs: + monkeypatch.setattr(kwargs["suppress"][0], "__file__", None) with pytest.raises(ValueError, match=next(iter(kwargs.keys()))): tracebacks.ExceptionDictTransformer(**kwargs) From da99c5c594b59cc10b478e991a4b277c24b8c5c0 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 16 Jul 2024 14:49:09 +0200 Subject: [PATCH 1230/1520] upgrade ruff --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9e4668a8..b2ce24f0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.5.1 + rev: v0.5.2 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From 15b18f6f7d64cd95908540dd058f0bff1d5080b2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 16 Jul 2024 14:49:52 +0200 Subject: [PATCH 1231/1520] docs: consistency --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6a3a58e..da4e84ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,11 +28,13 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ [#627](https://github.com/hynek/structlog/pull/627) + ### Changed - `structlog.testing.capture_logs()` now maps the `exception` log level to `error` (as it's elsewhere). [#628](https://github.com/hynek/structlog/pull/628) + ## [24.2.0](https://github.com/hynek/structlog/compare/24.1.0...24.2.0) - 2024-05-27 ### Added From a186fcbc23066550dd402952a28e5abd4cfeaf56 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 16 Jul 2024 16:09:37 +0200 Subject: [PATCH 1232/1520] Start serving sponsor logos from respective web locations (#629) --- README.md | 8 ++++---- {.github => docs/_static}/sponsors/FilePreviews.svg | 0 {.github => docs/_static}/sponsors/Klaviyo.svg | 0 {.github => docs/_static}/sponsors/Sentry.svg | 0 {.github => docs/_static}/sponsors/Tidelift.svg | 0 {.github => docs/_static}/sponsors/Variomedia.svg | 0 pyproject.toml | 6 ++++++ 7 files changed, 10 insertions(+), 4 deletions(-) rename {.github => docs/_static}/sponsors/FilePreviews.svg (100%) rename {.github => docs/_static}/sponsors/Klaviyo.svg (100%) rename {.github => docs/_static}/sponsors/Sentry.svg (100%) rename {.github => docs/_static}/sponsors/Tidelift.svg (100%) rename {.github => docs/_static}/sponsors/Variomedia.svg (100%) diff --git a/README.md b/README.md index a10fbda4..89729a75 100644 --- a/README.md +++ b/README.md @@ -40,10 +40,10 @@ The output format is just as flexible and *structlog* comes with support for JSO Especially those generously supporting us at the *The Organization* tier and higher:

    - - - - + + + +

    diff --git a/.github/sponsors/FilePreviews.svg b/docs/_static/sponsors/FilePreviews.svg similarity index 100% rename from .github/sponsors/FilePreviews.svg rename to docs/_static/sponsors/FilePreviews.svg diff --git a/.github/sponsors/Klaviyo.svg b/docs/_static/sponsors/Klaviyo.svg similarity index 100% rename from .github/sponsors/Klaviyo.svg rename to docs/_static/sponsors/Klaviyo.svg diff --git a/.github/sponsors/Sentry.svg b/docs/_static/sponsors/Sentry.svg similarity index 100% rename from .github/sponsors/Sentry.svg rename to docs/_static/sponsors/Sentry.svg diff --git a/.github/sponsors/Tidelift.svg b/docs/_static/sponsors/Tidelift.svg similarity index 100% rename from .github/sponsors/Tidelift.svg rename to docs/_static/sponsors/Tidelift.svg diff --git a/.github/sponsors/Variomedia.svg b/docs/_static/sponsors/Variomedia.svg similarity index 100% rename from .github/sponsors/Variomedia.svg rename to docs/_static/sponsors/Variomedia.svg diff --git a/pyproject.toml b/pyproject.toml index 53952998..1e8135e6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -233,6 +233,12 @@ text = """ """ +# Change sponsor URLs from GitHub to the docs. +[[tool.hatch.metadata.hooks.fancy-pypi-readme.substitutions]] +pattern = 'docs/_static/sponsors' +replacement = '/en/$HFPR_VERSION/sponsors' + + [[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]] path = "README.md" start-at = "## Credits" From 35f484e30a52660ed63ef4f99f1674ba7a9f93bc Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 16 Jul 2024 16:14:31 +0200 Subject: [PATCH 1233/1520] Revert "Start serving sponsor logos from respective web locations (#629)" This reverts commit a186fcbc23066550dd402952a28e5abd4cfeaf56. --- {docs/_static => .github}/sponsors/FilePreviews.svg | 0 {docs/_static => .github}/sponsors/Klaviyo.svg | 0 {docs/_static => .github}/sponsors/Sentry.svg | 0 {docs/_static => .github}/sponsors/Tidelift.svg | 0 {docs/_static => .github}/sponsors/Variomedia.svg | 0 README.md | 8 ++++---- pyproject.toml | 6 ------ 7 files changed, 4 insertions(+), 10 deletions(-) rename {docs/_static => .github}/sponsors/FilePreviews.svg (100%) rename {docs/_static => .github}/sponsors/Klaviyo.svg (100%) rename {docs/_static => .github}/sponsors/Sentry.svg (100%) rename {docs/_static => .github}/sponsors/Tidelift.svg (100%) rename {docs/_static => .github}/sponsors/Variomedia.svg (100%) diff --git a/docs/_static/sponsors/FilePreviews.svg b/.github/sponsors/FilePreviews.svg similarity index 100% rename from docs/_static/sponsors/FilePreviews.svg rename to .github/sponsors/FilePreviews.svg diff --git a/docs/_static/sponsors/Klaviyo.svg b/.github/sponsors/Klaviyo.svg similarity index 100% rename from docs/_static/sponsors/Klaviyo.svg rename to .github/sponsors/Klaviyo.svg diff --git a/docs/_static/sponsors/Sentry.svg b/.github/sponsors/Sentry.svg similarity index 100% rename from docs/_static/sponsors/Sentry.svg rename to .github/sponsors/Sentry.svg diff --git a/docs/_static/sponsors/Tidelift.svg b/.github/sponsors/Tidelift.svg similarity index 100% rename from docs/_static/sponsors/Tidelift.svg rename to .github/sponsors/Tidelift.svg diff --git a/docs/_static/sponsors/Variomedia.svg b/.github/sponsors/Variomedia.svg similarity index 100% rename from docs/_static/sponsors/Variomedia.svg rename to .github/sponsors/Variomedia.svg diff --git a/README.md b/README.md index 89729a75..a10fbda4 100644 --- a/README.md +++ b/README.md @@ -40,10 +40,10 @@ The output format is just as flexible and *structlog* comes with support for JSO Especially those generously supporting us at the *The Organization* tier and higher:

    - - - - + + + +

    diff --git a/pyproject.toml b/pyproject.toml index 1e8135e6..53952998 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -233,12 +233,6 @@ text = """ """ -# Change sponsor URLs from GitHub to the docs. -[[tool.hatch.metadata.hooks.fancy-pypi-readme.substitutions]] -pattern = 'docs/_static/sponsors' -replacement = '/en/$HFPR_VERSION/sponsors' - - [[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]] path = "README.md" start-at = "## Credits" From af74f85a0cd20cf61712bed3d646089066891340 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 17 Jul 2024 11:30:20 +0200 Subject: [PATCH 1234/1520] Cog to the rescue! (#630) We need very different URLs in Sphinx and in README so let's use Cog to build the lists dynamically. --- README.md | 25 +++++++++++++++--- .../_static}/sponsors/FilePreviews.svg | 0 .../_static}/sponsors/Klaviyo.svg | 0 {.github => docs/_static}/sponsors/Sentry.svg | 0 .../_static}/sponsors/Tidelift.svg | 0 .../_static}/sponsors/Variomedia.svg | 0 docs/index.md | 22 +++++++++++++++- pyproject.toml | 26 +++++++++++++++++++ tox.ini | 7 ++++- 9 files changed, 74 insertions(+), 6 deletions(-) rename {.github => docs/_static}/sponsors/FilePreviews.svg (100%) rename {.github => docs/_static}/sponsors/Klaviyo.svg (100%) rename {.github => docs/_static}/sponsors/Sentry.svg (100%) rename {.github => docs/_static}/sponsors/Tidelift.svg (100%) rename {.github => docs/_static}/sponsors/Variomedia.svg (100%) diff --git a/README.md b/README.md index a10fbda4..9119d131 100644 --- a/README.md +++ b/README.md @@ -39,11 +39,28 @@ The output format is just as flexible and *structlog* comes with support for JSO *structlog* would not be possible without our [amazing sponsors](https://github.com/sponsors/hynek). Especially those generously supporting us at the *The Organization* tier and higher: + + +

    + + + + + + +

    + +

    - - - - + + + +

    diff --git a/.github/sponsors/FilePreviews.svg b/docs/_static/sponsors/FilePreviews.svg similarity index 100% rename from .github/sponsors/FilePreviews.svg rename to docs/_static/sponsors/FilePreviews.svg diff --git a/.github/sponsors/Klaviyo.svg b/docs/_static/sponsors/Klaviyo.svg similarity index 100% rename from .github/sponsors/Klaviyo.svg rename to docs/_static/sponsors/Klaviyo.svg diff --git a/.github/sponsors/Sentry.svg b/docs/_static/sponsors/Sentry.svg similarity index 100% rename from .github/sponsors/Sentry.svg rename to docs/_static/sponsors/Sentry.svg diff --git a/.github/sponsors/Tidelift.svg b/docs/_static/sponsors/Tidelift.svg similarity index 100% rename from .github/sponsors/Tidelift.svg rename to docs/_static/sponsors/Tidelift.svg diff --git a/.github/sponsors/Variomedia.svg b/docs/_static/sponsors/Variomedia.svg similarity index 100% rename from .github/sponsors/Variomedia.svg rename to docs/_static/sponsors/Variomedia.svg diff --git a/docs/index.md b/docs/index.md index 2b536058..4c48be91 100644 --- a/docs/index.md +++ b/docs/index.md @@ -8,9 +8,29 @@ Release **{sub-ref}`release`** ([What's new?](https://github.com/hynek/structlo ```{include} ../README.md :start-after: -:end-before: +:end-before: ``` +{sub-ref} + + + + + + + +```{include} ../README.md +:start-after: +:end-before: +``` If you’d like more information on why structured logging in general – and *structlog* in particular – are good ideas, we’ve prepared a [summary](why.md) just for you. diff --git a/pyproject.toml b/pyproject.toml index 53952998..ec8b885f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -237,3 +237,29 @@ text = """ path = "README.md" start-at = "## Credits" end-before = "" + +# Point sponsor image URLs to versions. +[[tool.hatch.metadata.hooks.fancy-pypi-readme.substitutions]] +pattern = 'docs\/_static\/sponsors' +replacement = '/en/$HFPR_VERSION/_static/sponsors' + + +[[tool.sponcon.sponsors]] +title = "Variomedia AG" +url = "https://www.variomedia.de/" +img = "Variomedia.svg" + +[[tool.sponcon.sponsors]] +title = "Tidelift" +url = "https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek" +img = "Tidelift.svg" + +[[tool.sponcon.sponsors]] +title = "Klaviyo" +url = "https://klaviyo.com/" +img = "Klaviyo.svg" + +[[tool.sponcon.sponsors]] +title = "FilePreviews" +url = "https://filepreviews.io/" +img = "FilePreviews.svg" diff --git a/tox.ini b/tox.ini index 8365d3a2..9290b66d 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,7 @@ env_list = mypy-pkg, py3{8,9,10,11,12}-{tests,mypy} py3{8,11}-tests-{colorama,be,rich}, - docs, + docs{,-sponsors}, coverage-report @@ -72,6 +72,11 @@ base_python = {[testenv:docs]base_python} extras = {[testenv:docs]extras} commands = sphinx-build -W -b linkcheck -d {envtmpdir}/doctrees docs docs/_build/html +[testenv:docs-sponsors] +description = Ensure sponsor logos are up to date. +deps = cogapp +commands = cog -rP README.md docs/index.md + [testenv:pre-commit] skip_install = true From f47afe055b083cd82109ae77a6d8dff43ed09bfa Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 17 Jul 2024 12:32:43 +0200 Subject: [PATCH 1235/1520] docs: update contributing --- .github/CONTRIBUTING.md | 201 +++++++++++++++++++--------------------- 1 file changed, 95 insertions(+), 106 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 2f519f82..9cfc69b9 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,14 +1,8 @@ # How To Contribute -Thank you for considering contributing to *structlog*! -It's people like *you* who make it such a great tool for everyone. - -This document intends to make contribution more accessible by codifying tribal knowledge and expectations. -Don't be afraid to open half-finished PRs, and ask questions if something is unclear! - -Please note that this project is released with a Contributor [Code of Conduct](https://github.com/hynek/structlog/blob/main/.github/CODE_OF_CONDUCT.md). -By participating in this project you agree to abide by its terms. -Please report any harm to [Hynek Schlawack] in any way you find appropriate. +> [!IMPORTANT] +> This document is mainly to help you to get started by codifying tribal knowledge and expectations and make it more accessible to everyone. +> But don't be afraid to open half-finished PRs and ask questions if something is unclear! ## Support @@ -21,31 +15,43 @@ The official tag is `structlog` and helping out in support frees us up to improv ## Workflow +First off, thank you for considering to contribute! +It's people like *you* who make this project such a great tool for everyone. + - No contribution is too small! Please submit as many fixes for typos and grammar bloopers as you can! + - Try to limit each pull request to *one* change only. + - Since we squash on merge, it's up to you how you handle updates to the `main` branch. Whether you prefer to rebase on `main` or merge `main` into your branch, do whatever is more comfortable for you. + - *Always* add tests and docs for your code. This is a hard rule; patches with missing tests or documentation won't be merged. -- Make sure your changes pass our [CI]. + +- Consider updating [`CHANGELOG.md`](../CHANGELOG.md) to reflect the changes as observed by people using this library. + +- Make sure your changes pass our [CI](https://github.com/hynek/structlog/actions). You won't get any feedback until it's green unless you ask for it. For the CI to pass, the coverage must be 100%. If you have problems to test something, open anyway and ask for advice. In some situations, we may agree to add an `# pragma: no cover`. + - Once you've addressed review feedback, make sure to bump the pull request with a short note, so we know you're done. -- Don’t break backwards-compatibility. + +- Don't break [backwards-compatibility](SECURITY.md). ## Local Development Environment -You can (and should) run our test suite using [*tox*]. -However, you’ll probably want a more traditional environment as well. +First, **fork** the repository on GitHub and **clone** it using one of the alternatives that you can copy-paste by pressing the big green button labeled `<> Code`. -First, create a [virtual environment](https://virtualenv.pypa.io/) so you don't break your system-wide Python installation. -We recommend using the Python version from the `.python-version-default` file in project's root directory. +You can (and should) run our test suite using [*tox*](https://tox.wiki/). +However, you'll probably want a more traditional environment as well. -If you're using [*direnv*](https://direnv.net), you can automate the creation of a virtual environment with the correct Python version by adding the following `.envrc` to the project root: +We recommend using the Python version from the `.python-version-default` file in the project's root directory, because that's the one that is used in the CI by default, too. + +If you're using [*direnv*](https://direnv.net), you can automate the creation of the project virtual environment with the correct Python version by adding the following `.envrc` to the project root: ```bash layout python python$(cat .python-version-default) @@ -58,38 +64,25 @@ test -d .venv || uv venv --python python$(cat .python-version-default) . .venv/bin/activate ``` ---- - -[Create a fork](https://github.com/hynek/structlog/fork) of the *structlog* repository and clone it: - -```console -$ git clone git@github.com:YOU/structlog.git -``` - -Or if you prefer to use Git via HTTPS: - -```console -$ git clone https://github.com/YOU/structlog.git -``` - > [!WARNING] > - **Before** you start working on a new pull request, use the "*Sync fork*" button in GitHub's web UI to ensure your fork is up to date. > - **Always create a new branch off `main` for each new pull request.** > Yes, you can work on `main` in your fork and submit pull requests. > But this will *inevitably* lead to you not being able to synchronize your fork with upstream and having to start over. -Change into the newly created directory and after activating a virtual environment, install an editable version of *structlog* along with its tests requirements: +Change into the newly created directory and after activating a virtual environment, install an editable version of this project along with its tests requirements: ```console -$ cd structlog -$ python -Im pip install --upgrade pip wheel # PLEASE don't skip this step -$ python -Im pip install -e '.[dev]' +$ pip install -e .[dev] # or `uv pip install -e .[dev]` ``` -At this point, +This will also install *tox* for you. +If you use *uv* and want to make the *tox* runs faster, you can also additionally install the [*tox-uv*](https://github.com/tox-dev/tox-uv) plugin using `uv pip install tox-uv`. + +Now you can run the test suite: ```console -$ python -m pytest +$ python -Im pytest ``` When working on the documentation, use: @@ -98,65 +91,53 @@ When working on the documentation, use: $ tox run -e docs-watch ``` -... to watch your files and automatically rebuild when a file changes. -And use: - -```console -$ tox run -e docs -``` - -... to build it once and run our doctests. - -The built documentation can then be found in `docs/_build/html/`. +This will build the documentation, watch for changes, and rebuild it whenever you save a file. ---- - -To avoid committing code that violates our style guide, we strongly advise you to install [*pre-commit*] and its hooks: +To just build the documentation and run doctests, use: ```console -$ pre-commit install -``` - -This is not strictly necessary, because our [*tox*] file contains an environment that runs: - -```console -$ pre-commit run --all-files +$ tox run -e docs ``` -and our CI has integration with [pre-commit.ci](https://pre-commit.ci). -But it's way more comfortable to run it locally and catch avoidable errors before pushing them to GitHub. +You will find the built documentation in `docs/_build/html`. ## Code -- Obey [PEP 8](https://www.python.org/dev/peps/pep-0008/) and [PEP 257](https://www.python.org/dev/peps/pep-0257/). +- Obey [PEP 8](https://peps.python.org/pep-0008/) and [PEP 257](https://peps.python.org/pep-0257/). We use the `"""`-on-separate-lines style for docstrings with [Napoleon](https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html)-style API documentation: ```python - def func(x: str) -> str: + def func(x: str, y: int) -> str: """ Do something. Args: - x: A very important parameter. + x: A very important argument. y: - Another important parameter but one that doesn't fit a line so - it already starts on the next one. + Another very important argument, but its description is so long + that it doesn't fit on one line. So, we start the whole block on a + fresh new line to keep the block together. Returns: - A very important return value. + The result of doing something. """ ``` -- If you add or change public APIs, tag the docstring using `.. versionadded:: 16.0.0 WHAT` or `.. versionchanged:: 16.2.0 WHAT`. -- We use [Ruff](https://ruff.rs/) to sort our imports, and we use [Black](https://github.com/psf/black) with line length of 79 characters to format our code. - As long as you run our full [*tox*] suite before committing, or install our [*pre-commit*] hooks (ideally you'll do both – see [*Local Development Environment*](#local-development-environment) above), you won't have to spend any time on formatting your code at all. - If you don't, [CI] will catch it for you – but that seems like a waste of your time! + + Please note that unlike everything else, the API docstrings are still reStructuredText. + +- If you add or change public APIs, tag the docstring using `.. versionadded:: 24.1.0 WHAT` or `.. versionchanged:: 24.1.0 WHAT`. + We follow CalVer, so the next version will be the current with with the middle number incremented (for example, `24.1.0` -> `24.2.0`). + +- We use [Ruff](https://ruff.rs/) to sort our imports, and we follow the [Black](https://github.com/psf/black) code style with a line length of 79 characters. + As long as you run our full *tox* suite before committing, or install our [*pre-commit*](https://pre-commit.com/) hooks (ideally you'll do both – see [*Local Development Environment*](#local-development-environment) above), you won't have to spend any time on formatting your code at all. + If you don't, CI will catch it for you -- but that seems like a waste of your time! ## Tests -- Write your asserts as `expected == actual` to line them up nicely: +- Write your asserts as `expected == actual` to line them up nicely, and leave an empty line before them: ```python x = f() @@ -165,29 +146,27 @@ But it's way more comfortable to run it locally and catch avoidable errors befor assert "foo" == x._a_private_attribute ``` -- To run the test suite, all you need is a recent [*tox*]. - It will ensure the test suite runs with all dependencies against all Python versions just as it will in our [CI]. - If you lack some Python versions, you can always limit the environments like `tox -e py38,py39`, or make it a non-failure using `tox --skip-missing-interpreters`. +- You can run the test suite runs with all (optional) dependencies against all Python versions just as it will in our CI by running `tox`. - In that case you should look into [*asdf*](https://asdf-vm.com) or [*pyenv*](https://github.com/pyenv/pyenv), which make it very easy to install many different Python versions in parallel. -- Write [good test docstrings](https://jml.io/pages/test-docstrings.html). -- If you've changed or added public APIs, please update our type stubs (files ending in `.pyi`). +- Write [good test docstrings](https://jml.io/test-docstrings/). ## Documentation -- We use [Markdown] everywhere except in `docs/api.rst` and docstrings. - -- Use [semantic newlines] in [reStructuredText] and [Markdown] files (files ending in `.rst` and `.md`): +- Use [semantic newlines] in [reStructuredText](https://www.sphinx-doc.org/en/stable/usage/restructuredtext/basics.html) (`*.rst`) and [Markdown](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax) (`*.md`) files: ```markdown This is a sentence. This is another sentence. + + This is a new paragraph. ``` -- If you start a new section, add two blank lines before and one blank line after the header, except if two headers follow immediately after each other: +- If you start a new section, add two blank lines before and one blank line after the header except if two headers follow immediately after each other: ```markdown + # Main Header + Last line of previous section. @@ -201,48 +180,58 @@ But it's way more comfortable to run it locally and catch avoidable errors befor ### Changelog -If your change is noteworthy, there needs to be a changelog entry in [`CHANGELOG.md`](https://github.com/hynek/structlog/blob/main/CHANGELOG.md), so our users can learn about it! +If your change is interesting to end-users, there needs to be an entry in our `CHANGELOG.md`, so they can learn about it. -- The changelog follows the [*Keep a Changelog*](https://keepachangelog.com/en/1.0.0/) standard. - Please add the best-fitting section if it's missing for the current release. +- The changelog follows the [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) standard. + Add the best-fitting section if it's missing for the current release. We use the following order: `Security`, `Removed`, `Deprecated`, `Added`, `Changed`, `Fixed`. + - As with other docs, please use [semantic newlines] in the changelog. + - Make the last line a link to your pull request. You probably have to open it first to know the number. -- Wrap symbols like modules, functions, or classes into backticks so they are rendered in a `monospace font`. -- Wrap arguments into asterisks like in docstrings: + +- Leave an empty line between entries, so it doesn't look like a wall of text. + +- Refer to all symbols by their fully-qualified names. + For example, `structlog.Foo` -- not just `Foo`. + +- Wrap symbols like modules, functions, or classes into backticks, so they are rendered in a `monospace font`. + +- Wrap arguments into asterisks so they are *italicized* like in API documentation: `Added new argument *an_argument*.` -- If you mention functions or other callables, add parentheses at the end of their names: + +- If you mention functions or methods, add parentheses at the end of their names: `structlog.func()` or `structlog.Class.method()`. This makes the changelog a lot more readable. + - Prefer simple past tense or constructions with "now". - For example: + In the `Added` section, you can leave out the "Added" prefix: + + ```markdown + ### Added - * Added `structlog.func()`. - * `structlog.func()` now doesn't crash the Large Hadron Collider anymore when passed the *foobar* argument. + - `structlog.func()` that does foo. + It's pretty cool. + [#1](https://github.com/hynek/structlog/pull/1) -#### Example entries + ### Fixed -```markdown -- Added `structlog.func()`. - The feature really *is* awesome. - [#1](https://github.com/hynek/structlog/pull/1) -``` + - `structlog.func()` now doesn't crash the Large Hadron Collider anymore. + That was a nasty bug! + [#2](https://github.com/hynek/structlog/pull/2) + ``` -or: -```markdown -- `structlog.func()` now doesn't crash the Large Hadron Collider anymore when passed the *foobar* argument. - The bug really *was* nasty. - [#1](https://github.com/hynek/structlog/pull/1) -``` +## See You on GitHub! + +Again, this whole file is mainly to help you to get started by codifying tribal knowledge and expectations to save you time and turnarounds. +It is **not** meant to be a barrier to entry, so don't be afraid to open half-finished PRs and ask questions if something is unclear! + +Please note that this project is released with a Contributor [Code of Conduct](CODE_OF_CONDUCT.md). +By participating in this project you agree to abide by its terms. +Please report any harm to [Hynek Schlawack](https://hynek.me/about/) in any way you find appropriate. -[CI]: https://github.com/hynek/structlog/actions -[Hynek Schlawack]: https://hynek.me/about/ -[*pre-commit*]: https://pre-commit.com/ -[*tox*]: https://tox.wiki/ [semantic newlines]: https://rhodesmill.org/brandon/2012/one-sentence-per-line/ -[reStructuredText]: https://www.sphinx-doc.org/en/stable/usage/restructuredtext/basics.html -[Markdown]: https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax From 9c743124459762fd3af75878a16bf05c4634f698 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 17 Jul 2024 12:39:04 +0200 Subject: [PATCH 1236/1520] docs: polish --- .github/CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 9cfc69b9..75c16f38 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -131,7 +131,7 @@ You will find the built documentation in `docs/_build/html`. We follow CalVer, so the next version will be the current with with the middle number incremented (for example, `24.1.0` -> `24.2.0`). - We use [Ruff](https://ruff.rs/) to sort our imports, and we follow the [Black](https://github.com/psf/black) code style with a line length of 79 characters. - As long as you run our full *tox* suite before committing, or install our [*pre-commit*](https://pre-commit.com/) hooks (ideally you'll do both – see [*Local Development Environment*](#local-development-environment) above), you won't have to spend any time on formatting your code at all. + As long as you run our full *tox* suite before committing, or install our [*pre-commit*](https://pre-commit.com/) hooks (ideally you'll do both -- see [*Local Development Environment*](#local-development-environment) above), you won't have to spend any time on formatting your code at all. If you don't, CI will catch it for you -- but that seems like a waste of your time! @@ -146,7 +146,7 @@ You will find the built documentation in `docs/_build/html`. assert "foo" == x._a_private_attribute ``` -- You can run the test suite runs with all (optional) dependencies against all Python versions just as it will in our CI by running `tox`. +- You can run the test suite runs with all (optional) dependencies against all supported Python versions just as it will in our CI by running `tox`. - Write [good test docstrings](https://jml.io/test-docstrings/). From 6b1f912d03f5907a5e28d4794ec24abb380a51c3 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 17 Jul 2024 12:40:41 +0200 Subject: [PATCH 1237/1520] docs: remove blooper --- docs/index.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 4c48be91..b9b700c1 100644 --- a/docs/index.md +++ b/docs/index.md @@ -11,7 +11,6 @@ Release **{sub-ref}`release`** ([What's new?](https://github.com/hynek/structlo :end-before: ``` -{sub-ref}

    - -

    - - - - -

    -

    Please consider joining them to help make structlog’s maintenance more sustainable!

    From c9b7d062a0d512ac9a6dd19b677cef2f28bc13e6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 17 Jul 2024 12:51:41 +0200 Subject: [PATCH 1239/1520] docs: try adding empty lines (#631) * docs: try adding empty lines * More empty lines * Try removing some again --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index b00de941..f39889fb 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ Especially those generously supporting us at the *The Organization* tier and hig

    + +

    From 4699e092b592d9f7af9cdd7d4031d6650fd9b78b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 17 Jul 2024 13:03:32 +0200 Subject: [PATCH 1240/1520] docs: fix links --- docs/frameworks.md | 2 +- docs/logging-best-practices.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/frameworks.md b/docs/frameworks.md index a0a997eb..59fc6c92 100644 --- a/docs/frameworks.md +++ b/docs/frameworks.md @@ -74,7 +74,7 @@ request_started.connect(bind_request_details, app) ## OpenTelemetry -The [Python OpenTelemetry SDK](https://opentelemetry.io/docs/instrumentation/python/) offers an easy API to get the current span, so you can enrich your logs with a straight-forward processor: +The [Python OpenTelemetry SDK](https://opentelemetry.io/docs/languages/python/) offers an easy API to get the current span, so you can enrich your logs with a straight-forward processor: ```python from opentelemetry import trace diff --git a/docs/logging-best-practices.md b/docs/logging-best-practices.md index 39e5b1a2..f018a9f6 100644 --- a/docs/logging-best-practices.md +++ b/docs/logging-best-practices.md @@ -82,9 +82,9 @@ All you have to do is to tell [Logstash] either that your log entries are prepen ### Graylog -[Graylog](https://www.graylog.org/) goes one step further. +[Graylog](https://graylog.org/) goes one step further. It not only supports everything those above do (and then some); you can also directly log JSON entries towards it -- optionally even through an AMQP server (like [RabbitMQ](https://www.rabbitmq.com/)) for better reliability. -Additionally, [Graylog's Extended Log Format](https://docs.graylog.org/docs/gelf) (GELF) allows for structured data which makes it an obvious choice to use together with *structlog*. +Additionally, [Graylog's Extended Log Format](https://go2docs.graylog.org/current/getting_in_log_data/gelf.html) (GELF) allows for structured data which makes it an obvious choice to use together with *structlog*. [elasticsearch]: https://www.elastic.co/elasticsearch From 320e61a79cc47c089363f6f18ff5c5b5cd375278 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 17 Jul 2024 13:04:42 +0200 Subject: [PATCH 1241/1520] Prepare 24.3.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index da4e84ce..00b73e4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ -## [Unreleased](https://github.com/hynek/structlog/compare/24.2.0...HEAD) +## [24.3.0](https://github.com/hynek/structlog/compare/24.2.0...24.3.0) - 2024-07-17 ### Added From 81b1d4409e3a0e637663c4e0c1250a1617afa0c7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 17 Jul 2024 13:07:23 +0200 Subject: [PATCH 1242/1520] Start new development cycle --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 00b73e4f..dc413396 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ +## [Unreleased](https://github.com/hynek/structlog/compare/24.3.0...HEAD) + + ## [24.3.0](https://github.com/hynek/structlog/compare/24.2.0...24.3.0) - 2024-07-17 ### Added From d4ea660b90408ad8b76541231d23f4543aa4044a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 17 Jul 2024 13:35:16 +0200 Subject: [PATCH 1243/1520] Improve RTD and run Cog on docs build (#632) --- .readthedocs.yaml | 5 ++++- docs/conf.py | 9 +++++++++ docs/index.md | 2 ++ pyproject.toml | 1 + 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 7b669cdc..0258b66b 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -2,10 +2,13 @@ version: 2 build: - os: ubuntu-22.04 + os: ubuntu-lts-latest tools: # Keep version in sync with tox.ini/docs and ci.yml/docs python: "3.12" + jobs: + pre_build: + - cog -rP docs/index.md python: install: diff --git a/docs/conf.py b/docs/conf.py index d95868f8..fc28d61a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -3,9 +3,18 @@ # 2.0, and the MIT License. See the LICENSE file in the root of this # repository for complete details. +import os + from importlib import metadata +# Set canonical URL from the Read the Docs Domain +html_baseurl = os.environ.get("READTHEDOCS_CANONICAL_URL", "") + +# Tell Jinja2 templates the build is running on Read the Docs +if os.environ.get("READTHEDOCS", "") == "True": + html_context = {"READTHEDOCS": True} + # We want an image in the README and include the README in the docs. suppress_warnings = ["image.nonlocal_uri"] diff --git a/docs/index.md b/docs/index.md index b9b700c1..e48b5848 100644 --- a/docs/index.md +++ b/docs/index.md @@ -12,6 +12,8 @@ Release **{sub-ref}`release`** ([What's new?](https://github.com/hynek/structlo ``` " # Point sponsor image URLs to versions. [[tool.hatch.metadata.hooks.fancy-pypi-readme.substitutions]] pattern = 'docs\/_static\/sponsors' -replacement = '/en/$HFPR_VERSION/_static/sponsors' +replacement = 'https://www.structlog.org/en/$HFPR_VERSION/_static/sponsors' [[tool.sponcon.sponsors]] From 42fca8c440d4460a9665acd72e0a5a1b9888c3ca Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 17 Jul 2024 14:32:10 +0200 Subject: [PATCH 1246/1520] Prepare 24.4.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 717a8ca9..ecb4927c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ -## [Unreleased](https://github.com/hynek/structlog/compare/24.3.0...HEAD) +## [24.4.0](https://github.com/hynek/structlog/compare/24.3.0...24.4.0) - 2024-07-17 ### Changed From 91b47a2fcedff479cf612b0093c049055f0fa9ed Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 17 Jul 2024 14:35:37 +0200 Subject: [PATCH 1247/1520] Start new development cycle --- CHANGELOG.md | 3 +++ pyproject.toml | 1 + tox.ini | 4 ++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ecb4927c..cdbbc45b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ +## [Unreleased](https://github.com/hynek/structlog/compare/24.4.0...HEAD) + + ## [24.4.0](https://github.com/hynek/structlog/compare/24.3.0...24.4.0) - 2024-07-17 ### Changed diff --git a/pyproject.toml b/pyproject.toml index 936c6f10..694d1135 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,6 +22,7 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Topic :: System :: Logging", "Typing :: Typed", ] diff --git a/tox.ini b/tox.ini index 9290b66d..005f8b1e 100644 --- a/tox.ini +++ b/tox.ini @@ -3,8 +3,8 @@ min_version = 4 env_list = pre-commit, mypy-pkg, - py3{8,9,10,11,12}-{tests,mypy} - py3{8,11}-tests-{colorama,be,rich}, + py3{8,9,10,11,12,13}-{tests,mypy} + py3{8,12}-tests-{colorama,be,rich}, docs{,-sponsors}, coverage-report From 0761c1522240c56b398450ab98e8ee5dd8a7385a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 17 Jul 2024 15:34:42 +0200 Subject: [PATCH 1248/1520] docs: fix mistake It does not, in fact, install tox. --- .github/CONTRIBUTING.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 75c16f38..0a41d33d 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -76,9 +76,6 @@ Change into the newly created directory and after activating a virtual environme $ pip install -e .[dev] # or `uv pip install -e .[dev]` ``` -This will also install *tox* for you. -If you use *uv* and want to make the *tox* runs faster, you can also additionally install the [*tox-uv*](https://github.com/tox-dev/tox-uv) plugin using `uv pip install tox-uv`. - Now you can run the test suite: ```console From 71db6e9085fc9b24ef8bcd8a3ff1580e2594cc22 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 19 Jul 2024 11:26:56 +0200 Subject: [PATCH 1249/1520] update Ruff --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b2ce24f0..68fb6529 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.5.2 + rev: v0.5.3 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From e48a553979b00ab580d8ab0e55b5cf96e752a324 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 19 Jul 2024 11:27:50 +0200 Subject: [PATCH 1250/1520] Shrink logos on docs page to fit, use relative paths to simplify --- docs/index.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/docs/index.md b/docs/index.md index e48b5848..4fbcd6f6 100644 --- a/docs/index.md +++ b/docs/index.md @@ -14,13 +14,10 @@ Release **{sub-ref}`release`** ([What's new?](https://github.com/hynek/structlo From e1d6b015aad6f397658d8e0f27b61219ffb78e8d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 25 Jul 2024 09:00:29 +0200 Subject: [PATCH 1251/1520] docs --- .github/CONTRIBUTING.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 0a41d33d..b5aec0b3 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -26,13 +26,16 @@ It's people like *you* who make this project such a great tool for everyone. - Since we squash on merge, it's up to you how you handle updates to the `main` branch. Whether you prefer to rebase on `main` or merge `main` into your branch, do whatever is more comfortable for you. + Just remember to [not use your own `main` branch for the pull request](https://hynek.me/articles/pull-requests-branch/). + - *Always* add tests and docs for your code. This is a hard rule; patches with missing tests or documentation won't be merged. -- Consider updating [`CHANGELOG.md`](../CHANGELOG.md) to reflect the changes as observed by people using this library. +- Consider updating [`CHANGELOG.md`](../CHANGELOG.md) to reflect the changes as observed by people *using* this library. - Make sure your changes pass our [CI](https://github.com/hynek/structlog/actions). You won't get any feedback until it's green unless you ask for it. + For the CI to pass, the coverage must be 100%. If you have problems to test something, open anyway and ask for advice. In some situations, we may agree to add an `# pragma: no cover`. @@ -122,7 +125,7 @@ You will find the built documentation in `docs/_build/html`. """ ``` - Please note that unlike everything else, the API docstrings are still reStructuredText. + Please note that the API docstrings are still reStructuredText. - If you add or change public APIs, tag the docstring using `.. versionadded:: 24.1.0 WHAT` or `.. versionchanged:: 24.1.0 WHAT`. We follow CalVer, so the next version will be the current with with the middle number incremented (for example, `24.1.0` -> `24.2.0`). @@ -143,7 +146,7 @@ You will find the built documentation in `docs/_build/html`. assert "foo" == x._a_private_attribute ``` -- You can run the test suite runs with all (optional) dependencies against all supported Python versions just as it will in our CI by running `tox`. +- You can run the test suite runs with all (optional) dependencies against all supported Python versions -- just as it will in our CI -- by running `tox`. - Write [good test docstrings](https://jml.io/test-docstrings/). From 59561f4eb298c62c5d188cfa549d7e0222a77641 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 25 Jul 2024 09:00:44 +0200 Subject: [PATCH 1252/1520] update ruff --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 68fb6529..6a2cd0ad 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.5.3 + rev: v0.5.4 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From ea89b7506289dcb73c046d2b2f6b55af67efb6dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tin=20Tvrtkovi=C4=87?= Date: Fri, 26 Jul 2024 05:59:50 +0200 Subject: [PATCH 1253/1520] Tweak `add_log_level` type (#636) --- src/structlog/_log_levels.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index 3b759f41..52d93c58 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -9,7 +9,7 @@ from __future__ import annotations -import logging +from typing import Any from .typing import EventDict @@ -59,7 +59,7 @@ def map_method_name(method_name: str) -> str: def add_log_level( - logger: logging.Logger, method_name: str, event_dict: EventDict + logger: Any, method_name: str, event_dict: EventDict ) -> EventDict: """ Add the log level to the event dict under the ``level`` key. From 777fcccf07d4fc8fa64570f800ffef551165e3f4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 26 Jul 2024 06:33:20 +0200 Subject: [PATCH 1254/1520] Use tox for sponsors handling --- .readthedocs.yaml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 6d72724a..8ba33e0f 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -4,16 +4,17 @@ version: 2 build: os: ubuntu-lts-latest tools: - # Keep version in sync with tox.ini/docs and ci.yml/docs + # Keep version in sync with tox.ini/docs and ci.yml/docs. python: "3.12" jobs: - # Need the tags to calculate the version + # Need the tags to calculate the version. post_checkout: - git fetch --tags - # Replace versions in sponsor URLs + # Replace versions in sponsor URLs. pre_build: - - cog -rP docs/index.md + - python -Im pip install tox-uv + - python -Im tox run -e docs-sponsors python: install: From 12e7a98d6759f04fe42393a33b30ec15982bc696 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 26 Jul 2024 06:33:37 +0200 Subject: [PATCH 1255/1520] update Ruff --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6a2cd0ad..9068dd0a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.5.4 + rev: v0.5.5 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From ddf90cd9b3cfecd0204178847bbf2eeed0edb339 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 26 Jul 2024 15:21:21 +0200 Subject: [PATCH 1256/1520] Use setup-cached-uv (#637) --- .github/workflows/ci.yml | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a59cf634..b44ed586 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,8 +50,8 @@ jobs: with: python-version: ${{ matrix.python-version }} allow-prereleases: true - cache: pip - - run: python -Im pip install tox-uv + - uses: hynek/setup-cached-uv@v2 + - run: uv pip install --system tox-uv - run: python -Im tox run --installpkg dist/*.whl -f py$(echo ${{ matrix.python-version }} | tr -d .) @@ -72,8 +72,8 @@ jobs: - uses: actions/setup-python@v5 with: python-version-file: .python-version-default - cache: pip - - run: python -Im pip install --upgrade coverage[toml] + - uses: hynek/setup-cached-uv@v2 + - run: uv pip install --system --upgrade coverage[toml] - uses: actions/download-artifact@v4 with: pattern: coverage-data-* @@ -113,8 +113,8 @@ jobs: with: python-version-file: .python-version-default allow-prereleases: true - cache: pip - - run: python -Im pip install tox-uv + - uses: hynek/setup-cached-uv@v2 + - run: uv pip install --system tox-uv - run: python -Im tox run --installpkg dist/*.whl -e mypy-pkg @@ -134,8 +134,8 @@ jobs: with: python-version-file: .python-version-default allow-prereleases: true - cache: pip - - run: python -Im pip install tox-uv + - uses: hynek/setup-cached-uv@v2 + - run: uv pip install --system tox-uv - run: python -Im tox run --installpkg dist/*.whl -e pyright @@ -154,8 +154,8 @@ jobs: with: # Keep in sync with tox.ini/docs & .readthedocs.yaml python-version: "3.12" - cache: pip - - run: python -Im pip install tox-uv + - uses: hynek/setup-cached-uv@v2 + - run: uv pip install --system tox-uv - run: python -Im tox run -e docs @@ -171,9 +171,8 @@ jobs: - uses: actions/setup-python@v5 with: python-version-file: .python-version-default - cache: pip + - uses: hynek/setup-cached-uv@v2 - - run: python -Im pip install uv - run: uv venv - run: uv pip install -e .[dev] @@ -211,8 +210,7 @@ jobs: - uses: actions/setup-python@v5 with: python-version-file: .python-version-default - cache: pip - # tox 4.12.0 started passing FORCE_COLOR and NO_COLOR by default. - - run: python -Im pip install 'tox>=4.12.0' tox-uv + - uses: hynek/setup-cached-uv@v2 + - run: uv pip install --system tox-uv - run: python -Im tox run -f color From a8dd4d2e0333a7d418e824bb1c572ccf85694a20 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 1 Aug 2024 17:27:27 +0200 Subject: [PATCH 1257/1520] Semantic --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f39889fb..c566808b 100644 --- a/README.md +++ b/README.md @@ -112,4 +112,6 @@ The logs-loving beaver logo has been contributed by [Lynn Root](https://www.rogu Available as part of the Tidelift Subscription. -The maintainers of *structlog* and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. [Learn more.](https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek) +The maintainers of *structlog* and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. +Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. +[Learn more.](https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek) From 87ac2babbd193b3836c5d32c9fa81510c28b82e0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 5 Aug 2024 19:44:18 +0200 Subject: [PATCH 1258/1520] [pre-commit.ci] pre-commit autoupdate (#639) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/psf/black: 24.4.2 → 24.8.0](https://github.com/psf/black/compare/24.4.2...24.8.0) - [github.com/astral-sh/ruff-pre-commit: v0.5.5 → v0.5.6](https://github.com/astral-sh/ruff-pre-commit/compare/v0.5.5...v0.5.6) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9068dd0a..e3fe811e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,12 +4,12 @@ ci: repos: - repo: https://github.com/psf/black - rev: 24.4.2 + rev: 24.8.0 hooks: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.5.5 + rev: v0.5.6 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From c2371c6ba6bc242d02f434edabe268d3ca602e61 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 16 Aug 2024 06:52:15 +0200 Subject: [PATCH 1259/1520] update Ruff --- .pre-commit-config.yaml | 2 +- pyproject.toml | 1 - tests/processors/test_processors.py | 4 ++-- tests/test_frames.py | 2 +- tests/test_stdlib.py | 14 +++++++------- tests/test_twisted.py | 2 +- 6 files changed, 12 insertions(+), 13 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e3fe811e..9d0ef8cf 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.5.6 + rev: v0.6.0 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/pyproject.toml b/pyproject.toml index 694d1135..d9a3cc92 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -161,7 +161,6 @@ ignore = [ "EM", # tests have different rules around exceptions "LOG001", # need to instantiate log messages in tests "PLC1901", # empty strings are falsey, but are less specific in tests - "PT005", # we always add underscores and explicit name "RUF012", # no type hints in tests "S", # it's test; chill out security "SIM300", # Yoda rocks in tests diff --git a/tests/processors/test_processors.py b/tests/processors/test_processors.py index 91443509..09ea0e99 100644 --- a/tests/processors/test_processors.py +++ b/tests/processors/test_processors.py @@ -204,7 +204,7 @@ def test_exception_on_py3(self, sio): assert "XXX" in sio.getvalue() -@pytest.fixture() +@pytest.fixture def sir(): return StackInfoRenderer() @@ -297,7 +297,7 @@ def test_all_parameters(self) -> None: } assert self.parameter_strings == self.get_callsite_parameters().keys() - @pytest.mark.asyncio() + @pytest.mark.asyncio @pytest.mark.parametrize( ("wrapper_class", "method_name"), [ diff --git a/tests/test_frames.py b/tests/test_frames.py index 7eb1128d..19aa2933 100644 --- a/tests/test_frames.py +++ b/tests/test_frames.py @@ -84,7 +84,7 @@ def test_tolerates_f_back_is_None(self): assert (f1, "?") == (f, n) -@pytest.fixture() +@pytest.fixture def exc_info(): """ Fake a valid exc_info. diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 13a8e3b6..e79050f9 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -1309,14 +1309,14 @@ def test_sync_bl(self, abl, cl): CapturedCall(method_name="info", args=(), kwargs={"event": "test"}) ] == cl.calls - @pytest.mark.asyncio() + @pytest.mark.asyncio async def test_protocol(self, abl): """ AsyncBoundLogger is a proper BindableLogger. """ assert isinstance(abl, BindableLogger) - @pytest.mark.asyncio() + @pytest.mark.asyncio async def test_correct_levels(self, abl, cl, stdlib_log_method): """ The proxy methods call the correct upstream methods. @@ -1330,7 +1330,7 @@ async def test_correct_levels(self, abl, cl, stdlib_log_method): assert expect == cl.calls[0].method_name - @pytest.mark.asyncio() + @pytest.mark.asyncio async def test_log_method(self, abl, cl): """ The `log` method is proxied too. @@ -1339,7 +1339,7 @@ async def test_log_method(self, abl, cl): assert "error" == cl.calls[0].method_name - @pytest.mark.asyncio() + @pytest.mark.asyncio async def test_exception(self, abl, cl): """ `exception` makes sure 'exc_info" is set, if it's not set already. @@ -1354,7 +1354,7 @@ async def test_exception(self, abl, cl): assert ValueError is ei[0] assert ("omg",) == ei[1].args - @pytest.mark.asyncio() + @pytest.mark.asyncio async def test_exception_do_not_overwrite(self, abl, cl): """ `exception` leaves exc_info be, if it's set. @@ -1371,7 +1371,7 @@ async def test_exception_do_not_overwrite(self, abl, cl): ei = cl.calls[0].kwargs["exc_info"] assert (o1, o2, o3) == ei - @pytest.mark.asyncio() + @pytest.mark.asyncio async def test_bind_unbind(self, cl): """ new/bind/unbind/try_unbind are correctly propagated. @@ -1402,7 +1402,7 @@ async def test_bind_unbind(self, cl): assert {} == l5._context assert l4 is not l5 - @pytest.mark.asyncio() + @pytest.mark.asyncio async def test_integration(self, capsys): """ Configure and log an actual entry. diff --git a/tests/test_twisted.py b/tests/test_twisted.py index 902f430c..24c31b0b 100644 --- a/tests/test_twisted.py +++ b/tests/test_twisted.py @@ -227,7 +227,7 @@ def test_catchesConflictingEventAnd_why(self): la(None, "err", {"event": "someEvent", "_why": "someReason"}) -@pytest.fixture() +@pytest.fixture def jr(): """ A plain Twisted JSONRenderer. From 370582fef8dd3cf61380890d727cc75b37a87cb4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 16 Aug 2024 07:01:41 +0200 Subject: [PATCH 1260/1520] Make sponsors fit on PyPI --- README.md | 10 +++++----- docs/index.md | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index c566808b..340167dc 100644 --- a/README.md +++ b/README.md @@ -47,12 +47,12 @@ Especially those generously supporting us at the *The Organization* tier and hig import pathlib, tomllib for sponsor in tomllib.loads(pathlib.Path("pyproject.toml").read_text())["tool"]["sponcon"]["sponsors"]: - print(f'') + print(f'') ]]] --> - - - - + + + +

    diff --git a/docs/index.md b/docs/index.md index 4fbcd6f6..58f8b350 100644 --- a/docs/index.md +++ b/docs/index.md @@ -17,12 +17,12 @@ Release **{sub-ref}`release`** ([What's new?](https://github.com/hynek/structlo import pathlib, tomllib for sponsor in tomllib.loads(pathlib.Path("pyproject.toml").read_text())["tool"]["sponcon"]["sponsors"]: - print(f'') + print(f'') ]]] --> - - - - + + + + ```{include} ../README.md @@ -63,7 +63,7 @@ exceptions ## Development Affordances -*structlog*'s focus is production systems, but it comes with **pretty console logging** and handy in-development helpers both for your **comfort** and your code's **quality**. +*structlog*'s focus is on production systems, but it comes with **pretty console logging** and handy in-development helpers both for your **comfort** and your code's **quality**. ```{toctree} :maxdepth: 2 From 2ddebdc9ee852307d0d15c847a1f2b1d5738f0f2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 24 Aug 2024 08:14:53 +0200 Subject: [PATCH 1261/1520] update ruff --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9d0ef8cf..33a82228 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.6.0 + rev: v0.6.2 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From 6c14e51f93d525f07f4a05d9a55f5bd1fcdf1dc4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 24 Aug 2024 08:15:12 +0200 Subject: [PATCH 1262/1520] Better reproducibility Ref: https://github.com/python-attrs/attrs/pull/1338 --- .git_archival.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/.git_archival.txt b/.git_archival.txt index 8fb235d7..7c510094 100644 --- a/.git_archival.txt +++ b/.git_archival.txt @@ -1,4 +1,3 @@ node: $Format:%H$ node-date: $Format:%cI$ describe-name: $Format:%(describe:tags=true,match=*[0-9]*)$ -ref-names: $Format:%D$ From 561806468c7ec6eddabe090fabb69e50b914cd2e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 25 Aug 2024 08:16:01 +0200 Subject: [PATCH 1263/1520] Pet peeve --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 340167dc..b849c462 100644 --- a/README.md +++ b/README.md @@ -114,4 +114,4 @@ Available as part of the Tidelift Subscription. The maintainers of *structlog* and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. -[Learn more.](https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek) +[Learn more](https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek). From 485ca19617bde31e288386edc0e49d70096885bd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 25 Aug 2024 08:17:33 +0200 Subject: [PATCH 1264/1520] docs: this is better still --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index b849c462..ee620296 100644 --- a/README.md +++ b/README.md @@ -110,8 +110,7 @@ The logs-loving beaver logo has been contributed by [Lynn Root](https://www.rogu ## *structlog* for Enterprise -Available as part of the Tidelift Subscription. +Available as part of the [Tidelift Subscription](https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek). The maintainers of *structlog* and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. -[Learn more](https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek). From 2f060a7ccd6d63440eb6f21ba6f6b0a1228d86a3 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 25 Aug 2024 19:58:31 +0200 Subject: [PATCH 1265/1520] Make BindableLogger return Self on binds (#642) --- CHANGELOG.md | 7 +++++++ pyproject.toml | 2 +- src/structlog/threadlocal.py | 2 +- src/structlog/typing.py | 16 ++++++++++++---- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cdbbc45b..c566dda0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,13 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ## [Unreleased](https://github.com/hynek/structlog/compare/24.4.0...HEAD) +## Changed + +- `structlog.typing.BindableLogger` protocol now returns `Self` instead of `BindableLogger`. + This adds a dependency on [*typing-extensions*](https://pypi.org/project/typing-extensions/) for Pythons older than 3.11. + + [#642](https://github.com/hynek/structlog/pull/642) + ## [24.4.0](https://github.com/hynek/structlog/compare/24.3.0...24.4.0) - 2024-07-17 diff --git a/pyproject.toml b/pyproject.toml index d9a3cc92..4e0c2a6d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ classifiers = [ "Topic :: System :: Logging", "Typing :: Typed", ] -dependencies = [] +dependencies = ["typing-extensions; python_version<'3.11'"] [project.urls] Documentation = "https://www.structlog.org/" diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index c9e412e4..7c827c2e 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -152,7 +152,7 @@ def tmp_bind( saved = as_immutable(logger)._context try: - yield logger.bind(**tmp_values) # type: ignore[misc] + yield logger.bind(**tmp_values) finally: logger._context.clear() logger._context.update(saved) diff --git a/src/structlog/typing.py b/src/structlog/typing.py index 8a07d60a..222e0496 100644 --- a/src/structlog/typing.py +++ b/src/structlog/typing.py @@ -14,6 +14,8 @@ from __future__ import annotations +import sys + from types import TracebackType from typing import ( Any, @@ -31,6 +33,12 @@ ) +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self + + WrappedLogger = Any """ A logger that is wrapped by a bound logger and is ultimately responsible for @@ -130,13 +138,13 @@ class BindableLogger(Protocol): _context: Context - def bind(self, **new_values: Any) -> BindableLogger: ... + def bind(self, **new_values: Any) -> Self: ... - def unbind(self, *keys: str) -> BindableLogger: ... + def unbind(self, *keys: str) -> Self: ... - def try_unbind(self, *keys: str) -> BindableLogger: ... + def try_unbind(self, *keys: str) -> Self: ... - def new(self, **new_values: Any) -> BindableLogger: ... + def new(self, **new_values: Any) -> Self: ... class FilteringBoundLogger(BindableLogger, Protocol): From a98c79a2841aa912219db2fc7792aff7cbe3308b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 26 Aug 2024 06:59:56 +0200 Subject: [PATCH 1266/1520] Add Polar.sh --- README.md | 1 + docs/_static/sponsors/Polar.svg | 10 ++++++++++ docs/index.md | 1 + pyproject.toml | 5 +++++ 4 files changed, 17 insertions(+) create mode 100644 docs/_static/sponsors/Polar.svg diff --git a/README.md b/README.md index ee620296..6d32fd9f 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ for sponsor in tomllib.loads(pathlib.Path("pyproject.toml").read_text())["tool"] +

    diff --git a/docs/_static/sponsors/Polar.svg b/docs/_static/sponsors/Polar.svg new file mode 100644 index 00000000..b278cb75 --- /dev/null +++ b/docs/_static/sponsors/Polar.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/docs/index.md b/docs/index.md index 58f8b350..1433430a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -23,6 +23,7 @@ for sponsor in tomllib.loads(pathlib.Path("pyproject.toml").read_text())["tool"] + ```{include} ../README.md diff --git a/pyproject.toml b/pyproject.toml index 4e0c2a6d..401cd305 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -264,3 +264,8 @@ img = "Klaviyo.svg" title = "FilePreviews" url = "https://filepreviews.io/" img = "FilePreviews.svg" + +[[tool.sponcon.sponsors]] +title = "Polar" +url = "https://polar.sh/" +img = "Polar.svg" From e6066f837d9d89bd1f8b9e999d5e8d6e1010202e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 26 Aug 2024 07:08:35 +0200 Subject: [PATCH 1267/1520] docs: structure intro --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6d32fd9f..a4c97d25 100644 --- a/README.md +++ b/README.md @@ -58,13 +58,13 @@ for sponsor in tomllib.loads(pathlib.Path("pyproject.toml").read_text())["tool"]

    + +

    Please consider joining them to help make structlog’s maintenance more sustainable!

    ---- - - +## Introduction *structlog* has been successfully used in production at every scale since **2013**, while embracing cutting-edge technologies like *asyncio*, context variables, or type hints as they emerged. Its paradigms proved influential enough to [help design](https://twitter.com/sirupsen/status/638330548361019392) structured logging [packages across ecosystems](https://github.com/sirupsen/logrus). From 713e4866d1dd2fd8b2c521e8f764bee43ff0db88 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 3 Sep 2024 07:16:51 +0200 Subject: [PATCH 1268/1520] Fix coverage upload --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b44ed586..3795b9c4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -60,6 +60,7 @@ jobs: with: name: coverage-data-${{ matrix.python-version }} path: .coverage.* + include-hidden-files: true if-no-files-found: ignore coverage: From f282ab26878f70605b41f92f2dfccc80130b942e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 3 Sep 2024 07:18:56 +0200 Subject: [PATCH 1269/1520] [pre-commit.ci] pre-commit autoupdate (#645) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.6.2 → v0.6.3](https://github.com/astral-sh/ruff-pre-commit/compare/v0.6.2...v0.6.3) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Hynek Schlawack --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 33a82228..db580ce2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.6.2 + rev: v0.6.3 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From b265c7acbb700f7483f59b70c58855e59d9fc232 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 3 Sep 2024 07:53:53 +0200 Subject: [PATCH 1270/1520] typo --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 5599a435..b63ad631 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -15,7 +15,7 @@ If an item doesn't apply to your pull request, **check it anyway** to make it ap - [ ] Do **not** open pull requests from your `main` branch – **use a separate branch**! - There's a ton of footguns waiting if you don't heed this warning. You can still go back to your project, create a branch from your main branch, push it, and open the pull request from the new branch. - - This is not a pre-requisite for your your pull request to be accepted, but **you have been warned**. + - This is not a pre-requisite for your pull request to be accepted, but **you have been warned**. - [ ] Added **tests** for changed code. - The CI fails with less than 100% coverage. - [ ] **New APIs** are added to our typing tests in [`api.py`](https://github.com/hynek/structlog/blob/main/tests/typing/api.py). From c0f4491f41e5f45f13c01e888cb1c6bf11aafe42 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 18 Sep 2024 13:14:09 +0200 Subject: [PATCH 1271/1520] Fix CI (#650) * Fix CI for prereleases * Use uv tool for coverage * typo --- .github/workflows/ci.yml | 43 +++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3795b9c4..8fd4e416 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,9 +51,12 @@ jobs: python-version: ${{ matrix.python-version }} allow-prereleases: true - uses: hynek/setup-cached-uv@v2 - - run: uv pip install --system tox-uv - - run: python -Im tox run --installpkg dist/*.whl -f py$(echo ${{ matrix.python-version }} | tr -d .) + - run: > + uvx --with=tox-uv + tox run + --installpkg dist/*.whl + -f py$(echo ${{ matrix.python-version }} | tr -d .) - name: Upload coverage data uses: actions/upload-artifact@v4 @@ -82,14 +85,16 @@ jobs: - name: Combine coverage & fail if it's <100%. run: | - python -Im coverage combine - python -Im coverage html --skip-covered --skip-empty + uv tool install 'coverage[toml]' + + coverage combine + coverage html --skip-covered --skip-empty # Report and write to summary. - python -Im coverage report --format=markdown >> $GITHUB_STEP_SUMMARY + coverage report --format=markdown >> $GITHUB_STEP_SUMMARY # Report again and fail if under 100%. - python -Im coverage report --fail-under=100 + coverage report --fail-under=100 - name: Upload HTML report if check failed. uses: actions/upload-artifact@v4 @@ -115,9 +120,12 @@ jobs: python-version-file: .python-version-default allow-prereleases: true - uses: hynek/setup-cached-uv@v2 - - run: uv pip install --system tox-uv - - run: python -Im tox run --installpkg dist/*.whl -e mypy-pkg + - run: > + uvx --with=tox-uv + tox run + --installpkg dist/*.whl + -e mypy-pkg pyright: name: Pyright @@ -136,9 +144,12 @@ jobs: python-version-file: .python-version-default allow-prereleases: true - uses: hynek/setup-cached-uv@v2 - - run: uv pip install --system tox-uv - - run: python -Im tox run --installpkg dist/*.whl -e pyright + - run: > + uvx --with=tox-uv + tox run + --installpkg dist/*.whl + -e pyright docs: name: Build docs & run doctests @@ -156,9 +167,11 @@ jobs: # Keep in sync with tox.ini/docs & .readthedocs.yaml python-version: "3.12" - uses: hynek/setup-cached-uv@v2 - - run: uv pip install --system tox-uv - - run: python -Im tox run -e docs + - run: > + uvx --with=tox-uv + tox run + -e docs install-dev: name: Verify dev env @@ -212,6 +225,8 @@ jobs: with: python-version-file: .python-version-default - uses: hynek/setup-cached-uv@v2 - - run: uv pip install --system tox-uv - - run: python -Im tox run -f color + - run: > + uvx --with=tox-uv + tox run + -f color From 2c77735b78f69805e548a684e8b22599d56f5c99 Mon Sep 17 00:00:00 2001 From: Trim21 Date: Wed, 18 Sep 2024 19:17:44 +0800 Subject: [PATCH 1272/1520] quote str value with special char in dev output (#649) * quote * ignore * lint * fix test * add changelog * Update CHANGELOG.md * more char * fix lint * make it private --------- Co-authored-by: Hynek Schlawack --- .gitignore | 1 + CHANGELOG.md | 4 ++++ src/structlog/dev.py | 3 ++- tests/test_dev.py | 2 +- 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 89b4da12..1364bb57 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ .pytest_cache .tox .vscode +.idea benchmarks build dist diff --git a/CHANGELOG.md b/CHANGELOG.md index c566dda0..5158ccc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,10 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ [#642](https://github.com/hynek/structlog/pull/642) +- `structlog.dev.ConsoleRenderer` will quote string value with special characters. + + [#647](https://github.com/hynek/structlog/pull/647) + ## [24.4.0](https://github.com/hynek/structlog/compare/24.3.0...24.4.0) - 2024-07-17 diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 5a27df66..2c1e81e4 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -53,7 +53,6 @@ except ImportError: rich = None # type: ignore[assignment] - __all__ = [ "ConsoleRenderer", "plain_traceback", @@ -703,6 +702,8 @@ def _repr(self, val: Any) -> str: return repr(val) if isinstance(val, str): + if set(val) & {" ", "\t", "=", "\r", "\n", '"', "'"}: + return repr(val) return val return repr(val) diff --git a/tests/test_dev.py b/tests/test_dev.py index 00d40cd4..10597dd0 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -95,7 +95,7 @@ def test_event_renamed(self): """ cr = dev.ConsoleRenderer(colors=False, event_key="msg") - assert "new event name event=something custom" == cr( + assert "new event name event='something custom'" == cr( None, None, {"msg": "new event name", "event": "something custom"} ) From 23e23ec222eb353fc53bfe69052658bacd1ead79 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 18 Sep 2024 13:23:27 +0200 Subject: [PATCH 1273/1520] Switch formatters --- .pre-commit-config.yaml | 8 ++------ pyproject.toml | 10 ++++------ src/structlog/_config.py | 4 +++- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index db580ce2..1e7872f8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,14 +3,10 @@ ci: autoupdate_schedule: monthly repos: - - repo: https://github.com/psf/black - rev: 24.8.0 - hooks: - - id: black - - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.6.3 + rev: v0.6.5 hooks: + - id: ruff-format - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/pyproject.toml b/pyproject.toml index 401cd305..56a65ca2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -114,12 +114,9 @@ fail-under = 100 whitelist-regex = ["test_.*"] -[tool.black] -line-length = 79 - - [tool.ruff] src = ["src", "tests"] +line-length = 79 [tool.ruff.lint] select = ["ALL"] @@ -128,13 +125,14 @@ ignore = [ "ANN", # Mypy is better at this "ARG", # unused arguments are common w/ interfaces "C901", # sometimes you trade complexity for performance - "COM", # Black takes care of our commas + "COM", # Formatter takes care of our commas "D", # We prefer our own docstring style. - "E501", # leave line-length enforcement to Black + "E501", # leave line-length enforcement to formatter "EM101", # simple strings are fine "FBT", # bools are our friends "FIX", # Yes, we want XXX as a marker. "INP001", # sometimes we want Python files outside of packages + "ISC001", # conflicts with formatter "N802", # some names are non-pep8 due to stdlib logging / Twisted "N803", # ditto "N806", # ditto diff --git a/src/structlog/_config.py b/src/structlog/_config.py index bd6001bd..bb493fa9 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -363,7 +363,9 @@ def bind(self, **new_values: Any) -> BindableLogger: # Looks like Protocols ignore definitions of __init__ so we have to # silence Mypy here. logger = cls( - _logger, processors=procs, context=ctx # type: ignore[call-arg] + _logger, + processors=procs, + context=ctx, # type: ignore[call-arg] ) def finalized_bind(**new_values: Any) -> BindableLogger: From d38cf212561f51012868d5bdf5f8c450d27a8c8c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 18 Sep 2024 13:38:49 +0200 Subject: [PATCH 1274/1520] docs --- .github/CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index b5aec0b3..75bbbf78 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -130,7 +130,7 @@ You will find the built documentation in `docs/_build/html`. - If you add or change public APIs, tag the docstring using `.. versionadded:: 24.1.0 WHAT` or `.. versionchanged:: 24.1.0 WHAT`. We follow CalVer, so the next version will be the current with with the middle number incremented (for example, `24.1.0` -> `24.2.0`). -- We use [Ruff](https://ruff.rs/) to sort our imports, and we follow the [Black](https://github.com/psf/black) code style with a line length of 79 characters. +- We use [Ruff](https://ruff.rs/) to sort our imports and format our code with a line length of 79 characters. As long as you run our full *tox* suite before committing, or install our [*pre-commit*](https://pre-commit.com/) hooks (ideally you'll do both -- see [*Local Development Environment*](#local-development-environment) above), you won't have to spend any time on formatting your code at all. If you don't, CI will catch it for you -- but that seems like a waste of your time! From 4f909dde024213823dae7b85d19459fcfb6917af Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 18 Sep 2024 13:44:29 +0200 Subject: [PATCH 1275/1520] Lint first, format then --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1e7872f8..add0d687 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,9 +6,9 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.6.5 hooks: - - id: ruff-format - id: ruff args: [--fix, --exit-non-zero-on-fix] + - id: ruff-format - repo: https://github.com/econchick/interrogate rev: 1.7.0 From 60f0931159df767b11bade280d99a477aefd2f25 Mon Sep 17 00:00:00 2001 From: Emmanuel Ferdman Date: Thu, 19 Sep 2024 12:23:20 +0300 Subject: [PATCH 1276/1520] Update license reference (#651) Signed-off-by: Emmanuel Ferdman --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a4c97d25..29daf8dd 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@

    Documentation - License: MIT / Apache 2.0 + License: MIT / Apache 2.0 DOI Supported Python versions of the current PyPI release. From 0bd3ac2fb7df14797f20af1595e2ef9b34a1d2a5 Mon Sep 17 00:00:00 2001 From: Max Linke Date: Wed, 25 Sep 2024 11:27:24 +0200 Subject: [PATCH 1277/1520] Fix Open Telemetry framework example (#653) The `hex` function does not format the trace and span id correctly. In as much as the spec [says](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#retrieving-the-traceid-and-spanid) the span-id and trace-id are fixed with hex numbers. 16 chars for the span-id and 32 for the trace-id. --- docs/frameworks.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/frameworks.md b/docs/frameworks.md index 59fc6c92..a09609c8 100644 --- a/docs/frameworks.md +++ b/docs/frameworks.md @@ -89,9 +89,9 @@ def add_open_telemetry_spans(_, __, event_dict): parent = getattr(span, "parent", None) event_dict["span"] = { - "span_id": hex(ctx.span_id), - "trace_id": hex(ctx.trace_id), - "parent_span_id": None if not parent else hex(parent.span_id), + "span_id": format(ctx.span_id, "016x"), + "trace_id": format(ctx.trace_id, "032x"), + "parent_span_id": None if not parent else format(parent.span_id, "016x"), } return event_dict From 9e9711c1b5a88970005fb1a1722f9e81ec12932d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 29 Sep 2024 13:52:12 +0200 Subject: [PATCH 1278/1520] Remove unnecessary install --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8fd4e416..9040b834 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -77,7 +77,6 @@ jobs: with: python-version-file: .python-version-default - uses: hynek/setup-cached-uv@v2 - - run: uv pip install --system --upgrade coverage[toml] - uses: actions/download-artifact@v4 with: pattern: coverage-data-* From c53f14832d0284d704e9aef6fc44f2b86f562bcf Mon Sep 17 00:00:00 2001 From: Andrew Thorp Date: Mon, 7 Oct 2024 02:25:39 -0400 Subject: [PATCH 1279/1520] Switch base methods to return Self instead of BoundLoggerBase (#659) * Switch base methods to return Self instead of BoundLoggerBase * add tests for BoundLoggerBase return type * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * re-export version-safe Self in typings * workaround self-assignment (pun intended) * switch _self import name to be consistent with class _Self * fix (generic) BoundLogger api test to only call generic methods * remove re-export of Self due to typealias, state issues * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fix redundant import rename * fix redundant import rename * remove no-longer-necessary type ignores! * remove moar no-longer-necessary type-ignores! --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- src/structlog/_base.py | 16 ++++++++++++---- src/structlog/stdlib.py | 8 ++++---- tests/typing/api.py | 8 ++++++++ 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/structlog/_base.py b/src/structlog/_base.py index 25f59277..3342a8f7 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -9,6 +9,8 @@ from __future__ import annotations +import sys + from typing import Any, Iterable, Mapping, Sequence from structlog.exceptions import DropEvent @@ -16,6 +18,12 @@ from .typing import BindableLogger, Context, Processor, WrappedLogger +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self + + class BoundLoggerBase: """ Immutable context carrier. @@ -62,7 +70,7 @@ def __eq__(self, other: object) -> bool: def __ne__(self, other: object) -> bool: return not self.__eq__(other) - def bind(self, **new_values: Any) -> BoundLoggerBase: + def bind(self, **new_values: Any) -> Self: """ Return a new logger with *new_values* added to the existing ones. """ @@ -72,7 +80,7 @@ def bind(self, **new_values: Any) -> BoundLoggerBase: self._context.__class__(self._context, **new_values), ) - def unbind(self, *keys: str) -> BoundLoggerBase: + def unbind(self, *keys: str) -> Self: """ Return a new logger with *keys* removed from the context. @@ -85,7 +93,7 @@ def unbind(self, *keys: str) -> BoundLoggerBase: return bl - def try_unbind(self, *keys: str) -> BoundLoggerBase: + def try_unbind(self, *keys: str) -> Self: """ Like :meth:`unbind`, but best effort: missing keys are ignored. @@ -97,7 +105,7 @@ def try_unbind(self, *keys: str) -> BoundLoggerBase: return bl - def new(self, **new_values: Any) -> BoundLoggerBase: + def new(self, **new_values: Any) -> Self: """ Clear context and binds *new_values* using `bind`. diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index dbb530f9..fb5fa15d 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -156,7 +156,7 @@ def bind(self, **new_values: Any) -> BoundLogger: """ Return a new logger with *new_values* added to the existing ones. """ - return super().bind(**new_values) # type: ignore[return-value] + return super().bind(**new_values) def unbind(self, *keys: str) -> BoundLogger: """ @@ -165,7 +165,7 @@ def unbind(self, *keys: str) -> BoundLogger: Raises: KeyError: If the key is not part of the context. """ - return super().unbind(*keys) # type: ignore[return-value] + return super().unbind(*keys) def try_unbind(self, *keys: str) -> BoundLogger: """ @@ -173,7 +173,7 @@ def try_unbind(self, *keys: str) -> BoundLogger: .. versionadded:: 18.2.0 """ - return super().try_unbind(*keys) # type: ignore[return-value] + return super().try_unbind(*keys) def new(self, **new_values: Any) -> BoundLogger: """ @@ -183,7 +183,7 @@ def new(self, **new_values: Any) -> BoundLogger: those wrapped by `structlog.threadlocal.wrap_dict` when threads are re-used. """ - return super().new(**new_values) # type: ignore[return-value] + return super().new(**new_values) def debug(self, event: str | None = None, *args: Any, **kw: Any) -> Any: """ diff --git a/tests/typing/api.py b/tests/typing/api.py index 719f290c..d4e1afe6 100644 --- a/tests/typing/api.py +++ b/tests/typing/api.py @@ -323,6 +323,14 @@ async def typecheck_stdlib_async() -> None: await logger.alog(logging.CRITICAL, "async log") +def typecheck_bound_logger_return() -> None: + blogger: structlog.BoundLogger = structlog.get_logger(__name__) + blog = blogger.bind(key1="value1", key2="value2", key3="value3") + blog = blog.unbind("key1") + blog = blog.try_unbind("bad_key") + blog = blog.new(new="value") + + # Structured tracebacks and ExceptionRenderer with ExceptionDictTransformer struct_tb: structlog.tracebacks.Trace = structlog.tracebacks.extract( ValueError, ValueError("onoes"), None From 62a1bc63f342d9ea1ae10fd2b9c9815a4ebd07f1 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 7 Oct 2024 08:26:51 +0200 Subject: [PATCH 1280/1520] Add relatd PR# --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5158ccc9..559c4a28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ This adds a dependency on [*typing-extensions*](https://pypi.org/project/typing-extensions/) for Pythons older than 3.11. [#642](https://github.com/hynek/structlog/pull/642) + [#659](https://github.com/hynek/structlog/pull/659) - `structlog.dev.ConsoleRenderer` will quote string value with special characters. From 8a31eaaac810b4c3a271f903a430735f3445e29f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 7 Oct 2024 08:27:09 +0200 Subject: [PATCH 1281/1520] pre-commit autoupdate --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index add0d687..f6fc9181 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.6.5 + rev: v0.6.9 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] @@ -23,7 +23,7 @@ repos: args: [-L, alog] - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 + rev: v5.0.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer From 22e024538ac7865f1e0a9d2896edc3a1164819fb Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 12 Oct 2024 15:14:34 +0200 Subject: [PATCH 1282/1520] Use 3.13 in dev --- .python-version-default | 2 +- pyproject.toml | 1 + tox.ini | 12 ++++-------- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/.python-version-default b/.python-version-default index e4fba218..24ee5b1b 100644 --- a/.python-version-default +++ b/.python-version-default @@ -1 +1 @@ -3.12 +3.13 diff --git a/pyproject.toml b/pyproject.toml index 56a65ca2..28ac2ebe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,6 +75,7 @@ filterwarnings = [ 'ignore:datetime.datetime.utcfromtimestamp\(\) is deprecated:DeprecationWarning:dateutil.tz', ] asyncio_mode = "auto" +asyncio_default_fixture_loop_scope = "function" [tool.coverage.run] diff --git a/tox.ini b/tox.ini index 005f8b1e..9defe0bd 100644 --- a/tox.ini +++ b/tox.ini @@ -4,7 +4,7 @@ env_list = pre-commit, mypy-pkg, py3{8,9,10,11,12,13}-{tests,mypy} - py3{8,12}-tests-{colorama,be,rich}, + py3{8,13}-tests-{colorama,be,rich}, docs{,-sponsors}, coverage-report @@ -22,12 +22,10 @@ commands = # Run oldest and latest under Coverage. # Keep in-sync with coverage `depends below. -[testenv:py3{8,12}-tests{,-colorama,-be,-rich}] -set_env = - py312: COVERAGE_CORE=sysmon +[testenv:py3{8,13}-tests{,-colorama,-be,-rich}] deps = coverage[toml] - py312: twisted + py313: twisted colorama: colorama rich: rich be: better-exceptions @@ -35,13 +33,11 @@ commands = coverage run -m pytest {posargs} [testenv:coverage-report] -# Keep in-sync with .python-version-default -base_python = py312 deps = coverage[toml] skip_install = true parallel_show_output = true # Keep in-sync with test env definition above. -depends = py3{8,12}-{tests,colorama,be,rich} +depends = py3{8,13}-{tests,colorama,be,rich} commands = coverage combine coverage report From e7f36a5349105ba3dd18eceb42eedfc296cd439d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 12 Oct 2024 15:19:05 +0200 Subject: [PATCH 1283/1520] Pin sphinx Currently breaks CI --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 28ac2ebe..58d0f65f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,7 +52,7 @@ docs = [ "cogapp", "furo", "myst-parser", - "sphinx", + "sphinx<8.1", "sphinx-notfound-page", "sphinxcontrib-mermaid", "sphinxext-opengraph", From 46aee58613c6ec0911b80f58df7ecae4972eef44 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 12 Oct 2024 15:26:59 +0200 Subject: [PATCH 1284/1520] Use an empty string when omitting a logger name To not violate our own type hints and intentions. Ref #660 --- docs/api.rst | 26 +++++++++++++------------- docs/processors.md | 4 ++-- docs/recipes.md | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 99acb1cb..6879f1e0 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -152,7 +152,7 @@ API Reference .. doctest:: >>> from structlog.processors import JSONRenderer - >>> JSONRenderer(sort_keys=True)(None, None, {"a": 42, "b": [1, 2, 3]}) + >>> JSONRenderer(sort_keys=True)(None, "", {"a": 42, "b": [1, 2, 3]}) '{"a": 42, "b": [1, 2, 3]}' Bound objects are attempted to be serialize using a ``__structlog__`` method. @@ -169,7 +169,7 @@ API Reference ... def __repr__(self): ... return "No __structlog__, so this is used." >>> from structlog.processors import JSONRenderer - >>> JSONRenderer(sort_keys=True)(None, None, {"c1": C1(), "c2": C2()}) + >>> JSONRenderer(sort_keys=True)(None, "", {"c1": C1(), "c2": C2()}) '{"c1": ["C1!"], "c2": "No __structlog__, so this is used."}' Please note that additionally to strings, you can also return any type the standard library JSON module knows about -- like in this example a list. @@ -204,9 +204,9 @@ API Reference .. doctest:: >>> from structlog.processors import KeyValueRenderer - >>> KeyValueRenderer(sort_keys=True)(None, None, {"a": 42, "b": [1, 2, 3]}) + >>> KeyValueRenderer(sort_keys=True)(None, "", {"a": 42, "b": [1, 2, 3]}) 'a=42 b=[1, 2, 3]' - >>> KeyValueRenderer(key_order=["b", "a"])(None, None, + >>> KeyValueRenderer(key_order=["b", "a"])(None, "", ... {"a": 42, "b": [1, 2, 3]}) 'b=[1, 2, 3] a=42' @@ -216,9 +216,9 @@ API Reference >>> from structlog.processors import LogfmtRenderer >>> event_dict = {"a": 42, "b": [1, 2, 3], "flag": True} - >>> LogfmtRenderer(sort_keys=True)(None, None, event_dict) + >>> LogfmtRenderer(sort_keys=True)(None, "", event_dict) 'a=42 b="[1, 2, 3]" flag' - >>> LogfmtRenderer(key_order=["b", "a"], bool_as_flag=False)(None, None, event_dict) + >>> LogfmtRenderer(key_order=["b", "a"], bool_as_flag=False)(None, "", event_dict) 'b="[1, 2, 3]" a=42 flag=true' .. autoclass:: EventRenamer @@ -239,7 +239,7 @@ API Reference >>> try: ... raise ValueError ... except ValueError: - ... format_exc_info(None, None, {"exc_info": True}) # doctest: +ELLIPSIS + ... format_exc_info(None, "", {"exc_info": True}) # doctest: +ELLIPSIS {'exception': 'Traceback (most recent call last):... .. autofunction:: dict_tracebacks @@ -250,7 +250,7 @@ API Reference >>> try: ... raise ValueError("onoes") ... except ValueError: - ... dict_tracebacks(None, None, {"exc_info": True}) # doctest: +ELLIPSIS + ... dict_tracebacks(None, "", {"exc_info": True}) # doctest: +ELLIPSIS {'exception': [{'exc_type': 'ValueError', 'exc_value': 'onoes', ..., 'frames': [{'filename': ... .. autoclass:: StackInfoRenderer @@ -262,11 +262,11 @@ API Reference .. doctest:: >>> from structlog.processors import TimeStamper - >>> TimeStamper()(None, None, {}) # doctest: +SKIP + >>> TimeStamper()(None, "", {}) # doctest: +SKIP {'timestamp': 1378994017} - >>> TimeStamper(fmt="iso")(None, None, {}) # doctest: +SKIP + >>> TimeStamper(fmt="iso")(None, "", {}) # doctest: +SKIP {'timestamp': '2013-09-12T13:54:26.996778Z'} - >>> TimeStamper(fmt="%Y", key="year")(None, None, {}) # doctest: +SKIP + >>> TimeStamper(fmt="%Y", key="year")(None, "", {}) # doctest: +SKIP {'year': '2013'} .. autoclass:: MaybeTimeStamper @@ -274,9 +274,9 @@ API Reference .. doctest:: >>> from structlog.processors import MaybeTimeStamper - >>> MaybeTimeStamper()(None, None, {}) # doctest: +SKIP + >>> MaybeTimeStamper()(None, "", {}) # doctest: +SKIP {'timestamp': 1690036074.494428} - >>> MaybeTimeStamper()(None, None, {"timestamp": 42}) + >>> MaybeTimeStamper()(None, "", {"timestamp": 42}) {'timestamp': 42} .. autoclass:: CallsiteParameter diff --git a/docs/processors.md b/docs/processors.md index f23ef999..85b4118c 100644 --- a/docs/processors.md +++ b/docs/processors.md @@ -106,9 +106,9 @@ class ConditionalDropper: def __call__(self, logger, method_name, event_dict): """ >>> cd = ConditionalDropper("127.0.0.1") - >>> cd(None, None, {"event": "foo", "peer": "10.0.0.1"}) + >>> cd(None, "", {"event": "foo", "peer": "10.0.0.1"}) {'peer': '10.0.0.1', 'event': 'foo'} - >>> cd(None, None, {"event": "foo", "peer": "127.0.0.1"}) + >>> cd(None, "", {"event": "foo", "peer": "127.0.0.1"}) Traceback (most recent call last): ... DropEvent diff --git a/docs/recipes.md b/docs/recipes.md index b990ecc4..adb4585c 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -17,7 +17,7 @@ With the {class}`structlog.processors.EventRenamer` processor, you can, for inst ```pycon >>> from structlog.processors import EventRenamer >>> event_dict = {"event": "something happened", "_event": "our event!"} ->>> EventRenamer("msg", "_event")(None, None, event_dict) +>>> EventRenamer("msg", "_event")(None, "", event_dict) {'msg': 'something happened', 'event': 'our event!'} ``` From 81ba67ef12cb7f9da4649ab123633c765ae18ac8 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 13 Oct 2024 06:04:54 +0200 Subject: [PATCH 1285/1520] Unpin Sphinx again --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 58d0f65f..28ac2ebe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,7 +52,7 @@ docs = [ "cogapp", "furo", "myst-parser", - "sphinx<8.1", + "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", "sphinxext-opengraph", From f3e6fdee0658e9c6ab89aaa8823abe0d78e49b3a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 14 Oct 2024 08:56:36 +0200 Subject: [PATCH 1286/1520] The Python used for coverage is new enough for toml --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9040b834..e6eee1fd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -84,7 +84,7 @@ jobs: - name: Combine coverage & fail if it's <100%. run: | - uv tool install 'coverage[toml]' + uv tool install coverage coverage combine coverage html --skip-covered --skip-empty From 0a2b8bbee8eb62a5f2b9deace743357cc374333e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 31 Oct 2024 10:02:39 +0100 Subject: [PATCH 1287/1520] dev: fix type annotations for style parameters --- src/structlog/dev.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 2c1e81e4..7e9a541d 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -469,9 +469,10 @@ class ConsoleRenderer: level_styles: When present, use these styles for colors. This must be a dict from - level names (strings) to Colorama styles. The default can be - obtained by calling `ConsoleRenderer.get_default_level_styles`. - Ignored when *columns* are passed. + level names (strings) to terminal sequences (for example, Colorama) + styles. The default can be obtained by calling + `ConsoleRenderer.get_default_level_styles`. Ignored when *columns* + are passed. exception_formatter: A callable to render ``exc_infos``. If Rich_ or better-exceptions_ @@ -547,7 +548,7 @@ def __init__( # noqa: PLR0912, PLR0915 colors: bool = _has_colors, force_colors: bool = False, repr_native_str: bool = False, - level_styles: Styles | None = None, + level_styles: dict[str, str] | None = None, exception_formatter: ExceptionRenderer = default_exception_formatter, sort_keys: bool = True, event_key: str = "event", @@ -750,7 +751,7 @@ def __call__( return sio.getvalue() @staticmethod - def get_default_level_styles(colors: bool = True) -> Any: + def get_default_level_styles(colors: bool = True) -> dict[str, str]: """ Get the default styles for log levels From 300f0d2a0434089c2142c1417d1f469421915f78 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 31 Oct 2024 10:02:52 +0100 Subject: [PATCH 1288/1520] update ruff --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f6fc9181..dee91d6a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.6.9 + rev: v0.7.1 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From 0e6b7f0de50d0d802bfb50472839c83c0af7616c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 31 Oct 2024 10:05:57 +0100 Subject: [PATCH 1289/1520] Thank you Doctor Zizmor! (#663) --- .github/workflows/build-docset.yml | 1 + .github/workflows/ci.yml | 78 +++++++++++++++++---------- .github/workflows/codeql-analysis.yml | 2 + .github/workflows/pypi-package.yml | 21 +++++--- .github/workflows/zizmor.yml | 37 +++++++++++++ 5 files changed, 103 insertions(+), 36 deletions(-) create mode 100644 .github/workflows/zizmor.yml diff --git a/.github/workflows/build-docset.yml b/.github/workflows/build-docset.yml index 110532fe..fe14f451 100644 --- a/.github/workflows/build-docset.yml +++ b/.github/workflows/build-docset.yml @@ -19,6 +19,7 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 # get correct version + persist-credentials: false - uses: actions/setup-python@v5 with: python-version: "3.12" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e6eee1fd..47a43a65 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,6 +14,7 @@ env: permissions: {} + jobs: build-package: name: Build & verify package @@ -23,20 +24,25 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 + persist-credentials: false - uses: hynek/build-and-inspect-python-package@v2 id: baipp outputs: + # Used to define the matrix for tests below. The value is based on + # packaging metadata (trove classifiers). python-versions: ${{ steps.baipp.outputs.supported_python_classifiers_json_array }} tests: - name: Tests & API Mypy on ${{ matrix.python-version }} - needs: build-package + name: Tests & Mypy API on ${{ matrix.python-version }} runs-on: ubuntu-latest + needs: build-package + strategy: fail-fast: false matrix: + # Created by the build-and-inspect-python-package action above. python-version: ${{ fromJson(needs.build-package.outputs.python-versions) }} steps: @@ -45,18 +51,22 @@ jobs: with: name: Packages path: dist - - run: tar xf dist/*.tar.gz --strip-components=1 + - run: | + tar xf dist/*.tar.gz --strip-components=1 + rm -rf src - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} allow-prereleases: true - uses: hynek/setup-cached-uv@v2 - - run: > - uvx --with=tox-uv - tox run + - name: Run tests + env: + PYTHON: ${{ matrix.python-version }} + run: > + uvx --with tox-uv tox run --installpkg dist/*.whl - -f py$(echo ${{ matrix.python-version }} | tr -d .) + -f py${PYTHON//./}-tests - name: Upload coverage data uses: actions/upload-artifact@v4 @@ -66,23 +76,36 @@ jobs: include-hidden-files: true if-no-files-found: ignore + - name: Check public API with Mypy + env: + PYTHON: ${{ matrix.python-version }} + run: > + uvx --with tox-uv tox run + --installpkg dist/*.whl + -e py${PYTHON//./}-mypy + coverage: - name: Combine & check coverage - needs: tests + name: Ensure 100% test coverage runs-on: ubuntu-latest + needs: tests + if: always() steps: - uses: actions/checkout@v4 + with: + persist-credentials: false - uses: actions/setup-python@v5 with: python-version-file: .python-version-default - uses: hynek/setup-cached-uv@v2 - - uses: actions/download-artifact@v4 + + - name: Download coverage data + uses: actions/download-artifact@v4 with: pattern: coverage-data-* merge-multiple: true - - name: Combine coverage & fail if it's <100%. + - name: Combine coverage and fail if it's <100%. run: | uv tool install coverage @@ -103,9 +126,9 @@ jobs: if: ${{ failure() }} mypy-pkg: - name: Type-check package - needs: build-package + name: Mypy Codebase runs-on: ubuntu-latest + needs: build-package steps: - name: Download pre-built packages @@ -117,20 +140,16 @@ jobs: - uses: actions/setup-python@v5 with: python-version-file: .python-version-default - allow-prereleases: true - uses: hynek/setup-cached-uv@v2 - run: > - uvx --with=tox-uv - tox run - --installpkg dist/*.whl - -e mypy-pkg + uvx --with tox-uv + tox run -e mypy-pkg pyright: - name: Pyright + name: Pyright Codebase runs-on: ubuntu-latest needs: build-package - steps: - name: Download pre-built packages uses: actions/download-artifact@v4 @@ -141,14 +160,12 @@ jobs: - uses: actions/setup-python@v5 with: python-version-file: .python-version-default - allow-prereleases: true - uses: hynek/setup-cached-uv@v2 - run: > - uvx --with=tox-uv - tox run - --installpkg dist/*.whl - -e pyright + uvx --with tox-uv + tox run -e pyright + docs: name: Build docs & run doctests @@ -168,9 +185,8 @@ jobs: - uses: hynek/setup-cached-uv@v2 - run: > - uvx --with=tox-uv - tox run - -e docs + uvx --with tox-uv + tox run -e docs install-dev: name: Verify dev env @@ -181,6 +197,8 @@ jobs: steps: - uses: actions/checkout@v4 + with: + persist-credentials: false - uses: actions/setup-python@v5 with: python-version-file: .python-version-default @@ -200,10 +218,10 @@ jobs: needs: - coverage - - docs - install-dev - mypy-pkg - pyright + - docs runs-on: ubuntu-latest @@ -220,6 +238,8 @@ jobs: steps: - uses: actions/checkout@v4 + with: + persist-credentials: false - uses: actions/setup-python@v5 with: python-version-file: .python-version-default diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 68f325e6..7907ccb0 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -25,6 +25,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 + with: + persist-credentials: false - name: Initialize CodeQL uses: github/codeql-action/init@v3 diff --git a/.github/workflows/pypi-package.yml b/.github/workflows/pypi-package.yml index 43093ce5..9417b97d 100644 --- a/.github/workflows/pypi-package.yml +++ b/.github/workflows/pypi-package.yml @@ -1,5 +1,5 @@ --- -name: Build & maybe upload PyPI package +name: Build & upload PyPI package on: push: @@ -10,20 +10,21 @@ on: - published workflow_dispatch: -permissions: - attestations: write - contents: read - id-token: write jobs: + # Always build & lint package. build-package: name: Build & verify package runs-on: ubuntu-latest + permissions: + attestations: write + id-token: write steps: - uses: actions/checkout@v4 with: fetch-depth: 0 + persist-credentials: false - uses: hynek/build-and-inspect-python-package@v2 with: @@ -33,10 +34,13 @@ jobs: release-test-pypi: name: Publish in-dev package to test.pypi.org environment: release-test-pypi - if: github.event_name == 'push' && github.ref == 'refs/heads/main' + if: github.repository_owner == 'hynek' && github.event_name == 'push' && github.ref == 'refs/heads/main' runs-on: ubuntu-latest needs: build-package + permissions: + id-token: write + steps: - name: Download packages built by build-and-inspect-python-package uses: actions/download-artifact@v4 @@ -53,10 +57,13 @@ jobs: release-pypi: name: Publish released package to pypi.org environment: release-pypi - if: github.event.action == 'published' + if: github.repository_owner == 'hynek' && github.event.action == 'published' runs-on: ubuntu-latest needs: build-package + permissions: + id-token: write + steps: - name: Download packages built by build-and-inspect-python-package uses: actions/download-artifact@v4 diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml new file mode 100644 index 00000000..08294a4a --- /dev/null +++ b/.github/workflows/zizmor.yml @@ -0,0 +1,37 @@ +# https://github.com/woodruffw/zizmor +name: GitHub Actions Security Analysis with Zizmor + +on: + push: + branches: ["main"] + pull_request: + branches: ["*"] + +permissions: + contents: read + +jobs: + zizmor: + name: Zizmor latest via Cargo + runs-on: ubuntu-latest + permissions: + security-events: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + persist-credentials: false + - name: Setup Rust + uses: actions-rust-lang/setup-rust-toolchain@v1 + - name: Get zizmor + run: cargo install zizmor + - name: Run zizmor + run: zizmor --format sarif . > results.sarif + - name: Upload SARIF file + uses: github/codeql-action/upload-sarif@v3 + with: + # Path to SARIF file relative to the root of the repository + sarif_file: results.sarif + # Optional category for the results + # Used to differentiate multiple results for one commit + category: zizmor From 3c507359cc9d4f5531a858bace66cbd41ab44832 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 31 Oct 2024 10:07:44 +0100 Subject: [PATCH 1290/1520] ci: use job-wide env --- .github/workflows/ci.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 47a43a65..b6df253f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,6 +45,9 @@ jobs: # Created by the build-and-inspect-python-package action above. python-version: ${{ fromJson(needs.build-package.outputs.python-versions) }} + env: + PYTHON: ${{ matrix.python-version }} + steps: - name: Download pre-built packages uses: actions/download-artifact@v4 @@ -61,8 +64,6 @@ jobs: - uses: hynek/setup-cached-uv@v2 - name: Run tests - env: - PYTHON: ${{ matrix.python-version }} run: > uvx --with tox-uv tox run --installpkg dist/*.whl @@ -77,8 +78,6 @@ jobs: if-no-files-found: ignore - name: Check public API with Mypy - env: - PYTHON: ${{ matrix.python-version }} run: > uvx --with tox-uv tox run --installpkg dist/*.whl From 9b2daab7ec1575664522004c93cb3c13ae1635d4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 31 Oct 2024 10:37:57 +0100 Subject: [PATCH 1291/1520] ci: pedantry --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b6df253f..fff26d70 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,6 +34,7 @@ jobs: # packaging metadata (trove classifiers). python-versions: ${{ steps.baipp.outputs.supported_python_classifiers_json_array }} + tests: name: Tests & Mypy API on ${{ matrix.python-version }} runs-on: ubuntu-latest From 6251d206c73cd82c6fadf67751570fc6d6b46762 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 31 Oct 2024 10:44:32 +0100 Subject: [PATCH 1292/1520] ci: more pedantry --- .github/workflows/ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fff26d70..a7c0b25e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -84,6 +84,7 @@ jobs: --installpkg dist/*.whl -e py${PYTHON//./}-mypy + coverage: name: Ensure 100% test coverage runs-on: ubuntu-latest @@ -125,6 +126,7 @@ jobs: path: htmlcov if: ${{ failure() }} + mypy-pkg: name: Mypy Codebase runs-on: ubuntu-latest @@ -146,6 +148,7 @@ jobs: uvx --with tox-uv tox run -e mypy-pkg + pyright: name: Pyright Codebase runs-on: ubuntu-latest @@ -188,6 +191,7 @@ jobs: uvx --with tox-uv tox run -e docs + install-dev: name: Verify dev env runs-on: ${{ matrix.os }} @@ -212,6 +216,7 @@ jobs: - run: .\.venv\Scripts\python.exe -Ic 'import structlog; print(structlog.__version__)' if: runner.os == 'Windows' + required-checks-pass: name: Ensure everything required is passing for branch protection if: always() @@ -231,6 +236,7 @@ jobs: with: jobs: ${{ toJSON(needs) }} + colors: name: Visual check for color settings using env variables needs: build-package From 6aaa0e2ee4fad999510f9b97b143ba51372f968d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 18:45:50 +0100 Subject: [PATCH 1293/1520] [pre-commit.ci] pre-commit autoupdate (#667) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.7.1 → v0.7.2](https://github.com/astral-sh/ruff-pre-commit/compare/v0.7.1...v0.7.2) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index dee91d6a..f9bebbcd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.7.1 + rev: v0.7.2 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From 6f9ed85b7524cc9fc98417384497f996e4eca695 Mon Sep 17 00:00:00 2001 From: Yael Mintz Date: Sat, 9 Nov 2024 08:42:58 +0200 Subject: [PATCH 1294/1520] handle missing exc_info in ExceptionDictTransformer (#657) * handle missing exc_info in ExceptionDictTransformer - Added a new utility function is_missing_exc_info to check if exc_info is missing. - Updated ExceptionDictTransformer to return an empty list when exc_info is missing. - Modified _format_exception to use the new is_missing_exc_info function. - Added a test case to verify that ExceptionDictTransformer returns an empty list when exc_info is missing. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update tests/test_tracebacks.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Hynek Schlawack --- src/structlog/_frames.py | 9 ++++++++- src/structlog/tracebacks.py | 4 ++++ tests/test_tracebacks.py | 11 +++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/structlog/_frames.py b/src/structlog/_frames.py index 35c06eaa..1eb8e7c9 100644 --- a/src/structlog/_frames.py +++ b/src/structlog/_frames.py @@ -16,13 +16,20 @@ from .typing import ExcInfo +def is_missing_exc_info(exc_info: ExcInfo) -> bool: + """ + Return True if exc_info is the missing value. + """ + return exc_info == (None, None, None) # type: ignore[comparison-overlap] + + def _format_exception(exc_info: ExcInfo) -> str: """ Prettyprint an `exc_info` tuple. Shamelessly stolen from stdlib's logging module. """ - if exc_info == (None, None, None): # type: ignore[comparison-overlap] + if is_missing_exc_info(exc_info): return "MISSING" sio = StringIO() diff --git a/src/structlog/tracebacks.py b/src/structlog/tracebacks.py index 2331b2fa..2392b342 100644 --- a/src/structlog/tracebacks.py +++ b/src/structlog/tracebacks.py @@ -22,6 +22,8 @@ from types import ModuleType, TracebackType from typing import Any, Iterable, Sequence, Tuple, Union +from ._frames import is_missing_exc_info + try: import rich @@ -412,6 +414,8 @@ def __init__( self.use_rich = use_rich def __call__(self, exc_info: ExcInfo) -> list[dict[str, Any]]: + if is_missing_exc_info(exc_info): + return [] trace = extract( *exc_info, show_locals=self.show_locals, diff --git a/tests/test_tracebacks.py b/tests/test_tracebacks.py index 2de04776..a086a042 100644 --- a/tests/test_tracebacks.py +++ b/tests/test_tracebacks.py @@ -730,3 +730,14 @@ def test_json_traceback_value_error( monkeypatch.setattr(kwargs["suppress"][0], "__file__", None) with pytest.raises(ValueError, match=next(iter(kwargs.keys()))): tracebacks.ExceptionDictTransformer(**kwargs) + + +def test_exception_dict_transformer_missing_exc_info(): + """ + ExceptionDictTransformer returns an empty list if exc_info is missing. + """ + transformer = tracebacks.ExceptionDictTransformer() + + result = transformer(exc_info=(None, None, None)) + + assert [] == result From d4a5a8d46b0aca87050a60924e02ca2cc9a26035 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 9 Nov 2024 07:45:22 +0100 Subject: [PATCH 1295/1520] Add changelog for #657 --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 559c4a28..c9f8382b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,15 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ [#647](https://github.com/hynek/structlog/pull/647) + +## Fixed + +- `structlog.traceback.ExceptionDictTransformer` now correctly handles missing exceptions. + + [#657](https://github.com/hynek/structlog/pull/657) + + + ## [24.4.0](https://github.com/hynek/structlog/compare/24.3.0...24.4.0) - 2024-07-17 ### Changed From 891e351c2b175ae3b1a5c1fd937b20cef92cb72f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 9 Nov 2024 07:50:14 +0100 Subject: [PATCH 1296/1520] ci: shorten --- .github/workflows/zizmor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index 08294a4a..2a8b5bf2 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -1,5 +1,5 @@ # https://github.com/woodruffw/zizmor -name: GitHub Actions Security Analysis with Zizmor +name: Zizmor on: push: From 8da1ba578479c1a40988eff897c08659d901b7cb Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 9 Nov 2024 07:50:27 +0100 Subject: [PATCH 1297/1520] pre-commit update --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f9bebbcd..944235ea 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.7.2 + rev: v0.7.3 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From 5551c2f025626ce539dd28121df8108e3ac5cde3 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 9 Nov 2024 08:17:36 +0100 Subject: [PATCH 1298/1520] Stop mutating styles in ConsoleRenderer (#669) Fixes #643 --- CHANGELOG.md | 4 +++- src/structlog/dev.py | 2 +- tests/test_dev.py | 13 +++++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9f8382b..4e0886fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,13 +28,15 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ [#647](https://github.com/hynek/structlog/pull/647) - ## Fixed - `structlog.traceback.ExceptionDictTransformer` now correctly handles missing exceptions. [#657](https://github.com/hynek/structlog/pull/657) +- Instantiating `structlog.dev.ConsoleRenderer` does not mutate the passed *styles* dict anymore. + + [#658](https://github.com/hynek/structlog/pull/658) ## [24.4.0](https://github.com/hynek/structlog/compare/24.3.0...24.4.0) - 2024-07-17 diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 7e9a541d..a3ae8394 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -635,7 +635,7 @@ def add_meaningless_arg(arg: str) -> None: self.get_default_level_styles(colors) if level_styles is None else level_styles - ) + ).copy() for key in level_to_color: level_to_color[key] += styles.bright diff --git a/tests/test_dev.py b/tests/test_dev.py index 10597dd0..1193c040 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -614,6 +614,19 @@ def test_enforces_presence_of_exactly_one_default_formatter(self): ] ) + def test_does_not_modify_styles(self): + """ + Instantiating ConsoleRenderer should not modify the styles passed in. + + Ref #643 + """ + styles = {"info": "something"} + copy = styles.copy() + + dev.ConsoleRenderer(level_styles=styles) + + assert copy == styles + class TestSetExcInfo: def test_wrong_name(self): From ea14124ccb8b45747a403d3064f6a4aac6926985 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 9 Nov 2024 08:18:10 +0100 Subject: [PATCH 1299/1520] Fix PR# --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e0886fc..9267b458 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,7 +36,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - Instantiating `structlog.dev.ConsoleRenderer` does not mutate the passed *styles* dict anymore. - [#658](https://github.com/hynek/structlog/pull/658) + [#669](https://github.com/hynek/structlog/pull/669) ## [24.4.0](https://github.com/hynek/structlog/compare/24.3.0...24.4.0) - 2024-07-17 From a022e06d17a66731b3bd775f4ff51b81649f6d55 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 10 Nov 2024 09:46:47 +0100 Subject: [PATCH 1300/1520] Use real methods for fatal/warn (#670) For better DX in IDEs. Fixes #648 --- src/structlog/stdlib.py | 22 +++++++++++++++++----- tests/test_stdlib.py | 35 +++++++++++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index fb5fa15d..166578be 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -217,6 +217,12 @@ def critical(self, event: str | None = None, *args: Any, **kw: Any) -> Any: """ return self._proxy_to_logger("critical", event, *args, **kw) + def fatal(self, event: str | None = None, *args: Any, **kw: Any) -> Any: + """ + Process event and call `logging.Logger.critical` with the result. + """ + return self._proxy_to_logger("critical", event, *args, **kw) + def exception( self, event: str | None = None, *args: Any, **kw: Any ) -> Any: @@ -236,8 +242,6 @@ def log( """ return self._proxy_to_logger(LEVEL_TO_NAME[level], event, *args, **kw) - fatal = critical - def _proxy_to_logger( self, method_name: str, @@ -448,7 +452,13 @@ async def acritical(self, event: str, *args: Any, **kw: Any) -> None: """ await self._dispatch_to_sync(self.critical, event, args, kw) - afatal = acritical + async def afatal(self, event: str, *args: Any, **kw: Any) -> None: + """ + Log using `critical()`, but asynchronously in a separate thread. + + .. versionadded:: 23.1.0 + """ + await self._dispatch_to_sync(self.critical, event, args, kw) async def aexception(self, event: str, *args: Any, **kw: Any) -> None: """ @@ -625,7 +635,8 @@ async def info(self, event: str, *args: Any, **kw: Any) -> None: async def warning(self, event: str, *args: Any, **kw: Any) -> None: await self._dispatch_to_sync(self.sync_bl.warning, event, args, kw) - warn = warning + async def warn(self, event: str, *args: Any, **kw: Any) -> None: + await self._dispatch_to_sync(self.sync_bl.warning, event, args, kw) async def error(self, event: str, *args: Any, **kw: Any) -> None: await self._dispatch_to_sync(self.sync_bl.error, event, args, kw) @@ -633,7 +644,8 @@ async def error(self, event: str, *args: Any, **kw: Any) -> None: async def critical(self, event: str, *args: Any, **kw: Any) -> None: await self._dispatch_to_sync(self.sync_bl.critical, event, args, kw) - fatal = critical + async def fatal(self, event: str, *args: Any, **kw: Any) -> None: + await self._dispatch_to_sync(self.sync_bl.critical, event, args, kw) async def exception(self, event: str, *args: Any, **kw: Any) -> None: # To make `log.exception("foo") work, we have to check if the user diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index e79050f9..9bba39f9 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -206,6 +206,15 @@ def test_proxies_to_correct_method(self, method_name): assert method_name == getattr(bl, method_name)("event") + def test_proxies_to_correct_method_special_cases(self): + """ + Fatal maps to critical and warn to warning. + """ + bl = BoundLogger(ReturnLogger(), [return_method_name], {}) + + assert "warning" == bl.warn("event") + assert "critical" == bl.fatal("event") + def test_proxies_log(self): """ BoundLogger.exception.log() is proxied to the appropriate method. @@ -359,6 +368,20 @@ async def test_async_log_methods(self, meth, cl): CapturedCall(method_name=meth, args=(), kwargs={"event": "Async!"}) ] == cl.calls + async def test_async_log_methods_special_cases(self, cl): + """ + afatal maps to critical. + """ + bl = build_bl(cl, processors=[]) + + await bl.afatal("Async!") + + assert [ + CapturedCall( + method_name="critical", args=(), kwargs={"event": "Async!"} + ) + ] == cl.calls + async def test_alog(self, cl): """ Alog logs async at the correct level. @@ -1325,11 +1348,19 @@ async def test_correct_levels(self, abl, cl, stdlib_log_method): aliases = {"warn": "warning"} - alias = aliases.get(stdlib_log_method) - expect = alias if alias else stdlib_log_method + expect = aliases.get(stdlib_log_method, stdlib_log_method) assert expect == cl.calls[0].method_name + @pytest.mark.asyncio + async def test_correct_level_fatal(self, abl, cl): + """ + fatal, that I have no idea why we support, maps to critical. + """ + await abl.bind(foo="bar").fatal("42") + + assert "critical" == cl.calls[0].method_name + @pytest.mark.asyncio async def test_log_method(self, abl, cl): """ From 95905138f9b894c20a8189267102103391b82f7e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 10 Nov 2024 12:06:35 +0100 Subject: [PATCH 1301/1520] docs: new title house style --- .github/CONTRIBUTING.md | 4 ++-- .github/SECURITY.md | 4 ++-- docs/bound-loggers.md | 6 +++--- docs/configuration.md | 6 +++--- docs/console-output.md | 6 +++--- docs/contextvars.md | 2 +- docs/exceptions.md | 2 +- docs/getting-started.md | 8 ++++---- docs/index.md | 8 ++++---- docs/logging-best-practices.md | 6 +++--- docs/processors.md | 4 ++-- docs/recipes.md | 10 +++++----- docs/standard-library.md | 14 +++++++------- docs/thread-local.md | 8 ++++---- docs/twisted.md | 6 +++--- docs/why.md | 10 +++++----- 16 files changed, 52 insertions(+), 52 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 75bbbf78..b488ed05 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -45,7 +45,7 @@ It's people like *you* who make this project such a great tool for everyone. - Don't break [backwards-compatibility](SECURITY.md). -## Local Development Environment +## Local development environment First, **fork** the repository on GitHub and **clone** it using one of the alternatives that you can copy-paste by pressing the big green button labeled `<> Code`. @@ -224,7 +224,7 @@ If your change is interesting to end-users, there needs to be an entry in our `C ``` -## See You on GitHub! +## See you on GitHub! Again, this whole file is mainly to help you to get started by codifying tribal knowledge and expectations to save you time and turnarounds. It is **not** meant to be a barrier to entry, so don't be afraid to open half-finished PRs and ask questions if something is unclear! diff --git a/.github/SECURITY.md b/.github/SECURITY.md index 4357414a..db9b7559 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -1,6 +1,6 @@ # Security Policy -## Supported Versions +## Supported versions We are following [*CalVer*](https://calver.org) with generous backwards-compatibility guarantees. Therefore we only support the latest version. @@ -13,7 +13,7 @@ They may be adjusted in the future to provide a better experience when starting So please make sure to **always** properly configure your applications. -## Reporting a Vulnerability +## Reporting a vulnerability To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. diff --git a/docs/bound-loggers.md b/docs/bound-loggers.md index ac7cb646..deb7254f 100644 --- a/docs/bound-loggers.md +++ b/docs/bound-loggers.md @@ -65,7 +65,7 @@ Whenever you call one of those methods on the *bound logger*, it will: [^str]: {any}`str`, {any}`bytes`, or {any}`bytearray` to be exact. -### Step-by-Step Example +### Step-by-Step example Assuming you've left the default configuration and have: @@ -103,7 +103,7 @@ If you call `log.info("Hello, %s!", "world", number=42)` now, the following happ (filtering)= -## Filtering by Log Levels +## Filtering by log levels Filtering based on log levels can be done in a processor very easily[^stdlib], however that means unnecessary performance overhead through function calls. We care a lot about performance and that's why *structlog*'s default *bound logger* class implements level-filtering as close to the users as possible: in the *bound logger*'s logging methods *before* even creating an *event dict* and starting the processor chain. @@ -146,7 +146,7 @@ Passing `20` instead of `logging.INFO` would have worked too. [^stdlib]: And it's in fact supported for standard library logging with the {func}`structlog.stdlib.filter_by_level` processor. -## Wrapping Loggers Manually +## Wrapping loggers manually In practice, you won't be instantiating bound loggers yourself. You will configure *structlog* as explained in the {doc}`next chapter ` and then just call {func}`structlog.get_logger`. diff --git a/docs/configuration.md b/docs/configuration.md index 9c750d05..ee4cf520 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -51,12 +51,12 @@ See also {doc}`performance`. ::: -## What To Configure +## What to configure You can find the details in the API documentation of {func}`structlog.configure`, but let's introduce the most important ones at a high level first. -### Wrapper Classes +### Wrapper classes You've met {doc}`bound-loggers` in the last chapter. They're the objects returned by {func}`~structlog.get_logger` and allow to bind key-value pairs into their private context. @@ -65,7 +65,7 @@ You can configure their type using the `wrapper_class` keyword. Whenever you bind or unbind data to a *bound logger*, this class is instantiated with the new context and returned. -### Logger Factories +### Logger factories We've already talked about wrapped loggers responsible for the output, but we haven't explained where they come from until now. Unlike with *bound loggers*, you often need more flexibility when instantiating them. diff --git a/docs/console-output.md b/docs/console-output.md index 302342a2..13985f40 100644 --- a/docs/console-output.md +++ b/docs/console-output.md @@ -34,7 +34,7 @@ For the console and beyond. (columns-config)= -## Console Output Configuration +## Console output configuration :::{versionadded} 23.3.0 ::: @@ -106,7 +106,7 @@ structlog.configure(processors=structlog.get_config()["processors"][:-1]+[cr]) ::: -## Standard Environment Variables +## Standard environment variables *structlog*'s default configuration uses colors if standard out is a TTY (that is, an interactive session). @@ -117,6 +117,6 @@ It's possible to override this behavior by setting two standard environment vari Please note that `NO_COLOR` disables _all_ styling, including bold and italics. -## Disabling Exception Pretty-Printing +## Disabling exception pretty-printing If you prefer the default terse Exception rendering, but still want Rich installed, you can disable the pretty-printing by instantiating {class}`structlog.dev.ConsoleRenderer()` yourself and passing `exception_formatter=structlog.dev.plain_traceback`. diff --git a/docs/contextvars.md b/docs/contextvars.md index caead6c9..10c1b1e9 100644 --- a/docs/contextvars.md +++ b/docs/contextvars.md @@ -101,7 +101,7 @@ def _helper(): (flask-example)= -## Example: Flask and Thread-Local Data +## Example: Flask and thread-local data Let's assume you want to bind a unique request ID, the URL path, and the peer's IP to every log entry by storing it in thread-local storage that is managed by context variables: diff --git a/docs/exceptions.md b/docs/exceptions.md index b32fcd86..7fe452ec 100644 --- a/docs/exceptions.md +++ b/docs/exceptions.md @@ -27,7 +27,7 @@ The most common use-cases are already covered by the following processors: : Uses {class}`structlog.tracebacks.ExceptionDictTransformer` to give you a structured and JSON-serializable `exception` key. -## Console Rendering +## Console rendering Our {doc}`console-output`'s {class}`structlog.dev.ConsoleRenderer` takes an *exception_formatter* argument that allows for customizing the output of exceptions. diff --git a/docs/getting-started.md b/docs/getting-started.md index 86a60987..d0042c98 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -16,7 +16,7 @@ Try both to find out which one you like better -- the screenshot in the README a On **Windows**, you also have to install [Colorama](https://pypi.org/project/colorama/) if you want colorful output beside exceptions. -## Your First Log Entry +## Your first log entry A lot of effort went into making *structlog* accessible without reading pages of documentation. As a result, the simplest possible usage looks like this: @@ -81,7 +81,7 @@ So let's go a step further. (building-ctx)= -## Building a Context +## Building a context Imagine a hypothetical web application that wants to log out all relevant data with just the APIs that we've introduced so far: @@ -167,7 +167,7 @@ For that, *structlog* gives you thread-local context storage based on the {mod}` See {doc}`contextvars` for more information and a more complete example. -## Manipulating Log Entries in Flight +## Manipulating log entries in flight Now that your log events are dictionaries, it's also much easier to manipulate them than if they were plain strings. @@ -212,7 +212,7 @@ So assuming you want to follow [best practices](logging-best-practices.md) and r ``` -## *structlog* and Standard Library's `logging` +## *structlog* and standard library's `logging` While *structlog*'s loggers are very fast and sufficient for the majority of our users, you're not bound to them. Instead, it's been designed from day one to wrap your *existing* loggers and **add** *structure* and *incremental context building* to them. diff --git a/docs/index.md b/docs/index.md index 1433430a..c9833440 100644 --- a/docs/index.md +++ b/docs/index.md @@ -62,7 +62,7 @@ exceptions ``` -## Development Affordances +## Development affordances *structlog*'s focus is on production systems, but it comes with **pretty console logging** and handy in-development helpers both for your **comfort** and your code's **quality**. @@ -77,7 +77,7 @@ typing (integration)= -## Integration with Existing Systems +## Integration with existing systems *structlog* is both zero-config as well as highly configurable. You can use it on its own or integrate with existing systems. @@ -93,7 +93,7 @@ twisted ``` -## *structlog* in Practice +## *structlog* in practice The following chapters deal with considerations of using *structlog* in the real world. @@ -121,7 +121,7 @@ modindex ``` -## Deprecated Features +## Deprecated features ```{toctree} :maxdepth: 1 diff --git a/docs/logging-best-practices.md b/docs/logging-best-practices.md index f018a9f6..70a7f2cc 100644 --- a/docs/logging-best-practices.md +++ b/docs/logging-best-practices.md @@ -14,7 +14,7 @@ It doesn't matter where or how your application runs -- it just works, and the r [^unix]: This is obviously a privileged UNIX-centric view but even Windows has tools and means for log management although we won't be able to discuss them here. -## Canonical Log Lines +## Canonical log lines Generally speaking, having as few log entries per request as possible is a good thing. The less noise, the more insights. @@ -24,7 +24,7 @@ The less noise, the more insights. At Stripe, this concept is called [Canonical Log Lines](https://brandur.org/canonical-log-lines). -## Pretty Printing vs. Structured Output +## Pretty printing vs. structured output Colorful and pretty printed log messages are nice during development when you locally run your code. @@ -61,7 +61,7 @@ Here is a simple example of how you can have pretty logs during development and ``` -## Centralized Logging +## Centralized logging Nowadays you usually don't want your log files in compressed archives distributed over dozens -- if not thousands -- of servers or cluster nodes. You want them in a single location. diff --git a/docs/processors.md b/docs/processors.md index 85b4118c..b5f1fc62 100644 --- a/docs/processors.md +++ b/docs/processors.md @@ -124,7 +124,7 @@ It does **not** use the standard library, but it does use its names and order of (adapting)= -## Adapting and Rendering +## Adapting and rendering An important role is played by the *last* processor because its duty is to adapt the `event_dict` into something the logging methods of the *wrapped logger* understand. With that, it's also the *only* processor that needs to know anything about the underlying system. @@ -156,7 +156,7 @@ Advanced log aggregation and analysis tools like [*Logstash*](https://www.elasti For a list of shipped processors, check out the {ref}`API documentation `. -## Third-Party Packages +## Third-Party packages *structlog* was specifically designed to be as composable and reusable as possible, so whatever you're missing: chances are, you can solve it with a processor! diff --git a/docs/recipes.md b/docs/recipes.md index adb4585c..29e786b8 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -7,7 +7,7 @@ Please note that recipes related to integration with frameworks have an [own cha (rename-event)= -## Renaming the `event` Key +## Renaming the `event` key The name of the event is hard-coded in *structlog* to `event`. But that doesn't mean it has to be called that in your logs. @@ -23,7 +23,7 @@ With the {class}`structlog.processors.EventRenamer` processor, you can, for inst (finer-filtering)= -## Fine-Grained Log-Level Filtering +## Fine-grained log-level filtering *structlog*'s native log levels as provided by {func}`structlog.make_filtering_bound_logger` only know **one** log level – the one that is passed to `make_filtering_bound_logger()`. Sometimes, that can be a bit too coarse, though. @@ -78,7 +78,7 @@ Pick the data you're interested in from the {class}`structlog.processors.Callsit (custom-wrappers)= -## Custom Wrappers +## Custom wrappers ```{testsetup} import structlog @@ -141,7 +141,7 @@ These two methods and one attribute are all you need to write own *bound loggers [dry]: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself -## Passing Context to Worker Threads +## Passing context to worker threads Thread-local context data based on [context variables](contextvars.md) is -- as the name says -- local to the thread that binds it. When using threads to process work in parallel, you have to pass the thread-local context **into** the worker threads. @@ -188,7 +188,7 @@ def manager(request_id: str): See the [issue 425](https://github.com/hynek/structlog/issues/425) for a more complete example. -## Switching Console Output to Standard Error +## Switching console output to standard error When using structlog without standard library integration and want the log output to go to standard error (*stderr*) instead of standard out (*stdout*), you can switch with a single line of configuration: diff --git a/docs/standard-library.md b/docs/standard-library.md index 541fcdf6..3b307541 100644 --- a/docs/standard-library.md +++ b/docs/standard-library.md @@ -12,7 +12,7 @@ It will recreate the default configuration on top of `logging` and optionally co ::: -## Just Enough `logging` +## Just enough `logging` If you want to use *structlog* with `logging`, you should have at least a fleeting understanding on how the standard library operates because *structlog* will *not* do any magic things in the background for you. Most importantly you have to *configure* the `logging` system *additionally* to configuring *structlog*. @@ -35,7 +35,7 @@ This will send all log messages with the [log level](https://docs.python.org/3/l If you require more complex behavior, please refer to the standard library's `logging` documentation. -## Concrete Bound Logger +## Concrete bound logger *structlog* ships a stdlib-specific [*bound logger*](bound-loggers.md) that mirrors the log methods of standard library's {any}`logging.Logger` with correct type hints. @@ -125,7 +125,7 @@ To use it, {doc}`configure ` *structlog* to use `AsyncBoundLogger (stdlib-config)= -## Suggested Configurations +## Suggested configurations :::{note} We do appreciate that fully integrating *structlog* with standard library's `logging` is fiddly when done for the first time. @@ -137,7 +137,7 @@ However, once it is set up, you can rely on not having to ever touch it again. Depending *where* you'd like to do your formatting, you can take one of four approaches: -### Don't Integrate +### Don't integrate The most straight-forward option is to configure standard library `logging` close enough to what *structlog* is logging and leaving it at that. @@ -155,7 +155,7 @@ This can cause interleaving of log entries from *structlog* and `logging` logger ::: -### Rendering Within *structlog* +### Rendering within *structlog* This is the simplest approach where *structlog* does all the heavy lifting and passes a fully-formatted string to `logging`. Chances are, this is all you need. @@ -250,7 +250,7 @@ hello ``` -### Rendering Using `logging`-based Formatters +### Rendering using `logging`-based formatters You can choose to use *structlog* only for building the event dictionary and leave all formatting -- additionally to the output -- to the standard library. @@ -328,7 +328,7 @@ Keep this in mind if you only get the event name without any context, and except (processor-formatter)= -### Rendering Using *structlog*-based Formatters Within `logging` +### Rendering using *structlog*-based formatters within `logging` Finally, the most ambitious approach. Here, you use *structlog*'s {class}`~structlog.stdlib.ProcessorFormatter` as a {any}`logging.Formatter` for both `logging` as well as *structlog* log entries. diff --git a/docs/thread-local.md b/docs/thread-local.md index 3ed17dfa..227179e1 100644 --- a/docs/thread-local.md +++ b/docs/thread-local.md @@ -21,7 +21,7 @@ structlog.reset_defaults() ``` -## The `merge_threadlocal` Processor +## The `merge_threadlocal` processor *structlog* provides a simple set of functions that allow explicitly binding certain fields to a global (thread-local) context and merge them later using a processor into the event dict. @@ -43,7 +43,7 @@ These functions map 1:1 to the {doc}`contextvars` APIs, so please use those inst - {func}`structlog.contextvars.get_merged_contextvars` -## Thread-local Contexts +## Thread-local contexts *structlog* also provides thread-local context storage in a form that you may already know from [*Flask*](https://flask.palletsprojects.com/en/latest/design/#thread-locals) and that makes the *entire context* global to your thread or greenlet. @@ -51,7 +51,7 @@ This makes its behavior more difficult to reason about which is why we generally Therefore, there are currently no plans to re-implement this behavior on top of context variables. -### Wrapped Dicts +### Wrapped dicts In order to make your context thread-local, *structlog* ships with a function that can wrap any dict-like class to make it usable for thread-local storage: {func}`structlog.threadlocal.wrap_dict`. @@ -123,7 +123,7 @@ The state before the `with` statement is saved and restored once it's left. If you want to detach a logger from thread-local data, there's {func}`structlog.threadlocal.as_immutable`. -#### Downsides & Caveats +#### Downsides & caveats The convenience of having a thread-local context comes at a price though: diff --git a/docs/twisted.md b/docs/twisted.md index 8629a7f8..3c547264 100644 --- a/docs/twisted.md +++ b/docs/twisted.md @@ -9,7 +9,7 @@ Since `sys.exc_clear` has been dropped in Python 3, there is currently no way to ::: -## Concrete Bound Logger +## Concrete bound logger To make *structlog*'s behavior less magical, it ships with a Twisted-specific wrapper class that has an explicit API instead of improvising: `structlog.twisted.BoundLogger`. It behaves exactly like the generic `structlog.BoundLogger` except: @@ -56,7 +56,7 @@ In order to avoid that *structlog* disturbs your CamelCase harmony, it comes wit That gives you regular and simple-to-parse single-line JSON log entries no matter what happens. -## Bending Foreign Logging To Your Will +## Bending foreign logging to your will *structlog* comes with a wrapper for Twisted's log observers to ensure the rest of your logs are in JSON too: `structlog.twisted.JSONLogObserverWrapper`. @@ -89,7 +89,7 @@ $ twistd -n --logger structlog.twisted.plainJSONStdOutLogger web ... ``` -## Suggested Configuration +## Suggested configuration ```python import structlog diff --git a/docs/why.md b/docs/why.md index a1ac4135..5dd575f9 100644 --- a/docs/why.md +++ b/docs/why.md @@ -1,6 +1,6 @@ # Why … -## … Structured Logging? +## … structured logging? > I believe the widespread use of format strings in logging is based on two presumptions: > @@ -21,7 +21,7 @@ More general advice about production-grade logging can be found in the later cha ## … structlog? -### Easier Logging +### Easier logging You can stop writing prose and start thinking in terms of an event that happens in the context of key-value pairs: @@ -42,7 +42,7 @@ You can still use string interpolation using positional arguments: 2022-10-10 07:19:25 [info ] Hello, world! ``` -### Data Binding +### Data binding Since log entries are dictionaries, you can start binding and re-binding key-value pairs to your loggers to ensure they are present in every following logging call: @@ -56,7 +56,7 @@ Since log entries are dictionaries, you can start binding and re-binding key-val You can also bind key-value pairs to {doc}`context variables ` that look global, but are local to your thread or *asyncio* context -- which usually means your web request. -### Powerful Pipelines +### Powerful pipelines Each log entry goes through a [processor pipeline](processors.md) that is just a chain of functions that receive a dictionary and return a new dictionary that gets fed into the next function. That allows for simple but powerful data manipulation: @@ -103,7 +103,7 @@ Internally, formatters are processors whose return value (usually a string) is p Reported use cases are sending them out via network or saving them to a database. -### Highly Testable +### Highly testable *structlog* is thoroughly tested and we see it as our duty to help you to achieve the same in *your* applications. That's why it ships with a [test helpers](testing.md) to introspect your application's logging behavior with little-to-no boilerplate. From 51641b764085c1b907a9b57857c1e71b2810a70e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 10 Nov 2024 15:07:22 +0100 Subject: [PATCH 1302/1520] Go where the people are --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 28ac2ebe..8734c317 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,6 +35,7 @@ GitHub = "https://github.com/hynek/structlog" Funding = "https://github.com/sponsors/hynek" Tidelift = "https://tidelift.com?utm_source=lifter&utm_medium=referral&utm_campaign=hynek" Mastodon = "https://mastodon.social/@hynek" +Bluesky = "https://bsky.app/profile/hynek.me" Twitter = "https://twitter.com/hynek" [project.optional-dependencies] From 6a111d62f0f9154d96e94a42bc4e5b6776cc9b5a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 15 Nov 2024 10:02:19 +0100 Subject: [PATCH 1303/1520] Map native fatal to critical (#677) Fixes #640 --- CHANGELOG.md | 5 +++++ src/structlog/_native.py | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9267b458..ea0c0efd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,11 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ [#669](https://github.com/hynek/structlog/pull/669) +- The native `FilteringBoundLogger.fatal()` method now maps to the critical level, as it does in the standard library. + Note that the level is discouraged to use there, so we recommend to stick to `error()` or `critical()`. + + [#677](https://github.com/hynek/structlog/pull/677) + ## [24.4.0](https://github.com/hynek/structlog/compare/24.3.0...24.4.0) - 2024-07-17 diff --git a/src/structlog/_native.py b/src/structlog/_native.py index a96e6da2..dedf8a6c 100644 --- a/src/structlog/_native.py +++ b/src/structlog/_native.py @@ -202,8 +202,8 @@ async def alog( meths["exception"] = exception meths["aexception"] = aexception - meths["fatal"] = meths["error"] - meths["afatal"] = meths["aerror"] + meths["fatal"] = meths["critical"] + meths["afatal"] = meths["acritical"] meths["warn"] = meths["warning"] meths["awarn"] = meths["awarning"] meths["msg"] = meths["info"] From a60ce7bbb50451ed786ace3c3893fb3a6a01df0a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 3 Dec 2024 06:43:51 +0100 Subject: [PATCH 1304/1520] Update Ruff --- .pre-commit-config.yaml | 2 +- src/structlog/__init__.py | 18 +++++++++--------- src/structlog/_output.py | 2 +- src/structlog/dev.py | 2 +- src/structlog/processors.py | 8 ++++---- src/structlog/stdlib.py | 14 +++++++------- src/structlog/types.py | 6 +++--- tests/typing/api.py | 1 + 8 files changed, 27 insertions(+), 26 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 944235ea..3ab7f6a5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.7.3 + rev: v0.8.1 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/src/structlog/__init__.py b/src/structlog/__init__.py index 81d26d7c..0c72e360 100644 --- a/src/structlog/__init__.py +++ b/src/structlog/__init__.py @@ -61,23 +61,25 @@ "BoundLoggerBase", "BytesLogger", "BytesLoggerFactory", - "configure_once", + "DropEvent", + "PrintLogger", + "PrintLoggerFactory", + "ReturnLogger", + "ReturnLoggerFactory", + "WriteLogger", + "WriteLoggerFactory", "configure", + "configure_once", "contextvars", "dev", - "DropEvent", + "getLogger", "get_config", "get_context", "get_logger", - "getLogger", "is_configured", "make_filtering_bound_logger", - "PrintLogger", - "PrintLoggerFactory", "processors", "reset_defaults", - "ReturnLogger", - "ReturnLoggerFactory", "stdlib", "testing", "threadlocal", @@ -86,8 +88,6 @@ "types", "typing", "wrap_logger", - "WriteLogger", - "WriteLoggerFactory", ] diff --git a/src/structlog/_output.py b/src/structlog/_output.py index f4ce3b7f..b1612de6 100644 --- a/src/structlog/_output.py +++ b/src/structlog/_output.py @@ -256,7 +256,7 @@ class BytesLogger: .. versionadded:: 20.2.0 """ - __slots__ = ("_file", "_write", "_flush", "_lock") + __slots__ = ("_file", "_flush", "_lock", "_write") def __init__(self, file: BinaryIO | None = None): self._file = file or sys.stdout.buffer diff --git a/src/structlog/dev.py b/src/structlog/dev.py index a3ae8394..40dc636a 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -55,9 +55,9 @@ __all__ = [ "ConsoleRenderer", + "better_traceback", "plain_traceback", "rich_traceback", - "better_traceback", ] _IS_WINDOWS = sys.platform == "win32" diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 65e6e00e..c4803a30 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -43,19 +43,19 @@ __all__ = [ "NAME_TO_LEVEL", # some people rely on it being here - "add_log_level", "CallsiteParameter", "CallsiteParameterAdder", - "dict_tracebacks", "EventRenamer", "ExceptionPrettyPrinter", - "format_exc_info", "JSONRenderer", "KeyValueRenderer", "StackInfoRenderer", "TimeStamper", "UnicodeDecoder", "UnicodeEncoder", + "add_log_level", + "dict_tracebacks", + "format_exc_info", ] @@ -472,7 +472,7 @@ class TimeStamper: .. versionchanged:: 19.2.0 Can be pickled now. """ - __slots__ = ("_stamper", "fmt", "utc", "key") + __slots__ = ("_stamper", "fmt", "key", "utc") def __init__( self, diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 166578be..18db1371 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -39,16 +39,16 @@ __all__ = [ - "add_log_level_number", - "add_log_level", - "add_logger_name", - "ExtraAdder", "BoundLogger", - "filter_by_level", - "get_logger", + "ExtraAdder", "LoggerFactory", "PositionalArgumentsFormatter", "ProcessorFormatter", + "add_log_level", + "add_log_level_number", + "add_logger_name", + "filter_by_level", + "get_logger", "recreate_defaults", "render_to_log_kwargs", ] @@ -521,7 +521,7 @@ class AsyncBoundLogger: Callsite parameters are now also collected for async log methods. """ - __slots__ = ("sync_bl", "_loop") + __slots__ = ("_loop", "sync_bl") #: The wrapped synchronous logger. It is useful to be able to log #: synchronously occasionally. diff --git a/src/structlog/types.py b/src/structlog/types.py index 5d79fd5d..6b48850f 100644 --- a/src/structlog/types.py +++ b/src/structlog/types.py @@ -26,13 +26,13 @@ __all__ = ( - "WrappedLogger", + "BindableLogger", "Context", "EventDict", - "Processor", "ExcInfo", "ExceptionRenderer", "ExceptionTransformer", - "BindableLogger", "FilteringBoundLogger", + "Processor", + "WrappedLogger", ) diff --git a/tests/typing/api.py b/tests/typing/api.py index d4e1afe6..102cfe80 100644 --- a/tests/typing/api.py +++ b/tests/typing/api.py @@ -29,6 +29,7 @@ def bytes_dumps( __obj: Any, + /, default: Callable[[Any], Any] | None = None, option: int | None = None, ) -> bytes: From d03d1ef342fb228c6a89eb8693de050765dd0468 Mon Sep 17 00:00:00 2001 From: Bruce Christensen Date: Fri, 6 Dec 2024 01:42:45 -0800 Subject: [PATCH 1305/1520] Fix a small typo. (#683) --- docs/why.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/why.md b/docs/why.md index 5dd575f9..98d8a898 100644 --- a/docs/why.md +++ b/docs/why.md @@ -81,7 +81,7 @@ There are [plenty of processors](structlog.processors) for most common tasks com Since each log entry is a dictionary, it can be formatted to **any** format: - A colorful key-value format for [local development](console-output.md), -- [JSON](structlog.processors.JSONRenderer) of [*logfmt*](structlog.processors.LogfmtRenderer) for easy parsing, +- [JSON](structlog.processors.JSONRenderer) or [*logfmt*](structlog.processors.LogfmtRenderer) for easy parsing, - or some standard format you have parsers for like *nginx* or Apache *httpd*. Internally, formatters are processors whose return value (usually a string) is passed into loggers that are responsible for the output of your message. From 41bf7d43588b71684e3253f682d2ecb3991bb27c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 9 Dec 2024 10:42:47 +0100 Subject: [PATCH 1306/1520] Sponsors: add emsys cc @sscherfke --- README.md | 1 + docs/_static/sponsors/emsys-renewables.svg | 1 + docs/index.md | 1 + pyproject.toml | 5 +++++ 4 files changed, 8 insertions(+) create mode 100644 docs/_static/sponsors/emsys-renewables.svg diff --git a/README.md b/README.md index 29daf8dd..165d2625 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ for sponsor in tomllib.loads(pathlib.Path("pyproject.toml").read_text())["tool"] + diff --git a/docs/_static/sponsors/emsys-renewables.svg b/docs/_static/sponsors/emsys-renewables.svg new file mode 100644 index 00000000..d5738cec --- /dev/null +++ b/docs/_static/sponsors/emsys-renewables.svg @@ -0,0 +1 @@ + diff --git a/docs/index.md b/docs/index.md index c9833440..f81227de 100644 --- a/docs/index.md +++ b/docs/index.md @@ -22,6 +22,7 @@ for sponsor in tomllib.loads(pathlib.Path("pyproject.toml").read_text())["tool"] + diff --git a/pyproject.toml b/pyproject.toml index 8734c317..7f768f0e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -260,6 +260,11 @@ title = "Klaviyo" url = "https://klaviyo.com/" img = "Klaviyo.svg" +[[tool.sponcon.sponsors]] +title = "emsys renewables" +url = "https://www.emsys-renewables.com/" +img = "emsys-renewables.svg" + [[tool.sponcon.sponsors]] title = "FilePreviews" url = "https://filepreviews.io/" From e51f34705d0e6c6551ca0915eded697dc99f0e57 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 14 Dec 2024 15:11:26 +0100 Subject: [PATCH 1307/1520] Run Zizmor with token --- .github/workflows/zizmor.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index 2a8b5bf2..cde16a0a 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -10,9 +10,10 @@ on: permissions: contents: read + jobs: zizmor: - name: Zizmor latest via Cargo + name: Zizmor latest via PyPI runs-on: ubuntu-latest permissions: security-events: write @@ -21,12 +22,13 @@ jobs: uses: actions/checkout@v4 with: persist-credentials: false - - name: Setup Rust - uses: actions-rust-lang/setup-rust-toolchain@v1 - - name: Get zizmor - run: cargo install zizmor - - name: Run zizmor - run: zizmor --format sarif . > results.sarif + - uses: hynek/setup-cached-uv@v2 + + - name: Run zizmor 🌈 + run: uvx zizmor --format sarif . > results.sarif + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Upload SARIF file uses: github/codeql-action/upload-sarif@v3 with: From 6f822dc6caba09bf9b0f712c8cd8eed552dd9e48 Mon Sep 17 00:00:00 2001 From: David Nies Date: Sat, 4 Jan 2025 12:04:17 +0100 Subject: [PATCH 1308/1520] Make sure locals_max_{length,string} work as expected in case they are None (#675) * Make sure locals_max_{length,string} work as expected in case they are None * Update tests/test_tracebacks.py --------- Co-authored-by: Hynek Schlawack --- src/structlog/tracebacks.py | 4 ++-- tests/test_tracebacks.py | 40 +++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/structlog/tracebacks.py b/src/structlog/tracebacks.py index 2392b342..8fada4da 100644 --- a/src/structlog/tracebacks.py +++ b/src/structlog/tracebacks.py @@ -382,10 +382,10 @@ def __init__( max_frames: int = MAX_FRAMES, use_rich: bool = True, ) -> None: - if locals_max_length < 0: + if locals_max_length is not None and locals_max_length < 0: msg = f'"locals_max_length" must be >= 0: {locals_max_length}' raise ValueError(msg) - if locals_max_string < 0: + if locals_max_string is not None and locals_max_string < 0: msg = f'"locals_max_string" must be >= 0: {locals_max_string}' raise ValueError(msg) if max_frames < 2: diff --git a/tests/test_tracebacks.py b/tests/test_tracebacks.py index a086a042..f8d0f1e5 100644 --- a/tests/test_tracebacks.py +++ b/tests/test_tracebacks.py @@ -531,6 +531,46 @@ def bar(n): ] +@pytest.mark.parametrize( + ("kwargs", "local_variable"), + [ + ( + {"locals_max_string": None}, + "x" * (tracebacks.LOCALS_MAX_STRING + 10), + ), + ( + {"locals_max_length": None}, + list(range(tracebacks.LOCALS_MAX_LENGTH + 10)), + ), + ], +) +def test_exception_dict_transformer_locals_max_accept_none_argument( + kwargs, local_variable +): + """ + ExceptionDictTransformer works when either locals_max_string or + locals_max_length is set to None. + """ + + try: + my_local = local_variable + 1 / 0 + except Exception as e: + format_json = tracebacks.ExceptionDictTransformer( + show_locals=True, **kwargs + ) + result = format_json((type(e), e, e.__traceback__)) + + _ = my_local + + assert len(result) == 1 + assert len(result[0]["frames"]) == 1 + + frame = result[0]["frames"][0] + + assert frame["locals"]["my_local"].strip("'") == str(local_variable) + + def test_json_traceback(): """ Tracebacks are formatted to JSON with all information. From 3ba1c2e6dddfe543cd508f1414f0be41d70a593f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 4 Jan 2025 12:09:05 +0100 Subject: [PATCH 1309/1520] Add changelog for #675 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea0c0efd..ea129dcd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,10 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ [#677](https://github.com/hynek/structlog/pull/677) +- `structlog.tracebacks.ExceptionDictTransformer` now actually accepts `None` `locals_max_length` and `locals_max_string`. + + [#675](https://github.com/hynek/structlog/pull/675) + ## [24.4.0](https://github.com/hynek/structlog/compare/24.3.0...24.4.0) - 2024-07-17 From df8ff6397e705e563602f502828341223cb1a1cd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 4 Jan 2025 12:14:26 +0100 Subject: [PATCH 1310/1520] Add versionchanged --- CHANGELOG.md | 2 +- src/structlog/tracebacks.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea129dcd..cc53c62f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,7 +43,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ [#677](https://github.com/hynek/structlog/pull/677) -- `structlog.tracebacks.ExceptionDictTransformer` now actually accepts `None` `locals_max_length` and `locals_max_string`. +- `structlog.tracebacks.ExceptionDictTransformer` now actually accepts `None` for `locals_max_length` and `locals_max_string`. [#675](https://github.com/hynek/structlog/pull/675) diff --git a/src/structlog/tracebacks.py b/src/structlog/tracebacks.py index 8fada4da..b5c4b433 100644 --- a/src/structlog/tracebacks.py +++ b/src/structlog/tracebacks.py @@ -368,6 +368,10 @@ class ExceptionDictTransformer: .. versionchanged:: 24.3.0 Added *locals_max_length*, *locals_hide_sunder*, *locals_hide_dunder*, *suppress* and *use_rich* arguments. + + .. versionchanged:: 25.1.0 + *locals_max_length* and *locals_max_string* may be None to disable + truncation. """ def __init__( From 8ff0f8ad1cdebdf31d52eab1142a1d4b497ba166 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 4 Jan 2025 12:14:39 +0100 Subject: [PATCH 1311/1520] Update Ruff --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3ab7f6a5..d8ab80ac 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.8.1 + rev: v0.8.5 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From 234b6fe02da138379a58f0fd409d95358b4f0b68 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 4 Jan 2025 14:45:02 +0100 Subject: [PATCH 1312/1520] Ruff: fix TC new name --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 7f768f0e..a745df2f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -145,7 +145,7 @@ ignore = [ "RUF001", # leave my smart characters alone "SLF001", # private members are accessed by friendly functions "T201", # prints are fine - "TCH", # TYPE_CHECKING blocks break autodocs + "TC", # TYPE_CHECKING blocks break autodocs "TD", # we don't follow other people's todo style "TID252", # Relative imports are fine "TRY003", # simple strings are fine From 2f7298ac4214f5b47fde3808f14dc1e4c80aa0b7 Mon Sep 17 00:00:00 2001 From: Stefan Scherfke Date: Sun, 5 Jan 2025 13:26:57 +0100 Subject: [PATCH 1313/1520] Handle Logger.exception() outside "except" block (#680) * Handle Logger.exception() outside "except" block Fixes: #634 * Continue fixing * Try a more radical approach to fix _figure_out_exc_info() The main problem of the function is that *v* can really be anything (depending on what the users) do and the annotated return type did not properly match it (e.g., if *v* was "0", the return value would be "0"). The function now rigorously checks the user input and either returns the desired result (an exc info tuple) or None. This makes it easier and safer to use this function. * Revert #657 The changes introduced in #657 are no longer needed since _format_exception() is now only called if _figure_out_exc_info() detects an actual exception * Simplify branch condition * Apply suggestions from code review Co-authored-by: Hynek Schlawack * Add changelog entry Also remove the entry for the now obsolete #657 --------- Co-authored-by: Hynek Schlawack --- CHANGELOG.md | 11 +++-- src/structlog/_frames.py | 10 ---- src/structlog/dev.py | 6 +-- src/structlog/processors.py | 39 ++++++++++------ src/structlog/tracebacks.py | 4 -- tests/processors/test_renderers.py | 8 ++-- tests/test_dev.py | 5 +- tests/test_tracebacks.py | 75 ++++++++++++++++++++++++++++-- 8 files changed, 110 insertions(+), 48 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc53c62f..f8cf7148 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,9 +30,14 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ## Fixed -- `structlog.traceback.ExceptionDictTransformer` now correctly handles missing exceptions. - - [#657](https://github.com/hynek/structlog/pull/657) +- Fix handling calls to `{logger}.exception()` outside of exception blocks. + Depending on the structlog configuration, + this either resulted in an event dict key `exception: "MISSING"` or lead to an error. + Now, an invalid or missing `exc_info` will just be ignored. + This means, that calling `{logger}.exception()` outside of an exception block is basically the same as calling `{logger}.error()`. + + [#634](https://github.com/hynek/structlog/issues/634) + [#680](https://github.com/hynek/structlog/pull/680) - Instantiating `structlog.dev.ConsoleRenderer` does not mutate the passed *styles* dict anymore. diff --git a/src/structlog/_frames.py b/src/structlog/_frames.py index 1eb8e7c9..6acd7549 100644 --- a/src/structlog/_frames.py +++ b/src/structlog/_frames.py @@ -16,22 +16,12 @@ from .typing import ExcInfo -def is_missing_exc_info(exc_info: ExcInfo) -> bool: - """ - Return True if exc_info is the missing value. - """ - return exc_info == (None, None, None) # type: ignore[comparison-overlap] - - def _format_exception(exc_info: ExcInfo) -> str: """ Prettyprint an `exc_info` tuple. Shamelessly stolen from stdlib's logging module. """ - if is_missing_exc_info(exc_info): - return "MISSING" - sio = StringIO() traceback.print_exception(exc_info[0], exc_info[1], exc_info[2], None, sio) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 40dc636a..38b02df0 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -733,11 +733,9 @@ def __call__( if exc_info or exc is not None: sio.write("\n\n" + "=" * 79 + "\n") + exc_info = _figure_out_exc_info(exc_info) if exc_info: - exc_info = _figure_out_exc_info(exc_info) - - if exc_info != (None, None, None): - self._exception_formatter(sio, exc_info) + self._exception_formatter(sio, exc_info) elif exc is not None: if self._exception_formatter is not plain_traceback: warnings.warn( diff --git a/src/structlog/processors.py b/src/structlog/processors.py index c4803a30..ac1bd98c 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -19,7 +19,7 @@ import threading import time -from types import FrameType +from types import FrameType, TracebackType from typing import ( Any, Callable, @@ -28,6 +28,7 @@ NamedTuple, Sequence, TextIO, + cast, ) from ._frames import ( @@ -38,7 +39,12 @@ from ._log_levels import NAME_TO_LEVEL, add_log_level from ._utils import get_processname from .tracebacks import ExceptionDictTransformer -from .typing import EventDict, ExceptionTransformer, ExcInfo, WrappedLogger +from .typing import ( + EventDict, + ExceptionTransformer, + ExcInfo, + WrappedLogger, +) __all__ = [ @@ -407,11 +413,9 @@ def __init__( def __call__( self, logger: WrappedLogger, name: str, event_dict: EventDict ) -> EventDict: - exc_info = event_dict.pop("exc_info", None) + exc_info = _figure_out_exc_info(event_dict.pop("exc_info", None)) if exc_info: - event_dict["exception"] = self.format_exception( - _figure_out_exc_info(exc_info) - ) + event_dict["exception"] = self.format_exception(exc_info) return event_dict @@ -586,21 +590,30 @@ def __call__( return event_dict -def _figure_out_exc_info(v: Any) -> ExcInfo: +def _figure_out_exc_info(v: Any) -> ExcInfo | None: """ - Depending on the Python version will try to do the smartest thing possible - to transform *v* into an ``exc_info`` tuple. + Try to convert *v* into an ``exc_info`` tuple. + + Return ``None`` if *v* does not represent an exception or if there is no + current exception. """ if isinstance(v, BaseException): return (v.__class__, v, v.__traceback__) - if isinstance(v, tuple): - return v + if isinstance(v, tuple) and len(v) == 3: + has_type = isinstance(v[0], type) and issubclass(v[0], BaseException) + has_exc = isinstance(v[1], BaseException) + has_tb = v[2] is None or isinstance(v[2], TracebackType) + if has_type and has_exc and has_tb: + return v if v: - return sys.exc_info() # type: ignore[return-value] + result = sys.exc_info() + if result == (None, None, None): + return None + return cast(ExcInfo, result) - return v + return None class ExceptionPrettyPrinter: diff --git a/src/structlog/tracebacks.py b/src/structlog/tracebacks.py index b5c4b433..96ab71e6 100644 --- a/src/structlog/tracebacks.py +++ b/src/structlog/tracebacks.py @@ -22,8 +22,6 @@ from types import ModuleType, TracebackType from typing import Any, Iterable, Sequence, Tuple, Union -from ._frames import is_missing_exc_info - try: import rich @@ -418,8 +416,6 @@ def __init__( self.use_rich = use_rich def __call__(self, exc_info: ExcInfo) -> list[dict[str, Any]]: - if is_missing_exc_info(exc_info): - return [] trace = extract( *exc_info, show_locals=self.show_locals, diff --git a/tests/processors/test_renderers.py b/tests/processors/test_renderers.py index 8f225c80..9fa24e5c 100644 --- a/tests/processors/test_renderers.py +++ b/tests/processors/test_renderers.py @@ -514,12 +514,12 @@ def test_nop_missing(self): def test_formats_tuple(self): """ - If exc_info is a tuple, it is used. + If exc_info is an arbitrary 3-tuple, it is not used. """ formatter = ExceptionRenderer(lambda exc_info: exc_info) d = formatter(None, None, {"exc_info": (None, None, 42)}) - assert {"exception": (None, None, 42)} == d + assert {} == d def test_gets_exc_info_on_bool(self): """ @@ -580,6 +580,4 @@ def test_no_exception(self, ei): """ A missing exception does not blow up. """ - assert {"exception": "MISSING"} == format_exc_info( - None, None, {"exc_info": ei} - ) + assert {} == format_exc_info(None, None, {"exc_info": ei}) diff --git a/tests/test_dev.py b/tests/test_dev.py index 1193c040..89871300 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -545,10 +545,7 @@ def test_no_exception(self): r = dev.ConsoleRenderer(colors=False) assert ( - "hi" - == r( - None, None, {"event": "hi", "exc_info": (None, None, None)} - ).rstrip() + "hi" == r(None, None, {"event": "hi", "exc_info": None}).rstrip() ) def test_columns_warns_about_meaningless_arguments(self, recwarn): diff --git a/tests/test_tracebacks.py b/tests/test_tracebacks.py index f8d0f1e5..42a5b75c 100644 --- a/tests/test_tracebacks.py +++ b/tests/test_tracebacks.py @@ -15,6 +15,8 @@ import pytest +import structlog + from structlog import tracebacks @@ -772,12 +774,75 @@ def test_json_traceback_value_error( tracebacks.ExceptionDictTransformer(**kwargs) -def test_exception_dict_transformer_missing_exc_info(): +class TestLogException: """ - ExceptionDictTransformer returns an empty list if exc_info is missing. + Higher level integration tests for `Logger.exception()`. """ - transformer = tracebacks.ExceptionDictTransformer() - result = transformer(exc_info=(None, None, None)) + @pytest.fixture + def cap_logs(self) -> structlog.testing.LogCapture: + """ + Create a LogCapture to be used as processor and fixture for retrieving + logs in tests. + """ + return structlog.testing.LogCapture() + + @pytest.fixture + def logger( + self, cap_logs: structlog.testing.LogCapture + ) -> structlog.Logger: + """ + Create a logger with the dict_tracebacks and a LogCapture processor. + """ + old_processors = structlog.get_config()["processors"] + structlog.configure([structlog.processors.dict_tracebacks, cap_logs]) + logger = structlog.get_logger("dict_tracebacks") + try: + yield logger + finally: + structlog.configure(processors=old_processors) + + def test_log_explicit_exception( + self, logger: structlog.Logger, cap_logs: structlog.testing.LogCapture + ) -> None: + """ + The log row contains a traceback when `Logger.exception()` is + explicitly called with an exception instance. + """ + try: + 1 / 0 + except ZeroDivisionError as e: + logger.exception("onoes", exception=e) + + log_row = cap_logs.entries[0] + + assert log_row["exception"][0]["exc_type"] == "ZeroDivisionError" + + def test_log_implicit_exception( + self, logger: structlog.Logger, cap_logs: structlog.testing.LogCapture + ) -> None: + """ + The log row contains a traceback when `Logger.exception()` is called + in an `except` block but without explicitly passing the exception. + """ + try: + 1 / 0 + except ZeroDivisionError: + logger.exception("onoes") + + log_row = cap_logs.entries[0] + + assert log_row["exception"][0]["exc_type"] == "ZeroDivisionError" + + def test_no_exception( + self, logger: structlog.Logger, cap_logs: structlog.testing.LogCapture + ) -> None: + """ + `Logger.exception()` should not be called outside an `except` block + but this cases is gracefully handled and does not lead to an exception. + + See: https://github.com/hynek/structlog/issues/634 + """ + logger.exception("onoes") - assert [] == result + assert [{"event": "onoes", "log_level": "error"}] == cap_logs.entries From b488a8bf589a01aabc41e3bf8df81a9848cd426c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 7 Jan 2025 06:46:04 +0100 Subject: [PATCH 1314/1520] [pre-commit.ci] pre-commit autoupdate (#688) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.8.5 → v0.8.6](https://github.com/astral-sh/ruff-pre-commit/compare/v0.8.5...v0.8.6) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d8ab80ac..1202728b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.8.5 + rev: v0.8.6 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From ab23bbe6b04f257fabaa2d8c5418b86f43b1246e Mon Sep 17 00:00:00 2001 From: Denis Savran Date: Sun, 12 Jan 2025 14:19:03 +0300 Subject: [PATCH 1315/1520] Add 'structlog.stdlib.render_to_log_args_and_kwargs' processor (#668) * Add 'structlog.stdlib.render_to_log_args_and_kwargs' processor * Update docs/standard-library.md * Update src/structlog/stdlib.py * Update CHANGELOG.md --------- Co-authored-by: Denis Savran Co-authored-by: Hynek Schlawack --- CHANGELOG.md | 8 ++ docs/api.rst | 4 +- docs/standard-library.md | 21 +++-- src/structlog/stdlib.py | 46 +++++++++-- tests/test_stdlib.py | 167 ++++++++++++++++++++++++++++++++++++++- tests/typing/api.py | 8 ++ 6 files changed, 239 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8cf7148..fb438f9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,14 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ## [Unreleased](https://github.com/hynek/structlog/compare/24.4.0...HEAD) +### Added + +- Add `structlog.stdlib.render_to_log_args_and_kwargs` processor. + Same as `structlog.stdlib.render_to_log_kwargs`, but also allows to pass positional arguments to `logging`. + With it, you do not need to add `structlog.stdlib.PositionalArgumentsFormatter` processor to format positional arguments from *structlog* loggers. + [#668](https://github.com/hynek/structlog/pull/668) + + ## Changed - `structlog.typing.BindableLogger` protocol now returns `Self` instead of `BindableLogger`. diff --git a/docs/api.rst b/docs/api.rst index 6879f1e0..9eaf1fcc 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -303,6 +303,8 @@ API Reference .. autoclass:: LoggerFactory :members: __call__ +.. autofunction:: render_to_log_args_and_kwargs + .. autofunction:: render_to_log_kwargs .. autofunction:: filter_by_level @@ -313,7 +315,7 @@ API Reference .. autofunction:: add_logger_name -.. autofunction:: ExtraAdder +.. autoclass:: ExtraAdder .. autoclass:: PositionalArgumentsFormatter diff --git a/docs/standard-library.md b/docs/standard-library.md index 3b307541..95991f61 100644 --- a/docs/standard-library.md +++ b/docs/standard-library.md @@ -77,11 +77,16 @@ To use it, {doc}`configure ` *structlog* to use `AsyncBoundLogger *structlog* comes with a few standard library-specific processors: -{func}`~structlog.stdlib.render_to_log_kwargs`: +{func}`~structlog.stdlib.render_to_log_args_and_kwargs`: -: Renders the event dictionary into keyword arguments for `logging.log` that attaches everything except the `event` field to the *extra* argument. +: Renders the event dictionary into positional and keyword arguments for `logging.Logger` logging methods. This is useful if you want to render your log entries entirely within `logging`. +{func}`~structlog.stdlib.render_to_log_kwargs`: + +: Same as above, but does not support passing positional arguments from *structlog* loggers to `logging.Logger` logging methods as positional arguments. + *structlog* positional arguments are still passed to `logging` under `positional_args` key of `extra` keyword argument. + {func}`~structlog.stdlib.filter_by_level`: : Checks the log entry's log level against the configuration of standard library's logging. @@ -92,12 +97,6 @@ To use it, {doc}`configure ` *structlog* to use `AsyncBoundLogger : Adds the name of the logger to the event dictionary under the key `logger`. -{func}`~structlog.stdlib.ExtraAdder`: - -: Add extra attributes of `logging.LogRecord` objects to the event dictionary. - - This processor can be used for adding data passed in the `extra` parameter of the `logging` module's log methods to the event dictionary. - {func}`~structlog.stdlib.add_log_level`: : Adds the log level to the event dictionary under the key `level`. @@ -117,6 +116,12 @@ To use it, {doc}`configure ` *structlog* to use `AsyncBoundLogger The mapping of names to numbers is in `structlog.stdlib._NAME_TO_LEVEL`. +{class}`~structlog.stdlib.ExtraAdder`: + +: Add extra attributes of `logging.LogRecord` objects to the event dictionary. + +This processor can be used for adding data passed in the `extra` parameter of the `logging` module's log methods to the event dictionary. + {func}`~structlog.stdlib.PositionalArgumentsFormatter`: : This processes and formats positional arguments (if any) passed to log methods in the same way the `logging` module would do, for example, `logger.info("Hello, %s", name)`. diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 18db1371..282bf7c1 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -50,6 +50,7 @@ "filter_by_level", "get_logger", "recreate_defaults", + "render_to_log_args_and_kwargs", "render_to_log_kwargs", ] @@ -885,15 +886,50 @@ def _copy_allowed( event_dict[key] = record.__dict__[key] +LOG_KWARG_NAMES = ("exc_info", "stack_info", "stacklevel") + + +def render_to_log_args_and_kwargs( + _: logging.Logger, __: str, event_dict: EventDict +) -> tuple[tuple[Any, ...], dict[str, Any]]: + """ + Render ``event_dict`` into positional and keyword arguments for + `logging.Logger` logging methods. + See `logging.Logger.debug` method for keyword arguments reference. + + The ``event`` field is passed in the first positional argument, positional + arguments from ``positional_args`` field are passed in subsequent positional + arguments, keyword arguments are extracted from the *event_dict* and the + rest of the *event_dict* is added as ``extra``. + + This allows you to defer formatting to `logging`. + + .. versionadded:: 25.1.0 + """ + args = (event_dict.pop("event"), *event_dict.pop("positional_args", ())) + + kwargs = { + kwarg_name: event_dict.pop(kwarg_name) + for kwarg_name in LOG_KWARG_NAMES + if kwarg_name in event_dict + } + if event_dict: + kwargs["extra"] = event_dict + + return args, kwargs + + def render_to_log_kwargs( _: logging.Logger, __: str, event_dict: EventDict ) -> EventDict: """ - Render ``event_dict`` into keyword arguments for `logging.log`. - See `logging.Logger`'s ``_log`` method for kwargs reference. + Render ``event_dict`` into keyword arguments for `logging.Logger` logging + methods. + See `logging.Logger.debug` method for keyword arguments reference. - The ``event`` field is translated into ``msg`` and the rest of the - *event_dict* is added as ``extra``. + The ``event`` field is translated into ``msg``, keyword arguments are + extracted from the *event_dict* and the rest of the *event_dict* is added as + ``extra``. This allows you to defer formatting to `logging`. @@ -909,7 +945,7 @@ def render_to_log_kwargs( "extra": event_dict, **{ kw: event_dict.pop(kw) - for kw in ("exc_info", "stack_info", "stacklevel") + for kw in LOG_KWARG_NAMES if kw in event_dict }, } diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 9bba39f9..383e60dd 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -46,6 +46,7 @@ filter_by_level, get_logger, recreate_defaults, + render_to_log_args_and_kwargs, render_to_log_kwargs, ) from structlog.testing import CapturedCall @@ -706,7 +707,171 @@ def _stdlib_logger(): logging.basicConfig() -class TestRenderToLogKW: +class TestRenderToLogArgsAndKwargs: + def test_default(self, stdlib_logger: logging.Logger): + """ + Passes `event` key from `event_dict` in the first positional argument + and handles otherwise empty `event_dict`. + """ + method_name = "debug" + event = "message" + args, kwargs = render_to_log_args_and_kwargs( + stdlib_logger, method_name, {"event": event} + ) + + assert (event,) == args + assert {} == kwargs + + with patch.object(stdlib_logger, "_log") as mock_log: + getattr(stdlib_logger, method_name)(*args, **kwargs) + + mock_log.assert_called_once_with(logging.DEBUG, event, ()) + + def test_pass_remaining_event_dict_as_extra( + self, stdlib_logger: logging.Logger, event_dict: dict[str, Any] + ): + """ + Passes remaining `event_dict` as `extra`. + """ + expected_extra = event_dict.copy() + + method_name = "info" + event = "message" + event_dict["event"] = event + + args, kwargs = render_to_log_args_and_kwargs( + stdlib_logger, method_name, event_dict + ) + + assert (event,) == args + assert {"extra": expected_extra} == kwargs + + with patch.object(stdlib_logger, "_log") as mock_log: + getattr(stdlib_logger, method_name)(*args, **kwargs) + + mock_log.assert_called_once_with( + logging.INFO, event, (), extra=expected_extra + ) + + def test_pass_positional_args_from_event_dict_as_args( + self, stdlib_logger: logging.Logger, event_dict: dict[str, Any] + ): + """ + Passes items from "positional_args" key from `event_dict` as positional + arguments. + """ + expected_extra = event_dict.copy() + + method_name = "warning" + event = "message: a = %s, b = %d" + positional_args = ("foo", 123) + event_dict["event"] = event + event_dict["positional_args"] = positional_args + + args, kwargs = render_to_log_args_and_kwargs( + stdlib_logger, method_name, event_dict + ) + + assert (event, *(positional_args)) == args + assert {"extra": expected_extra} == kwargs + + with patch.object(stdlib_logger, "_log") as mock_log: + getattr(stdlib_logger, method_name)(*args, **kwargs) + + mock_log.assert_called_once_with( + logging.WARNING, event, positional_args, extra=expected_extra + ) + + def test_pass_kwargs_from_event_dict_as_kwargs( + self, stdlib_logger: logging.Logger, event_dict: dict[str, Any] + ): + """ + Passes "exc_info", "stack_info", and "stacklevel" keys from `event_dict` + as keyword arguments. + """ + expected_extra = event_dict.copy() + + method_name = "info" + event = "message" + exc_info = True + stack_info = False + stacklevel = 2 + event_dict["event"] = event + event_dict["exc_info"] = exc_info + event_dict["stack_info"] = stack_info + event_dict["stacklevel"] = stacklevel + + args, kwargs = render_to_log_args_and_kwargs( + stdlib_logger, method_name, event_dict + ) + + assert (event,) == args + assert { + "exc_info": exc_info, + "stack_info": stack_info, + "stacklevel": stacklevel, + "extra": expected_extra, + } == kwargs + + with patch.object(stdlib_logger, "_log") as mock_log: + getattr(stdlib_logger, method_name)(*args, **kwargs) + + mock_log.assert_called_once_with( + logging.INFO, + event, + (), + exc_info=exc_info, + stack_info=stack_info, + stacklevel=stacklevel, + extra=expected_extra, + ) + + def test_integration( + self, stdlib_logger: logging.Logger, event_dict: dict[str, Any] + ): + """ + `render_to_log_args_and_kwargs` with a wrapped logger calls the stdlib + logger correctly. + + Reserved stdlib keyword arguments are in `logging.Logger._log`. + https://github.com/python/cpython/blob/60403a5409ff2c3f3b07dd2ca91a7a3e096839c7/Lib/logging/__init__.py#L1640 + """ + event = "message: a = %s, b = %d" + arg_1 = "foo" + arg_2 = 123 + exc_info = False + stack_info = True + stacklevel = 3 + + struct_logger = wrap_logger( + stdlib_logger, + processors=[render_to_log_args_and_kwargs], + wrapper_class=BoundLogger, + ) + + with patch.object(stdlib_logger, "_log") as mock_log: + struct_logger.info( + event, + arg_1, + arg_2, + exc_info=exc_info, + stack_info=stack_info, + stacklevel=stacklevel, + **event_dict, + ) + + mock_log.assert_called_once_with( + logging.INFO, + event, + (arg_1, arg_2), + exc_info=exc_info, + stack_info=stack_info, + stacklevel=stacklevel, + extra=event_dict, + ) + + +class TestRenderToLogKwargs: def test_default(self, stdlib_logger): """ Translates `event` to `msg` and handles otherwise empty `event_dict`s. diff --git a/tests/typing/api.py b/tests/typing/api.py index 102cfe80..fa47c5e1 100644 --- a/tests/typing/api.py +++ b/tests/typing/api.py @@ -44,6 +44,14 @@ def bytes_dumps( processors=[structlog.processors.JSONRenderer(serializer=bytes_dumps)] ) +structlog.configure( + processors=[ + structlog.stdlib.render_to_log_args_and_kwargs, + ], + logger_factory=structlog.stdlib.LoggerFactory(), + wrapper_class=structlog.stdlib.BoundLogger, + cache_logger_on_first_use=True, +) structlog.configure( processors=[ From 2a317b73ea7c0f9bedab9305c8d0e3bd9219a0c6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 12 Jan 2025 12:45:27 +0100 Subject: [PATCH 1316/1520] stdlib: add PositionalArgumensFormatter to recreate_defaults This matches the behavior of native loggers. --- CHANGELOG.md | 3 +++ src/structlog/stdlib.py | 2 ++ 2 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb438f9d..598f30df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ [#647](https://github.com/hynek/structlog/pull/647) +- `structlog.stdlib.recreate_defaults()` now also adds `structlog.stdlib.PositionalArgumentsFormatter`. + In default native mode, this is done by the loggers at the edge. + ## Fixed diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 282bf7c1..b43f2433 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -76,6 +76,7 @@ def recreate_defaults(*, log_level: int | None = logging.NOTSET) -> None: .. versionadded:: 22.1.0 .. versionchanged:: 23.3.0 Added `add_logger_name`. + .. versionchanged:: 25.1.0 Added `PositionalArgumentsFormatter`. """ if log_level is not None: kw = {"force": True} @@ -90,6 +91,7 @@ def recreate_defaults(*, log_level: int | None = logging.NOTSET) -> None: _config.reset_defaults() _config.configure( processors=[ + PositionalArgumentsFormatter(), # handled by native loggers merge_contextvars, add_log_level, add_logger_name, From af4733e4a2a095911910a19a1a52333ec0fd9983 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 12 Jan 2025 12:45:56 +0100 Subject: [PATCH 1317/1520] Update Ruff --- .pre-commit-config.yaml | 2 +- docs/conf.py | 2 +- src/structlog/testing.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1202728b..3ba36cf4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.8.6 + rev: v0.9.1 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/docs/conf.py b/docs/conf.py index fc28d61a..b4c06ffd 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -56,7 +56,7 @@ # General information about the project. project = "structlog" author = "Hynek Schlawack" -copyright = f"2013, { author }" +copyright = f"2013, {author}" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/src/structlog/testing.py b/src/structlog/testing.py index 35ad87dd..293c6184 100644 --- a/src/structlog/testing.py +++ b/src/structlog/testing.py @@ -177,7 +177,7 @@ def __init__(self) -> None: self.calls = [] def __repr__(self) -> str: - return f"" + return f"" def __getattr__(self, name: str) -> Any: """ From 51f97bf2b2b443194a902f780f49fb55ee38fe29 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 12 Jan 2025 12:50:20 +0100 Subject: [PATCH 1318/1520] Remove unused warnings filter --- pyproject.toml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index a745df2f..0a3ff080 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,10 +71,7 @@ raw-options = { local_scheme = "no-local-version" } addopts = ["-ra", "--strict-markers", "--strict-config"] testpaths = "tests" xfail_strict = true -filterwarnings = [ - "once::Warning", - 'ignore:datetime.datetime.utcfromtimestamp\(\) is deprecated:DeprecationWarning:dateutil.tz', -] +filterwarnings = ["once::Warning"] asyncio_mode = "auto" asyncio_default_fixture_loop_scope = "function" From 6af2807ce83572ef10279a911cd205c3d546922c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 13 Jan 2025 07:38:31 +0100 Subject: [PATCH 1319/1520] docs: write out --- .github/SECURITY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/SECURITY.md b/.github/SECURITY.md index db9b7559..d65b3c31 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -2,7 +2,7 @@ ## Supported versions -We are following [*CalVer*](https://calver.org) with generous backwards-compatibility guarantees. +We are following [Calendar Versioning](https://calver.org) with generous backwards-compatibility guarantees. Therefore we only support the latest version. Put simply, you shouldn't ever be afraid to upgrade as long as you're only using our public APIs. From d43b2cb767a598e17b992c935566259ec87d53bf Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 13 Jan 2025 08:44:21 +0100 Subject: [PATCH 1320/1520] Inter is cliche now --- docs/_static/custom.css | 6 +++--- docs/conf.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/_static/custom.css b/docs/_static/custom.css index fc58887c..b0c135ed 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -1,4 +1,4 @@ -@import url('https://rsms.me/inter/inter.css'); +@import url(https://fonts.bunny.net/css?family=b612:400,400i,700,700i); @import url('https://assets.hynek.me/css/bm.css'); @@ -9,7 +9,7 @@ @supports (font-variation-settings: normal) { :root { - font-family: InterVariable, sans-serif; + font-family: 'B612', sans-serif; } } @@ -17,4 +17,4 @@ /* Hide ToC caption text within the main body (but leave them in the side-bar). */ #furo-main-content span.caption-text { display: none; -} \ No newline at end of file +} diff --git a/docs/conf.py b/docs/conf.py index b4c06ffd..6f1b2c0d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -102,7 +102,7 @@ html_theme_options = { "top_of_page_buttons": [], "light_css_variables": { - "font-stack": "Inter, sans-serif", + "font-stack": "B612, sans-serif", "font-stack--monospace": "BerkeleyMono, MonoLisa, ui-monospace, " "SFMono-Regular, Menlo, Consolas, Liberation Mono, monospace", }, From c7a6a101fdf644fd8c1ece7388ff1405895f3a4a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 13 Jan 2025 09:29:05 +0100 Subject: [PATCH 1321/1520] Allow make_filtering_bound_logger to receive a str for level fixes #665 --- CHANGELOG.md | 2 ++ src/structlog/_native.py | 12 +++++++++++- tests/test_log_levels.py | 10 ++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 598f30df..d85cc191 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,8 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - `structlog.stdlib.recreate_defaults()` now also adds `structlog.stdlib.PositionalArgumentsFormatter`. In default native mode, this is done by the loggers at the edge. +- `structlog.make_filtering_bound_logger()` now also accepts a string for *min_level*. + ## Fixed diff --git a/src/structlog/_native.py b/src/structlog/_native.py index dedf8a6c..86bb7d4e 100644 --- a/src/structlog/_native.py +++ b/src/structlog/_native.py @@ -22,6 +22,7 @@ ERROR, INFO, LEVEL_TO_NAME, + NAME_TO_LEVEL, NOTSET, WARNING, ) @@ -70,7 +71,9 @@ async def aexception( return runner -def make_filtering_bound_logger(min_level: int) -> type[FilteringBoundLogger]: +def make_filtering_bound_logger( + min_level: int | str, +) -> type[FilteringBoundLogger]: """ Create a new `FilteringBoundLogger` that only logs *min_level* or higher. @@ -103,12 +106,19 @@ def make_filtering_bound_logger(min_level: int) -> type[FilteringBoundLogger]: `_ for possible values. + If you pass a string, it must be one of: ``critical``, ``error``, + ``warning``, ``info``, ``debug``, ``notset`` (upper/lower case + doesn't matter). + .. versionadded:: 20.2.0 .. versionchanged:: 21.1.0 The returned loggers are now pickleable. .. versionadded:: 20.1.0 The ``log()`` method. .. versionadded:: 22.2.0 Async variants ``alog()``, ``adebug()``, ``ainfo()``, and so forth. + .. versionchanged:: 25.1.0 *min_level* can now be a string. """ + if isinstance(min_level, str): + min_level = NAME_TO_LEVEL[min_level.lower()] return LEVEL_TO_FILTERING_LOGGER[min_level] diff --git a/tests/test_log_levels.py b/tests/test_log_levels.py index 2dec4f08..30aa7a79 100644 --- a/tests/test_log_levels.py +++ b/tests/test_log_levels.py @@ -10,6 +10,7 @@ from structlog import make_filtering_bound_logger from structlog._log_levels import LEVEL_TO_NAME +from structlog._native import _nop from structlog.contextvars import ( bind_contextvars, clear_contextvars, @@ -314,3 +315,12 @@ def test_log_percent(self, bl, cl): bl.info("hey %! %%!") assert [("info", (), {"event": "hey %! %%!"})] == cl.calls + + def test_log_level_str(self): + """ + *min_level* can be a string and the case doesn't matter. + """ + bl = make_filtering_bound_logger("wArNiNg") + + assert bl.warning is not _nop + assert bl.info is _nop From 8688c323641f2d241f31ad5705560f55f57a5e65 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 13 Jan 2025 10:56:27 +0100 Subject: [PATCH 1322/1520] docs: use uv & 3.13 for build (#690) * docs: use uv & 3.13 for build * Add unused config to appease RTD --- .github/workflows/ci.yml | 2 +- .readthedocs.yaml | 26 +++++++++++--------------- tox.ini | 7 ++++--- 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a7c0b25e..5dd2c213 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -184,7 +184,7 @@ jobs: - uses: actions/setup-python@v5 with: # Keep in sync with tox.ini/docs & .readthedocs.yaml - python-version: "3.12" + python-version: "3.13" - uses: hynek/setup-cached-uv@v2 - run: > diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 8ba33e0f..71410923 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -5,20 +5,16 @@ build: os: ubuntu-lts-latest tools: # Keep version in sync with tox.ini/docs and ci.yml/docs. - python: "3.12" - jobs: - # Need the tags to calculate the version. - post_checkout: - - git fetch --tags + python: "3.13" + commands: + # Need the tags to calculate the version (sometimes). + - git fetch --tags + - asdf plugin add uv + - asdf install uv latest + - asdf global uv latest - # Replace versions in sponsor URLs. - pre_build: - - python -Im pip install tox-uv - - python -Im tox run -e docs-sponsors + - uvx --with tox-uv tox run -e docs-sponsors + - uvx --with tox-uv tox run -e docs -- $READTHEDOCS_OUTPUT -python: - install: - - method: pip - path: . - extra_requirements: - - docs +sphinx: + configuration: docs/conf.py diff --git a/tox.ini b/tox.ini index 9defe0bd..7c9aedb1 100644 --- a/tox.ini +++ b/tox.ini @@ -45,11 +45,12 @@ commands = [testenv:docs] # Keep base_python in sync with ci.yml/docs and .readthedocs.yaml. -base_python = py312 +base_python = py313 extras = docs commands = - sphinx-build -n -T -W -b html -d {envtmpdir}/doctrees docs docs/_build/html - sphinx-build -n -T -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html + sphinx-build -n -T -W -b html -d {envtmpdir}/doctrees docs {posargs:docs/_build/}html + sphinx-build -n -T -W -b doctest -d {envtmpdir}/doctrees docs {posargs:docs/_build/}html + [testenv:docs-watch] package = editable From e97b83935e143d796c1ade553a609511239d5c36 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 15 Jan 2025 07:34:06 +0100 Subject: [PATCH 1323/1520] native loggers: add is_enabled_for & get_effective_level (#689) * native loggers: add is_enabled_for & get_effective_level fixes #685 * add PR# --- CHANGELOG.md | 3 +++ src/structlog/_native.py | 4 ++++ src/structlog/typing.py | 14 ++++++++++++++ tests/{test_log_levels.py => test_native.py} | 18 +++++++++++++++++- tests/typing/api.py | 15 +++++++-------- 5 files changed, 45 insertions(+), 9 deletions(-) rename tests/{test_log_levels.py => test_native.py} (94%) diff --git a/CHANGELOG.md b/CHANGELOG.md index d85cc191..c21bf9ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ With it, you do not need to add `structlog.stdlib.PositionalArgumentsFormatter` processor to format positional arguments from *structlog* loggers. [#668](https://github.com/hynek/structlog/pull/668) +- Native loggers now have `is_enabled_for()` and `get_effective_level()` methods that mirror the behavior of the standard library's `logging.Logger.isEnabledFor()` and `logging.Logger.getEffectiveLevel()`. + [#689](https://github.com/hynek/structlog/pull/689) + ## Changed diff --git a/src/structlog/_native.py b/src/structlog/_native.py index 86bb7d4e..43d732b5 100644 --- a/src/structlog/_native.py +++ b/src/structlog/_native.py @@ -219,6 +219,10 @@ async def alog( meths["msg"] = meths["info"] meths["amsg"] = meths["ainfo"] + # Introspection + meths["is_enabled_for"] = lambda self, level: level >= min_level + meths["get_effective_level"] = lambda self: min_level + return type( f"BoundLoggerFilteringAt{LEVEL_TO_NAME.get(min_level, 'Notset').capitalize()}", (BoundLoggerBase,), diff --git a/src/structlog/typing.py b/src/structlog/typing.py index 222e0496..4fe9e0cd 100644 --- a/src/structlog/typing.py +++ b/src/structlog/typing.py @@ -190,6 +190,20 @@ def new(self, **new_values: Any) -> FilteringBoundLogger: .. versionadded:: 22.1.0 """ + def is_enabled_for(self, level: int) -> bool: + """ + Check whether the logger is enabled for *level*. + + .. versionadded:: 25.1.0 + """ + + def get_effective_level(self) -> int: + """ + Return the effective level of the logger. + + .. versionadded:: 25.1.0 + """ + def debug(self, event: str, *args: Any, **kw: Any) -> Any: """ Log ``event % args`` with **kw** at **debug** level. diff --git a/tests/test_log_levels.py b/tests/test_native.py similarity index 94% rename from tests/test_log_levels.py rename to tests/test_native.py index 30aa7a79..2d152e72 100644 --- a/tests/test_log_levels.py +++ b/tests/test_native.py @@ -23,7 +23,23 @@ def _bl(cl): return make_filtering_bound_logger(logging.INFO)(cl, [], {}) -class TestFilteringLogger: +class TestNativeFilteringLogger: + def test_is_enabled_for(self, bl): + """ + is_enabled_for returns True if the log level is enabled. + """ + assert bl.is_enabled_for(20) + assert bl.is_enabled_for(logging.INFO) + + assert not bl.is_enabled_for(19) + assert not bl.is_enabled_for(logging.DEBUG) + + def test_get_effective_level(self, bl): + """ + get_effective_level returns the log level. + """ + assert 20 == logging.INFO == bl.get_effective_level() + def test_exact_level(self, bl, cl): """ if log level is exactly the min_level, log. diff --git a/tests/typing/api.py b/tests/typing/api.py index fa47c5e1..1ca1b91c 100644 --- a/tests/typing/api.py +++ b/tests/typing/api.py @@ -44,17 +44,10 @@ def bytes_dumps( processors=[structlog.processors.JSONRenderer(serializer=bytes_dumps)] ) -structlog.configure( - processors=[ - structlog.stdlib.render_to_log_args_and_kwargs, - ], - logger_factory=structlog.stdlib.LoggerFactory(), - wrapper_class=structlog.stdlib.BoundLogger, - cache_logger_on_first_use=True, -) structlog.configure( processors=[ + structlog.stdlib.render_to_log_args_and_kwargs, structlog.stdlib.filter_by_level, structlog.stdlib.add_logger_name, structlog.stdlib.add_log_level, @@ -359,3 +352,9 @@ def typecheck_bound_logger_return() -> None: fbl: FilteringBoundLogger = structlog.get_logger() fbl.info("Hello %s! The answer is %d.", "World", 42, x=1) + + +# Introspection +level: int = fbl.get_effective_level() +is_active: bool = fbl.is_enabled_for(logging.INFO) +is_active = fbl.is_enabled_for(20) From bc147a45f97cbe2e4676999600236eb2d1f2fc12 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 16 Jan 2025 10:35:26 +0100 Subject: [PATCH 1324/1520] Only build in RTD and only doctests in CI (#691) * Only build in RTD and only doctests in CI * Adjust CI and contributing docs --- .github/CONTRIBUTING.md | 10 ++++++++-- .github/workflows/ci.yml | 4 ++-- .readthedocs.yaml | 21 +++++++++++---------- tox.ini | 19 +++++++------------ 4 files changed, 28 insertions(+), 26 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index b488ed05..53d8b094 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -93,14 +93,20 @@ $ tox run -e docs-watch This will build the documentation, watch for changes, and rebuild it whenever you save a file. -To just build the documentation and run doctests, use: +To just build the documentation and exit immediately use: ```console -$ tox run -e docs +$ tox run -e docs-build ``` You will find the built documentation in `docs/_build/html`. +To run doctests: + +```console +$ tox run -e docs-doctests +``` + ## Code diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5dd2c213..ac4fb547 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -171,7 +171,7 @@ jobs: docs: - name: Build docs & run doctests + name: Run doctests needs: build-package runs-on: ubuntu-latest steps: @@ -189,7 +189,7 @@ jobs: - run: > uvx --with tox-uv - tox run -e docs + tox run -e docs-doctests install-dev: diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 71410923..d58ce338 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -6,15 +6,16 @@ build: tools: # Keep version in sync with tox.ini/docs and ci.yml/docs. python: "3.13" - commands: - # Need the tags to calculate the version (sometimes). - - git fetch --tags - - asdf plugin add uv - - asdf install uv latest - - asdf global uv latest + jobs: + create_environment: + # Need the tags to calculate the version (sometimes). + - git fetch --tags - - uvx --with tox-uv tox run -e docs-sponsors - - uvx --with tox-uv tox run -e docs -- $READTHEDOCS_OUTPUT + - asdf plugin add uv + - asdf install uv latest + - asdf global uv latest -sphinx: - configuration: docs/conf.py + build: + html: + - uvx --with tox-uv tox run -e docs-sponsors + - uvx --with tox-uv tox run -e docs-build -- $READTHEDOCS_OUTPUT diff --git a/tox.ini b/tox.ini index 7c9aedb1..005c8f20 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,7 @@ env_list = mypy-pkg, py3{8,9,10,11,12,13}-{tests,mypy} py3{8,13}-tests-{colorama,be,rich}, - docs{,-sponsors}, + docs-{sponsors,doctests}, coverage-report @@ -43,19 +43,19 @@ commands = coverage report -[testenv:docs] +[testenv:docs-{build,doctests,linkcheck}] # Keep base_python in sync with ci.yml/docs and .readthedocs.yaml. base_python = py313 extras = docs commands = - sphinx-build -n -T -W -b html -d {envtmpdir}/doctrees docs {posargs:docs/_build/}html - sphinx-build -n -T -W -b doctest -d {envtmpdir}/doctrees docs {posargs:docs/_build/}html - + build: sphinx-build -n -T -W -b html -d {envtmpdir}/doctrees docs {posargs:docs/_build/}html + doctests: sphinx-build -n -T -W -b doctest -d {envtmpdir}/doctrees docs {posargs:docs/_build/}html + linkcheck: sphinx-build -W -b linkcheck -d {envtmpdir}/doctrees docs docs/_build/html [testenv:docs-watch] package = editable -base_python = {[testenv:docs]base_python} -extras = {[testenv:docs]extras} +base_python = {[testenv:docs-build]base_python} +extras = {[testenv:docs-build]extras} deps = watchfiles commands = watchfiles \ @@ -64,11 +64,6 @@ commands = src \ docs -[testenv:docs-linkcheck] -base_python = {[testenv:docs]base_python} -extras = {[testenv:docs]extras} -commands = sphinx-build -W -b linkcheck -d {envtmpdir}/doctrees docs docs/_build/html - [testenv:docs-sponsors] description = Ensure sponsor logos are up to date. deps = cogapp From 4350cdd2d495a18ae29d72c8ee6596fa3409f7bd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 16 Jan 2025 10:55:39 +0100 Subject: [PATCH 1325/1520] Try if test PyPI will deduct the correct license with lower 2.3 metadata --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 0a3ff080..af4e411e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 [build-system] -requires = ["hatchling", "hatch-vcs", "hatch-fancy-pypi-readme>=22.8.0"] +requires = ["hatchling<1.27.0", "hatch-vcs", "hatch-fancy-pypi-readme>=22.8.0"] build-backend = "hatchling.build" From 02d072aad9e2a5ea41165d296794c7a45dbbd9a0 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 16 Jan 2025 11:00:46 +0100 Subject: [PATCH 1326/1520] Makes no difference --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index af4e411e..0a3ff080 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 [build-system] -requires = ["hatchling<1.27.0", "hatch-vcs", "hatch-fancy-pypi-readme>=22.8.0"] +requires = ["hatchling", "hatch-vcs", "hatch-fancy-pypi-readme>=22.8.0"] build-backend = "hatchling.build" From 3eab3e9e5ee981af0b40c8dbda0ac400b0578793 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 16 Jan 2025 11:05:02 +0100 Subject: [PATCH 1327/1520] Fix changelog headings --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c21bf9ea..d1c5964c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,7 +26,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ [#689](https://github.com/hynek/structlog/pull/689) -## Changed +### Changed - `structlog.typing.BindableLogger` protocol now returns `Self` instead of `BindableLogger`. This adds a dependency on [*typing-extensions*](https://pypi.org/project/typing-extensions/) for Pythons older than 3.11. @@ -44,7 +44,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - `structlog.make_filtering_bound_logger()` now also accepts a string for *min_level*. -## Fixed +### Fixed - Fix handling calls to `{logger}.exception()` outside of exception blocks. Depending on the structlog configuration, From c5803e89f693ebeaf21351dc59af55afd353fe51 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 16 Jan 2025 11:07:12 +0100 Subject: [PATCH 1328/1520] Consistency --- CHANGELOG.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1c5964c..6016c136 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,12 +30,10 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - `structlog.typing.BindableLogger` protocol now returns `Self` instead of `BindableLogger`. This adds a dependency on [*typing-extensions*](https://pypi.org/project/typing-extensions/) for Pythons older than 3.11. - [#642](https://github.com/hynek/structlog/pull/642) [#659](https://github.com/hynek/structlog/pull/659) - `structlog.dev.ConsoleRenderer` will quote string value with special characters. - [#647](https://github.com/hynek/structlog/pull/647) - `structlog.stdlib.recreate_defaults()` now also adds `structlog.stdlib.PositionalArgumentsFormatter`. @@ -51,21 +49,17 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ this either resulted in an event dict key `exception: "MISSING"` or lead to an error. Now, an invalid or missing `exc_info` will just be ignored. This means, that calling `{logger}.exception()` outside of an exception block is basically the same as calling `{logger}.error()`. - [#634](https://github.com/hynek/structlog/issues/634) [#680](https://github.com/hynek/structlog/pull/680) - Instantiating `structlog.dev.ConsoleRenderer` does not mutate the passed *styles* dict anymore. - [#669](https://github.com/hynek/structlog/pull/669) - The native `FilteringBoundLogger.fatal()` method now maps to the critical level, as it does in the standard library. Note that the level is discouraged to use there, so we recommend to stick to `error()` or `critical()`. - [#677](https://github.com/hynek/structlog/pull/677) - `structlog.tracebacks.ExceptionDictTransformer` now actually accepts `None` for `locals_max_length` and `locals_max_string`. - [#675](https://github.com/hynek/structlog/pull/675) From a38a5ac5d6e7a461b0c304294b7446a2bf674410 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 16 Jan 2025 11:09:21 +0100 Subject: [PATCH 1329/1520] Prepare 25.1.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6016c136..6ee908ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ -## [Unreleased](https://github.com/hynek/structlog/compare/24.4.0...HEAD) +## [25.1.0](https://github.com/hynek/structlog/compare/24.4.0...25.1.0) - 2025-01-16 ### Added From 2197fbc45c38e59d469c713f1287a368e019e3d5 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 16 Jan 2025 11:14:18 +0100 Subject: [PATCH 1330/1520] Start new development cycle --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ee908ef..6dc05515 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ +## [Unreleased](https://github.com/hynek/structlog/compare/25.1.0...HEAD) + + ## [25.1.0](https://github.com/hynek/structlog/compare/24.4.0...25.1.0) - 2025-01-16 ### Added From 177f346d61214c64bd94e1c975b1d437e13a4790 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 21 Jan 2025 05:58:24 +0100 Subject: [PATCH 1331/1520] docs: stdlib polish --- docs/standard-library.md | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/docs/standard-library.md b/docs/standard-library.md index 95991f61..ad30b2e3 100644 --- a/docs/standard-library.md +++ b/docs/standard-library.md @@ -32,7 +32,7 @@ logging.basicConfig( This will send all log messages with the [log level](https://docs.python.org/3/library/logging.html#logging-levels) `logging.INFO` and above (that means that, for example, `logging.debug` calls are ignored) to standard out without any special formatting by the standard library. -If you require more complex behavior, please refer to the standard library's `logging` documentation. +If you require more complex behavior, please refer to the standard library's {mod}`logging` documentation. ## Concrete bound logger @@ -48,7 +48,7 @@ See also {doc}`typing`. ### `asyncio` -For `asyncio` applications, you may not want your whole application to block while the processor chain is formatting your log entries. +In {mod}`asyncio` applications, you may not want your whole application to block while the processor chain is formatting your log entries. For that use case *structlog* comes with a set of non-standard methods that will do all processing in a thread pool executor. They have the same names as the regular methods, except they are prefixed by an `a`. @@ -151,7 +151,7 @@ Since these are usually log entries from third parties that don't take advantage For instance, if you log JSON in production, configure `logging` to use [*python-json-logger*] to make it print JSON too, and then tweak the configuration to match their outputs. You can also use {class}`~structlog.stdlib.ProcessorFormatter` as a formatter for `logging` to get the same output for both *structlog* and `logging` log entries -- see [below](processor-formatter) for an example. -:::{note} +:::{important} If you want to use same file (for example, `sys.stdout` or `sys.stderr`) for both *structlog* and `logging.StreamHandler` output, you must use {class}`~structlog.WriteLogger` instead of {class}`~structlog.PrintLogger`. This is because {class}`~structlog.PrintLogger` uses `print(log, file=file, flush=True)` to write log, and `print` writes the `log` message and a newline ("\n") to the stream separately. @@ -171,7 +171,8 @@ Chances are, this is all you need. flowchart TD User structlog - stdlib[Standard Library\ne.g. logging.StreamHandler] + stdlib[Standard Library + e.g. logging.StreamHandler] User --> |"structlog.get_logger().info('foo')"| structlog User --> |"logging.getLogger().info('foo')"| stdlib @@ -231,7 +232,7 @@ structlog.configure( ) ``` -To make your program behave like a proper [*12 Factor App*](https://12factor.net/logs) that outputs only JSON to `stdout`, configure the `logging` module like this: +To make your program behave like a proper [12 Factor App](https://12factor.net/logs) that outputs only JSON to `stdout`, configure the `logging` module like this: ``` import logging @@ -265,7 +266,8 @@ You can choose to use *structlog* only for building the event dictionary and lea flowchart TD User structlog - stdlib[Standard Library\ne.g. logging.StreamHandler] + stdlib[Standard Library + e.g. logging.StreamHandler] User --> |"structlog.get_logger().info('foo', bar=42)"| structlog User --> |"logging.getLogger().info('foo')"| stdlib @@ -354,9 +356,11 @@ flowchart TD structlog --> |"logging.getLogger().info(event_dict, {#quot;extra#quot;: {#quot;_logger#quot;: logger, #quot;_name#quot;: name})"| stdlib stdlib --> |"structlog.stdlib.ProcessorFormatter.format(logging.Record)"| structlog2 - structlog2 --> |"Returns a string that is passed into logging handlers.\nThis flow is controlled by the logging configuration."| stdlib2 + structlog2 --> |"Returns a string that is passed into logging handlers. + This flow is controlled by the logging configuration."| stdlib2 - stdlib2[Standard Library\ne.g. logging.StreamHandler] ==> Output + stdlib2[Standard Library + e.g. logging.StreamHandler] ==> Output ``` {class}`~structlog.stdlib.ProcessorFormatter` has two parts to its API: From fe29e5c227effb7321a90445ae8c78ae54b3477c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 21 Jan 2025 05:58:40 +0100 Subject: [PATCH 1332/1520] update ruff --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3ba36cf4..769998e9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.9.1 + rev: v0.9.2 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From 20f246f264b1395de4f86ee6d1b5adb837b12894 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 22 Jan 2025 06:43:24 +0100 Subject: [PATCH 1333/1520] docset: ust --icon-2x instead of cp --- tox.ini | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index 005c8f20..4873754a 100644 --- a/tox.ini +++ b/tox.ini @@ -109,6 +109,5 @@ allowlist_externals = commands = rm -rf structlog.docset structlog.tgz docs/_build sphinx-build -n -T -W -b html -d {envtmpdir}/doctrees docs docs/_build/html - doc2dash --index-page index.html --icon docs/_static/docset-icon.png --online-redirect-url https://www.structlog.org/en/latest/ docs/_build/html - cp docs/_static/docset-icon@2x.png structlog.docset/icon@2x.png + doc2dash --index-page index.html --icon docs/_static/docset-icon.png --icon-2x docs/_static/docset-icon@2x.png --online-redirect-url https://www.structlog.org/en/latest/ docs/_build/html tar --exclude='.DS_Store' -cvzf structlog.tgz structlog.docset From 0fe98409b55b37e82842c12ed8c8baabe9f2a001 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 22 Jan 2025 10:02:16 +0100 Subject: [PATCH 1334/1520] sponsors: add Privacy Solutions --- README.md | 1 + docs/_static/sponsors/Privacy-Solutions.svg | 1 + docs/index.md | 1 + pyproject.toml | 5 +++++ 4 files changed, 8 insertions(+) create mode 100644 docs/_static/sponsors/Privacy-Solutions.svg diff --git a/README.md b/README.md index 165d2625..bd7e50a2 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ for sponsor in tomllib.loads(pathlib.Path("pyproject.toml").read_text())["tool"] + diff --git a/docs/_static/sponsors/Privacy-Solutions.svg b/docs/_static/sponsors/Privacy-Solutions.svg new file mode 100644 index 00000000..f8e9593d --- /dev/null +++ b/docs/_static/sponsors/Privacy-Solutions.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index f81227de..f09755db 100644 --- a/docs/index.md +++ b/docs/index.md @@ -24,6 +24,7 @@ for sponsor in tomllib.loads(pathlib.Path("pyproject.toml").read_text())["tool"] + diff --git a/pyproject.toml b/pyproject.toml index 0a3ff080..7b3a59a8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -267,6 +267,11 @@ title = "FilePreviews" url = "https://filepreviews.io/" img = "FilePreviews.svg" +[[tool.sponcon.sponsors]] +title = "Privacy Solutions" +url = "https://privacy-solutions.org/" +img = "Privacy-Solutions.svg" + [[tool.sponcon.sponsors]] title = "Polar" url = "https://polar.sh/" From a35ee318a1a8f8b7e8b1279a5ccc1892bb8ec288 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 22 Jan 2025 10:07:34 +0100 Subject: [PATCH 1335/1520] Add white background --- docs/_static/sponsors/Privacy-Solutions.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_static/sponsors/Privacy-Solutions.svg b/docs/_static/sponsors/Privacy-Solutions.svg index f8e9593d..d7f68d23 100644 --- a/docs/_static/sponsors/Privacy-Solutions.svg +++ b/docs/_static/sponsors/Privacy-Solutions.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file From 42452dc16a6877c00b859615a119284d785344bf Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 22 Jan 2025 10:13:37 +0100 Subject: [PATCH 1336/1520] Fix aspect --- docs/_static/sponsors/Privacy-Solutions.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_static/sponsors/Privacy-Solutions.svg b/docs/_static/sponsors/Privacy-Solutions.svg index d7f68d23..d742309b 100644 --- a/docs/_static/sponsors/Privacy-Solutions.svg +++ b/docs/_static/sponsors/Privacy-Solutions.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file From 03b514304ee4299f7532a5db45eeee6fa5d0c5f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yannick=20P=C3=89ROUX?= Date: Mon, 27 Jan 2025 08:24:07 +0100 Subject: [PATCH 1337/1520] Typing: return Self in stdlib.BoundLogger (#694) * Typing: use Self in BoundLogger * Fix missing import * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fix Self import for Python < 3.11 --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Hynek Schlawack --- src/structlog/stdlib.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index b43f2433..dd953863 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -21,6 +21,13 @@ from functools import partial from typing import Any, Callable, Collection, Dict, Iterable, Sequence, cast + +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self + + from . import _config from ._base import BoundLoggerBase from ._frames import _find_first_app_frame_and_name, _format_stack @@ -155,13 +162,13 @@ class BoundLogger(BoundLoggerBase): _logger: logging.Logger - def bind(self, **new_values: Any) -> BoundLogger: + def bind(self, **new_values: Any) -> Self: """ Return a new logger with *new_values* added to the existing ones. """ return super().bind(**new_values) - def unbind(self, *keys: str) -> BoundLogger: + def unbind(self, *keys: str) -> Self: """ Return a new logger with *keys* removed from the context. @@ -170,7 +177,7 @@ def unbind(self, *keys: str) -> BoundLogger: """ return super().unbind(*keys) - def try_unbind(self, *keys: str) -> BoundLogger: + def try_unbind(self, *keys: str) -> Self: """ Like :meth:`unbind`, but best effort: missing keys are ignored. @@ -178,7 +185,7 @@ def try_unbind(self, *keys: str) -> BoundLogger: """ return super().try_unbind(*keys) - def new(self, **new_values: Any) -> BoundLogger: + def new(self, **new_values: Any) -> Self: """ Clear context and binds *initial_values* using `bind`. From 4eb2646586469e84e46caf087d842542d015c28c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 27 Jan 2025 08:24:54 +0100 Subject: [PATCH 1338/1520] Add changelog entry for #694 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6dc05515..837d3d5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,11 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ## [Unreleased](https://github.com/hynek/structlog/compare/25.1.0...HEAD) +### Changed + +- `structlog.stdlib.BoundLogger`'s binding-related methods now also return `Self`. + [#694](https://github.com/hynek/structlog/pull/694) + ## [25.1.0](https://github.com/hynek/structlog/compare/24.4.0...25.1.0) - 2025-01-16 From d8f4e6ea099a327469e5cd3b015209cb13062335 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 27 Jan 2025 08:27:07 +0100 Subject: [PATCH 1339/1520] pre-commit autoupdate --- .pre-commit-config.yaml | 6 +++--- docs/thread-local.md | 2 +- src/structlog/_base.py | 2 +- src/structlog/stdlib.py | 2 +- src/structlog/testing.py | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 769998e9..5dec266b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.9.2 + rev: v0.9.3 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] @@ -17,10 +17,10 @@ repos: args: [tests] - repo: https://github.com/codespell-project/codespell - rev: v2.3.0 + rev: v2.4.0 hooks: - id: codespell - args: [-L, alog] + args: [-L, alog, -L, abl] - repo: https://github.com/pre-commit/pre-commit-hooks rev: v5.0.0 diff --git a/docs/thread-local.md b/docs/thread-local.md index 227179e1..44fa789b 100644 --- a/docs/thread-local.md +++ b/docs/thread-local.md @@ -128,7 +128,7 @@ If you want to detach a logger from thread-local data, there's {func}`structlog. The convenience of having a thread-local context comes at a price though: :::{warning} -- If you can't rule out that your application re-uses threads, you *must* remember to **initialize your thread-local context** at the start of each request using {func}`~structlog.BoundLogger.new` (instead of {func}`~structlog.BoundLogger.bind`). +- If you can't rule out that your application reuses threads, you *must* remember to **initialize your thread-local context** at the start of each request using {func}`~structlog.BoundLogger.new` (instead of {func}`~structlog.BoundLogger.bind`). Otherwise you may start a new request with the context still filled with data from the request before. - **Don't** stop assigning the results of your `bind()`s and `new()`s! diff --git a/src/structlog/_base.py b/src/structlog/_base.py index 3342a8f7..dab02754 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -111,7 +111,7 @@ def new(self, **new_values: Any) -> Self: Only necessary with dict implementations that keep global state like those wrapped by `structlog.threadlocal.wrap_dict` when threads - are re-used. + are reused. """ self._context.clear() diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index dd953863..80ee628d 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -191,7 +191,7 @@ def new(self, **new_values: Any) -> Self: Only necessary with dict implementations that keep global state like those wrapped by `structlog.threadlocal.wrap_dict` when threads - are re-used. + are reused. """ return super().new(**new_values) diff --git a/src/structlog/testing.py b/src/structlog/testing.py index 293c6184..797372da 100644 --- a/src/structlog/testing.py +++ b/src/structlog/testing.py @@ -194,7 +194,7 @@ class CapturingLoggerFactory: r""" Produce and cache `CapturingLogger`\ s. - Each factory produces and re-uses only **one** logger. + Each factory produces and reuses only **one** logger. You can access it via the ``logger`` attribute. From c2de5c347dfb607ee11f6de56b8bbba0e43b7df9 Mon Sep 17 00:00:00 2001 From: Camillo Date: Sun, 2 Feb 2025 21:22:52 -0800 Subject: [PATCH 1340/1520] Include notes when logging exceptions (#684) * Include notes when logging exceptions This adds support for the notes feature from https://peps.python.org/pep-0678/, which was introduced in Python 3.11. * update docs * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * skip notes tests before 3.11 * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * update api.rst example * link PR in changelog * make exc_notes a tuple * fix docs * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * update next version * shorter * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Make exc_notes a list for consistency ref https://github.com/hynek/structlog/pull/684#discussion_r1938791139 --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Hynek Schlawack --- CHANGELOG.md | 6 ++++ docs/api.rst | 2 +- src/structlog/tracebacks.py | 7 ++++ tests/test_tracebacks.py | 70 +++++++++++++++++++++++++++++++++++++ 4 files changed, 84 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 837d3d5a..572cf83e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,12 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ## [Unreleased](https://github.com/hynek/structlog/compare/25.1.0...HEAD) +### Added + +- `structlog.tracebacks.Stack` now includes an `exc_notes` field reflecting the notes attached to the exception. + [#684](https://github.com/hynek/structlog/pull/684) + + ### Changed - `structlog.stdlib.BoundLogger`'s binding-related methods now also return `Self`. diff --git a/docs/api.rst b/docs/api.rst index 9eaf1fcc..3719756a 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -197,7 +197,7 @@ API Reference ... 1 / 0 ... except ZeroDivisionError: ... log.exception("Cannot compute!") - {"event": "Cannot compute!", "exception": [{"exc_type": "ZeroDivisionError", "exc_value": "division by zero", "syntax_error": null, "is_cause": false, "frames": [{"filename": "", "lineno": 2, "name": "", "locals": {..., "var": "'spam'"}}]}]} + {"event": "Cannot compute!", "exception": [{"exc_type": "ZeroDivisionError", "exc_value": "division by zero", "exc_notes": [], "syntax_error": null, "is_cause": false, "frames": [{"filename": "", "lineno": 2, "name": "", "locals": {..., "var": "'spam'"}}]}]} .. autoclass:: KeyValueRenderer diff --git a/src/structlog/tracebacks.py b/src/structlog/tracebacks.py index 96ab71e6..a6c6cefc 100644 --- a/src/structlog/tracebacks.py +++ b/src/structlog/tracebacks.py @@ -81,10 +81,14 @@ class SyntaxError_: # noqa: N801 class Stack: """ Represents an exception and a list of stack frames. + + .. versionchanged:: 25.2.0 + Added the *exc_notes* field. """ exc_type: str exc_value: str + exc_notes: list[str] = field(default_factory=list) syntax_error: SyntaxError_ | None = None is_cause: bool = False frames: list[Frame] = field(default_factory=list) @@ -230,6 +234,9 @@ def extract( stack = Stack( exc_type=safe_str(exc_type.__name__), exc_value=safe_str(exc_value), + exc_notes=[ + safe_str(note) for note in getattr(exc_value, "__notes__", ()) + ], is_cause=is_cause, ) diff --git a/tests/test_tracebacks.py b/tests/test_tracebacks.py index 42a5b75c..0dd1eb80 100644 --- a/tests/test_tracebacks.py +++ b/tests/test_tracebacks.py @@ -160,6 +160,40 @@ def test_simple_exception(): ] == trace.stacks +@pytest.mark.skipif( + sys.version_info < (3, 11), reason="Requires Python 3.11 or higher" +) +def test_simple_exception_with_notes(): + """ + Notes are included in the traceback. + """ + try: + lineno = get_next_lineno() + 1 / 0 + except Exception as e: + e.add_note("This is a note.") + e.add_note("This is another note.") + trace = tracebacks.extract(type(e), e, e.__traceback__) + + assert [ + tracebacks.Stack( + exc_type="ZeroDivisionError", + exc_value="division by zero", + exc_notes=["This is a note.", "This is another note."], + syntax_error=None, + is_cause=False, + frames=[ + tracebacks.Frame( + filename=__file__, + lineno=lineno, + name="test_simple_exception_with_notes", + locals=None, + ), + ], + ), + ] == trace.stacks + + def test_raise_hide_cause(): """ If "raise ... from None" is used, the trace looks like from a simple @@ -588,6 +622,7 @@ def test_json_traceback(): { "exc_type": "ZeroDivisionError", "exc_value": "division by zero", + "exc_notes": [], "frames": [ { "filename": __file__, @@ -601,6 +636,40 @@ def test_json_traceback(): ] == result +@pytest.mark.skipif( + sys.version_info < (3, 11), reason="Requires Python 3.11 or higher" +) +def test_json_traceback_with_notes(): + """ + Tracebacks are formatted to JSON with all information. + """ + try: + lineno = get_next_lineno() + 1 / 0 + except Exception as e: + e.add_note("This is a note.") + e.add_note("This is another note.") + format_json = tracebacks.ExceptionDictTransformer(show_locals=False) + result = format_json((type(e), e, e.__traceback__)) + + assert [ + { + "exc_type": "ZeroDivisionError", + "exc_value": "division by zero", + "exc_notes": ["This is a note.", "This is another note."], + "frames": [ + { + "filename": __file__, + "lineno": lineno, + "name": "test_json_traceback_with_notes", + } + ], + "is_cause": False, + "syntax_error": None, + }, + ] == result + + def test_json_traceback_locals_max_string(): """ Local variables in each frame are trimmed to locals_max_string. @@ -617,6 +686,7 @@ def test_json_traceback_locals_max_string(): { "exc_type": "ZeroDivisionError", "exc_value": "division by zero", + "exc_notes": [], "frames": [ { "filename": __file__, From 66e22d261bf493ad2084009ec97c51832fdbb0b9 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 3 Feb 2025 06:23:25 +0100 Subject: [PATCH 1341/1520] pre-commit update --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5dec266b..82d1b7cc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.9.3 + rev: v0.9.4 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] @@ -17,7 +17,7 @@ repos: args: [tests] - repo: https://github.com/codespell-project/codespell - rev: v2.4.0 + rev: v2.4.1 hooks: - id: codespell args: [-L, alog, -L, abl] From ea7cac413fc8dae38af68cb4ea29b19581ebd413 Mon Sep 17 00:00:00 2001 From: Alvin Yip <107124700+keongalvin@users.noreply.github.com> Date: Wed, 19 Feb 2025 17:47:36 +0800 Subject: [PATCH 1342/1520] expose RichTracebackFormatter for imports in structlog.dev (#699) * expose RichTracebackFormatter for imports in structlog.dev * Fix whitespace --------- Co-authored-by: Hynek Schlawack --- CHANGELOG.md | 6 ++++++ src/structlog/dev.py | 1 + 2 files changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 572cf83e..da135b50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,12 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ [#694](https://github.com/hynek/structlog/pull/694) +### Fixed + +- Expose `structlog.dev.RichTracebackFormatter` for imports. + [#699](https://github.com/hynek/structlog/pull/699) + + ## [25.1.0](https://github.com/hynek/structlog/compare/24.4.0...25.1.0) - 2025-01-16 ### Added diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 38b02df0..47d52607 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -55,6 +55,7 @@ __all__ = [ "ConsoleRenderer", + "RichTracebackFormatter", "better_traceback", "plain_traceback", "rich_traceback", From 768931a79f2ae08e7a42778289eec2e1b94f8c27 Mon Sep 17 00:00:00 2001 From: Alvin Yip <107124700+keongalvin@users.noreply.github.com> Date: Tue, 25 Feb 2025 12:54:23 +0800 Subject: [PATCH 1343/1520] expose LogfmtRenderer for imports (#701) --- CHANGELOG.md | 3 ++- src/structlog/processors.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index da135b50..b781577b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,7 +31,8 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - Expose `structlog.dev.RichTracebackFormatter` for imports. [#699](https://github.com/hynek/structlog/pull/699) - +- Expose `structlog.processors.LogfmtRenderer` for imports. + [#701](https://github.com/hynek/structlog/pull/701) ## [25.1.0](https://github.com/hynek/structlog/compare/24.4.0...25.1.0) - 2025-01-16 diff --git a/src/structlog/processors.py b/src/structlog/processors.py index ac1bd98c..24731521 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -55,6 +55,7 @@ "ExceptionPrettyPrinter", "JSONRenderer", "KeyValueRenderer", + "LogfmtRenderer", "StackInfoRenderer", "TimeStamper", "UnicodeDecoder", From 08aba073f84e2acd603378d28858ae9c5e1a0bf9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 6 Mar 2025 08:20:51 +0100 Subject: [PATCH 1344/1520] [pre-commit.ci] pre-commit autoupdate (#704) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.9.4 → v0.9.9](https://github.com/astral-sh/ruff-pre-commit/compare/v0.9.4...v0.9.9) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 82d1b7cc..769f6700 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.9.4 + rev: v0.9.9 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From 7555f0cb022cadb13d3d7804bf9071ea99cc55e0 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 6 Mar 2025 09:59:17 +0100 Subject: [PATCH 1345/1520] sponsors: update tiers --- pyproject.toml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 7b3a59a8..69dc5d92 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -257,6 +257,11 @@ title = "Klaviyo" url = "https://klaviyo.com/" img = "Klaviyo.svg" +[[tool.sponcon.sponsors]] +title = "Privacy Solutions" +url = "https://privacy-solutions.org/" +img = "Privacy-Solutions.svg" + [[tool.sponcon.sponsors]] title = "emsys renewables" url = "https://www.emsys-renewables.com/" @@ -267,11 +272,6 @@ title = "FilePreviews" url = "https://filepreviews.io/" img = "FilePreviews.svg" -[[tool.sponcon.sponsors]] -title = "Privacy Solutions" -url = "https://privacy-solutions.org/" -img = "Privacy-Solutions.svg" - [[tool.sponcon.sponsors]] title = "Polar" url = "https://polar.sh/" From 2f0cc42d92ac64b7a0e844e6359bc0d97318f1d2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 6 Mar 2025 10:00:24 +0100 Subject: [PATCH 1346/1520] run cog --- README.md | 2 +- docs/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bd7e50a2..0f7fbdf7 100644 --- a/README.md +++ b/README.md @@ -52,9 +52,9 @@ for sponsor in tomllib.loads(pathlib.Path("pyproject.toml").read_text())["tool"] + - diff --git a/docs/index.md b/docs/index.md index f09755db..61a318db 100644 --- a/docs/index.md +++ b/docs/index.md @@ -22,9 +22,9 @@ for sponsor in tomllib.loads(pathlib.Path("pyproject.toml").read_text())["tool"] + - From 3a7006d616bd828ed4eb5c66756f8bdc13fc5fea Mon Sep 17 00:00:00 2001 From: Reinis Taukulis Date: Fri, 7 Mar 2025 09:32:24 +0200 Subject: [PATCH 1347/1520] Clarify sentence about get_logger() arguments (#706) Currently the sentence starts with "these", but it's not clear to what that word refers. --- docs/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index ee4cf520..5f1835e7 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -75,7 +75,7 @@ It's a callable that returns the logger that gets wrapped and returned. In the simplest case, it's a function that returns a logger -- or just a class. But you can also pass in an instance of a class with a `__call__` method for more complicated setups. -These will be passed to the logger factories. +The arguments you pass to `structlog.get_logger()` will be passed to the logger factory. For example, if you use `structlog.get_logger("a name")` and configure *structlog* to use the standard library {class}`~structlog.stdlib.LoggerFactory`, which has support for positional parameters, the returned logger will have the name `"a name"`. For the common cases of standard library logging and Twisted logging, *structlog* comes with two factories built right in: From 1600b0f7affaabace165f1260301c632fbcdd12c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 8 Mar 2025 18:13:42 +0100 Subject: [PATCH 1348/1520] TimeStamper() now uses TZ-aware objects (#709) * TimeStamper() now uses TZ-aware objects The default output doesn't change but manual formatting allows for TZ data now. Fixes #703 * Add changelog * Handle negative timezones * Only add TZ when potentially useful --- CHANGELOG.md | 4 ++++ src/structlog/processors.py | 5 +++-- tests/processors/test_renderers.py | 15 +++++++++++++-- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b781577b..63cb557e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,10 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - `structlog.stdlib.BoundLogger`'s binding-related methods now also return `Self`. [#694](https://github.com/hynek/structlog/pull/694) +- `structlog.processors.TimeStamper` now produces internally timezone-aware `datetime` objects. + Default output hasn't changed, but you can now use `%z` in your *fmt* string. + [#709](https://github.com/hynek/structlog/pull/709) + ### Fixed diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 24731521..4ef75780 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -525,7 +525,8 @@ def now() -> datetime.datetime: else: def now() -> datetime.datetime: - # A naive local datetime is fine here, because we only format it. + # We don't need the TZ for our own formatting. We add it only for + # user-defined formats later. return datetime.datetime.now() # noqa: DTZ005 if fmt is None: @@ -553,7 +554,7 @@ def stamper_iso_utc(event_dict: EventDict) -> EventDict: return stamper_iso_local def stamper_fmt(event_dict: EventDict) -> EventDict: - event_dict[key] = now().strftime(fmt) + event_dict[key] = now().astimezone().strftime(fmt) return event_dict diff --git a/tests/processors/test_renderers.py b/tests/processors/test_renderers.py index 9fa24e5c..be8007ad 100644 --- a/tests/processors/test_renderers.py +++ b/tests/processors/test_renderers.py @@ -396,8 +396,8 @@ def test_inserts_utc_unix_timestamp_by_default(self): @freeze_time("1980-03-25 16:00:00") def test_local(self): """ - Timestamp in local timezone work. We can't add a timezone to the - string without additional libraries. + Timestamp in local timezone work. Due to historic reasons, the default + format does not include a timezone. """ ts = TimeStamper(fmt="iso", utc=False) d = ts(None, None, {}) @@ -414,6 +414,17 @@ def test_formats(self): assert "1980" == d["timestamp"] + @freeze_time("1980-03-25 16:00:00") + def test_tz_aware(self): + """ + The timestamp that is used for formatting is timezone-aware. + """ + ts = TimeStamper(fmt="%z") + d = ts(None, None, {}) + + assert "" == datetime.datetime.now().strftime("%z") # noqa: DTZ005 + assert "" != d["timestamp"] + @freeze_time("1980-03-25 16:00:00") def test_adds_Z_to_iso(self): """ From 482fbabd1822676ac7783eff2a86a2531c30ee39 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 11 Mar 2025 18:31:05 +0100 Subject: [PATCH 1349/1520] update ruff --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 769f6700..4d55243b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.9.9 + rev: v0.9.10 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From e948850c1bd20334247ce5d8228eab6549ab94a6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 11 Mar 2025 18:32:04 +0100 Subject: [PATCH 1350/1520] Prepare 25.2.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63cb557e..23f15a67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ -## [Unreleased](https://github.com/hynek/structlog/compare/25.1.0...HEAD) +## [25.2.0](https://github.com/hynek/structlog/compare/25.1.0...25.2.0) - 2025-03-11 ### Added From 244fde4d4b1818ad3eda083c7d25ea957ea5e128 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 11 Mar 2025 18:34:25 +0100 Subject: [PATCH 1351/1520] Start new development cycle --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23f15a67..772903b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ +## [Unreleased](https://github.com/hynek/structlog/compare/25.2.0...HEAD) + + ## [25.2.0](https://github.com/hynek/structlog/compare/25.1.0...25.2.0) - 2025-03-11 ### Added From 414047d9f699e168ce595e08c67253e9c0969247 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 8 Apr 2025 08:02:19 +0200 Subject: [PATCH 1352/1520] update Ruff --- .pre-commit-config.yaml | 2 +- tests/test_stdlib.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4d55243b..30545782 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.9.10 + rev: v0.11.4 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 383e60dd..607308d3 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -663,7 +663,7 @@ def test_add_extra_e2e( handler.setLevel(0) logger.addHandler(handler) logger.setLevel(0) - logging.warning("allow = %s", allow) + logging.warning("allow = %s", allow) # noqa: LOG015 event_dict = {"event": "Some text"} expected = self._copy_allowed(event_dict, extra_dict, allow) From 1b8680ea843cfc594c50f6431038628569534115 Mon Sep 17 00:00:00 2001 From: Marcin Endraszka <46051040+m-endra@users.noreply.github.com> Date: Fri, 25 Apr 2025 17:38:03 +0200 Subject: [PATCH 1353/1520] TimeStamper now returns UTC timezone for custom format string. (#713) * TimeStamper now returns UTC timezone for custom format string. * Add pull request link for #713 --------- Co-authored-by: Marcin Endraszka Co-authored-by: Hynek Schlawack --- CHANGELOG.md | 3 +++ src/structlog/processors.py | 10 ++++++++-- tests/processors/test_renderers.py | 30 ++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 772903b3..1fa55489 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ## [Unreleased](https://github.com/hynek/structlog/compare/25.2.0...HEAD) +### Fixed +- `structlog.processors.TimeStamper` now returns UTC timezone for custom format string. + [#713](https://github.com/hynek/structlog/pull/713) ## [25.2.0](https://github.com/hynek/structlog/compare/25.1.0...25.2.0) - 2025-03-11 diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 4ef75780..39e15328 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -553,12 +553,18 @@ def stamper_iso_utc(event_dict: EventDict) -> EventDict: return stamper_iso_local - def stamper_fmt(event_dict: EventDict) -> EventDict: + def stamper_fmt_local(event_dict: EventDict) -> EventDict: event_dict[key] = now().astimezone().strftime(fmt) + return event_dict + def stamper_fmt_utc(event_dict: EventDict) -> EventDict: + event_dict[key] = now().strftime(fmt) return event_dict - return stamper_fmt + if utc: + return stamper_fmt_utc + + return stamper_fmt_local class MaybeTimeStamper: diff --git a/tests/processors/test_renderers.py b/tests/processors/test_renderers.py index be8007ad..1bef95f0 100644 --- a/tests/processors/test_renderers.py +++ b/tests/processors/test_renderers.py @@ -414,6 +414,36 @@ def test_formats(self): assert "1980" == d["timestamp"] + @freeze_time("1980-03-25 16:00:00") + def test_inserts_formatted_utc(self): + """ + The fmt string in UTC timezone works. + + The exact hours calculated here maybe incorrect because of freezegun bugs: + https://github.com/spulec/freezegun/issues/348 + https://github.com/spulec/freezegun/issues/494 + """ + + ts = TimeStamper(fmt="%Y-%m-%d %H:%M:%S %Z") + d = ts(None, None, {}) + + assert "1980-03-25 16:00:00 UTC" == d["timestamp"] + + @freeze_time("1980-03-25 16:00:00") + def test_inserts_formatted_local(self): + """ + The fmt string in local timezone works. + + The exact hours calculated here maybe incorrect because of freezegun bugs: + https://github.com/spulec/freezegun/issues/348 + https://github.com/spulec/freezegun/issues/494 + """ + local_tz = datetime.datetime.now().astimezone().tzname() + ts = TimeStamper(fmt="%Y-%m-%d %H:%M:%S %Z", utc=False) + d = ts(None, None, {}) + + assert f"1980-03-25 16:00:00 {local_tz}" == d["timestamp"] + @freeze_time("1980-03-25 16:00:00") def test_tz_aware(self): """ From 4c844e8f3f02dc88a0d5965a1291b43ae68b9bed Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 25 Apr 2025 17:45:26 +0200 Subject: [PATCH 1354/1520] docs: polish changelog --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fa55489..6d05e5ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,9 +16,11 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ## [Unreleased](https://github.com/hynek/structlog/compare/25.2.0...HEAD) ### Fixed -- `structlog.processors.TimeStamper` now returns UTC timezone for custom format string. + +- `structlog.processors.TimeStamper` now again uses timestamps using UTC for custom format strings when `utc=True`. [#713](https://github.com/hynek/structlog/pull/713) + ## [25.2.0](https://github.com/hynek/structlog/compare/25.1.0...25.2.0) - 2025-03-11 ### Added From 637dce6b1e0573f50217ab60735f155eb054661a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 25 Apr 2025 17:46:05 +0200 Subject: [PATCH 1355/1520] update ruff --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 30545782..922c569d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.11.4 + rev: v0.11.7 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From edfa953b981be4f0a4365bd991dc0ee5e130eedd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 25 Apr 2025 17:50:14 +0200 Subject: [PATCH 1356/1520] Prepare 25.3.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d05e5ed..ce0ac4b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ -## [Unreleased](https://github.com/hynek/structlog/compare/25.2.0...HEAD) +## [25.3.0](https://github.com/hynek/structlog/compare/25.2.0...25.3.0) - 2025-04-25 ### Fixed From 677d00b8b7384b35fdde179093cfd5113894d75b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 25 Apr 2025 17:52:52 +0200 Subject: [PATCH 1357/1520] Start new development cycle --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce0ac4b4..13aeabc2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ +## [Unreleased](https://github.com/hynek/structlog/compare/25.3.0...HEAD) + + ## [25.3.0](https://github.com/hynek/structlog/compare/25.2.0...25.3.0) - 2025-04-25 ### Fixed From 4ce82b01e3cb871f8b0fd97598533d99d35d0a26 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 1 May 2025 13:51:17 +0200 Subject: [PATCH 1358/1520] docs: fix typo ref https://github.com/hynek/structlog/issues/341#issuecomment-2697352382 --- src/structlog/dev.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 47d52607..fd3f6984 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -759,8 +759,8 @@ def get_default_level_styles(colors: bool = True) -> dict[str, str]: home-grown :func:`~structlog.stdlib.add_log_level` you could do:: my_styles = ConsoleRenderer.get_default_level_styles() - my_styles["EVERYTHING_IS_ON_FIRE"] = my_styles["critical"] renderer - = ConsoleRenderer(level_styles=my_styles) + my_styles["EVERYTHING_IS_ON_FIRE"] = my_styles["critical"] + renderer = ConsoleRenderer(level_styles=my_styles) Args: colors: From 3c275ea558dd0881f6f09fcb6427f7e53971d8a8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 5 May 2025 19:26:35 +0200 Subject: [PATCH 1359/1520] [pre-commit.ci] pre-commit autoupdate (#722) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.11.7 → v0.11.8](https://github.com/astral-sh/ruff-pre-commit/compare/v0.11.7...v0.11.8) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 922c569d..c13a93c3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.11.7 + rev: v0.11.8 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From 2e8e34fb1e95c3b1479166e93405a2feafecbaf6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 9 May 2025 09:02:12 +0200 Subject: [PATCH 1360/1520] docs/threadlocal: mention #591 Can't remove it while contextvars crash. --- docs/thread-local.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/thread-local.md b/docs/thread-local.md index 44fa789b..2bd73adf 100644 --- a/docs/thread-local.md +++ b/docs/thread-local.md @@ -5,7 +5,8 @@ The `structlog.threadlocal` module is deprecated as of *structlog* 22.1.0 in fav The standard library {mod}`contextvars` module provides a more feature-rich superset of the thread-local APIs and works with thread-local data, async code, and greenlets. -Therefore, as of 22.1.0, the `structlog.threadlocal` module is frozen and will be removed after May 2023. +The plan was to remove this module after 2023, however people are reporting [odd crashes with {doc}`contextvars`, that we can't reproduce](https://github.com/hynek/structlog/issues/591). +Until we find a solution, this module will **not** be removed, since it's a viable workaround. ::: ```{testsetup} * From 12d04df1e2e4d47a50cf3d4e56efa1caf7315200 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 28 May 2025 11:38:06 +0200 Subject: [PATCH 1361/1520] Add 3.14 (#723) --- CHANGELOG.md | 4 ++++ pyproject.toml | 1 + src/structlog/stdlib.py | 7 ++++++- tox.ini | 2 +- 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13aeabc2..7e4f69bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ## [Unreleased](https://github.com/hynek/structlog/compare/25.3.0...HEAD) +### Added + +- Support for Python 3.14. + ## [25.3.0](https://github.com/hynek/structlog/compare/25.2.0...25.3.0) - 2025-04-25 diff --git a/pyproject.toml b/pyproject.toml index 69dc5d92..456f7579 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Topic :: System :: Logging", "Typing :: Typed", ] diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 80ee628d..2c49b788 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -787,7 +787,12 @@ def filter_by_level( ... DropEvent """ - if logger.isEnabledFor(NAME_TO_LEVEL[method_name]): + if ( + # We can't use logger.isEnabledFor() because it's always disabled when + # a log entry is in flight on Python 3.14 and later, + not logger.disabled + and NAME_TO_LEVEL[method_name] >= logger.getEffectiveLevel() + ): return event_dict raise DropEvent diff --git a/tox.ini b/tox.ini index 4873754a..3fdc388d 100644 --- a/tox.ini +++ b/tox.ini @@ -3,7 +3,7 @@ min_version = 4 env_list = pre-commit, mypy-pkg, - py3{8,9,10,11,12,13}-{tests,mypy} + py3{8,9,10,11,12,13,14}-{tests,mypy} py3{8,13}-tests-{colorama,be,rich}, docs-{sponsors,doctests}, coverage-report From 12494f1b1545d9c4df155a1b3b8cd9b2380d2870 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 28 May 2025 14:23:49 +0200 Subject: [PATCH 1362/1520] Mention the logging fixes are for the next 3.13 point release too Thanks @paravoid! --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e4f69bb..e9590404 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,8 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ### Added -- Support for Python 3.14. +- Support for Python 3.14 and Python 3.13.4. + [#723](https://github.com/hynek/structlog/pull/723) ## [25.3.0](https://github.com/hynek/structlog/compare/25.2.0...25.3.0) - 2025-04-25 From 02e12433155f0b30977dadc8e69f35901ad6bcb0 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 28 May 2025 14:24:28 +0200 Subject: [PATCH 1363/1520] update Ruff --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c13a93c3..31fe1366 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.11.8 + rev: v0.11.11 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] From d887c003526ba15c3909bf909c712cb11b31656a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 29 May 2025 11:06:04 +0200 Subject: [PATCH 1364/1520] Use dependency groups (#725) --- .github/CONTRIBUTING.md | 2 +- .github/workflows/ci.yml | 2 +- pyproject.toml | 8 +++++--- tox.ini | 12 ++++++------ 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 53d8b094..53033c27 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -76,7 +76,7 @@ test -d .venv || uv venv --python python$(cat .python-version-default) Change into the newly created directory and after activating a virtual environment, install an editable version of this project along with its tests requirements: ```console -$ pip install -e .[dev] # or `uv pip install -e .[dev]` +$ pip install -e . --group dev # or `uv pip install -e . --group dev` ``` Now you can run the test suite: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ac4fb547..6e062cae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -209,7 +209,7 @@ jobs: - uses: hynek/setup-cached-uv@v2 - run: uv venv - - run: uv pip install -e .[dev] + - run: uv pip install -e . --group dev - run: .venv/bin/python -Ic 'import structlog; print(structlog.__version__)' if: runner.os != 'Windows' diff --git a/pyproject.toml b/pyproject.toml index 456f7579..2b6854e2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ Mastodon = "https://mastodon.social/@hynek" Bluesky = "https://bsky.app/profile/hynek.me" Twitter = "https://twitter.com/hynek" -[project.optional-dependencies] +[dependency-groups] tests = [ "freezegun>=0.2.8", "pretend", @@ -60,7 +60,10 @@ docs = [ "sphinxext-opengraph", "twisted", ] -dev = ["structlog[tests,typing]"] +dev = [ + {include-group = "tests"}, + {include-group = "typing"}, +] [tool.hatch.version] @@ -140,7 +143,6 @@ ignore = [ "PLR2004", # numbers are sometimes fine "PLW2901", # overwriting a loop var can be useful "RUF001", # leave my smart characters alone - "RUF001", # leave my smart characters alone "SLF001", # private members are accessed by friendly functions "T201", # prints are fine "TC", # TYPE_CHECKING blocks break autodocs diff --git a/tox.ini b/tox.ini index 3fdc388d..113251af 100644 --- a/tox.ini +++ b/tox.ini @@ -12,7 +12,7 @@ env_list = [testenv] package = wheel wheel_build_env = .pkg -extras = +dependency_groups = tests: tests mypy: typing commands = @@ -46,7 +46,7 @@ commands = [testenv:docs-{build,doctests,linkcheck}] # Keep base_python in sync with ci.yml/docs and .readthedocs.yaml. base_python = py313 -extras = docs +dependency_groups = docs commands = build: sphinx-build -n -T -W -b html -d {envtmpdir}/doctrees docs {posargs:docs/_build/}html doctests: sphinx-build -n -T -W -b doctest -d {envtmpdir}/doctrees docs {posargs:docs/_build/}html @@ -55,7 +55,7 @@ commands = [testenv:docs-watch] package = editable base_python = {[testenv:docs-build]base_python} -extras = {[testenv:docs-build]extras} +dependency_groups = {[testenv:docs-build]dependency_groups} deps = watchfiles commands = watchfiles \ @@ -77,13 +77,13 @@ commands = pre-commit run --all-files [testenv:mypy-pkg] -extras = typing +dependency_groups = typing commands = mypy src [testenv:pyright] deps = pyright -extras = typing +dependency_groups = typing commands = pyright tests/typing @@ -101,7 +101,7 @@ commands = python -c "import structlog; structlog.get_logger().warning('should b [testenv:docset] deps = doc2dash -extras = docs +dependency_groups = docs allowlist_externals = rm cp From de3dfc8dce7c31c73064db5fdee7322f2b5f112b Mon Sep 17 00:00:00 2001 From: Anuj Das Date: Thu, 29 May 2025 02:13:15 -0700 Subject: [PATCH 1365/1520] fix ExceptionPrettyPrinter custom formatter support (#724) * Fix ExceptionPrettyPrinter custom formatter support * Update CHANGELOG.md --------- Co-authored-by: Hynek Schlawack --- CHANGELOG.md | 4 ++++ src/structlog/processors.py | 17 +++++++++++++---- tests/processors/test_processors.py | 22 +++++++++++++++++++++- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9590404..0125f807 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,10 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - Support for Python 3.14 and Python 3.13.4. [#723](https://github.com/hynek/structlog/pull/723) +### Fixed + +- `structlog.processors.ExceptionPrettyPrinter` now respects the *exception_formatter* arguments instead of always using the default formatter. + ## [25.3.0](https://github.com/hynek/structlog/compare/25.2.0...25.3.0) - 2025-04-25 diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 39e15328..ee70e509 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -626,16 +626,21 @@ def _figure_out_exc_info(v: Any) -> ExcInfo | None: class ExceptionPrettyPrinter: """ - Pretty print exceptions and remove them from the ``event_dict``. + Pretty print exceptions rendered by *exception_formatter* and remove them + from the ``event_dict``. Args: file: Target file for output (default: ``sys.stdout``). + exception_formatter: + A callable that is used to format the exception from the + ``exc_info`` field into the ``exception`` field. This processor is mostly for development and testing so you can read exceptions properly formatted. - It behaves like `format_exc_info` except it removes the exception data from - the event dictionary after printing it. + It behaves like `format_exc_info`, except that it removes the exception data + from the event dictionary after printing it using the passed + *exception_formatter*, which defaults to Python's built-in traceback formatting. It's tolerant to having `format_exc_info` in front of itself in the processor chain but doesn't require it. In other words, it handles both @@ -645,6 +650,9 @@ class ExceptionPrettyPrinter: .. versionchanged:: 16.0.0 Added support for passing exceptions as ``exc_info`` on Python 3. + + .. versionchanged:: 25.4.0 + Fixed *exception_formatter* so that it overrides the default if set. """ def __init__( @@ -652,6 +660,7 @@ def __init__( file: TextIO | None = None, exception_formatter: ExceptionTransformer = _format_exception, ) -> None: + self.format_exception = exception_formatter if file is not None: self._file = file else: @@ -664,7 +673,7 @@ def __call__( if exc is None: exc_info = _figure_out_exc_info(event_dict.pop("exc_info", None)) if exc_info: - exc = _format_exception(exc_info) + exc = self.format_exception(exc_info) if exc: print(exc, file=self._file) diff --git a/tests/processors/test_processors.py b/tests/processors/test_processors.py index 09ea0e99..13f4478d 100644 --- a/tests/processors/test_processors.py +++ b/tests/processors/test_processors.py @@ -36,7 +36,7 @@ format_exc_info, ) from structlog.stdlib import ProcessorFormatter -from structlog.typing import EventDict +from structlog.typing import EventDict, ExcInfo from ..additional_frame import additional_frame @@ -125,6 +125,26 @@ def test_prints_exception(self, sio): assert "test_prints_exception" in out assert "raise ValueError" in out + def test_uses_exception_formatter(self, sio): + """ + If an `exception_formatter` is passed, use that to render the + exception rather than the default. + """ + + def formatter(exc_info: ExcInfo) -> str: + return f"error: {exc_info}" + + epp = ExceptionPrettyPrinter(file=sio, exception_formatter=formatter) + try: + raise ValueError + except ValueError as e: + epp(None, None, {"exc_info": True}) + formatted = formatter(e) + + out = sio.getvalue() + + assert formatted in out + def test_removes_exception_after_printing(self, sio): """ After pretty printing `exception` is removed from the event_dict. From f07c1367e790c3de161e1248e5c98e911f8377b4 Mon Sep 17 00:00:00 2001 From: Stefan Scherfke Date: Thu, 29 May 2025 12:02:27 +0200 Subject: [PATCH 1366/1520] tracebacks: Handle ExceptionGroup (#720) * tracebacks: Handle ExceptionGroup Fixes: #676 * Update docs and CHANGELOG * Update tests Exc values for ZeroDivisionError 1 // 0 changed in py314... * Move changelog entry to correct heading * Let's link * Update version * Fix typo * Another one --------- Co-authored-by: Hynek Schlawack --- CHANGELOG.md | 6 ++ docs/api.rst | 2 +- src/structlog/tracebacks.py | 47 ++++++++++- tests/test_tracebacks.py | 155 ++++++++++++++++++++++++++++++++++++ 4 files changed, 205 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0125f807..87601113 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,12 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - Support for Python 3.14 and Python 3.13.4. [#723](https://github.com/hynek/structlog/pull/723) +- `structlog.tracebacks` now handles [exception groups](https://docs.python.org/3/library/exceptions.html#exception-groups). + `structlog.tracebacks.Stack` has two new fields, `is_group: bool` and `exceptions: list[Trace]`. + This works similarly to what Rich v14.0.0 does. + [#720](https://github.com/hynek/structlog/pull/720) + + ### Fixed - `structlog.processors.ExceptionPrettyPrinter` now respects the *exception_formatter* arguments instead of always using the default formatter. diff --git a/docs/api.rst b/docs/api.rst index 3719756a..f13fdbb9 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -197,7 +197,7 @@ API Reference ... 1 / 0 ... except ZeroDivisionError: ... log.exception("Cannot compute!") - {"event": "Cannot compute!", "exception": [{"exc_type": "ZeroDivisionError", "exc_value": "division by zero", "exc_notes": [], "syntax_error": null, "is_cause": false, "frames": [{"filename": "", "lineno": 2, "name": "", "locals": {..., "var": "'spam'"}}]}]} + {"event": "Cannot compute!", "exception": [{"exc_type": "ZeroDivisionError", "exc_value": "division by zero", "exc_notes": [], "syntax_error": null, "is_cause": false, "frames": [{"filename": "", "lineno": 2, "name": "", "locals": {..., "var": "'spam'"}}], "is_group": false, "exceptions": []}]} .. autoclass:: KeyValueRenderer diff --git a/src/structlog/tracebacks.py b/src/structlog/tracebacks.py index a6c6cefc..949df9cd 100644 --- a/src/structlog/tracebacks.py +++ b/src/structlog/tracebacks.py @@ -16,6 +16,7 @@ import os import os.path +import sys from dataclasses import asdict, dataclass, field from traceback import walk_tb @@ -84,6 +85,9 @@ class Stack: .. versionchanged:: 25.2.0 Added the *exc_notes* field. + + .. versionchanged:: 25.4.0 + Added the *is_group* and *exceptions* fields. """ exc_type: str @@ -92,6 +96,8 @@ class Stack: syntax_error: SyntaxError_ | None = None is_cause: bool = False frames: list[Frame] = field(default_factory=list) + is_group: bool = False + exceptions: list[Trace] = field(default_factory=list) @dataclass @@ -222,9 +228,13 @@ def extract( A Trace instance with structured information about all exceptions. .. versionadded:: 22.1.0 + .. versionchanged:: 24.3.0 Added *locals_max_length*, *locals_hide_sunder*, *locals_hide_dunder* and *use_rich* arguments. + + .. versionchanged:: 25.4.0 + Handle exception groups. """ stacks: list[Stack] = [] @@ -240,6 +250,24 @@ def extract( is_cause=is_cause, ) + if sys.version_info >= (3, 11): + if isinstance(exc_value, (BaseExceptionGroup, ExceptionGroup)): # noqa: F821 + stack.is_group = True + for exception in exc_value.exceptions: + stack.exceptions.append( + extract( + type(exception), + exception, + exception.__traceback__, + show_locals=show_locals, + locals_max_length=locals_max_length, + locals_max_string=locals_max_string, + locals_hide_dunder=locals_hide_dunder, + locals_hide_sunder=locals_hide_sunder, + use_rich=use_rich, + ) + ) + if isinstance(exc_value, SyntaxError): stack.syntax_error = SyntaxError_( offset=exc_value.offset or 0, @@ -377,6 +405,9 @@ class ExceptionDictTransformer: .. versionchanged:: 25.1.0 *locals_max_length* and *locals_max_string* may be None to disable truncation. + + .. versionchanged:: 25.4.0 + Handle exception groups. """ def __init__( @@ -451,13 +482,21 @@ def __call__(self, exc_info: ExcInfo) -> list[dict[str, Any]]: *stack.frames[-half:], ] - stacks = [asdict(stack) for stack in trace.stacks] - for stack_dict in stacks: + return self._as_dict(trace) + + def _as_dict(self, trace: Trace) -> list[dict[str, Any]]: + stack_dicts = [] + for stack in trace.stacks: + stack_dict = asdict(stack) for frame_dict in stack_dict["frames"]: if frame_dict["locals"] is None or any( frame_dict["filename"].startswith(path) for path in self.suppress ): del frame_dict["locals"] - - return stacks + if stack.is_group: + stack_dict["exceptions"] = [ + self._as_dict(t) for t in stack.exceptions + ] + stack_dicts.append(stack_dict) + return stack_dicts diff --git a/tests/test_tracebacks.py b/tests/test_tracebacks.py index 0dd1eb80..f83f72fb 100644 --- a/tests/test_tracebacks.py +++ b/tests/test_tracebacks.py @@ -5,6 +5,7 @@ from __future__ import annotations +import asyncio import inspect import json import sys @@ -567,6 +568,84 @@ def bar(n): ] +@pytest.mark.skipif( + sys.version_info < (3, 11), reason="Requires Python 3.11 or higher" +) +def test_exception_groups() -> None: + """ + Exception groups are detected and a list of Trace instances is added to + the exception group's Trace. + """ + lineno = get_next_lineno() + + async def t1() -> None: + 1 / 0 + + async def t2() -> None: + raise ValueError("Blam!") + + async def main(): + async with asyncio.TaskGroup() as tg: + tg.create_task(t1()) + tg.create_task(t2()) + + try: + asyncio.run(main()) + except Exception as e: + trace = tracebacks.extract(type(e), e, e.__traceback__) + + assert "ExceptionGroup" == trace.stacks[0].exc_type + assert ( + "unhandled errors in a TaskGroup (2 sub-exceptions)" + == trace.stacks[0].exc_value + ) + exceptions = trace.stacks[0].exceptions + assert [ + tracebacks.Trace( + stacks=[ + tracebacks.Stack( + exc_type="ZeroDivisionError", + exc_value="division by zero", + exc_notes=[], + syntax_error=None, + is_cause=False, + frames=[ + tracebacks.Frame( + filename=__file__, + lineno=lineno + 2, + name="t1", + locals=None, + ) + ], + is_group=False, + exceptions=[], + ) + ] + ), + tracebacks.Trace( + stacks=[ + tracebacks.Stack( + exc_type="ValueError", + exc_value="Blam!", + exc_notes=[], + syntax_error=None, + is_cause=False, + frames=[ + tracebacks.Frame( + filename=__file__, + lineno=lineno + 5, + name="t2", + locals=None, + ) + ], + is_group=False, + exceptions=[], + ) + ] + ), + ] == exceptions + + @pytest.mark.parametrize( ("kwargs", "local_variable"), [ @@ -623,6 +702,7 @@ def test_json_traceback(): "exc_type": "ZeroDivisionError", "exc_value": "division by zero", "exc_notes": [], + "exceptions": [], "frames": [ { "filename": __file__, @@ -631,6 +711,7 @@ def test_json_traceback(): } ], "is_cause": False, + "is_group": False, "syntax_error": None, }, ] == result @@ -657,6 +738,7 @@ def test_json_traceback_with_notes(): "exc_type": "ZeroDivisionError", "exc_value": "division by zero", "exc_notes": ["This is a note.", "This is another note."], + "exceptions": [], "frames": [ { "filename": __file__, @@ -665,6 +747,7 @@ def test_json_traceback_with_notes(): } ], "is_cause": False, + "is_group": False, "syntax_error": None, }, ] == result @@ -687,6 +770,7 @@ def test_json_traceback_locals_max_string(): "exc_type": "ZeroDivisionError", "exc_value": "division by zero", "exc_notes": [], + "exceptions": [], "frames": [ { "filename": __file__, @@ -700,6 +784,7 @@ def test_json_traceback_locals_max_string(): } ], "is_cause": False, + "is_group": False, "syntax_error": None, }, ] == result @@ -844,6 +929,76 @@ def test_json_traceback_value_error( tracebacks.ExceptionDictTransformer(**kwargs) +@pytest.mark.skipif( + sys.version_info < (3, 11), reason="Requires Python 3.11 or higher" +) +def test_json_exception_groups() -> None: + """ + When rendered as JSON, the "Trace.stacks" is stripped, so "exceptions" is a + list of lists and not a list of objects (with a single "stacks" attribute. + """ + + lineno = get_next_lineno() + + async def t1() -> None: + 1 / 0 + + async def t2() -> None: + raise ValueError("Blam!") + + async def main(): + async with asyncio.TaskGroup() as tg: + tg.create_task(t1()) + tg.create_task(t2()) + + try: + asyncio.run(main()) + except Exception as e: + format_json = tracebacks.ExceptionDictTransformer(show_locals=False) + result = format_json((type(e), e, e.__traceback__)) + + assert "ExceptionGroup" == result[0]["exc_type"] + exceptions = result[0]["exceptions"] + assert [ + [ + { + "exc_type": "ZeroDivisionError", + "exc_value": "division by zero", + "exc_notes": [], + "syntax_error": None, + "is_cause": False, + "frames": [ + { + "filename": __file__, + "lineno": lineno + 2, + "name": "t1", + } + ], + "is_group": False, + "exceptions": [], + } + ], + [ + { + "exc_type": "ValueError", + "exc_value": "Blam!", + "exc_notes": [], + "syntax_error": None, + "is_cause": False, + "frames": [ + { + "filename": __file__, + "lineno": lineno + 5, + "name": "t2", + } + ], + "is_group": False, + "exceptions": [], + } + ], + ] == exceptions + + class TestLogException: """ Higher level integration tests for `Logger.exception()`. From 5d9c7f8ef81c9de40a3644cd3216409d771ecdd5 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 29 May 2025 12:15:27 +0200 Subject: [PATCH 1367/1520] docs: clarify compat --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87601113..213f331c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ### Added - Support for Python 3.14 and Python 3.13.4. + + Python 3.14 has an backwards-incompatible change to `logging.Logger.isEnabledFor()` (it now always returns False if a log entry is in flight) that has been backported to 3.13.4 (expected on 2025-06-03). + It mainly affects `structlog.stdlib.filter_by_level()`. [#723](https://github.com/hynek/structlog/pull/723) - `structlog.tracebacks` now handles [exception groups](https://docs.python.org/3/library/exceptions.html#exception-groups). From bcc2df82d6fd9bd9d09e0e060fcf2833a9b0e846 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 29 May 2025 12:17:01 +0200 Subject: [PATCH 1368/1520] docs: add missing link --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 213f331c..26f03d81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ### Fixed - `structlog.processors.ExceptionPrettyPrinter` now respects the *exception_formatter* arguments instead of always using the default formatter. + [#724](https://github.com/hynek/structlog/pull/724) ## [25.3.0](https://github.com/hynek/structlog/compare/25.2.0...25.3.0) - 2025-04-25 From 5e57018d460ace553077883751d6e6be9d7396ac Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 29 May 2025 13:57:23 +0200 Subject: [PATCH 1369/1520] Make Dr Zizmor happy --- .github/workflows/ci.yml | 2 +- zizmor.yml | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 zizmor.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6e062cae..5ccb9c42 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -232,7 +232,7 @@ jobs: steps: - name: Decide whether the needed jobs succeeded or failed - uses: re-actors/alls-green@release/v1 + uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2 with: jobs: ${{ toJSON(needs) }} diff --git a/zizmor.yml b/zizmor.yml new file mode 100644 index 00000000..eb9e5b8b --- /dev/null +++ b/zizmor.yml @@ -0,0 +1,9 @@ +--- +rules: + unpinned-uses: + config: + policies: + "actions/*": ref-pin + "github/*": ref-pin + "pypa/*": ref-pin + "hynek/*": ref-pin From 034f067ed904406fcad33d0cb0dd0335135e9051 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 29 May 2025 14:54:14 +0200 Subject: [PATCH 1370/1520] Add explanation --- zizmor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/zizmor.yml b/zizmor.yml index eb9e5b8b..f06684f6 100644 --- a/zizmor.yml +++ b/zizmor.yml @@ -3,6 +3,7 @@ rules: unpinned-uses: config: policies: + # We trust GitHub, the PyPA and ourselves. "actions/*": ref-pin "github/*": ref-pin "pypa/*": ref-pin From ea14fda0c7067237292f4f214890054c77036e0e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 29 May 2025 15:56:53 +0200 Subject: [PATCH 1371/1520] Oxford! --- zizmor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zizmor.yml b/zizmor.yml index f06684f6..1bab80ba 100644 --- a/zizmor.yml +++ b/zizmor.yml @@ -3,7 +3,7 @@ rules: unpinned-uses: config: policies: - # We trust GitHub, the PyPA and ourselves. + # We trust GitHub, the PyPA, and ourselves. "actions/*": ref-pin "github/*": ref-pin "pypa/*": ref-pin From d9480273261e4d55d05465c434c41c7e25af4dde Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 29 May 2025 15:57:37 +0200 Subject: [PATCH 1372/1520] Update Ruff --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 31fe1366..9d72d8c0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,9 +4,9 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.11.11 + rev: v0.11.12 hooks: - - id: ruff + - id: ruff-check args: [--fix, --exit-non-zero-on-fix] - id: ruff-format From e941e337d312eaf256595d9d09da4542c5e94d0b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 30 May 2025 07:33:29 +0200 Subject: [PATCH 1373/1520] ci: work around weird new failure in Mypy 1.16 --- tox.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tox.ini b/tox.ini index 113251af..82404dc6 100644 --- a/tox.ini +++ b/tox.ini @@ -79,6 +79,8 @@ commands = pre-commit run --all-files [testenv:mypy-pkg] dependency_groups = typing commands = mypy src +# 1.16 fails with a "redundant cast/I need a cast!" flip-flop in stdlib.py +deps = mypy<1.16 [testenv:pyright] From 57e165bfacb79eb5942389c20eb9d883d88bfcb6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 30 May 2025 10:42:56 +0200 Subject: [PATCH 1374/1520] Make Mypy 1.16 pass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tin Tvrtković <1909233+tinche@users.noreply.github.com> --- src/structlog/stdlib.py | 2 +- tox.ini | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 2c49b788..27998e46 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -1157,7 +1157,7 @@ def format(self, record: logging.LogRecord) -> str: record.stack_info = None for p in self.processors: - ed = p(logger, meth_name, cast(EventDict, ed)) + ed = p(logger, meth_name, ed) # type: ignore[arg-type] if not isinstance(ed, str): warnings.warn( diff --git a/tox.ini b/tox.ini index 82404dc6..113251af 100644 --- a/tox.ini +++ b/tox.ini @@ -79,8 +79,6 @@ commands = pre-commit run --all-files [testenv:mypy-pkg] dependency_groups = typing commands = mypy src -# 1.16 fails with a "redundant cast/I need a cast!" flip-flop in stdlib.py -deps = mypy<1.16 [testenv:pyright] From d38385cda711f62ad56018abfd72d4384f94e3ce Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 2 Jun 2025 10:06:07 +0200 Subject: [PATCH 1375/1520] Prepare 25.4.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26f03d81..526adc5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ -## [Unreleased](https://github.com/hynek/structlog/compare/25.3.0...HEAD) +## [25.4.0](https://github.com/hynek/structlog/compare/25.3.0...25.4.0) - 2025-06-02 ### Added From 480ae5f2bcd7e77669bd40b43c329bfbc5f5bd31 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 2 Jun 2025 10:16:03 +0200 Subject: [PATCH 1376/1520] Start new development cycle --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 526adc5d..e1223594 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ +## [Unreleased](https://github.com/hynek/structlog/compare/25.4.0...HEAD) + + ## [25.4.0](https://github.com/hynek/structlog/compare/25.3.0...25.4.0) - 2025-06-02 ### Added From bc753c2864356adc0ac24ee8c58a3d0aa04ae717 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 4 Jul 2025 15:19:27 +0200 Subject: [PATCH 1377/1520] ci: fix Pyright job name --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5ccb9c42..89358919 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -150,7 +150,7 @@ jobs: pyright: - name: Pyright Codebase + name: Pyright API runs-on: ubuntu-latest needs: build-package steps: From 0cbe543192fc48a8afc82dc60db1db17fab39dab Mon Sep 17 00:00:00 2001 From: "Axel H." Date: Wed, 23 Jul 2025 16:03:56 +0200 Subject: [PATCH 1378/1520] feat(rich): expose `code_width` and delegate full width handling to `rich` (#717) * feat(rich): expose `code_width` and use the full terminal width by default * Fix changelog * Update tests/test_dev.py --------- Co-authored-by: Hynek Schlawack --- CHANGELOG.md | 6 +++++ src/structlog/dev.py | 62 ++++++++++++++++++++++++++++---------------- tests/test_dev.py | 35 ++++++++++++++++++++++--- 3 files changed, 77 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1223594..64a41c2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,12 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ This works similarly to what Rich v14.0.0 does. [#720](https://github.com/hynek/structlog/pull/720) +- `structlog.dev.RichTracebackFormatter` now exposes the upstream *code_width* parameter. + Default *width* is now `None` for full terminal width. + Full terminal width is now handled by Rich itself, bringing support for reflow and `COLUMN` environment variable. + Passing `-1` for *width* is now deprecated and automatically replaced by `None`. + [#717](https://github.com/hynek/structlog/pull/717) + ### Fixed diff --git a/src/structlog/dev.py b/src/structlog/dev.py index fd3f6984..88889b99 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -11,7 +11,6 @@ from __future__ import annotations -import shutil import sys import warnings @@ -348,10 +347,18 @@ class RichTracebackFormatter: See :class:`rich.traceback.Traceback` for details on the arguments. - If a *width* of -1 is passed, the terminal width is used. If the width - can't be determined, fall back to 80. + If *width* is `None`, the terminal width is used. If the width can't be + determined, fall back to 80. .. versionadded:: 23.2.0 + + .. versionchanged:: 25.4.0 + Default *width* is ``None`` to have full width and reflow support. + Passing ``-1`` as width is deprecated, use ``None`` instead. + *word_wrap* is now True by default. + + .. versionadded:: 25.4.0 + *code_width* """ color_system: Literal[ @@ -360,9 +367,10 @@ class RichTracebackFormatter: show_locals: bool = True max_frames: int = 100 theme: str | None = None - word_wrap: bool = False + word_wrap: bool = True extra_lines: int = 3 - width: int = 100 + width: int | None = None + code_width: int | None = 88 indent_guides: bool = True locals_max_length: int = 10 locals_max_string: int = 80 @@ -372,29 +380,37 @@ class RichTracebackFormatter: def __call__(self, sio: TextIO, exc_info: ExcInfo) -> None: if self.width == -1: - self.width, _ = shutil.get_terminal_size((80, 0)) + warnings.warn( + "Use None to use the terminal width instead of -1.", + DeprecationWarning, + stacklevel=2, + ) + self.width = None sio.write("\n") - Console( + console = Console( file=sio, color_system=self.color_system, width=self.width - ).print( - Traceback.from_exception( - *exc_info, - show_locals=self.show_locals, - max_frames=self.max_frames, - theme=self.theme, - word_wrap=self.word_wrap, - extra_lines=self.extra_lines, - width=self.width, - indent_guides=self.indent_guides, - locals_max_length=self.locals_max_length, - locals_max_string=self.locals_max_string, - locals_hide_dunder=self.locals_hide_dunder, - locals_hide_sunder=self.locals_hide_sunder, - suppress=self.suppress, - ) ) + tb = Traceback.from_exception( + *exc_info, + show_locals=self.show_locals, + max_frames=self.max_frames, + theme=self.theme, + word_wrap=self.word_wrap, + extra_lines=self.extra_lines, + width=self.width, + indent_guides=self.indent_guides, + locals_max_length=self.locals_max_length, + locals_max_string=self.locals_max_string, + locals_hide_dunder=self.locals_hide_dunder, + locals_hide_sunder=self.locals_hide_sunder, + suppress=self.suppress, + ) + if hasattr(tb, "code_width"): + # `code_width` requires `rich>=13.8.0` + tb.code_width = self.code_width + console.print(tb) rich_traceback = RichTracebackFormatter() diff --git a/tests/test_dev.py b/tests/test_dev.py index 89871300..9af2e5b6 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -671,17 +671,46 @@ def test_does_not_blow_up(self, sio): def test_width_minus_one(self, sio): """ - If width is -1, it's replaced by the terminal width on first use. + If width is -1, it raises a DeprecationWarning and is replaced by None to let `rich` handle it. """ rtf = dev.RichTracebackFormatter(width=-1) - with mock.patch("shutil.get_terminal_size", return_value=(42, 0)): + with pytest.deprecated_call(): try: 0 / 0 except ZeroDivisionError: rtf(sio, sys.exc_info()) - assert 42 == rtf.width + assert rtf.width is None + + @pytest.mark.parametrize("code_width_support", [True, False]) + def test_code_width_support(self, sio, code_width_support): + """ + If rich does not support code_width, it should not fail + """ + from rich.traceback import Trace + + tb = mock.Mock( + spec=[ + attr + for attr in dir(dev.Traceback(Trace([]))) + if (code_width_support or attr != "code_width") + ] + ) + tb.__rich_console__.return_value = "for Python 3.8 compatibility" + + with mock.patch.object( + dev.Traceback, "from_exception", return_value=tb + ) as factory: + try: + 0 / 0 + except ZeroDivisionError: + dev.rich_traceback(sio, sys.exc_info()) + + assert "code_width" not in factory.call_args.kwargs + + if code_width_support: + assert tb.code_width == 88 @pytest.mark.skipif( From 70ca975d1c8169229cda2198aed289f929a6e735 Mon Sep 17 00:00:00 2001 From: Oscar Linderoth <56576927+l1nd3r0th@users.noreply.github.com> Date: Wed, 23 Jul 2025 14:35:44 +0000 Subject: [PATCH 1379/1520] Add processors param to capture_logs() (#728) * Add processors param to capture_logs() * Update tests/test_testing.py * Update tests/test_testing.py * Update tests/test_testing.py --------- Co-authored-by: Hynek Schlawack --- CHANGELOG.md | 3 +++ docs/testing.md | 13 +++++++++++++ src/structlog/testing.py | 29 ++++++++++++++++++----------- tests/test_testing.py | 26 +++++++++++++++++++++++++- 4 files changed, 59 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64a41c2d..c0829084 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ## [Unreleased](https://github.com/hynek/structlog/compare/25.4.0...HEAD) +### Added + +- `structlog.testing.capture_logs()` now optionally accepts `processors` to apply before capture ## [25.4.0](https://github.com/hynek/structlog/compare/25.3.0...25.4.0) - 2025-06-02 diff --git a/docs/testing.md b/docs/testing.md index 33f8be6f..9834c148 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -15,6 +15,19 @@ If you need functionality similar to {meth}`unittest.TestCase.assertLogs`, or yo Note that inside the context manager all configured processors are disabled. +If you want to capture logs after certain processors have been applied, they can be passed to the context manager. +For example, to capture {doc}`contextvars`: + +```{doctest} +>>> from structlog import contextvars, get_logger +>>> from structlog.testing import capture_logs +>>> with capture_logs(processors=[contextvars.merge_contextvars]) as cap_logs: +... _ = contextvars.bind_contextvars(x="y") +... get_logger().info("hello") +>>> cap_logs +[{'event': 'hello', 'x': 'y', 'log_level': 'info'}] +``` + :::{note} `capture_logs()` relies on changing the configuration. If you have *cache_logger_on_first_use* enabled for {doc}`performance `, any cached loggers will not be affected, so it’s recommended you do not enable it during tests. diff --git a/src/structlog/testing.py b/src/structlog/testing.py index 797372da..a0ab0c65 100644 --- a/src/structlog/testing.py +++ b/src/structlog/testing.py @@ -14,12 +14,12 @@ from __future__ import annotations from contextlib import contextmanager -from typing import Any, Generator, NamedTuple, NoReturn +from typing import Any, Generator, Iterable, NamedTuple, NoReturn from ._config import configure, get_config from ._log_levels import map_method_name from .exceptions import DropEvent -from .typing import EventDict, WrappedLogger +from .typing import EventDict, Processor, WrappedLogger __all__ = [ @@ -63,7 +63,9 @@ def __call__( @contextmanager -def capture_logs() -> Generator[list[EventDict], None, None]: +def capture_logs( + processors: Iterable[Processor] = (), +) -> Generator[list[EventDict], None, None]: """ Context manager that appends all logging statements to its yielded list while it is active. Disables all configured processors for the duration @@ -71,25 +73,30 @@ def capture_logs() -> Generator[list[EventDict], None, None]: Attention: this is **not** thread-safe! + Args: + processors: Processors to apply before the logs are captured + .. versionadded:: 20.1.0 + .. versionadded:: 25.5.0 *processors* parameter """ cap = LogCapture() # Modify `_Configuration.default_processors` set via `configure` but always # keep the list instance intact to not break references held by bound # loggers. - processors = get_config()["processors"] - old_processors = processors.copy() + configured_processors = get_config()["processors"] + old_processors = configured_processors.copy() try: # clear processors list and use LogCapture for testing - processors.clear() - processors.append(cap) - configure(processors=processors) + configured_processors.clear() + configured_processors.extend(processors) + configured_processors.append(cap) + configure(processors=configured_processors) yield cap.entries finally: # remove LogCapture and restore original processors - processors.clear() - processors.extend(old_processors) - configure(processors=processors) + configured_processors.clear() + configured_processors.extend(old_processors) + configure(processors=configured_processors) class ReturnLogger: diff --git a/tests/test_testing.py b/tests/test_testing.py index 78d6246b..72f0085f 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -7,7 +7,7 @@ import structlog -from structlog import get_config, get_logger, testing +from structlog import contextvars, get_config, get_logger, testing from structlog.testing import ( CapturedCall, CapturingLogger, @@ -56,6 +56,30 @@ def test_restores_processors_on_success(self): assert orig_procs is restored_procs assert len(restored_procs) > 1 + def test_uses_processors_arg_and_restores_on_success(self): + """ + Processors passed with `processors` arg are active only until context + exits. + """ + orig_procs = self.get_active_procs() + + assert len(orig_procs) > 1 + + with testing.capture_logs(processors=[contextvars.merge_contextvars]): + modified_procs = self.get_active_procs() + + assert len(modified_procs) == 2 + assert contextvars.merge_contextvars == modified_procs[0] + assert isinstance(modified_procs[1], LogCapture) + assert len(modified_procs) == 2 + assert contextvars.merge_contextvars == modified_procs[0] + assert isinstance(modified_procs[1], LogCapture) + + restored_procs = self.get_active_procs() + + assert orig_procs is restored_procs + assert len(restored_procs) > 1 + def test_restores_processors_on_error(self): """ Processors are restored even on errors. From 074b9e1363e15b4cc2330e6a08505c3fd8fd0b07 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 23 Jul 2025 16:37:51 +0200 Subject: [PATCH 1380/1520] Update changelog --- CHANGELOG.md | 16 +++++++++------- src/structlog/dev.py | 3 +-- src/structlog/testing.py | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0829084..c38ddd2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,15 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ### Added -- `structlog.testing.capture_logs()` now optionally accepts `processors` to apply before capture +- `structlog.testing.capture_logs()` now optionally accepts *processors* to apply before capture. + [#728](https://github.com/hynek/structlog/pull/728) + +- `structlog.dev.RichTracebackFormatter` now exposes the upstream *code_width* parameter. + Default *width* is now `None` for full terminal width. + Full terminal width is now handled by Rich itself, bringing support for reflow and `COLUMN` environment variable. + Passing `-1` for *width* is now deprecated and automatically replaced by `None`. + [#717](https://github.com/hynek/structlog/pull/717) + ## [25.4.0](https://github.com/hynek/structlog/compare/25.3.0...25.4.0) - 2025-06-02 @@ -34,12 +42,6 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ This works similarly to what Rich v14.0.0 does. [#720](https://github.com/hynek/structlog/pull/720) -- `structlog.dev.RichTracebackFormatter` now exposes the upstream *code_width* parameter. - Default *width* is now `None` for full terminal width. - Full terminal width is now handled by Rich itself, bringing support for reflow and `COLUMN` environment variable. - Passing `-1` for *width* is now deprecated and automatically replaced by `None`. - [#717](https://github.com/hynek/structlog/pull/717) - ### Fixed diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 88889b99..beac9bb7 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -357,8 +357,7 @@ class RichTracebackFormatter: Passing ``-1`` as width is deprecated, use ``None`` instead. *word_wrap* is now True by default. - .. versionadded:: 25.4.0 - *code_width* + .. versionadded:: 25.4.0 *code_width* """ color_system: Literal[ diff --git a/src/structlog/testing.py b/src/structlog/testing.py index a0ab0c65..8271d1e9 100644 --- a/src/structlog/testing.py +++ b/src/structlog/testing.py @@ -74,7 +74,7 @@ def capture_logs( Attention: this is **not** thread-safe! Args: - processors: Processors to apply before the logs are captured + processors: Processors to apply before the logs are captured. .. versionadded:: 20.1.0 .. versionadded:: 25.5.0 *processors* parameter From 65636b30feeb261c3289ca96e699a9b51d4d554c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 23 Jul 2025 16:45:53 +0200 Subject: [PATCH 1381/1520] Update Ruff --- .pre-commit-config.yaml | 2 +- pyproject.toml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9d72d8c0..b876a7e1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.11.12 + rev: v0.12.4 hooks: - id: ruff-check args: [--fix, --exit-non-zero-on-fix] diff --git a/pyproject.toml b/pyproject.toml index 2b6854e2..7f0f47ca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -139,8 +139,10 @@ ignore = [ "N802", # some names are non-pep8 due to stdlib logging / Twisted "N803", # ditto "N806", # ditto + "PLC0415", # sometimes, imports have to live elsewhere "PLR0913", # leave complexity to me "PLR2004", # numbers are sometimes fine + "PLW1641", # unhashable is often fine "PLW2901", # overwriting a loop var can be useful "RUF001", # leave my smart characters alone "SLF001", # private members are accessed by friendly functions From 1f7765e7645e42cdf0f228cc75d531ace3d31e92 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 29 Jul 2025 17:13:24 +0200 Subject: [PATCH 1382/1520] Raise useful error if trying to use RichTracebackFormatter w/o Rich (#735) * Raise useful error if trying to use RichTracebackFormatter w/o Rich Fixes #733 * Optimize * Add changelog entry --- CHANGELOG.md | 6 ++++++ src/structlog/dev.py | 25 +++++++++++++++++-------- tests/test_dev.py | 13 +++++++++++++ 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c38ddd2f..14e0dcc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,12 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ [#717](https://github.com/hynek/structlog/pull/717) +### Changed + +- `structlog.dev.rich_traceback()` now throws a more helpful error when Rich is missing. + [#735](https://github.com/hynek/structlog/pull/735) + + ## [25.4.0](https://github.com/hynek/structlog/compare/25.3.0...25.4.0) - 2025-06-02 ### Added diff --git a/src/structlog/dev.py b/src/structlog/dev.py index beac9bb7..f49b38a0 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -412,17 +412,26 @@ def __call__(self, sio: TextIO, exc_info: ExcInfo) -> None: console.print(tb) -rich_traceback = RichTracebackFormatter() -""" -Pretty-print *exc_info* to *sio* using the Rich package. +if rich is None: -To be passed into `ConsoleRenderer`'s ``exception_formatter`` argument. + def rich_traceback(*args, **kw): + raise ModuleNotFoundError( + "RichTracebackFormatter requires Rich to be installed.", + name="rich", + ) -This is a `RichTracebackFormatter` with default arguments and used by default -if Rich is installed. +else: + rich_traceback = RichTracebackFormatter() + """ + Pretty-print *exc_info* to *sio* using the Rich package. -.. versionadded:: 21.2.0 -""" + To be passed into `ConsoleRenderer`'s ``exception_formatter`` argument. + + This is a `RichTracebackFormatter` with default arguments and used by default + if Rich is installed. + + .. versionadded:: 21.2.0 + """ def better_traceback(sio: TextIO, exc_info: ExcInfo) -> None: diff --git a/tests/test_dev.py b/tests/test_dev.py index 9af2e5b6..558d4016 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -649,6 +649,19 @@ def test_set_it(self): assert {"exc_info": True} == dev.set_exc_info(None, "exception", {}) +@pytest.mark.skipif(dev.rich is not None, reason="Needs missing Rich.") +def test_rich_traceback_formatter_no_rich(): + """ + Trying to use RichTracebackFormatter without Rich should raise an helpful + error. + """ + with pytest.raises( + ModuleNotFoundError, + match="RichTracebackFormatter requires Rich to be installed.", + ): + dev.rich_traceback(StringIO(), sys.exc_info()) + + @pytest.mark.skipif(dev.rich is None, reason="Needs Rich.") class TestRichTracebackFormatter: def test_default(self): From f654adf89488778a81a616f15e9b9b3999a19cfd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 29 Jul 2025 17:18:57 +0200 Subject: [PATCH 1383/1520] Update sponsors update ruff --- .pre-commit-config.yaml | 2 +- README.md | 1 - docs/index.md | 1 - pyproject.toml | 5 ----- 4 files changed, 1 insertion(+), 8 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b876a7e1..a5660402 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.12.4 + rev: v0.12.5 hooks: - id: ruff-check args: [--fix, --exit-non-zero-on-fix] diff --git a/README.md b/README.md index 0f7fbdf7..4336066d 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,6 @@ for sponsor in tomllib.loads(pathlib.Path("pyproject.toml").read_text())["tool"] - diff --git a/docs/index.md b/docs/index.md index 61a318db..2a179f1a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -23,7 +23,6 @@ for sponsor in tomllib.loads(pathlib.Path("pyproject.toml").read_text())["tool"] - diff --git a/pyproject.toml b/pyproject.toml index 7f0f47ca..e2f8ce2a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -267,11 +267,6 @@ title = "Privacy Solutions" url = "https://privacy-solutions.org/" img = "Privacy-Solutions.svg" -[[tool.sponcon.sponsors]] -title = "emsys renewables" -url = "https://www.emsys-renewables.com/" -img = "emsys-renewables.svg" - [[tool.sponcon.sponsors]] title = "FilePreviews" url = "https://filepreviews.io/" From 8527f1306794499968f78f3371318cd4654ffc1f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 31 Jul 2025 11:20:17 +0200 Subject: [PATCH 1384/1520] Improve install instructions --- .github/CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 53033c27..7833d369 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -63,7 +63,7 @@ layout python python$(cat .python-version-default) or, if you like [*uv*](https://github.com/astral-sh/uv): ```bash -test -d .venv || uv venv --python python$(cat .python-version-default) +test -d .venv || (uv venv --python $(cat .python-version-default) && uv pip install -e . --group dev) . .venv/bin/activate ``` From 383ce0ffa0fa26ca3e572de3722092f217e2f24f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 31 Jul 2025 11:21:07 +0200 Subject: [PATCH 1385/1520] Add typing test for contextvars.bound_contextvars --- tests/typing/api.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/typing/api.py b/tests/typing/api.py index 1ca1b91c..473b8254 100644 --- a/tests/typing/api.py +++ b/tests/typing/api.py @@ -358,3 +358,12 @@ def typecheck_bound_logger_return() -> None: level: int = fbl.get_effective_level() is_active: bool = fbl.is_enabled_for(logging.INFO) is_active = fbl.is_enabled_for(20) + + +# contextvars + + +@structlog.contextvars.bound_contextvars(x=42) +def f() -> None: + with structlog.contextvars.bound_contextvars(y=23): + pass From 3882f8dda66e7945ddae3ba28eeab37ca8d6ad7a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 31 Jul 2025 11:40:03 +0200 Subject: [PATCH 1386/1520] Fix nonsensical typing tests --- tests/typing/api.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/typing/api.py b/tests/typing/api.py index 473b8254..08894ea7 100644 --- a/tests/typing/api.py +++ b/tests/typing/api.py @@ -78,13 +78,14 @@ def bytes_dumps( processors=[ structlog.processors.CallsiteParameterAdder(), structlog.processors.CallsiteParameterAdder( - set(CallsiteParameter), ["threading"] + {CallsiteParameter.FILENAME}, ["threading"] ), structlog.processors.CallsiteParameterAdder( - set(CallsiteParameter), additional_ignores=["threading"] + {CallsiteParameter.LINENO}, additional_ignores=["threading"] ), structlog.processors.CallsiteParameterAdder( - parameters=set(CallsiteParameter), additional_ignores=["threading"] + parameters={CallsiteParameter.FUNC_NAME}, + additional_ignores=["threading"], ), structlog.processors.CallsiteParameterAdder( [ From 89a903b09e1ecd75b32bddb42cbf96576534b44b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 31 Jul 2025 11:59:23 +0200 Subject: [PATCH 1387/1520] Bring AsyncBoundLogger closer to protocol contract --- src/structlog/stdlib.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 27998e46..b8e0a6bb 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -573,8 +573,8 @@ def __init__( def _context(self) -> Context: return self.sync_bl._context - def bind(self, **new_values: Any) -> AsyncBoundLogger: - return AsyncBoundLogger( + def bind(self, **new_values: Any) -> Self: + return self.__class__( # logger, processors and context are within sync_bl. These # arguments are ignored if _sync_bl is passed. *vroom vroom* over # purity. @@ -585,8 +585,8 @@ def bind(self, **new_values: Any) -> AsyncBoundLogger: _loop=self._loop, ) - def new(self, **new_values: Any) -> AsyncBoundLogger: - return AsyncBoundLogger( + def new(self, **new_values: Any) -> Self: + return self.__class__( # c.f. comment in bind logger=None, # type: ignore[arg-type] processors=(), @@ -595,8 +595,8 @@ def new(self, **new_values: Any) -> AsyncBoundLogger: _loop=self._loop, ) - def unbind(self, *keys: str) -> AsyncBoundLogger: - return AsyncBoundLogger( + def unbind(self, *keys: str) -> Self: + return self.__class__( # c.f. comment in bind logger=None, # type: ignore[arg-type] processors=(), @@ -605,8 +605,8 @@ def unbind(self, *keys: str) -> AsyncBoundLogger: _loop=self._loop, ) - def try_unbind(self, *keys: str) -> AsyncBoundLogger: - return AsyncBoundLogger( + def try_unbind(self, *keys: str) -> Self: + return self.__class__( # c.f. comment in bind logger=None, # type: ignore[arg-type] processors=(), From 3bc3268ce36801727d7aa71e769a05cf8fd419fa Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 31 Jul 2025 12:40:39 +0200 Subject: [PATCH 1388/1520] typing: make BindableLogger._context read-only Nobody is writing into it except a deprecated threadlocal API. --- src/structlog/stdlib.py | 8 +------- src/structlog/threadlocal.py | 2 +- src/structlog/typing.py | 3 ++- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index b8e0a6bb..af2ff30c 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -537,10 +537,6 @@ class AsyncBoundLogger: #: synchronously occasionally. sync_bl: BoundLogger - # Blatant lie, we use a property for _context. Need this for Protocol - # though. - _context: Context - _executor = None _bound_logger_factory = BoundLogger @@ -565,11 +561,9 @@ def __init__( ) self._loop = asyncio.get_running_loop() - # We have to ignore the type because we've already declared it to ensure - # we're a BindableLogger. # Instances would've been correctly recognized as such, however the class # not and we need the class in `structlog.configure()`. - @property # type: ignore[no-redef] + @property def _context(self) -> Context: return self.sync_bl._context diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index 7c827c2e..0ea71f3a 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -127,7 +127,7 @@ def as_immutable(logger: TLLogger) -> TLLogger: processors=logger._processors, # type: ignore[attr-defined] context={}, ) - bl._context = ctx + bl._context = ctx # type: ignore[misc] return bl except AttributeError: diff --git a/src/structlog/typing.py b/src/structlog/typing.py index 4fe9e0cd..c86d2808 100644 --- a/src/structlog/typing.py +++ b/src/structlog/typing.py @@ -136,7 +136,8 @@ class BindableLogger(Protocol): .. versionadded:: 20.2.0 """ - _context: Context + @property + def _context(self) -> Context: ... def bind(self, **new_values: Any) -> Self: ... From 16957ea4f382c8c2008276fa98df9ff71f7d951a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 4 Aug 2025 07:01:54 +0200 Subject: [PATCH 1389/1520] Let's be more legible --- docs/_static/custom.css | 4 ++-- docs/conf.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/_static/custom.css b/docs/_static/custom.css index b0c135ed..b5bbc2d3 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -1,4 +1,4 @@ -@import url(https://fonts.bunny.net/css?family=b612:400,400i,700,700i); +@import url(https://fonts.bunny.net/css?family=atkinson-hyperlegible:400,400i,700,700i); @import url('https://assets.hynek.me/css/bm.css'); @@ -9,7 +9,7 @@ @supports (font-variation-settings: normal) { :root { - font-family: 'B612', sans-serif; + font-family: 'Atkinson Hyperlegible', sans-serif; } } diff --git a/docs/conf.py b/docs/conf.py index 6f1b2c0d..0b7d83a6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -102,7 +102,7 @@ html_theme_options = { "top_of_page_buttons": [], "light_css_variables": { - "font-stack": "B612, sans-serif", + "font-stack": "Atkinson Hyperlegible, sans-serif", "font-stack--monospace": "BerkeleyMono, MonoLisa, ui-monospace, " "SFMono-Regular, Menlo, Consolas, Liberation Mono, monospace", }, From 5a0eb1df7fe309c28cead9c67242dc1e77a900d5 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 4 Aug 2025 10:03:05 +0200 Subject: [PATCH 1390/1520] Fix tox -p coverage --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 113251af..4451f2d9 100644 --- a/tox.ini +++ b/tox.ini @@ -37,7 +37,7 @@ deps = coverage[toml] skip_install = true parallel_show_output = true # Keep in-sync with test env definition above. -depends = py3{8,13}-{tests,colorama,be,rich} +depends = py3{8,13}-tests{,colorama,be,rich} commands = coverage combine coverage report From d5e9bf2e9988bd08591bcc8b3ad1eaebf21b60cc Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 4 Aug 2025 20:24:46 +0200 Subject: [PATCH 1391/1520] [pre-commit.ci] pre-commit autoupdate (#737) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.12.5 → v0.12.7](https://github.com/astral-sh/ruff-pre-commit/compare/v0.12.5...v0.12.7) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a5660402..d479615c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.12.5 + rev: v0.12.7 hooks: - id: ruff-check args: [--fix, --exit-non-zero-on-fix] From 3ac0ae586c0046103f13e273382ee7be2715966f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 5 Aug 2025 09:01:56 +0200 Subject: [PATCH 1392/1520] Simplify coverage config --- pyproject.toml | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e2f8ce2a..26356d40 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -92,22 +92,6 @@ source = ["src", ".tox/py*/**/site-packages"] show_missing = true skip_covered = true omit = ["src/structlog/_greenlets.py"] -exclude_lines = [ - # a more strict default pragma - "\\# pragma: no cover\\b", - - # allow defensive code - "^\\s*raise AssertionError\\b", - "^\\s*raise NotImplementedError\\b", - "^\\s*return NotImplemented\\b", - "^\\s*raise$", - - # typing-related code - "^if (False|TYPE_CHECKING):", - ": \\.\\.\\.(\\s*#.*)?$", - "^ +\\.\\.\\.$", - "-> ['\"]?NoReturn['\"]?:", -] [tool.interrogate] From 9f065611e80bdb102a0e70548969c65336479a15 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 18 Aug 2025 11:19:37 +0200 Subject: [PATCH 1393/1520] tests: migrate from freezegun to time-machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace freezegun usage in tests with time-machine decorators/context and switch test dependency to time-machine. This avoids freezegun’s time.time limitations and aligns with recommended migration path. --- pyproject.toml | 2 +- tests/processors/test_renderers.py | 38 +++++++++++++----------------- tests/test_generic.py | 5 ++-- 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 26356d40..0fc4fc33 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,7 +41,7 @@ Twitter = "https://twitter.com/hynek" [dependency-groups] tests = [ - "freezegun>=0.2.8", + "time-machine>=2.14.1", "pretend", "pytest-asyncio>=0.17", "pytest>=6.0", diff --git a/tests/processors/test_renderers.py b/tests/processors/test_renderers.py index 1bef95f0..3cf27a58 100644 --- a/tests/processors/test_renderers.py +++ b/tests/processors/test_renderers.py @@ -10,8 +10,7 @@ import pickle import pytest - -from freezegun import freeze_time +import time_machine from structlog.processors import ( ExceptionRenderer, @@ -390,10 +389,9 @@ def test_inserts_utc_unix_timestamp_by_default(self): ts = TimeStamper() d = ts(None, None, {}) - # freezegun doesn't work with time.time. :( assert isinstance(d["timestamp"], float) - @freeze_time("1980-03-25 16:00:00") + @time_machine.travel("1980-03-25 16:00:00") def test_local(self): """ Timestamp in local timezone work. Due to historic reasons, the default @@ -404,7 +402,7 @@ def test_local(self): assert "1980-03-25T16:00:00" == d["timestamp"] - @freeze_time("1980-03-25 16:00:00") + @time_machine.travel("1980-03-25 16:00:00") def test_formats(self): """ The fmt string is respected. @@ -414,14 +412,12 @@ def test_formats(self): assert "1980" == d["timestamp"] - @freeze_time("1980-03-25 16:00:00") + @time_machine.travel( + datetime.datetime(1980, 3, 25, 16, 0, 0, tzinfo=datetime.timezone.utc) + ) def test_inserts_formatted_utc(self): """ The fmt string in UTC timezone works. - - The exact hours calculated here maybe incorrect because of freezegun bugs: - https://github.com/spulec/freezegun/issues/348 - https://github.com/spulec/freezegun/issues/494 """ ts = TimeStamper(fmt="%Y-%m-%d %H:%M:%S %Z") @@ -429,14 +425,10 @@ def test_inserts_formatted_utc(self): assert "1980-03-25 16:00:00 UTC" == d["timestamp"] - @freeze_time("1980-03-25 16:00:00") + @time_machine.travel("1980-03-25 16:00:00") def test_inserts_formatted_local(self): """ The fmt string in local timezone works. - - The exact hours calculated here maybe incorrect because of freezegun bugs: - https://github.com/spulec/freezegun/issues/348 - https://github.com/spulec/freezegun/issues/494 """ local_tz = datetime.datetime.now().astimezone().tzname() ts = TimeStamper(fmt="%Y-%m-%d %H:%M:%S %Z", utc=False) @@ -444,7 +436,7 @@ def test_inserts_formatted_local(self): assert f"1980-03-25 16:00:00 {local_tz}" == d["timestamp"] - @freeze_time("1980-03-25 16:00:00") + @time_machine.travel("1980-03-25 16:00:00") def test_tz_aware(self): """ The timestamp that is used for formatting is timezone-aware. @@ -455,7 +447,9 @@ def test_tz_aware(self): assert "" == datetime.datetime.now().strftime("%z") # noqa: DTZ005 assert "" != d["timestamp"] - @freeze_time("1980-03-25 16:00:00") + @time_machine.travel( + datetime.datetime(1980, 3, 25, 16, 0, 0, tzinfo=datetime.timezone.utc) + ) def test_adds_Z_to_iso(self): """ stdlib's isoformat is buggy, so we fix it. @@ -465,7 +459,7 @@ def test_adds_Z_to_iso(self): assert "1980-03-25T16:00:00Z" == d["timestamp"] - @freeze_time("1980-03-25 16:00:00") + @time_machine.travel("1980-03-25 16:00:00") def test_key_can_be_specified(self): """ Timestamp is stored with the specified key. @@ -475,7 +469,7 @@ def test_key_can_be_specified(self): assert "03" == d["month"] - @freeze_time("1980-03-25 16:00:00") + @time_machine.travel("1980-03-25 16:00:00", tick=False) @pytest.mark.parametrize("fmt", [None, "%Y"]) @pytest.mark.parametrize("utc", [True, False]) @pytest.mark.parametrize("key", [None, "other-key"]) @@ -494,13 +488,15 @@ def test_pickle(self, fmt, utc, key, proto): None, None, {} ) - def test_apply_freezegun_after_instantiation(self): + def test_apply_time_machine_after_instantiation(self): """ Freezing time after instantiation of TimeStamper works. """ ts = TimeStamper(fmt="iso", utc=False) - with freeze_time("1980-03-25 16:00:00", tz_offset=1): + # Simulate a different local time by traveling to a different timestamp + # after the stamper was created. + with time_machine.travel("1980-03-25 17:00:00"): d = ts(None, None, {}) assert "1980-03-25T17:00:00" == d["timestamp"] diff --git a/tests/test_generic.py b/tests/test_generic.py index 4bc7b36e..1ef91b48 100644 --- a/tests/test_generic.py +++ b/tests/test_generic.py @@ -6,8 +6,7 @@ import pickle import pytest - -from freezegun import freeze_time +import time_machine from structlog._config import _CONFIG from structlog._generic import BoundLogger @@ -40,7 +39,7 @@ def test_caches(self): assert "msg" in b.__dict__ @pytest.mark.parametrize("proto", range(3, pickle.HIGHEST_PROTOCOL + 1)) - @freeze_time("2023-05-22 17:00") + @time_machine.travel("2023-05-22 17:00", tick=False) def test_pickle(self, proto): """ Can be pickled and unpickled. From 56a55923115f11a37ef1a23b69b98cd942a1c9cf Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 18 Aug 2025 16:08:31 +0200 Subject: [PATCH 1394/1520] docs: fix default logger fixes #738 --- docs/processors.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/processors.md b/docs/processors.md index b5f1fc62..5c6b13b5 100644 --- a/docs/processors.md +++ b/docs/processors.md @@ -13,8 +13,8 @@ Each processors receives three positional arguments: **logger** -: Your wrapped logger object. - For example {class}`logging.Logger` or {class}`structlog.typing.FilteringBoundLogger` (default). +: Your wrapped logger object that is called with the final processor return value. + For example {class}`logging.Logger` or {class}`structlog.PrintLogger` (default). **method_name** From 5f84c1244413080136fc2ea04538741fefd05d58 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Sep 2025 07:35:02 +0200 Subject: [PATCH 1395/1520] Bump actions/download-artifact from 4 to 5 (#744) Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 5. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 10 +++++----- .github/workflows/pypi-package.yml | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 89358919..7cf2fe4f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,7 +51,7 @@ jobs: steps: - name: Download pre-built packages - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: Packages path: dist @@ -101,7 +101,7 @@ jobs: - uses: hynek/setup-cached-uv@v2 - name: Download coverage data - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: pattern: coverage-data-* merge-multiple: true @@ -134,7 +134,7 @@ jobs: steps: - name: Download pre-built packages - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: Packages path: dist @@ -155,7 +155,7 @@ jobs: needs: build-package steps: - name: Download pre-built packages - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: Packages path: dist @@ -176,7 +176,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download pre-built packages - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: Packages path: dist diff --git a/.github/workflows/pypi-package.yml b/.github/workflows/pypi-package.yml index 9417b97d..65f67d0c 100644 --- a/.github/workflows/pypi-package.yml +++ b/.github/workflows/pypi-package.yml @@ -43,7 +43,7 @@ jobs: steps: - name: Download packages built by build-and-inspect-python-package - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: Packages path: dist @@ -66,7 +66,7 @@ jobs: steps: - name: Download packages built by build-and-inspect-python-package - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: Packages path: dist From d8fc180d39e225ca209b881f21dbe63ec11b0652 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Sep 2025 07:40:01 +0200 Subject: [PATCH 1396/1520] Bump actions/checkout from 4 to 5 (#743) Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Hynek Schlawack --- .github/workflows/build-docset.yml | 2 +- .github/workflows/ci.yml | 8 ++++---- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/pypi-package.yml | 2 +- .github/workflows/zizmor.yml | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build-docset.yml b/.github/workflows/build-docset.yml index fe14f451..50f4ee04 100644 --- a/.github/workflows/build-docset.yml +++ b/.github/workflows/build-docset.yml @@ -16,7 +16,7 @@ jobs: docset: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-depth: 0 # get correct version persist-credentials: false diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7cf2fe4f..c6eeb853 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-depth: 0 persist-credentials: false @@ -92,7 +92,7 @@ jobs: if: always() steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: persist-credentials: false - uses: actions/setup-python@v5 @@ -200,7 +200,7 @@ jobs: os: [ubuntu-latest, windows-latest] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: persist-credentials: false - uses: actions/setup-python@v5 @@ -243,7 +243,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: persist-credentials: false - uses: actions/setup-python@v5 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 7907ccb0..d77a037a 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: persist-credentials: false diff --git a/.github/workflows/pypi-package.yml b/.github/workflows/pypi-package.yml index 65f67d0c..ee808fd3 100644 --- a/.github/workflows/pypi-package.yml +++ b/.github/workflows/pypi-package.yml @@ -21,7 +21,7 @@ jobs: id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-depth: 0 persist-credentials: false diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index cde16a0a..8d339cc8 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -19,7 +19,7 @@ jobs: security-events: write steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: persist-credentials: false - uses: hynek/setup-cached-uv@v2 From 99bd5a909079c7e8966c2be74db9149b4f17d54c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 2 Sep 2025 07:42:18 +0200 Subject: [PATCH 1397/1520] [pre-commit.ci] pre-commit autoupdate (#742) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.12.7 → v0.12.11](https://github.com/astral-sh/ruff-pre-commit/compare/v0.12.7...v0.12.11) - [github.com/pre-commit/pre-commit-hooks: v5.0.0 → v6.0.0](https://github.com/pre-commit/pre-commit-hooks/compare/v5.0.0...v6.0.0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Hynek Schlawack --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d479615c..17a5c238 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.12.7 + rev: v0.12.11 hooks: - id: ruff-check args: [--fix, --exit-non-zero-on-fix] @@ -23,7 +23,7 @@ repos: args: [-L, alog, -L, abl] - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 + rev: v6.0.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer From c44431c544095e61163598372737c1c76a91790f Mon Sep 17 00:00:00 2001 From: Andrew Gunnerson <151555334+agunnerson-elastic@users.noreply.github.com> Date: Thu, 11 Sep 2025 02:22:00 -0400 Subject: [PATCH 1398/1520] MaybeTimeStamper: Fix custom keys always being overwritten (#747) Previously, the conditional always checked specifically for `timestamp`, which caused MaybeTimeStamper to always behave like TimeStamper when a custom key is used. Signed-off-by: Andrew Gunnerson --- CHANGELOG.md | 5 +++++ src/structlog/processors.py | 2 +- tests/processors/test_renderers.py | 8 ++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14e0dcc9..b5ecca31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,11 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - `structlog.dev.rich_traceback()` now throws a more helpful error when Rich is missing. [#735](https://github.com/hynek/structlog/pull/735) +### Fixed + +- `structlog.processors.MaybeTimeStamper` now respects the *key* argument when determining whether to overwrite the timestamp field. + [#747](https://github.com/hynek/structlog/pull/747) + ## [25.4.0](https://github.com/hynek/structlog/compare/25.3.0...25.4.0) - 2025-06-02 diff --git a/src/structlog/processors.py b/src/structlog/processors.py index ee70e509..804b8d0d 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -592,7 +592,7 @@ def __init__( def __call__( self, logger: WrappedLogger, name: str, event_dict: EventDict ) -> EventDict: - if "timestamp" not in event_dict: + if self.stamper.key not in event_dict: return self.stamper(logger, name, event_dict) return event_dict diff --git a/tests/processors/test_renderers.py b/tests/processors/test_renderers.py index 3cf27a58..791b18a4 100644 --- a/tests/processors/test_renderers.py +++ b/tests/processors/test_renderers.py @@ -511,6 +511,14 @@ def test_overwrite(self): assert {"timestamp": 42} == mts(None, None, {"timestamp": 42}) + def test_overwrite_custom_key(self): + """ + If there is a timestamp with a custom key, leave it. + """ + mts = MaybeTimeStamper(key="timestamp2") + + assert {"timestamp2": 42} == mts(None, None, {"timestamp2": 42}) + def test_none(self): """ If there is no timestamp, add one. From 4bf05624b33c0f86bcbc77096a2c128de0b13ec4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 11 Sep 2025 11:09:15 +0200 Subject: [PATCH 1399/1520] local dev: fix parallel race condition in tox --- tox.ini | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/tox.ini b/tox.ini index 4451f2d9..f2c58ecd 100644 --- a/tox.ini +++ b/tox.ini @@ -6,7 +6,7 @@ env_list = py3{8,9,10,11,12,13,14}-{tests,mypy} py3{8,13}-tests-{colorama,be,rich}, docs-{sponsors,doctests}, - coverage-report + coverage-{combine,report} [testenv] @@ -32,15 +32,25 @@ deps = commands = coverage run -m pytest {posargs} -[testenv:coverage-report] -deps = coverage[toml] +# Split combine/report in 2 to avoid excessive "Combined data file ..." output. +[testenv:coverage-combine] +# Keep base_python in-sync with .python-version-default +base_python = py313 +# Keep in-sync with test env definition above. +depends = py3{8,13}-tests{,-colorama,-be,-rich} skip_install = true +deps = coverage +commands = coverage combine + +[testenv:coverage-report] +# Keep base_python in-sync with .python-version-default +base_python = py313 +depends = coverage-combine parallel_show_output = true -# Keep in-sync with test env definition above. -depends = py3{8,13}-tests{,colorama,be,rich} -commands = - coverage combine - coverage report +skip_install = true +deps = coverage +commands = coverage report + [testenv:docs-{build,doctests,linkcheck}] From 0c0a9b58e64dfe39eeab7413532ae58b17c2d913 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 11 Sep 2025 11:29:42 +0200 Subject: [PATCH 1400/1520] Silence pytest-asyncio ResourceWarning --- pyproject.toml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 0fc4fc33..d899c45e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -72,10 +72,14 @@ raw-options = { local_scheme = "no-local-version" } [tool.pytest.ini_options] -addopts = ["-ra", "--strict-markers", "--strict-config"] +addopts = ["--strict-markers", "--strict-config", "--import-mode=importlib"] testpaths = "tests" xfail_strict = true -filterwarnings = ["once::Warning"] +filterwarnings = [ + "once::Warning", + # Probably + "ignore:unclosed event loop:ResourceWarning", +] asyncio_mode = "auto" asyncio_default_fixture_loop_scope = "function" From 01ae286ddf3dfded19c7ed7e9fd0fda44877999e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 11 Sep 2025 11:44:43 +0200 Subject: [PATCH 1401/1520] Update Ruff --- .pre-commit-config.yaml | 2 +- src/structlog/stdlib.py | 2 +- tests/processors/test_renderers.py | 4 +--- tests/test_dev.py | 4 ++-- tests/test_output.py | 2 +- tests/test_stdlib.py | 8 ++++---- tests/test_twisted.py | 6 +++--- 7 files changed, 13 insertions(+), 15 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 17a5c238..66446127 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.12.11 + rev: v0.13.0 hooks: - id: ruff-check args: [--fix, --exit-non-zero-on-fix] diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index af2ff30c..dc4c94ae 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -130,7 +130,7 @@ def findCaller( This logger gets set as the default one when using LoggerFactory. """ sinfo: str | None - f, name = _find_first_app_frame_and_name(["logging"]) + f, _name = _find_first_app_frame_and_name(["logging"]) sinfo = _format_stack(f) if stack_info else None return f.f_code.co_filename, f.f_lineno, f.f_code.co_name, sinfo diff --git a/tests/processors/test_renderers.py b/tests/processors/test_renderers.py index 791b18a4..b133aabe 100644 --- a/tests/processors/test_renderers.py +++ b/tests/processors/test_renderers.py @@ -377,9 +377,7 @@ def test_disallows_non_utc_unix_timestamps(self): A asking for a UNIX timestamp with a timezone that's not UTC raises a ValueError. """ - with pytest.raises( - ValueError, match="UNIX timestamps are always UTC." - ): + with pytest.raises(ValueError, match="UNIX timestamps are always UTC"): TimeStamper(utc=False) def test_inserts_utc_unix_timestamp_by_default(self): diff --git a/tests/test_dev.py b/tests/test_dev.py index 558d4016..58020d8a 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -602,7 +602,7 @@ def test_enforces_presence_of_exactly_one_default_formatter(self): with pytest.raises( ValueError, - match="Only one default column formatter allowed.", + match="Only one default column formatter allowed", ): dev.ConsoleRenderer( columns=[ @@ -657,7 +657,7 @@ def test_rich_traceback_formatter_no_rich(): """ with pytest.raises( ModuleNotFoundError, - match="RichTracebackFormatter requires Rich to be installed.", + match="RichTracebackFormatter requires Rich to be installed", ): dev.rich_traceback(StringIO(), sys.exc_info()) diff --git a/tests/test_output.py b/tests/test_output.py index 82db52df..0c84ed65 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -102,7 +102,7 @@ def test_pickle_not_stdout_stderr(self, logger_cls, tmpdir, proto): f.write("") pl = logger_cls(file=f.open()) - with pytest.raises(pickle.PicklingError, match="Only (.+)Loggers to"): + with pytest.raises(pickle.PicklingError, match=r"Only (.+)Loggers to"): pickle.dumps(pl, proto) def test_deepcopy(self, logger_cls, capsys): diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 607308d3..a045386f 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -117,7 +117,7 @@ def test_deduces_correct_caller(self): """ logger = _FixedFindCallerLogger("test") - file_name, line_number, func_name = logger.findCaller()[:3] + file_name, _line_number, func_name = logger.findCaller()[:3] assert file_name == os.path.realpath(__file__) assert func_name == "test_deduces_correct_caller" @@ -127,7 +127,7 @@ def test_stack_info(self): If we ask for stack_info, it will returned. """ logger = _FixedFindCallerLogger("test") - testing, is_, fun, stack_info = logger.findCaller(stack_info=True) + testing, is_, fun, stack_info = logger.findCaller(stack_info=True) # noqa: RUF059 assert "testing, is_, fun" in stack_info @@ -136,7 +136,7 @@ def test_no_stack_info_by_default(self): If we don't ask for stack_info, it won't be returned. """ logger = _FixedFindCallerLogger("test") - testing, is_, fun, stack_info = logger.findCaller() + testing, is_, fun, stack_info = logger.findCaller() # noqa: RUF059 assert None is stack_info @@ -230,7 +230,7 @@ def test_positional_args_proxied(self): Positional arguments supplied are proxied as kwarg. """ bl = BoundLogger(ReturnLogger(), [], {}) - args, kwargs = bl.debug("event", "foo", bar="baz") + _args, kwargs = bl.debug("event", "foo", bar="baz") assert "baz" == kwargs.get("bar") assert ("foo",) == kwargs.get("positional_args") diff --git a/tests/test_twisted.py b/tests/test_twisted.py index 24c31b0b..d13e7f80 100644 --- a/tests/test_twisted.py +++ b/tests/test_twisted.py @@ -105,7 +105,7 @@ def test_extractFailsOnTwoFailures(self): """ with pytest.raises( ValueError, - match="Both _stuff and event contain an Exception/Failure.", + match="Both _stuff and event contain an Exception/Failure", ): _extractStuffAndWhy( { @@ -119,7 +119,7 @@ def test_failsOnConflictingEventAnd_why(self): Raise ValueError if both _why and event are in the event_dict. """ with pytest.raises( - ValueError, match="Both `_why` and `event` supplied." + ValueError, match="Both `_why` and `event` supplied" ): _extractStuffAndWhy({"_why": "foo", "event": "bar"}) @@ -222,7 +222,7 @@ def test_catchesConflictingEventAnd_why(self): la = EventAdapter(_render_repr) with pytest.raises( - ValueError, match="Both `_why` and `event` supplied." + ValueError, match="Both `_why` and `event` supplied" ): la(None, "err", {"event": "someEvent", "_why": "someReason"}) From addf622407a9343333bbd5c4e26be788e1aad3b8 Mon Sep 17 00:00:00 2001 From: Leonardo Panseri Date: Thu, 11 Sep 2025 12:33:13 +0200 Subject: [PATCH 1402/1520] Fix unbounded recursion when traceback contains an exception that has a reference to itself in its cause chain (#739) * Fix unbounded traceback recursion * Update CHANGELOG.md * Fixes & attributions Co-authored-by: yuwu <47444399+leiyi2000@users.noreply.github.com> Co-authored-by: William FH <13333726+hinthornw@users.noreply.github.com> --------- Co-authored-by: Hynek Schlawack Co-authored-by: yuwu <47444399+leiyi2000@users.noreply.github.com> Co-authored-by: William FH <13333726+hinthornw@users.noreply.github.com> --- CHANGELOG.md | 3 + src/structlog/tracebacks.py | 13 ++++ tests/test_tracebacks.py | 118 ++++++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5ecca31..2abd8867 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - `structlog.processors.MaybeTimeStamper` now respects the *key* argument when determining whether to overwrite the timestamp field. [#747](https://github.com/hynek/structlog/pull/747) +- `structlog.tracebacks.extract()` no longer raises a *RecursionError* when the cause chain of an exception contains itself. + [#739](https://github.com/hynek/structlog/pull/739) + ## [25.4.0](https://github.com/hynek/structlog/compare/25.3.0...25.4.0) - 2025-06-02 diff --git a/src/structlog/tracebacks.py b/src/structlog/tracebacks.py index 949df9cd..f42f5302 100644 --- a/src/structlog/tracebacks.py +++ b/src/structlog/tracebacks.py @@ -190,6 +190,7 @@ def extract( locals_hide_dunder: bool = True, locals_hide_sunder: bool = False, use_rich: bool = True, + _seen: set[int] | None = None, ) -> Trace: """ Extract traceback information. @@ -235,12 +236,23 @@ def extract( .. versionchanged:: 25.4.0 Handle exception groups. + + .. versionchanged:: 25.5.0 + Handle loops in exception cause chain. """ stacks: list[Stack] = [] is_cause = False + if _seen is None: + _seen = set() + while True: + exc_id = id(exc_value) + if exc_id in _seen: + break + _seen.add(exc_id) + stack = Stack( exc_type=safe_str(exc_type.__name__), exc_value=safe_str(exc_value), @@ -265,6 +277,7 @@ def extract( locals_hide_dunder=locals_hide_dunder, locals_hide_sunder=locals_hide_sunder, use_rich=use_rich, + _seen=_seen, ) ) diff --git a/tests/test_tracebacks.py b/tests/test_tracebacks.py index f83f72fb..9477b063 100644 --- a/tests/test_tracebacks.py +++ b/tests/test_tracebacks.py @@ -1071,3 +1071,121 @@ def test_no_exception( logger.exception("onoes") assert [{"event": "onoes", "log_level": "error"}] == cap_logs.entries + + +@pytest.mark.skipif( + sys.version_info < (3, 11), reason="Requires Python 3.11 or higher" +) +def test_reraise_error_from_exception_group(): + """ + There is no RecursionError when building the traceback for an exception + that has been re-raised from an ExceptionGroup. + """ + inner_lineno = None + lineno = None + + try: + try: + inner_lineno = get_next_lineno() + raise ExceptionGroup( # noqa: F821 + "Some error occurred", + [ValueError("value error")], + ) + except ExceptionGroup as e: # noqa: F821 + lineno = get_next_lineno() + raise e.exceptions[0] # noqa: B904 + except Exception as e: + trace = tracebacks.extract(type(e), e, e.__traceback__) + + assert lineno is not None + assert inner_lineno is not None + assert 2 == len(trace.stacks) + assert lineno == trace.stacks[0].frames[0].lineno + assert ( + tracebacks.Stack( + exc_type="ValueError", + exc_value="value error", + syntax_error=None, + is_cause=False, + frames=[ + tracebacks.Frame( + filename=__file__, + lineno=lineno, + name="test_reraise_error_from_exception_group", + locals=None, + ) + ], + is_group=False, + exceptions=[], + ) + == trace.stacks[0] + ) + assert ( + tracebacks.Stack( + exc_type="ExceptionGroup", + exc_value="Some error occurred (1 sub-exception)", + syntax_error=None, + is_cause=False, + frames=[ + tracebacks.Frame( + filename=__file__, + lineno=inner_lineno, + name="test_reraise_error_from_exception_group", + locals=None, + ), + ], + is_group=True, + exceptions=[tracebacks.Trace(stacks=[])], + ) + == trace.stacks[1] + ) + + +def test_exception_cycle(): + """ + There is no RecursionError when building the traceback for an exception + that has itself in its cause chain. + """ + inner_lineno = None + lineno = None + + try: + try: + exc = ValueError("onoes") + inner_lineno = get_next_lineno() + raise exc + except Exception as exc: + lineno = get_next_lineno() + raise exc from exc + except Exception as e: + trace = tracebacks.extract(type(e), e, e.__traceback__) + + assert lineno is not None + assert inner_lineno is not None + assert 1 == len(trace.stacks) + assert lineno == trace.stacks[0].frames[0].lineno + assert ( + tracebacks.Stack( + exc_type="ValueError", + exc_value="onoes", + syntax_error=None, + is_cause=False, + frames=[ + tracebacks.Frame( + filename=__file__, + lineno=lineno, + name="test_exception_cycle", + locals=None, + ), + tracebacks.Frame( + filename=__file__, + lineno=inner_lineno, + name="test_exception_cycle", + locals=None, + ), + ], + is_group=False, + exceptions=[], + ) + == trace.stacks[0] + ) From 01794b706f18c2975fcf54edecfe42f8049e315f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 11 Sep 2025 14:07:05 +0200 Subject: [PATCH 1403/1520] ci: pin all actions --- .github/workflows/build-docset.yml | 6 ++-- .github/workflows/ci.yml | 52 +++++++++++++-------------- .github/workflows/codeql-analysis.yml | 8 ++--- .github/workflows/pypi-package.yml | 12 +++---- .github/workflows/zizmor.yml | 6 ++-- zizmor.yml | 10 ------ 6 files changed, 42 insertions(+), 52 deletions(-) delete mode 100644 zizmor.yml diff --git a/.github/workflows/build-docset.yml b/.github/workflows/build-docset.yml index 50f4ee04..a1fcfdcb 100644 --- a/.github/workflows/build-docset.yml +++ b/.github/workflows/build-docset.yml @@ -16,11 +16,11 @@ jobs: docset: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: fetch-depth: 0 # get correct version persist-credentials: false - - uses: actions/setup-python@v5 + - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 with: python-version: "3.12" @@ -29,7 +29,7 @@ jobs: - run: tox run -e docset - run: tar --exclude='.DS_Store' -cvzf structlog.tgz structlog.docset - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: docset path: structlog.tgz diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c6eeb853..d726a342 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,12 +21,12 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: fetch-depth: 0 persist-credentials: false - - uses: hynek/build-and-inspect-python-package@v2 + - uses: hynek/build-and-inspect-python-package@c52c3a4710070b50470d903818a7b25115dcd076 # v2.13.0 id: baipp outputs: @@ -51,18 +51,18 @@ jobs: steps: - name: Download pre-built packages - uses: actions/download-artifact@v5 + uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 with: name: Packages path: dist - run: | tar xf dist/*.tar.gz --strip-components=1 rm -rf src - - uses: actions/setup-python@v5 + - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 with: python-version: ${{ matrix.python-version }} allow-prereleases: true - - uses: hynek/setup-cached-uv@v2 + - uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817 # v2.3.0 - name: Run tests run: > @@ -71,7 +71,7 @@ jobs: -f py${PYTHON//./}-tests - name: Upload coverage data - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: coverage-data-${{ matrix.python-version }} path: .coverage.* @@ -92,16 +92,16 @@ jobs: if: always() steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - - uses: actions/setup-python@v5 + - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 with: python-version-file: .python-version-default - - uses: hynek/setup-cached-uv@v2 + - uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817 # v2.3.0 - name: Download coverage data - uses: actions/download-artifact@v5 + uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 with: pattern: coverage-data-* merge-multiple: true @@ -120,7 +120,7 @@ jobs: coverage report --fail-under=100 - name: Upload HTML report if check failed. - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: html-report path: htmlcov @@ -134,15 +134,15 @@ jobs: steps: - name: Download pre-built packages - uses: actions/download-artifact@v5 + uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 with: name: Packages path: dist - run: tar xf dist/*.tar.gz --strip-components=1 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 with: python-version-file: .python-version-default - - uses: hynek/setup-cached-uv@v2 + - uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817 # v2.3.0 - run: > uvx --with tox-uv @@ -155,15 +155,15 @@ jobs: needs: build-package steps: - name: Download pre-built packages - uses: actions/download-artifact@v5 + uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 with: name: Packages path: dist - run: tar xf dist/*.tar.gz --strip-components=1 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 with: python-version-file: .python-version-default - - uses: hynek/setup-cached-uv@v2 + - uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817 # v2.3.0 - run: > uvx --with tox-uv @@ -176,16 +176,16 @@ jobs: runs-on: ubuntu-latest steps: - name: Download pre-built packages - uses: actions/download-artifact@v5 + uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 with: name: Packages path: dist - run: tar xf dist/*.tar.gz --strip-components=1 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 with: # Keep in sync with tox.ini/docs & .readthedocs.yaml python-version: "3.13" - - uses: hynek/setup-cached-uv@v2 + - uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817 # v2.3.0 - run: > uvx --with tox-uv @@ -200,13 +200,13 @@ jobs: os: [ubuntu-latest, windows-latest] steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - - uses: actions/setup-python@v5 + - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 with: python-version-file: .python-version-default - - uses: hynek/setup-cached-uv@v2 + - uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817 # v2.3.0 - run: uv venv - run: uv pip install -e . --group dev @@ -243,13 +243,13 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - - uses: actions/setup-python@v5 + - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 with: python-version-file: .python-version-default - - uses: hynek/setup-cached-uv@v2 + - uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817 # v2.3.0 - run: > uvx --with=tox-uv diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index d77a037a..478b8be6 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -24,17 +24,17 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@v3 + uses: github/codeql-action/autobuild@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3 diff --git a/.github/workflows/pypi-package.yml b/.github/workflows/pypi-package.yml index ee808fd3..5b40420a 100644 --- a/.github/workflows/pypi-package.yml +++ b/.github/workflows/pypi-package.yml @@ -21,12 +21,12 @@ jobs: id-token: write steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: fetch-depth: 0 persist-credentials: false - - uses: hynek/build-and-inspect-python-package@v2 + - uses: hynek/build-and-inspect-python-package@c52c3a4710070b50470d903818a7b25115dcd076 # v2.13.0 with: attest-build-provenance-github: 'true' @@ -43,13 +43,13 @@ jobs: steps: - name: Download packages built by build-and-inspect-python-package - uses: actions/download-artifact@v5 + uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 with: name: Packages path: dist - name: Upload package to Test PyPI - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0 with: repository-url: https://test.pypi.org/legacy/ @@ -66,10 +66,10 @@ jobs: steps: - name: Download packages built by build-and-inspect-python-package - uses: actions/download-artifact@v5 + uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 with: name: Packages path: dist - name: Upload package to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0 diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index 8d339cc8..7745e18c 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -19,10 +19,10 @@ jobs: security-events: write steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - - uses: hynek/setup-cached-uv@v2 + - uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817 # v2.3.0 - name: Run zizmor 🌈 run: uvx zizmor --format sarif . > results.sarif @@ -30,7 +30,7 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload SARIF file - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3 with: # Path to SARIF file relative to the root of the repository sarif_file: results.sarif diff --git a/zizmor.yml b/zizmor.yml deleted file mode 100644 index 1bab80ba..00000000 --- a/zizmor.yml +++ /dev/null @@ -1,10 +0,0 @@ ---- -rules: - unpinned-uses: - config: - policies: - # We trust GitHub, the PyPA, and ourselves. - "actions/*": ref-pin - "github/*": ref-pin - "pypa/*": ref-pin - "hynek/*": ref-pin From 83d7cdc337fe84ae9bce354747d3bc66bcff58cd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 12 Sep 2025 10:34:10 +0200 Subject: [PATCH 1404/1520] Run docs-build locally to catch errors before RTD --- tox.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index f2c58ecd..ca047ba6 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,7 @@ env_list = mypy-pkg, py3{8,9,10,11,12,13,14}-{tests,mypy} py3{8,13}-tests-{colorama,be,rich}, - docs-{sponsors,doctests}, + docs-{sponsors,build,doctests}, coverage-{combine,report} @@ -58,6 +58,7 @@ commands = coverage report base_python = py313 dependency_groups = docs commands = + # N.B. doctests is not a nitpicky as build -- we need to run both in CI! build: sphinx-build -n -T -W -b html -d {envtmpdir}/doctrees docs {posargs:docs/_build/}html doctests: sphinx-build -n -T -W -b doctest -d {envtmpdir}/doctrees docs {posargs:docs/_build/}html linkcheck: sphinx-build -W -b linkcheck -d {envtmpdir}/doctrees docs docs/_build/html From 9d4022c796eaaf1637648519db5ee6a84169e152 Mon Sep 17 00:00:00 2001 From: HairlessVillager <64526732+HairlessVillager@users.noreply.github.com> Date: Fri, 12 Sep 2025 19:01:26 +0800 Subject: [PATCH 1405/1520] refactor: extract styles configuration to separate method (#741) * refactor: extract styles configuration to separate method Extract the styles configuration logic from ConsoleRenderer.__init__ into a dedicated configure_styles class method. This improves code readability and makes the styles setup logic reusable and testable. - Move colorama initialization and styles selection to configure_styles() - Add comprehensive docstring with args, returns, and raises sections - Remove noqa comment as method complexity is now reduced - Maintain existing behavior for colors and force_colors parameters * docs, tests * docs: versionadded * docs: changelog.md * fix: _Styles -> Styles * Fix type `Styles` already includes `Type[_Styles]`, so `type[Styles]` should be wrong * Fix Sphinx build --------- Co-authored-by: Hynek Schlawack --- CHANGELOG.md | 3 ++ docs/api.rst | 2 +- docs/conf.py | 1 + src/structlog/dev.py | 73 +++++++++++++++++++++++++++++--------------- tests/test_dev.py | 58 +++++++++++++++++++++++++++++++++++ 5 files changed, 112 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2abd8867..3177c0f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ### Added +- Added `structlog.dev.ConsoleRenderer.get_default_column_styles` for reuse the default column styles. + [#741](https://github.com/hynek/structlog/pull/741) + - `structlog.testing.capture_logs()` now optionally accepts *processors* to apply before capture. [#728](https://github.com/hynek/structlog/pull/728) diff --git a/docs/api.rst b/docs/api.rst index f13fdbb9..644dc649 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -76,7 +76,7 @@ API Reference .. automodule:: structlog.dev .. autoclass:: ConsoleRenderer - :members: get_default_level_styles + :members: get_default_level_styles, get_default_column_styles .. autoclass:: Column .. autoclass:: ColumnFormatter(typing.Protocol) diff --git a/docs/conf.py b/docs/conf.py index 0b7d83a6..44efba9a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -83,6 +83,7 @@ ("py:class", "PlainFileObserver"), ("py:class", "Processor"), ("py:class", "Styles"), + ("py:class", "structlog.dev._Styles"), ("py:class", "WrappedLogger"), ("py:class", "structlog.threadlocal.TLLogger"), ("py:class", "structlog.typing.EventDict"), diff --git a/src/structlog/dev.py b/src/structlog/dev.py index f49b38a0..2c0a7640 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -567,7 +567,7 @@ class ConsoleRenderer: .. versionadded:: 24.2.0 *pad_level* """ - def __init__( # noqa: PLR0912, PLR0915 + def __init__( self, pad_event: int = _EVENT_WIDTH, colors: bool = _has_colors, @@ -630,29 +630,7 @@ def add_meaningless_arg(arg: str) -> None: return # Create default columns configuration. - styles: Styles - if colors: - if _IS_WINDOWS: # pragma: no cover - # On Windows, we can't do colorful output without colorama. - if colorama is None: - classname = self.__class__.__name__ - raise SystemError( - _MISSING.format( - who=classname + " with `colors=True`", - package="colorama", - ) - ) - # Colorama must be init'd on Windows, but must NOT be - # init'd on other OSes, because it can break colors. - if force_colors: - colorama.deinit() - colorama.init(strip=False) - else: - colorama.init() - - styles = _ColorfulStyles - else: - styles = _PlainStyles + styles = self.get_default_column_styles(colors, force_colors) self._styles = styles @@ -719,6 +697,53 @@ def add_meaningless_arg(arg: str) -> None: Column("logger_name", logger_name_formatter), ] + @classmethod + def get_default_column_styles( + cls, colors: bool = _has_colors, force_colors: bool = False + ) -> Styles: + """ + Configure and return the appropriate styles class for console output. + + This method handles the setup of colorful or plain styles, including + proper colorama initialization on Windows systems when colors are enabled. + + Args: + colors: Whether to use colorful output styles. + + force_colors: + Force colorful output even in non-interactive environments. + Only relevant on Windows with colorama. + + Returns: + The configured styles class (_ColorfulStyles or _PlainStyles). + + Raises: + SystemError: On Windows when colors=True but colorama is not installed. + + .. versionadded:: 25.5.0 + """ + if not colors: + return _PlainStyles + + if _IS_WINDOWS: # pragma: no cover + # On Windows, we can't do colorful output without colorama. + if colorama is None: + raise SystemError( + _MISSING.format( + who=cls.__name__ + " with `colors=True`", + package="colorama", + ) + ) + # Colorama must be init'd on Windows, but must NOT be + # init'd on other OSes, because it can break colors. + if force_colors: + colorama.deinit() + colorama.init(strip=False) + else: + colorama.init() + + return _ColorfulStyles + def _repr(self, val: Any) -> str: """ Determine representation of *val* depending on its type & diff --git a/tests/test_dev.py b/tests/test_dev.py index 58020d8a..05da67d5 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -175,6 +175,64 @@ def test_init_accepts_overriding_levels(self, styles, padded): + styles.reset ) == rv + def test_returns_colorful_styles_when_colors_true(self): + """ + When colors=True, returns _ColorfulStyles class. + """ + styles = dev.ConsoleRenderer.get_default_column_styles(colors=True) + + assert styles is dev._ColorfulStyles + assert hasattr(styles, "reset") + assert hasattr(styles, "bright") + assert hasattr(styles, "level_critical") + assert hasattr(styles, "kv_key") + assert hasattr(styles, "kv_value") + + def test_returns_plain_styles_when_colors_false(self): + """ + When colors=False, returns _PlainStyles class. + """ + styles = dev.ConsoleRenderer.get_default_column_styles(colors=False) + + assert styles is dev._PlainStyles + assert styles.reset == "" + assert styles.bright == "" + assert styles.level_critical == "" + assert styles.kv_key == "" + assert styles.kv_value == "" + + @pytest.mark.skipif( + not dev._IS_WINDOWS or dev.colorama is not None, + reason="Only relevant on Windows without colorama", + ) + def test_raises_system_error_on_windows_without_colorama(self): + """ + On Windows without colorama, raises SystemError when colors=True. + """ + with pytest.raises(SystemError, match="requires the colorama package"): + dev.ConsoleRenderer.get_default_column_styles(colors=True) + + @pytest.mark.skipif( + not dev._IS_WINDOWS or dev.colorama is None, + reason="Only relevant on Windows with colorama", + ) + def test_initializes_colorama_on_windows_with_force_colors(self): + """ + On Windows with colorama, force_colors=True reinitializes colorama. + """ + with mock.patch.object( + dev.colorama, "init" + ) as mock_init, mock.patch.object( + dev.colorama, "deinit" + ) as mock_deinit: + styles = dev.ConsoleRenderer.get_default_column_styles( + colors=True, force_colors=True + ) + + assert styles is dev._ColorfulStyles + mock_deinit.assert_called_once() + mock_init.assert_called_once_with(strip=False) + def test_logger_name(self, cr, styles, padded): """ Logger names are appended after the event. From fa231cffcbbade5d593aeaa43a2375b6a7325429 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 12 Sep 2025 15:28:30 +0200 Subject: [PATCH 1406/1520] Add missing versionadded tag --- src/structlog/dev.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 2c0a7640..858fcee1 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -840,6 +840,8 @@ def set_exc_info( Set ``event_dict["exc_info"] = True`` if *method_name* is ``"exception"``. Do nothing if the name is different or ``exc_info`` is already set. + + .. versionadded:: 19.2.0 """ if ( method_name != "exception" From 5204bc33ef26b68afbb3de97c8cf1728b994bdbf Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 18 Sep 2025 09:10:39 +0200 Subject: [PATCH 1407/1520] Add support for dict-based interpolation in native loggers (#748) --- CHANGELOG.md | 3 +++ docs/bound-loggers.md | 1 + docs/getting-started.md | 7 +++++++ docs/why.md | 8 ++++++++ src/structlog/_native.py | 41 ++++++++++++++++++++++++++++------------ src/structlog/typing.py | 4 ++++ tests/test_native.py | 40 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 92 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3177c0f4..5937f430 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ Passing `-1` for *width* is now deprecated and automatically replaced by `None`. [#717](https://github.com/hynek/structlog/pull/717) +- Native loggers now allow the passing of a dictionary for dictionary-based interpolation `log.info("hello %(name)s!", {"name": "world"})`. + [#748](https://github.com/hynek/structlog/pull/748) + ### Changed diff --git a/docs/bound-loggers.md b/docs/bound-loggers.md index deb7254f..bb797963 100644 --- a/docs/bound-loggers.md +++ b/docs/bound-loggers.md @@ -100,6 +100,7 @@ If you call `log.info("Hello, %s!", "world", number=42)` now, the following happ For example, if you wanted JSON logs, you just have to replace the last processor with {class}`structlog.processors.JSONRenderer`. [^interpolation]: String interpolation only takes place if you pass positional arguments. + If the first and only argument is a mapping, it will be used for dict-based interpolation. (filtering)= diff --git a/docs/getting-started.md b/docs/getting-started.md index d0042c98..161c0078 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -31,14 +31,21 @@ As a result, the simplest possible usage looks like this: Here, *structlog* takes advantage of its default settings: - Output is sent to **[standard out](https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29)** instead of doing nothing. + - It **imitates** standard library {mod}`logging`'s **log level names** for familiarity. By default, no level-based filtering is done, but it comes with a **very fast [filtering machinery](filtering)**. + - Like in `logging`, positional arguments are [**interpolated into the message string using %**](https://docs.python.org/3/library/stdtypes.html#old-string-formatting). That might look dated, but it's *much* faster than using {any}`str.format` and allows *structlog* to be used as drop-in replacement for {mod}`logging`. If you *know* that the log entry is *always* gonna be logged out, just use [f-strings](https://docs.python.org/3/tutorial/inputoutput.html#formatted-string-literals) which are the fastest. + + *structlog* supports both positional and dict-based interpolation, therefore `log.info("hello %(name)s!", {"name": "world"})` generates the same output as above. + - All keywords are formatted using {class}`structlog.dev.ConsoleRenderer`. That in turn uses {func}`repr` to serialize **any value to a string**. + - It's rendered in nice **{doc}`colors `**. + - If you have [Rich] or [*better-exceptions*] installed, **exceptions** will be rendered in **colors** and with additional **helpful information**. Please note that even in most complex logging setups the example would still look just like that thanks to {doc}`configuration`. diff --git a/docs/why.md b/docs/why.md index 98d8a898..b8d34236 100644 --- a/docs/why.md +++ b/docs/why.md @@ -42,6 +42,14 @@ You can still use string interpolation using positional arguments: 2022-10-10 07:19:25 [info ] Hello, world! ``` +Dictionary-based interpolation works too: + +```pycon +>>> log.info("Hello, %(name)s!", {"name": "world"}) +2025-09-11 13:00:42 [info ] Hello, world! +``` + + ### Data binding Since log entries are dictionaries, you can start binding and re-binding key-value pairs to your loggers to ensure they are present in every following logging call: diff --git a/src/structlog/_native.py b/src/structlog/_native.py index 43d732b5..4d0926de 100644 --- a/src/structlog/_native.py +++ b/src/structlog/_native.py @@ -10,6 +10,7 @@ from __future__ import annotations import asyncio +import collections import contextvars import sys @@ -123,6 +124,26 @@ def make_filtering_bound_logger( return LEVEL_TO_FILTERING_LOGGER[min_level] +def _maybe_interpolate(event: str, args: tuple[Any, ...]) -> str: + """ + Interpolate the event string with the given arguments. + + If there's exactly one argument and it's a mapping, use it for dict-based + interpolation. Otherwise, use the arguments for positional interpolation. + """ + if not args: + return event + + if ( + len(args) == 1 + and isinstance(args[0], collections.abc.Mapping) + and args[0] + ): + return event % args[0] + + return event % args + + def _make_filtering_bound_logger(min_level: int) -> type[FilteringBoundLogger]: """ Create a new `FilteringBoundLogger` that only logs *min_level* or higher. @@ -140,18 +161,16 @@ def make_method( name = LEVEL_TO_NAME[level] def meth(self: Any, event: str, *args: Any, **kw: Any) -> Any: - if not args: - return self._proxy_to_logger(name, event, **kw) - - return self._proxy_to_logger(name, event % args, **kw) + return self._proxy_to_logger( + name, _maybe_interpolate(event, args), **kw + ) async def ameth(self: Any, event: str, *args: Any, **kw: Any) -> Any: """ .. versionchanged:: 23.3.0 Callsite parameters are now also collected under asyncio. """ - if args: - event = event % args + event = _maybe_interpolate(event, args) scs_token = _ASYNC_CALLING_STACK.set(sys._getframe().f_back) # type: ignore[arg-type] ctx = contextvars.copy_context() @@ -175,10 +194,9 @@ def log(self: Any, level: int, event: str, *args: Any, **kw: Any) -> Any: return None name = LEVEL_TO_NAME[level] - if not args: - return self._proxy_to_logger(name, event, **kw) - - return self._proxy_to_logger(name, event % args, **kw) + return self._proxy_to_logger( + name, _maybe_interpolate(event, args), **kw + ) async def alog( self: Any, level: int, event: str, *args: Any, **kw: Any @@ -190,8 +208,7 @@ async def alog( if level < min_level: return None name = LEVEL_TO_NAME[level] - if args: - event = event % args + event = _maybe_interpolate(event, args) scs_token = _ASYNC_CALLING_STACK.set(sys._getframe().f_back) # type: ignore[arg-type] ctx = contextvars.copy_context() diff --git a/src/structlog/typing.py b/src/structlog/typing.py index c86d2808..9b2ee5a2 100644 --- a/src/structlog/typing.py +++ b/src/structlog/typing.py @@ -161,6 +161,10 @@ class FilteringBoundLogger(BindableLogger, Protocol): .. versionchanged:: 22.3.0 String interpolation is only attempted if positional arguments are passed. + .. versionadded:: 25.5.0 + String interpolation using dictionary-based arguments if the first and + only argument is a mapping. + """ def bind(self, **new_values: Any) -> FilteringBoundLogger: diff --git a/tests/test_native.py b/tests/test_native.py index 2d152e72..90b1ebf3 100644 --- a/tests/test_native.py +++ b/tests/test_native.py @@ -158,6 +158,14 @@ def test_log_interp(self, bl, cl): assert "answer is 42." == cl.calls[0][2]["event"] + def test_log_interp_dict(self, bl, cl): + """ + Dict-based interpolation happens if a mapping is passed. + """ + bl.log(logging.INFO, "answer is %(answer)d.", {"answer": 42}) + + assert "answer is 42." == cl.calls[0][2]["event"] + async def test_alog_interp(self, bl, cl): """ Interpolation happens if args are passed. @@ -166,6 +174,14 @@ async def test_alog_interp(self, bl, cl): assert "answer is 42." == cl.calls[0][2]["event"] + async def test_alog_interp_dict(self, bl, cl): + """ + Dict-based interpolation happens if a mapping is passed. + """ + await bl.alog(logging.INFO, "answer is %(answer)d.", {"answer": 42}) + + assert "answer is 42." == cl.calls[0][2]["event"] + def test_filter_bound_below_missing_event_string(self, bl): """ Missing event arg causes exception below min_level. @@ -222,11 +238,35 @@ def test_exception_positional_args(self, bl, cl): ("error", (), {"event": "boom bastic", "exc_info": True}) ] == cl.calls + def test_exception_dict_args(self, bl, cl): + """ + exception allows for dict-based args + """ + bl.exception( + "%(action)s %(what)s", {"action": "boom", "what": "bastic"} + ) + + assert [ + ("error", (), {"event": "boom bastic", "exc_info": True}) + ] == cl.calls + async def test_aexception_positional_args(self, bl, cl): """ aexception allows for positional args """ await bl.aexception("%s %s", "boom", "bastic") + + assert 1 == len(cl.calls) + assert "boom bastic" == cl.calls[0][2]["event"] + + async def test_aexception_dict_args(self, bl, cl): + """ + aexception allows for dict-based args + """ + await bl.aexception( + "%(action)s %(what)s", {"action": "boom", "what": "bastic"} + ) + assert 1 == len(cl.calls) assert "boom bastic" == cl.calls[0][2]["event"] From c76d079f4ab3fdc5a2e608f31890a26be9d34c82 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 26 Sep 2025 10:55:11 +0200 Subject: [PATCH 1408/1520] Update sponsors --- README.md | 1 - docs/index.md | 1 - pyproject.toml | 5 ----- 3 files changed, 7 deletions(-) diff --git a/README.md b/README.md index 4336066d..b11fd158 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,6 @@ for sponsor in tomllib.loads(pathlib.Path("pyproject.toml").read_text())["tool"] ]]] --> - diff --git a/docs/index.md b/docs/index.md index 2a179f1a..c3ecf276 100644 --- a/docs/index.md +++ b/docs/index.md @@ -21,7 +21,6 @@ for sponsor in tomllib.loads(pathlib.Path("pyproject.toml").read_text())["tool"] ]]] --> - diff --git a/pyproject.toml b/pyproject.toml index d899c45e..3cdfe033 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -245,11 +245,6 @@ title = "Tidelift" url = "https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek" img = "Tidelift.svg" -[[tool.sponcon.sponsors]] -title = "Klaviyo" -url = "https://klaviyo.com/" -img = "Klaviyo.svg" - [[tool.sponcon.sponsors]] title = "Privacy Solutions" url = "https://privacy-solutions.org/" From 0662886b44950d44ee861d32b6aba3b7e3582f56 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 1 Oct 2025 06:47:50 +0200 Subject: [PATCH 1409/1520] Update dev --- .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/zizmor.yml | 2 +- .pre-commit-config.yaml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 478b8be6..63f56529 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -29,12 +29,12 @@ jobs: persist-credentials: false - name: Initialize CodeQL - uses: github/codeql-action/init@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3 + uses: github/codeql-action/init@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3 + uses: github/codeql-action/autobuild@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3 + uses: github/codeql-action/analyze@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5 diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index 7745e18c..9755a127 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -30,7 +30,7 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload SARIF file - uses: github/codeql-action/upload-sarif@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3 + uses: github/codeql-action/upload-sarif@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5 with: # Path to SARIF file relative to the root of the repository sarif_file: results.sarif diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 66446127..c24cd082 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.13.0 + rev: v0.13.2 hooks: - id: ruff-check args: [--fix, --exit-non-zero-on-fix] From 7e92f4baba4eda4cab28663f07074e417f4856b2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 1 Oct 2025 12:28:21 +0200 Subject: [PATCH 1410/1520] Group dependabot updates --- .github/dependabot.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 64284b90..b339aaeb 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,7 +1,11 @@ --- version: 2 updates: - - package-ecosystem: "github-actions" - directory: "/" + - package-ecosystem: github-actions + directory: / schedule: - interval: "monthly" + interval: monthly + groups: + github-actions: + patterns: + - "*" From 9594c539e4fe3fbefeac2b5a1576be49f7901e6e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 6 Oct 2025 08:45:37 +0200 Subject: [PATCH 1411/1520] Fix python-json-logger URL to new maintainer --- docs/standard-library.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/standard-library.md b/docs/standard-library.md index ad30b2e3..2f45ac4e 100644 --- a/docs/standard-library.md +++ b/docs/standard-library.md @@ -570,4 +570,4 @@ If you leave `foreign_pre_chain` as `None`, formatting will be left to `logging` Meaning: you can define a `format` for {class}`~structlog.stdlib.ProcessorFormatter` too! -[*python-json-logger*]: https://github.com/madzak/python-json-logger +[*python-json-logger*]: https://github.com/nhairs/python-json-logger From fda30395799f5b60252a530eb947fbd4e8a15a7f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 19:40:13 +0200 Subject: [PATCH 1412/1520] [pre-commit.ci] pre-commit autoupdate (#753) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.13.2 → v0.13.3](https://github.com/astral-sh/ruff-pre-commit/compare/v0.13.2...v0.13.3) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c24cd082..8a44df69 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.13.2 + rev: v0.13.3 hooks: - id: ruff-check args: [--fix, --exit-non-zero-on-fix] From b4edc3428849f78f3878584df556fd9911193421 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 11 Oct 2025 12:28:55 +0200 Subject: [PATCH 1413/1520] Update dev deps (#755) --- .github/workflows/ci.yml | 2 +- .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/pypi-package.yml | 2 +- .github/workflows/zizmor.yml | 2 +- .pre-commit-config.yaml | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d726a342..b9fb6a8b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: fetch-depth: 0 persist-credentials: false - - uses: hynek/build-and-inspect-python-package@c52c3a4710070b50470d903818a7b25115dcd076 # v2.13.0 + - uses: hynek/build-and-inspect-python-package@efb823f52190ad02594531168b7a2d5790e66516 # v2.14.0 id: baipp outputs: diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 63f56529..e9bd115b 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -29,12 +29,12 @@ jobs: persist-credentials: false - name: Initialize CodeQL - uses: github/codeql-action/init@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5 + uses: github/codeql-action/init@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5 + uses: github/codeql-action/autobuild@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5 + uses: github/codeql-action/analyze@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8 diff --git a/.github/workflows/pypi-package.yml b/.github/workflows/pypi-package.yml index 5b40420a..99735e7e 100644 --- a/.github/workflows/pypi-package.yml +++ b/.github/workflows/pypi-package.yml @@ -26,7 +26,7 @@ jobs: fetch-depth: 0 persist-credentials: false - - uses: hynek/build-and-inspect-python-package@c52c3a4710070b50470d903818a7b25115dcd076 # v2.13.0 + - uses: hynek/build-and-inspect-python-package@efb823f52190ad02594531168b7a2d5790e66516 # v2.14.0 with: attest-build-provenance-github: 'true' diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index 9755a127..932b465d 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -30,7 +30,7 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload SARIF file - uses: github/codeql-action/upload-sarif@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5 + uses: github/codeql-action/upload-sarif@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8 with: # Path to SARIF file relative to the root of the repository sarif_file: results.sarif diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8a44df69..3dd4f673 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.13.3 + rev: v0.14.0 hooks: - id: ruff-check args: [--fix, --exit-non-zero-on-fix] From 11e08722d6052350e1ee631f542c2dd8af6e6fe7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 11 Oct 2025 13:56:27 +0200 Subject: [PATCH 1414/1520] Switch docs to sphinx-book-theme The only reason is because MyST figure captions vanished and I have no time to investigate --- README.md | 2 +- docs/_static/custom.css | 18 ++++-------------- docs/conf.py | 12 +++--------- docs/console-output.md | 2 ++ pyproject.toml | 4 +++- 5 files changed, 13 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index b11fd158..d209dc66 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Thanks to its flexible design, *you* choose whether you want *structlog* to take The output format is just as flexible and *structlog* comes with support for JSON, [*logfmt*](https://brandur.org/logfmt), as well as pretty console output out-of-the-box: -[![image](https://github.com/hynek/structlog/blob/main/docs/_static/console_renderer.png?raw=true)](https://github.com/hynek/structlog/blob/main/docs/_static/console_renderer.png?raw=true) +[![Screenshot of colorful structlog output with ConsoleRenderer](https://github.com/hynek/structlog/blob/main/docs/_static/console_renderer.png?raw=true)](https://github.com/hynek/structlog/blob/main/docs/_static/console_renderer.png?raw=true) ## Sponsors diff --git a/docs/_static/custom.css b/docs/_static/custom.css index b5bbc2d3..564f3d08 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -3,18 +3,8 @@ :root { - font-feature-settings: 'liga' 1, 'calt' 1; - /* fix for Chrome */ -} - -@supports (font-variation-settings: normal) { - :root { - font-family: 'Atkinson Hyperlegible', sans-serif; - } -} - - -/* Hide ToC caption text within the main body (but leave them in the side-bar). */ -#furo-main-content span.caption-text { - display: none; + font-feature-settings: 'liga' 1, 'calt' 1; /* fix for Chrome */ + --pst-font-family-base: "Atkinson Hyperlegible", system-ui, sans-serif; + --pst-font-family-heading: "Atkinson Hyperlegible", system-ui, sans-serif; + --pst-font-family-monospace: BerkeleyMono, ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace; } diff --git a/docs/conf.py b/docs/conf.py index 44efba9a..0b9ba7a4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -32,6 +32,7 @@ "sphinx.ext.viewcode", "sphinxcontrib.mermaid", "sphinxext.opengraph", + "sphinx_copybutton", ] myst_enable_extensions = [ @@ -99,15 +100,8 @@ # -- Options for HTML output -------------------------------------------------- -html_theme = "furo" -html_theme_options = { - "top_of_page_buttons": [], - "light_css_variables": { - "font-stack": "Atkinson Hyperlegible, sans-serif", - "font-stack--monospace": "BerkeleyMono, MonoLisa, ui-monospace, " - "SFMono-Regular, Menlo, Consolas, Liberation Mono, monospace", - }, -} +html_theme = "sphinx_book_theme" +html_theme_options = {} html_logo = "_static/structlog_logo.svg" html_static_path = ["_static"] html_css_files = ["custom.css"] diff --git a/docs/console-output.md b/docs/console-output.md index 13985f40..af31853c 100644 --- a/docs/console-output.md +++ b/docs/console-output.md @@ -12,6 +12,8 @@ Rich takes precedence over *better-exceptions*, but you can configure it by pass The following output is rendered using Rich: ```{figure} _static/console_renderer.png +:alt: Screenshot of colorful console output by ConsoleRenderer. + Colorful console output by ConsoleRenderer. ``` diff --git a/pyproject.toml b/pyproject.toml index 3cdfe033..a6c43c41 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,9 +52,11 @@ tests = [ typing = ["mypy>=1.4", "rich", "twisted"] docs = [ "cogapp", - "furo", "myst-parser", "sphinx", + "sphinx-design", + "sphinx-copybutton", + "sphinx-book-theme", "sphinx-notfound-page", "sphinxcontrib-mermaid", "sphinxext-opengraph", From d517cde8ad7b22e9015e2144134ad805b024f1d4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 12 Oct 2025 08:38:24 +0200 Subject: [PATCH 1415/1520] Improve ConsoleRenderer ergonomics (#749) * Add structlog.dev.get_active_console_renderer() * Allow setting exception_formatter --- CHANGELOG.md | 13 ++++++++ docs/api.rst | 6 +++- docs/console-output.md | 9 +++++- src/structlog/dev.py | 59 +++++++++++++++++++++++++++++++++++++ src/structlog/exceptions.py | 17 +++++++++++ tests/test_dev.py | 51 ++++++++++++++++++++++++++++++++ tox.ini | 4 +-- 7 files changed, 155 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5937f430..518d0100 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,19 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ### Added +- Added `structlog.dev.get_active_console_renderer()` that returns the currently active `structlog.dev.ConsoleRenderer()`. + [#749](https://github.com/hynek/structlog/pull/749) + +- `structlog.dev.ConsoleRenderer()` now supports setting the `exception_formatter` attribute. + + You can now disable the pretty-printing of exceptions by setting it to `structlog.dev.plain_traceback`: + + ```python + cr = structlog.dev.get_active_console_renderer() + cr.exception_formatter = structlog.dev.plain_traceback + ``` + [#749](https://github.com/hynek/structlog/pull/749) + - Added `structlog.dev.ConsoleRenderer.get_default_column_styles` for reuse the default column styles. [#741](https://github.com/hynek/structlog/pull/741) diff --git a/docs/api.rst b/docs/api.rst index 644dc649..a78fa53e 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -76,7 +76,11 @@ API Reference .. automodule:: structlog.dev .. autoclass:: ConsoleRenderer - :members: get_default_level_styles, get_default_column_styles + :members: get_default_level_styles, get_default_column_styles, exception_formatter + +.. autofunction:: get_active_console_renderer +.. autoexception:: NoConsoleRendererConfiguredError +.. autoexception:: MultipleConsoleRenderersConfiguredError .. autoclass:: Column .. autoclass:: ColumnFormatter(typing.Protocol) diff --git a/docs/console-output.md b/docs/console-output.md index af31853c..715b6413 100644 --- a/docs/console-output.md +++ b/docs/console-output.md @@ -121,4 +121,11 @@ It's possible to override this behavior by setting two standard environment vari ## Disabling exception pretty-printing -If you prefer the default terse Exception rendering, but still want Rich installed, you can disable the pretty-printing by instantiating {class}`structlog.dev.ConsoleRenderer()` yourself and passing `exception_formatter=structlog.dev.plain_traceback`. +If you prefer the default terse Exception rendering, but still want Rich installed, you can disable the auto-enabled pretty-printing by configuring your {class}`~structlog.dev.ConsoleRenderer` to use {class}`structlog.dev.plain_traceback`. + +You can either instantiate {class}`structlog.dev.ConsoleRenderer()` yourself and pass `exception_formatter=structlog.dev.plain_traceback`, or set the `exception_formatter` attribute of the active console renderer to it: + +```python +cr = structlog.dev.get_active_console_renderer() +cr.exception_formatter = structlog.dev.plain_traceback +``` diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 858fcee1..db300c7c 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -30,6 +30,10 @@ ) from ._frames import _format_exception +from .exceptions import ( + MultipleConsoleRenderersConfiguredError, + NoConsoleRendererConfiguredError, +) from .processors import _figure_out_exc_info from .typing import EventDict, ExceptionRenderer, ExcInfo, WrappedLogger @@ -463,6 +467,13 @@ class ConsoleRenderer: *after* the log line. If Rich_ or better-exceptions_ are present, in colors and with extra context. + Tip: + Since `ConsoleRenderer` is mainly a development helper, it is less + strict about immutability than the rest of *structlog* for better + ergonomics. Notably, the currently active instance can be obtained by + calling `get_active_console_renderer()` and it offers properties to + configure its behavior after instantiation. + Args: columns: A list of `Column` objects defining both the order and format of @@ -829,6 +840,22 @@ def get_default_level_styles(colors: bool = True) -> dict[str, str]: "notset": styles.level_notset, } + @property + def exception_formatter(self) -> ExceptionRenderer: + """ + The exception formatter used by this console renderer. + + .. versionadded:: 25.5.0 + """ + return self._exception_formatter + + @exception_formatter.setter + def exception_formatter(self, value: ExceptionRenderer) -> None: + """ + .. versionadded:: 25.5.0 + """ + self._exception_formatter = value + _SENTINEL = object() @@ -852,3 +879,35 @@ def set_exc_info( event_dict["exc_info"] = True return event_dict + + +def get_active_console_renderer() -> ConsoleRenderer: + """ + If *structlog* is configured to use `ConsoleRenderer`, it's returned. + + It does not have to be the last processor. + + Raises: + NoConsoleRendererConfiguredError: + If no ConsoleRenderer is found in the current configuration. + + MultipleConsoleRenderersConfiguredError: + If more than one is found in the current configuration. This is + almost certainly a bug. + + .. versionadded:: 25.5.0 + """ + from ._config import get_config + + cr = None + for p in get_config()["processors"]: + if isinstance(p, ConsoleRenderer): + if cr is not None: + raise MultipleConsoleRenderersConfiguredError + + cr = p + + if cr is None: + raise NoConsoleRendererConfiguredError + + return cr diff --git a/src/structlog/exceptions.py b/src/structlog/exceptions.py index af46a357..df0b5a34 100644 --- a/src/structlog/exceptions.py +++ b/src/structlog/exceptions.py @@ -16,3 +16,20 @@ class DropEvent(BaseException): Derives from BaseException because it's technically not an error. """ + + +class NoConsoleRendererConfiguredError(Exception): + """ + A user asked for the current `structlog.dev.ConsoleRenderer` but none is + configured. + + .. versionadded:: 25.5.0 + """ + + +class MultipleConsoleRenderersConfiguredError(Exception): + """ + A user asked for the current `structlog.dev.ConsoleRenderer` and more than one is configured. + + .. versionadded:: 25.5.0 + """ diff --git a/tests/test_dev.py b/tests/test_dev.py index 05da67d5..6d6b08b4 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -11,6 +11,8 @@ import pytest +import structlog + from structlog import dev @@ -682,6 +684,18 @@ def test_does_not_modify_styles(self): assert copy == styles + def test_exception_formatter_property(self, cr): + """ + The exception formatter can be set and retrieved without + re-instantiating ConsoleRenderer. + """ + sentinel = object() + + cr.exception_formatter = sentinel + + assert sentinel is cr.exception_formatter + assert sentinel is cr._exception_formatter + class TestSetExcInfo: def test_wrong_name(self): @@ -820,3 +834,40 @@ def test_no_style(self): assert "[critical]" == dev.LogLevelColumnFormatter(None, "foo")( "", "critical" ) + + +class TestGetActiveConsoleRenderer: + def test_ok(self): + """ + If there's an active ConsoleRenderer, it's returned. + """ + assert ( + structlog.get_config()["processors"][-1] + is dev.get_active_console_renderer() + ) + + def test_no_console_renderer(self): + """ + If no ConsoleRenderer is configured, raise + NoConsoleRendererConfiguredError. + """ + structlog.configure(processors=[]) + + with pytest.raises( + structlog.exceptions.NoConsoleRendererConfiguredError + ): + dev.get_active_console_renderer() + + def test_multiple_console_renderers(self): + """ + If multiple ConsoleRenderers are configured, raise + MultipleConsoleRenderersConfiguredError because it's most likely a bug. + """ + structlog.configure( + processors=[dev.ConsoleRenderer(), dev.ConsoleRenderer()] + ) + + with pytest.raises( + structlog.exceptions.MultipleConsoleRenderersConfiguredError + ): + dev.get_active_console_renderer() diff --git a/tox.ini b/tox.ini index ca047ba6..d4b99701 100644 --- a/tox.ini +++ b/tox.ini @@ -83,8 +83,8 @@ commands = cog -rP README.md docs/index.md [testenv:pre-commit] skip_install = true -deps = pre-commit -commands = pre-commit run --all-files +deps = prek +commands = prek run --all-files [testenv:mypy-pkg] From 26e9e09622454d4914a07dbb166ab59b916838bf Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 12 Oct 2025 08:42:28 +0200 Subject: [PATCH 1416/1520] Fix Starlette case --- docs/contextvars.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contextvars.md b/docs/contextvars.md index 10c1b1e9..ca8daf2f 100644 --- a/docs/contextvars.md +++ b/docs/contextvars.md @@ -22,7 +22,7 @@ This context is safe to be used both in threaded as well as asynchronous code. :::{warning} Since the storage mechanics of your context variables is different for each concurrency method, they are _isolated_ from each other. -This can be a problem in hybrid applications like those based on [*starlette*](https://www.starlette.io) (this [includes FastAPI](https://github.com/tiangolo/fastapi/discussions/5999)) where context variables set in a synchronous context don't appear in logs from an async context and vice versa. +This can be a problem in hybrid applications like those based on [Starlette](https://www.starlette.io) (this [includes FastAPI](https://github.com/tiangolo/fastapi/discussions/5999)) where context variables set in a synchronous context don't appear in logs from an async context and vice versa. ::: The general flow is: From 17f4023cfbe7e283be2265d361c1e5ba5c13585d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 12 Oct 2025 14:59:04 +0200 Subject: [PATCH 1417/1520] dev: use property to set exception formatter --- src/structlog/dev.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index db300c7c..195a0ca4 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -592,7 +592,7 @@ def __init__( columns: list[Column] | None = None, pad_level: bool = True, ): - self._exception_formatter = exception_formatter + self.exception_formatter = exception_formatter self._sort_keys = sort_keys if columns is not None: From 7935efe2df58148e7601d065f0a001c2866b35aa Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 12 Oct 2025 15:05:41 +0200 Subject: [PATCH 1418/1520] Allow setting sort_keys on current ConsoleRenderer (#756) --- CHANGELOG.md | 2 ++ docs/api.rst | 2 +- src/structlog/dev.py | 16 ++++++++++++++++ tests/test_dev.py | 16 ++++++++++++++++ 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 518d0100..48adf545 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,8 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ``` [#749](https://github.com/hynek/structlog/pull/749) +- Same for *sort_keys*. + - Added `structlog.dev.ConsoleRenderer.get_default_column_styles` for reuse the default column styles. [#741](https://github.com/hynek/structlog/pull/741) diff --git a/docs/api.rst b/docs/api.rst index a78fa53e..5076c83f 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -76,7 +76,7 @@ API Reference .. automodule:: structlog.dev .. autoclass:: ConsoleRenderer - :members: get_default_level_styles, get_default_column_styles, exception_formatter + :members: get_default_level_styles, get_default_column_styles, exception_formatter, sort_keys .. autofunction:: get_active_console_renderer .. autoexception:: NoConsoleRendererConfiguredError diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 195a0ca4..6e6ce35f 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -856,6 +856,22 @@ def exception_formatter(self, value: ExceptionRenderer) -> None: """ self._exception_formatter = value + @property + def sort_keys(self) -> bool: + """ + Whether to sort keys when formatting. + + .. versionadded:: 25.5.0 + """ + return self._sort_keys + + @sort_keys.setter + def sort_keys(self, value: bool) -> None: + """ + .. versionadded:: 25.5.0 + """ + self._sort_keys = value + _SENTINEL = object() diff --git a/tests/test_dev.py b/tests/test_dev.py index 6d6b08b4..a6c7ba94 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -696,6 +696,22 @@ def test_exception_formatter_property(self, cr): assert sentinel is cr.exception_formatter assert sentinel is cr._exception_formatter + def test_sort_keys_property(self, cr): + """ + The sort_keys setting can be set and retrieved without re-instantiating + ConsoleRenderer. + """ + assert cr.sort_keys is True + assert cr._sort_keys is True + + cr.sort_keys = False + assert cr.sort_keys is False + assert cr._sort_keys is False + + cr.sort_keys = True + assert cr.sort_keys is True + assert cr._sort_keys is True + class TestSetExcInfo: def test_wrong_name(self): From 6df51b0bba1a557333605341fdc9ec923846286f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 12 Oct 2025 15:06:59 +0200 Subject: [PATCH 1419/1520] Add PR# --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48adf545..c1e44725 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ [#749](https://github.com/hynek/structlog/pull/749) - Same for *sort_keys*. + [#756](https://github.com/hynek/structlog/pull/756) - Added `structlog.dev.ConsoleRenderer.get_default_column_styles` for reuse the default column styles. [#741](https://github.com/hynek/structlog/pull/741) From cd71eb472f140d979b15874fb57cba34c2f75947 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 12 Oct 2025 15:36:05 +0200 Subject: [PATCH 1420/1520] Whitespace --- tests/test_dev.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_dev.py b/tests/test_dev.py index a6c7ba94..8d5fd7e1 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -705,10 +705,12 @@ def test_sort_keys_property(self, cr): assert cr._sort_keys is True cr.sort_keys = False + assert cr.sort_keys is False assert cr._sort_keys is False cr.sort_keys = True + assert cr.sort_keys is True assert cr._sort_keys is True From 3a9d88a17f2e8143a5b5ebf77868efc718431240 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 12 Oct 2025 15:45:04 +0200 Subject: [PATCH 1421/1520] dev: make ConsoleRenderer.get_default_column_styles more explicit --- src/structlog/dev.py | 9 +++++---- tests/test_dev.py | 5 ----- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 6e6ce35f..bd06ea43 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -640,7 +640,6 @@ def add_meaningless_arg(arg: str) -> None: return - # Create default columns configuration. styles = self.get_default_column_styles(colors, force_colors) self._styles = styles @@ -710,13 +709,14 @@ def add_meaningless_arg(arg: str) -> None: @classmethod def get_default_column_styles( - cls, colors: bool = _has_colors, force_colors: bool = False + cls, colors: bool, force_colors: bool = False ) -> Styles: """ Configure and return the appropriate styles class for console output. This method handles the setup of colorful or plain styles, including - proper colorama initialization on Windows systems when colors are enabled. + proper colorama initialization on Windows systems when colors are + enabled. Args: colors: Whether to use colorful output styles. @@ -729,7 +729,8 @@ def get_default_column_styles( The configured styles class (_ColorfulStyles or _PlainStyles). Raises: - SystemError: On Windows when colors=True but colorama is not installed. + SystemError: + On Windows when colors=True but colorama is not installed. .. versionadded:: 25.5.0 """ diff --git a/tests/test_dev.py b/tests/test_dev.py index 8d5fd7e1..d4060caa 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -184,11 +184,6 @@ def test_returns_colorful_styles_when_colors_true(self): styles = dev.ConsoleRenderer.get_default_column_styles(colors=True) assert styles is dev._ColorfulStyles - assert hasattr(styles, "reset") - assert hasattr(styles, "bright") - assert hasattr(styles, "level_critical") - assert hasattr(styles, "kv_key") - assert hasattr(styles, "kv_value") def test_returns_plain_styles_when_colors_false(self): """ From acc17edee1119fe89c3f0447d66b31add526e6bb Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 12 Oct 2025 15:59:13 +0200 Subject: [PATCH 1422/1520] dev: make Styles public for easier customization --- docs/api.rst | 2 + src/structlog/dev.py | 93 ++++++++++++++++++++++++-------------------- tests/test_dev.py | 16 ++++---- 3 files changed, 61 insertions(+), 50 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 5076c83f..4a52e383 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -78,6 +78,8 @@ API Reference .. autoclass:: ConsoleRenderer :members: get_default_level_styles, get_default_column_styles, exception_formatter, sort_keys +.. autoclass:: Styles + .. autofunction:: get_active_console_renderer .. autoexception:: NoConsoleRendererConfiguredError .. autoexception:: MultipleConsoleRenderersConfiguredError diff --git a/src/structlog/dev.py b/src/structlog/dev.py index bd06ea43..b0e7ecd9 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -24,8 +24,6 @@ Protocol, Sequence, TextIO, - Type, - Union, cast, ) @@ -112,9 +110,22 @@ def _pad(s: str, length: int) -> str: _use_colors = _has_colors -class _Styles(Protocol): +@dataclass(frozen=True) +class Styles: + """ + Style settings for console rendering. + + These are console ANSI codes that are printed before the respective fields. + This allows for a certain amount of customization if you don't want to + configure your columns. + + .. versionadded:: 25.5.0 + It was handled by private structures before. + """ + reset: str bright: str + level_critical: str level_exception: str level_error: str @@ -129,43 +140,41 @@ class _Styles(Protocol): kv_value: str -Styles = Union[_Styles, Type[_Styles]] - - -class _ColorfulStyles: - reset = RESET_ALL - bright = BRIGHT - - level_critical = RED - level_exception = RED - level_error = RED - level_warn = YELLOW - level_info = GREEN - level_debug = GREEN - level_notset = RED_BACK - - timestamp = DIM - logger_name = BLUE - kv_key = CYAN - kv_value = MAGENTA - - -class _PlainStyles: - reset = "" - bright = "" +_colorful_styles = Styles( + reset=RESET_ALL, + bright=BRIGHT, + level_critical=RED, + level_exception=RED, + level_error=RED, + level_warn=YELLOW, + level_info=GREEN, + level_debug=GREEN, + level_notset=RED_BACK, + timestamp=DIM, + logger_name=BLUE, + kv_key=CYAN, + kv_value=MAGENTA, +) - level_critical = "" - level_exception = "" - level_error = "" - level_warn = "" - level_info = "" - level_debug = "" - level_notset = "" +_plain_styles = Styles( + reset="", + bright="", + level_critical="", + level_exception="", + level_error="", + level_warn="", + level_info="", + level_debug="", + level_notset="", + timestamp="", + logger_name="", + kv_key="", + kv_value="", +) - timestamp = "" - logger_name = "" - kv_key = "" - kv_value = "" +# Backward compatibility aliases +_ColorfulStyles = _colorful_styles +_PlainStyles = _plain_styles class ColumnFormatter(Protocol): @@ -726,7 +735,7 @@ def get_default_column_styles( Only relevant on Windows with colorama. Returns: - The configured styles class (_ColorfulStyles or _PlainStyles). + The configured styles. Raises: SystemError: @@ -735,7 +744,7 @@ def get_default_column_styles( .. versionadded:: 25.5.0 """ if not colors: - return _PlainStyles + return _plain_styles if _IS_WINDOWS: # pragma: no cover # On Windows, we can't do colorful output without colorama. @@ -754,7 +763,7 @@ def get_default_column_styles( else: colorama.init() - return _ColorfulStyles + return _colorful_styles def _repr(self, val: Any) -> str: """ @@ -829,7 +838,7 @@ def get_default_level_styles(colors: bool = True) -> dict[str, str]: parameter to `ConsoleRenderer`. Default: `True`. """ styles: Styles - styles = _ColorfulStyles if colors else _PlainStyles + styles = _colorful_styles if colors else _plain_styles return { "critical": styles.level_critical, "exception": styles.level_exception, diff --git a/tests/test_dev.py b/tests/test_dev.py index d4060caa..d108769b 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -179,19 +179,19 @@ def test_init_accepts_overriding_levels(self, styles, padded): def test_returns_colorful_styles_when_colors_true(self): """ - When colors=True, returns _ColorfulStyles class. + When colors=True, returns _colorful_styles instance. """ styles = dev.ConsoleRenderer.get_default_column_styles(colors=True) - assert styles is dev._ColorfulStyles + assert styles is dev._colorful_styles def test_returns_plain_styles_when_colors_false(self): """ - When colors=False, returns _PlainStyles class. + When colors=False, returns _plain_styles instance. """ styles = dev.ConsoleRenderer.get_default_column_styles(colors=False) - assert styles is dev._PlainStyles + assert styles is dev._plain_styles assert styles.reset == "" assert styles.bright == "" assert styles.level_critical == "" @@ -226,7 +226,7 @@ def test_initializes_colorama_on_windows_with_force_colors(self): colors=True, force_colors=True ) - assert styles is dev._ColorfulStyles + assert styles is dev._colorful_styles mock_deinit.assert_called_once() mock_init.assert_called_once_with(strip=False) @@ -529,7 +529,7 @@ def test_colorama_colors_false(self): None, None, {"event": "event", "level": "info", "foo": "bar"} ) - assert dev._PlainStyles is plain_cr._styles + assert dev._plain_styles is plain_cr._styles assert "[info ] event foo=bar" == rv def test_colorama_force_colors(self, styles, padded): @@ -562,7 +562,7 @@ def test_colorama_force_colors(self, styles, padded): + styles.reset ) == rv - assert not dev._has_colors or dev._ColorfulStyles is cr._styles + assert not dev._has_colors or dev._colorful_styles is cr._styles @pytest.mark.parametrize("rns", [True, False]) def test_repr_native_str(self, rns): @@ -613,7 +613,7 @@ def test_columns_warns_about_meaningless_arguments(self, recwarn): colors=not dev._has_colors, force_colors=True, repr_native_str=True, - level_styles=dev._PlainStyles, + level_styles=dev._plain_styles, event_key="not event", timestamp_key="not timestamp", ) From 509902ceb22bfeb6ee3e3085a8ccdb2859deaad3 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 12 Oct 2025 16:17:21 +0200 Subject: [PATCH 1423/1520] dev: refactor default columns configuration into a method This way we can re-run it on demand. --- docs/api.rst | 2 +- src/structlog/dev.py | 141 ++++++++++++++++++++++++------------------- 2 files changed, 81 insertions(+), 62 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 4a52e383..8a20b007 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -78,7 +78,7 @@ API Reference .. autoclass:: ConsoleRenderer :members: get_default_level_styles, get_default_column_styles, exception_formatter, sort_keys -.. autoclass:: Styles +.. autoclass:: ColumnStyles .. autofunction:: get_active_console_renderer .. autoexception:: NoConsoleRendererConfiguredError diff --git a/src/structlog/dev.py b/src/structlog/dev.py index b0e7ecd9..af4386a8 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -111,9 +111,9 @@ def _pad(s: str, length: int) -> str: @dataclass(frozen=True) -class Styles: +class ColumnStyles: """ - Style settings for console rendering. + Column styles settings for console rendering. These are console ANSI codes that are printed before the respective fields. This allows for a certain amount of customization if you don't want to @@ -140,7 +140,7 @@ class Styles: kv_value: str -_colorful_styles = Styles( +_colorful_styles = ColumnStyles( reset=RESET_ALL, bright=BRIGHT, level_critical=RED, @@ -156,7 +156,7 @@ class Styles: kv_value=MAGENTA, ) -_plain_styles = Styles( +_plain_styles = ColumnStyles( reset="", bright="", level_critical="", @@ -651,13 +651,83 @@ def add_meaningless_arg(arg: str) -> None: styles = self.get_default_column_styles(colors, force_colors) - self._styles = styles + self._repr_native_str = repr_native_str - level_to_color = ( - self.get_default_level_styles(colors) + self._configure_columns( + styles=styles, + level_styles=self.get_default_level_styles(colors) if level_styles is None - else level_styles - ).copy() + else level_styles, + pad_level=pad_level, + timestamp_key=timestamp_key, + event_key=event_key, + pad_event=pad_event, + ) + + @classmethod + def get_default_column_styles( + cls, colors: bool, force_colors: bool = False + ) -> ColumnStyles: + """ + Configure and return the appropriate styles class for console output. + + This method handles the setup of colorful or plain styles, including + proper colorama initialization on Windows systems when colors are + enabled. + + Args: + colors: Whether to use colorful output styles. + + force_colors: + Force colorful output even in non-interactive environments. + Only relevant on Windows with colorama. + + Returns: + The configured styles. + + Raises: + SystemError: + On Windows when colors=True but colorama is not installed. + + .. versionadded:: 25.5.0 + """ + if not colors: + return _plain_styles + + if _IS_WINDOWS: # pragma: no cover + # On Windows, we can't do colorful output without colorama. + if colorama is None: + raise SystemError( + _MISSING.format( + who=cls.__name__ + " with `colors=True`", + package="colorama", + ) + ) + # Colorama must be init'd on Windows, but must NOT be + # init'd on other OSes, because it can break colors. + if force_colors: + colorama.deinit() + colorama.init(strip=False) + else: + colorama.init() + + return _colorful_styles + + def _configure_columns( + self, + *, + styles: ColumnStyles, + level_styles: dict[str, str], + pad_level: bool, + timestamp_key: str, + event_key: str, + pad_event: int, + ) -> None: + """ + Re-configures columns according to the given styles and parameters. + """ + self._styles = styles + level_to_color = level_styles.copy() for key in level_to_color: level_to_color[key] += styles.bright @@ -665,8 +735,6 @@ def add_meaningless_arg(arg: str) -> None: max(level_to_color.keys(), key=lambda e: len(e)) ) - self._repr_native_str = repr_native_str - self._default_column_formatter = KeyValueColumnFormatter( styles.kv_key, styles.kv_value, @@ -716,55 +784,6 @@ def add_meaningless_arg(arg: str) -> None: Column("logger_name", logger_name_formatter), ] - @classmethod - def get_default_column_styles( - cls, colors: bool, force_colors: bool = False - ) -> Styles: - """ - Configure and return the appropriate styles class for console output. - - This method handles the setup of colorful or plain styles, including - proper colorama initialization on Windows systems when colors are - enabled. - - Args: - colors: Whether to use colorful output styles. - - force_colors: - Force colorful output even in non-interactive environments. - Only relevant on Windows with colorama. - - Returns: - The configured styles. - - Raises: - SystemError: - On Windows when colors=True but colorama is not installed. - - .. versionadded:: 25.5.0 - """ - if not colors: - return _plain_styles - - if _IS_WINDOWS: # pragma: no cover - # On Windows, we can't do colorful output without colorama. - if colorama is None: - raise SystemError( - _MISSING.format( - who=cls.__name__ + " with `colors=True`", - package="colorama", - ) - ) - # Colorama must be init'd on Windows, but must NOT be - # init'd on other OSes, because it can break colors. - if force_colors: - colorama.deinit() - colorama.init(strip=False) - else: - colorama.init() - - return _colorful_styles - def _repr(self, val: Any) -> str: """ Determine representation of *val* depending on its type & @@ -837,7 +856,7 @@ def get_default_level_styles(colors: bool = True) -> dict[str, str]: Whether to use colorful styles. This must match the *colors* parameter to `ConsoleRenderer`. Default: `True`. """ - styles: Styles + styles: ColumnStyles styles = _colorful_styles if colors else _plain_styles return { "critical": styles.level_critical, From b0081ac705cebb8c6c50e17a450fa28627eb079f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 13 Oct 2025 06:42:27 +0200 Subject: [PATCH 1424/1520] dev: allow columns to be got and set (#757) --- CHANGELOG.md | 3 +++ docs/api.rst | 2 +- docs/console-output.md | 9 ++++--- src/structlog/dev.py | 55 +++++++++++++++++++++++++++++++++--------- tests/test_dev.py | 15 ++++++++++++ 5 files changed, 68 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1e44725..3a422b20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - Same for *sort_keys*. [#756](https://github.com/hynek/structlog/pull/756) +- Same for *columns*. + [#757](https://github.com/hynek/structlog/pull/757) + - Added `structlog.dev.ConsoleRenderer.get_default_column_styles` for reuse the default column styles. [#741](https://github.com/hynek/structlog/pull/741) diff --git a/docs/api.rst b/docs/api.rst index 8a20b007..a7f30d2a 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -76,7 +76,7 @@ API Reference .. automodule:: structlog.dev .. autoclass:: ConsoleRenderer - :members: get_default_level_styles, get_default_column_styles, exception_formatter, sort_keys + :members: get_default_level_styles, get_default_column_styles, exception_formatter, sort_keys, columns .. autoclass:: ColumnStyles diff --git a/docs/console-output.md b/docs/console-output.md index 715b6413..41e21a81 100644 --- a/docs/console-output.md +++ b/docs/console-output.md @@ -99,13 +99,14 @@ cr = structlog.dev.ConsoleRenderer( structlog.configure(processors=structlog.get_config()["processors"][:-1]+[cr]) ``` -:::{hint} -You can replace only the last processor using: +You can also access and configure the columns of the active console renderer: ```python -structlog.configure(processors=structlog.get_config()["processors"][:-1]+[cr]) +cr = structlog.dev.get_active_console_renderer() +cr.columns = [ + ... +] ``` -::: ## Standard environment variables diff --git a/src/structlog/dev.py b/src/structlog/dev.py index af4386a8..dcdd2637 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -587,6 +587,8 @@ class ConsoleRenderer: .. versionadded:: 24.2.0 *pad_level* """ + _default_column_formatter: ColumnFormatter + def __init__( self, pad_event: int = _EVENT_WIDTH, @@ -636,16 +638,7 @@ def add_meaningless_arg(arg: str) -> None: for w in to_warn: warnings.warn(w, stacklevel=2) - defaults = [col for col in columns if col.key == ""] - if not defaults: - raise ValueError( - "Must pass a default column formatter (a column with `key=''`)." - ) - if len(defaults) > 1: - raise ValueError("Only one default column formatter allowed.") - - self._default_column_formatter = defaults[0].formatter - self._columns = [col for col in columns if col.key] + self.columns = columns return @@ -808,7 +801,7 @@ def __call__( kvs = [ col.formatter(col.key, val) - for col in self._columns + for col in self.columns if (val := event_dict.pop(col.key, _NOTHING)) is not _NOTHING ] + [ self._default_column_formatter(key, event_dict[key]) @@ -901,6 +894,46 @@ def sort_keys(self, value: bool) -> None: """ self._sort_keys = value + @property + def columns(self) -> list[Column]: + """ + The columns configuration for this console renderer. + + Warning: + Just like with passing *columns* argument, many of the other + arguments you may have passed are ignored. + + Args: + value: + A list of `Column` objects defining both the order and format + of the key-value pairs in the output. + + **Must** contain a column with ``key=''`` that defines the + default formatter. + + Raises: + ValueError: If there's not exactly one default column formatter. + + .. versionadded:: 25.5.0 + """ + return [Column("", self._default_column_formatter), *self._columns] + + @columns.setter + def columns(self, value: list[Column]) -> None: + """ + .. versionadded:: 25.5.0 + """ + defaults = [col for col in value if col.key == ""] + if not defaults: + raise ValueError( + "Must pass a default column formatter (a column with `key=''`)." + ) + if len(defaults) > 1: + raise ValueError("Only one default column formatter allowed.") + + self._default_column_formatter = defaults[0].formatter + self._columns = [col for col in value if col.key] + _SENTINEL = object() diff --git a/tests/test_dev.py b/tests/test_dev.py index d108769b..fbd23d02 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -709,6 +709,21 @@ def test_sort_keys_property(self, cr): assert cr.sort_keys is True assert cr._sort_keys is True + def test_columns_property(self, cr): + """ + The columns property can be set and retrieved without re-instantiating + ConsoleRenderer. + + The property also fakes the default column formatter. + """ + cols = [dev.Column("", lambda k, v: "")] + + cr.columns = cols + + assert cols == cr.columns + assert [] == cr._columns + assert cols[0].formatter == cr._default_column_formatter + class TestSetExcInfo: def test_wrong_name(self): From d3e15eb6084d4a1794d539b893d8f89fcebb3db6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 13 Oct 2025 07:30:33 +0200 Subject: [PATCH 1425/1520] docs: update console rendering --- docs/console-output.md | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/docs/console-output.md b/docs/console-output.md index 41e21a81..c1aa420e 100644 --- a/docs/console-output.md +++ b/docs/console-output.md @@ -38,22 +38,39 @@ For the console and beyond. ## Console output configuration -:::{versionadded} 23.3.0 -::: +Since {class}`~structlog.dev.ConsoleRenderer` is mainly a development helper, it is less +strict about immutability than the rest of *structlog* for better +ergonomics. +Notably, the currently active instance can be obtained by calling {func}`structlog.dev.get_active_console_renderer()` and it offers properties to configure its behavior after instantiation. + +Roughly speaking, there are two ways to configure the console output. + + +### Defaults plus tweaking + +The easier way where you're mostly using our defaults and just tweak a few things here and there by passing arguments or setting properties (as of 25.5.0). + +For example, you can easily change the colors of the the log levels by passing the *level_styles* parameter or switch *colors* on and off completely. + +When the API talks about "styles", it means ANSI control strings. +You can find them, for example, in [Colorama](https://github.com/tartley/colorama). + -You can freely configure how the key-value pairs are formatted: colors, order, and how values are stringified. +### Explicit columns configuration + +The more flexible way is to configure *everything* by explicitly defining the columns: +Colors, order, and how values are stringified. +This is the way *structlog* represents the output configuration internally, too. For that {class}`~structlog.dev.ConsoleRenderer` accepts the *columns* parameter that takes a list of {class}`~structlog.dev.Column`s. +Once you pass the *columns* parameter, all other output-related parameters are ignored. + It allows you to assign a formatter to each key and a default formatter for the rest (by passing an empty key name). The order of the column definitions is the order in which the columns are rendered; the rest is -- depending on the *sort_keys* argument to {class}`~structlog.dev.ConsoleRenderer` -- either sorted alphabetically or in the order of the keys in the event dictionary. You can use a column definition to drop a key-value pair from the output by returning an empty string from the formatter. -When the API talks about "styles", it means ANSI control strings. -You can find them, for example, in [Colorama](https://github.com/tartley/colorama). - - It's best demonstrated by an example: ```python From bc67e8a7c1cd36f3f704e0646c712ff1e6287123 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 13 Oct 2025 07:50:28 +0200 Subject: [PATCH 1426/1520] =?UTF-8?q?dev:=20get=5Factive=5Fconsole=5Frende?= =?UTF-8?q?rer=20=E2=86=92=20ConsoleRenderer.get=5Factive?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 4 +-- docs/api.rst | 3 +- docs/console-output.md | 6 ++-- src/structlog/dev.py | 66 +++++++++++++++++++++--------------------- tests/test_dev.py | 6 ++-- 5 files changed, 42 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a422b20..f17943fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ### Added -- Added `structlog.dev.get_active_console_renderer()` that returns the currently active `structlog.dev.ConsoleRenderer()`. +- Added `structlog.dev.ConsoleRenderer.get_active()` that returns the currently active `structlog.dev.ConsoleRenderer()`. [#749](https://github.com/hynek/structlog/pull/749) - `structlog.dev.ConsoleRenderer()` now supports setting the `exception_formatter` attribute. @@ -25,7 +25,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ You can now disable the pretty-printing of exceptions by setting it to `structlog.dev.plain_traceback`: ```python - cr = structlog.dev.get_active_console_renderer() + cr = structlog.dev.ConsoleRenderer.get_active() cr.exception_formatter = structlog.dev.plain_traceback ``` [#749](https://github.com/hynek/structlog/pull/749) diff --git a/docs/api.rst b/docs/api.rst index a7f30d2a..39ed731b 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -76,11 +76,10 @@ API Reference .. automodule:: structlog.dev .. autoclass:: ConsoleRenderer - :members: get_default_level_styles, get_default_column_styles, exception_formatter, sort_keys, columns + :members: get_default_level_styles, get_default_column_styles, exception_formatter, sort_keys, columns, get_active .. autoclass:: ColumnStyles -.. autofunction:: get_active_console_renderer .. autoexception:: NoConsoleRendererConfiguredError .. autoexception:: MultipleConsoleRenderersConfiguredError diff --git a/docs/console-output.md b/docs/console-output.md index c1aa420e..2809344e 100644 --- a/docs/console-output.md +++ b/docs/console-output.md @@ -41,7 +41,7 @@ For the console and beyond. Since {class}`~structlog.dev.ConsoleRenderer` is mainly a development helper, it is less strict about immutability than the rest of *structlog* for better ergonomics. -Notably, the currently active instance can be obtained by calling {func}`structlog.dev.get_active_console_renderer()` and it offers properties to configure its behavior after instantiation. +Notably, the currently active instance can be obtained by calling {meth}`ConsoleRenderer.get_active() ` and it offers properties to configure its behavior after instantiation. Roughly speaking, there are two ways to configure the console output. @@ -119,7 +119,7 @@ structlog.configure(processors=structlog.get_config()["processors"][:-1]+[cr]) You can also access and configure the columns of the active console renderer: ```python -cr = structlog.dev.get_active_console_renderer() +cr = structlog.dev.ConsoleRenderer.get_active() cr.columns = [ ... ] @@ -144,6 +144,6 @@ If you prefer the default terse Exception rendering, but still want Rich install You can either instantiate {class}`structlog.dev.ConsoleRenderer()` yourself and pass `exception_formatter=structlog.dev.plain_traceback`, or set the `exception_formatter` attribute of the active console renderer to it: ```python -cr = structlog.dev.get_active_console_renderer() +cr = structlog.dev.ConsoleRenderer.get_active() cr.exception_formatter = structlog.dev.plain_traceback ``` diff --git a/src/structlog/dev.py b/src/structlog/dev.py index dcdd2637..b25a9306 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -480,7 +480,7 @@ class ConsoleRenderer: Since `ConsoleRenderer` is mainly a development helper, it is less strict about immutability than the rest of *structlog* for better ergonomics. Notably, the currently active instance can be obtained by - calling `get_active_console_renderer()` and it offers properties to + calling `ConsoleRenderer.get_active()` and it offers properties to configure its behavior after instantiation. Args: @@ -934,6 +934,38 @@ def columns(self, value: list[Column]) -> None: self._default_column_formatter = defaults[0].formatter self._columns = [col for col in value if col.key] + @classmethod + def get_active(cls) -> ConsoleRenderer: + """ + If *structlog* is configured to use `ConsoleRenderer`, it's returned. + + It does not have to be the last processor. + + Raises: + NoConsoleRendererConfiguredError: + If no ConsoleRenderer is found in the current configuration. + + MultipleConsoleRenderersConfiguredError: + If more than one is found in the current configuration. This is + almost certainly a bug. + + .. versionadded:: 25.5.0 + """ + from ._config import get_config + + cr = None + for p in get_config()["processors"]: + if isinstance(p, ConsoleRenderer): + if cr is not None: + raise MultipleConsoleRenderersConfiguredError + + cr = p + + if cr is None: + raise NoConsoleRendererConfiguredError + + return cr + _SENTINEL = object() @@ -957,35 +989,3 @@ def set_exc_info( event_dict["exc_info"] = True return event_dict - - -def get_active_console_renderer() -> ConsoleRenderer: - """ - If *structlog* is configured to use `ConsoleRenderer`, it's returned. - - It does not have to be the last processor. - - Raises: - NoConsoleRendererConfiguredError: - If no ConsoleRenderer is found in the current configuration. - - MultipleConsoleRenderersConfiguredError: - If more than one is found in the current configuration. This is - almost certainly a bug. - - .. versionadded:: 25.5.0 - """ - from ._config import get_config - - cr = None - for p in get_config()["processors"]: - if isinstance(p, ConsoleRenderer): - if cr is not None: - raise MultipleConsoleRenderersConfiguredError - - cr = p - - if cr is None: - raise NoConsoleRendererConfiguredError - - return cr diff --git a/tests/test_dev.py b/tests/test_dev.py index fbd23d02..16609da9 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -871,7 +871,7 @@ def test_ok(self): """ assert ( structlog.get_config()["processors"][-1] - is dev.get_active_console_renderer() + is dev.ConsoleRenderer.get_active() ) def test_no_console_renderer(self): @@ -884,7 +884,7 @@ def test_no_console_renderer(self): with pytest.raises( structlog.exceptions.NoConsoleRendererConfiguredError ): - dev.get_active_console_renderer() + dev.ConsoleRenderer.get_active() def test_multiple_console_renderers(self): """ @@ -898,4 +898,4 @@ def test_multiple_console_renderers(self): with pytest.raises( structlog.exceptions.MultipleConsoleRenderersConfiguredError ): - dev.get_active_console_renderer() + dev.ConsoleRenderer.get_active() From 635621bf694887b969003a6b0c4ecf4531e1e0d9 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 13 Oct 2025 08:46:53 +0200 Subject: [PATCH 1427/1520] Refactor terminal initialization into separate function (#758) * Refactor terminal initialization into separate function * Fix FORCE_COLOR on Windows --- .github/workflows/ci.yml | 15 +++++------ CHANGELOG.md | 3 +++ src/structlog/_config.py | 11 +++++--- src/structlog/dev.py | 56 ++++++++++++++++++++++++++++------------ 4 files changed, 57 insertions(+), 28 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b9fb6a8b..8c656b16 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,6 @@ env: permissions: {} - jobs: build-package: name: Build & verify package @@ -34,7 +33,6 @@ jobs: # packaging metadata (trove classifiers). python-versions: ${{ steps.baipp.outputs.supported_python_classifiers_json_array }} - tests: name: Tests & Mypy API on ${{ matrix.python-version }} runs-on: ubuntu-latest @@ -84,7 +82,6 @@ jobs: --installpkg dist/*.whl -e py${PYTHON//./}-mypy - coverage: name: Ensure 100% test coverage runs-on: ubuntu-latest @@ -126,7 +123,6 @@ jobs: path: htmlcov if: ${{ failure() }} - mypy-pkg: name: Mypy Codebase runs-on: ubuntu-latest @@ -148,7 +144,6 @@ jobs: uvx --with tox-uv tox run -e mypy-pkg - pyright: name: Pyright API runs-on: ubuntu-latest @@ -169,7 +164,6 @@ jobs: uvx --with tox-uv tox run -e pyright - docs: name: Run doctests needs: build-package @@ -191,7 +185,6 @@ jobs: uvx --with tox-uv tox run -e docs-doctests - install-dev: name: Verify dev env runs-on: ${{ matrix.os }} @@ -216,6 +209,11 @@ jobs: - run: .\.venv\Scripts\python.exe -Ic 'import structlog; print(structlog.__version__)' if: runner.os == 'Windows' + # Exercise the terminal initialization that we don't test otherwise. + - run: uv pip install colorama + if: runner.os == 'Windows' + - run: .\.venv\Scripts\python.exe -Ic 'import structlog; structlog.get_logger().info("test")' + if: runner.os == 'Windows' required-checks-pass: name: Ensure everything required is passing for branch protection @@ -232,11 +230,10 @@ jobs: steps: - name: Decide whether the needed jobs succeeded or failed - uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2 + uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2 with: jobs: ${{ toJSON(needs) }} - colors: name: Visual check for color settings using env variables needs: build-package diff --git a/CHANGELOG.md b/CHANGELOG.md index f17943fa..d4861723 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,6 +65,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - `structlog.tracebacks.extract()` no longer raises a *RecursionError* when the cause chain of an exception contains itself. [#739](https://github.com/hynek/structlog/pull/739) +- Default config now respects `FORCE_COLOR` on Windows. + [#758](https://github.com/hynek/structlog/pull/758) + ## [25.4.0](https://github.com/hynek/structlog/compare/25.3.0...25.4.0) - 2025-06-02 diff --git a/src/structlog/_config.py b/src/structlog/_config.py index bb493fa9..98e2f211 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -29,6 +29,10 @@ - `getting-started`. - structlog.stdlib.recreate_defaults()'s docstring. """ + +_no_colors = os.environ.get("NO_COLOR", "") != "" +_force_colors = os.environ.get("FORCE_COLOR", "") != "" + _BUILTIN_DEFAULT_PROCESSORS: Sequence[Processor] = [ merge_contextvars, add_log_level, @@ -36,16 +40,17 @@ set_exc_info, TimeStamper(fmt="%Y-%m-%d %H:%M:%S", utc=False), ConsoleRenderer( - colors=os.environ.get("NO_COLOR", "") == "" + colors=not _no_colors and ( - os.environ.get("FORCE_COLOR", "") != "" + _force_colors or ( _has_colors and sys.stdout is not None and hasattr(sys.stdout, "isatty") and sys.stdout.isatty() ) - ) + ), + force_colors=_force_colors, ), ] _BUILTIN_DEFAULT_CONTEXT_CLASS = cast(Type[Context], dict) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index b25a9306..170443d0 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -68,6 +68,45 @@ _EVENT_WIDTH = 30 # pad the event name to so many characters +if _IS_WINDOWS: # pragma: no cover + + def _init_terminal(who: str, force_colors: bool) -> None: + """ + Initialize colorama on Windows systems for colorful console output. + + Args: + who: The name of the caller for error messages. + + force_colors: + Force colorful output even in non-interactive environments. + + Raises: + SystemError: + When colorama is not installed. + """ + # On Windows, we can't do colorful output without colorama. + if colorama is None: + raise SystemError( + _MISSING.format( + who=who + " with `colors=True` on Windows", + package="colorama", + ) + ) + # Colorama must be init'd on Windows, but must NOT be + # init'd on other OSes, because it can break colors. + if force_colors: + colorama.deinit() + colorama.init(strip=False) + else: + colorama.init() +else: + + def _init_terminal(who: str, force_colors: bool) -> None: + """ + Currently, nothing to be done on non-Windows systems. + """ + + def _pad(s: str, length: int) -> str: """ Pads *s* to length *length*. @@ -687,22 +726,7 @@ def get_default_column_styles( if not colors: return _plain_styles - if _IS_WINDOWS: # pragma: no cover - # On Windows, we can't do colorful output without colorama. - if colorama is None: - raise SystemError( - _MISSING.format( - who=cls.__name__ + " with `colors=True`", - package="colorama", - ) - ) - # Colorama must be init'd on Windows, but must NOT be - # init'd on other OSes, because it can break colors. - if force_colors: - colorama.deinit() - colorama.init(strip=False) - else: - colorama.init() + _init_terminal(cls.__name__, force_colors) return _colorful_styles From f3a0d115a4f864bec726c4b3496831a8fea26424 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 13 Oct 2025 08:49:22 +0200 Subject: [PATCH 1428/1520] docs: clarify --- docs/console-output.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/console-output.md b/docs/console-output.md index 2809344e..d309e00b 100644 --- a/docs/console-output.md +++ b/docs/console-output.md @@ -128,7 +128,7 @@ cr.columns = [ ## Standard environment variables -*structlog*'s default configuration uses colors if standard out is a TTY (that is, an interactive session). +*structlog*'s default configuration uses colors if standard out is a TTY (that is, an interactive session) and is able to do so (that is, Colorama is installed on Windows). It's possible to override this behavior by setting two standard environment variables to any value except an empty string: From 19ad6c7e590b3098f0d3f8e10fdd8a8f28213d02 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 13 Oct 2025 09:00:28 +0200 Subject: [PATCH 1429/1520] dev: refactor column re-creation We're gonna have to call this for every change to the easy change properties. --- src/structlog/dev.py | 71 +++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 170443d0..ff582eb2 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -684,17 +684,18 @@ def add_meaningless_arg(arg: str) -> None: styles = self.get_default_column_styles(colors, force_colors) self._repr_native_str = repr_native_str - - self._configure_columns( - styles=styles, - level_styles=self.get_default_level_styles(colors) + self._styles = styles + self._level_styles = ( + self.get_default_level_styles(colors) if level_styles is None - else level_styles, - pad_level=pad_level, - timestamp_key=timestamp_key, - event_key=event_key, - pad_event=pad_event, + else level_styles ) + self._pad_event = pad_event + self._timestamp_key = timestamp_key + self._event_key = event_key + self._pad_level = pad_level + + self._configure_columns() @classmethod def get_default_column_styles( @@ -730,71 +731,67 @@ def get_default_column_styles( return _colorful_styles - def _configure_columns( - self, - *, - styles: ColumnStyles, - level_styles: dict[str, str], - pad_level: bool, - timestamp_key: str, - event_key: str, - pad_event: int, - ) -> None: + def _configure_columns(self) -> None: """ - Re-configures columns according to the given styles and parameters. + Re-configure self._columns and self._default_column_formatter + according to our current settings. + + Overwrite existing columns settings, regardless of whether they were + explicitly passed by the user or derived by us. """ - self._styles = styles - level_to_color = level_styles.copy() + level_to_color = self._level_styles.copy() for key in level_to_color: - level_to_color[key] += styles.bright + level_to_color[key] += self._styles.bright self._longest_level = len( max(level_to_color.keys(), key=lambda e: len(e)) ) self._default_column_formatter = KeyValueColumnFormatter( - styles.kv_key, - styles.kv_value, - styles.reset, + self._styles.kv_key, + self._styles.kv_value, + self._styles.reset, value_repr=self._repr, width=0, ) logger_name_formatter = KeyValueColumnFormatter( key_style=None, - value_style=styles.bright + styles.logger_name, - reset_style=styles.reset, + value_style=self._styles.bright + self._styles.logger_name, + reset_style=self._styles.reset, value_repr=str, prefix="[", postfix="]", ) - level_width = 0 if not pad_level else None + level_width = 0 if not self._pad_level else None self._columns = [ Column( - timestamp_key, + self._timestamp_key, KeyValueColumnFormatter( key_style=None, - value_style=styles.timestamp, - reset_style=styles.reset, + value_style=self._styles.timestamp, + reset_style=self._styles.reset, value_repr=str, ), ), Column( "level", LogLevelColumnFormatter( - level_to_color, reset_style=styles.reset, width=level_width + level_to_color, + reset_style=self._styles.reset, + width=level_width, ), ), Column( - event_key, + self._event_key, KeyValueColumnFormatter( key_style=None, - value_style=styles.bright, - reset_style=styles.reset, + value_style=self._styles.bright, + reset_style=self._styles.reset, value_repr=str, - width=pad_event, + width=self._pad_event, ), ), Column("logger", logger_name_formatter), From bf51b4a2a5f98d1c9a7289b5ceb55b6c01fcdb7a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 13 Oct 2025 09:07:59 +0200 Subject: [PATCH 1430/1520] dev: always store all configuration To enable the user to switch from columns to default + tweaks. They shouldn't, but they 100% will. --- src/structlog/dev.py | 78 +++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 40 deletions(-) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index ff582eb2..e5d4f117 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -642,60 +642,58 @@ def __init__( columns: list[Column] | None = None, pad_level: bool = True, ): + # Store all settings in case the user later switches from columns to + # defaults. self.exception_formatter = exception_formatter self._sort_keys = sort_keys + self._repr_native_str = repr_native_str + self._styles = self.get_default_column_styles(colors, force_colors) + self._level_styles = ( + self.get_default_level_styles(colors) + if level_styles is None + else level_styles + ) + self._pad_event = pad_event + self._timestamp_key = timestamp_key + self._event_key = event_key + self._pad_level = pad_level - if columns is not None: - to_warn = [] - - def add_meaningless_arg(arg: str) -> None: - to_warn.append( - f"The `{arg}` argument is ignored when passing `columns`.", - ) - - if pad_event != _EVENT_WIDTH: - add_meaningless_arg("pad_event") - - if colors != _has_colors: - add_meaningless_arg("colors") + if columns is None: + self._configure_columns() + return - if force_colors is not False: - add_meaningless_arg("force_colors") + self.columns = columns - if repr_native_str is not False: - add_meaningless_arg("repr_native_str") + to_warn = [] - if level_styles is not None: - add_meaningless_arg("level_styles") + def add_meaningless_arg(arg: str) -> None: + to_warn.append( + f"The `{arg}` argument is ignored when passing `columns`.", + ) - if event_key != "event": - add_meaningless_arg("event_key") + if pad_event != _EVENT_WIDTH: + add_meaningless_arg("pad_event") - if timestamp_key != "timestamp": - add_meaningless_arg("timestamp_key") + if colors != _has_colors: + add_meaningless_arg("colors") - for w in to_warn: - warnings.warn(w, stacklevel=2) + if force_colors is not False: + add_meaningless_arg("force_colors") - self.columns = columns + if repr_native_str is not False: + add_meaningless_arg("repr_native_str") - return + if level_styles is not None: + add_meaningless_arg("level_styles") - styles = self.get_default_column_styles(colors, force_colors) + if event_key != "event": + add_meaningless_arg("event_key") - self._repr_native_str = repr_native_str - self._styles = styles - self._level_styles = ( - self.get_default_level_styles(colors) - if level_styles is None - else level_styles - ) - self._pad_event = pad_event - self._timestamp_key = timestamp_key - self._event_key = event_key - self._pad_level = pad_level + if timestamp_key != "timestamp": + add_meaningless_arg("timestamp_key") - self._configure_columns() + for w in to_warn: + warnings.warn(w, stacklevel=2) @classmethod def get_default_column_styles( From 1e51f5f6a272bd7c049731fef1a23992e18932db Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 13 Oct 2025 10:38:15 +0200 Subject: [PATCH 1431/1520] dev: add colors and force_colors properties (#759) --- .github/workflows/ci.yml | 2 +- CHANGELOG.md | 3 + show_off.py | 4 ++ src/structlog/dev.py | 52 ++++++++++++++ tests/test_dev.py | 143 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 203 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8c656b16..7df9f889 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -212,7 +212,7 @@ jobs: # Exercise the terminal initialization that we don't test otherwise. - run: uv pip install colorama if: runner.os == 'Windows' - - run: .\.venv\Scripts\python.exe -Ic 'import structlog; structlog.get_logger().info("test")' + - run: .\.venv\Scripts\python.exe -Ic 'import structlog; log = structlog.get_logger(); log.info("colors"); structlog.dev.ConsoleRenderer.get_active().colors = False; log.info("bw")' if: runner.os == 'Windows' required-checks-pass: diff --git a/CHANGELOG.md b/CHANGELOG.md index d4861723..6cee9d38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - Same for *columns*. [#757](https://github.com/hynek/structlog/pull/757) +- Same for *colors* and *force_colors*. + [#759](https://github.com/hynek/structlog/pull/759) + - Added `structlog.dev.ConsoleRenderer.get_default_column_styles` for reuse the default column styles. [#741](https://github.com/hynek/structlog/pull/741) diff --git a/show_off.py b/show_off.py index 8fad80ab..f1e5e1ea 100644 --- a/show_off.py +++ b/show_off.py @@ -25,6 +25,10 @@ class SomeClass: log.warning("uh-uh!") log.error("omg", a_dict={"a": 42, "b": "foo"}) log.critical("wtf", what=SomeClass(x=1, y="z")) +structlog.dev.ConsoleRenderer.get_active().colors = False +log.info("where are the colors!?", colors="gone") +structlog.dev.ConsoleRenderer.get_active().colors = True +log.info("there they are!", colors="back") log2 = structlog.get_logger("another_logger") diff --git a/src/structlog/dev.py b/src/structlog/dev.py index e5d4f117..a93bbb40 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -648,6 +648,8 @@ def __init__( self._sort_keys = sort_keys self._repr_native_str = repr_native_str self._styles = self.get_default_column_styles(colors, force_colors) + self._colors = colors + self._force_colors = force_colors self._level_styles = ( self.get_default_level_styles(colors) if level_styles is None @@ -953,6 +955,56 @@ def columns(self, value: list[Column]) -> None: self._default_column_formatter = defaults[0].formatter self._columns = [col for col in value if col.key] + @property + def colors(self) -> bool: + """ + Whether to use colorful output styles. + + Setting this will update the renderer's styles immediately and reset + level styles to the defaults according to the new color setting -- even + if the color value is the same. + + .. versionadded:: 25.5.0 + """ + return self._colors + + @colors.setter + def colors(self, value: bool) -> None: + """ + .. versionadded:: 25.5.0 + """ + self._colors = value + self._styles = self.get_default_column_styles( + value, self._force_colors + ) + self._level_styles = self.get_default_level_styles(value) + + self._configure_columns() + + @property + def force_colors(self) -> bool: + """ + Force colorful output even in non-interactive environments. + + Setting this will update the renderer's styles immediately and reset + level styles to the defaults according to the current color setting -- + even if the value is the same. + + .. versionadded:: 25.5.0 + """ + return self._force_colors + + @force_colors.setter + def force_colors(self, value: bool) -> None: + """ + .. versionadded:: 25.5.0 + """ + self._force_colors = value + self._styles = self.get_default_column_styles(self._colors, value) + self._level_styles = self.get_default_level_styles(self._colors) + + self._configure_columns() + @classmethod def get_active(cls) -> ConsoleRenderer: """ diff --git a/tests/test_dev.py b/tests/test_dev.py index 16609da9..7c258dfe 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -899,3 +899,146 @@ def test_multiple_console_renderers(self): structlog.exceptions.MultipleConsoleRenderersConfiguredError ): dev.ConsoleRenderer.get_active() + + +class TestConsoleRendererColorsProperty: + def test_reset(self, cr): + """ + Setting colors to the same value resets the level styles to the + defaults. + """ + val = cr.colors + cr._level_styles = {"info": "X", "error": "Y"} + + cr.colors = cr.colors + + assert val is cr.colors + assert ( + cr._level_styles + == dev.ConsoleRenderer.get_default_level_styles(colors=val) + ) + + @pytest.mark.skipif( + dev._IS_WINDOWS and dev.colorama is None, + reason="Toggling colors=True requires colorama on Windows", + ) + def test_toggle_colors_updates_styles_and_levels(self): + """ + Toggling colors updates the styles and level styles to colorful styles. + """ + cr = dev.ConsoleRenderer(colors=False) + + assert cr.colors is False + assert cr._colors is False + assert cr._styles is dev._plain_styles + assert ( + cr._level_styles + == dev.ConsoleRenderer.get_default_level_styles(colors=False) + ) + + cr.colors = True + + assert cr.colors is True + assert cr._colors is True + assert cr._styles is dev._colorful_styles + assert ( + cr._level_styles + == dev.ConsoleRenderer.get_default_level_styles(colors=True) + ) + + @pytest.mark.skipif( + dev._IS_WINDOWS and dev.colorama is None, + reason="Toggling colors=True requires colorama on Windows", + ) + def test_toggle_resets_custom_level_styles(self): + """ + Toggling colors resets the level styles to the defaults for the new + color setting. + """ + custom = {"info": "X", "error": "Y"} + cr = dev.ConsoleRenderer(colors=False, level_styles=custom) + + assert custom == cr._level_styles + + cr.colors = True + assert ( + dev.ConsoleRenderer.get_default_level_styles(colors=True) + == cr._level_styles + ) + + # And switching back follows defaults for the new setting again + cr.colors = False + assert ( + dev.ConsoleRenderer.get_default_level_styles(colors=False) + == cr._level_styles + ) + + +class TestConsoleRendererForceColorsProperty: + def test_reset(self, cr): + """ + Setting force_colors to the same value resets the level styles to the + defaults. + """ + val = cr.force_colors + + cr._level_styles = {"info": "X", "error": "Y"} + + cr.force_colors = cr.force_colors + + assert val is cr.force_colors + assert ( + cr._level_styles + == dev.ConsoleRenderer.get_default_level_styles(colors=cr.colors) + ) + + def test_toggle_force_colors_updates_styles_and_levels(self): + """ + Setting force_colors to the same value resets the level styles to the + defaults. + """ + cr = dev.ConsoleRenderer(colors=True, force_colors=False) + + assert cr.force_colors is False + assert cr._force_colors is False + assert cr._styles is dev.ConsoleRenderer.get_default_column_styles( + colors=True, force_colors=False + ) + assert ( + cr._level_styles + == dev.ConsoleRenderer.get_default_level_styles(colors=True) + ) + + cr.force_colors = True + + assert cr.force_colors is True + assert cr._force_colors is True + assert cr._styles is dev.ConsoleRenderer.get_default_column_styles( + colors=True, force_colors=True + ) + assert ( + cr._level_styles + == dev.ConsoleRenderer.get_default_level_styles(colors=True) + ) + + def test_toggle_resets_custom_level_styles(self): + """ + Toggling force_colors resets the level styles to the defaults for the + new force_colors setting. + """ + custom = {"info": "X", "error": "Y"} + cr = dev.ConsoleRenderer(colors=True, level_styles=custom) + + assert custom == cr._level_styles + + cr.force_colors = True + assert ( + dev.ConsoleRenderer.get_default_level_styles(colors=True) + == cr._level_styles + ) + + cr.force_colors = False + assert ( + dev.ConsoleRenderer.get_default_level_styles(colors=True) + == cr._level_styles + ) From 9ac5612725c21ed7133d6a1d45a47c0002379d88 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 13 Oct 2025 11:17:28 +0200 Subject: [PATCH 1432/1520] dev: add level-styles properties --- CHANGELOG.md | 6 +----- docs/console-output.md | 12 +++++++++++- src/structlog/dev.py | 25 +++++++++++++++++++++++++ tests/test_dev.py | 30 ++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cee9d38..3d142e94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,13 +30,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ``` [#749](https://github.com/hynek/structlog/pull/749) -- Same for *sort_keys*. +- Same for *sort_keys*, *columns*, *colors*, *force_colors*, and *level_styles*. [#756](https://github.com/hynek/structlog/pull/756) - -- Same for *columns*. [#757](https://github.com/hynek/structlog/pull/757) - -- Same for *colors* and *force_colors*. [#759](https://github.com/hynek/structlog/pull/759) - Added `structlog.dev.ConsoleRenderer.get_default_column_styles` for reuse the default column styles. diff --git a/docs/console-output.md b/docs/console-output.md index d309e00b..de32f701 100644 --- a/docs/console-output.md +++ b/docs/console-output.md @@ -43,7 +43,17 @@ strict about immutability than the rest of *structlog* for better ergonomics. Notably, the currently active instance can be obtained by calling {meth}`ConsoleRenderer.get_active() ` and it offers properties to configure its behavior after instantiation. -Roughly speaking, there are two ways to configure the console output. + +:::{important} +Roughly speaking, there are two ways to configure console output. + +1. Using our defaults and tweak some settings. +2. Explicit columns configuration. + +You have to pick one and not mix the two. +For example, if you pass *columns* to {class}`~structlog.dev.ConsoleRenderer`, all other output-related parameters are ignored, but if you set one of the properties, the columns will be reconfigured accordingly and your columns settings will be lost. +::: + ### Defaults plus tweaking diff --git a/src/structlog/dev.py b/src/structlog/dev.py index a93bbb40..b4ee8477 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -1037,6 +1037,31 @@ def get_active(cls) -> ConsoleRenderer: return cr + @property + def level_styles(self) -> dict[str, str]: + """ + The level styles mapping for this console renderer. + + Setting this property will reset to defaults if set to None, otherwise + it applies the provided mapping. In all cases, columns are rebuilt to + reflect the change. + + .. versionadded:: 25.5.0 + """ + return self._level_styles + + @level_styles.setter + def level_styles(self, value: dict[str, str] | None) -> None: + """ + .. versionadded:: 25.5.0 + """ + self._level_styles = ( + self.get_default_level_styles(self._colors) + if value is None + else value + ) + self._configure_columns() + _SENTINEL = object() diff --git a/tests/test_dev.py b/tests/test_dev.py index 7c258dfe..6a52eec6 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -864,6 +864,36 @@ def test_no_style(self): ) +class TestConsoleRendererLevelStylesProperty: + def test_getter_setter_roundtrip(self): + """ + The level_styles property can be set and retrieved without + re-instantiating ConsoleRenderer. + """ + cr = dev.ConsoleRenderer(colors=True) + custom = {"info": "X", "error": "Y"} + + cr.level_styles = custom + + assert cr.level_styles is custom + assert cr._level_styles is custom + + @pytest.mark.parametrize("colors", [True, False]) + def test_set_none_resets_to_defaults(self, colors): + """ + Setting level_styles to None resets to defaults. + """ + cr = dev.ConsoleRenderer(colors=colors) + cr.level_styles = {"info": "X"} + + cr.level_styles = None + + assert ( + dev.ConsoleRenderer.get_default_level_styles(colors=colors) + == cr._level_styles + ) + + class TestGetActiveConsoleRenderer: def test_ok(self): """ From 567c4c133f44ebdaea24088223d410212dc7b6de Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 13 Oct 2025 15:00:26 +0200 Subject: [PATCH 1433/1520] docs --- docs/console-output.md | 12 +++++++----- src/structlog/dev.py | 1 + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/console-output.md b/docs/console-output.md index de32f701..8be4619c 100644 --- a/docs/console-output.md +++ b/docs/console-output.md @@ -50,21 +50,23 @@ Roughly speaking, there are two ways to configure console output. 1. Using our defaults and tweak some settings. 2. Explicit columns configuration. -You have to pick one and not mix the two. -For example, if you pass *columns* to {class}`~structlog.dev.ConsoleRenderer`, all other output-related parameters are ignored, but if you set one of the properties, the columns will be reconfigured accordingly and your columns settings will be lost. +You should pick one and not mix the two. +For example, if you pass *columns* to {class}`~structlog.dev.ConsoleRenderer`, all other output-related parameters are stored but otherwise ignored. +But if you set one of the non-*columns* properties, the columns will be reconfigured accordingly and *your* columns settings will be lost. ::: - ### Defaults plus tweaking The easier way where you're mostly using our defaults and just tweak a few things here and there by passing arguments or setting properties (as of 25.5.0). -For example, you can easily change the colors of the the log levels by passing the *level_styles* parameter or switch *colors* on and off completely. +For example, you can easily change the colors of the the log levels by passing the *level_styles*[^styles] parameter or switch *colors* on and off completely. -When the API talks about "styles", it means ANSI control strings. +[^styles]: When the API talks about "styles", it means ANSI control strings. You can find them, for example, in [Colorama](https://github.com/tartley/colorama). +You can find the relevant arguments and properties in the {class}`~structlog.dev.ConsoleRenderer` documentation. + ### Explicit columns configuration diff --git a/src/structlog/dev.py b/src/structlog/dev.py index b4ee8477..4d81071c 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -913,6 +913,7 @@ def sort_keys(self, value: bool) -> None: """ .. versionadded:: 25.5.0 """ + # _sort_keys is a format-time setting, so we can just set it directly. self._sort_keys = value @property From 90cd20308d45fefdb71dabce252b0477646416c6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 14 Oct 2025 06:20:18 +0200 Subject: [PATCH 1434/1520] Add AI statement --- .github/CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 7833d369..2d9104a2 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,8 +1,8 @@ # How To Contribute > [!IMPORTANT] -> This document is mainly to help you to get started by codifying tribal knowledge and expectations and make it more accessible to everyone. -> But don't be afraid to open half-finished PRs and ask questions if something is unclear! +> We do not care how you write your code, but you're taking full responsibility for it by submitting a pull request. +> Do not waste our time with LLM/"AI" slop that you don't understand yourself. ## Support @@ -21,7 +21,7 @@ It's people like *you* who make this project such a great tool for everyone. - No contribution is too small! Please submit as many fixes for typos and grammar bloopers as you can! -- Try to limit each pull request to *one* change only. +- Try to limit each pull request to *one* change only (except for typos -- please group those). - Since we squash on merge, it's up to you how you handle updates to the `main` branch. Whether you prefer to rebase on `main` or merge `main` into your branch, do whatever is more comfortable for you. From 52898bf892a889e67bce6960c5a73a8cc74dadf4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 14 Oct 2025 06:35:41 +0200 Subject: [PATCH 1435/1520] Expand API type-checking (#760) --- .github/workflows/ci.yml | 29 ++++------------------------- pyproject.toml | 6 ++++++ tox.ini | 24 +++++++++++++++--------- 3 files changed, 25 insertions(+), 34 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7df9f889..6a9d5f8c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -123,8 +123,8 @@ jobs: path: htmlcov if: ${{ failure() }} - mypy-pkg: - name: Mypy Codebase + typing: + name: Check types using supported type checkers runs-on: ubuntu-latest needs: build-package @@ -142,27 +142,7 @@ jobs: - run: > uvx --with tox-uv - tox run -e mypy-pkg - - pyright: - name: Pyright API - runs-on: ubuntu-latest - needs: build-package - steps: - - name: Download pre-built packages - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 - with: - name: Packages - path: dist - - run: tar xf dist/*.tar.gz --strip-components=1 - - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 - with: - python-version-file: .python-version-default - - uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817 # v2.3.0 - - - run: > - uvx --with tox-uv - tox run -e pyright + tox run -f typing docs: name: Run doctests @@ -222,8 +202,7 @@ jobs: needs: - coverage - install-dev - - mypy-pkg - - pyright + - typing - docs runs-on: ubuntu-latest diff --git a/pyproject.toml b/pyproject.toml index a6c43c41..2edaa2c3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -182,6 +182,12 @@ ignore_errors = true module = "tests.typing.*" ignore_errors = false +[tool.ty.src] +include = ["tests/typing"] + +[tool.pyrefly] +project-includes = ["tests/typing"] + [tool.hatch.metadata.hooks.fancy-pypi-readme] content-type = "text/markdown" diff --git a/tox.ini b/tox.ini index d4b99701..cd9c02df 100644 --- a/tox.ini +++ b/tox.ini @@ -2,9 +2,9 @@ min_version = 4 env_list = pre-commit, - mypy-pkg, py3{8,9,10,11,12,13,14}-{tests,mypy} py3{8,13}-tests-{colorama,be,rich}, + typing-{mypy,pyright,ty,pyrefly}, docs-{sponsors,build,doctests}, coverage-{combine,report} @@ -87,15 +87,21 @@ deps = prek commands = prek run --all-files -[testenv:mypy-pkg] -dependency_groups = typing -commands = mypy src - - -[testenv:pyright] -deps = pyright +[testenv:typing-{pyright,ty,mypy,pyrefly}] +description = Type-check the package. +# Keep base_python in-sync with .python-version-default +base_python = py313 dependency_groups = typing -commands = pyright tests/typing +deps = + pyrefly: pyrefly + pyright: pyright + ty: ty +commands = + # Mypy API checks need to happen per-Python version. + mypy: mypy src + pyrefly: pyrefly check + pyright: pyright tests/typing + ty: ty check [testenv:color-force] From 6c11ae9a650e36ae8e7fe128fba6a09a4ff95b48 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 14 Oct 2025 06:43:42 +0200 Subject: [PATCH 1436/1520] Add type assertions for ConsoleRenderer properties --- tests/typing/api.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/typing/api.py b/tests/typing/api.py index 08894ea7..2a409877 100644 --- a/tests/typing/api.py +++ b/tests/typing/api.py @@ -368,3 +368,31 @@ def typecheck_bound_logger_return() -> None: def f() -> None: with structlog.contextvars.bound_contextvars(y=23): pass + + +# ConsoleRenderer properties + +cr = structlog.dev.ConsoleRenderer.get_active() + +cr.exception_formatter +cr.exception_formatter = structlog.dev.plain_traceback +cr.exception_formatter = structlog.dev.better_traceback + +cr.columns +cr.columns = [ + structlog.dev.Column( + "", structlog.dev.KeyValueColumnFormatter("", "", "", repr, 0) + ) +] + +cr.colors +cr.colors = False + +cr.force_colors +cr.force_colors = False + +cr.level_styles +cr.level_styles = {"info": "foo"} + +cr.sort_keys +cr.sort_keys = True From bac52127fdbd903cf6f1fdf025aafc6458cf9f8d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 14 Oct 2025 06:58:18 +0200 Subject: [PATCH 1437/1520] dev: add pad_level property --- CHANGELOG.md | 2 +- src/structlog/dev.py | 20 ++++++++++ tests/test_dev.py | 88 +++++++++++++++++++++++++------------------- 3 files changed, 72 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d142e94..92d5cd5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,7 +30,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ``` [#749](https://github.com/hynek/structlog/pull/749) -- Same for *sort_keys*, *columns*, *colors*, *force_colors*, and *level_styles*. +- Same for *sort_keys*, *columns*, *colors*, *force_colors*, *level_styles*, and *pad_level*. [#756](https://github.com/hynek/structlog/pull/756) [#757](https://github.com/hynek/structlog/pull/757) [#759](https://github.com/hynek/structlog/pull/759) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 4d81071c..373add7f 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -1063,6 +1063,26 @@ def level_styles(self, value: dict[str, str] | None) -> None: ) self._configure_columns() + @property + def pad_level(self) -> bool: + """ + Whether to pad log level with blanks to the longest amongst all + level labels. + + Setting this will rebuild columns to reflect the change. + + .. versionadded:: 25.5.0 + """ + return self._pad_level + + @pad_level.setter + def pad_level(self, value: bool) -> None: + """ + .. versionadded:: 25.5.0 + """ + self._pad_level = value + self._configure_columns() + _SENTINEL = object() diff --git a/tests/test_dev.py b/tests/test_dev.py index 6a52eec6..948dad94 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -864,36 +864,6 @@ def test_no_style(self): ) -class TestConsoleRendererLevelStylesProperty: - def test_getter_setter_roundtrip(self): - """ - The level_styles property can be set and retrieved without - re-instantiating ConsoleRenderer. - """ - cr = dev.ConsoleRenderer(colors=True) - custom = {"info": "X", "error": "Y"} - - cr.level_styles = custom - - assert cr.level_styles is custom - assert cr._level_styles is custom - - @pytest.mark.parametrize("colors", [True, False]) - def test_set_none_resets_to_defaults(self, colors): - """ - Setting level_styles to None resets to defaults. - """ - cr = dev.ConsoleRenderer(colors=colors) - cr.level_styles = {"info": "X"} - - cr.level_styles = None - - assert ( - dev.ConsoleRenderer.get_default_level_styles(colors=colors) - == cr._level_styles - ) - - class TestGetActiveConsoleRenderer: def test_ok(self): """ @@ -931,8 +901,54 @@ def test_multiple_console_renderers(self): dev.ConsoleRenderer.get_active() -class TestConsoleRendererColorsProperty: - def test_reset(self, cr): +class TestConsoleRendererProperties: + def test_level_styles_roundtrip(self): + """ + The level_styles property can be set and retrieved. + """ + cr = dev.ConsoleRenderer(colors=True) + custom = {"info": "X", "error": "Y"} + + cr.level_styles = custom + + assert cr.level_styles is custom + assert cr._level_styles is custom + + @pytest.mark.parametrize("colors", [True, False]) + def test_set_level_styles_none_resets_to_defaults(self, colors): + """ + Setting level_styles to None resets to defaults. + """ + cr = dev.ConsoleRenderer(colors=colors) + cr.level_styles = {"info": "X"} + + cr.level_styles = None + + assert ( + dev.ConsoleRenderer.get_default_level_styles(colors=colors) + == cr._level_styles + ) + + def test_roundtrip_pad_level(self): + """ + The pad_level property can be set and retrieved. + """ + cr = dev.ConsoleRenderer(pad_level=True) + + assert cr.pad_level is True + assert cr._pad_level is True + + cr.pad_level = False + + assert cr.pad_level is False + assert cr._pad_level is False + + cr.pad_level = True + + assert cr.pad_level is True + assert cr._pad_level is True + + def test_same_value_resets_level_styles(self, cr): """ Setting colors to the same value resets the level styles to the defaults. @@ -980,7 +996,7 @@ def test_toggle_colors_updates_styles_and_levels(self): dev._IS_WINDOWS and dev.colorama is None, reason="Toggling colors=True requires colorama on Windows", ) - def test_toggle_resets_custom_level_styles(self): + def test_toggle_colors_resets_custom_level_styles(self): """ Toggling colors resets the level styles to the defaults for the new color setting. @@ -1003,9 +1019,7 @@ def test_toggle_resets_custom_level_styles(self): == cr._level_styles ) - -class TestConsoleRendererForceColorsProperty: - def test_reset(self, cr): + def test_same_force_colors_value_resets_level_styles(self, cr): """ Setting force_colors to the same value resets the level styles to the defaults. @@ -1051,7 +1065,7 @@ def test_toggle_force_colors_updates_styles_and_levels(self): == dev.ConsoleRenderer.get_default_level_styles(colors=True) ) - def test_toggle_resets_custom_level_styles(self): + def test_toggle_force_colors_resets_custom_level_styles(self): """ Toggling force_colors resets the level styles to the defaults for the new force_colors setting. From 8b3b2703edfe92ec3afa758beb1d386bf57373f7 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 14 Oct 2025 07:57:14 +0200 Subject: [PATCH 1438/1520] dev: add pad_event_to property, rename argument It's confusing to have a bool pad_level and an int pad_event. Keep it at first position such that positional uses aren't affected. --- src/structlog/dev.py | 42 +++++++++++++++++++++++++++++++++++----- tests/test_dev.py | 46 ++++++++++++++++++++++++++++++++++++++++---- tests/typing/api.py | 6 ++++++ 3 files changed, 85 insertions(+), 9 deletions(-) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 373add7f..e1095f33 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -630,7 +630,7 @@ class ConsoleRenderer: def __init__( self, - pad_event: int = _EVENT_WIDTH, + pad_event_to: int = _EVENT_WIDTH, colors: bool = _has_colors, force_colors: bool = False, repr_native_str: bool = False, @@ -641,7 +641,20 @@ def __init__( timestamp_key: str = "timestamp", columns: list[Column] | None = None, pad_level: bool = True, + pad_event: int | None = None, ): + if pad_event is not None: + if pad_event_to != _EVENT_WIDTH: + raise ValueError( + "Cannot set both `pad_event` and `pad_event_to`." + ) + warnings.warn( + "The `pad_event` argument is deprecated. Use `pad_event_to` instead.", + DeprecationWarning, + stacklevel=2, + ) + pad_event_to = pad_event + # Store all settings in case the user later switches from columns to # defaults. self.exception_formatter = exception_formatter @@ -655,7 +668,7 @@ def __init__( if level_styles is None else level_styles ) - self._pad_event = pad_event + self._pad_event_to = pad_event_to self._timestamp_key = timestamp_key self._event_key = event_key self._pad_level = pad_level @@ -673,8 +686,8 @@ def add_meaningless_arg(arg: str) -> None: f"The `{arg}` argument is ignored when passing `columns`.", ) - if pad_event != _EVENT_WIDTH: - add_meaningless_arg("pad_event") + if pad_event_to != _EVENT_WIDTH: + add_meaningless_arg("pad_event_to") if colors != _has_colors: add_meaningless_arg("colors") @@ -791,7 +804,7 @@ def _configure_columns(self) -> None: value_style=self._styles.bright, reset_style=self._styles.reset, value_repr=str, - width=self._pad_event, + width=self._pad_event_to, ), ), Column("logger", logger_name_formatter), @@ -1083,6 +1096,25 @@ def pad_level(self, value: bool) -> None: self._pad_level = value self._configure_columns() + @property + def pad_event_to(self) -> int: + """ + The number of characters to pad the event to. + + Setting this will rebuild columns to reflect the change. + + .. versionadded:: 25.5.0 + """ + return self._pad_event_to + + @pad_event_to.setter + def pad_event_to(self, value: int) -> None: + """ + .. versionadded:: 25.5.0 + """ + self._pad_event_to = value + self._configure_columns() + _SENTINEL = object() diff --git a/tests/test_dev.py b/tests/test_dev.py index 948dad94..9085481d 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -409,9 +409,9 @@ def test_exc_info_exception(self, cr, styles, padded): assert (f"{padded}\n" + exc) == rv - def test_pad_event_param(self, styles): + def test_pad_event_to_param(self, styles): """ - `pad_event` parameter works. + `pad_event_to` parameter works. """ rv = dev.ConsoleRenderer(42, dev._has_colors)( None, None, {"event": "test", "foo": "bar"} @@ -609,7 +609,7 @@ def test_columns_warns_about_meaningless_arguments(self, recwarn): """ dev.ConsoleRenderer( columns=[dev.Column("", lambda k, v: "")], - pad_event=42, + pad_event_to=42, colors=not dev._has_colors, force_colors=True, repr_native_str=True, @@ -621,7 +621,7 @@ def test_columns_warns_about_meaningless_arguments(self, recwarn): assert { f"The `{arg}` argument is ignored when passing `columns`." for arg in ( - "pad_event", + "pad_event_to", "colors", "force_colors", "repr_native_str", @@ -948,6 +948,44 @@ def test_roundtrip_pad_level(self): assert cr.pad_level is True assert cr._pad_level is True + def test_roundtrip_pad_event_to(self): + """ + The pad_event_to property can be set and retrieved. + """ + cr = dev.ConsoleRenderer() + + assert cr.pad_event_to == dev._EVENT_WIDTH + assert cr._pad_event_to == dev._EVENT_WIDTH + + cr.pad_event_to = 50 + + assert cr.pad_event_to == 50 + assert cr._pad_event_to == 50 + + cr.pad_event_to = 20 + + assert cr.pad_event_to == 20 + assert cr._pad_event_to == 20 + + def test_pad_event_deprecation_warning(self, recwarn): + """ + Using pad_event argument raises a deprecation warning. + """ + dev.ConsoleRenderer(pad_event=42) + + (w,) = recwarn.list + assert ( + "The `pad_event` argument is deprecated. Use `pad_event_to` instead." + ) == w.message.args[0] + assert w.category is DeprecationWarning + + def test_pad_event_to_param_raises_value_error(self): + """ + Using pad_event_to and pad_event raises a ValueError. + """ + with pytest.raises(ValueError): # noqa: PT011 + dev.ConsoleRenderer(pad_event_to=42, pad_event=42) + def test_same_value_resets_level_styles(self, cr): """ Setting colors to the same value resets the level styles to the diff --git a/tests/typing/api.py b/tests/typing/api.py index 2a409877..a0b0920c 100644 --- a/tests/typing/api.py +++ b/tests/typing/api.py @@ -396,3 +396,9 @@ def f() -> None: cr.sort_keys cr.sort_keys = True + +cr.pad_level +cr.pad_level = True + +cr.pad_event_to +cr.pad_event_to = 42 From 95f6ce39ac8f9944d1fd2860394aa13d5502d816 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 14 Oct 2025 08:00:08 +0200 Subject: [PATCH 1439/1520] docs --- CHANGELOG.md | 9 ++++++++- src/structlog/dev.py | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92d5cd5f..ada1d692 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,12 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ## [Unreleased](https://github.com/hynek/structlog/compare/25.4.0...HEAD) +### Deprecated + +- `structlog.dev.ConsoleRenderer()` *pad_event* argument has been renamed to *pad_event_to* to differentiate it from the boolean *pad_level* argument. + *pad_event* is now deprecated. + + ### Added - Added `structlog.dev.ConsoleRenderer.get_active()` that returns the currently active `structlog.dev.ConsoleRenderer()`. @@ -30,7 +36,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ``` [#749](https://github.com/hynek/structlog/pull/749) -- Same for *sort_keys*, *columns*, *colors*, *force_colors*, *level_styles*, and *pad_level*. +- Same for *sort_keys*, *columns*, *colors*, *force_colors*, *level_styles*, *pad_event_to*, and *pad_level*. [#756](https://github.com/hynek/structlog/pull/756) [#757](https://github.com/hynek/structlog/pull/757) [#759](https://github.com/hynek/structlog/pull/759) @@ -56,6 +62,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - `structlog.dev.rich_traceback()` now throws a more helpful error when Rich is missing. [#735](https://github.com/hynek/structlog/pull/735) + ### Fixed - `structlog.processors.MaybeTimeStamper` now respects the *key* argument when determining whether to overwrite the timestamp field. diff --git a/src/structlog/dev.py b/src/structlog/dev.py index e1095f33..6fc7082c 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -533,7 +533,7 @@ class ConsoleRenderer: .. seealso:: `columns-config` - pad_event: + pad_event_to: Pad the event to this many characters. Ignored if *columns* are passed. From 59e5a7702d5c58db0de4912db2d6aae52be53016 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 14 Oct 2025 08:00:33 +0200 Subject: [PATCH 1440/1520] grammar --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ada1d692..92e3362f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ### Deprecated -- `structlog.dev.ConsoleRenderer()` *pad_event* argument has been renamed to *pad_event_to* to differentiate it from the boolean *pad_level* argument. +- `structlog.dev.ConsoleRenderer()`'s *pad_event* argument has been renamed to *pad_event_to* to differentiate it from the boolean *pad_level* argument. *pad_event* is now deprecated. From f2992eae0359a7cff0fb97a5b27aa9b3fef96678 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 14 Oct 2025 08:01:39 +0200 Subject: [PATCH 1441/1520] Markup --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92e3362f..02218ebe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,7 +68,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - `structlog.processors.MaybeTimeStamper` now respects the *key* argument when determining whether to overwrite the timestamp field. [#747](https://github.com/hynek/structlog/pull/747) -- `structlog.tracebacks.extract()` no longer raises a *RecursionError* when the cause chain of an exception contains itself. +- `structlog.tracebacks.extract()` no longer raises a `RecursionError` when the cause chain of an exception contains itself. [#739](https://github.com/hynek/structlog/pull/739) - Default config now respects `FORCE_COLOR` on Windows. From ad85c52da62197a6ab965baa724a3f348f95b7d5 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 14 Oct 2025 08:34:38 +0200 Subject: [PATCH 1442/1520] dev: add event_key and timestamp_key properties --- CHANGELOG.md | 5 +++-- src/structlog/dev.py | 38 ++++++++++++++++++++++++++++++++++++++ tests/test_dev.py | 37 +++++++++++++++++++++++++++++++++++++ tests/typing/api.py | 6 ++++++ 4 files changed, 84 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02218ebe..f7bfb10e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,9 +34,10 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ cr = structlog.dev.ConsoleRenderer.get_active() cr.exception_formatter = structlog.dev.plain_traceback ``` - [#749](https://github.com/hynek/structlog/pull/749) -- Same for *sort_keys*, *columns*, *colors*, *force_colors*, *level_styles*, *pad_event_to*, and *pad_level*. + Same goes for *sort_keys*, *columns*, *colors*, *force_colors*, *level_styles*, *pad_event_to*, *event_key*, and *timestamp_key*. + + [#749](https://github.com/hynek/structlog/pull/749) [#756](https://github.com/hynek/structlog/pull/756) [#757](https://github.com/hynek/structlog/pull/757) [#759](https://github.com/hynek/structlog/pull/759) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 6fc7082c..0bcddb89 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -1115,6 +1115,44 @@ def pad_event_to(self, value: int) -> None: self._pad_event_to = value self._configure_columns() + @property + def event_key(self) -> str: + """ + The key to look for the main log message. + + Setting this will rebuild columns to reflect the change. + + .. versionadded:: 25.5.0 + """ + return self._event_key + + @event_key.setter + def event_key(self, value: str) -> None: + """ + .. versionadded:: 25.5.0 + """ + self._event_key = value + self._configure_columns() + + @property + def timestamp_key(self) -> str: + """ + The key to look for the timestamp of the log message. + + Setting this will rebuild columns to reflect the change. + + .. versionadded:: 25.5.0 + """ + return self._timestamp_key + + @timestamp_key.setter + def timestamp_key(self, value: str) -> None: + """ + .. versionadded:: 25.5.0 + """ + self._timestamp_key = value + self._configure_columns() + _SENTINEL = object() diff --git a/tests/test_dev.py b/tests/test_dev.py index 9085481d..1dd777d1 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -116,6 +116,43 @@ def test_timestamp_renamed(self): ).rstrip() ) + def test_event_key_property(self): + """ + The event_key property can be set and retrieved. + """ + cr = dev.ConsoleRenderer(colors=False) + + assert cr.event_key == "event" + + cr.event_key = "msg" + + assert cr.event_key == "msg" + assert "new event name event='something custom'" == cr( + None, + None, + {"msg": "new event name", "event": "something custom"}, + ) + + def test_timestamp_key_property(self): + """ + The timestamp_key property can be set and retrieved. + """ + cr = dev.ConsoleRenderer(colors=False) + + assert cr.timestamp_key == "timestamp" + + cr.timestamp_key = "ts" + + assert cr.timestamp_key == "ts" + assert ( + "2023-09-07 le event" + == cr( + None, + None, + {"ts": "2023-09-07", "event": "le event"}, + ).rstrip() + ) + def test_level(self, cr, styles, padded): """ Levels are rendered aligned, in square brackets, and color-coded. diff --git a/tests/typing/api.py b/tests/typing/api.py index a0b0920c..546d3e62 100644 --- a/tests/typing/api.py +++ b/tests/typing/api.py @@ -402,3 +402,9 @@ def f() -> None: cr.pad_event_to cr.pad_event_to = 42 + +cr.timestamp_key +cr.timestamp_key = "ts" + +cr.event_key +cr.event_key = "le event" From af571c8aecb3a3a31d3052a388d8c95e44b9fd96 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 14 Oct 2025 08:51:38 +0200 Subject: [PATCH 1443/1520] dev: add repr_native_str property --- docs/api.rst | 2 +- src/structlog/dev.py | 142 ++++++++++++++++++++++++------------------- tests/test_dev.py | 17 ++++++ tests/typing/api.py | 3 + 4 files changed, 100 insertions(+), 64 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 39ed731b..2c16414f 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -76,7 +76,7 @@ API Reference .. automodule:: structlog.dev .. autoclass:: ConsoleRenderer - :members: get_default_level_styles, get_default_column_styles, exception_formatter, sort_keys, columns, get_active + :members: get_default_level_styles, get_default_column_styles, exception_formatter, sort_keys, columns, get_active, event_key, timestamp_key, level_styles,colors, force_colors, repr_native_str, pad_level, pad_event_to .. autoclass:: ColumnStyles diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 0bcddb89..7a98024f 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -710,6 +710,38 @@ def add_meaningless_arg(arg: str) -> None: for w in to_warn: warnings.warn(w, stacklevel=2) + @classmethod + def get_active(cls) -> ConsoleRenderer: + """ + If *structlog* is configured to use `ConsoleRenderer`, it's returned. + + It does not have to be the last processor. + + Raises: + NoConsoleRendererConfiguredError: + If no ConsoleRenderer is found in the current configuration. + + MultipleConsoleRenderersConfiguredError: + If more than one is found in the current configuration. This is + almost certainly a bug. + + .. versionadded:: 25.5.0 + """ + from ._config import get_config + + cr = None + for p in get_config()["processors"]: + if isinstance(p, ConsoleRenderer): + if cr is not None: + raise MultipleConsoleRenderersConfiguredError + + cr = p + + if cr is None: + raise NoConsoleRendererConfiguredError + + return cr + @classmethod def get_default_column_styles( cls, colors: bool, force_colors: bool = False @@ -744,6 +776,37 @@ def get_default_column_styles( return _colorful_styles + @staticmethod + def get_default_level_styles(colors: bool = True) -> dict[str, str]: + """ + Get the default styles for log levels + + This is intended to be used with `ConsoleRenderer`'s ``level_styles`` + parameter. For example, if you are adding custom levels in your + home-grown :func:`~structlog.stdlib.add_log_level` you could do:: + + my_styles = ConsoleRenderer.get_default_level_styles() + my_styles["EVERYTHING_IS_ON_FIRE"] = my_styles["critical"] + renderer = ConsoleRenderer(level_styles=my_styles) + + Args: + colors: + Whether to use colorful styles. This must match the *colors* + parameter to `ConsoleRenderer`. Default: `True`. + """ + styles: ColumnStyles + styles = _colorful_styles if colors else _plain_styles + return { + "critical": styles.level_critical, + "exception": styles.level_exception, + "error": styles.level_error, + "warn": styles.level_warn, + "warning": styles.level_warn, + "info": styles.level_info, + "debug": styles.level_debug, + "notset": styles.level_notset, + } + def _configure_columns(self) -> None: """ Re-configure self._columns and self._default_column_formatter @@ -865,37 +928,6 @@ def __call__( return sio.getvalue() - @staticmethod - def get_default_level_styles(colors: bool = True) -> dict[str, str]: - """ - Get the default styles for log levels - - This is intended to be used with `ConsoleRenderer`'s ``level_styles`` - parameter. For example, if you are adding custom levels in your - home-grown :func:`~structlog.stdlib.add_log_level` you could do:: - - my_styles = ConsoleRenderer.get_default_level_styles() - my_styles["EVERYTHING_IS_ON_FIRE"] = my_styles["critical"] - renderer = ConsoleRenderer(level_styles=my_styles) - - Args: - colors: - Whether to use colorful styles. This must match the *colors* - parameter to `ConsoleRenderer`. Default: `True`. - """ - styles: ColumnStyles - styles = _colorful_styles if colors else _plain_styles - return { - "critical": styles.level_critical, - "exception": styles.level_exception, - "error": styles.level_error, - "warn": styles.level_warn, - "warning": styles.level_warn, - "info": styles.level_info, - "debug": styles.level_debug, - "notset": styles.level_notset, - } - @property def exception_formatter(self) -> ExceptionRenderer: """ @@ -1019,38 +1051,6 @@ def force_colors(self, value: bool) -> None: self._configure_columns() - @classmethod - def get_active(cls) -> ConsoleRenderer: - """ - If *structlog* is configured to use `ConsoleRenderer`, it's returned. - - It does not have to be the last processor. - - Raises: - NoConsoleRendererConfiguredError: - If no ConsoleRenderer is found in the current configuration. - - MultipleConsoleRenderersConfiguredError: - If more than one is found in the current configuration. This is - almost certainly a bug. - - .. versionadded:: 25.5.0 - """ - from ._config import get_config - - cr = None - for p in get_config()["processors"]: - if isinstance(p, ConsoleRenderer): - if cr is not None: - raise MultipleConsoleRenderersConfiguredError - - cr = p - - if cr is None: - raise NoConsoleRendererConfiguredError - - return cr - @property def level_styles(self) -> dict[str, str]: """ @@ -1153,6 +1153,22 @@ def timestamp_key(self, value: str) -> None: self._timestamp_key = value self._configure_columns() + @property + def repr_native_str(self) -> bool: + """ + Whether native strings are passed through repr() in non-event values. + + .. versionadded:: 25.5.0 + """ + return self._repr_native_str + + @repr_native_str.setter + def repr_native_str(self, value: bool) -> None: + """ + .. versionadded:: 25.5.0 + """ + self._repr_native_str = value + _SENTINEL = object() diff --git a/tests/test_dev.py b/tests/test_dev.py index 1dd777d1..11055f64 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -1004,6 +1004,23 @@ def test_roundtrip_pad_event_to(self): assert cr.pad_event_to == 20 assert cr._pad_event_to == 20 + def test_repr_native_str_property(self, cr): + """ + The repr_native_str property can be set and retrieved, and affects formatting. + """ + cr = dev.ConsoleRenderer(colors=False, repr_native_str=False) + + assert False is cr.repr_native_str + assert "event key=plain" == cr( + None, None, {"event": "event", "key": "plain"} + ) + + cr.repr_native_str = True + + assert "event key='plain'" == cr( + None, None, {"event": "event", "key": "plain"} + ) + def test_pad_event_deprecation_warning(self, recwarn): """ Using pad_event argument raises a deprecation warning. diff --git a/tests/typing/api.py b/tests/typing/api.py index 546d3e62..8d850e06 100644 --- a/tests/typing/api.py +++ b/tests/typing/api.py @@ -408,3 +408,6 @@ def f() -> None: cr.event_key cr.event_key = "le event" + +cr.repr_native_str +cr.repr_native_str = True From 80023700607ab8f0130a18476c5a44e5d5b23dd1 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 14 Oct 2025 08:53:00 +0200 Subject: [PATCH 1444/1520] cl --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7bfb10e..768a9a54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,7 +35,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ cr.exception_formatter = structlog.dev.plain_traceback ``` - Same goes for *sort_keys*, *columns*, *colors*, *force_colors*, *level_styles*, *pad_event_to*, *event_key*, and *timestamp_key*. + Same goes for *sort_keys*, *columns*, *colors*, *force_colors*, *level_styles*, *pad_event_to*, *event_key*, *timestamp_key*, and *repr_native_str*. [#749](https://github.com/hynek/structlog/pull/749) [#756](https://github.com/hynek/structlog/pull/756) From ee29b71b6d589ee258b7ecaaf4afe41b867c6756 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 14 Oct 2025 09:32:56 +0200 Subject: [PATCH 1445/1520] Update demo screenshot --- docs/_static/console_renderer.png | Bin 253716 -> 353918 bytes show_off.py | 7 +++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/_static/console_renderer.png b/docs/_static/console_renderer.png index df8e503d40c208856076cbdc904248c0713e0fdf..fcc0a9356a4e79517bedb6381158f6a0866703c7 100644 GIT binary patch literal 353918 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�B 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 z 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 literal 253716 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%0A;^bx#j%Os@qHj*nb%&0Rvp3>~R~O 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

    FRVNH3=;KqvzMhKxUkR5+*kb_QtY8Dg|aPO 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

    X6s_54d1{Iudd^vSXB%~nntv9iLL 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≠jS_?GL48*91rfu?1Qdv3etO+r~zGKmRYPyElK_V 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 o`7!q5PnEwUB7ULvOXA-i)kYuVrbFF_(NuK)l5 diff --git a/show_off.py b/show_off.py index f1e5e1ea..667fd98f 100644 --- a/show_off.py +++ b/show_off.py @@ -25,9 +25,12 @@ class SomeClass: log.warning("uh-uh!") log.error("omg", a_dict={"a": 42, "b": "foo"}) log.critical("wtf", what=SomeClass(x=1, y="z")) -structlog.dev.ConsoleRenderer.get_active().colors = False + +# Demonstrate writable properties +cr = structlog.dev.ConsoleRenderer.get_active() +cr.colors = False log.info("where are the colors!?", colors="gone") -structlog.dev.ConsoleRenderer.get_active().colors = True +cr.colors = True log.info("there they are!", colors="back") From 141c15ddacc5db55bc734139892f538b7e80536a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 14 Oct 2025 09:44:41 +0200 Subject: [PATCH 1446/1520] Remove broken link --- docs/thread-local.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/thread-local.md b/docs/thread-local.md index 2bd73adf..2aa12a0a 100644 --- a/docs/thread-local.md +++ b/docs/thread-local.md @@ -46,7 +46,7 @@ These functions map 1:1 to the {doc}`contextvars` APIs, so please use those inst ## Thread-local contexts -*structlog* also provides thread-local context storage in a form that you may already know from [*Flask*](https://flask.palletsprojects.com/en/latest/design/#thread-locals) and that makes the *entire context* global to your thread or greenlet. +*structlog* also provides thread-local context storage in a form that you may already know from Flask and that makes the *entire context* global to your thread or greenlet. This makes its behavior more difficult to reason about which is why we generally recommend to use the {func}`~structlog.contextvars.merge_contextvars` route. Therefore, there are currently no plans to re-implement this behavior on top of context variables. From bef0e257b46b0fbc841459387014e82fafec79b4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 14 Oct 2025 09:45:31 +0200 Subject: [PATCH 1447/1520] Update FastAPI URL --- docs/contextvars.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contextvars.md b/docs/contextvars.md index ca8daf2f..caabc257 100644 --- a/docs/contextvars.md +++ b/docs/contextvars.md @@ -22,7 +22,7 @@ This context is safe to be used both in threaded as well as asynchronous code. :::{warning} Since the storage mechanics of your context variables is different for each concurrency method, they are _isolated_ from each other. -This can be a problem in hybrid applications like those based on [Starlette](https://www.starlette.io) (this [includes FastAPI](https://github.com/tiangolo/fastapi/discussions/5999)) where context variables set in a synchronous context don't appear in logs from an async context and vice versa. +This can be a problem in hybrid applications like those based on [Starlette](https://www.starlette.io) (this [includes FastAPI](https://github.com/fastapi/fastapi/discussions/5999)) where context variables set in a synchronous context don't appear in logs from an async context and vice versa. ::: The general flow is: From cb4ddda7edde0d1593fb133be6e32043716976dd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 15 Oct 2025 09:49:25 +0200 Subject: [PATCH 1448/1520] Add thanks.dev --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index fd64f81f..03065f57 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,3 +1,4 @@ --- github: hynek tidelift: pypi/structlog +thanks_dev: u/gh/hynek From f002806241bbb5e6cae4d69681738afda4cac0d4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 15 Oct 2025 09:49:56 +0200 Subject: [PATCH 1449/1520] Custom, too --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 03065f57..1c95cd4f 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -2,3 +2,4 @@ github: hynek tidelift: pypi/structlog thanks_dev: u/gh/hynek +custom: https://hynek.me/say-thanks/ From 005ce7301e6ab088b788a1aaa931e99940a020f8 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 16 Oct 2025 07:04:27 +0200 Subject: [PATCH 1450/1520] Add CallsiteParameter.QUAL_NAME (#761) * Add CallsiteParameter.QUAL_NAME Fixes #386 * Get rid of gunk * Make it truly 3.11-only * Streamline * Terse --- CHANGELOG.md | 3 ++ src/structlog/processors.py | 24 ++++++++++--- tests/processors/test_processors.py | 55 +++++++++++++++++++++++++++-- 3 files changed, 75 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 768a9a54..42e0177b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,6 +57,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - Native loggers now allow the passing of a dictionary for dictionary-based interpolation `log.info("hello %(name)s!", {"name": "world"})`. [#748](https://github.com/hynek/structlog/pull/748) +- On Python 3.11+, `structlog.processors.CallsiteParameterAdder` now supports `CallsiteParameter.QUAL_NAME` that adds the qualified name of the callsite, including scope and class names. + This is only available for *structlog*-originated events since the standard library has no equivalent. + ### Changed diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 804b8d0d..496883d6 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -729,6 +729,9 @@ class CallsiteParameter(enum.Enum): the callsite parameters in the event dictionary. .. versionadded:: 21.5.0 + + .. versionadded:: 25.5.0 + `QUAL_NAME` parameter. """ #: The full path to the python source file of the callsite. @@ -742,6 +745,9 @@ class CallsiteParameter(enum.Enum): MODULE = "module" #: The name of the function that the callsite was in. FUNC_NAME = "func_name" + #: The qualified name of the callsite (includes scope and class names). + #: Requires Python 3.11+. + QUAL_NAME = "qual_name" #: The line number of the callsite. LINENO = "lineno" #: The ID of the thread the callsite was executed in. @@ -770,6 +776,10 @@ def _get_callsite_func_name(module: str, frame: FrameType) -> Any: return frame.f_code.co_name +def _get_callsite_qual_name(module: str, frame: FrameType) -> Any: + return frame.f_code.co_qualname # will crash on Python <3.11 + + def _get_callsite_lineno(module: str, frame: FrameType) -> Any: return frame.f_lineno @@ -837,6 +847,7 @@ class CallsiteParameterAdder: CallsiteParameter.FILENAME: _get_callsite_filename, CallsiteParameter.MODULE: _get_callsite_module, CallsiteParameter.FUNC_NAME: _get_callsite_func_name, + CallsiteParameter.QUAL_NAME: _get_callsite_qual_name, CallsiteParameter.LINENO: _get_callsite_lineno, CallsiteParameter.THREAD: _get_callsite_thread, CallsiteParameter.THREAD_NAME: _get_callsite_thread_name, @@ -882,12 +893,15 @@ def __init__( self._active_handlers.append( (parameter, self._handlers[parameter]) ) - self._record_mappings.append( - self._RecordMapping( - parameter.value, - self._record_attribute_map[parameter], + if ( + record_attr := self._record_attribute_map.get(parameter) + ) is not None: + self._record_mappings.append( + self._RecordMapping( + parameter.value, + record_attr, + ) ) - ) def __call__( self, logger: logging.Logger, name: str, event_dict: EventDict diff --git a/tests/processors/test_processors.py b/tests/processors/test_processors.py index 13f4478d..e43485e1 100644 --- a/tests/processors/test_processors.py +++ b/tests/processors/test_processors.py @@ -303,7 +303,13 @@ class TestCallsiteParameterAdder: "process_name", } - _all_parameters = set(CallsiteParameter) + # Exclude QUAL_NAME from the general set to keep parity with stdlib + # LogRecord-derived parameters. QUAL_NAME is tested separately. + _all_parameters = { + p + for p in set(CallsiteParameter) + if p is not CallsiteParameter.QUAL_NAME + } def test_all_parameters(self) -> None: """ @@ -317,6 +323,50 @@ def test_all_parameters(self) -> None: } assert self.parameter_strings == self.get_callsite_parameters().keys() + @pytest.mark.skipif( + sys.version_info < (3, 11), reason="QUAL_NAME requires Python 3.11+" + ) + def test_qual_name_structlog(self) -> None: + """ + QUAL_NAME is added for structlog-originated events on Python 3.11+. + """ + processor = CallsiteParameterAdder( + parameters={CallsiteParameter.QUAL_NAME} + ) + event_dict: EventDict = {"event": "msg"} + actual = processor(None, None, event_dict) + + assert actual["qual_name"].endswith( + f"{self.__class__.__name__}.test_qual_name_structlog" + ) + + def test_qual_name_logging_origin_absent(self) -> None: + """ + QUAL_NAME is not sourced from stdlib LogRecord and remains absent + (because it doesn't exist). + """ + processor = CallsiteParameterAdder( + parameters={CallsiteParameter.QUAL_NAME} + ) + record = logging.LogRecord( + "name", + logging.INFO, + __file__, + 0, + "message", + None, + None, + "func", + ) + event_dict: EventDict = { + "event": "message", + "_record": record, + "_from_structlog": False, + } + actual = processor(None, None, event_dict) + + assert "qual_name" not in actual + @pytest.mark.asyncio @pytest.mark.parametrize( ("wrapper_class", "method_name"), @@ -550,7 +600,8 @@ def make_processor( """ if parameter_strings is None: return CallsiteParameterAdder( - additional_ignores=additional_ignores + parameters=cls._all_parameters, + additional_ignores=additional_ignores, ) parameters = cls.filter_parameters(parameter_strings) From d4bb98ce2ff0ad1cba904345ab7642b689fe90c2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 16 Oct 2025 07:07:27 +0200 Subject: [PATCH 1451/1520] Make Dr. Zizmor happy --- .github/dependabot.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index b339aaeb..201f28e7 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,6 +5,8 @@ updates: directory: / schedule: interval: monthly + cooldown: + default-days: 4 groups: github-actions: patterns: From a786cc0d91eb4c8362109a8b867dc69cb9c2287d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 16 Oct 2025 07:29:45 +0200 Subject: [PATCH 1452/1520] Add explanation --- src/structlog/processors.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 496883d6..2235f2cb 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -843,6 +843,7 @@ class CallsiteParameterAdder: _handlers: ClassVar[ dict[CallsiteParameter, Callable[[str, FrameType], Any]] ] = { + # We can't use lambda functions here because they are not pickleable. CallsiteParameter.PATHNAME: _get_callsite_pathname, CallsiteParameter.FILENAME: _get_callsite_filename, CallsiteParameter.MODULE: _get_callsite_module, From c16c2ea714cac5df3c139676121e5fdf3a2f3f37 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 16 Oct 2025 07:48:32 +0200 Subject: [PATCH 1453/1520] Clarify callsite flow --- src/structlog/processors.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 2235f2cb..4248648e 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -908,7 +908,8 @@ def __call__( self, logger: logging.Logger, name: str, event_dict: EventDict ) -> EventDict: record: logging.LogRecord | None = event_dict.get("_record") - from_structlog: bool | None = event_dict.get("_from_structlog") + from_structlog: bool = event_dict.get("_from_structlog", False) + # If the event dictionary has a record, but it comes from structlog, # then the callsite parameters of the record will not be correct. if record is not None and not from_structlog: @@ -916,12 +917,15 @@ def __call__( event_dict[mapping.event_dict_key] = record.__dict__[ mapping.record_attribute ] - else: - frame, module = _find_first_app_frame_and_name( - additional_ignores=self._additional_ignores - ) - for parameter, handler in self._active_handlers: - event_dict[parameter.value] = handler(module, frame) + + return event_dict + + frame, module = _find_first_app_frame_and_name( + additional_ignores=self._additional_ignores + ) + for parameter, handler in self._active_handlers: + event_dict[parameter.value] = handler(module, frame) + return event_dict From 98a27a47ff1b0c276918dcd3320cbb35e314e842 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 18 Oct 2025 12:01:03 +0200 Subject: [PATCH 1454/1520] update dev --- .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/zizmor.yml | 2 +- .pre-commit-config.yaml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index e9bd115b..b4e51706 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -29,12 +29,12 @@ jobs: persist-credentials: false - name: Initialize CodeQL - uses: github/codeql-action/init@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8 + uses: github/codeql-action/init@16140ae1a102900babc80a33c44059580f687047 # v4.30.9 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8 + uses: github/codeql-action/autobuild@16140ae1a102900babc80a33c44059580f687047 # v4.30.9 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8 + uses: github/codeql-action/analyze@16140ae1a102900babc80a33c44059580f687047 # v4.30.9 diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index 932b465d..7ac6c10e 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -30,7 +30,7 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload SARIF file - uses: github/codeql-action/upload-sarif@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8 + uses: github/codeql-action/upload-sarif@16140ae1a102900babc80a33c44059580f687047 # v4.30.9 with: # Path to SARIF file relative to the root of the repository sarif_file: results.sarif diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3dd4f673..57a45e71 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.14.0 + rev: v0.14.1 hooks: - id: ruff-check args: [--fix, --exit-non-zero-on-fix] From c102862e3f30de84c898c4501418dede15056c6d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 23 Oct 2025 17:27:53 +0200 Subject: [PATCH 1455/1520] docs: bigger font --- docs/_static/custom.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/_static/custom.css b/docs/_static/custom.css index 564f3d08..c42aa542 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -8,3 +8,9 @@ --pst-font-family-heading: "Atkinson Hyperlegible", system-ui, sans-serif; --pst-font-family-monospace: BerkeleyMono, ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace; } + +/* Override theme's font-size-base with higher specificity */ +html[data-theme=light], +html[data-theme=dark] { + --pst-font-size-base: 1.1rem; +} From 5acfc85e3c3fa821dc65b55a226900d40dc0831c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 24 Oct 2025 07:13:03 +0200 Subject: [PATCH 1456/1520] docs: 5% bigger still --- docs/_static/custom.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_static/custom.css b/docs/_static/custom.css index c42aa542..4c10c35d 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -12,5 +12,5 @@ /* Override theme's font-size-base with higher specificity */ html[data-theme=light], html[data-theme=dark] { - --pst-font-size-base: 1.1rem; + --pst-font-size-base: 1.15rem; } From 7f7a221aed6bbff3c13cefd7effe14cc4f0cfc24 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 25 Oct 2025 13:00:50 +0200 Subject: [PATCH 1457/1520] update dev (#765) --- .github/workflows/build-docset.yml | 2 +- .github/workflows/ci.yml | 12 ++++++------ .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/pypi-package.yml | 4 ++-- .github/workflows/zizmor.yml | 2 +- .pre-commit-config.yaml | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/build-docset.yml b/.github/workflows/build-docset.yml index a1fcfdcb..e86414cf 100644 --- a/.github/workflows/build-docset.yml +++ b/.github/workflows/build-docset.yml @@ -29,7 +29,7 @@ jobs: - run: tox run -e docset - run: tar --exclude='.DS_Store' -cvzf structlog.tgz structlog.docset - - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: docset path: structlog.tgz diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6a9d5f8c..2cdfbee6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,7 +49,7 @@ jobs: steps: - name: Download pre-built packages - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 with: name: Packages path: dist @@ -69,7 +69,7 @@ jobs: -f py${PYTHON//./}-tests - name: Upload coverage data - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: coverage-data-${{ matrix.python-version }} path: .coverage.* @@ -98,7 +98,7 @@ jobs: - uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817 # v2.3.0 - name: Download coverage data - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 with: pattern: coverage-data-* merge-multiple: true @@ -117,7 +117,7 @@ jobs: coverage report --fail-under=100 - name: Upload HTML report if check failed. - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: html-report path: htmlcov @@ -130,7 +130,7 @@ jobs: steps: - name: Download pre-built packages - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 with: name: Packages path: dist @@ -150,7 +150,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download pre-built packages - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 with: name: Packages path: dist diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b4e51706..5216985f 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -29,12 +29,12 @@ jobs: persist-credentials: false - name: Initialize CodeQL - uses: github/codeql-action/init@16140ae1a102900babc80a33c44059580f687047 # v4.30.9 + uses: github/codeql-action/init@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.0 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@16140ae1a102900babc80a33c44059580f687047 # v4.30.9 + uses: github/codeql-action/autobuild@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.0 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@16140ae1a102900babc80a33c44059580f687047 # v4.30.9 + uses: github/codeql-action/analyze@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.0 diff --git a/.github/workflows/pypi-package.yml b/.github/workflows/pypi-package.yml index 99735e7e..c83ef6c9 100644 --- a/.github/workflows/pypi-package.yml +++ b/.github/workflows/pypi-package.yml @@ -43,7 +43,7 @@ jobs: steps: - name: Download packages built by build-and-inspect-python-package - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 with: name: Packages path: dist @@ -66,7 +66,7 @@ jobs: steps: - name: Download packages built by build-and-inspect-python-package - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 with: name: Packages path: dist diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index 7ac6c10e..738efb5d 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -30,7 +30,7 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload SARIF file - uses: github/codeql-action/upload-sarif@16140ae1a102900babc80a33c44059580f687047 # v4.30.9 + uses: github/codeql-action/upload-sarif@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.0 with: # Path to SARIF file relative to the root of the repository sarif_file: results.sarif diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 57a45e71..3b7ea9a1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.14.1 + rev: v0.14.2 hooks: - id: ruff-check args: [--fix, --exit-non-zero-on-fix] From ecaa15ac6b166ebca9f2b4f5cfdb4c4ec138a602 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 25 Oct 2025 14:47:46 +0200 Subject: [PATCH 1458/1520] stdlib: add support for stacklevel (#763) * stdlib: add support for stacklevel * Add changelog entry * Keep order * Fix wrong adjustment * Clarify comment * Clarify changelog --- CHANGELOG.md | 3 +++ src/structlog/_frames.py | 15 ++++++++++++++- src/structlog/stdlib.py | 18 +++++++++++++++--- tests/test_frames.py | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42e0177b..cd7bdf55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,6 +60,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - On Python 3.11+, `structlog.processors.CallsiteParameterAdder` now supports `CallsiteParameter.QUAL_NAME` that adds the qualified name of the callsite, including scope and class names. This is only available for *structlog*-originated events since the standard library has no equivalent. +- `structlog.stdlib.LoggerFactory` now supports the *stacklevel* parameter. + [#763](https://github.com/hynek/structlog/pull/763) + ### Changed diff --git a/src/structlog/_frames.py b/src/structlog/_frames.py index 6acd7549..57841afd 100644 --- a/src/structlog/_frames.py +++ b/src/structlog/_frames.py @@ -36,6 +36,7 @@ def _format_exception(exc_info: ExcInfo) -> str: def _find_first_app_frame_and_name( additional_ignores: list[str] | None = None, *, + stacklevel: int | None = None, _getframe: Callable[[], FrameType] = sys._getframe, ) -> tuple[FrameType, str]: """ @@ -45,6 +46,9 @@ def _find_first_app_frame_and_name( additional_ignores: Additional names with which the first frame must not start. + stacklevel: + After getting out of structlog, skip this many frames. + _getframe: Callable to find current frame. Only for testing to avoid monkeypatching of sys._getframe. @@ -52,15 +56,24 @@ def _find_first_app_frame_and_name( Returns: tuple of (frame, name) """ - ignores = tuple(["structlog"] + (additional_ignores or [])) + ignores = ("structlog", *tuple(additional_ignores or ())) f = _ASYNC_CALLING_STACK.get(_getframe()) name = f.f_globals.get("__name__") or "?" + while name.startswith(ignores): if f.f_back is None: name = "?" break f = f.f_back name = f.f_globals.get("__name__") or "?" + + if stacklevel is not None: + for _ in range(stacklevel): + if f.f_back is None: + break + f = f.f_back + name = f.f_globals.get("__name__") or "?" + return f, name diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index dc4c94ae..608a40ef 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -130,7 +130,15 @@ def findCaller( This logger gets set as the default one when using LoggerFactory. """ sinfo: str | None - f, _name = _find_first_app_frame_and_name(["logging"]) + # stdlib logging passes stacklevel=1 from log methods like .warning(), + # but we've already skipped those frames by ignoring "logging", so we + # need to adjust stacklevel down by 1. We need to manually drop + # logging frames, because there's cases where we call logging methods + # from within structlog and the stacklevel offsets don't work anymore. + adjusted_stacklevel = max(0, stacklevel - 1) if stacklevel else None + f, _name = _find_first_app_frame_and_name( + ["logging"], stacklevel=adjusted_stacklevel + ) sinfo = _format_stack(f) if stack_info else None return f.f_code.co_filename, f.f_lineno, f.f_code.co_name, sinfo @@ -323,12 +331,16 @@ def setLevel(self, level: int) -> None: self._logger.setLevel(level) def findCaller( - self, stack_info: bool = False + self, stack_info: bool = False, stacklevel: int = 1 ) -> tuple[str, int, str, str | None]: """ Calls :meth:`logging.Logger.findCaller` with unmodified arguments. """ - return self._logger.findCaller(stack_info=stack_info) + # No need for stacklevel-adjustments since we're within structlog and + # our frames are ignored unconditionally. + return self._logger.findCaller( + stack_info=stack_info, stacklevel=stacklevel + ) def makeRecord( self, diff --git a/tests/test_frames.py b/tests/test_frames.py index 19aa2933..3eef27a5 100644 --- a/tests/test_frames.py +++ b/tests/test_frames.py @@ -42,6 +42,40 @@ def test_ignoring_of_additional_frame_names_works(self): assert (f1, "test") == (f, n) + def test_stacklevel(self): + """ + stacklevel is respected. + """ + f0 = stub( + f_globals={"__name__": "test"}, + f_back=stub(f_globals={"__name__": "too far"}, f_back=None), + ) + f1 = stub(f_globals={"__name__": "skipped"}, f_back=f0) + f2 = stub(f_globals={"__name__": "ignored.bar"}, f_back=f1) + f3 = stub(f_globals={"__name__": "structlog.blubb"}, f_back=f2) + + f, n = _find_first_app_frame_and_name( + additional_ignores=["ignored"], stacklevel=1, _getframe=lambda: f3 + ) + + assert (f0, "test") == (f, n) + + def test_stacklevel_capped(self): + """ + stacklevel is capped at the number of frames. + """ + f0 = stub(f_globals={"__name__": "test"}, f_back=None) + f1 = stub(f_globals={"__name__": "skipped"}, f_back=f0) + f2 = stub(f_globals={"__name__": "ignored.bar"}, f_back=f1) + f3 = stub(f_globals={"__name__": "structlog.blubb"}, f_back=f2) + + f, n = _find_first_app_frame_and_name( + additional_ignores=["ignored"], + stacklevel=100, + _getframe=lambda: f3, + ) + assert (f0, "test") == (f, n) + def test_tolerates_missing_name(self): """ Use ``?`` if `f_globals` lacks a `__name__` key From 3800d401db2c682c7c83b2d3eec38d81c9791f4d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 26 Oct 2025 19:10:03 +0100 Subject: [PATCH 1459/1520] docs: use native --- docs/_static/custom.css | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/_static/custom.css b/docs/_static/custom.css index 4c10c35d..8a03172e 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -1,11 +1,9 @@ @import url(https://fonts.bunny.net/css?family=atkinson-hyperlegible:400,400i,700,700i); @import url('https://assets.hynek.me/css/bm.css'); - :root { - font-feature-settings: 'liga' 1, 'calt' 1; /* fix for Chrome */ - --pst-font-family-base: "Atkinson Hyperlegible", system-ui, sans-serif; - --pst-font-family-heading: "Atkinson Hyperlegible", system-ui, sans-serif; + --pst-font-family-base: system-ui, sans-serif; + --pst-font-family-heading: Bahnschrift, 'DIN Alternate', 'Franklin Gothic Medium', 'Nimbus Sans Narrow', sans-serif-condensed, sans-serif; --pst-font-family-monospace: BerkeleyMono, ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace; } From aca10f23dd12bd9e14cfe712f1ce66c9cb5f4400 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 27 Oct 2025 07:24:44 +0100 Subject: [PATCH 1460/1520] Drop pretend dependency (#766) --- pyproject.toml | 1 - tests/helpers.py | 46 ++++++++++++++++++++++++++++++ tests/processors/test_renderers.py | 2 +- tests/test_base.py | 5 ++-- tests/test_config.py | 8 ++++-- tests/test_frames.py | 4 +-- tests/test_output.py | 2 +- tests/test_stdlib.py | 13 ++++----- tests/test_threadlocal.py | 3 +- tests/test_twisted.py | 8 +++--- tests/utils.py | 19 ------------ 11 files changed, 69 insertions(+), 42 deletions(-) create mode 100644 tests/helpers.py delete mode 100644 tests/utils.py diff --git a/pyproject.toml b/pyproject.toml index 2edaa2c3..31ff784c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,7 +42,6 @@ Twitter = "https://twitter.com/hynek" [dependency-groups] tests = [ "time-machine>=2.14.1", - "pretend", "pytest-asyncio>=0.17", "pytest>=6.0", "simplejson", diff --git a/tests/helpers.py b/tests/helpers.py new file mode 100644 index 00000000..97e63676 --- /dev/null +++ b/tests/helpers.py @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the MIT License. See the LICENSE file in the root of this +# repository for complete details. + +""" +Shared test utilities. +""" + +from unittest.mock import Mock, seal + +from structlog._log_levels import NAME_TO_LEVEL + + +stdlib_log_methods = [m for m in NAME_TO_LEVEL if m != "notset"] + + +class CustomError(Exception): + """ + Custom exception for testing purposes. + """ + + +def stub(**kwargs): + """ + Create a restrictive mock that prevents new attributes after creation. + Similar to pretend.stub(). + """ + m = Mock(**kwargs) + seal(m) + + return m + + +def raiser(exception): + """ + Create a mock that raises the given exception when called. + """ + return Mock(side_effect=exception) + + +def call_recorder(func): + """ + Create a mock that records calls while executing func. + """ + return Mock(side_effect=func) diff --git a/tests/processors/test_renderers.py b/tests/processors/test_renderers.py index b133aabe..82645633 100644 --- a/tests/processors/test_renderers.py +++ b/tests/processors/test_renderers.py @@ -24,7 +24,7 @@ ) from structlog.threadlocal import wrap_dict -from ..utils import CustomError +from ..helpers import CustomError try: diff --git a/tests/test_base.py b/tests/test_base.py index de810c72..fa34cc8b 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -5,15 +5,14 @@ import pytest -from pretend import raiser, stub - from structlog import get_context from structlog._base import BoundLoggerBase from structlog._config import _CONFIG from structlog.exceptions import DropEvent from structlog.processors import KeyValueRenderer from structlog.testing import ReturnLogger -from tests.utils import CustomError + +from .helpers import CustomError, raiser, stub def build_bl(logger=None, processors=None, context=None): diff --git a/tests/test_config.py b/tests/test_config.py index a25388b1..fa9dfad5 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -7,9 +7,9 @@ import pickle import warnings -import pytest +from unittest.mock import call -from pretend import call, call_recorder, stub +import pytest import structlog @@ -28,6 +28,8 @@ ) from structlog.typing import BindableLogger +from .helpers import call_recorder, stub + @pytest.fixture(name="proxy") def _proxy(): @@ -463,4 +465,4 @@ def test_get_logger_passes_positional_arguments_to_logger_factory(self): get_logger("test").bind(x=42) - assert [call("test")] == factory.calls + assert [call("test")] == factory.call_args_list diff --git a/tests/test_frames.py b/tests/test_frames.py index 3eef27a5..bca8082e 100644 --- a/tests/test_frames.py +++ b/tests/test_frames.py @@ -7,14 +7,14 @@ import pytest -from pretend import stub - from structlog._frames import ( _find_first_app_frame_and_name, _format_exception, _format_stack, ) +from .helpers import stub + class TestFindFirstAppFrameAndName: def test_ignores_structlog_by_default(self): diff --git a/tests/test_output.py b/tests/test_output.py index 0c84ed65..8553aad9 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -20,7 +20,7 @@ ) from structlog._output import WRITE_LOCKS, stderr, stdout -from .utils import stdlib_log_methods +from .helpers import stdlib_log_methods class TestLoggers: diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index a045386f..b3ec4579 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -18,8 +18,6 @@ import pytest import pytest_asyncio -from pretend import call_recorder, stub - from structlog import ( PrintLogger, ReturnLogger, @@ -53,6 +51,7 @@ from structlog.typing import BindableLogger, EventDict from .additional_frame import additional_frame +from .helpers import call_recorder, stub def build_bl(logger=None, processors=None, context=None): @@ -1100,7 +1099,7 @@ def test_pass_foreign_args_true_sets_positional_args_key(self): positional_args = {"foo": "bar"} logging.getLogger().info("okay %(foo)s", positional_args) - event_dict = test_processor.calls[0].args[2] + event_dict = test_processor.call_args_list[0].args[2] assert "positional_args" in event_dict assert positional_args == event_dict["positional_args"] @@ -1181,7 +1180,7 @@ def test_foreign_pre_chain_gets_exc_info(self): except Exception: logging.getLogger().exception("okay") - event_dict = test_processor.calls[0].args[2] + event_dict = test_processor.call_args_list[0].args[2] assert "exc_info" in event_dict assert isinstance(event_dict["exc_info"], tuple) @@ -1209,7 +1208,7 @@ def add_excinfo(logger, log_method, event_dict): except Exception: logging.getLogger().error("okay") - event_dict = test_processor.calls[0].args[2] + event_dict = test_processor.call_args_list[0].args[2] assert MyError is event_dict["exc_info"][0] @@ -1232,9 +1231,9 @@ def test_other_handlers_get_original_record(self): logger.info("meh") - assert 1 == len(handler2.handle.calls) + assert 1 == len(handler2.handle.call_args_list) - handler2_record = handler2.handle.calls[0].args[0] + handler2_record = handler2.handle.call_args_list[0].args[0] assert "meh" == handler2_record.msg diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py index 9a06e12f..1b454cd5 100644 --- a/tests/test_threadlocal.py +++ b/tests/test_threadlocal.py @@ -28,7 +28,8 @@ unbind_threadlocal, wrap_dict, ) -from tests.utils import CustomError + +from .helpers import CustomError try: diff --git a/tests/test_twisted.py b/tests/test_twisted.py index d13e7f80..571d7d56 100644 --- a/tests/test_twisted.py +++ b/tests/test_twisted.py @@ -7,12 +7,12 @@ import pytest -from pretend import call_recorder - from structlog import ReturnLogger from structlog._config import _CONFIG from structlog.processors import KeyValueRenderer +from .helpers import call_recorder + try: from twisted.python.failure import Failure @@ -327,7 +327,7 @@ def test_callsWrappedObserver(self): o = call_recorder(lambda *a, **kw: None) JSONLogObserverWrapper(o)({"message": ("hello",)}) - assert 1 == len(o.calls) + assert 1 == len(o.call_args_list) def test_jsonifiesPlainLogEntries(self): """ @@ -336,7 +336,7 @@ def test_jsonifiesPlainLogEntries(self): """ o = call_recorder(lambda *a, **kw: None) JSONLogObserverWrapper(o)({"message": ("hello",), "system": "-"}) - msg = json.loads(o.calls[0].args[0]["message"][0]) + msg = json.loads(o.call_args_list[0].args[0]["message"][0]) assert msg == {"event": "hello", "system": "-"} diff --git a/tests/utils.py b/tests/utils.py deleted file mode 100644 index aa68ab46..00000000 --- a/tests/utils.py +++ /dev/null @@ -1,19 +0,0 @@ -# SPDX-License-Identifier: MIT OR Apache-2.0 -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the MIT License. See the LICENSE file in the root of this -# repository for complete details. - -""" -Shared test utilities. -""" - -from structlog._log_levels import NAME_TO_LEVEL - - -stdlib_log_methods = [m for m in NAME_TO_LEVEL if m != "notset"] - - -class CustomError(Exception): - """ - Custom exception for testing purposes. - """ From 1c2c19aa19c8f30330b76465b7a0d9993b9e8360 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 27 Oct 2025 07:53:35 +0100 Subject: [PATCH 1461/1520] Try validating pyproject.toml --- .pre-commit-config.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3b7ea9a1..2c9e4670 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,6 +22,13 @@ repos: - id: codespell args: [-L, alog, -L, abl] + - repo: https://github.com/abravalheri/validate-pyproject + rev: v0.24.1 + hooks: + - id: validate-pyproject + # Optional extra validations from SchemaStore: + additional_dependencies: ["validate-pyproject-schema-store[all]"] + - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 hooks: From 5400612735ad07bbe8ee9f2279f3040aa2e69ca4 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 27 Oct 2025 08:35:38 +0100 Subject: [PATCH 1462/1520] docs/stdlib: add warning about ProcessorFormatter ref #486 --- docs/standard-library.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/standard-library.md b/docs/standard-library.md index 2f45ac4e..bf090cdc 100644 --- a/docs/standard-library.md +++ b/docs/standard-library.md @@ -373,6 +373,12 @@ flowchart TD For that, `ProcessorFormatter` wraps a processor chain that is responsible for rendering your log entries to strings. +:::{warning} +When using {class}`~structlog.stdlib.ProcessorFormatter`, you **must not** use {func}`~structlog.stdlib.render_to_log_kwargs` or {func}`~structlog.stdlib.render_to_log_args_and_kwargs` in your processor chain. + +You _**must**_ use {func}`structlog.stdlib.ProcessorFormatter.wrap_for_formatter()` -- otherwise you _**will**_ get puzzling errors from the standard library. +::: + Thus, the simplest possible configuration looks like the following: ```python From 9cb662fe32046f92f08346c58089a2dcba7cb4bf Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 27 Oct 2025 09:07:22 +0100 Subject: [PATCH 1463/1520] docs: nit --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd7bdf55..88269179 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,7 +42,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ [#757](https://github.com/hynek/structlog/pull/757) [#759](https://github.com/hynek/structlog/pull/759) -- Added `structlog.dev.ConsoleRenderer.get_default_column_styles` for reuse the default column styles. +- Added `structlog.dev.ConsoleRenderer.get_default_column_styles()` for reuse the default column styles. [#741](https://github.com/hynek/structlog/pull/741) - `structlog.testing.capture_logs()` now optionally accepts *processors* to apply before capture. From c0ef9e09e7a536cae65e33c1ac1c8b4e6a6f7511 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 27 Oct 2025 09:10:09 +0100 Subject: [PATCH 1464/1520] Prepare 25.5.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88269179..5baae346 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ -## [Unreleased](https://github.com/hynek/structlog/compare/25.4.0...HEAD) +## [25.5.0](https://github.com/hynek/structlog/compare/25.4.0...25.5.0) - 2025-10-27 ### Deprecated From 67f478a943e893ecccaa02cf6934502dc44b9544 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 27 Oct 2025 09:17:40 +0100 Subject: [PATCH 1465/1520] Start new development cycle --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5baae346..3a9caad1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ +## [Unreleased](https://github.com/hynek/structlog/compare/25.5.0...HEAD) + + ## [25.5.0](https://github.com/hynek/structlog/compare/25.4.0...25.5.0) - 2025-10-27 ### Deprecated From 3cc86e61ec9196cd8a80e07f05a4a74235683dd2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 27 Oct 2025 09:35:37 +0100 Subject: [PATCH 1466/1520] docs: remove forgotten resource --- docs/_static/custom.css | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/_static/custom.css b/docs/_static/custom.css index 8a03172e..2c3a5125 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -1,4 +1,3 @@ -@import url(https://fonts.bunny.net/css?family=atkinson-hyperlegible:400,400i,700,700i); @import url('https://assets.hynek.me/css/bm.css'); :root { From 53051f190c845c1bba6ef85351cf8fd60a4b9192 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 27 Oct 2025 10:12:02 +0100 Subject: [PATCH 1467/1520] Make tests order-independent (#767) --- pyproject.toml | 3 ++- tests/conftest.py | 2 ++ tests/test_dev.py | 6 +++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 31ff784c..3903c611 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,10 +41,11 @@ Twitter = "https://twitter.com/hynek" [dependency-groups] tests = [ - "time-machine>=2.14.1", "pytest-asyncio>=0.17", + "pytest-randomly", "pytest>=6.0", "simplejson", + "time-machine>=2.14.1", ] # Need Twisted & Rich for stubs. # Otherwise mypy fails in tox. diff --git a/tests/conftest.py b/tests/conftest.py index b2419c9f..b549a52b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -29,10 +29,12 @@ def _ensure_logging_framework_not_altered(): Prevents 'ValueError: I/O operation on closed file.' errors. """ before_handlers = list(LOGGER.handlers) + before_level = LOGGER.level yield LOGGER.handlers = before_handlers + LOGGER.setLevel(before_level) @pytest.fixture(name="sio") diff --git a/tests/test_dev.py b/tests/test_dev.py index 11055f64..f35bf013 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -30,19 +30,19 @@ def test_negative(self): assert len("test") == len(dev._pad("test", 2)) -@pytest.fixture(name="cr", scope="session") +@pytest.fixture(name="cr") def _cr(): return dev.ConsoleRenderer( colors=dev._has_colors, exception_formatter=dev.plain_traceback ) -@pytest.fixture(name="styles", scope="session") +@pytest.fixture(name="styles") def _styles(cr): return cr._styles -@pytest.fixture(name="padded", scope="session") +@pytest.fixture(name="padded") def _padded(styles): return styles.bright + dev._pad("test", dev._EVENT_WIDTH) + styles.reset From de1a79e045c886688d5608c1b167a88c7416e993 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 27 Oct 2025 10:34:15 +0100 Subject: [PATCH 1468/1520] Drop Python 3.8 (#768) --- CHANGELOG.md | 4 ++++ pyproject.toml | 3 +-- src/structlog/_base.py | 3 ++- src/structlog/_config.py | 5 +++-- src/structlog/contextvars.py | 3 ++- src/structlog/dev.py | 2 +- src/structlog/processors.py | 3 +-- src/structlog/stdlib.py | 5 +++-- src/structlog/testing.py | 3 ++- src/structlog/threadlocal.py | 3 ++- src/structlog/tracebacks.py | 5 +++-- src/structlog/twisted.py | 3 ++- src/structlog/typing.py | 12 ++++-------- tests/test_dev.py | 9 ++++----- tests/test_stdlib.py | 7 +++---- tests/test_threadlocal.py | 8 +++++--- tox.ini | 8 ++++---- 17 files changed, 46 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a9caad1..5952e405 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ## [Unreleased](https://github.com/hynek/structlog/compare/25.5.0...HEAD) +### Removed + +- Python 3.8 support. + ## [25.5.0](https://github.com/hynek/structlog/compare/25.4.0...25.5.0) - 2025-10-27 diff --git a/pyproject.toml b/pyproject.toml index 3903c611..23a45317 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,14 +10,13 @@ dynamic = ["readme", "version"] name = "structlog" description = "Structured Logging for Python" authors = [{ name = "Hynek Schlawack", email = "hs@ox.cx" }] -requires-python = ">=3.8" +requires-python = ">=3.9" license = "MIT OR Apache-2.0" keywords = ["logging", "structured", "structure", "log"] classifiers = [ "Development Status :: 5 - Production/Stable", "License :: OSI Approved :: Apache Software License", "License :: OSI Approved :: MIT License", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", diff --git a/src/structlog/_base.py b/src/structlog/_base.py index dab02754..93845e65 100644 --- a/src/structlog/_base.py +++ b/src/structlog/_base.py @@ -11,7 +11,8 @@ import sys -from typing import Any, Iterable, Mapping, Sequence +from collections.abc import Iterable, Mapping, Sequence +from typing import Any from structlog.exceptions import DropEvent diff --git a/src/structlog/_config.py b/src/structlog/_config.py index 98e2f211..dd5c3d0a 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -13,7 +13,8 @@ import sys import warnings -from typing import Any, Callable, Iterable, Sequence, Type, cast +from collections.abc import Iterable, Sequence +from typing import Any, Callable, cast from ._native import make_filtering_bound_logger from ._output import PrintLoggerFactory @@ -53,7 +54,7 @@ force_colors=_force_colors, ), ] -_BUILTIN_DEFAULT_CONTEXT_CLASS = cast(Type[Context], dict) +_BUILTIN_DEFAULT_CONTEXT_CLASS = cast(type[Context], dict) _BUILTIN_DEFAULT_WRAPPER_CLASS = make_filtering_bound_logger(0) _BUILTIN_DEFAULT_LOGGER_FACTORY = PrintLoggerFactory() _BUILTIN_CACHE_LOGGER_ON_FIRST_USE = False diff --git a/src/structlog/contextvars.py b/src/structlog/contextvars.py index 6bc79d72..71561a76 100644 --- a/src/structlog/contextvars.py +++ b/src/structlog/contextvars.py @@ -22,8 +22,9 @@ import contextlib import contextvars +from collections.abc import Generator, Mapping from types import FrameType -from typing import Any, Generator, Mapping +from typing import Any import structlog diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 7a98024f..ca982e14 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -14,6 +14,7 @@ import sys import warnings +from collections.abc import Sequence from dataclasses import dataclass from io import StringIO from types import ModuleType @@ -22,7 +23,6 @@ Callable, Literal, Protocol, - Sequence, TextIO, cast, ) diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 4248648e..80841561 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -19,14 +19,13 @@ import threading import time +from collections.abc import Collection, Sequence from types import FrameType, TracebackType from typing import ( Any, Callable, ClassVar, - Collection, NamedTuple, - Sequence, TextIO, cast, ) diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 608a40ef..2ed978fd 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -18,8 +18,9 @@ import sys import warnings +from collections.abc import Collection, Iterable, Sequence from functools import partial -from typing import Any, Callable, Collection, Dict, Iterable, Sequence, cast +from typing import Any, Callable, cast if sys.version_info >= (3, 11): @@ -1121,7 +1122,7 @@ def format(self, record: logging.LogRecord) -> str: # We need to copy because it's possible that the same record gets # processed by multiple logging formatters. LogRecord.getMessage # would transform our dict into a str. - ed = cast(Dict[str, Any], record.msg).copy() + ed = cast(dict[str, Any], record.msg).copy() ed["_record"] = record ed["_from_structlog"] = True else: diff --git a/src/structlog/testing.py b/src/structlog/testing.py index 8271d1e9..85862e2e 100644 --- a/src/structlog/testing.py +++ b/src/structlog/testing.py @@ -13,8 +13,9 @@ from __future__ import annotations +from collections.abc import Generator, Iterable from contextlib import contextmanager -from typing import Any, Generator, Iterable, NamedTuple, NoReturn +from typing import Any, NamedTuple, NoReturn from ._config import configure, get_config from ._log_levels import map_method_name diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index 0ea71f3a..c36df3df 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -20,7 +20,8 @@ import uuid import warnings -from typing import Any, Generator, Iterator, TypeVar +from collections.abc import Generator, Iterator +from typing import Any, TypeVar import structlog diff --git a/src/structlog/tracebacks.py b/src/structlog/tracebacks.py index f42f5302..f73f7971 100644 --- a/src/structlog/tracebacks.py +++ b/src/structlog/tracebacks.py @@ -18,10 +18,11 @@ import os.path import sys +from collections.abc import Iterable, Sequence from dataclasses import asdict, dataclass, field from traceback import walk_tb from types import ModuleType, TracebackType -from typing import Any, Iterable, Sequence, Tuple, Union +from typing import Any, Union try: @@ -50,7 +51,7 @@ LOCALS_MAX_STRING = 80 MAX_FRAMES = 50 -OptExcInfo = Union[ExcInfo, Tuple[None, None, None]] +OptExcInfo = Union[ExcInfo, tuple[None, None, None]] @dataclass diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index a4caf897..1752cb27 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -15,7 +15,8 @@ import json import sys -from typing import Any, Callable, Sequence, TextIO +from collections.abc import Sequence +from typing import Any, Callable, TextIO from twisted.python import log from twisted.python.failure import Failure diff --git a/src/structlog/typing.py b/src/structlog/typing.py index 9b2ee5a2..2cfd9cb2 100644 --- a/src/structlog/typing.py +++ b/src/structlog/typing.py @@ -16,18 +16,14 @@ import sys +from collections.abc import Mapping, MutableMapping from types import TracebackType from typing import ( Any, Callable, - Dict, - Mapping, - MutableMapping, Optional, Protocol, TextIO, - Tuple, - Type, Union, runtime_checkable, ) @@ -50,7 +46,7 @@ """ -Context = Union[Dict[str, Any], Dict[Any, Any]] +Context = Union[dict[str, Any], dict[Any, Any]] """ A dict-like context carrier. @@ -69,7 +65,7 @@ """ ProcessorReturnValue = Union[ - Mapping[str, Any], str, bytes, bytearray, Tuple[Any, ...] + Mapping[str, Any], str, bytes, bytearray, tuple[Any, ...] ] """ A value returned by a processor. @@ -84,7 +80,7 @@ .. versionadded:: 20.2.0 """ -ExcInfo = Tuple[Type[BaseException], BaseException, Optional[TracebackType]] +ExcInfo = tuple[type[BaseException], BaseException, Optional[TracebackType]] """ An exception info tuple as returned by `sys.exc_info`. diff --git a/tests/test_dev.py b/tests/test_dev.py index f35bf013..614472c6 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -254,11 +254,10 @@ def test_initializes_colorama_on_windows_with_force_colors(self): """ On Windows with colorama, force_colors=True reinitializes colorama. """ - with mock.patch.object( - dev.colorama, "init" - ) as mock_init, mock.patch.object( - dev.colorama, "deinit" - ) as mock_deinit: + with ( + mock.patch.object(dev.colorama, "init") as mock_init, + mock.patch.object(dev.colorama, "deinit") as mock_deinit, + ): styles = dev.ConsoleRenderer.get_default_column_styles( colors=True, force_colors=True ) diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index b3ec4579..f54ae6b2 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -11,8 +11,9 @@ import os import sys +from collections.abc import Collection from io import StringIO -from typing import Any, Callable, Collection, Dict +from typing import Any, Callable from unittest.mock import patch import pytest @@ -1409,9 +1410,7 @@ def test_logrecord_exc_info(self): # handlers will receive LogRecord objects that come from both structlog # and non-structlog loggers. - records: Dict[ # noqa: UP006 - dict isn't generic until Python 3.9 - str, logging.LogRecord - ] = {} + records: dict[str, logging.LogRecord] = {} class DummyHandler(logging.Handler): def emit(self, record): diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py index 1b454cd5..9a27c88a 100644 --- a/tests/test_threadlocal.py +++ b/tests/test_threadlocal.py @@ -94,9 +94,11 @@ def test_bind_exc(self, log): """ log = log.bind(y=23) - with pytest.raises( # noqa: PT012 - CustomError - ), pytest.deprecated_call(), tmp_bind(log, x=42, y="foo") as tmp_log: + with ( # noqa: PT012 + pytest.raises(CustomError), + pytest.deprecated_call(), + tmp_bind(log, x=42, y="foo") as tmp_log, + ): assert ( {"y": "foo", "x": 42} == tmp_log._context._dict diff --git a/tox.ini b/tox.ini index cd9c02df..bb36aa00 100644 --- a/tox.ini +++ b/tox.ini @@ -2,8 +2,8 @@ min_version = 4 env_list = pre-commit, - py3{8,9,10,11,12,13,14}-{tests,mypy} - py3{8,13}-tests-{colorama,be,rich}, + py3{9,10,11,12,13,14}-{tests,mypy} + py3{9,13}-tests-{colorama,be,rich}, typing-{mypy,pyright,ty,pyrefly}, docs-{sponsors,build,doctests}, coverage-{combine,report} @@ -22,7 +22,7 @@ commands = # Run oldest and latest under Coverage. # Keep in-sync with coverage `depends below. -[testenv:py3{8,13}-tests{,-colorama,-be,-rich}] +[testenv:py3{9,13}-tests{,-colorama,-be,-rich}] deps = coverage[toml] py313: twisted @@ -37,7 +37,7 @@ commands = coverage run -m pytest {posargs} # Keep base_python in-sync with .python-version-default base_python = py313 # Keep in-sync with test env definition above. -depends = py3{8,13}-tests{,-colorama,-be,-rich} +depends = py3{9,13}-tests{,-colorama,-be,-rich} skip_install = true deps = coverage commands = coverage combine From 8c5dbfc53e3fd156d455d407a896dfa0db3983bd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 28 Oct 2025 08:56:56 +0100 Subject: [PATCH 1469/1520] Clean up unused logos --- docs/_static/sponsors/Klaviyo.svg | 1 - docs/_static/sponsors/emsys-renewables.svg | 1 - 2 files changed, 2 deletions(-) delete mode 100644 docs/_static/sponsors/Klaviyo.svg delete mode 100644 docs/_static/sponsors/emsys-renewables.svg diff --git a/docs/_static/sponsors/Klaviyo.svg b/docs/_static/sponsors/Klaviyo.svg deleted file mode 100644 index 6c7449bc..00000000 --- a/docs/_static/sponsors/Klaviyo.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/_static/sponsors/emsys-renewables.svg b/docs/_static/sponsors/emsys-renewables.svg deleted file mode 100644 index d5738cec..00000000 --- a/docs/_static/sponsors/emsys-renewables.svg +++ /dev/null @@ -1 +0,0 @@ - From 3b80ab71061708147b8b086580632d4f64dd1de5 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 28 Oct 2025 09:21:27 +0100 Subject: [PATCH 1470/1520] sponsors: add LambdaTest --- README.md | 1 + docs/_static/sponsors/LambdaTest.svg | 1 + docs/index.md | 1 + pyproject.toml | 5 +++++ 4 files changed, 8 insertions(+) create mode 100644 docs/_static/sponsors/LambdaTest.svg diff --git a/README.md b/README.md index d209dc66..ae81fce3 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ for sponsor in tomllib.loads(pathlib.Path("pyproject.toml").read_text())["tool"] + diff --git a/docs/_static/sponsors/LambdaTest.svg b/docs/_static/sponsors/LambdaTest.svg new file mode 100644 index 00000000..4b89ed79 --- /dev/null +++ b/docs/_static/sponsors/LambdaTest.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index c3ecf276..17e84924 100644 --- a/docs/index.md +++ b/docs/index.md @@ -23,6 +23,7 @@ for sponsor in tomllib.loads(pathlib.Path("pyproject.toml").read_text())["tool"] + diff --git a/pyproject.toml b/pyproject.toml index 23a45317..21475dfc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -262,6 +262,11 @@ title = "FilePreviews" url = "https://filepreviews.io/" img = "FilePreviews.svg" +[[tool.sponcon.sponsors]] +title = "LambdaTest" +url = "https://www.lambdatest.com/?utm_source=structlog&utm_medium=sponsor" +img = "LambdaTest.svg" + [[tool.sponcon.sponsors]] title = "Polar" url = "https://polar.sh/" From 94fd0411152d419658b332d6e73f8120db5de821 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 28 Oct 2025 09:59:11 +0100 Subject: [PATCH 1471/1520] sponsors: make Polar fit better --- docs/_static/sponsors/Polar.svg | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/docs/_static/sponsors/Polar.svg b/docs/_static/sponsors/Polar.svg index b278cb75..bdc7a1c0 100644 --- a/docs/_static/sponsors/Polar.svg +++ b/docs/_static/sponsors/Polar.svg @@ -1,10 +1 @@ - - - - - - - - - - + \ No newline at end of file From e15dd8ff5d21359822416dd4a4c4f8acfa0c41c5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 3 Nov 2025 21:09:07 +0100 Subject: [PATCH 1472/1520] [pre-commit.ci] pre-commit autoupdate (#770) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2c9e4670..9a437cb0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.14.2 + rev: v0.14.3 hooks: - id: ruff-check args: [--fix, --exit-non-zero-on-fix] From ba303ff5b5b95797fe462637edc9bfe9f4dab6d7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 1 Dec 2025 19:42:32 +0100 Subject: [PATCH 1473/1520] [pre-commit.ci] pre-commit autoupdate (#774) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.14.3 → v0.14.7](https://github.com/astral-sh/ruff-pre-commit/compare/v0.14.3...v0.14.7) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9a437cb0..67f2cbaf 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.14.3 + rev: v0.14.7 hooks: - id: ruff-check args: [--fix, --exit-non-zero-on-fix] From d157cfd809d564e191645b7be85412a703cfab40 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 1 Dec 2025 08:43:22 -1000 Subject: [PATCH 1474/1520] Align CoC with PSF --- .github/CODE_OF_CONDUCT.md | 131 ++----------------------------------- 1 file changed, 7 insertions(+), 124 deletions(-) diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md index 348412b1..057262b1 100644 --- a/.github/CODE_OF_CONDUCT.md +++ b/.github/CODE_OF_CONDUCT.md @@ -1,133 +1,16 @@ +# Code of Conduct -# Contributor Covenant Code of Conduct +While not being a [Python Software Foundation](https://www.python.org/psf-landing/) project, everyone interacting in this project is expected to follow the [PSF Code of Conduct](https://policies.python.org/python.org/code-of-conduct/). -## Our Pledge +In general, this means that everyone is expected to be **open**, **considerate**, and **respectful** of others no matter what their position is within the project. -We as members, contributors, and leaders pledge to make participation in our -community a harassment-free experience for everyone, regardless of age, body -size, visible or invisible disability, ethnicity, sex characteristics, gender -identity and expression, level of experience, education, socioeconomic status, -nationality, personal appearance, race, caste, color, religion, or sexual -identity and orientation. - -We pledge to act and interact in ways that contribute to an open, welcoming, -diverse, inclusive, and healthy community. - -## Our Standards - -Examples of behavior that contributes to a positive environment for our -community include: - -* Demonstrating empathy and kindness toward other people -* Being respectful of differing opinions, viewpoints, and experiences -* Giving and gracefully accepting constructive feedback -* Accepting responsibility and apologizing to those affected by our mistakes, - and learning from the experience -* Focusing on what is best not just for us as individuals, but for the overall - community - -Examples of unacceptable behavior include: - -* The use of sexualized language or imagery, and sexual attention or advances of - any kind -* Trolling, insulting or derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or email address, - without their explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Enforcement Responsibilities - -Community leaders are responsible for clarifying and enforcing our standards of -acceptable behavior and will take appropriate and fair corrective action in -response to any behavior that they deem inappropriate, threatening, offensive, -or harmful. - -Community leaders have the right and responsibility to remove, edit, or reject -comments, commits, code, wiki edits, issues, and other contributions that are -not aligned to this Code of Conduct, and will communicate reasons for moderation -decisions when appropriate. - -## Scope - -This Code of Conduct applies within all community spaces, and also applies when -an individual is officially representing the community in public spaces. -Examples of representing our community include using an official e-mail address, -posting via an official social media account, or acting as an appointed -representative at an online or offline event. ## Enforcement -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported to the community leaders responsible for enforcement at -. -All complaints will be reviewed and investigated promptly and fairly. - -All community leaders are obligated to respect the privacy and security of the -reporter of any incident. - -## Enforcement Guidelines - -Community leaders will follow these Community Impact Guidelines in determining -the consequences for any action they deem in violation of this Code of Conduct: - -### 1. Correction - -**Community Impact**: Use of inappropriate language or other behavior deemed -unprofessional or unwelcome in the community. - -**Consequence**: A private, written warning from community leaders, providing -clarity around the nature of the violation and an explanation of why the -behavior was inappropriate. A public apology may be requested. - -### 2. Warning - -**Community Impact**: A violation through a single incident or series of -actions. - -**Consequence**: A warning with consequences for continued behavior. No -interaction with the people involved, including unsolicited interaction with -those enforcing the Code of Conduct, for a specified period of time. This -includes avoiding interactions in community spaces as well as external channels -like social media. Violating these terms may lead to a temporary or permanent -ban. - -### 3. Temporary Ban - -**Community Impact**: A serious violation of community standards, including -sustained inappropriate behavior. - -**Consequence**: A temporary ban from any sort of interaction or public -communication with the community for a specified period of time. No public or -private interaction with the people involved, including unsolicited interaction -with those enforcing the Code of Conduct, is allowed during this period. -Violating these terms may lead to a permanent ban. - -### 4. Permanent Ban - -**Community Impact**: Demonstrating a pattern of violation of community -standards, including sustained inappropriate behavior, harassment of an -individual, or aggression toward or disparagement of classes of individuals. - -**Consequence**: A permanent ban from any sort of public interaction within the -community. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], -version 2.1, available at -[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. +We take Code of Conduct violations seriously, and will act to ensure our spaces are welcoming, inclusive, and professional environments to communicate in. -Community Impact Guidelines were inspired by -[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. +If you need to raise a Code of Conduct report, you may do so privately by email to [Hynek Schlawack](mailto:hs@ox.cx). -For answers to common questions about this code of conduct, see the FAQ at -[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at -[https://www.contributor-covenant.org/translations][translations]. +Reports will be treated confidentially. -[homepage]: https://www.contributor-covenant.org -[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html -[Mozilla CoC]: https://github.com/mozilla/diversity -[FAQ]: https://www.contributor-covenant.org/faq -[translations]: https://www.contributor-covenant.org/translations +Alternately you can make a [report to the Python Software Foundation](https://policies.python.org/python.org/code-of-conduct/Procedures-for-Reporting-Incidents/). From 130372d618862ef2c7552378e070cca205a06eeb Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 1 Dec 2025 08:44:12 -1000 Subject: [PATCH 1475/1520] Raise cooldown --- .github/dependabot.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 201f28e7..cd46bd07 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,7 +6,8 @@ updates: schedule: interval: monthly cooldown: - default-days: 4 + # https://blog.yossarian.net/2025/11/21/We-should-all-be-using-dependency-cooldowns + default-days: 7 groups: github-actions: patterns: From 11e651e81bb7955fa41894c020ec25b52774fd80 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Dec 2025 20:01:51 +0100 Subject: [PATCH 1476/1520] build(deps): bump the github-actions group with 2 updates (#773) Bumps the github-actions group with 2 updates: [actions/checkout](https://github.com/actions/checkout) and [actions/setup-python](https://github.com/actions/setup-python). Updates `actions/checkout` from 5.0.0 to 6.0.0 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/08c6903cd8c0fde910a37f88322edcfb5dd907a8...1af3b93b6815bc44a9784bd300feb67ff0d1eeb3) Updates `actions/setup-python` from 6.0.0 to 6.1.0 - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/e797f83bcb11b83ae66e0230d6156d7c80228e7c...83679a892e2d95755f2dac6acb0bfd1e9ac5d548) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 6.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: actions/setup-python dependency-version: 6.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Hynek Schlawack --- .github/workflows/build-docset.yml | 4 ++-- .github/workflows/ci.yml | 20 ++++++++++---------- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/pypi-package.yml | 2 +- .github/workflows/zizmor.yml | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build-docset.yml b/.github/workflows/build-docset.yml index e86414cf..a137cdcb 100644 --- a/.github/workflows/build-docset.yml +++ b/.github/workflows/build-docset.yml @@ -16,11 +16,11 @@ jobs: docset: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 0 # get correct version persist-credentials: false - - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 + - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 with: python-version: "3.12" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2cdfbee6..7efa855f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 0 persist-credentials: false @@ -56,7 +56,7 @@ jobs: - run: | tar xf dist/*.tar.gz --strip-components=1 rm -rf src - - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 + - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 with: python-version: ${{ matrix.python-version }} allow-prereleases: true @@ -89,10 +89,10 @@ jobs: if: always() steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false - - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 + - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 with: python-version-file: .python-version-default - uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817 # v2.3.0 @@ -135,7 +135,7 @@ jobs: name: Packages path: dist - run: tar xf dist/*.tar.gz --strip-components=1 - - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 + - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 with: python-version-file: .python-version-default - uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817 # v2.3.0 @@ -155,7 +155,7 @@ jobs: name: Packages path: dist - run: tar xf dist/*.tar.gz --strip-components=1 - - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 + - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 with: # Keep in sync with tox.ini/docs & .readthedocs.yaml python-version: "3.13" @@ -173,10 +173,10 @@ jobs: os: [ubuntu-latest, windows-latest] steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false - - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 + - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 with: python-version-file: .python-version-default - uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817 # v2.3.0 @@ -219,10 +219,10 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false - - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 + - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 with: python-version-file: .python-version-default - uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817 # v2.3.0 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 5216985f..baa7de24 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false diff --git a/.github/workflows/pypi-package.yml b/.github/workflows/pypi-package.yml index c83ef6c9..cb0b0880 100644 --- a/.github/workflows/pypi-package.yml +++ b/.github/workflows/pypi-package.yml @@ -21,7 +21,7 @@ jobs: id-token: write steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 0 persist-credentials: false diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index 738efb5d..f17f99a5 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -19,7 +19,7 @@ jobs: security-events: write steps: - name: Checkout repository - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false - uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817 # v2.3.0 From 0c21532213ea759f427f616404dcada4ec771858 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 16 Dec 2025 09:39:21 +0100 Subject: [PATCH 1477/1520] Optimize sponsor SVGs --- docs/_static/sponsors/FilePreviews.svg | 2 +- docs/_static/sponsors/LambdaTest.svg | 2 +- docs/_static/sponsors/Polar.svg | 2 +- docs/_static/sponsors/Privacy-Solutions.svg | 2 +- docs/_static/sponsors/Variomedia.svg | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/_static/sponsors/FilePreviews.svg b/docs/_static/sponsors/FilePreviews.svg index 2fff3aa3..dae09787 100644 --- a/docs/_static/sponsors/FilePreviews.svg +++ b/docs/_static/sponsors/FilePreviews.svg @@ -1 +1 @@ - + \ No newline at end of file diff --git a/docs/_static/sponsors/LambdaTest.svg b/docs/_static/sponsors/LambdaTest.svg index 4b89ed79..7579d698 100644 --- a/docs/_static/sponsors/LambdaTest.svg +++ b/docs/_static/sponsors/LambdaTest.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/_static/sponsors/Polar.svg b/docs/_static/sponsors/Polar.svg index bdc7a1c0..b12e9c0b 100644 --- a/docs/_static/sponsors/Polar.svg +++ b/docs/_static/sponsors/Polar.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/_static/sponsors/Privacy-Solutions.svg b/docs/_static/sponsors/Privacy-Solutions.svg index d742309b..efd2e9c2 100644 --- a/docs/_static/sponsors/Privacy-Solutions.svg +++ b/docs/_static/sponsors/Privacy-Solutions.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/_static/sponsors/Variomedia.svg b/docs/_static/sponsors/Variomedia.svg index 90e750d2..af4ef5d8 100644 --- a/docs/_static/sponsors/Variomedia.svg +++ b/docs/_static/sponsors/Variomedia.svg @@ -1 +1 @@ - + \ No newline at end of file From 19d6987e21b5a42c432c02ff08e0e62e83a2f669 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 16 Dec 2025 09:51:00 +0100 Subject: [PATCH 1478/1520] Add @kraken-tech to sponsors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ❤️ --- README.md | 1 + docs/_static/sponsors/Kraken.svg | 1 + docs/index.md | 1 + pyproject.toml | 5 +++++ 4 files changed, 8 insertions(+) create mode 100644 docs/_static/sponsors/Kraken.svg diff --git a/README.md b/README.md index ae81fce3..f8b0bf8b 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ for sponsor in tomllib.loads(pathlib.Path("pyproject.toml").read_text())["tool"] ]]] --> + diff --git a/docs/_static/sponsors/Kraken.svg b/docs/_static/sponsors/Kraken.svg new file mode 100644 index 00000000..8ee115b6 --- /dev/null +++ b/docs/_static/sponsors/Kraken.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index 17e84924..11de836b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -21,6 +21,7 @@ for sponsor in tomllib.loads(pathlib.Path("pyproject.toml").read_text())["tool"] ]]] --> + diff --git a/pyproject.toml b/pyproject.toml index 21475dfc..ec46e547 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -252,6 +252,11 @@ title = "Tidelift" url = "https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek" img = "Tidelift.svg" +[[tool.sponcon.sponsors]] +title = "Kraken Tech" +url = "https://kraken.tech/" +img = "Kraken.svg" + [[tool.sponcon.sponsors]] title = "Privacy Solutions" url = "https://privacy-solutions.org/" From 615af520e451a987fccf12981f384464a07b4952 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Jan 2026 13:17:08 +0100 Subject: [PATCH 1479/1520] build(deps): bump the github-actions group with 4 updates (#780) Bumps the github-actions group with 4 updates: [actions/checkout](https://github.com/actions/checkout), [actions/upload-artifact](https://github.com/actions/upload-artifact), [actions/download-artifact](https://github.com/actions/download-artifact) and [github/codeql-action](https://github.com/github/codeql-action). Updates `actions/checkout` from 6.0.0 to 6.0.1 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/1af3b93b6815bc44a9784bd300feb67ff0d1eeb3...8e8c483db84b4bee98b60c0593521ed34d9990e8) Updates `actions/upload-artifact` from 5.0.0 to 6.0.0 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/330a01c490aca151604b8cf639adc76d48f6c5d4...b7c566a772e6b6bfb58ed0dc250532a479d7789f) Updates `actions/download-artifact` from 6.0.0 to 7.0.0 - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/018cc2cf5baa6db3ef3c5f8a56943fffe632ef53...37930b1c2abaa49bbe596cd826c3c89aef350131) Updates `github/codeql-action` from 4.31.0 to 4.31.9 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/4e94bd11f71e507f7f87df81788dff88d1dacbfb...5d4e8d1aca955e8d8589aabd499c5cae939e33c7) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 6.0.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: actions/upload-artifact dependency-version: 6.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: actions/download-artifact dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: github/codeql-action dependency-version: 4.31.9 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-docset.yml | 4 ++-- .github/workflows/ci.yml | 20 ++++++++++---------- .github/workflows/codeql-analysis.yml | 8 ++++---- .github/workflows/pypi-package.yml | 6 +++--- .github/workflows/zizmor.yml | 4 ++-- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/workflows/build-docset.yml b/.github/workflows/build-docset.yml index a137cdcb..c6371f3e 100644 --- a/.github/workflows/build-docset.yml +++ b/.github/workflows/build-docset.yml @@ -16,7 +16,7 @@ jobs: docset: runs-on: ubuntu-latest steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: fetch-depth: 0 # get correct version persist-credentials: false @@ -29,7 +29,7 @@ jobs: - run: tox run -e docset - run: tar --exclude='.DS_Store' -cvzf structlog.tgz structlog.docset - - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: docset path: structlog.tgz diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7efa855f..bd6f1309 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: fetch-depth: 0 persist-credentials: false @@ -49,7 +49,7 @@ jobs: steps: - name: Download pre-built packages - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: name: Packages path: dist @@ -69,7 +69,7 @@ jobs: -f py${PYTHON//./}-tests - name: Upload coverage data - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: coverage-data-${{ matrix.python-version }} path: .coverage.* @@ -89,7 +89,7 @@ jobs: if: always() steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 @@ -98,7 +98,7 @@ jobs: - uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817 # v2.3.0 - name: Download coverage data - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: pattern: coverage-data-* merge-multiple: true @@ -117,7 +117,7 @@ jobs: coverage report --fail-under=100 - name: Upload HTML report if check failed. - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: html-report path: htmlcov @@ -130,7 +130,7 @@ jobs: steps: - name: Download pre-built packages - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: name: Packages path: dist @@ -150,7 +150,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download pre-built packages - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: name: Packages path: dist @@ -173,7 +173,7 @@ jobs: os: [ubuntu-latest, windows-latest] steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 @@ -219,7 +219,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index baa7de24..2f0a0c00 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -24,17 +24,17 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false - name: Initialize CodeQL - uses: github/codeql-action/init@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.0 + uses: github/codeql-action/init@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.0 + uses: github/codeql-action/autobuild@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.0 + uses: github/codeql-action/analyze@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9 diff --git a/.github/workflows/pypi-package.yml b/.github/workflows/pypi-package.yml index cb0b0880..e4102ad4 100644 --- a/.github/workflows/pypi-package.yml +++ b/.github/workflows/pypi-package.yml @@ -21,7 +21,7 @@ jobs: id-token: write steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: fetch-depth: 0 persist-credentials: false @@ -43,7 +43,7 @@ jobs: steps: - name: Download packages built by build-and-inspect-python-package - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: name: Packages path: dist @@ -66,7 +66,7 @@ jobs: steps: - name: Download packages built by build-and-inspect-python-package - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: name: Packages path: dist diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index f17f99a5..63fb00b4 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -19,7 +19,7 @@ jobs: security-events: write steps: - name: Checkout repository - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false - uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817 # v2.3.0 @@ -30,7 +30,7 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload SARIF file - uses: github/codeql-action/upload-sarif@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.0 + uses: github/codeql-action/upload-sarif@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9 with: # Path to SARIF file relative to the root of the repository sarif_file: results.sarif From b57405e7e5693843f5df240ff63b95c6278ebffa Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 6 Jan 2026 06:06:07 +0100 Subject: [PATCH 1480/1520] [pre-commit.ci] pre-commit autoupdate (#781) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.14.7 → v0.14.10](https://github.com/astral-sh/ruff-pre-commit/compare/v0.14.7...v0.14.10) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 67f2cbaf..bf5a8552 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.14.7 + rev: v0.14.10 hooks: - id: ruff-check args: [--fix, --exit-non-zero-on-fix] From b7fce31a2dd646862424a21094cc7aef55bb2ffc Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 6 Jan 2026 06:08:14 +0100 Subject: [PATCH 1481/1520] tox: use version ranges --- tox.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index bb36aa00..cee42cbd 100644 --- a/tox.ini +++ b/tox.ini @@ -1,8 +1,8 @@ [tox] -min_version = 4 +min_version = 4.25 env_list = pre-commit, - py3{9,10,11,12,13,14}-{tests,mypy} + py3{9-14}-{tests,mypy} py3{9,13}-tests-{colorama,be,rich}, typing-{mypy,pyright,ty,pyrefly}, docs-{sponsors,build,doctests}, From 1090fe375d6ab06b6a3ecb11ec7cb2614133dcfa Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 21 Jan 2026 12:49:44 +0100 Subject: [PATCH 1482/1520] Add sphinx<9 pin ``` WARNING: while setting up extension sphinx.ext.autodoc.typehints: extension 'sphinx.ext.autodoc.typehints' has no setup() function; is it really a Sphinx extension module? ``` --- .pre-commit-config.yaml | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bf5a8552..77bb1c89 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.14.10 + rev: v0.14.13 hooks: - id: ruff-check args: [--fix, --exit-non-zero-on-fix] diff --git a/pyproject.toml b/pyproject.toml index ec46e547..41408afc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,7 +52,7 @@ typing = ["mypy>=1.4", "rich", "twisted"] docs = [ "cogapp", "myst-parser", - "sphinx", + "sphinx<9", "sphinx-design", "sphinx-copybutton", "sphinx-book-theme", From d68669c06f1801bb666227ba6c2528c7fda12210 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 21 Jan 2026 12:49:51 +0100 Subject: [PATCH 1483/1520] update dev --- .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/zizmor.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 2f0a0c00..61daa420 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -29,12 +29,12 @@ jobs: persist-credentials: false - name: Initialize CodeQL - uses: github/codeql-action/init@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9 + uses: github/codeql-action/init@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v4.31.10 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9 + uses: github/codeql-action/autobuild@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v4.31.10 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9 + uses: github/codeql-action/analyze@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v4.31.10 diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index 63fb00b4..32415236 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -30,7 +30,7 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload SARIF file - uses: github/codeql-action/upload-sarif@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9 + uses: github/codeql-action/upload-sarif@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v4.31.10 with: # Path to SARIF file relative to the root of the repository sarif_file: results.sarif From a06c89b6a6dfb97edb8e6f21df0fce40bf0d02d1 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 22 Jan 2026 06:44:02 +0100 Subject: [PATCH 1484/1520] sponsors: LambdaTest is now TestMu AI --- .pre-commit-config.yaml | 2 +- README.md | 2 +- docs/_static/sponsors/LambdaTest.svg | 1 - docs/_static/sponsors/TestMu-AI.svg | 1 + docs/index.md | 2 +- pyproject.toml | 6 +++--- 6 files changed, 7 insertions(+), 7 deletions(-) delete mode 100644 docs/_static/sponsors/LambdaTest.svg create mode 100644 docs/_static/sponsors/TestMu-AI.svg diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 77bb1c89..b6e6e93b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,7 +20,7 @@ repos: rev: v2.4.1 hooks: - id: codespell - args: [-L, alog, -L, abl] + args: [-L, alog, -L, abl, --skip=*.svg] - repo: https://github.com/abravalheri/validate-pyproject rev: v0.24.1 diff --git a/README.md b/README.md index f8b0bf8b..989d0498 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ for sponsor in tomllib.loads(pathlib.Path("pyproject.toml").read_text())["tool"] - + diff --git a/docs/_static/sponsors/LambdaTest.svg b/docs/_static/sponsors/LambdaTest.svg deleted file mode 100644 index 7579d698..00000000 --- a/docs/_static/sponsors/LambdaTest.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/docs/_static/sponsors/TestMu-AI.svg b/docs/_static/sponsors/TestMu-AI.svg new file mode 100644 index 00000000..72e2bfd3 --- /dev/null +++ b/docs/_static/sponsors/TestMu-AI.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index 11de836b..ac639a1e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -24,7 +24,7 @@ for sponsor in tomllib.loads(pathlib.Path("pyproject.toml").read_text())["tool"] - + diff --git a/pyproject.toml b/pyproject.toml index 41408afc..f4afa284 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -268,9 +268,9 @@ url = "https://filepreviews.io/" img = "FilePreviews.svg" [[tool.sponcon.sponsors]] -title = "LambdaTest" -url = "https://www.lambdatest.com/?utm_source=structlog&utm_medium=sponsor" -img = "LambdaTest.svg" +title = "TestMu AI" +url = "https://www.testmu.ai/?utm_source=structlog&utm_medium=sponsor" +img = "TestMu-AI.svg" [[tool.sponcon.sponsors]] title = "Polar" From db435259f68088ae7a0cacc48d9879660a26f43a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Thu, 22 Jan 2026 11:36:43 +0100 Subject: [PATCH 1485/1520] sponsors: pure-SVG logo --- docs/_static/sponsors/TestMu-AI.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_static/sponsors/TestMu-AI.svg b/docs/_static/sponsors/TestMu-AI.svg index 72e2bfd3..aa1b7a3a 100644 --- a/docs/_static/sponsors/TestMu-AI.svg +++ b/docs/_static/sponsors/TestMu-AI.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file From e1eb88852855a6d2cbcd0dd76fa3277307f7ebfa Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 4 Feb 2026 10:17:58 +0100 Subject: [PATCH 1486/1520] [pre-commit.ci] pre-commit autoupdate (#785) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.14.13 → v0.14.14](https://github.com/astral-sh/ruff-pre-commit/compare/v0.14.13...v0.14.14) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b6e6e93b..2124aaa5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.14.13 + rev: v0.14.14 hooks: - id: ruff-check args: [--fix, --exit-non-zero-on-fix] From 811245fe02fcf454f517f0677648457bfec52ef0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Feb 2026 10:21:44 +0100 Subject: [PATCH 1487/1520] build(deps): bump the github-actions group with 2 updates (#784) Bumps the github-actions group with 2 updates: [actions/checkout](https://github.com/actions/checkout) and [actions/setup-python](https://github.com/actions/setup-python). Updates `actions/checkout` from 6.0.1 to 6.0.2 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/8e8c483db84b4bee98b60c0593521ed34d9990e8...de0fac2e4500dabe0009e67214ff5f5447ce83dd) Updates `actions/setup-python` from 6.1.0 to 6.2.0 - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/83679a892e2d95755f2dac6acb0bfd1e9ac5d548...a309ff8b426b58ec0e2a45f0f869d46889d02405) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 6.0.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: actions/setup-python dependency-version: 6.2.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Hynek Schlawack --- .github/workflows/build-docset.yml | 4 ++-- .github/workflows/ci.yml | 20 ++++++++++---------- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/pypi-package.yml | 2 +- .github/workflows/zizmor.yml | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build-docset.yml b/.github/workflows/build-docset.yml index c6371f3e..5b11df16 100644 --- a/.github/workflows/build-docset.yml +++ b/.github/workflows/build-docset.yml @@ -16,11 +16,11 @@ jobs: docset: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 # get correct version persist-credentials: false - - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: "3.12" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bd6f1309..9c4b5b52 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 persist-credentials: false @@ -56,7 +56,7 @@ jobs: - run: | tar xf dist/*.tar.gz --strip-components=1 rm -rf src - - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: ${{ matrix.python-version }} allow-prereleases: true @@ -89,10 +89,10 @@ jobs: if: always() steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version-file: .python-version-default - uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817 # v2.3.0 @@ -135,7 +135,7 @@ jobs: name: Packages path: dist - run: tar xf dist/*.tar.gz --strip-components=1 - - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version-file: .python-version-default - uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817 # v2.3.0 @@ -155,7 +155,7 @@ jobs: name: Packages path: dist - run: tar xf dist/*.tar.gz --strip-components=1 - - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: # Keep in sync with tox.ini/docs & .readthedocs.yaml python-version: "3.13" @@ -173,10 +173,10 @@ jobs: os: [ubuntu-latest, windows-latest] steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version-file: .python-version-default - uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817 # v2.3.0 @@ -219,10 +219,10 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version-file: .python-version-default - uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817 # v2.3.0 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 61daa420..7354b61e 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false diff --git a/.github/workflows/pypi-package.yml b/.github/workflows/pypi-package.yml index e4102ad4..18bb85ee 100644 --- a/.github/workflows/pypi-package.yml +++ b/.github/workflows/pypi-package.yml @@ -21,7 +21,7 @@ jobs: id-token: write steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 persist-credentials: false diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index 32415236..eb21723f 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -19,7 +19,7 @@ jobs: security-events: write steps: - name: Checkout repository - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817 # v2.3.0 From 0c331c328567c6e9094fa083a7aad272516ae3c5 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 10 Feb 2026 17:41:53 +0100 Subject: [PATCH 1488/1520] sponsors: update URL --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index f4afa284..85085fad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -269,7 +269,7 @@ img = "FilePreviews.svg" [[tool.sponcon.sponsors]] title = "TestMu AI" -url = "https://www.testmu.ai/?utm_source=structlog&utm_medium=sponsor" +url = "https://www.testmuai.com/?utm_medium=sponsor&utm_source=structlog" img = "TestMu-AI.svg" [[tool.sponcon.sponsors]] From a223a6573f90a47558cd7bd897ff28864784c81f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 10 Feb 2026 17:43:17 +0100 Subject: [PATCH 1489/1520] Actually update --- README.md | 2 +- docs/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 989d0498..4d0ffa91 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ for sponsor in tomllib.loads(pathlib.Path("pyproject.toml").read_text())["tool"] - + diff --git a/docs/index.md b/docs/index.md index ac639a1e..18addaf3 100644 --- a/docs/index.md +++ b/docs/index.md @@ -24,7 +24,7 @@ for sponsor in tomllib.loads(pathlib.Path("pyproject.toml").read_text())["tool"] - + From 65ceffd6a2e3593005df7f5f9b439ad544fc053c Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sat, 21 Feb 2026 15:46:12 +0100 Subject: [PATCH 1490/1520] update dev --- .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/zizmor.yml | 2 +- .pre-commit-config.yaml | 4 ++-- src/structlog/dev.py | 6 ++---- tests/test_dev.py | 2 +- 5 files changed, 9 insertions(+), 11 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 7354b61e..e3575658 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -29,12 +29,12 @@ jobs: persist-credentials: false - name: Initialize CodeQL - uses: github/codeql-action/init@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v4.31.10 + uses: github/codeql-action/init@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v4.31.10 + uses: github/codeql-action/autobuild@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v4.31.10 + uses: github/codeql-action/analyze@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3 diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index eb21723f..1ba18644 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -30,7 +30,7 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload SARIF file - uses: github/codeql-action/upload-sarif@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v4.31.10 + uses: github/codeql-action/upload-sarif@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3 with: # Path to SARIF file relative to the root of the repository sarif_file: results.sarif diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2124aaa5..0ce02de8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.14.14 + rev: v0.15.2 hooks: - id: ruff-check args: [--fix, --exit-non-zero-on-fix] @@ -23,7 +23,7 @@ repos: args: [-L, alog, -L, abl, --skip=*.svg] - repo: https://github.com/abravalheri/validate-pyproject - rev: v0.24.1 + rev: v0.25 hooks: - id: validate-pyproject # Optional extra validations from SchemaStore: diff --git a/src/structlog/dev.py b/src/structlog/dev.py index ca982e14..110cdb51 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -356,7 +356,7 @@ def __init__( self.width = ( 0 if width == 0 - else len(max(self.level_styles.keys(), key=lambda e: len(e))) + else len(max(self.level_styles.keys(), key=len)) ) self.reset_style = reset_style else: @@ -819,9 +819,7 @@ def _configure_columns(self) -> None: for key in level_to_color: level_to_color[key] += self._styles.bright - self._longest_level = len( - max(level_to_color.keys(), key=lambda e: len(e)) - ) + self._longest_level = len(max(level_to_color.keys(), key=len)) self._default_column_formatter = KeyValueColumnFormatter( self._styles.kv_key, diff --git a/tests/test_dev.py b/tests/test_dev.py index 614472c6..fc825d8f 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -375,7 +375,7 @@ def test_exception_rendered( monkeypatch.setattr( cr, "_exception_formatter", - lambda s, ei: dev.plain_traceback(s, ei), + lambda s, ei: dev.plain_traceback(s, ei), # noqa: PLW0108 ) rv = cr(None, None, {"event": "test", "exception": exc}) From 3192da86b36a30546fa3d9221b9afdda928ef035 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 23 Feb 2026 16:10:33 +0100 Subject: [PATCH 1491/1520] Add AI policy --- .github/AI_POLICY.md | 71 +++++++++++++++++++++++++++++++++++++++++ .github/CONTRIBUTING.md | 10 ++++-- README.md | 1 + 3 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 .github/AI_POLICY.md diff --git a/.github/AI_POLICY.md b/.github/AI_POLICY.md new file mode 100644 index 00000000..4718250c --- /dev/null +++ b/.github/AI_POLICY.md @@ -0,0 +1,71 @@ +# Generative AI / LLM Policy + +We appreciate that we can't realistically police how you author your pull requests, which includes whether you employ large-language model (LLM)-based development tools. +So, we don't. + +However, due to both legal and human reasons, we have to establish boundaries. + +> [!CAUTION] +> **TL;DR:** +> - We take the responsibility for this project very seriously and we expect you to take your responsibility for your contributions seriously, too. +> This used to be a given, but it changed now that a pull request is just one prompt away. +> +> - Every contribution has to be backed by a human who unequivocally owns the copyright for all changes. +> No LLM bots in `Co-authored-by:`s. +> +> - DoS-by-slop leads to a permanent ban. +> +> - Absolutely **no** unsupervised agentic tools like OpenClaw. +> +> --- +> +> By submitting a pull request, you certify that: +> +> - You are the author of the contribution or have the legal right to submit it. +> - You either hold the copyright to the changes or have explicit legal authorization to contribute them under this project's license. +> - You understand the code. +> - You accept full responsibility for it. + + +## Legal + +There is ongoing legal uncertainty regarding the copyright status of LLM-generated works and their provenance. +Since we do not have a formal [Contributor License Agreement](https://en.wikipedia.org/wiki/Contributor_license_agreement) (CLA), you retain your copyright to your changes to this project. + +Therefore, allowing contributions by LLMs has unpredictable consequences for the copyright status of this project – even when leaving aside possible copyright violations due to plagiarism. + + +## Human + +As the makers of software that is used by millions of people worldwide and with a reputation for high-quality maintenance, we take our responsibility to our users very seriously. +No matter what LLM vendors or boosters on LinkedIn tell you, we have to manually review every change before merging, because it's **our responsibility** to keep the project stable. + +Please understand that by opening low-quality pull requests you're not helping anyone. +Worse, you're [poisoning the open source ecosystem](https://lwn.net/SubscriberLink/1058266/cfe99725c2855d66/) that was precarious even before the arrival of LLM tools. +Having to wade through plausible-looking-but-low-quality pull requests and trying to determine which ones are legit is extremely demoralizing and has already burned out many good maintainers. + +Put bluntly, we have no time or interest to become part of your vibe coding loop where you drop LLM slop at our door, we spend time and energy to review it, and you just feed it back into the LLM for another iteration. + +This dynamic is especially pernicious because it poisons the well for mentoring new contributors which we are committed to. + + +## Summary + +In practice, this means: + +- Pull requests that have an LLM product listed as co-author can't be merged and will be closed without further discussion. + We cannot risk the copyright status of this project. + + If you used LLM tools during development, you may still submit – but you must remove any LLM co-author tags and take full ownership of every line. + +- By submitting a pull request, **you** take full **technical and legal** responsibility for the contents of the pull request and promise that **you** hold the copyright for the changes submitted. + + "An LLM wrote it" is **not** an acceptable response to questions or critique. + **If you cannot explain and defend the changes you submit, do not submit them** and open a high-quality bug report/feature request instead. + +- Accounts that exercise bot-like behavior – like automated mass pull requests – will be permanently banned, whether they belong to a human or not. + +- Do **not** post LLM-generated review comments unless you agree with them. + Do **not** post summaries unless you take responsibility for 100% of their content. + Remember that *all* LLM output *looks* **plausible**. + When using these tools, it's **your** responsibility to ensure that it's also **correct**. diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 2d9104a2..f76dafb4 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,8 +1,10 @@ # How To Contribute > [!IMPORTANT] -> We do not care how you write your code, but you're taking full responsibility for it by submitting a pull request. -> Do not waste our time with LLM/"AI" slop that you don't understand yourself. +> - This document is mainly to help you to get started by codifying tribal knowledge and expectations and make it more accessible to everyone. +> But don't be afraid to open half-finished PRs and ask questions if something is unclear! +> +> - If you use LLM / "AI" tools for your contributions, please read and follow our [_Generative AI / LLM Policy_][llm]. ## Support @@ -21,6 +23,9 @@ It's people like *you* who make this project such a great tool for everyone. - No contribution is too small! Please submit as many fixes for typos and grammar bloopers as you can! +- **Only contribute code that you fully understand.** + See also our [AI policy][llm]. + - Try to limit each pull request to *one* change only (except for typos -- please group those). - Since we squash on merge, it's up to you how you handle updates to the `main` branch. @@ -241,3 +246,4 @@ Please report any harm to [Hynek Schlawack](https://hynek.me/about/) in any way [semantic newlines]: https://rhodesmill.org/brandon/2012/one-sentence-per-line/ +[llm]: AI_POLICY.md diff --git a/README.md b/README.md index 4d0ffa91..bda5d7ff 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ Documentation License: MIT / Apache 2.0 + No AI slop inside. DOI Supported Python versions of the current PyPI release. Downloads per month From 1c24de65d878b10d9546470e1669b63df413c328 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 23 Feb 2026 16:30:53 +0100 Subject: [PATCH 1492/1520] Link prominently --- .github/PULL_REQUEST_TEMPLATE.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index b63ad631..ed0595a2 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -13,19 +13,17 @@ But please read our [contribution guide](https://github.com/hynek/structlog/blob If an item doesn't apply to your pull request, **check it anyway** to make it apparent that there's nothing left to do. --> -- [ ] Do **not** open pull requests from your `main` branch – **use a separate branch**! - - There's a ton of footguns waiting if you don't heed this warning. You can still go back to your project, create a branch from your main branch, push it, and open the pull request from the new branch. - - This is not a pre-requisite for your pull request to be accepted, but **you have been warned**. -- [ ] Added **tests** for changed code. - - The CI fails with less than 100% coverage. +- [ ] I acknowledge this project's [**AI policy**](https://github.com/hynek/structlog/blob/main/.github/AI_POLICY.md). +- [ ] This pull requests is [**not** from my `main` branch](https://hynek.me/articles/pull-requests-branch/). + - Consider granting [push permissions to the PR branch](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork), so maintainers can fix minor issues themselves without pestering you. +- [ ] There's **tests** for all new and changed code. - [ ] **New APIs** are added to our typing tests in [`api.py`](https://github.com/hynek/structlog/blob/main/tests/typing/api.py). - [ ] Updated **documentation** for changed code. - [ ] New functions/classes have to be added to `docs/api.rst` by hand. - [ ] Changed/added classes/methods/functions have appropriate `versionadded`, `versionchanged`, or `deprecated` [directives](http://www.sphinx-doc.org/en/stable/markup/para.html#directive-versionadded). - - The next version is the second number in the current release + 1. The first number represents the current year. So if the current version on PyPI is 23.1.0, the next version is gonna be 23.2.0. If the next version is the first in the new year, it'll be 24.1.0. + - The next version is the second number in the current release + 1. The first number represents the current year. So if the current version on PyPI is 26.1.0, the next version is gonna be 26.2.0. If the next version is the first in the new year, it'll be 27.1.0. - [ ] Documentation in `.rst` and `.md` files is written using [**semantic newlines**](https://rhodesmill.org/brandon/2012/one-sentence-per-line/). - [ ] Changes (and possible deprecations) are documented in the [**changelog**](https://github.com/hynek/structlog/blob/main/CHANGELOG.md). -- [ ] Consider granting [push permissions to the PR branch](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork), so maintainers can fix minor issues themselves without pestering you. - [ ] I acknowledge this project's [**AI policy**](https://github.com/hynek/structlog/blob/main/.github/AI_POLICY.md). @@ -27,5 +29,5 @@ If an item doesn't apply to your pull request, **check it anyway** to make it ap From 8da644923454c953517f9f39dbeee93056212c52 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 27 Mar 2026 08:48:21 +0100 Subject: [PATCH 1501/1520] docs: tell about tags --- .github/CONTRIBUTING.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index f76dafb4..68ddf070 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -52,7 +52,11 @@ It's people like *you* who make this project such a great tool for everyone. ## Local development environment -First, **fork** the repository on GitHub and **clone** it using one of the alternatives that you can copy-paste by pressing the big green button labeled `<> Code`. +First, **fork** the repository on GitHub. +Make sure to **uncheck** the `Copy the main branch only` radio button on the `Create a new fork` page. +If you don't, our test suite will fail because we use Git tags for packaging. + +Finally, **clone** it using one of the alternatives that you can copy-paste by pressing the big green button labeled `<> Code`. You can (and should) run our test suite using [*tox*](https://tox.wiki/). However, you'll probably want a more traditional environment as well. From 294849e56508634e6d949e4d5ebc55ec4a315bbd Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 27 Mar 2026 08:53:12 +0100 Subject: [PATCH 1502/1520] Update dev --- .github/workflows/ci.yml | 2 +- .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/pypi-package.yml | 2 +- .github/workflows/zizmor.yml | 30 ++++++++++----------------- .pre-commit-config.yaml | 2 +- 5 files changed, 17 insertions(+), 25 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2acb9034..cae7f7ac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: fetch-depth: 0 persist-credentials: false - - uses: hynek/build-and-inspect-python-package@f3d069d0f9a3c9169d1a483318bb0e09876a6fd6 # v2.15.0 + - uses: hynek/build-and-inspect-python-package@fe0a0fb1925ca263d076ca4f2c13e93a6e92a33e # v2.17.0 id: baipp outputs: diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 127428f8..1df5c3b7 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -29,12 +29,12 @@ jobs: persist-credentials: false - name: Initialize CodeQL - uses: github/codeql-action/init@b1bff81932f5cdfc8695c7752dcee935dcd061c8 # v4.33.0 + uses: github/codeql-action/init@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@b1bff81932f5cdfc8695c7752dcee935dcd061c8 # v4.33.0 + uses: github/codeql-action/autobuild@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@b1bff81932f5cdfc8695c7752dcee935dcd061c8 # v4.33.0 + uses: github/codeql-action/analyze@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1 diff --git a/.github/workflows/pypi-package.yml b/.github/workflows/pypi-package.yml index 804164cf..0f4305d1 100644 --- a/.github/workflows/pypi-package.yml +++ b/.github/workflows/pypi-package.yml @@ -26,7 +26,7 @@ jobs: fetch-depth: 0 persist-credentials: false - - uses: hynek/build-and-inspect-python-package@f3d069d0f9a3c9169d1a483318bb0e09876a6fd6 # v2.15.0 + - uses: hynek/build-and-inspect-python-package@fe0a0fb1925ca263d076ca4f2c13e93a6e92a33e # v2.17.0 with: attest-build-provenance-github: 'true' diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index 6558827e..b8a75fc7 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -1,39 +1,31 @@ +--- # https://github.com/woodruffw/zizmor -name: Zizmor +name: Zizmor 🌈 on: push: branches: ["main"] pull_request: - branches: ["*"] + branches: ["**"] -permissions: - contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true +permissions: {} jobs: zizmor: - name: Zizmor latest via PyPI + name: Run zizmor 🌈 runs-on: ubuntu-latest permissions: - security-events: write + security-events: write # Required for upload-sarif (used by zizmor-action) to upload SARIF files. steps: - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - - uses: hynek/setup-cached-uv@0b9e52652c2d5d4fb6af4598efa3d14e60e934d1 # v2.4.0 - name: Run zizmor 🌈 - run: uvx zizmor --format sarif . > results.sarif - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Upload SARIF file - uses: github/codeql-action/upload-sarif@b1bff81932f5cdfc8695c7752dcee935dcd061c8 # v4.33.0 - with: - # Path to SARIF file relative to the root of the repository - sarif_file: results.sarif - # Optional category for the results - # Used to differentiate multiple results for one commit - category: zizmor + uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2 +... diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d67f4196..9c3fff80 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.15.6 + rev: v0.15.8 hooks: - id: ruff-check args: [--fix, --exit-non-zero-on-fix] From 0dd8ca570d48228d5985851680cd7f88ac154571 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 27 Mar 2026 08:55:24 +0100 Subject: [PATCH 1503/1520] ci: clamp concurrency --- .github/workflows/build-docset.yml | 4 ++++ .github/workflows/ci.yml | 4 ++++ .github/workflows/codeql-analysis.yml | 4 ++++ .github/workflows/pypi-package.yml | 3 +++ 4 files changed, 15 insertions(+) diff --git a/.github/workflows/build-docset.yml b/.github/workflows/build-docset.yml index 9c20b18a..5296643b 100644 --- a/.github/workflows/build-docset.yml +++ b/.github/workflows/build-docset.yml @@ -6,6 +6,10 @@ on: tags: ["*"] workflow_dispatch: +concurrency: + group: ${{ github.workflow }} + cancel-in-progress: true + env: PIP_DISABLE_PIP_VERSION_CHECK: 1 PIP_NO_PYTHON_VERSION_WARNING: 1 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cae7f7ac..903dd8d7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,6 +12,10 @@ env: PIP_DISABLE_PIP_VERSION_CHECK: "1" PIP_NO_PYTHON_VERSION_WARNING: "1" +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + permissions: {} jobs: diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 1df5c3b7..bdc78701 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -5,6 +5,10 @@ on: schedule: - cron: "41 3 * * 6" +concurrency: + group: ${{ github.workflow }} + cancel-in-progress: true + permissions: contents: read diff --git a/.github/workflows/pypi-package.yml b/.github/workflows/pypi-package.yml index 0f4305d1..7f6fce73 100644 --- a/.github/workflows/pypi-package.yml +++ b/.github/workflows/pypi-package.yml @@ -10,6 +10,9 @@ on: - published workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true jobs: # Always build & lint package. From 0fff862e08b1cd542eacf3ba2c655ad45daa6196 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 27 Mar 2026 04:40:41 -0400 Subject: [PATCH 1504/1520] ci: make workflows pass Zizmor in pedantic mode (#798) * ci: make workflows pass Zizmor in pedantic mode * Allow running CodeQL on demand * Add permission comment * Actually run in pedantic mode --- .github/workflows/build-docset.yml | 1 + .github/workflows/codeql-analysis.yml | 8 +++----- .github/workflows/pypi-package.yml | 10 ++++++---- .github/workflows/zizmor.yml | 2 ++ 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build-docset.yml b/.github/workflows/build-docset.yml index 5296643b..65fc69d2 100644 --- a/.github/workflows/build-docset.yml +++ b/.github/workflows/build-docset.yml @@ -18,6 +18,7 @@ permissions: {} jobs: docset: + name: Build docset runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index bdc78701..98496dd5 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -4,22 +4,20 @@ name: CodeQL on: schedule: - cron: "41 3 * * 6" + workflow_dispatch: concurrency: group: ${{ github.workflow }} cancel-in-progress: true -permissions: - contents: read +permissions: {} jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: - actions: read - contents: read - security-events: write + security-events: write # necessary according to docs strategy: fail-fast: false diff --git a/.github/workflows/pypi-package.yml b/.github/workflows/pypi-package.yml index 7f6fce73..32a74bd0 100644 --- a/.github/workflows/pypi-package.yml +++ b/.github/workflows/pypi-package.yml @@ -14,14 +14,16 @@ concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true +permissions: {} + jobs: # Always build & lint package. build-package: name: Build & verify package runs-on: ubuntu-latest permissions: - attestations: write - id-token: write + attestations: write # necessary for GitHub attestations + id-token: write # necessary for GitHub attestations steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -42,7 +44,7 @@ jobs: needs: build-package permissions: - id-token: write + id-token: write # necessary for trusted publishing steps: - name: Download packages built by build-and-inspect-python-package @@ -65,7 +67,7 @@ jobs: needs: build-package permissions: - id-token: write + id-token: write # necessary for trusted publishing steps: - name: Download packages built by build-and-inspect-python-package diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index b8a75fc7..bad2095b 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -28,4 +28,6 @@ jobs: - name: Run zizmor 🌈 uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2 + with: + persona: pedantic ... From 599fb22e271bbfa9c6951f26ea514b43ab7b2835 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 27 Mar 2026 11:48:09 +0100 Subject: [PATCH 1505/1520] update dev --- .github/workflows/ci.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 903dd8d7..76551237 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -64,7 +64,7 @@ jobs: with: python-version: ${{ matrix.python-version }} allow-prereleases: true - - uses: hynek/setup-cached-uv@0b9e52652c2d5d4fb6af4598efa3d14e60e934d1 # v2.4.0 + - uses: hynek/setup-cached-uv@4300ec2180bc77d705e626a34e381b81a4772c51 # v2.5.0 - name: Run tests run: > @@ -99,7 +99,7 @@ jobs: - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version-file: .python-version-default - - uses: hynek/setup-cached-uv@0b9e52652c2d5d4fb6af4598efa3d14e60e934d1 # v2.4.0 + - uses: hynek/setup-cached-uv@4300ec2180bc77d705e626a34e381b81a4772c51 # v2.5.0 - name: Download coverage data uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 @@ -142,7 +142,7 @@ jobs: - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version-file: .python-version-default - - uses: hynek/setup-cached-uv@0b9e52652c2d5d4fb6af4598efa3d14e60e934d1 # v2.4.0 + - uses: hynek/setup-cached-uv@4300ec2180bc77d705e626a34e381b81a4772c51 # v2.5.0 - run: > uvx --with tox-uv @@ -163,7 +163,7 @@ jobs: with: # Keep in sync with tox.ini/docs & .readthedocs.yaml python-version: "3.13" - - uses: hynek/setup-cached-uv@0b9e52652c2d5d4fb6af4598efa3d14e60e934d1 # v2.4.0 + - uses: hynek/setup-cached-uv@4300ec2180bc77d705e626a34e381b81a4772c51 # v2.5.0 - run: > uvx --with tox-uv @@ -183,7 +183,7 @@ jobs: - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version-file: .python-version-default - - uses: hynek/setup-cached-uv@0b9e52652c2d5d4fb6af4598efa3d14e60e934d1 # v2.4.0 + - uses: hynek/setup-cached-uv@4300ec2180bc77d705e626a34e381b81a4772c51 # v2.5.0 - run: uv venv - run: uv pip install -e . --group dev @@ -229,7 +229,7 @@ jobs: - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version-file: .python-version-default - - uses: hynek/setup-cached-uv@0b9e52652c2d5d4fb6af4598efa3d14e60e934d1 # v2.4.0 + - uses: hynek/setup-cached-uv@4300ec2180bc77d705e626a34e381b81a4772c51 # v2.5.0 - run: > uvx --with=tox-uv From d0e0f842ee9a12a42bb3d770e87e5f543d6bd3de Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 29 Mar 2026 08:31:18 +0200 Subject: [PATCH 1506/1520] Consistent endashes --- .github/AI_POLICY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/AI_POLICY.md b/.github/AI_POLICY.md index d943904e..41352d78 100644 --- a/.github/AI_POLICY.md +++ b/.github/AI_POLICY.md @@ -65,7 +65,7 @@ In practice, this means: - Accounts that exercise bot-like behavior – like automated mass pull requests – will be permanently banned, whether they belong to a human or not. -- Do **not** post LLM-generated review comments -- we can prompt LLMs ourselves should we desire their wisdom. +- Do **not** post LLM-generated review comments – we can prompt LLMs ourselves should we desire their wisdom. Do **not** post summaries unless you've fact-checked them and take responsibility for 100% of their content. Remember that *all* LLM output *looks* **plausible**. When using these tools, it's **your** responsibility to ensure that it's also **correct** and has a reasonable signal-to-noise ratio. From 41b008fe0d0ae1c351f4bb983f45fe598b8f4bed Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 29 Mar 2026 11:32:12 +0200 Subject: [PATCH 1507/1520] dev: simplify by modernizing tox --- .python-version-default | 2 +- tox.ini | 14 ++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/.python-version-default b/.python-version-default index 24ee5b1b..6324d401 100644 --- a/.python-version-default +++ b/.python-version-default @@ -1 +1 @@ -3.13 +3.14 diff --git a/tox.ini b/tox.ini index cee42cbd..69a2fa6e 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,7 @@ [tox] -min_version = 4.25 +requires = + tox>=4.51.0 + tox-uv env_list = pre-commit, py3{9-14}-{tests,mypy} @@ -34,17 +36,14 @@ commands = coverage run -m pytest {posargs} # Split combine/report in 2 to avoid excessive "Combined data file ..." output. [testenv:coverage-combine] -# Keep base_python in-sync with .python-version-default -base_python = py313 -# Keep in-sync with test env definition above. -depends = py3{9,13}-tests{,-colorama,-be,-rich} +base_python_file = .python-version-default +depends = py3*-tests* skip_install = true deps = coverage commands = coverage combine [testenv:coverage-report] -# Keep base_python in-sync with .python-version-default -base_python = py313 +base_python_file = .python-version-default depends = coverage-combine parallel_show_output = true skip_install = true @@ -52,7 +51,6 @@ deps = coverage commands = coverage report - [testenv:docs-{build,doctests,linkcheck}] # Keep base_python in sync with ci.yml/docs and .readthedocs.yaml. base_python = py313 From 15a4c48637eb61664216aaebfc743460117124a2 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 29 Mar 2026 08:34:55 -0400 Subject: [PATCH 1508/1520] Drop 3.9 (#800) * Drop 3.9 * Annotate type aliases as such * better-exceptions crashes on 3.14 but only on Linux?? * Explain why not actually latest --- CHANGELOG.md | 3 ++- pyproject.toml | 3 +-- src/structlog/_config.py | 4 ++-- src/structlog/_frames.py | 2 +- src/structlog/_native.py | 3 ++- src/structlog/dev.py | 3 +-- src/structlog/processors.py | 3 +-- src/structlog/stdlib.py | 4 ++-- src/structlog/tracebacks.py | 4 ++-- src/structlog/twisted.py | 4 ++-- src/structlog/typing.py | 28 +++++++++++++++------------- tests/test_stdlib.py | 4 ++-- tests/typing/api.py | 3 ++- tox.ini | 14 +++++++------- 14 files changed, 42 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07cd14b4..2d525eb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,8 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ### Removed -- Python 3.8 support. +- Python 3.8 and 3.9 support. + ### Changed diff --git a/pyproject.toml b/pyproject.toml index 85085fad..bdfc5143 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,14 +10,13 @@ dynamic = ["readme", "version"] name = "structlog" description = "Structured Logging for Python" authors = [{ name = "Hynek Schlawack", email = "hs@ox.cx" }] -requires-python = ">=3.9" +requires-python = ">=3.10" license = "MIT OR Apache-2.0" keywords = ["logging", "structured", "structure", "log"] classifiers = [ "Development Status :: 5 - Production/Stable", "License :: OSI Approved :: Apache Software License", "License :: OSI Approved :: MIT License", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", diff --git a/src/structlog/_config.py b/src/structlog/_config.py index dd5c3d0a..22fa589f 100644 --- a/src/structlog/_config.py +++ b/src/structlog/_config.py @@ -13,8 +13,8 @@ import sys import warnings -from collections.abc import Iterable, Sequence -from typing import Any, Callable, cast +from collections.abc import Callable, Iterable, Sequence +from typing import Any, cast from ._native import make_filtering_bound_logger from ._output import PrintLoggerFactory diff --git a/src/structlog/_frames.py b/src/structlog/_frames.py index 57841afd..dbd15d9c 100644 --- a/src/structlog/_frames.py +++ b/src/structlog/_frames.py @@ -8,9 +8,9 @@ import sys import traceback +from collections.abc import Callable from io import StringIO from types import FrameType -from typing import Callable from .contextvars import _ASYNC_CALLING_STACK from .typing import ExcInfo diff --git a/src/structlog/_native.py b/src/structlog/_native.py index 4d0926de..368779d8 100644 --- a/src/structlog/_native.py +++ b/src/structlog/_native.py @@ -14,7 +14,8 @@ import contextvars import sys -from typing import Any, Callable +from collections.abc import Callable +from typing import Any from ._base import BoundLoggerBase from ._log_levels import ( diff --git a/src/structlog/dev.py b/src/structlog/dev.py index b14eb39a..0f08d7aa 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -14,13 +14,12 @@ import sys import warnings -from collections.abc import Sequence +from collections.abc import Callable, Sequence from dataclasses import dataclass from io import StringIO from types import ModuleType from typing import ( Any, - Callable, Literal, Protocol, TextIO, diff --git a/src/structlog/processors.py b/src/structlog/processors.py index 80841561..34406ad9 100644 --- a/src/structlog/processors.py +++ b/src/structlog/processors.py @@ -19,11 +19,10 @@ import threading import time -from collections.abc import Collection, Sequence +from collections.abc import Callable, Collection, Sequence from types import FrameType, TracebackType from typing import ( Any, - Callable, ClassVar, NamedTuple, TextIO, diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 2ed978fd..46758146 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -18,9 +18,9 @@ import sys import warnings -from collections.abc import Collection, Iterable, Sequence +from collections.abc import Callable, Collection, Iterable, Sequence from functools import partial -from typing import Any, Callable, cast +from typing import Any, cast if sys.version_info >= (3, 11): diff --git a/src/structlog/tracebacks.py b/src/structlog/tracebacks.py index f73f7971..b9c9855a 100644 --- a/src/structlog/tracebacks.py +++ b/src/structlog/tracebacks.py @@ -22,7 +22,7 @@ from dataclasses import asdict, dataclass, field from traceback import walk_tb from types import ModuleType, TracebackType -from typing import Any, Union +from typing import Any, TypeAlias try: @@ -51,7 +51,7 @@ LOCALS_MAX_STRING = 80 MAX_FRAMES = 50 -OptExcInfo = Union[ExcInfo, tuple[None, None, None]] +OptExcInfo: TypeAlias = ExcInfo | tuple[None, None, None] @dataclass diff --git a/src/structlog/twisted.py b/src/structlog/twisted.py index 1752cb27..15d0a262 100644 --- a/src/structlog/twisted.py +++ b/src/structlog/twisted.py @@ -15,8 +15,8 @@ import json import sys -from collections.abc import Sequence -from typing import Any, Callable, TextIO +from collections.abc import Callable, Sequence +from typing import Any, TextIO from twisted.python import log from twisted.python.failure import Failure diff --git a/src/structlog/typing.py b/src/structlog/typing.py index 2cfd9cb2..136567e9 100644 --- a/src/structlog/typing.py +++ b/src/structlog/typing.py @@ -16,15 +16,13 @@ import sys -from collections.abc import Mapping, MutableMapping +from collections.abc import Callable, Mapping, MutableMapping from types import TracebackType from typing import ( Any, - Callable, - Optional, Protocol, TextIO, - Union, + TypeAlias, runtime_checkable, ) @@ -35,7 +33,7 @@ from typing_extensions import Self -WrappedLogger = Any +WrappedLogger: TypeAlias = Any """ A logger that is wrapped by a bound logger and is ultimately responsible for the output of the log entries. @@ -46,7 +44,7 @@ """ -Context = Union[dict[str, Any], dict[Any, Any]] +Context: TypeAlias = dict[str, Any] | dict[Any, Any] """ A dict-like context carrier. @@ -54,7 +52,7 @@ """ -EventDict = MutableMapping[str, Any] +EventDict: TypeAlias = MutableMapping[str, Any] """ An event dictionary as it is passed into processors. @@ -64,14 +62,16 @@ .. versionadded:: 20.2.0 """ -ProcessorReturnValue = Union[ - Mapping[str, Any], str, bytes, bytearray, tuple[Any, ...] -] +ProcessorReturnValue: TypeAlias = ( + Mapping[str, Any] | str | bytes | bytearray | tuple[Any, ...] +) """ A value returned by a processor. """ -Processor = Callable[[WrappedLogger, str, EventDict], ProcessorReturnValue] +Processor: TypeAlias = Callable[ + [WrappedLogger, str, EventDict], ProcessorReturnValue +] """ A callable that is part of the processor chain. @@ -80,7 +80,9 @@ .. versionadded:: 20.2.0 """ -ExcInfo = tuple[type[BaseException], BaseException, Optional[TracebackType]] +ExcInfo: TypeAlias = tuple[ + type[BaseException], BaseException, TracebackType | None +] """ An exception info tuple as returned by `sys.exc_info`. @@ -88,7 +90,7 @@ """ -ExceptionRenderer = Callable[[TextIO, ExcInfo], None] +ExceptionRenderer: TypeAlias = Callable[[TextIO, ExcInfo], None] """ A callable that pretty-prints an `ExcInfo` into a file-like object. diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index f54ae6b2..862e6f60 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -11,9 +11,9 @@ import os import sys -from collections.abc import Collection +from collections.abc import Callable, Collection from io import StringIO -from typing import Any, Callable +from typing import Any from unittest.mock import patch import pytest diff --git a/tests/typing/api.py b/tests/typing/api.py index 8d850e06..91041329 100644 --- a/tests/typing/api.py +++ b/tests/typing/api.py @@ -12,7 +12,8 @@ import logging import logging.config -from typing import Any, Callable +from collections.abc import Callable +from typing import Any import structlog diff --git a/tox.ini b/tox.ini index 69a2fa6e..1d00fddc 100644 --- a/tox.ini +++ b/tox.ini @@ -4,8 +4,8 @@ requires = tox-uv env_list = pre-commit, - py3{9-14}-{tests,mypy} - py3{9,13}-tests-{colorama,be,rich}, + py31{0-4}-{tests,mypy} + py31{0,3}-tests-{colorama,be,rich}, typing-{mypy,pyright,ty,pyrefly}, docs-{sponsors,build,doctests}, coverage-{combine,report} @@ -23,8 +23,9 @@ commands = # Run oldest and latest under Coverage. -# Keep in-sync with coverage `depends below. -[testenv:py3{9,13}-tests{,-colorama,-be,-rich}] +# Currently we're tied to 3.13 b/c better-exceptions doesn't run on later +# versions. +[testenv:py31{0,3}-tests{,-colorama,-be,-rich}] deps = coverage[toml] py313: twisted @@ -37,7 +38,7 @@ commands = coverage run -m pytest {posargs} # Split combine/report in 2 to avoid excessive "Combined data file ..." output. [testenv:coverage-combine] base_python_file = .python-version-default -depends = py3*-tests* +depends = *-tests* skip_install = true deps = coverage commands = coverage combine @@ -87,8 +88,7 @@ commands = prek run --all-files [testenv:typing-{pyright,ty,mypy,pyrefly}] description = Type-check the package. -# Keep base_python in-sync with .python-version-default -base_python = py313 +base_python_file = .python-version-default dependency_groups = typing deps = pyrefly: pyrefly From 75d65cf6d4e12d346ed116b064a765b6dd79ed5d Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 29 Mar 2026 14:36:37 +0200 Subject: [PATCH 1509/1520] dev: use new-style tox versions --- .github/workflows/ci.yml | 4 ++-- tox.ini | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 76551237..96f06077 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -70,7 +70,7 @@ jobs: run: > uvx --with tox-uv tox run --installpkg dist/*.whl - -f py${PYTHON//./}-tests + -f ${PYTHON}-tests - name: Upload coverage data uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 @@ -84,7 +84,7 @@ jobs: run: > uvx --with tox-uv tox run --installpkg dist/*.whl - -e py${PYTHON//./}-mypy + -e ${PYTHON}-mypy coverage: name: Ensure 100% test coverage diff --git a/tox.ini b/tox.ini index 1d00fddc..82a80f0e 100644 --- a/tox.ini +++ b/tox.ini @@ -4,8 +4,8 @@ requires = tox-uv env_list = pre-commit, - py31{0-4}-{tests,mypy} - py31{0,3}-tests-{colorama,be,rich}, + 3.1{0-4}-{tests,mypy} + 3.1{0,3}-tests-{colorama,be,rich}, typing-{mypy,pyright,ty,pyrefly}, docs-{sponsors,build,doctests}, coverage-{combine,report} @@ -25,10 +25,10 @@ commands = # Run oldest and latest under Coverage. # Currently we're tied to 3.13 b/c better-exceptions doesn't run on later # versions. -[testenv:py31{0,3}-tests{,-colorama,-be,-rich}] +[testenv:3.1{0,3}-tests{,-colorama,-be,-rich}] deps = coverage[toml] - py313: twisted + 3.13: twisted colorama: colorama rich: rich be: better-exceptions @@ -54,7 +54,7 @@ commands = coverage report [testenv:docs-{build,doctests,linkcheck}] # Keep base_python in sync with ci.yml/docs and .readthedocs.yaml. -base_python = py313 +base_python = 3.13 dependency_groups = docs commands = # N.B. doctests is not a nitpicky as build -- we need to run both in CI! From 372b7023cc8c1073b5993ac34eba9cd9c665886f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 29 Mar 2026 14:42:10 +0200 Subject: [PATCH 1510/1520] Fix coverage --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index bdfc5143..743ea513 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -90,7 +90,7 @@ branch = true source = ["structlog"] [tool.coverage.paths] -source = ["src", ".tox/py*/**/site-packages"] +source = ["src", ".tox/3.*tests*/**/site-packages"] [tool.coverage.report] show_missing = true From 2c059a0dc029d9370e1e4a6e9683063205bbb68f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 29 Mar 2026 09:01:39 -0400 Subject: [PATCH 1511/1520] Build docs on 3.14 (#801) --- .github/workflows/ci.yml | 2 +- .readthedocs.yaml | 2 +- tox.ini | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 96f06077..b144f862 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -162,7 +162,7 @@ jobs: - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: # Keep in sync with tox.ini/docs & .readthedocs.yaml - python-version: "3.13" + python-version: "3.14" - uses: hynek/setup-cached-uv@4300ec2180bc77d705e626a34e381b81a4772c51 # v2.5.0 - run: > diff --git a/.readthedocs.yaml b/.readthedocs.yaml index d58ce338..e310563c 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -5,7 +5,7 @@ build: os: ubuntu-lts-latest tools: # Keep version in sync with tox.ini/docs and ci.yml/docs. - python: "3.13" + python: "3.14" jobs: create_environment: # Need the tags to calculate the version (sometimes). diff --git a/tox.ini b/tox.ini index 82a80f0e..bff1fd7f 100644 --- a/tox.ini +++ b/tox.ini @@ -54,7 +54,7 @@ commands = coverage report [testenv:docs-{build,doctests,linkcheck}] # Keep base_python in sync with ci.yml/docs and .readthedocs.yaml. -base_python = 3.13 +base_python = 3.14 dependency_groups = docs commands = # N.B. doctests is not a nitpicky as build -- we need to run both in CI! From f0b2487050d26b1c40c48fbe29e563ae1258047e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 29 Mar 2026 09:31:53 -0400 Subject: [PATCH 1512/1520] Deprecate better-exceptions integration (#802) * Deprecate better-exceptions integration * Add CL entry * Typography --- CHANGELOG.md | 7 +++++++ docs/console-output.md | 6 +++--- docs/exceptions.md | 12 ++++++------ docs/getting-started.md | 7 +++---- src/structlog/dev.py | 29 +++++++++++++++++++++-------- tests/test_dev.py | 14 +++++++++++++- 6 files changed, 53 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d525eb8..f177a6bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,13 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - Python 3.8 and 3.9 support. +### Deprecated + +- Support for *better-exceptions* is deprecated and will be removed within a year. + Use our Rich integration or copy-paste the [one line of code you need](https://github.com/hynek/structlog/blob/2c059a0dc029d9370e1e4a6e9683063205bbb68f/src/structlog/dev.py#L488-L498). + [#802](https://github.com/hynek/structlog/pull/802) + + ### Changed - `structlog.dev.ConsoleRenderer` does not warn anymore when the `exception` key has a rendered value despite having a fancy formatter configured. diff --git a/docs/console-output.md b/docs/console-output.md index 8be4619c..4bbb3689 100644 --- a/docs/console-output.md +++ b/docs/console-output.md @@ -6,8 +6,8 @@ The highlight is {class}`structlog.dev.ConsoleRenderer` that offers nicely align [^win]: Requires the [Colorama package](https://pypi.org/project/colorama/) on Windows. -If either of the [Rich](https://rich.readthedocs.io/) or [*better-exceptions*](https://github.com/Qix-/better-exceptions) packages is installed, it will also pretty-print exceptions with helpful contextual data. -Rich takes precedence over *better-exceptions*, but you can configure it by passing {func}`structlog.dev.plain_traceback` or {func}`structlog.dev.better_traceback` for the `exception_formatter` parameter of {class}`~structlog.dev.ConsoleRenderer`. +If the [Rich](https://rich.readthedocs.io/) package is installed, it will also pretty-print exceptions with helpful contextual data. +You can configure it by passing {func}`structlog.dev.plain_traceback` or an instance of {class}`~structlog.dev.RichTracebackFormatter` for the `exception_formatter` parameter of {class}`~structlog.dev.ConsoleRenderer`. The following output is rendered using Rich: @@ -26,7 +26,7 @@ It will recognize logger names, log levels, time stamps, stack infos, and `exc_i For pretty exceptions to work, {func}`~structlog.processors.format_exc_info` must be **absent** from the processors chain. ::: -*structlog*'s default configuration already uses {class}`~structlog.dev.ConsoleRenderer`, therefore if you want nice colorful output on the console, you don't have to do anything except installing Rich or *better-exceptions* (and Colorama on Windows). +*structlog*'s default configuration already uses {class}`~structlog.dev.ConsoleRenderer`, therefore if you want nice colorful output on the console, you don't have to do anything except installing Rich (and Colorama on Windows). If you want to use it along with standard library logging, there's the {func}`structlog.stdlib.recreate_defaults` helper. :::{seealso} diff --git a/docs/exceptions.md b/docs/exceptions.md index 7fe452ec..84f7fc0d 100644 --- a/docs/exceptions.md +++ b/docs/exceptions.md @@ -33,14 +33,9 @@ Our {doc}`console-output`'s {class}`structlog.dev.ConsoleRenderer` takes an *exc {func}`structlog.dev.plain_traceback` -: Is the default if neither [Rich] nor [*better-exceptions*] are installed. +: Is the default if [Rich] is not installed. As the name suggests, it renders a plain traceback. -{func}`structlog.dev.better_traceback` - -: Uses [*better-exceptions*] to render a colorful traceback. -: It's the default if *better-exceptions* is installed and Rich is not. - {class}`structlog.dev.RichTracebackFormatter` : Uses [Rich] to render a colorful traceback. @@ -51,5 +46,10 @@ Our {doc}`console-output`'s {class}`structlog.dev.ConsoleRenderer` takes an *exc {doc}`console-output` for more information on *structlog*'s console features. ::: +:::{deprecated} 26.1.0 +Support for [*better-exceptions*] is deprecated and will be removed in a future release. +Use [Rich] instead. +::: + [*better-exceptions*]: https://github.com/qix-/better-exceptions [Rich]: https://github.com/Textualize/rich diff --git a/docs/getting-started.md b/docs/getting-started.md index 161c0078..5aeaf2e2 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -10,8 +10,8 @@ You can install *structlog* from [PyPI](https://pypi.org/project/structlog/) usi $ python -m pip install structlog ``` -If you want pretty exceptions in development (you know you do!), additionally install either [Rich] or [*better-exceptions*]. -Try both to find out which one you like better -- the screenshot in the README and docs homepage is rendered by Rich. +If you want pretty exceptions in development (you know you do!), additionally install [Rich]. +The screenshot in the README and docs homepage is rendered by Rich. On **Windows**, you also have to install [Colorama](https://pypi.org/project/colorama/) if you want colorful output beside exceptions. @@ -46,7 +46,7 @@ Here, *structlog* takes advantage of its default settings: - It's rendered in nice **{doc}`colors `**. -- If you have [Rich] or [*better-exceptions*] installed, **exceptions** will be rendered in **colors** and with additional **helpful information**. +- If you have [Rich] installed, **exceptions** will be rendered in **colors** and with additional **helpful information**. Please note that even in most complex logging setups the example would still look just like that thanks to {doc}`configuration`. Using the defaults, as above, is equivalent to: @@ -258,6 +258,5 @@ Now you're all set for the rest of the user's guide and can start reading about :end-before: ``` -[*better-exceptions*]: https://github.com/qix-/better-exceptions [recipe]: https://docs.python.org/3/howto/logging-cookbook.html#implementing-structured-logging [Rich]: https://github.com/Textualize/rich diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 0f08d7aa..c521ea17 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -494,7 +494,16 @@ def better_traceback(sio: TextIO, exc_info: ExcInfo) -> None: Used by default if *better-exceptions* is installed and Rich is absent. .. versionadded:: 21.2.0 + .. deprecated:: 26.1.0 + *better-exceptions* support is deprecated and will be removed in a + future release. Use Rich instead. """ + warnings.warn( + "better-exceptions support is deprecated and will be removed " + "in a future release. Use Rich instead.", + DeprecationWarning, + stacklevel=2, + ) sio.write("\n" + "".join(better_exceptions.format_exception(*exc_info))) @@ -502,6 +511,12 @@ def better_traceback(sio: TextIO, exc_info: ExcInfo) -> None: default_exception_formatter = rich_traceback elif better_exceptions is not None: default_exception_formatter = better_traceback + warnings.warn( + "better-exceptions support is deprecated and will be removed " + "in a future release. Use Rich instead.", + DeprecationWarning, + stacklevel=2, + ) else: default_exception_formatter = plain_traceback @@ -511,8 +526,8 @@ class ConsoleRenderer: Render ``event_dict`` nicely aligned, possibly in colors, and ordered. If ``event_dict`` contains a true-ish ``exc_info`` key, it will be rendered - *after* the log line. If Rich_ or better-exceptions_ are present, in colors - and with extra context. + *after* the log line. If Rich_ is present, in colors and with extra + context. Tip: Since `ConsoleRenderer` is mainly a development helper, it is less @@ -558,12 +573,10 @@ class ConsoleRenderer: are passed. exception_formatter: - A callable to render ``exc_infos``. If Rich_ or better-exceptions_ - are installed, they are used for pretty-printing by default (rich_ - taking precedence). You can also manually set it to - `plain_traceback`, `better_traceback`, an instance of - `RichTracebackFormatter` like `rich_traceback`, or implement your - own. + A callable to render ``exc_infos``. If Rich_ is installed, it is + used for pretty-printing by default. You can also manually set it + to `plain_traceback`, an instance of `RichTracebackFormatter` like + `rich_traceback`, or implement your own. sort_keys: Whether to sort keys when formatting. `True` by default. Ignored if diff --git a/tests/test_dev.py b/tests/test_dev.py index 7c6a20ba..45b07569 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -865,10 +865,22 @@ def test_does_not_blow_up(self): try: 0 / 0 except ZeroDivisionError: - dev.better_traceback(sio, sys.exc_info()) + with pytest.warns(DeprecationWarning, match="better-exceptions"): + dev.better_traceback(sio, sys.exc_info()) assert sio.getvalue().startswith("\n") + def test_deprecation_warning(self): + """ + better_traceback emits a DeprecationWarning. + """ + sio = StringIO() + try: + 0 / 0 + except ZeroDivisionError: + with pytest.warns(DeprecationWarning, match="better-exceptions"): + dev.better_traceback(sio, sys.exc_info()) + class TestLogLevelColumnFormatter: def test_no_style(self): From 413a4f5f1ac8940f68748c22a0307bd5208ff4b6 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 29 Mar 2026 15:39:49 +0200 Subject: [PATCH 1513/1520] typing: remove pointless union --- src/structlog/typing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/typing.py b/src/structlog/typing.py index 136567e9..f009a4b9 100644 --- a/src/structlog/typing.py +++ b/src/structlog/typing.py @@ -44,7 +44,7 @@ """ -Context: TypeAlias = dict[str, Any] | dict[Any, Any] +Context: TypeAlias = dict[Any, Any] """ A dict-like context carrier. From fe4ded11c743b50110f8be80d31b220156ff3f8b Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Sun, 29 Mar 2026 15:51:41 +0200 Subject: [PATCH 1514/1520] Fix ignore --- src/structlog/threadlocal.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/structlog/threadlocal.py b/src/structlog/threadlocal.py index c36df3df..c712f551 100644 --- a/src/structlog/threadlocal.py +++ b/src/structlog/threadlocal.py @@ -120,8 +120,8 @@ def as_immutable(logger: TLLogger) -> TLLogger: logger = logger.bind() try: - ctx = logger._context._tl.dict_.__class__( # type: ignore[union-attr] - logger._context._dict # type: ignore[union-attr] + ctx = logger._context._tl.dict_.__class__( # type: ignore[attr-defined] + logger._context._dict # type: ignore[attr-defined] ) bl = logger.__class__( logger._logger, # type: ignore[attr-defined, call-arg] From 0465576e62ade162983b41799ed7155c37ee50ae Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 30 Mar 2026 19:13:02 +0200 Subject: [PATCH 1515/1520] Add Klaviyo --- README.md | 1 + docs/_static/sponsors/Klaviyo.svg | 1 + docs/index.md | 1 + pyproject.toml | 5 +++++ 4 files changed, 8 insertions(+) create mode 100644 docs/_static/sponsors/Klaviyo.svg diff --git a/README.md b/README.md index bda5d7ff..0ee22819 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ for sponsor in tomllib.loads(pathlib.Path("pyproject.toml").read_text())["tool"] + diff --git a/docs/_static/sponsors/Klaviyo.svg b/docs/_static/sponsors/Klaviyo.svg new file mode 100644 index 00000000..6c7449bc --- /dev/null +++ b/docs/_static/sponsors/Klaviyo.svg @@ -0,0 +1 @@ + diff --git a/docs/index.md b/docs/index.md index 18addaf3..9927c955 100644 --- a/docs/index.md +++ b/docs/index.md @@ -23,6 +23,7 @@ for sponsor in tomllib.loads(pathlib.Path("pyproject.toml").read_text())["tool"] + diff --git a/pyproject.toml b/pyproject.toml index 743ea513..c2397643 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -261,6 +261,11 @@ title = "Privacy Solutions" url = "https://privacy-solutions.org/" img = "Privacy-Solutions.svg" +[[tool.sponcon.sponsors]] +title = "Klaviyo" +url = "https://klaviyo.com/" +img = "Klaviyo.svg" + [[tool.sponcon.sponsors]] title = "FilePreviews" url = "https://filepreviews.io/" From ff616475088df33f451722795ce4405208e9f0a9 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 30 Mar 2026 19:56:01 +0200 Subject: [PATCH 1516/1520] Upload to PyPI with attestations --- .github/workflows/pypi-package.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/pypi-package.yml b/.github/workflows/pypi-package.yml index 32a74bd0..f57079ee 100644 --- a/.github/workflows/pypi-package.yml +++ b/.github/workflows/pypi-package.yml @@ -78,3 +78,5 @@ jobs: - name: Upload package to PyPI uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0 + with: + attestations: true From c27a5281c3234939cf5a219b4359d06bc126ba8a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 1 Apr 2026 13:49:35 +0200 Subject: [PATCH 1517/1520] Update contributing guide --- .github/CONTRIBUTING.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 68ddf070..2e64d708 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -26,6 +26,9 @@ It's people like *you* who make this project such a great tool for everyone. - **Only contribute code that you fully understand.** See also our [AI policy][llm]. +- Very relatedly, our pull request check list is our mandatory [Van Halen test](https://en.wikipedia.org/wiki/Van_Halen_test). + Sadly, the current state of the world has forced us into being stricter about policies -- sorry fellow humans! + - Try to limit each pull request to *one* change only (except for typos -- please group those). - Since we squash on merge, it's up to you how you handle updates to the `main` branch. @@ -58,7 +61,7 @@ If you don't, our test suite will fail because we use Git tags for packaging. Finally, **clone** it using one of the alternatives that you can copy-paste by pressing the big green button labeled `<> Code`. -You can (and should) run our test suite using [*tox*](https://tox.wiki/). +You can (and should) run our test suite using [*tox*](https://tox.wiki/) (and keep in mind that `tox run-parallel` is about 5x faster than `tox run`). However, you'll probably want a more traditional environment as well. We recommend using the Python version from the `.python-version-default` file in the project's root directory, because that's the one that is used in the CI by default, too. From 572ce58a58336099ac1c62f9218b97c08daf3f22 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 1 Apr 2026 13:51:33 +0200 Subject: [PATCH 1518/1520] Update dev --- .github/workflows/codeql-analysis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 98496dd5..319f0426 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -31,12 +31,12 @@ jobs: persist-credentials: false - name: Initialize CodeQL - uses: github/codeql-action/init@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1 + uses: github/codeql-action/init@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1 + uses: github/codeql-action/autobuild@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1 + uses: github/codeql-action/analyze@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1 From 0f0150abe53f8c22efd63ae160f5ead7292db16e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Wed, 1 Apr 2026 13:51:41 +0200 Subject: [PATCH 1519/1520] Mypy error changed --- src/structlog/stdlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 46758146..bf0a2083 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -93,7 +93,7 @@ def recreate_defaults(*, log_level: int | None = logging.NOTSET) -> None: format="%(message)s", stream=sys.stdout, level=log_level, - **kw, # type: ignore[arg-type] + **kw, # type: ignore[call-overload] ) _config.reset_defaults() From 92fd882817a8e6aae192cfe6266fded2d597f522 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 6 Apr 2026 19:45:37 +0200 Subject: [PATCH 1520/1520] [pre-commit.ci] pre-commit autoupdate (#803) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9c3fff80..394c1e19 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.15.8 + rev: v0.15.9 hooks: - id: ruff-check args: [--fix, --exit-non-zero-on-fix]

    X6s_54d1{Iudd^vSXB%~nntv9iLL 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≠jS_?GL48*91rfu?1Qdv3etO+r~zGKmRYPyElK_V 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 o`7!q5PnEwUB7ULvOXA-i)kYuVrbFF_(NuK)l5 literal 319191 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%0AcT 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%0A_9n(-yK%WM$SAB`If_GE0Zw4?KN5xTX$ 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 diff --git a/docs/api.rst b/docs/api.rst index 5a911533..e027738d 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -78,6 +78,12 @@ API Reference .. autoclass:: ConsoleRenderer :members: get_default_level_styles +.. autoclass:: Column +.. autoclass:: ColumnFormatter(typing.Protocol) + :members: __call__ +.. autoclass:: KeyValueColumnFormatter +.. autoclass:: LogLevelColumnFormatter + .. autofunction:: plain_traceback .. autoclass:: RichTracebackFormatter .. autofunction:: rich_traceback diff --git a/docs/console-output.md b/docs/console-output.md index aa5fbb60..302342a2 100644 --- a/docs/console-output.md +++ b/docs/console-output.md @@ -25,36 +25,90 @@ For pretty exceptions to work, {func}`~structlog.processors.format_exc_info` mus ::: *structlog*'s default configuration already uses {class}`~structlog.dev.ConsoleRenderer`, therefore if you want nice colorful output on the console, you don't have to do anything except installing Rich or *better-exceptions* (and Colorama on Windows). -If you want to use it along with standard library logging, we suggest the following configuration: +If you want to use it along with standard library logging, there's the {func}`structlog.stdlib.recreate_defaults` helper. + +:::{seealso} +{doc}`exceptions` for more information on how to configure exception rendering. +For the console and beyond. +::: + +(columns-config)= + +## Console Output Configuration + +:::{versionadded} 23.3.0 +::: + +You can freely configure how the key-value pairs are formatted: colors, order, and how values are stringified. + +For that {class}`~structlog.dev.ConsoleRenderer` accepts the *columns* parameter that takes a list of {class}`~structlog.dev.Column`s. +It allows you to assign a formatter to each key and a default formatter for the rest (by passing an empty key name). +The order of the column definitions is the order in which the columns are rendered; +the rest is -- depending on the *sort_keys* argument to {class}`~structlog.dev.ConsoleRenderer` -- either sorted alphabetically or in the order of the keys in the event dictionary. + +You can use a column definition to drop a key-value pair from the output by returning an empty string from the formatter. + +When the API talks about "styles", it means ANSI control strings. +You can find them, for example, in [Colorama](https://github.com/tartley/colorama). + + +It's best demonstrated by an example: ```python import structlog - -structlog.configure( - processors=[ - structlog.stdlib.add_logger_name, - structlog.stdlib.add_log_level, - structlog.stdlib.PositionalArgumentsFormatter(), - structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M.%S"), - structlog.processors.StackInfoRenderer(), - structlog.dev.ConsoleRenderer() # <=== - ], - context_class=dict, - logger_factory=structlog.stdlib.LoggerFactory(), - wrapper_class=structlog.stdlib.BoundLogger, - cache_logger_on_first_use=True, +import colorama + +cr = structlog.dev.ConsoleRenderer( + columns=[ + # Render the timestamp without the key name in yellow. + structlog.dev.Column( + "timestamp", + structlog.dev.KeyValueColumnFormatter( + key_style=None, + value_style=colorama.Fore.YELLOW, + reset_style=colorama.Style.RESET_ALL, + value_repr=str, + ), + ), + # Render the event without the key name in bright magenta. + structlog.dev.Column( + "event", + structlog.dev.KeyValueColumnFormatter( + key_style=None, + value_style=colorama.Style.BRIGHT + colorama.Fore.MAGENTA, + reset_style=colorama.Style.RESET_ALL, + value_repr=str, + ), + ), + # Default formatter for all keys not explicitly mentioned. The key is + # cyan, the value is green. + structlog.dev.Column( + "", + structlog.dev.KeyValueColumnFormatter( + key_style=colorama.Fore.CYAN, + value_style=colorama.Fore.GREEN, + reset_style=colorama.Style.RESET_ALL, + value_repr=str, + ), + ), + ] ) + +structlog.configure(processors=structlog.get_config()["processors"][:-1]+[cr]) ``` -:::{seealso} -{doc}`exceptions` for more information on how to configure exception rendering. -For the console and beyond. +:::{hint} +You can replace only the last processor using: + +```python +structlog.configure(processors=structlog.get_config()["processors"][:-1]+[cr]) +``` ::: ## Standard Environment Variables -*structlog*'s default configuration uses colors if standard out is a TTY (i.e. an interactive session). +*structlog*'s default configuration uses colors if standard out is a TTY (that is, an interactive session). It's possible to override this behavior by setting two standard environment variables to any value except an empty string: diff --git a/show_off.py b/show_off.py index 45242ddb..8fad80ab 100644 --- a/show_off.py +++ b/show_off.py @@ -16,6 +16,8 @@ class SomeClass: y: str +structlog.stdlib.recreate_defaults() # so we have logger names + log = structlog.get_logger("some_logger") log.debug("debugging is hard", a_list=[1, 2, 3]) diff --git a/src/structlog/dev.py b/src/structlog/dev.py index 808da12d..e0125516 100644 --- a/src/structlog/dev.py +++ b/src/structlog/dev.py @@ -20,13 +20,14 @@ from types import ModuleType from typing import ( Any, - Iterable, + Callable, Literal, Protocol, Sequence, TextIO, Type, Union, + cast, ) from ._frames import _format_exception @@ -164,6 +165,156 @@ class _PlainStyles: kv_value = "" +class ColumnFormatter(Protocol): + """ + :class:`~typing.Protocol` for column formatters. + + See `KeyValueColumnFormatter` and `LogLevelColumnFormatter` for examples. + + .. versionadded:: 23.3.0 + """ + + def __call__(self, key: str, value: object) -> str: + """ + Format *value* for *key*. + + This method is responsible for formatting, *key*, the ``=``, and the + *value*. That means that it can use any string instead of the ``=`` and + it can leave out both the *key* or the *value*. + + If it returns an empty string, the column is omitted completely. + """ + + +@dataclass +class Column: + """ + A column defines the way a key-value pair is formatted, and, by it's + position to the *columns* argument of `ConsoleRenderer`, the order in which + it is rendered. + + Args: + key: + The key for which this column is responsible. Leave empty to define + it as the default formatter. + + formatter: The formatter for columns with *key*. + + .. versionadded:: 23.3.0 + """ + + key: str + formatter: ColumnFormatter + + +@dataclass +class KeyValueColumnFormatter: + """ + Format a key-value pair. + + Args: + key_style: The style to apply to the key. If None, the key is omitted. + + value_style: The style to apply to the value. + + reset_style: The style to apply whenever a style is no longer needed. + + value_repr: + A callable that returns the string representation of the value. + + width: The width to pad the value to. If 0, no padding is done. + + prefix: + A string to prepend to the formatted key-value pair. May contain + styles. + + postfix: + A string to append to the formatted key-value pair. May contain + styles. + + .. versionadded:: 23.3.0 + """ + + key_style: str | None + value_style: str + reset_style: str + value_repr: Callable[[object], str] + width: int = 0 + prefix: str = "" + postfix: str = "" + + def __call__(self, key: str, value: object) -> str: + sio = StringIO() + + if self.prefix: + sio.write(self.prefix) + sio.write(self.reset_style) + + if self.key_style is not None: + sio.write(self.key_style) + sio.write(key) + sio.write(self.reset_style) + sio.write("=") + + sio.write(self.value_style) + sio.write(_pad(self.value_repr(value), self.width)) + sio.write(self.reset_style) + + if self.postfix: + sio.write(self.postfix) + sio.write(self.reset_style) + + return sio.getvalue() + + +class LogLevelColumnFormatter: + """ + Format a log level according to *level_styles*. + + The width is padded to the longest level name (if *level_styles* is passed + -- otherwise there's no way to know the lengths of all levels). + + Args: + level_styles: + A dictionary of level names to styles that are applied to it. If + None, the level is formatted as a plain ``[level]``. + + reset_style: + What to use to reset the style after the level name. Ignored if + if *level_styles* is None. + + .. versionadded:: 23.3.0 + """ + + level_styles: dict[str, str] | None + reset_style: str + width: int + + def __init__(self, level_styles: dict[str, str], reset_style: str) -> None: + self.level_styles = level_styles + if level_styles: + self.width = len( + max(self.level_styles.keys(), key=lambda e: len(e)) + ) + self.reset_style = reset_style + else: + self.width = 0 + self.reset_style = "" + + def __call__(self, key: str, value: object) -> str: + level = cast(str, value) + style = ( + "" + if self.level_styles is None + else self.level_styles.get(level, "") + ) + + return f"[{style}{_pad(level, self.width)}{self.reset_style}]" + + +_NOTHING = object() + + def plain_traceback(sio: TextIO, exc_info: ExcInfo) -> None: """ "Pretty"-print *exc_info* to *sio* using our own plain formatter. @@ -275,29 +426,40 @@ class ConsoleRenderer: *after* the log line. If Rich_ or better-exceptions_ are present, in colors and with extra context. - Parameters: + Args: + columns: + A list of `Column` objects defining both the order and format of + the key-value pairs in the output. If passed, most other arguments + become meaningless. - pad_event: Pad the event to this many characters. + **Must** contain a column with ``key=''`` that defines the default + formatter. + + .. seealso:: `columns-config` + + pad_event: + Pad the event to this many characters. Ignored if *columns* are + passed. colors: Use colors for a nicer output. `True` by default. On Windows only - if Colorama_ is installed. + if Colorama_ is installed. Ignored if *columns* are passed. force_colors: Force colors even for non-tty destinations. Use this option if your logs are stored in a file that is meant to be streamed to the - console. Only meaningful on Windows. + console. Only meaningful on Windows. Ignored if *columns* are + passed. repr_native_str: - When `True`, `repr` is also applied to native strings (i.e. unicode - on Python 3 and bytes on Python 2). Setting this to `False` is - useful if you want to have human-readable non-ASCII output on - Python 2. The ``event`` key is *never* `repr` -ed. + When `True`, `repr` is also applied to ``str``s. The ``event`` key + is *never* `repr` -ed. Ignored if *columns* are passed. level_styles: When present, use these styles for colors. This must be a dict from level names (strings) to Colorama styles. The default can be - obtained by calling `ConsoleRenderer.get_default_level_styles` + obtained by calling `ConsoleRenderer.get_default_level_styles`. + Ignored when *columns* are passed. exception_formatter: A callable to render ``exc_infos``. If Rich_ or better-exceptions_ @@ -307,18 +469,25 @@ class ConsoleRenderer: `RichTracebackFormatter` like `rich_traceback`, or implement your own. - sort_keys: Whether to sort keys when formatting. `True` by default. + sort_keys: + Whether to sort keys when formatting. `True` by default. Ignored if + *columns* are passed. event_key: The key to look for the main log message. Needed when you rename it - e.g. using `structlog.processors.EventRenamer`. + e.g. using `structlog.processors.EventRenamer`. Ignored if + *columns* are passed. timestamp_key: The key to look for timestamp of the log message. Needed when you - rename it e.g. using `structlog.processors.EventRenamer`. + rename it e.g. using `structlog.processors.EventRenamer`. Ignored + if *columns* are passed. Requires the Colorama_ package if *colors* is `True` **on Windows**. + Raises: + ValueError: If there's not exactly one default column formatter. + .. _Colorama: https://pypi.org/project/colorama/ .. _better-exceptions: https://pypi.org/project/better-exceptions/ .. _Rich: https://pypi.org/project/rich/ @@ -352,9 +521,10 @@ class ConsoleRenderer: .. versionadded:: 21.3.0 *sort_keys* .. versionadded:: 22.1.0 *event_key* .. versionadded:: 23.2.0 *timestamp_key* + .. versionadded:: 23.3.0 *columns* """ - def __init__( + def __init__( # noqa: PLR0912 self, pad_event: int = _EVENT_WIDTH, colors: bool = _has_colors, @@ -365,7 +535,57 @@ def __init__( sort_keys: bool = True, event_key: str = "event", timestamp_key: str = "timestamp", + columns: list[Column] | None = None, ): + self._exception_formatter = exception_formatter + self._sort_keys = sort_keys + + if columns is not None: + to_warn = [] + + def add_meaningless_arg(arg: str) -> None: + to_warn.append( + f"The `{arg}` argument is ignored when passing `columns`.", + ) + + if pad_event != _EVENT_WIDTH: + add_meaningless_arg("pad_event") + + if colors != _has_colors: + add_meaningless_arg("colors") + + if force_colors is not False: + add_meaningless_arg("force_colors") + + if repr_native_str is not False: + add_meaningless_arg("repr_native_str") + + if level_styles is not None: + add_meaningless_arg("level_styles") + + if event_key != "event": + add_meaningless_arg("event_key") + + if timestamp_key != "timestamp": + add_meaningless_arg("timestamp_key") + + for w in to_warn: + warnings.warn(w, stacklevel=2) + + defaults = [col for col in columns if col.key == ""] + if not defaults: + raise ValueError( + "Must pass a default column formatter (a column with `key=''`)." + ) + if len(defaults) > 1: + raise ValueError("Only one default column formatter allowed.") + + self._default_column_formatter = defaults[0].formatter + self._columns = [col for col in columns if col.key] + + return + + # Create default columns configuration. styles: Styles if colors: if _IS_WINDOWS: # pragma: no cover @@ -391,24 +611,67 @@ def __init__( styles = _PlainStyles self._styles = styles - self._pad_event = pad_event - if level_styles is None: - self._level_to_color = self.get_default_level_styles(colors) - else: - self._level_to_color = level_styles + level_to_color = ( + self.get_default_level_styles(colors) + if level_styles is None + else level_styles + ) - for key in self._level_to_color: - self._level_to_color[key] += styles.bright + for key in level_to_color: + level_to_color[key] += styles.bright self._longest_level = len( - max(self._level_to_color.keys(), key=lambda e: len(e)) + max(level_to_color.keys(), key=lambda e: len(e)) ) self._repr_native_str = repr_native_str - self._exception_formatter = exception_formatter - self._sort_keys = sort_keys - self._event_key = event_key - self._timestamp_key = timestamp_key + + self._default_column_formatter = KeyValueColumnFormatter( + styles.kv_key, + styles.kv_value, + styles.reset, + value_repr=self._repr, + width=0, + ) + + logger_name_formatter = KeyValueColumnFormatter( + key_style=None, + value_style=styles.bright + styles.logger_name, + reset_style=styles.reset, + value_repr=str, + prefix="[", + postfix="]", + ) + + self._columns = [ + Column( + timestamp_key, + KeyValueColumnFormatter( + key_style=None, + value_style=styles.timestamp, + reset_style=styles.reset, + value_repr=str, + ), + ), + Column( + "level", + LogLevelColumnFormatter( + level_to_color, reset_style=styles.reset + ), + ), + Column( + event_key, + KeyValueColumnFormatter( + key_style=None, + value_style=styles.bright, + reset_style=styles.reset, + value_repr=str, + width=pad_event, + ), + ), + Column("logger", logger_name_formatter), + Column("logger_name", logger_name_formatter), + ] def _repr(self, val: Any) -> str: """ @@ -423,75 +686,24 @@ def _repr(self, val: Any) -> str: return repr(val) - def __call__( # noqa: PLR0912 + def __call__( self, logger: WrappedLogger, name: str, event_dict: EventDict ) -> str: - sio = StringIO() - - ts = event_dict.pop(self._timestamp_key, None) - if ts is not None: - sio.write( - # can be a number if timestamp is UNIXy - self._styles.timestamp - + str(ts) - + self._styles.reset - + " " - ) - level = event_dict.pop("level", None) - if level is not None: - sio.write( - "[" - + self._level_to_color.get(level, "") - + _pad(level, self._longest_level) - + self._styles.reset - + "] " - ) - - # force event to str for compatibility with standard library - event = event_dict.pop(self._event_key, None) - if not isinstance(event, str): - event = str(event) - - if event_dict: - event = _pad(event, self._pad_event) + self._styles.reset + " " - else: - event += self._styles.reset - sio.write(self._styles.bright + event) - - logger_name = event_dict.pop("logger", None) - if logger_name is None: - logger_name = event_dict.pop("logger_name", None) - - if logger_name is not None: - sio.write( - "[" - + self._styles.logger_name - + self._styles.bright - + logger_name - + self._styles.reset - + "] " - ) - stack = event_dict.pop("stack", None) exc = event_dict.pop("exception", None) exc_info = event_dict.pop("exc_info", None) - event_dict_keys: Iterable[str] = event_dict.keys() - if self._sort_keys: - event_dict_keys = sorted(event_dict_keys) - - sio.write( - " ".join( - self._styles.kv_key - + key - + self._styles.reset - + "=" - + self._styles.kv_value - + self._repr(event_dict[key]) - + self._styles.reset - for key in event_dict_keys - ) - ) + kvs = [ + col.formatter(col.key, val) + for col in self._columns + if (val := event_dict.pop(col.key, _NOTHING)) is not _NOTHING + ] + [ + self._default_column_formatter(key, event_dict[key]) + for key in (sorted(event_dict) if self._sort_keys else event_dict) + ] + + sio = StringIO() + sio.write((" ".join(kv for kv in kvs if kv)).rstrip(" ")) if stack is not None: sio.write("\n" + stack) @@ -510,6 +722,7 @@ def __call__( # noqa: PLR0912 "if you want pretty exceptions.", stacklevel=2, ) + sio.write("\n" + exc) return sio.getvalue() @@ -527,8 +740,7 @@ def get_default_level_styles(colors: bool = True) -> Any: my_styles["EVERYTHING_IS_ON_FIRE"] = my_styles["critical"] renderer = ConsoleRenderer(level_styles=my_styles) - Parameters: - + Args: colors: Whether to use colorful styles. This must match the *colors* parameter to `ConsoleRenderer`. Default: `True`. diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 9fbe5c7e..f5fbd0d3 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -63,8 +63,7 @@ def recreate_defaults(*, log_level: int | None = logging.NOTSET) -> None: As with vanilla defaults, the backwards-compatibility guarantees don't apply to the settings applied here. - Parameters: - + Args: log_level: If `None`, don't configure standard library logging **at all**. @@ -75,6 +74,8 @@ def recreate_defaults(*, log_level: int | None = logging.NOTSET) -> None: configure it yourself. .. versionadded:: 22.1.0 + .. versionchanged:: 23.3.0 + Added `add_logger_name`. """ if log_level is not None: kw = {"force": True} @@ -91,6 +92,7 @@ def recreate_defaults(*, log_level: int | None = logging.NOTSET) -> None: processors=[ merge_contextvars, add_log_level, + add_logger_name, StackInfoRenderer(), _config._BUILTIN_DEFAULT_PROCESSORS[-2], # TimeStamper _config._BUILTIN_DEFAULT_PROCESSORS[-1], # ConsoleRenderer @@ -1000,7 +1002,10 @@ def __init__( super().__init__(*args, fmt=fmt, **kwargs) # type: ignore[misc] if processor and processors: - msg = "The `processor` and `processors` arguments are mutually exclusive." + msg = ( + "The `processor` and `processors` arguments are mutually" + " exclusive." + ) raise TypeError(msg) self.processors: Sequence[Processor] @@ -1050,9 +1055,11 @@ def format(self, record: logging.LogRecord) -> str: logger = self.logger meth_name = record.levelname.lower() ed = { - "event": record.getMessage() - if self.use_get_message - else str(record.msg), + "event": ( + record.getMessage() + if self.use_get_message + else str(record.msg) + ), "_record": record, "_from_structlog": False, } diff --git a/tests/test_dev.py b/tests/test_dev.py index 531e76df..00d40cd4 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -28,28 +28,21 @@ def test_negative(self): assert len("test") == len(dev._pad("test", 2)) -@pytest.fixture(name="cr") +@pytest.fixture(name="cr", scope="session") def _cr(): return dev.ConsoleRenderer( colors=dev._has_colors, exception_formatter=dev.plain_traceback ) -@pytest.fixture(name="styles") +@pytest.fixture(name="styles", scope="session") def _styles(cr): return cr._styles -@pytest.fixture(name="padded") +@pytest.fixture(name="padded", scope="session") def _padded(styles): - return ( - styles.bright + dev._pad("test", dev._EVENT_WIDTH) + styles.reset + " " - ) - - -@pytest.fixture(name="unpadded") -def _unpadded(styles): - return styles.bright + "test" + styles.reset + return styles.bright + dev._pad("test", dev._EVENT_WIDTH) + styles.reset class TestConsoleRenderer: @@ -70,23 +63,23 @@ def test_missing_colorama(self): "installed." ) in e.value.args[0] - def test_plain(self, cr, unpadded): + def test_plain(self, cr, padded): """ Works with a plain event_dict with only the event. """ rv = cr(None, None, {"event": "test"}) - assert unpadded == rv + assert padded == rv - def test_timestamp(self, cr, styles, unpadded): + def test_timestamp(self, cr, styles, padded): """ Timestamps get prepended. """ rv = cr(None, None, {"event": "test", "timestamp": 42}) - assert (styles.timestamp + "42" + styles.reset + " " + unpadded) == rv + assert (styles.timestamp + "42" + styles.reset + " " + padded) == rv - def test_event_stringified(self, cr, unpadded): + def test_event_stringified(self, cr, padded): """ Event is cast to string. """ @@ -94,7 +87,7 @@ def test_event_stringified(self, cr, unpadded): rv = cr(None, None, {"event": not_a_string}) - assert unpadded == rv + assert padded == rv def test_event_renamed(self): """ @@ -112,15 +105,18 @@ def test_timestamp_renamed(self): """ cr = dev.ConsoleRenderer(colors=False, timestamp_key="ts") - assert "2023-09-07 le event" == cr( - None, - None, - {"ts": "2023-09-07", "event": "le event"}, + assert ( + "2023-09-07 le event" + == cr( + None, + None, + {"ts": "2023-09-07", "event": "le event"}, + ).rstrip() ) def test_level(self, cr, styles, padded): """ - Levels are rendered aligned, in square brackets, and color coded. + Levels are rendered aligned, in square brackets, and color-coded. """ rv = cr( None, None, {"event": "test", "level": "critical", "foo": "bar"} @@ -134,6 +130,7 @@ def test_level(self, cr, styles, padded): + styles.reset + "] " + padded + + " " + styles.kv_key + "foo" + styles.reset @@ -168,6 +165,7 @@ def test_init_accepts_overriding_levels(self, styles, padded): + styles.reset + "] " + padded + + " " + styles.kv_key + "foo" + styles.reset @@ -185,12 +183,14 @@ def test_logger_name(self, cr, styles, padded): assert ( padded - + "[" - + dev.BLUE + + " [" + + styles.reset + styles.bright + + dev.BLUE + "some_module" + styles.reset - + "] " + + "]" + + styles.reset ) == rv def test_logger_name_name(self, cr, padded, styles): @@ -199,12 +199,14 @@ def test_logger_name_name(self, cr, padded, styles): """ assert ( padded - + "[" - + dev.BLUE + + " [" + + styles.reset + styles.bright + + dev.BLUE + "yolo" + styles.reset - + "] " + + "]" + + styles.reset ) == cr(None, None, {"event": "test", "logger_name": "yolo"}) def test_key_values(self, cr, styles, padded): @@ -215,6 +217,7 @@ def test_key_values(self, cr, styles, padded): assert ( padded + + " " + styles.kv_key + "foo" + styles.reset @@ -246,6 +249,7 @@ def test_key_values_unsorted(self, styles, padded): assert ( padded + + " " + styles.kv_key + "key" + styles.reset @@ -264,7 +268,9 @@ def test_key_values_unsorted(self, styles, padded): ) == rv @pytest.mark.parametrize("wrap", [True, False]) - def test_exception_rendered(self, cr, padded, recwarn, wrap): + def test_exception_rendered( + self, cr, recwarn, wrap, styles, padded, monkeypatch + ): """ Exceptions are rendered after a new line if they are already rendered in the event dict. @@ -275,10 +281,15 @@ def test_exception_rendered(self, cr, padded, recwarn, wrap): # Wrap the formatter to provoke the warning. if wrap: - cr._exception_formatter = lambda s, ei: dev.plain_tracebacks(s, ei) + monkeypatch.setattr( + cr, + "_exception_formatter", + lambda s, ei: dev.plain_traceback(s, ei), + ) + rv = cr(None, None, {"event": "test", "exception": exc}) - assert (padded + "\n" + exc) == rv + assert (f"{padded}\n" + exc) == rv if wrap: (w,) = recwarn.list @@ -287,16 +298,16 @@ def test_exception_rendered(self, cr, padded, recwarn, wrap): "if you want pretty exceptions.", ) == w.message.args - def test_stack_info(self, cr, padded): + def test_stack_info(self, cr, styles, padded): """ Stack traces are rendered after a new line. """ stack = "fake stack" rv = cr(None, None, {"event": "test", "stack": stack}) - assert (padded + "\n" + stack) == rv + assert (f"{padded}\n" + stack) == rv - def test_exc_info_tuple(self, cr, padded): + def test_exc_info_tuple(self, cr, styles, padded): """ If exc_info is a tuple, it is used. """ @@ -310,9 +321,9 @@ def test_exc_info_tuple(self, cr, padded): exc = dev._format_exception(ei) - assert (padded + "\n" + exc) == rv + assert (f"{padded}\n" + exc) == rv - def test_exc_info_bool(self, cr, padded): + def test_exc_info_bool(self, cr, styles, padded): """ If exc_info is True, it is obtained using sys.exc_info(). """ @@ -325,9 +336,9 @@ def test_exc_info_bool(self, cr, padded): exc = dev._format_exception(ei) - assert (padded + "\n" + exc) == rv + assert (f"{padded}\n" + exc) == rv - def test_exc_info_exception(self, cr, padded): + def test_exc_info_exception(self, cr, styles, padded): """ If exc_info is an exception, it is used by converting to a tuple. """ @@ -341,7 +352,7 @@ def test_exc_info_exception(self, cr, padded): exc = dev._format_exception((ei.__class__, ei, ei.__traceback__)) - assert (padded + "\n" + exc) == rv + assert (f"{padded}\n" + exc) == rv def test_pad_event_param(self, styles): """ @@ -420,12 +431,15 @@ def test_everything(self, cr, styles, padded, explicit_ei): + styles.reset + "] " + padded - + "[" - + dev.BLUE + + " [" + + styles.reset + styles.bright + + dev.BLUE + "some_module" + styles.reset - + "] " + + "]" + + styles.reset + + " " + styles.kv_key + "foo" + styles.reset @@ -483,6 +497,7 @@ def test_colorama_force_colors(self, styles, padded): + styles.reset + "] " + padded + + " " + styles.kv_key + "foo" + styles.reset @@ -536,6 +551,69 @@ def test_no_exception(self): ).rstrip() ) + def test_columns_warns_about_meaningless_arguments(self, recwarn): + """ + If columns is set, a warning is emitted for all ignored arguments. + """ + dev.ConsoleRenderer( + columns=[dev.Column("", lambda k, v: "")], + pad_event=42, + colors=not dev._has_colors, + force_colors=True, + repr_native_str=True, + level_styles=dev._PlainStyles, + event_key="not event", + timestamp_key="not timestamp", + ) + + assert { + f"The `{arg}` argument is ignored when passing `columns`." + for arg in ( + "pad_event", + "colors", + "force_colors", + "repr_native_str", + "level_styles", + "event_key", + "timestamp_key", + ) + } == {str(w.message) for w in recwarn.list} + + def test_detects_default_column(self): + """ + The default renderer is detected and removed from the columns list. + """ + fake_formatter = object() + llcf = dev.Column("log_level", dev.LogLevelColumnFormatter(None, "")) + + cr = dev.ConsoleRenderer( + columns=[dev.Column("", fake_formatter), llcf] + ) + + assert fake_formatter is cr._default_column_formatter + assert [llcf] == cr._columns + + def test_enforces_presence_of_exactly_one_default_formatter(self): + """ + If there is no, or more than one, default formatter, raise ValueError. + """ + with pytest.raises( + ValueError, + match="Must pass a default column formatter", + ): + dev.ConsoleRenderer(columns=[]) + + with pytest.raises( + ValueError, + match="Only one default column formatter allowed.", + ): + dev.ConsoleRenderer( + columns=[ + dev.Column("", lambda k, v: ""), + dev.Column("", lambda k, v: ""), + ] + ) + class TestSetExcInfo: def test_wrong_name(self): @@ -622,3 +700,13 @@ def test_does_not_blow_up(self): dev.better_traceback(sio, sys.exc_info()) assert sio.getvalue().startswith("\n") + + +class TestLogLevelColumnFormatter: + def test_no_style(self): + """ + No level_styles means no control characters and no padding. + """ + assert "[critical]" == dev.LogLevelColumnFormatter(None, "foo")( + "", "critical" + ) diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 569bbbd7..48c9f36f 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -879,7 +879,7 @@ def test_foreign_pre_chain_add_logger_name(self, capsys): assert ( "", - "foo [sample-name] [in test_foreign_pr" + "foo [sample-name] [in test_foreign_pr" "e_chain_add_logger_name]\n", ) == capsys.readouterr() From a5bb980a79f76334c9a06ef068e1db2f07b1c59f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 29 Dec 2023 08:35:22 +0100 Subject: [PATCH 1146/1520] docs: get rid of e.g./i.e. --- CHANGELOG.md | 10 +++++----- docs/bound-loggers.md | 2 +- docs/contextvars.md | 2 +- docs/processors.md | 7 ++++--- docs/standard-library.md | 13 +++++++------ docs/why.md | 2 +- src/structlog/stdlib.py | 9 +++++---- 7 files changed, 24 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36360ed1..6443b631 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -124,7 +124,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ### Deprecated -- Accessing package metadata as attributes on the *structlog* module is deprecated (e.g. `structlog.__version__`). +- Accessing package metadata as attributes on the *structlog* module is deprecated (for example, `structlog.__version__`). Please use [`importlib.metadata`](https://docs.python.org/3.10/library/importlib.metadata.html) instead (for Python 3.7: the [*importlib-metadata*](https://pypi.org/project/importlib-metadata/) PyPI package). - The `structlog.types` module is now deprecated in favor of the `structlog.typing` module. It seems like the Python typing community is settling on this name. @@ -277,7 +277,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - *structlog* switched its packaging to [*flit*](https://flit.pypa.io/). Users shouldn't notice a difference, but (re-)packagers might. - `structlog.stdlib.AsyncBoundLogger` now determines the running loop when logging, not on instantiation. - That has a minor performance impact, but makes it more robust when loops change (e.g. `aiohttp.web.run_app()`), or you want to use `sync_bl` *before* a loop has started. + That has a minor performance impact, but makes it more robust when loops change (for example, `aiohttp.web.run_app()`), or you want to use `sync_bl` *before* a loop has started. ### Fixed @@ -331,7 +331,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ ### Fixed -- *structlog* is now importable if `sys.stdout` is `None` (e.g. when running using `pythonw`). [#313](https://github.com/hynek/structlog/issues/313) +- *structlog* is now importable if `sys.stdout` is `None` (for example, when running using `pythonw`). [#313](https://github.com/hynek/structlog/issues/313) ## [21.1.0](https://github.com/hynek/structlog/compare/20.2.0...21.1.0) - 2021-02-18 @@ -372,7 +372,7 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/ - *structlog* has now type hints for all of its APIs! Since *structlog* is highly dynamic and configurable, this led to a few concessions like a specialized `structlog.stdlib.get_logger()` whose only difference to `structlog.get_logger()` is that it has the correct type hints. - We consider them provisional for the time being – i.e. the backwards-compatibility does not apply to them in its full strength until we feel we got it right. + We consider them provisional for the time being – that means the backwards-compatibility does not apply to them in its full strength until we feel we got it right. Please feel free to provide feedback! [#223](https://github.com/hynek/structlog/issues/223), [#282](https://github.com/hynek/structlog/issues/282) @@ -788,7 +788,7 @@ Special thanks go to [Fabian Büchler](https://github.com/fabianbuechler), [Gilb - Add `structlog.processors.ExceptionPrettyPrinter` for development and testing when multiline log entries aren't just acceptable but even helpful. - Allow the standard library name guesser to ignore certain frame names. This is useful together with frameworks. -- Add meta data (e.g. function names, line numbers) extraction for wrapped stdlib loggers. [#5](https://github.com/hynek/structlog/pull/5) +- Add meta data (for example, function names, line numbers) extraction for wrapped stdlib loggers. [#5](https://github.com/hynek/structlog/pull/5) ## [0.3.2](https://github.com/hynek/structlog/compare/0.3.1...0.3.2) - 2013-09-27 diff --git a/docs/bound-loggers.md b/docs/bound-loggers.md index 4415af89..ac7cb646 100644 --- a/docs/bound-loggers.md +++ b/docs/bound-loggers.md @@ -153,7 +153,7 @@ You will configure *structlog* as explained in the {doc}`next chapter ` *structlog* to use `AsyncBoundLogger` as `wrapper_class`. ```{versionadded} 20.2.0 ``` - +```{deprecated} 23.1.0 +``` ## Processors @@ -118,7 +119,7 @@ To use it, {doc}`configure ` *structlog* to use `AsyncBoundLogger {func}`~structlog.stdlib.PositionalArgumentsFormatter`: -: This processes and formats positional arguments (if any) passed to log methods in the same way the `logging` module would do, e.g. `logger.info("Hello, %s", name)`. +: This processes and formats positional arguments (if any) passed to log methods in the same way the `logging` module would do, for example, `logger.info("Hello, %s", name)`. *structlog* also comes with {class}`~structlog.stdlib.ProcessorFormatter` which is a `logging.Formatter` that enables you to format non-*structlog* log entries using *structlog* renderers *and* multiplex *structlog*’s output with different renderers (see [below](processor-formatter) for an example). @@ -285,7 +286,7 @@ structlog.configure( ``` Now you have the event dict available within each log record. -If you want all your log entries (i.e. also those not from your application / *structlog*) to be formatted as JSON, you can use the [*python-json-logger*] library: +If you want *all* your log entries (meaning: also those not from your application / *structlog*) to be formatted as JSON, you can use the [*python-json-logger*] library: ```python import logging @@ -393,7 +394,7 @@ amazing _from_structlog=True _record= events=oh yes ``` Of course, you probably want timestamps and log levels in your output. -The `ProcessorFormatter` has a `foreign_pre_chain` argument which is responsible for adding properties to events from the standard library -- i.e. that do not originate from a *structlog* logger -- and which should in general match the `processors` argument to {func}`structlog.configure` so you get a consistent output. +The `ProcessorFormatter` has a `foreign_pre_chain` argument which is responsible for adding properties to events from the standard library -- in other words, those that do not originate from a *structlog* logger -- and which should in general match the `processors` argument to {func}`structlog.configure` so you get a consistent output. `_from_structlog` and `_record` allow your processors to determine whether the log entry is coming from *structlog*, and to extract information from `logging.LogRecord`s and add them to the event dictionary. However, you probably don't want to have them in your log files, thus we've added the `ProcessorFormatter.remove_processors_meta` processor to do so conveniently. diff --git a/docs/why.md b/docs/why.md index 6cfe4ae1..a1ac4135 100644 --- a/docs/why.md +++ b/docs/why.md @@ -53,7 +53,7 @@ Since log entries are dictionaries, you can start binding and re-binding key-val 2020-11-18 09:18:28 [info ] user.logged_in another_key=42 happy=True some_key=23 user=hynek ``` -You can also bind key-value pairs to {doc}`context variables ` that look global, but are local to your thread or *asyncio* context (i.e. usually your request). +You can also bind key-value pairs to {doc}`context variables ` that look global, but are local to your thread or *asyncio* context -- which usually means your web request. ### Powerful Pipelines diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index f5fbd0d3..f33c7484 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -1113,11 +1113,12 @@ def wrap_for_formatter( """ Wrap *logger*, *name*, and *event_dict*. - The result is later unpacked by `ProcessorFormatter` when - formatting log entries. + The result is later unpacked by `ProcessorFormatter` when formatting + log entries. - Use this static method as the renderer (i.e. final processor) if you - want to use `ProcessorFormatter` in your `logging` configuration. + Use this static method as the renderer (in other words, final + processor) if you want to use `ProcessorFormatter` in your `logging` + configuration. """ return (event_dict,), {"extra": {"_logger": logger, "_name": name}} From 84d7cfc65fbcd7b6f3725dc6a72a8a086b96cb7a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 29 Dec 2023 09:31:28 +0100 Subject: [PATCH 1147/1520] Avoid link artifacts --- README.md | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 9006f577..8b09286f 100644 --- a/README.md +++ b/README.md @@ -40,17 +40,11 @@ The output format is just as flexible and *structlog* comes with support for JSO Especially those generously supporting us at the *The Organization* tier and higher:

  • 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 z�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%0A})0h9@1u&O1Ms6SghFyBe38u$&ObF%6 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 Date: Mon, 17 Oct 2022 10:18:25 +0200 Subject: [PATCH 0881/1520] Add blackspace around screenshot --- docs/_static/console_renderer.png | Bin 291528 -> 311775 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/_static/console_renderer.png b/docs/_static/console_renderer.png index a8b4bc8ace6a74765ff91771b0309b186d44c061..7ecf742dfa5257056beb2484a6d3efb8c847414e 100644 GIT binary patch literal 311775 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

    3J*y#|NE;Xv^| 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 Q#b{5_#L(Q}KH53qKb?Y;?f?J) literal 520725 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