Skip to content

Commit

Permalink
Support for Python 3.12 #2836 (#2870)
Browse files Browse the repository at this point in the history
* Support for Python 3.12 #2836

* Extended test suite to meet required coverage.
  • Loading branch information
iAndriy authored Dec 21, 2023
1 parent d0bbcf5 commit 29d4289
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 12 deletions.
1 change: 1 addition & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ jobs:
- { python-version: "3.10", tox-env: py310, max-attempts: 3 }
- { python-version: "3.10", tox-env: py310-no-ext, max-attempts: 3 }
- { python-version: "3.11", tox-env: py311, max-attempts: 3 }
- { python-version: "3.12", tox-env: py312, max-attempts: 3 }
- { python-version: "3.11", tox-env: py311-no-ext, max-attempts: 3 }
- { python-version: "3.8", tox-env: py38-no-ext, platform: windows-latest, ignore-errors: true }
- { python-version: "3.9", tox-env: py39-no-ext, platform: windows-latest, ignore-errors: true }
Expand Down
2 changes: 1 addition & 1 deletion sanic/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "23.12.0"
__version__ = "23.12.1"
4 changes: 2 additions & 2 deletions sanic/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,11 +126,11 @@ def __getattr__(self, key: str) -> str:
if key.startswith("_"):
return self.__getattribute__(key)
key = key.rstrip("_").replace("_", "-")
return ",".join(self.getall(key, default=[]))
return ",".join(self.getall(key, []))

def get_all(self, key: str):
"""Convenience method mapped to ``getall()``."""
return self.getall(key, default=[])
return self.getall(key, [])


use_trio = sys.argv[0].endswith("hypercorn") and "trio" in sys.argv
Expand Down
12 changes: 12 additions & 0 deletions tests/test_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -657,3 +657,15 @@ def test_stop_trigger_terminate(app: Sanic):

app.stop(unregister=False)
app.multiplexer.terminate.assert_called_once()


def test_refresh_pass_passthru_data_to_new_instance(app: Sanic):
# arrange
passthru = {
'_inspector': 2,
'config': {'TOUCHUP': 23}
}
app = app.refresh(passthru)

assert app.inspector == 2
assert app.config.TOUCHUP == 23
10 changes: 10 additions & 0 deletions tests/test_blueprint_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ def test_bp_group_indexing(app: Sanic):
with raises(expected_exception=IndexError):
_ = group[3]

def test_bp_group_set_item_by_index(app: Sanic):
blueprint_1 = Blueprint("blueprint_1", url_prefix="/bp1")
blueprint_2 = Blueprint("blueprint_2", url_prefix="/bp2")

group = Blueprint.group(blueprint_1, blueprint_2)
group[0] = blueprint_2

assert group[0] == blueprint_2



def test_bp_group_with_additional_route_params(app: Sanic):
blueprint_1 = Blueprint("blueprint_1", url_prefix="/bp1")
Expand Down
40 changes: 40 additions & 0 deletions tests/test_blueprints.py
Original file line number Diff line number Diff line change
Expand Up @@ -1112,3 +1112,43 @@ async def index(_):
app.router.finalize()

assert app.router.routes[0].path == "foo/"


def test_blueprint_copy_returns_blueprint_with_the_name_of_original_blueprint(
app: Sanic,
):
# arrange
bp = Blueprint("bp")

# act
actual = bp.copy("new_bp_name")

# assert
assert bp.name == actual.copied_from


def test_blueprint_copy_returns_blueprint_with_overwritten_properties(
app: Sanic,
):
# arrange
bp = Blueprint("bp")
to_override_attrs = expected = dict(
url_prefix="v2",
version="v2",
version_prefix="v2",
allow_route_overwrite=True,
strict_slashes=True,
)

# act
actual = bp.copy(
"new_bp_name",
**to_override_attrs,
)

# assert
assert all(
value == getattr(actual, key)
for key, value in expected.items()
if hasattr(actual, key)
)
9 changes: 3 additions & 6 deletions tests/test_websockets.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import pytest

from websockets.frames import CTRL_OPCODES, DATA_OPCODES, Frame
from websockets.frames import CTRL_OPCODES, DATA_OPCODES, OP_TEXT, Frame

from sanic.exceptions import ServerError
from sanic.server.websockets.frame import WebsocketFrameAssembler
Expand Down Expand Up @@ -210,17 +210,14 @@ async def test_ws_frame_put_message_complete(opcode):
@pytest.mark.asyncio
@pytest.mark.parametrize("opcode", DATA_OPCODES)
async def test_ws_frame_put_message_into_queue(opcode):
foo = "foo" if (opcode == OP_TEXT) else b"foo"
assembler = WebsocketFrameAssembler(Mock())
assembler.chunks_queue = AsyncMock(spec=Queue)
assembler.message_fetched = AsyncMock()
assembler.message_fetched.is_set = Mock(return_value=False)

await assembler.put(Frame(opcode, b"foo"))

assembler.chunks_queue.put.has_calls(
call(b"foo"),
call(None),
)
assert assembler.chunks_queue.put.call_args_list == [call(foo), call(None)]


@pytest.mark.asyncio
Expand Down
7 changes: 4 additions & 3 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
[tox]
envlist = py38, py39, py310, py311, pyNightly, pypy310, {py38,py39,py310,py311,pyNightly,pypy310}-no-ext, lint, check, security, docs, type-checking
envlist = py38, py39, py310, py311, py312, pyNightly, pypy310, {py38,py39,py310,py311,py312,pyNightly,pypy310}-no-ext, lint, check, security, docs, type-checking

[testenv]
usedevelop = true
setenv =
{py38,py39,py310,py311,pyNightly}-no-ext: SANIC_NO_UJSON=1
{py38,py39,py310,py311,pyNightly}-no-ext: SANIC_NO_UVLOOP=1
{py38,py39,py310,py311,py312,pyNightly}-no-ext: SANIC_NO_UJSON=1
{py38,py39,py310,py311,py312,pyNightly}-no-ext: SANIC_NO_UVLOOP=1
extras = test, http3
deps =
httpx>=0.23
setuptools
allowlist_externals =
pytest
coverage
Expand Down

0 comments on commit 29d4289

Please sign in to comment.