Compare commits
24 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
05002d7ee4 | ||
|
b4360d4a20 | ||
|
3b85b3bbad | ||
|
6e55e73da1 | ||
|
89d942451f | ||
|
4d6205e6fe | ||
|
1684b0b986 | ||
|
4f5faa4a3c | ||
|
cbb77b536a | ||
|
35c76253bf | ||
|
8d86c3c598 | ||
|
97635111af | ||
|
7f3fe40cd4 | ||
|
ea34bcd849 | ||
|
05f758583b | ||
|
760c74a293 | ||
|
9def46beb8 | ||
|
04be8e95a5 | ||
|
78ced20fc7 | ||
|
c3003413d3 | ||
|
fe3fdc5d83 | ||
|
b66fb6f9e8 | ||
|
bf6175fb20 | ||
|
58ca887be4 |
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||||
|
patreon: # Replace with a single Patreon username
|
||||||
|
open_collective: sanic-org # Replace with a single Open Collective username
|
||||||
|
ko_fi: # Replace with a single Ko-fi username
|
||||||
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
|
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||||
|
liberapay: # Replace with a single Liberapay username
|
||||||
|
issuehunt: # Replace with a single IssueHunt username
|
||||||
|
otechie: # Replace with a single Otechie username
|
||||||
|
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
40
.github/workflows/codeql-analysis.yml
vendored
Normal file
40
.github/workflows/codeql-analysis.yml
vendored
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
name: "CodeQL"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- "*LTS"
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- "*LTS"
|
||||||
|
types: [opened, synchronize, reopened, ready_for_review]
|
||||||
|
schedule:
|
||||||
|
- cron: '25 16 * * 0'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
if: github.event.pull_request.draft == false
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
language: [ 'python' ]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v1
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
|
||||||
|
- name: Autobuild
|
||||||
|
uses: github/codeql-action/autobuild@v1
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v1
|
37
.github/workflows/coverage.yml
vendored
Normal file
37
.github/workflows/coverage.yml
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
name: Coverage check
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- "*LTS"
|
||||||
|
tags:
|
||||||
|
- "!*" # Do not execute on tags
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened, ready_for_review]
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
if: github.event.pull_request.draft == false
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
python-version: [3.9]
|
||||||
|
os: [ubuntu-latest]
|
||||||
|
fail-fast: false
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- uses: actions/setup-python@v1
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.python-version }}
|
||||||
|
|
||||||
|
- name: Install dependencies 🔨
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install tox
|
||||||
|
- uses: paambaati/codeclimate-action@v2.5.3
|
||||||
|
if: always()
|
||||||
|
env:
|
||||||
|
CC_TEST_REPORTER_ID: ${{ secrets.CODECLIMATE }}
|
||||||
|
with:
|
||||||
|
coverageCommand: tox -e coverage
|
39
.github/workflows/on-demand.yml
vendored
Normal file
39
.github/workflows/on-demand.yml
vendored
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
name: On Demand Task
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
python-version:
|
||||||
|
description: 'Version of Python to use for running Test'
|
||||||
|
required: false
|
||||||
|
default: "3.8"
|
||||||
|
tox-env:
|
||||||
|
description: 'Test Environment to Run'
|
||||||
|
required: true
|
||||||
|
default: ''
|
||||||
|
os:
|
||||||
|
description: 'Operating System to Run Test on'
|
||||||
|
required: false
|
||||||
|
default: ubuntu-latest
|
||||||
|
jobs:
|
||||||
|
onDemand:
|
||||||
|
name: tox-${{ matrix.config.tox-env }}-on-${{ matrix.os }}
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: ["${{ github.event.inputs.os}}"]
|
||||||
|
config:
|
||||||
|
- { tox-env: "${{ github.event.inputs.tox-env }}", py-version: "${{ github.event.inputs.python-version }}"}
|
||||||
|
steps:
|
||||||
|
- name: Checkout Repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
uses: harshanarayana/custom-actions@main
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.config.py-version }}
|
||||||
|
test-infra-tool: tox
|
||||||
|
test-infra-version: latest
|
||||||
|
action: tests
|
||||||
|
test-additional-args: "-e=${{ matrix.config.tox-env }}"
|
||||||
|
experimental-ignore-error: "yes"
|
36
.github/workflows/pr-bandit.yml
vendored
Normal file
36
.github/workflows/pr-bandit.yml
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
name: Security Analysis
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- "*LTS"
|
||||||
|
types: [opened, synchronize, reopened, ready_for_review]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
bandit:
|
||||||
|
if: github.event.pull_request.draft == false
|
||||||
|
name: type-check-${{ matrix.config.python-version }}
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest]
|
||||||
|
config:
|
||||||
|
- { python-version: 3.7, tox-env: security}
|
||||||
|
- { python-version: 3.8, tox-env: security}
|
||||||
|
- { python-version: 3.9, tox-env: security}
|
||||||
|
- { python-version: "3.10", tox-env: security}
|
||||||
|
steps:
|
||||||
|
- name: Checkout the repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
id: checkout-branch
|
||||||
|
|
||||||
|
- name: Run Linter Checks
|
||||||
|
id: linter-check
|
||||||
|
uses: harshanarayana/custom-actions@main
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.config.python-version }}
|
||||||
|
test-infra-tool: tox
|
||||||
|
test-infra-version: latest
|
||||||
|
action: tests
|
||||||
|
test-additional-args: "-e=${{ matrix.config.tox-env }}"
|
32
.github/workflows/pr-docs.yml
vendored
Normal file
32
.github/workflows/pr-docs.yml
vendored
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
name: Document Linter
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- "*LTS"
|
||||||
|
types: [opened, synchronize, reopened, ready_for_review]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docsLinter:
|
||||||
|
if: github.event.pull_request.draft == false
|
||||||
|
name: Lint Documentation
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
config:
|
||||||
|
- {python-version: "3.8", tox-env: "docs"}
|
||||||
|
fail-fast: false
|
||||||
|
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Run Document Linter
|
||||||
|
uses: harshanarayana/custom-actions@main
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.config.python-version }}
|
||||||
|
test-infra-tool: tox
|
||||||
|
test-infra-version: latest
|
||||||
|
action: tests
|
||||||
|
test-additional-args: "-e=${{ matrix.config.tox-env }}"
|
33
.github/workflows/pr-linter.yml
vendored
Normal file
33
.github/workflows/pr-linter.yml
vendored
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
name: Linter Checks
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- "*LTS"
|
||||||
|
types: [opened, synchronize, reopened, ready_for_review]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
linter:
|
||||||
|
if: github.event.pull_request.draft == false
|
||||||
|
name: lint
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest]
|
||||||
|
config:
|
||||||
|
- { python-version: 3.8, tox-env: lint}
|
||||||
|
steps:
|
||||||
|
- name: Checkout the repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
id: checkout-branch
|
||||||
|
|
||||||
|
- name: Run Linter Checks
|
||||||
|
id: linter-check
|
||||||
|
uses: harshanarayana/custom-actions@main
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.config.python-version }}
|
||||||
|
test-infra-tool: tox
|
||||||
|
test-infra-version: latest
|
||||||
|
action: tests
|
||||||
|
test-additional-args: "-e=${{ matrix.config.tox-env }}"
|
41
.github/workflows/pr-python-pypy.yml
vendored
Normal file
41
.github/workflows/pr-python-pypy.yml
vendored
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
name: Python PyPy Tests
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
tox-env:
|
||||||
|
description: "Tox Env to run on the PyPy Infra"
|
||||||
|
required: false
|
||||||
|
default: "pypy37"
|
||||||
|
pypy-version:
|
||||||
|
description: "Version of PyPy to use"
|
||||||
|
required: false
|
||||||
|
default: "pypy-3.7"
|
||||||
|
jobs:
|
||||||
|
testPyPy:
|
||||||
|
name: ut-${{ matrix.config.tox-env }}-${{ matrix.os }}
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
# os: [ubuntu-latest, macos-latest]
|
||||||
|
os: [ubuntu-latest]
|
||||||
|
config:
|
||||||
|
- {
|
||||||
|
python-version: "${{ github.event.inputs.pypy-version }}",
|
||||||
|
tox-env: "${{ github.event.inputs.tox-env }}",
|
||||||
|
}
|
||||||
|
steps:
|
||||||
|
- name: Checkout the Repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
id: checkout-branch
|
||||||
|
|
||||||
|
- name: Run Unit Tests
|
||||||
|
uses: harshanarayana/custom-actions@main
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.config.python-version }}
|
||||||
|
test-infra-tool: tox
|
||||||
|
test-infra-version: latest
|
||||||
|
action: tests
|
||||||
|
test-additional-args: "-e=${{ matrix.config.tox-env }}"
|
||||||
|
experimental-ignore-error: "true"
|
||||||
|
command-timeout: "600000"
|
35
.github/workflows/pr-python37.yml
vendored
Normal file
35
.github/workflows/pr-python37.yml
vendored
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
name: Python 3.7 Tests
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- "*LTS"
|
||||||
|
types: [opened, synchronize, reopened, ready_for_review]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
testPy37:
|
||||||
|
if: github.event.pull_request.draft == false
|
||||||
|
name: ut-${{ matrix.config.tox-env }}-${{ matrix.os }}
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: true
|
||||||
|
matrix:
|
||||||
|
# os: [ubuntu-latest, macos-latest]
|
||||||
|
os: [ubuntu-latest]
|
||||||
|
config:
|
||||||
|
- { python-version: 3.7, tox-env: py37 }
|
||||||
|
- { python-version: 3.7, tox-env: py37-no-ext }
|
||||||
|
steps:
|
||||||
|
- name: Checkout the Repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
id: checkout-branch
|
||||||
|
|
||||||
|
- name: Run Unit Tests
|
||||||
|
uses: harshanarayana/custom-actions@main
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.config.python-version }}
|
||||||
|
test-infra-tool: tox
|
||||||
|
test-infra-version: latest
|
||||||
|
action: tests
|
||||||
|
test-additional-args: "-e=${{ matrix.config.tox-env }}"
|
||||||
|
test-failure-retry: "3"
|
35
.github/workflows/pr-python38.yml
vendored
Normal file
35
.github/workflows/pr-python38.yml
vendored
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
name: Python 3.8 Tests
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- "*LTS"
|
||||||
|
types: [opened, synchronize, reopened, ready_for_review]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
testPy38:
|
||||||
|
if: github.event.pull_request.draft == false
|
||||||
|
name: ut-${{ matrix.config.tox-env }}-${{ matrix.os }}
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: true
|
||||||
|
matrix:
|
||||||
|
# os: [ubuntu-latest, macos-latest]
|
||||||
|
os: [ubuntu-latest]
|
||||||
|
config:
|
||||||
|
- { python-version: 3.8, tox-env: py38 }
|
||||||
|
- { python-version: 3.8, tox-env: py38-no-ext }
|
||||||
|
steps:
|
||||||
|
- name: Checkout the Repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
id: checkout-branch
|
||||||
|
|
||||||
|
- name: Run Unit Tests
|
||||||
|
uses: harshanarayana/custom-actions@main
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.config.python-version }}
|
||||||
|
test-infra-tool: tox
|
||||||
|
test-infra-version: latest
|
||||||
|
action: tests
|
||||||
|
test-additional-args: "-e=${{ matrix.config.tox-env }}"
|
||||||
|
test-failure-retry: "3"
|
47
.github/workflows/pr-python39.yml
vendored
Normal file
47
.github/workflows/pr-python39.yml
vendored
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
name: Python 3.9 Tests
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- "*LTS"
|
||||||
|
types: [opened, synchronize, reopened, ready_for_review]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
testPy39:
|
||||||
|
if: github.event.pull_request.draft == false
|
||||||
|
name: ut-${{ matrix.config.tox-env }}-${{ matrix.os }}
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: true
|
||||||
|
matrix:
|
||||||
|
# os: [ubuntu-latest, macos-latest]
|
||||||
|
os: [ubuntu-latest]
|
||||||
|
config:
|
||||||
|
- {
|
||||||
|
python-version: 3.9,
|
||||||
|
tox-env: py39,
|
||||||
|
ignore-error-flake: "false",
|
||||||
|
command-timeout: "0",
|
||||||
|
}
|
||||||
|
- {
|
||||||
|
python-version: 3.9,
|
||||||
|
tox-env: py39-no-ext,
|
||||||
|
ignore-error-flake: "true",
|
||||||
|
command-timeout: "600000",
|
||||||
|
}
|
||||||
|
steps:
|
||||||
|
- name: Checkout the Repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
id: checkout-branch
|
||||||
|
|
||||||
|
- name: Run Unit Tests
|
||||||
|
uses: harshanarayana/custom-actions@main
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.config.python-version }}
|
||||||
|
test-infra-tool: tox
|
||||||
|
test-infra-version: latest
|
||||||
|
action: tests
|
||||||
|
test-additional-args: "-e=${{ matrix.config.tox-env }},-vv=''"
|
||||||
|
experimental-ignore-error: "${{ matrix.config.ignore-error-flake }}"
|
||||||
|
command-timeout: "${{ matrix.config.command-timeout }}"
|
||||||
|
test-failure-retry: "3"
|
35
.github/workflows/pr-type-check.yml
vendored
Normal file
35
.github/workflows/pr-type-check.yml
vendored
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
name: Typing Checks
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- "*LTS"
|
||||||
|
types: [opened, synchronize, reopened, ready_for_review]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
typeChecking:
|
||||||
|
if: github.event.pull_request.draft == false
|
||||||
|
name: type-check-${{ matrix.config.python-version }}
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest]
|
||||||
|
config:
|
||||||
|
# - { python-version: 3.7, tox-env: type-checking}
|
||||||
|
- { python-version: 3.8, tox-env: type-checking}
|
||||||
|
- { python-version: 3.9, tox-env: type-checking}
|
||||||
|
steps:
|
||||||
|
- name: Checkout the repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
id: checkout-branch
|
||||||
|
|
||||||
|
- name: Run Linter Checks
|
||||||
|
id: linter-check
|
||||||
|
uses: harshanarayana/custom-actions@main
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.config.python-version }}
|
||||||
|
test-infra-tool: tox
|
||||||
|
test-infra-version: latest
|
||||||
|
action: tests
|
||||||
|
test-additional-args: "-e=${{ matrix.config.tox-env }}"
|
37
.github/workflows/pr-windows.yml
vendored
Normal file
37
.github/workflows/pr-windows.yml
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
name: Run Unit Tests on Windows
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- "*LTS"
|
||||||
|
types: [opened, synchronize, reopened, ready_for_review]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
testsOnWindows:
|
||||||
|
if: github.event.pull_request.draft == false
|
||||||
|
name: ut-${{ matrix.config.tox-env }}
|
||||||
|
runs-on: windows-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
config:
|
||||||
|
- { python-version: 3.7, tox-env: py37-no-ext }
|
||||||
|
- { python-version: 3.8, tox-env: py38-no-ext }
|
||||||
|
- { python-version: 3.9, tox-env: py39-no-ext }
|
||||||
|
- { python-version: pypy-3.7, tox-env: pypy37-no-ext }
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout Repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Run Unit Tests
|
||||||
|
uses: ahopkins/custom-actions@pip-extra-args
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.config.python-version }}
|
||||||
|
test-infra-tool: tox
|
||||||
|
test-infra-version: latest
|
||||||
|
action: tests
|
||||||
|
test-additional-args: "-e=${{ matrix.config.tox-env }}"
|
||||||
|
experimental-ignore-error: "true"
|
||||||
|
command-timeout: "600000"
|
||||||
|
pip-extra-args: "--user"
|
48
.github/workflows/publish-images.yml
vendored
Normal file
48
.github/workflows/publish-images.yml
vendored
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
name: Publish Docker Images
|
||||||
|
on:
|
||||||
|
workflow_run:
|
||||||
|
workflows:
|
||||||
|
- 'Publish Artifacts'
|
||||||
|
types:
|
||||||
|
- completed
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publishDockerImages:
|
||||||
|
name: Docker Image Build [${{ matrix.python-version }}]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: true
|
||||||
|
matrix:
|
||||||
|
python-version: ["3.7", "3.8", "3.9"]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Build Latest Base images for ${{ matrix.python-version }}
|
||||||
|
uses: harshanarayana/custom-actions@main
|
||||||
|
with:
|
||||||
|
docker-image-base-name: sanicframework/sanic-build
|
||||||
|
ignore-python-setup: 'true'
|
||||||
|
dockerfile-base-dir: './docker'
|
||||||
|
action: 'image-publish'
|
||||||
|
docker-image-tag: "${{ matrix.python-version }}"
|
||||||
|
docker-file-suffix: "base"
|
||||||
|
docker-build-args: "PYTHON_VERSION=${{ matrix.python-version }}"
|
||||||
|
registry-auth-user: ${{ secrets.DOCKER_ACCESS_USER }}
|
||||||
|
registry-auth-password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||||
|
push-images: 'true'
|
||||||
|
|
||||||
|
- name: Publish Sanic Docker Image for ${{ matrix.python-version }}
|
||||||
|
uses: harshanarayana/custom-actions@main
|
||||||
|
with:
|
||||||
|
docker-image-base-name: sanicframework/sanic
|
||||||
|
ignore-python-setup: 'true'
|
||||||
|
dockerfile-base-dir: './docker'
|
||||||
|
action: 'image-publish'
|
||||||
|
docker-build-args: "BASE_IMAGE_TAG=${{ matrix.python-version }}"
|
||||||
|
docker-image-prefix: "${{ matrix.python-version }}"
|
||||||
|
registry-auth-user: ${{ secrets.DOCKER_ACCESS_USER }}
|
||||||
|
registry-auth-password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||||
|
push-images: 'true'
|
28
.github/workflows/publish-package.yml
vendored
Normal file
28
.github/workflows/publish-package.yml
vendored
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
name: Publish Artifacts
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [created]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publishPythonPackage:
|
||||||
|
name: Publishing Sanic Release Artifacts
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: true
|
||||||
|
matrix:
|
||||||
|
python-version: ["3.8"]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout Repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Publish Python Package
|
||||||
|
uses: harshanarayana/custom-actions@main
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.python-version }}
|
||||||
|
package-infra-name: "twine"
|
||||||
|
pypi-user: __token__
|
||||||
|
pypi-access-token: ${{ secrets.PYPI_ACCESS_TOKEN }}
|
||||||
|
action: "package-publish"
|
||||||
|
pypi-verify-metadata: "true"
|
211
CHANGELOG.rst
211
CHANGELOG.rst
|
@ -1,9 +1,106 @@
|
||||||
|
Version 20.12.5
|
||||||
|
===============
|
||||||
|
|
||||||
|
Bugfixes
|
||||||
|
********
|
||||||
|
|
||||||
|
*
|
||||||
|
`#2366 <https://github.com/sanic-org/sanic/pull/2366>`_
|
||||||
|
websocket dependency for websockets 9.1 security fix
|
||||||
|
|
||||||
|
Version 20.12.0
|
||||||
|
===============
|
||||||
|
|
||||||
|
Features
|
||||||
|
********
|
||||||
|
|
||||||
|
*
|
||||||
|
`#1945 <https://github.com/huge-success/sanic/pull/1945>`_
|
||||||
|
Static route more verbose if file not found
|
||||||
|
|
||||||
|
*
|
||||||
|
`#1954 <https://github.com/huge-success/sanic/pull/1954>`_
|
||||||
|
Fix static routes registration on a blueprint
|
||||||
|
|
||||||
|
*
|
||||||
|
`#1961 <https://github.com/huge-success/sanic/pull/1961>`_
|
||||||
|
Add Python 3.9 support
|
||||||
|
|
||||||
|
*
|
||||||
|
`#1962 <https://github.com/huge-success/sanic/pull/1962>`_
|
||||||
|
Sanic CLI upgrade
|
||||||
|
|
||||||
|
*
|
||||||
|
`#1967 <https://github.com/huge-success/sanic/pull/1967>`_
|
||||||
|
Update aiofile version requirements
|
||||||
|
|
||||||
|
*
|
||||||
|
`#1969 <https://github.com/huge-success/sanic/pull/1969>`_
|
||||||
|
Update multidict version requirements
|
||||||
|
|
||||||
|
*
|
||||||
|
`#1970 <https://github.com/huge-success/sanic/pull/1970>`_
|
||||||
|
Add py.typed file
|
||||||
|
|
||||||
|
*
|
||||||
|
`#1972 <https://github.com/huge-success/sanic/pull/1972>`_
|
||||||
|
Speed optimization in request handler
|
||||||
|
|
||||||
|
*
|
||||||
|
`#1979 <https://github.com/huge-success/sanic/pull/1979>`_
|
||||||
|
Add app registry and Sanic class level app retrieval
|
||||||
|
|
||||||
|
Bugfixes
|
||||||
|
********
|
||||||
|
|
||||||
|
*
|
||||||
|
`#1965 <https://github.com/huge-success/sanic/pull/1965>`_
|
||||||
|
Fix Chunked Transport-Encoding in ASGI streaming response
|
||||||
|
|
||||||
|
Deprecations and Removals
|
||||||
|
*************************
|
||||||
|
|
||||||
|
*
|
||||||
|
`#1981 <https://github.com/huge-success/sanic/pull/1981>`_
|
||||||
|
Cleanup and remove deprecated code
|
||||||
|
|
||||||
|
Developer infrastructure
|
||||||
|
************************
|
||||||
|
|
||||||
|
*
|
||||||
|
`#1956 <https://github.com/huge-success/sanic/pull/1956>`_
|
||||||
|
Fix load module test
|
||||||
|
|
||||||
|
*
|
||||||
|
`#1973 <https://github.com/huge-success/sanic/pull/1973>`_
|
||||||
|
Transition Travis from .org to .com
|
||||||
|
|
||||||
|
*
|
||||||
|
`#1986 <https://github.com/huge-success/sanic/pull/1986>`_
|
||||||
|
Update tox requirements
|
||||||
|
|
||||||
|
Improved Documentation
|
||||||
|
**********************
|
||||||
|
|
||||||
|
*
|
||||||
|
`#1951 <https://github.com/huge-success/sanic/pull/1951>`_
|
||||||
|
Documentation improvements
|
||||||
|
|
||||||
|
*
|
||||||
|
`#1983 <https://github.com/huge-success/sanic/pull/1983>`_
|
||||||
|
Remove duplicate contents in testing.rst
|
||||||
|
|
||||||
|
*
|
||||||
|
`#1984 <https://github.com/huge-success/sanic/pull/1984>`_
|
||||||
|
Fix typo in routing.rst
|
||||||
|
|
||||||
|
|
||||||
Version 20.9.1
|
Version 20.9.1
|
||||||
===============
|
===============
|
||||||
|
|
||||||
Bugfixes
|
Bugfixes
|
||||||
********
|
********
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1954 <https://github.com/huge-success/sanic/pull/1954>`_
|
`#1954 <https://github.com/huge-success/sanic/pull/1954>`_
|
||||||
Fix static route registration on blueprints
|
Fix static route registration on blueprints
|
||||||
|
@ -17,7 +114,7 @@ Version 19.12.3
|
||||||
|
|
||||||
Bugfixes
|
Bugfixes
|
||||||
********
|
********
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1959 <https://github.com/huge-success/sanic/pull/1959>`_
|
`#1959 <https://github.com/huge-success/sanic/pull/1959>`_
|
||||||
Removes duplicate headers in ASGI streaming body
|
Removes duplicate headers in ASGI streaming body
|
||||||
|
@ -37,27 +134,27 @@ Features
|
||||||
*
|
*
|
||||||
`#1894 <https://github.com/huge-success/sanic/pull/1894>`_
|
`#1894 <https://github.com/huge-success/sanic/pull/1894>`_
|
||||||
Automatically set ``test_mode`` flag on app instance
|
Automatically set ``test_mode`` flag on app instance
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1903 <https://github.com/huge-success/sanic/pull/1903>`_
|
`#1903 <https://github.com/huge-success/sanic/pull/1903>`_
|
||||||
Add new unified method for updating app values
|
Add new unified method for updating app values
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1906 <https://github.com/huge-success/sanic/pull/1906>`_,
|
`#1906 <https://github.com/huge-success/sanic/pull/1906>`_,
|
||||||
`#1909 <https://github.com/huge-success/sanic/pull/1909>`_
|
`#1909 <https://github.com/huge-success/sanic/pull/1909>`_
|
||||||
Adds WEBSOCKET_PING_TIMEOUT and WEBSOCKET_PING_INTERVAL configuration values
|
Adds WEBSOCKET_PING_TIMEOUT and WEBSOCKET_PING_INTERVAL configuration values
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1935 <https://github.com/huge-success/sanic/pull/1935>`_
|
`#1935 <https://github.com/huge-success/sanic/pull/1935>`_
|
||||||
httpx version dependency updated, it is slated for removal as a dependency in v20.12
|
httpx version dependency updated, it is slated for removal as a dependency in v20.12
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1937 <https://github.com/huge-success/sanic/pull/1937>`_
|
`#1937 <https://github.com/huge-success/sanic/pull/1937>`_
|
||||||
Added auto, text, and json fallback error handlers (in v21.3, the default will change form html to auto)
|
Added auto, text, and json fallback error handlers (in v21.3, the default will change form html to auto)
|
||||||
|
|
||||||
Bugfixes
|
Bugfixes
|
||||||
********
|
********
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1897 <https://github.com/huge-success/sanic/pull/1897>`_
|
`#1897 <https://github.com/huge-success/sanic/pull/1897>`_
|
||||||
Resolves exception from unread bytes in stream
|
Resolves exception from unread bytes in stream
|
||||||
|
@ -98,7 +195,7 @@ Version 20.6.3
|
||||||
|
|
||||||
Bugfixes
|
Bugfixes
|
||||||
********
|
********
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1884 <https://github.com/huge-success/sanic/pull/1884>`_
|
`#1884 <https://github.com/huge-success/sanic/pull/1884>`_
|
||||||
Revert change to multiprocessing mode
|
Revert change to multiprocessing mode
|
||||||
|
@ -109,7 +206,7 @@ Version 20.6.2
|
||||||
|
|
||||||
Features
|
Features
|
||||||
********
|
********
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1641 <https://github.com/huge-success/sanic/pull/1641>`_
|
`#1641 <https://github.com/huge-success/sanic/pull/1641>`_
|
||||||
Socket binding implemented properly for IPv6 and UNIX sockets
|
Socket binding implemented properly for IPv6 and UNIX sockets
|
||||||
|
@ -120,7 +217,7 @@ Version 20.6.1
|
||||||
|
|
||||||
Features
|
Features
|
||||||
********
|
********
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1760 <https://github.com/huge-success/sanic/pull/1760>`_
|
`#1760 <https://github.com/huge-success/sanic/pull/1760>`_
|
||||||
Add version parameter to websocket routes
|
Add version parameter to websocket routes
|
||||||
|
@ -131,7 +228,7 @@ Features
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1880 <https://github.com/huge-success/sanic/pull/1880>`_
|
`#1880 <https://github.com/huge-success/sanic/pull/1880>`_
|
||||||
Add handler names for websockets for url_for usage
|
Add handler names for websockets for url_for usage
|
||||||
|
|
||||||
Bugfixes
|
Bugfixes
|
||||||
********
|
********
|
||||||
|
@ -151,7 +248,7 @@ Bugfixes
|
||||||
*
|
*
|
||||||
`#1848 <https://github.com/huge-success/sanic/pull/1848>`_
|
`#1848 <https://github.com/huge-success/sanic/pull/1848>`_
|
||||||
Reverse named_response_middlware execution order, to match normal response middleware execution order
|
Reverse named_response_middlware execution order, to match normal response middleware execution order
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1853 <https://github.com/huge-success/sanic/pull/1853>`_
|
`#1853 <https://github.com/huge-success/sanic/pull/1853>`_
|
||||||
Fix pickle error when attempting to pickle an application which contains websocket routes
|
Fix pickle error when attempting to pickle an application which contains websocket routes
|
||||||
|
@ -203,28 +300,28 @@ Version 20.3.0
|
||||||
Features
|
Features
|
||||||
********
|
********
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1762 <https://github.com/huge-success/sanic/pull/1762>`_
|
`#1762 <https://github.com/huge-success/sanic/pull/1762>`_
|
||||||
Add ``srv.start_serving()`` and ``srv.serve_forever()`` to ``AsyncioServer``
|
Add ``srv.start_serving()`` and ``srv.serve_forever()`` to ``AsyncioServer``
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1767 <https://github.com/huge-success/sanic/pull/1767>`_
|
`#1767 <https://github.com/huge-success/sanic/pull/1767>`_
|
||||||
Make Sanic usable on ``hypercorn -k trio myweb.app``
|
Make Sanic usable on ``hypercorn -k trio myweb.app``
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1768 <https://github.com/huge-success/sanic/pull/1768>`_
|
`#1768 <https://github.com/huge-success/sanic/pull/1768>`_
|
||||||
No tracebacks on normal errors and prettier error pages
|
No tracebacks on normal errors and prettier error pages
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1769 <https://github.com/huge-success/sanic/pull/1769>`_
|
`#1769 <https://github.com/huge-success/sanic/pull/1769>`_
|
||||||
Code cleanup in file responses
|
Code cleanup in file responses
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1793 <https://github.com/huge-success/sanic/pull/1793>`_ and
|
`#1793 <https://github.com/huge-success/sanic/pull/1793>`_ and
|
||||||
`#1819 <https://github.com/huge-success/sanic/pull/1819>`_
|
`#1819 <https://github.com/huge-success/sanic/pull/1819>`_
|
||||||
Upgrade ``str.format()`` to f-strings
|
Upgrade ``str.format()`` to f-strings
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1798 <https://github.com/huge-success/sanic/pull/1798>`_
|
`#1798 <https://github.com/huge-success/sanic/pull/1798>`_
|
||||||
Allow multiple workers on MacOS with Python 3.8
|
Allow multiple workers on MacOS with Python 3.8
|
||||||
|
|
||||||
|
@ -235,19 +332,19 @@ Features
|
||||||
Bugfixes
|
Bugfixes
|
||||||
********
|
********
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1748 <https://github.com/huge-success/sanic/pull/1748>`_
|
`#1748 <https://github.com/huge-success/sanic/pull/1748>`_
|
||||||
Remove loop argument in ``asyncio.Event`` in Python 3.8
|
Remove loop argument in ``asyncio.Event`` in Python 3.8
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1764 <https://github.com/huge-success/sanic/pull/1764>`_
|
`#1764 <https://github.com/huge-success/sanic/pull/1764>`_
|
||||||
Allow route decorators to stack up again
|
Allow route decorators to stack up again
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1789 <https://github.com/huge-success/sanic/pull/1789>`_
|
`#1789 <https://github.com/huge-success/sanic/pull/1789>`_
|
||||||
Fix tests using hosts yielding incorrect ``url_for``
|
Fix tests using hosts yielding incorrect ``url_for``
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1808 <https://github.com/huge-success/sanic/pull/1808>`_
|
`#1808 <https://github.com/huge-success/sanic/pull/1808>`_
|
||||||
Fix Ctrl+C and tests on Windows
|
Fix Ctrl+C and tests on Windows
|
||||||
|
|
||||||
|
@ -261,7 +358,7 @@ Deprecations and Removals
|
||||||
*
|
*
|
||||||
`#1801 <https://github.com/huge-success/sanic/pull/1801>`_
|
`#1801 <https://github.com/huge-success/sanic/pull/1801>`_
|
||||||
Complete deprecation from `#1666 <https://github.com/huge-success/sanic/pull/1666>`_ of dictionary context on ``request`` objects.
|
Complete deprecation from `#1666 <https://github.com/huge-success/sanic/pull/1666>`_ of dictionary context on ``request`` objects.
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1807 <https://github.com/huge-success/sanic/pull/1807>`_
|
`#1807 <https://github.com/huge-success/sanic/pull/1807>`_
|
||||||
Remove server config args that can be read directly from app
|
Remove server config args that can be read directly from app
|
||||||
|
@ -284,22 +381,22 @@ Dependencies
|
||||||
Developer infrastructure
|
Developer infrastructure
|
||||||
************************
|
************************
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1833 <https://github.com/huge-success/sanic/pull/1833>`_
|
`#1833 <https://github.com/huge-success/sanic/pull/1833>`_
|
||||||
Resolve broken documentation builds
|
Resolve broken documentation builds
|
||||||
|
|
||||||
Improved Documentation
|
Improved Documentation
|
||||||
**********************
|
**********************
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1755 <https://github.com/huge-success/sanic/pull/1755>`_
|
`#1755 <https://github.com/huge-success/sanic/pull/1755>`_
|
||||||
Usage of ``response.empty()``
|
Usage of ``response.empty()``
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1778 <https://github.com/huge-success/sanic/pull/1778>`_
|
`#1778 <https://github.com/huge-success/sanic/pull/1778>`_
|
||||||
Update README
|
Update README
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1783 <https://github.com/huge-success/sanic/pull/1783>`_
|
`#1783 <https://github.com/huge-success/sanic/pull/1783>`_
|
||||||
Fix typo
|
Fix typo
|
||||||
|
|
||||||
|
@ -326,7 +423,7 @@ Improved Documentation
|
||||||
*
|
*
|
||||||
`#1834 <https://github.com/huge-success/sanic/pull/1834>`_
|
`#1834 <https://github.com/huge-success/sanic/pull/1834>`_
|
||||||
Order of listeners
|
Order of listeners
|
||||||
|
|
||||||
|
|
||||||
Version 19.12.0
|
Version 19.12.0
|
||||||
===============
|
===============
|
||||||
|
@ -392,16 +489,16 @@ Version 19.6.2
|
||||||
Features
|
Features
|
||||||
********
|
********
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1562 <https://github.com/huge-success/sanic/pull/1562>`_
|
`#1562 <https://github.com/huge-success/sanic/pull/1562>`_
|
||||||
Remove ``aiohttp`` dependency and create new ``SanicTestClient`` based upon
|
Remove ``aiohttp`` dependency and create new ``SanicTestClient`` based upon
|
||||||
`requests-async <https://github.com/encode/requests-async>`_
|
`requests-async <https://github.com/encode/requests-async>`_
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1475 <https://github.com/huge-success/sanic/pull/1475>`_
|
`#1475 <https://github.com/huge-success/sanic/pull/1475>`_
|
||||||
Added ASGI support (Beta)
|
Added ASGI support (Beta)
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1436 <https://github.com/huge-success/sanic/pull/1436>`_
|
`#1436 <https://github.com/huge-success/sanic/pull/1436>`_
|
||||||
Add Configure support from object string
|
Add Configure support from object string
|
||||||
|
|
||||||
|
@ -409,19 +506,19 @@ Features
|
||||||
Bugfixes
|
Bugfixes
|
||||||
********
|
********
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1587 <https://github.com/huge-success/sanic/pull/1587>`_
|
`#1587 <https://github.com/huge-success/sanic/pull/1587>`_
|
||||||
Add missing handle for Expect header.
|
Add missing handle for Expect header.
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1560 <https://github.com/huge-success/sanic/pull/1560>`_
|
`#1560 <https://github.com/huge-success/sanic/pull/1560>`_
|
||||||
Allow to disable Transfer-Encoding: chunked.
|
Allow to disable Transfer-Encoding: chunked.
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1558 <https://github.com/huge-success/sanic/pull/1558>`_
|
`#1558 <https://github.com/huge-success/sanic/pull/1558>`_
|
||||||
Fix graceful shutdown.
|
Fix graceful shutdown.
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1594 <https://github.com/huge-success/sanic/pull/1594>`_
|
`#1594 <https://github.com/huge-success/sanic/pull/1594>`_
|
||||||
Strict Slashes behavior fix
|
Strict Slashes behavior fix
|
||||||
|
|
||||||
|
@ -432,11 +529,11 @@ Deprecations and Removals
|
||||||
`#1544 <https://github.com/huge-success/sanic/pull/1544>`_
|
`#1544 <https://github.com/huge-success/sanic/pull/1544>`_
|
||||||
Drop dependency on distutil
|
Drop dependency on distutil
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1562 <https://github.com/huge-success/sanic/pull/1562>`_
|
`#1562 <https://github.com/huge-success/sanic/pull/1562>`_
|
||||||
Drop support for Python 3.5
|
Drop support for Python 3.5
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1568 <https://github.com/huge-success/sanic/pull/1568>`_
|
`#1568 <https://github.com/huge-success/sanic/pull/1568>`_
|
||||||
Deprecate route removal.
|
Deprecate route removal.
|
||||||
|
|
||||||
|
@ -453,39 +550,39 @@ Version 19.3
|
||||||
Features
|
Features
|
||||||
********
|
********
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1497 <https://github.com/huge-success/sanic/pull/1497>`_
|
`#1497 <https://github.com/huge-success/sanic/pull/1497>`_
|
||||||
Add support for zero-length and RFC 5987 encoded filename for
|
Add support for zero-length and RFC 5987 encoded filename for
|
||||||
multipart/form-data requests.
|
multipart/form-data requests.
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1484 <https://github.com/huge-success/sanic/pull/1484>`_
|
`#1484 <https://github.com/huge-success/sanic/pull/1484>`_
|
||||||
The type of ``expires`` attribute of ``sanic.cookies.Cookie`` is now
|
The type of ``expires`` attribute of ``sanic.cookies.Cookie`` is now
|
||||||
enforced to be of type ``datetime``.
|
enforced to be of type ``datetime``.
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1482 <https://github.com/huge-success/sanic/pull/1482>`_
|
`#1482 <https://github.com/huge-success/sanic/pull/1482>`_
|
||||||
Add support for the ``stream`` parameter of ``sanic.Sanic.add_route()``
|
Add support for the ``stream`` parameter of ``sanic.Sanic.add_route()``
|
||||||
available to ``sanic.Blueprint.add_route()``.
|
available to ``sanic.Blueprint.add_route()``.
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1481 <https://github.com/huge-success/sanic/pull/1481>`_
|
`#1481 <https://github.com/huge-success/sanic/pull/1481>`_
|
||||||
Accept negative values for route parameters with type ``int`` or ``number``.
|
Accept negative values for route parameters with type ``int`` or ``number``.
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1476 <https://github.com/huge-success/sanic/pull/1476>`_
|
`#1476 <https://github.com/huge-success/sanic/pull/1476>`_
|
||||||
Deprecated the use of ``sanic.request.Request.raw_args`` - it has a
|
Deprecated the use of ``sanic.request.Request.raw_args`` - it has a
|
||||||
fundamental flaw in which is drops repeated query string parameters.
|
fundamental flaw in which is drops repeated query string parameters.
|
||||||
Added ``sanic.request.Request.query_args`` as a replacement for the
|
Added ``sanic.request.Request.query_args`` as a replacement for the
|
||||||
original use-case.
|
original use-case.
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1472 <https://github.com/huge-success/sanic/pull/1472>`_
|
`#1472 <https://github.com/huge-success/sanic/pull/1472>`_
|
||||||
Remove an unwanted ``None`` check in Request class ``repr`` implementation.
|
Remove an unwanted ``None`` check in Request class ``repr`` implementation.
|
||||||
This changes the default ``repr`` of a Request from ``<Request>`` to
|
This changes the default ``repr`` of a Request from ``<Request>`` to
|
||||||
``<Request: None />``
|
``<Request: None />``
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1470 <https://github.com/huge-success/sanic/pull/1470>`_
|
`#1470 <https://github.com/huge-success/sanic/pull/1470>`_
|
||||||
Added 2 new parameters to ``sanic.app.Sanic.create_server``\ :
|
Added 2 new parameters to ``sanic.app.Sanic.create_server``\ :
|
||||||
|
|
||||||
|
@ -496,21 +593,21 @@ Features
|
||||||
|
|
||||||
This is a breaking change.
|
This is a breaking change.
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1499 <https://github.com/huge-success/sanic/pull/1499>`_
|
`#1499 <https://github.com/huge-success/sanic/pull/1499>`_
|
||||||
Added a set of test cases that test and benchmark route resolution.
|
Added a set of test cases that test and benchmark route resolution.
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1457 <https://github.com/huge-success/sanic/pull/1457>`_
|
`#1457 <https://github.com/huge-success/sanic/pull/1457>`_
|
||||||
The type of the ``"max-age"`` value in a ``sanic.cookies.Cookie`` is now
|
The type of the ``"max-age"`` value in a ``sanic.cookies.Cookie`` is now
|
||||||
enforced to be an integer. Non-integer values are replaced with ``0``.
|
enforced to be an integer. Non-integer values are replaced with ``0``.
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1445 <https://github.com/huge-success/sanic/pull/1445>`_
|
`#1445 <https://github.com/huge-success/sanic/pull/1445>`_
|
||||||
Added the ``endpoint`` attribute to an incoming ``request``\ , containing the
|
Added the ``endpoint`` attribute to an incoming ``request``\ , containing the
|
||||||
name of the handler function.
|
name of the handler function.
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1423 <https://github.com/huge-success/sanic/pull/1423>`_
|
`#1423 <https://github.com/huge-success/sanic/pull/1423>`_
|
||||||
Improved request streaming. ``request.stream`` is now a bounded-size buffer
|
Improved request streaming. ``request.stream`` is now a bounded-size buffer
|
||||||
instead of an unbounded queue. Callers must now call
|
instead of an unbounded queue. Callers must now call
|
||||||
|
@ -523,7 +620,7 @@ Bugfixes
|
||||||
********
|
********
|
||||||
|
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1502 <https://github.com/huge-success/sanic/pull/1502>`_
|
`#1502 <https://github.com/huge-success/sanic/pull/1502>`_
|
||||||
Sanic was prefetching ``time.time()`` and updating it once per second to
|
Sanic was prefetching ``time.time()`` and updating it once per second to
|
||||||
avoid excessive ``time.time()`` calls. The implementation was observed to
|
avoid excessive ``time.time()`` calls. The implementation was observed to
|
||||||
|
@ -531,25 +628,25 @@ Bugfixes
|
||||||
to negligible, so this has been removed. Fixes
|
to negligible, so this has been removed. Fixes
|
||||||
`#1500 <https://github.com/huge-success/sanic/pull/1500>`_
|
`#1500 <https://github.com/huge-success/sanic/pull/1500>`_
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1501 <https://github.com/huge-success/sanic/pull/1501>`_
|
`#1501 <https://github.com/huge-success/sanic/pull/1501>`_
|
||||||
Fix a bug in the auto-reloader when the process was launched as a module
|
Fix a bug in the auto-reloader when the process was launched as a module
|
||||||
i.e. ``python -m init0.mod1`` where the sanic server is started
|
i.e. ``python -m init0.mod1`` where the sanic server is started
|
||||||
in ``init0/mod1.py`` with ``debug`` enabled and imports another module in
|
in ``init0/mod1.py`` with ``debug`` enabled and imports another module in
|
||||||
``init0``.
|
``init0``.
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1376 <https://github.com/huge-success/sanic/pull/1376>`_
|
`#1376 <https://github.com/huge-success/sanic/pull/1376>`_
|
||||||
Allow sanic test client to bind to a random port by specifying
|
Allow sanic test client to bind to a random port by specifying
|
||||||
``port=None`` when constructing a ``SanicTestClient``
|
``port=None`` when constructing a ``SanicTestClient``
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1399 <https://github.com/huge-success/sanic/pull/1399>`_
|
`#1399 <https://github.com/huge-success/sanic/pull/1399>`_
|
||||||
Added the ability to specify middleware on a blueprint group, so that all
|
Added the ability to specify middleware on a blueprint group, so that all
|
||||||
routes produced from the blueprints in the group have the middleware
|
routes produced from the blueprints in the group have the middleware
|
||||||
applied.
|
applied.
|
||||||
|
|
||||||
*
|
*
|
||||||
`#1442 <https://github.com/huge-success/sanic/pull/1442>`_
|
`#1442 <https://github.com/huge-success/sanic/pull/1442>`_
|
||||||
Allow the the use the ``SANIC_ACCESS_LOG`` environment variable to
|
Allow the the use the ``SANIC_ACCESS_LOG`` environment variable to
|
||||||
enable/disable the access log when not explicitly passed to ``app.run()``.
|
enable/disable the access log when not explicitly passed to ``app.run()``.
|
||||||
|
@ -591,7 +688,7 @@ Version 18.12
|
||||||
18.12.0
|
18.12.0
|
||||||
*******
|
*******
|
||||||
|
|
||||||
*
|
*
|
||||||
Changes:
|
Changes:
|
||||||
|
|
||||||
|
|
||||||
|
@ -609,7 +706,7 @@ Version 18.12
|
||||||
* Deprecate Handler.log
|
* Deprecate Handler.log
|
||||||
* Pinned httptools requirement to version 0.0.10+
|
* Pinned httptools requirement to version 0.0.10+
|
||||||
|
|
||||||
*
|
*
|
||||||
Fixes:
|
Fixes:
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
__version__ = "20.9.1"
|
__version__ = "20.12.7"
|
||||||
|
|
43
sanic/app.py
43
sanic/app.py
|
@ -2,6 +2,7 @@ import logging
|
||||||
import logging.config
|
import logging.config
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
from asyncio import CancelledError, Protocol, ensure_future, get_event_loop
|
from asyncio import CancelledError, Protocol, ensure_future, get_event_loop
|
||||||
from collections import defaultdict, deque
|
from collections import defaultdict, deque
|
||||||
|
@ -12,6 +13,7 @@ from ssl import Purpose, SSLContext, create_default_context
|
||||||
from traceback import format_exc
|
from traceback import format_exc
|
||||||
from typing import Any, Dict, Optional, Type, Union
|
from typing import Any, Dict, Optional, Type, Union
|
||||||
from urllib.parse import urlencode, urlunparse
|
from urllib.parse import urlencode, urlunparse
|
||||||
|
from warnings import warn
|
||||||
|
|
||||||
from sanic import reloader_helpers
|
from sanic import reloader_helpers
|
||||||
from sanic.asgi import ASGIApp
|
from sanic.asgi import ASGIApp
|
||||||
|
@ -50,6 +52,7 @@ class Sanic:
|
||||||
strict_slashes=False,
|
strict_slashes=False,
|
||||||
log_config=None,
|
log_config=None,
|
||||||
configure_logging=True,
|
configure_logging=True,
|
||||||
|
register=None,
|
||||||
):
|
):
|
||||||
|
|
||||||
# Get name from previous stack frame
|
# Get name from previous stack frame
|
||||||
|
@ -63,6 +66,18 @@ class Sanic:
|
||||||
if configure_logging:
|
if configure_logging:
|
||||||
logging.config.dictConfig(log_config or LOGGING_CONFIG_DEFAULTS)
|
logging.config.dictConfig(log_config or LOGGING_CONFIG_DEFAULTS)
|
||||||
|
|
||||||
|
if sys.version_info >= (3, 10):
|
||||||
|
error_logger.error(
|
||||||
|
"Unsupported version of Python has been detected.\n\nPython "
|
||||||
|
f"version {sys.version} is not supported by this version of "
|
||||||
|
"Sanic. There is a security advisory that has been issued for "
|
||||||
|
"Sanic v20.12 while running Python 3.10+. You should either "
|
||||||
|
"use a supported version of Python (v3.6 - v3.9) or upgrade "
|
||||||
|
"Sanic to v21+.\n\nPlease see https://github.com/sanic-org/"
|
||||||
|
"sanic/security/advisories/GHSA-7p79-6x2v-5h88 for "
|
||||||
|
"more information.\n"
|
||||||
|
)
|
||||||
|
|
||||||
self.name = name
|
self.name = name
|
||||||
self.asgi = False
|
self.asgi = False
|
||||||
self.router = router or Router(self)
|
self.router = router or Router(self)
|
||||||
|
@ -88,7 +103,11 @@ class Sanic:
|
||||||
# Register alternative method names
|
# Register alternative method names
|
||||||
self.go_fast = self.run
|
self.go_fast = self.run
|
||||||
|
|
||||||
self.__class__.register_app(self)
|
if register is not None:
|
||||||
|
self.config.REGISTER = register
|
||||||
|
|
||||||
|
if self.config.REGISTER:
|
||||||
|
self.__class__.register_app(self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def loop(self):
|
def loop(self):
|
||||||
|
@ -489,9 +508,7 @@ class Sanic:
|
||||||
websocket_handler = partial(
|
websocket_handler = partial(
|
||||||
self._websocket_handler, handler, subprotocols=subprotocols
|
self._websocket_handler, handler, subprotocols=subprotocols
|
||||||
)
|
)
|
||||||
websocket_handler.__name__ = (
|
websocket_handler.__name__ = handler.__name__
|
||||||
"websocket_handler_" + handler.__name__
|
|
||||||
)
|
|
||||||
routes.extend(
|
routes.extend(
|
||||||
self.router.add(
|
self.router.add(
|
||||||
uri=uri,
|
uri=uri,
|
||||||
|
@ -742,6 +759,24 @@ class Sanic:
|
||||||
kw.update(name=view_name)
|
kw.update(name=view_name)
|
||||||
|
|
||||||
uri, route = self.router.find_route_by_view_name(view_name, **kw)
|
uri, route = self.router.find_route_by_view_name(view_name, **kw)
|
||||||
|
|
||||||
|
# TODO(laggardkernel): this fix should be removed in v21.3.
|
||||||
|
# Try again without the unnecessary prefix "websocket_handler_",
|
||||||
|
# which was added by accident on non-blueprint handlers. GH-2021
|
||||||
|
if not (uri and route) and view_name.startswith("websocket_handler_"):
|
||||||
|
view_name = view_name[18:]
|
||||||
|
uri, route = self.router.find_route_by_view_name(view_name, **kw)
|
||||||
|
if uri and route:
|
||||||
|
warn(
|
||||||
|
"The bug of adding unnecessary `websocket_handler_` "
|
||||||
|
"prefix in param `view_name` for non-blueprint handlers "
|
||||||
|
"is fixed. This backward support will be removed in "
|
||||||
|
"v21.3. Please update `Sanic.url_for()` callings in your "
|
||||||
|
"code soon.",
|
||||||
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
|
||||||
if not (uri and route):
|
if not (uri and route):
|
||||||
raise URLBuildError(
|
raise URLBuildError(
|
||||||
f"Endpoint with name `{view_name}` was not found"
|
f"Endpoint with name `{view_name}` was not found"
|
||||||
|
|
|
@ -20,7 +20,6 @@ if use_trio:
|
||||||
def stat_async(path):
|
def stat_async(path):
|
||||||
return Path(path).stat()
|
return Path(path).stat()
|
||||||
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
from aiofiles import open as aio_open # type: ignore
|
from aiofiles import open as aio_open # type: ignore
|
||||||
from aiofiles.os import stat as stat_async # type: ignore # noqa: F401
|
from aiofiles.os import stat as stat_async # type: ignore # noqa: F401
|
||||||
|
|
|
@ -40,6 +40,7 @@ DEFAULT_CONFIG = {
|
||||||
"PROXIES_COUNT": None,
|
"PROXIES_COUNT": None,
|
||||||
"FORWARDED_FOR_HEADER": "X-Forwarded-For",
|
"FORWARDED_FOR_HEADER": "X-Forwarded-For",
|
||||||
"FALLBACK_ERROR_FORMAT": "html",
|
"FALLBACK_ERROR_FORMAT": "html",
|
||||||
|
"REGISTER": True,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ class StreamBuffer:
|
||||||
self._queue = asyncio.Queue(buffer_size)
|
self._queue = asyncio.Queue(buffer_size)
|
||||||
|
|
||||||
async def read(self):
|
async def read(self):
|
||||||
""" Stop reading when gets None """
|
"""Stop reading when gets None"""
|
||||||
payload = await self._queue.get()
|
payload = await self._queue.get()
|
||||||
self._queue.task_done()
|
self._queue.task_done()
|
||||||
return payload
|
return payload
|
||||||
|
@ -265,9 +265,12 @@ class Request:
|
||||||
:type errors: str
|
:type errors: str
|
||||||
:return: RequestParameters
|
:return: RequestParameters
|
||||||
"""
|
"""
|
||||||
if not self.parsed_args[
|
if (
|
||||||
(keep_blank_values, strict_parsing, encoding, errors)
|
keep_blank_values,
|
||||||
]:
|
strict_parsing,
|
||||||
|
encoding,
|
||||||
|
errors,
|
||||||
|
) not in self.parsed_args:
|
||||||
if self.query_string:
|
if self.query_string:
|
||||||
self.parsed_args[
|
self.parsed_args[
|
||||||
(keep_blank_values, strict_parsing, encoding, errors)
|
(keep_blank_values, strict_parsing, encoding, errors)
|
||||||
|
@ -321,9 +324,12 @@ class Request:
|
||||||
:type errors: str
|
:type errors: str
|
||||||
:return: list
|
:return: list
|
||||||
"""
|
"""
|
||||||
if not self.parsed_not_grouped_args[
|
if (
|
||||||
(keep_blank_values, strict_parsing, encoding, errors)
|
keep_blank_values,
|
||||||
]:
|
strict_parsing,
|
||||||
|
encoding,
|
||||||
|
errors,
|
||||||
|
) not in self.parsed_not_grouped_args:
|
||||||
if self.query_string:
|
if self.query_string:
|
||||||
self.parsed_not_grouped_args[
|
self.parsed_not_grouped_args[
|
||||||
(keep_blank_values, strict_parsing, encoding, errors)
|
(keep_blank_values, strict_parsing, encoding, errors)
|
||||||
|
|
|
@ -169,7 +169,11 @@ class HttpProtocol(asyncio.Protocol):
|
||||||
self.request_class = self.app.request_class or Request
|
self.request_class = self.app.request_class or Request
|
||||||
self.is_request_stream = self.app.is_request_stream
|
self.is_request_stream = self.app.is_request_stream
|
||||||
self._is_stream_handler = False
|
self._is_stream_handler = False
|
||||||
self._not_paused = asyncio.Event(loop=deprecated_loop)
|
self._not_paused = (
|
||||||
|
asyncio.Event()
|
||||||
|
if sys.version_info >= (3, 10)
|
||||||
|
else asyncio.Event(loop=deprecated_loop)
|
||||||
|
)
|
||||||
self._total_request_size = 0
|
self._total_request_size = 0
|
||||||
self._request_timeout_handler = None
|
self._request_timeout_handler = None
|
||||||
self._response_timeout_handler = None
|
self._response_timeout_handler = None
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from functools import partial, wraps
|
from functools import partial, wraps
|
||||||
from mimetypes import guess_type
|
from mimetypes import guess_type
|
||||||
from os import path
|
from os import path, sep
|
||||||
from re import sub
|
from pathlib import Path
|
||||||
from time import gmtime, strftime
|
from time import gmtime, strftime
|
||||||
from urllib.parse import unquote
|
from urllib.parse import unquote
|
||||||
|
|
||||||
|
@ -26,28 +26,41 @@ async def _static_request_handler(
|
||||||
content_type=None,
|
content_type=None,
|
||||||
file_uri=None,
|
file_uri=None,
|
||||||
):
|
):
|
||||||
# Using this to determine if the URL is trying to break out of the path
|
|
||||||
# served. os.path.realpath seems to be very slow
|
|
||||||
if file_uri and "../" in file_uri:
|
|
||||||
raise InvalidUsage("Invalid URL")
|
|
||||||
# Merge served directory and requested file if provided
|
# Merge served directory and requested file if provided
|
||||||
# Strip all / that in the beginning of the URL to help prevent python
|
file_path_raw = Path(unquote(file_or_directory))
|
||||||
# from herping a derp and treating the uri as an absolute path
|
root_path = file_path = file_path_raw.resolve()
|
||||||
root_path = file_path = file_or_directory
|
not_found = FileNotFound(
|
||||||
if file_uri:
|
"File not found",
|
||||||
file_path = path.join(file_or_directory, sub("^[/]*", "", file_uri))
|
path=file_or_directory,
|
||||||
|
relative_url=file_uri,
|
||||||
|
)
|
||||||
|
|
||||||
|
if file_uri:
|
||||||
|
# Strip all / that in the beginning of the URL to help prevent
|
||||||
|
# python from herping a derp and treating the uri as an
|
||||||
|
# absolute path
|
||||||
|
unquoted_file_uri = unquote(file_uri).lstrip("/")
|
||||||
|
file_path_raw = Path(file_or_directory, unquoted_file_uri)
|
||||||
|
file_path = file_path_raw.resolve()
|
||||||
|
if (
|
||||||
|
file_path < root_path and not file_path_raw.is_symlink()
|
||||||
|
) or ".." in file_path_raw.parts:
|
||||||
|
error_logger.exception(
|
||||||
|
f"File not found: path={file_or_directory}, "
|
||||||
|
f"relative_url={file_uri}"
|
||||||
|
)
|
||||||
|
raise not_found
|
||||||
|
|
||||||
|
try:
|
||||||
|
file_path.relative_to(root_path)
|
||||||
|
except ValueError:
|
||||||
|
if not file_path_raw.is_symlink():
|
||||||
|
error_logger.exception(
|
||||||
|
f"File not found: path={file_or_directory}, "
|
||||||
|
f"relative_url={file_uri}"
|
||||||
|
)
|
||||||
|
raise not_found
|
||||||
|
|
||||||
# URL decode the path sent by the browser otherwise we won't be able to
|
|
||||||
# match filenames which got encoded (filenames with spaces etc)
|
|
||||||
file_path = path.abspath(unquote(file_path))
|
|
||||||
if not file_path.startswith(path.abspath(unquote(root_path))):
|
|
||||||
error_logger.exception(
|
|
||||||
f"File not found: path={file_or_directory}, "
|
|
||||||
f"relative_url={file_uri}"
|
|
||||||
)
|
|
||||||
raise FileNotFound(
|
|
||||||
"File not found", path=file_or_directory, relative_url=file_uri
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
headers = {}
|
headers = {}
|
||||||
# Check if the client has been sent this file before
|
# Check if the client has been sent this file before
|
||||||
|
|
5
setup.py
5
setup.py
|
@ -57,7 +57,8 @@ setup_kwargs = {
|
||||||
"author": "Sanic Community",
|
"author": "Sanic Community",
|
||||||
"author_email": "admhpkns@gmail.com",
|
"author_email": "admhpkns@gmail.com",
|
||||||
"description": (
|
"description": (
|
||||||
"A web server and web framework that's written to go fast. Build fast. Run fast."
|
"A web server and web framework that's written to go fast. "
|
||||||
|
"Build fast. Run fast."
|
||||||
),
|
),
|
||||||
"long_description": long_description,
|
"long_description": long_description,
|
||||||
"packages": ["sanic"],
|
"packages": ["sanic"],
|
||||||
|
@ -87,7 +88,7 @@ requirements = [
|
||||||
uvloop,
|
uvloop,
|
||||||
ujson,
|
ujson,
|
||||||
"aiofiles>=0.6.0",
|
"aiofiles>=0.6.0",
|
||||||
"websockets>=8.1,<9.0",
|
"websockets>=8.1,<=9.1",
|
||||||
"multidict>=5.0,<6.0",
|
"multidict>=5.0,<6.0",
|
||||||
"httpx==0.15.4",
|
"httpx==0.15.4",
|
||||||
]
|
]
|
||||||
|
|
|
@ -3,6 +3,7 @@ import logging
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from inspect import isawaitable
|
from inspect import isawaitable
|
||||||
|
from os import environ
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
@ -290,6 +291,7 @@ def test_app_registry_name_reuse():
|
||||||
with pytest.raises(SanicException):
|
with pytest.raises(SanicException):
|
||||||
Sanic("test")
|
Sanic("test")
|
||||||
Sanic.test_mode = True
|
Sanic.test_mode = True
|
||||||
|
Sanic("test")
|
||||||
|
|
||||||
|
|
||||||
def test_app_registry_retrieval():
|
def test_app_registry_retrieval():
|
||||||
|
@ -306,3 +308,17 @@ def test_get_app_does_not_exist_force_create():
|
||||||
assert isinstance(
|
assert isinstance(
|
||||||
Sanic.get_app("does-not-exist", force_create=True), Sanic
|
Sanic.get_app("does-not-exist", force_create=True), Sanic
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_app_no_registry():
|
||||||
|
Sanic("no-register", register=False)
|
||||||
|
with pytest.raises(SanicException):
|
||||||
|
Sanic.get_app("no-register")
|
||||||
|
|
||||||
|
|
||||||
|
def test_app_no_registry_env():
|
||||||
|
environ["SANIC_REGISTER"] = "False"
|
||||||
|
Sanic("no-register")
|
||||||
|
with pytest.raises(SanicException):
|
||||||
|
Sanic.get_app("no-register")
|
||||||
|
del environ["SANIC_REGISTER"]
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
import asyncio
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from collections import deque, namedtuple
|
from collections import deque, namedtuple
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
@ -82,14 +79,6 @@ def test_listeners_triggered(app):
|
||||||
with pytest.warns(UserWarning):
|
with pytest.warns(UserWarning):
|
||||||
server.run()
|
server.run()
|
||||||
|
|
||||||
all_tasks = (
|
|
||||||
asyncio.Task.all_tasks()
|
|
||||||
if sys.version_info < (3, 7)
|
|
||||||
else asyncio.all_tasks(asyncio.get_event_loop())
|
|
||||||
)
|
|
||||||
for task in all_tasks:
|
|
||||||
task.cancel()
|
|
||||||
|
|
||||||
assert before_server_start
|
assert before_server_start
|
||||||
assert after_server_start
|
assert after_server_start
|
||||||
assert before_server_stop
|
assert before_server_stop
|
||||||
|
@ -132,14 +121,6 @@ def test_listeners_triggered_async(app):
|
||||||
with pytest.warns(UserWarning):
|
with pytest.warns(UserWarning):
|
||||||
server.run()
|
server.run()
|
||||||
|
|
||||||
all_tasks = (
|
|
||||||
asyncio.Task.all_tasks()
|
|
||||||
if sys.version_info < (3, 7)
|
|
||||||
else asyncio.all_tasks(asyncio.get_event_loop())
|
|
||||||
)
|
|
||||||
for task in all_tasks:
|
|
||||||
task.cancel()
|
|
||||||
|
|
||||||
assert before_server_start
|
assert before_server_start
|
||||||
assert after_server_start
|
assert after_server_start
|
||||||
assert before_server_stop
|
assert before_server_stop
|
||||||
|
|
|
@ -13,7 +13,7 @@ from sanic.exceptions import PyFileError
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def temp_path():
|
def temp_path():
|
||||||
""" a simple cross platform replacement for NamedTemporaryFile """
|
"""a simple cross platform replacement for NamedTemporaryFile"""
|
||||||
with TemporaryDirectory() as td:
|
with TemporaryDirectory() as td:
|
||||||
yield Path(td, "file")
|
yield Path(td, "file")
|
||||||
|
|
||||||
|
|
|
@ -102,7 +102,7 @@ def test_logging_pass_customer_logconfig():
|
||||||
|
|
||||||
@pytest.mark.parametrize("debug", (True, False))
|
@pytest.mark.parametrize("debug", (True, False))
|
||||||
def test_log_connection_lost(app, debug, monkeypatch):
|
def test_log_connection_lost(app, debug, monkeypatch):
|
||||||
""" Should not log Connection lost exception on non debug """
|
"""Should not log Connection lost exception on non debug"""
|
||||||
stream = StringIO()
|
stream = StringIO()
|
||||||
root = logging.getLogger("sanic.root")
|
root = logging.getLogger("sanic.root")
|
||||||
root.addHandler(logging.StreamHandler(stream))
|
root.addHandler(logging.StreamHandler(stream))
|
||||||
|
|
|
@ -290,6 +290,17 @@ def test_query_string(app):
|
||||||
assert request.args.get("test3", default="My value") == "My value"
|
assert request.args.get("test3", default="My value") == "My value"
|
||||||
|
|
||||||
|
|
||||||
|
def test_popped_stays_popped(app):
|
||||||
|
@app.route("/")
|
||||||
|
async def handler(request):
|
||||||
|
return text("OK")
|
||||||
|
|
||||||
|
request, response = app.test_client.get("/", params=[("test1", "1")])
|
||||||
|
|
||||||
|
assert request.args.pop("test1") == ["1"]
|
||||||
|
assert "test1" not in request.args
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_query_string_asgi(app):
|
async def test_query_string_asgi(app):
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
import inspect
|
import inspect
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
from time import gmtime, strftime
|
from time import gmtime, strftime
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from sanic.app import Sanic
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def static_file_directory():
|
def static_file_directory():
|
||||||
|
@ -15,6 +19,22 @@ def static_file_directory():
|
||||||
return static_directory
|
return static_directory
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def double_dotted_directory_file(static_file_directory: str):
|
||||||
|
"""Generate double dotted directory and its files"""
|
||||||
|
if sys.platform == "win32":
|
||||||
|
raise Exception("Windows doesn't support double dotted directories")
|
||||||
|
|
||||||
|
file_path = Path(static_file_directory) / "dotted.." / "dot.txt"
|
||||||
|
double_dotted_dir = file_path.parent
|
||||||
|
Path.mkdir(double_dotted_dir, exist_ok=True)
|
||||||
|
with open(file_path, "w") as f:
|
||||||
|
f.write("DOT\n")
|
||||||
|
yield file_path
|
||||||
|
Path.unlink(file_path)
|
||||||
|
Path.rmdir(double_dotted_dir)
|
||||||
|
|
||||||
|
|
||||||
def get_file_path(static_file_directory, file_name):
|
def get_file_path(static_file_directory, file_name):
|
||||||
return os.path.join(static_file_directory, file_name)
|
return os.path.join(static_file_directory, file_name)
|
||||||
|
|
||||||
|
@ -374,3 +394,43 @@ def test_static_name(app, static_file_directory, static_name, file_name):
|
||||||
request, response = app.test_client.get(f"/static/{file_name}")
|
request, response = app.test_client.get(f"/static/{file_name}")
|
||||||
|
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
sys.platform == "win32",
|
||||||
|
reason="Windows does not support double dotted directories",
|
||||||
|
)
|
||||||
|
def test_dotted_dir_ok(
|
||||||
|
app: Sanic, static_file_directory: str, double_dotted_directory_file: Path
|
||||||
|
):
|
||||||
|
app.static("/foo", static_file_directory)
|
||||||
|
dot_relative_path = str(
|
||||||
|
double_dotted_directory_file.relative_to(static_file_directory)
|
||||||
|
)
|
||||||
|
_, response = app.test_client.get("/foo/" + dot_relative_path)
|
||||||
|
assert response.status == 200
|
||||||
|
assert response.body == b"DOT\n"
|
||||||
|
|
||||||
|
|
||||||
|
def test_breakout(app: Sanic, static_file_directory: str):
|
||||||
|
app.static("/foo", static_file_directory)
|
||||||
|
|
||||||
|
_, response = app.test_client.get("/foo/..%2Ffake/server.py")
|
||||||
|
assert response.status == 404
|
||||||
|
|
||||||
|
_, response = app.test_client.get("/foo/..%2Fstatic/test.file")
|
||||||
|
assert response.status == 404
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
sys.platform != "win32", reason="Block backslash on Windows only"
|
||||||
|
)
|
||||||
|
def test_double_backslash_prohibited_on_win32(
|
||||||
|
app: Sanic, static_file_directory: str
|
||||||
|
):
|
||||||
|
app.static("/foo", static_file_directory)
|
||||||
|
|
||||||
|
_, response = app.test_client.get("/foo/static/..\\static/test.file")
|
||||||
|
assert response.status == 404
|
||||||
|
_, response = app.test_client.get("/foo/static\\../static/test.file")
|
||||||
|
assert response.status == 404
|
||||||
|
|
|
@ -348,3 +348,13 @@ def test_methodview_naming(methodview_app):
|
||||||
|
|
||||||
assert viewone_url == "/view_one"
|
assert viewone_url == "/view_one"
|
||||||
assert viewtwo_url == "/view_two"
|
assert viewtwo_url == "/view_two"
|
||||||
|
|
||||||
|
|
||||||
|
def test_url_for_with_websocket_handlers(app):
|
||||||
|
# Test for a specific bugfix in GH-2021
|
||||||
|
@app.websocket("/ws")
|
||||||
|
async def my_handler(request, ws):
|
||||||
|
pass
|
||||||
|
|
||||||
|
assert app.url_for("my_handler") == "/ws"
|
||||||
|
assert app.url_for("websocket_handler_my_handler") == "/ws"
|
||||||
|
|
4
tox.ini
4
tox.ini
|
@ -16,11 +16,11 @@ deps =
|
||||||
pytest-dependency
|
pytest-dependency
|
||||||
httpcore==0.11.*
|
httpcore==0.11.*
|
||||||
httpx==0.15.4
|
httpx==0.15.4
|
||||||
chardet==3.*
|
multidict>=5.0,<6.0
|
||||||
beautifulsoup4
|
beautifulsoup4
|
||||||
gunicorn==20.0.4
|
gunicorn==20.0.4
|
||||||
uvicorn
|
uvicorn
|
||||||
websockets>=8.1,<9.0
|
websockets>=8.1,<=9.1
|
||||||
commands =
|
commands =
|
||||||
pytest {posargs:tests --cov sanic}
|
pytest {posargs:tests --cov sanic}
|
||||||
- coverage combine --append
|
- coverage combine --append
|
||||||
|
|
Loading…
Reference in New Issue
Block a user