Repository: django/asgiref
Pull request #213 (2020-11-05 19:19:52)

Use GitHub actions
* Adds a tox config and GitHub Actions workflow. 
* Uses flake8, fixes errors.
* Removed travis config. 

Possibly: could drop Python 3.5 support, as it is EOL. (But no necessity for that.) 

carltongibson: Checks are running on my fork until merged. 

https://github.com/carltongibson/asgiref/actions/runs/348143120

Patch:
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 8e5f49c..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,42 +0,0 @@
-language: python
-
-python:
-  - "3.9"
-  - "3.8"
-  - "3.7"
-  - "3.6"
-  - "3.5"
-
-install:
-  - pip install -U pytest  # Travis comes with an old version pre-installed.
-  - pip install -e .[tests]
-  - pip freeze
-
-script:
-  - pytest
-
-stages:
-  - test
-  - lint
-  - name: release
-    if: tag IS present
-
-jobs:
-  include:
-    - stage: lint
-      install: pip install -U -e .[tests] black pyflakes isort
-      script:
-        - pyflakes asgiref tests
-        - black --check --diff asgiref tests
-        - isort --check-only --diff --recursive asgiref tests
-
-    - stage: deploy
-      script: skip
-      deploy:
-        provider: pypi
-        user: andrewgodwin_bot
-        on:
-          tags: true
-        distributions: sdist bdist_wheel
-        password:
-          secure: Bt6uFOAf2n9D5z06Orv8w6a3zU86mkpA9wspLsu8AIJ2kZx61bpO+27vHvJFyVpkEW+EerzUY9sOq02jd8EhzHL86wcM5zgXyDYhlZ6CxYxU9vFXrBmLzC/rrGbirArseXnDZY5ulPnuRBFxJyqJ2mZeDKjn+qoa8qe364si/wPDWs9YjQFSbT6lJz0MVIVKQNHw5iAXBsQ+yQewjbNPo4nOd81kqlO8Bg/Xpu85/rHjim8zG9PWAMUnueIMyYSTUTXSmZFRR+3viJ7HZz7o0HxepokkpLODdvbUKnKi2fdQAa4fAlInqFf4gSaLN8f+Ch5aDFeDmz7FVcwUbKEmWo67/lzb0NQwiYz11O+K78xFPRHopCljR3VFpCSxw/oJuLRlbElXO0q8JLznKVdgdoFqSV4/W7HgXXdYuDjcYWHiYHHc1t/JoOF3bRkjRu7Ax9HwmEi1RLL4ou5G/lT60Pd50FRcLV788AYw7CiZFewRyXjJSB59Crqt05Eyl0Wtynd1JwHDkJC2SYuWfqRHYM+oicqxbSyecjbMu8vDD56soDEeM/oHojBo4IpEYtGYHndGvnmtOuPpiKNpxxZC6ipghrv74s0Btw9HaI8SW1/G3EDCudL5rd7X9gdMFESdp/WshKlr4treEYfPRkZcuh3WW9CE2QS0IiCXoWk60AA=
diff --git a/asgiref/server.py b/asgiref/server.py
index 9fd2e0c..a83b7bf 100644
--- a/asgiref/server.py
+++ b/asgiref/server.py
@@ -3,6 +3,8 @@ import logging
 import time
 import traceback
 
+from .compatibility import guarantee_single_callable
+
 logger = logging.getLogger(__name__)
 
 
@@ -84,10 +86,11 @@ class StatelessServer:
             self.delete_oldest_application_instance()
         # Make an instance of the application
         input_queue = asyncio.Queue()
