From c4a5f32e19297c498b09b35923a5339dedecb530 Mon Sep 17 00:00:00 2001
From: Vytautas Liuolia <vytautas.liuolia@gmail.com>
Date: Tue, 7 May 2024 20:26:49 +0200
Subject: [PATCH 1/2] chore(CI): pin `pytest` + ASGI tutorial fixes (#2233)

---
 docs/user/tutorial-asgi.rst         | 5 +----
 examples/asgilook/asgilook/store.py | 2 +-
 requirements/tests                  | 5 ++++-
 tox.ini                             | 3 +--
 4 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/docs/user/tutorial-asgi.rst b/docs/user/tutorial-asgi.rst
index 65ffa2fa9..dff2206b2 100644
--- a/docs/user/tutorial-asgi.rst
+++ b/docs/user/tutorial-asgi.rst
@@ -180,13 +180,12 @@ We can now implement a basic async image store. Save the following code as
 
 
     class Image:
-
         def __init__(self, config, image_id, size):
             self._config = config
 
             self.image_id = image_id
             self.size = size
-            self.modified = datetime.datetime.utcnow()
+            self.modified = datetime.datetime.now(datetime.timezone.utc)
 
         @property
         def path(self):
@@ -206,7 +205,6 @@ We can now implement a basic async image store. Save the following code as
 
 
     class Store:
-
         def __init__(self, config):
             self._config = config
             self._images = {}
@@ -272,7 +270,6 @@ of images. Place the code below in a file named ``images.py``:
 
 
     class Images:
-
         def __init__(self, config, store):
             self._config = config
             self._store = store
diff --git a/examples/asgilook/asgilook/store.py b/examples/asgilook/asgilook/store.py
index 2633f0ac0..faf873c91 100644
--- a/examples/asgilook/asgilook/store.py
+++ b/examples/asgilook/asgilook/store.py
@@ -13,7 +13,7 @@ def __init__(self, config, image_id, size):
 
         self.image_id = image_id
         self.size = size
-        self.modified = datetime.datetime.utcnow()
+        self.modified = datetime.datetime.now(datetime.timezone.utc)
 
     @property
     def path(self):
diff --git a/requirements/tests b/requirements/tests
index 19b34bcd3..e3623da8d 100644
--- a/requirements/tests
+++ b/requirements/tests
@@ -1,5 +1,8 @@
 coverage >= 4.1
-pytest
+# TODO(vytas): Our use of testtools breaks under pytest 8.2 along the lines of
+#   https://github.com/pytest-dev/pytest/issues/12263, unpin when fixed
+#   (or drop support for testtools altogether?)
+pytest >= 7.0, < 8.2
 pyyaml
 requests
 # TODO(vytas): Check if testtools still brings anything to the table, and
diff --git a/tox.ini b/tox.ini
index 0e6dcd477..e6ca31342 100644
--- a/tox.ini
+++ b/tox.ini
@@ -435,7 +435,6 @@ commands =
 # --------------------------------------------------------------------
 
 [testenv:look]
-basepython = python3.10
 deps =
     -r{toxinidir}/examples/look/requirements/test
 commands =
@@ -446,7 +445,7 @@ commands =
 # --------------------------------------------------------------------
 
 [testenv:asgilook]
-basepython = python3.10
+basepython = python3.12
 deps =
     -r{toxinidir}/examples/asgilook/requirements/asgilook
     -r{toxinidir}/examples/asgilook/requirements/test

From 9b27c71e40ffafa76a160b33905281084430ef98 Mon Sep 17 00:00:00 2001
From: Mario Rivera <150161290+MRLab12@users.noreply.github.com>
Date: Tue, 7 May 2024 15:30:52 -0400
Subject: [PATCH 2/2] docs(asgi-tutorial): include info on setting up logging
 for debugging (#2223)

* Update tutorial-asgi to include info on setting up logging for debugging an application

* Add Python logging docs link/add note that debugging asgi also applies to wsgi

* 80 char limit / changed logging example to show use with falcon / added intersphinx

* docs: update tutorial-asgi.rst

---------

Co-authored-by: Vytautas Liuolia <vytautas.liuolia@gmail.com>
---
 docs/user/tutorial-asgi.rst | 48 +++++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/docs/user/tutorial-asgi.rst b/docs/user/tutorial-asgi.rst
index dff2206b2..dd7c63b20 100644
--- a/docs/user/tutorial-asgi.rst
+++ b/docs/user/tutorial-asgi.rst
@@ -964,6 +964,54 @@ adding ``--cov-fail-under=100`` (or any other percent threshold) to our
     tests in multiple environments would most probably involve running
     ``coverage`` directly, and combining results.
 
+Debugging ASGI Applications
+---------------------------
+(This section also applies to WSGI applications)
+
+While developing and testing ASGI applications, understanding how to configure
+and utilize logging can be helpful, especially when you encounter unexpected
+issues or behaviors.
+
+By default, Falcon does not set up logging for you,
+but Python's built-in :mod:`logging` module provides a flexible framework for
+emitting and capturing log messages. Here's how you can set up basic logging in
+your ASGI Falcon application:
+
+.. code:: python
+
+    import falcon
+    import logging
+
+    logging.basicConfig(level=logging.INFO)
+
+    class ErrorResource:
+        def on_get(self, req, resp):
+            raise Exception('Something went wrong!')
+
+    app = falcon.App()
+    app.add_route('/error', ErrorResource())
+
+
+When the above route is accessed, Falcon will catch the unhandled exception and
+automatically log an error message. Below is an example of what the log output
+might look like:
+
+.. code-block:: none
+
+    ERROR:falcon.asgi.app:Unhandled exception in ASGI application
+    Traceback (most recent call last):
+      File "path/to/falcon/app.py", line 123, in __call__
+        resp = resource.on_get(req, resp)
+      File "/path/to/your/app.py", line 7, in on_get
+        raise Exception("Something went wrong!")
+    Exception: Something went wrong!
+
+
+.. note::
+   While logging is helpful for development and debugging, be mindful of logging
+   sensitive information. Ensure that log files are stored securely and are not
+   accessible to unauthorized users.
+
 What Now?
 ---------