-        application_instance = self.application(scope=scope)
+        application_instance = guarantee_single_callable(self.application)
         # Run it, and stash the future for later checking
         future = asyncio.ensure_future(
             application_instance(
+                scope=scope,
                 receive=input_queue.get,
                 send=lambda message: self.application_send(scope, message),
             )
diff --git a/asgiref/sync.py b/asgiref/sync.py
index 97b5d31..cc8a0e9 100644
--- a/asgiref/sync.py
+++ b/asgiref/sync.py
@@ -206,7 +206,7 @@ class AsyncToSync:
             if exc_info[1]:
                 try:
                     raise exc_info[1]
-                except:
+                except Exception:
                     result = await self.awaitable(*args, **kwargs)
             else:
                 result = await self.awaitable(*args, **kwargs)
@@ -337,7 +337,7 @@ class SyncToAsync:
             if exc_info[1]:
                 try:
                     raise exc_info[1]
-                except:
+                except Exception:
                     return func(*args, **kwargs)
             else:
                 return func(*args, **kwargs)
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000..2523c24
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,21 @@
+[tox]
+envlist =
+    py{35,36,37,38,39}
+    qa
+
+[testenv]
+usedevelop = true
+extras = tests
+commands =
+    pytest -v {posargs}
+
+[testenv:qa]
+skip_install=true
+deps =
+    black
+    flake8
+    isort
+commands =
+    flake8 asgiref tests
+    black --check asgiref tests
+    isort --check-only --diff asgiref tests


Test patch:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
new file mode 100644
index 0000000..6737a86
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,50 @@
+name: Tests
+
+on:
+  push:
+   branches:
+   - master
+  pull_request:
+
+jobs:
+  tests:
+    name: Python ${{ matrix.python-version }}
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        python-version:
+        - 3.5
+        - 3.6
+        - 3.7
+        - 3.8
+        - 3.9
+
+    steps:
+      - uses: actions/checkout@v2
+      - name: Set up Python ${{ matrix.python-version }}
+        uses: actions/setup-python@v2
+        with:
+          python-version: ${{ matrix.python-version }}
+      - name: Install dependencies
+        run: |
+          python -m pip install --upgrade pip wheel setuptools tox
+      - name: Run tox targets for ${{ matrix.python-version }}
+        run: |
+          ENV_PREFIX=$(tr -C -d "0-9" <<< "${{ matrix.python-version }}")
+          TOXENV=$(tox --listenvs | grep "^py$ENV_PREFIX" | tr '\n' ',') python -m tox
+
+  lint:
+    name: Lint
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - name: Set up Python
+        uses: actions/setup-python@v2
+        with:
+          python-version: 3.9
+      - name: Install dependencies
+        run: |
+          python -m pip install --upgrade pip tox
+      - name: Run lint
+        run: tox -e qa
diff --git a/tests/test_compatibility.py b/tests/test_compatibility.py
index 61868c1..4164683 100644
--- a/tests/test_compatibility.py
+++ b/tests/test_compatibility.py
@@ -67,11 +67,11 @@ def test_is_double_callable():
     """
     Tests that the signature matcher works as expected.
     """
-    assert is_double_callable(double_application_function) == True
-    assert is_double_callable(DoubleApplicationClass) == True
-    assert is_double_callable(DoubleApplicationClassNestedFunction()) == True
-    assert is_double_callable(single_application_function) == False
-    assert is_double_callable(SingleApplicationClass()) == False
+    assert is_double_callable(double_application_function) is True
+    assert is_double_callable(DoubleApplicationClass) is True
+    assert is_double_callable(DoubleApplicationClassNestedFunction()) is True
+    assert is_double_callable(single_application_function) is False
+    assert is_double_callable(SingleApplicationClass()) is False
 
 
 def test_double_to_single_signature():
@@ -80,7 +80,7 @@ def test_double_to_single_signature():
     """
     assert (
         is_double_callable(double_to_single_callable(double_application_function))
-        == False
+        is False
     )
 
 
diff --git a/tests/test_local.py b/tests/test_local.py
index 6ea2522..035c99f 100644
--- a/tests/test_local.py
+++ b/tests/test_local.py
@@ -53,6 +53,7 @@ def test_local_thread_nested():
     # Unassigned should be an error
     with pytest.raises(AttributeError):
         test_local.foo
+
     # Assign and check it does not persist inside the thread
     class TestThread(threading.Thread):
         # Failure reason
@@ -132,6 +133,7 @@ async def test_local_task_to_sync():
     # Set up the local
     test_local = Local()
     test_local.foo = 3
+
     # Look at it in a sync context
     def sync_function():
         assert test_local.foo == 3
@@ -149,6 +151,7 @@ def test_local_thread_to_async():
     # Set up the local
     test_local = Local()
     test_local.foo = 12
+
     # Look at it in an async context
     async def async_function():
         assert test_local.foo == 12
@@ -168,6 +171,7 @@ async def test_local_task_to_sync_to_task():
     # Set up the local
     test_local = Local()
     test_local.foo = 756
+
     # Look at it in an async context inside a sync context
     def sync_function():
         async def async_function():
@@ -189,6 +193,7 @@ async def test_local_many_layers():
     # Set up the local
     test_local = Local()
     test_local.foo = 8374
+
     # Make sure we go between each world at least twice
     def sync_function():
         async def async_function():
@@ -217,6 +222,7 @@ async def test_local_critical_no_task_to_thread():
     # Set up the local
     test_local = Local(thread_critical=True)
     test_local.foo = 86
+
     # Look at it in a sync context
     def sync_function():
         with pytest.raises(AttributeError):
@@ -237,6 +243,7 @@ def test_local_critical_no_thread_to_task():
     # Set up the local
     test_local = Local(thread_critical=True)
     test_local.foo = 89
+
     # Look at it in an async context
     async def async_function():
         with pytest.raises(AttributeError):
diff --git a/tests/test_server.py b/tests/test_server.py
new file mode 100644
index 0000000..77bbd4d
--- /dev/null
+++ b/tests/test_server.py
@@ -0,0 +1,11 @@
+from asgiref.server import StatelessServer
+
+
+def test_stateless_server():
+    """StatlessServer can be instantiated with an ASGI 3 application."""
+
+    async def app(scope, receive, send):
+        pass
+
+    server = StatelessServer(app)
+    server.get_or_create_application_instance("scope_id", {})