Compare commits
	
		
			1 Commits
		
	
	
		
			bind_excep
			...
			smoother-p
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | e0839fe130 | 
							
								
								
									
										28
									
								
								.github/workflows/coverage.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										28
									
								
								.github/workflows/coverage.yml
									
									
									
									
										vendored
									
									
								
							| @@ -12,23 +12,29 @@ on: | |||||||
|       - main |       - main | ||||||
|       - current-release |       - current-release | ||||||
|       - "*LTS" |       - "*LTS" | ||||||
|  |  | ||||||
| jobs: | jobs: | ||||||
|   coverage: |   test: | ||||||
|     name: Check coverage |     runs-on: ${{ matrix.os }} | ||||||
|     runs-on: ubuntu-latest |  | ||||||
|     strategy: |     strategy: | ||||||
|  |       matrix: | ||||||
|  |         python-version: [3.9] | ||||||
|  |         os: [ubuntu-latest] | ||||||
|       fail-fast: false |       fail-fast: false | ||||||
|  |  | ||||||
|     steps: |     steps: | ||||||
|       - name: Run coverage |       - uses: actions/checkout@v2 | ||||||
|         uses: sanic-org/simple-tox-action@v1 |       - uses: actions/setup-python@v1 | ||||||
|         with: |         with: | ||||||
|           python-version: "3.11" |           python-version: ${{ matrix.python-version }} | ||||||
|           tox-env: coverage |  | ||||||
|           ignore-errors: true |       - name: Install dependencies 🔨 | ||||||
|       - name: Run Codecov |         run: | | ||||||
|         uses: codecov/codecov-action@v3 |           python -m pip install --upgrade pip | ||||||
|  |           pip install tox | ||||||
|  |       - name: Run coverage | ||||||
|  |         run: tox -e coverage | ||||||
|  |         continue-on-error: true | ||||||
|  |       - uses: codecov/codecov-action@v2 | ||||||
|         with: |         with: | ||||||
|           files: ./coverage.xml |           files: ./coverage.xml | ||||||
|           fail_ci_if_error: false |           fail_ci_if_error: false | ||||||
|   | |||||||
							
								
								
									
										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" | ||||||
							
								
								
									
										37
									
								
								.github/workflows/pr-bandit.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								.github/workflows/pr-bandit.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | |||||||
|  | name: Security Analysis | ||||||
|  | on: | ||||||
|  |   pull_request: | ||||||
|  |     branches: | ||||||
|  |       - main | ||||||
|  |       - current-release | ||||||
|  |       - "*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.8, tox-env: security} | ||||||
|  |           - { python-version: 3.9, tox-env: security} | ||||||
|  |           - { python-version: "3.10", tox-env: security} | ||||||
|  |           - { python-version: "3.11", 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 }}" | ||||||
							
								
								
									
										33
									
								
								.github/workflows/pr-docs.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								.github/workflows/pr-docs.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | |||||||
|  | name: Document Linter | ||||||
|  | on: | ||||||
|  |   pull_request: | ||||||
|  |     branches: | ||||||
|  |       - main | ||||||
|  |       - current-release | ||||||
|  |       - "*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.10", 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 }}" | ||||||
							
								
								
									
										34
									
								
								.github/workflows/pr-linter.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								.github/workflows/pr-linter.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | |||||||
|  | name: Linter Checks | ||||||
|  | on: | ||||||
|  |   pull_request: | ||||||
|  |     branches: | ||||||
|  |       - main | ||||||
|  |       - current-release | ||||||
|  |       - "*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.10", 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: "pypy310" | ||||||
|  |       pypy-version: | ||||||
|  |         description: "Version of PyPy to use" | ||||||
|  |         required: false | ||||||
|  |         default: "pypy-3.10" | ||||||
|  | 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" | ||||||
							
								
								
									
										48
									
								
								.github/workflows/pr-python310.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								.github/workflows/pr-python310.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | |||||||
|  | name: Python 3.10 Tests | ||||||
|  | on: | ||||||
|  |   pull_request: | ||||||
|  |     branches: | ||||||
|  |       - main | ||||||
|  |       - current-release | ||||||
|  |       - "*LTS" | ||||||
|  |     types: [opened, synchronize, reopened, ready_for_review] | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |   testPy310: | ||||||
|  |     if: github.event.pull_request.draft == false | ||||||
|  |     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: "3.10", | ||||||
|  |               tox-env: py310, | ||||||
|  |               ignore-error-flake: "false", | ||||||
|  |               command-timeout: "0", | ||||||
|  |             } | ||||||
|  |           - { | ||||||
|  |               python-version: "3.10", | ||||||
|  |               tox-env: py310-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" | ||||||
							
								
								
									
										48
									
								
								.github/workflows/pr-python311.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								.github/workflows/pr-python311.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | |||||||
|  | name: Python 3.11 Tests | ||||||
|  | on: | ||||||
|  |   pull_request: | ||||||
|  |     branches: | ||||||
|  |       - main | ||||||
|  |       - current-release | ||||||
|  |       - "*LTS" | ||||||
|  |     types: [opened, synchronize, reopened, ready_for_review] | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |   testPy311: | ||||||
|  |     if: github.event.pull_request.draft == false | ||||||
|  |     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: "3.11", | ||||||
|  |               tox-env: py311, | ||||||
|  |               ignore-error-flake: "false", | ||||||
|  |               command-timeout: "0", | ||||||
|  |             } | ||||||
|  |           - { | ||||||
|  |               python-version: "3.11", | ||||||
|  |               tox-env: py311-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" | ||||||
							
								
								
									
										36
									
								
								.github/workflows/pr-python38.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								.github/workflows/pr-python38.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | |||||||
|  | name: Python 3.8 Tests | ||||||
|  | on: | ||||||
|  |   pull_request: | ||||||
|  |     branches: | ||||||
|  |       - main | ||||||
|  |       - current-release | ||||||
|  |       - "*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" | ||||||
							
								
								
									
										48
									
								
								.github/workflows/pr-python39.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								.github/workflows/pr-python39.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | |||||||
|  | name: Python 3.9 Tests | ||||||
|  | on: | ||||||
|  |   pull_request: | ||||||
|  |     branches: | ||||||
|  |       - main | ||||||
|  |       - current-release | ||||||
|  |       - "*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" | ||||||
							
								
								
									
										37
									
								
								.github/workflows/pr-type-check.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								.github/workflows/pr-type-check.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | |||||||
|  | name: Typing Checks | ||||||
|  | on: | ||||||
|  |   pull_request: | ||||||
|  |     branches: | ||||||
|  |       - main | ||||||
|  |       - current-release | ||||||
|  |       - "*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.8, tox-env: type-checking} | ||||||
|  |           - { python-version: 3.9, tox-env: type-checking} | ||||||
|  |           - { python-version: "3.10", tox-env: type-checking} | ||||||
|  |           - { python-version: "3.11", 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 }}" | ||||||
							
								
								
									
										38
									
								
								.github/workflows/pr-windows.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								.github/workflows/pr-windows.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | |||||||
|  | name: Run Unit Tests on Windows | ||||||
|  | on: | ||||||
|  |   pull_request: | ||||||
|  |     branches: | ||||||
|  |       - main | ||||||
|  |       - current-release | ||||||
|  |       - "*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.8, tox-env: py38-no-ext } | ||||||
|  |           - { python-version: 3.9, tox-env: py39-no-ext } | ||||||
|  |           - { python-version: "3.10", tox-env: py310-no-ext } | ||||||
|  |           - { python-version: "3.11", tox-env: py310-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.8", "3.9", "3.10", "3.11"] | ||||||
|  |  | ||||||
|  |     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' | ||||||
							
								
								
									
										39
									
								
								.github/workflows/publish-package.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								.github/workflows/publish-package.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | |||||||
|  | name: Upload Python Package | ||||||
|  |  | ||||||
|  | on: | ||||||
|  |   release: | ||||||
|  |     types: [created] | ||||||
|  |   workflow_dispatch: | ||||||
|  | jobs: | ||||||
|  |   build-n-publish: | ||||||
|  |     name: Build and publish Python 🐍 distributions 📦 to PyPI and TestPyPI | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |     steps: | ||||||
|  |     - uses: actions/checkout@v3 | ||||||
|  |     - name: Set up Python | ||||||
|  |       uses: actions/setup-python@v4 | ||||||
|  |       with: | ||||||
|  |         python-version: "3.x" | ||||||
|  |     - name: Install pypa/build | ||||||
|  |       run: >- | ||||||
|  |         python3 -m | ||||||
|  |         pip install | ||||||
|  |         build | ||||||
|  |         --user | ||||||
|  |     - name: Build a binary wheel and a source tarball | ||||||
|  |       run: >- | ||||||
|  |         python3 -m | ||||||
|  |         build | ||||||
|  |         --sdist | ||||||
|  |         --wheel | ||||||
|  |         --outdir dist/ | ||||||
|  |         . | ||||||
|  |     # - name: Publish distribution 📦 to Test PyPI | ||||||
|  |     #   uses: pypa/gh-action-pypi-publish@release/v1 | ||||||
|  |     #   with: | ||||||
|  |     #     password: ${{ secrets.SANIC_TEST_PYPI_API_TOKEN }} | ||||||
|  |     #     repository-url: https://test.pypi.org/legacy/ | ||||||
|  |     - name: Publish distribution 📦 to PyPI | ||||||
|  |       uses: pypa/gh-action-pypi-publish@release/v1 | ||||||
|  |       with: | ||||||
|  |         password: ${{ secrets.SANIC_PYPI_API_TOKEN }} | ||||||
							
								
								
									
										174
									
								
								.github/workflows/publish-release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										174
									
								
								.github/workflows/publish-release.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,174 +0,0 @@ | |||||||
| name: Publish release |  | ||||||
|  |  | ||||||
| on: |  | ||||||
|   release: |  | ||||||
|     types: [created] |  | ||||||
|  |  | ||||||
| env: |  | ||||||
|   IS_TEST: false |  | ||||||
|   DOCKER_ORG_NAME: sanicframework |  | ||||||
|   DOCKER_IMAGE_NAME: sanic |  | ||||||
|   DOCKER_BASE_IMAGE_NAME: sanic-build |  | ||||||
|   DOCKER_IMAGE_DOCKERFILE: ./docker/Dockerfile |  | ||||||
|   DOCKER_BASE_IMAGE_DOCKERFILE: ./docker/Dockerfile-base |  | ||||||
|  |  | ||||||
| jobs: |  | ||||||
|   generate_info: |  | ||||||
|     name: Generate info |  | ||||||
|     runs-on: ubuntu-latest |  | ||||||
|     outputs: |  | ||||||
|       docker-tags: ${{ steps.generate_docker_info.outputs.tags }} |  | ||||||
|       pypi-version: ${{ steps.parse_version_tag.outputs.pypi-version }} |  | ||||||
|     steps: |  | ||||||
|       - name: Parse version tag |  | ||||||
|         id: parse_version_tag |  | ||||||
|         env: |  | ||||||
|           TAG_NAME: ${{ github.event.release.tag_name }} |  | ||||||
|         run: | |  | ||||||
|           tag_name="${{ env.TAG_NAME }}" |  | ||||||
|  |  | ||||||
|           if [[ ! "${tag_name}" =~ ^v([0-9]{2})\.([0-9]{1,2})\.([0-9]+)$ ]]; then |  | ||||||
|             echo "::error::Tag name must be in the format vYY.MM.MICRO" |  | ||||||
|             exit 1 |  | ||||||
|           fi |  | ||||||
|  |  | ||||||
|           year_output="year=${BASH_REMATCH[1]}" |  | ||||||
|           month_output="month=${BASH_REMATCH[2]}" |  | ||||||
|           pypi_output="pypi-version=${tag_name#v}" |  | ||||||
|  |  | ||||||
|           echo "${year_output}" |  | ||||||
|           echo "${month_output}" |  | ||||||
|           echo "${pypi_output}" |  | ||||||
|  |  | ||||||
|           echo "${year_output}" >> $GITHUB_OUTPUT |  | ||||||
|           echo "${month_output}" >> $GITHUB_OUTPUT |  | ||||||
|           echo "${pypi_output}" >> $GITHUB_OUTPUT |  | ||||||
|  |  | ||||||
|       - name: Get latest release |  | ||||||
|         id: get_latest_release |  | ||||||
|         run: | |  | ||||||
|           latest_tag=$( |  | ||||||
|             curl -L \ |  | ||||||
|               -H "Accept: application/vnd.github+json" \ |  | ||||||
|               -H "Authorization: Bearer ${{ github.token }}" \ |  | ||||||
|               -H "X-GitHub-Api-Version: 2022-11-28" \ |  | ||||||
|               https://api.github.com/repos/${{ github.repository }}/releases/latest \ |  | ||||||
|               | jq -r '.tag_name' |  | ||||||
|           ) |  | ||||||
|           echo "latest_tag=$latest_tag" >> $GITHUB_OUTPUT |  | ||||||
|  |  | ||||||
|       - name: Generate Docker info |  | ||||||
|         id: generate_docker_info |  | ||||||
|         run: | |  | ||||||
|           tag_year="${{ steps.parse_version_tag.outputs.year }}" |  | ||||||
|           tag_month="${{ steps.parse_version_tag.outputs.month }}" |  | ||||||
|           latest_tag="${{ steps.get_latest_release.outputs.latest_tag }}" |  | ||||||
|           tag="${{ github.event.release.tag_name }}" |  | ||||||
|  |  | ||||||
|           tags="${tag_year}.${tag_month}" |  | ||||||
|  |  | ||||||
|           if [[ "${tag_month}" == "12" ]]; then |  | ||||||
|             tags+=",LTS" |  | ||||||
|             echo "::notice::Tag ${tag} is LTS version" |  | ||||||
|           else |  | ||||||
|             echo "::notice::Tag ${tag} is not LTS version" |  | ||||||
|           fi |  | ||||||
|  |  | ||||||
|           if [[ "${latest_tag}" == "${{ github.event.release.tag_name }}" ]]; then |  | ||||||
|             tags+=",latest" |  | ||||||
|             echo "::notice::Tag ${tag} is marked as latest" |  | ||||||
|           else |  | ||||||
|             echo "::notice::Tag ${tag} is not marked as latest" |  | ||||||
|           fi |  | ||||||
|  |  | ||||||
|           tags_output="tags=${tags}" |  | ||||||
|  |  | ||||||
|           echo "${tags_output}" |  | ||||||
|           echo "${tags_output}" >> $GITHUB_OUTPUT |  | ||||||
|  |  | ||||||
|   publish_package: |  | ||||||
|     name: Build and publish package |  | ||||||
|     runs-on: ubuntu-latest |  | ||||||
|     needs: generate_info |  | ||||||
|     steps: |  | ||||||
|     - name: Checkout repo |  | ||||||
|       uses: actions/checkout@v3 |  | ||||||
|  |  | ||||||
|     - name: Setup Python |  | ||||||
|       uses: actions/setup-python@v4 |  | ||||||
|       with: |  | ||||||
|         python-version: "3.11" |  | ||||||
|  |  | ||||||
|     - name: Install dependencies |  | ||||||
|       run: pip install build twine |  | ||||||
|  |  | ||||||
|     - name: Update package version |  | ||||||
|       run: | |  | ||||||
|         echo "__version__ = \"${{ needs.generate_info.outputs.pypi-version }}\"" > sanic/__version__.py |  | ||||||
|  |  | ||||||
|     - name: Build a binary wheel and a source tarball |  | ||||||
|       run: python -m build --sdist --wheel --outdir dist/ . |  | ||||||
|  |  | ||||||
|     - name: Publish to PyPi 🚀 |  | ||||||
|       run: twine upload --non-interactive --disable-progress-bar dist/* |  | ||||||
|       env: |  | ||||||
|         TWINE_USERNAME: __token__ |  | ||||||
|         TWINE_PASSWORD: ${{ env.IS_TEST == 'true' && secrets.SANIC_TEST_PYPI_API_TOKEN || secrets.SANIC_PYPI_API_TOKEN }} |  | ||||||
|         TWINE_REPOSITORY: ${{ env.IS_TEST == 'true' && 'testpypi' || 'pypi' }} |  | ||||||
|  |  | ||||||
|   publish_docker: |  | ||||||
|     name: Publish Docker / Python ${{ matrix.python-version }} |  | ||||||
|     needs: [generate_info, publish_package] |  | ||||||
|     runs-on: ubuntu-latest |  | ||||||
|     strategy: |  | ||||||
|       fail-fast: true |  | ||||||
|       matrix: |  | ||||||
|         python-version: ["3.10", "3.11"] |  | ||||||
|     steps: |  | ||||||
|       - name: Checkout repository |  | ||||||
|         uses: actions/checkout@v3 |  | ||||||
|  |  | ||||||
|       - name: Set up Docker Buildx |  | ||||||
|         uses: docker/setup-buildx-action@v2 |  | ||||||
|  |  | ||||||
|       - name: Login to Docker Hub |  | ||||||
|         uses: docker/login-action@v2 |  | ||||||
|         with: |  | ||||||
|           username: ${{ secrets.DOCKER_ACCESS_USER }} |  | ||||||
|           password: ${{ secrets.DOCKER_ACCESS_TOKEN }} |  | ||||||
|  |  | ||||||
|       - name: Build and push base image |  | ||||||
|         uses: docker/build-push-action@v4 |  | ||||||
|         with: |  | ||||||
|           push: ${{ env.IS_TEST == 'false' }} |  | ||||||
|           file: ${{ env.DOCKER_BASE_IMAGE_DOCKERFILE }} |  | ||||||
|           tags: ${{ env.DOCKER_ORG_NAME }}/${{ env.DOCKER_BASE_IMAGE_NAME }}:${{ matrix.python-version }} |  | ||||||
|           build-args: | |  | ||||||
|             PYTHON_VERSION=${{ matrix.python-version }} |  | ||||||
|  |  | ||||||
|       - name: Parse tags for this Python version |  | ||||||
|         id: parse_tags |  | ||||||
|         run: | |  | ||||||
|           IFS=',' read -ra tags <<< "${{ needs.generate_info.outputs.docker-tags }}" |  | ||||||
|           tag_args="" |  | ||||||
|  |  | ||||||
|           for tag in "${tags[@]}"; do |  | ||||||
|               tag_args+=",${{ env.DOCKER_ORG_NAME }}/${{ env.DOCKER_IMAGE_NAME }}:${tag}-py${{ matrix.python-version }}" |  | ||||||
|           done |  | ||||||
|  |  | ||||||
|           tag_args_output="tag_args=${tag_args:1}" |  | ||||||
|  |  | ||||||
|           echo "${tag_args_output}" |  | ||||||
|           echo "${tag_args_output}" >> $GITHUB_OUTPUT |  | ||||||
|  |  | ||||||
|       - name: Build and push Sanic image |  | ||||||
|         uses: docker/build-push-action@v4 |  | ||||||
|         with: |  | ||||||
|           push: ${{ env.IS_TEST == 'false' }} |  | ||||||
|           file: ${{ env.DOCKER_IMAGE_DOCKERFILE }} |  | ||||||
|           tags: ${{ steps.parse_tags.outputs.tag_args }} |  | ||||||
|           build-args: | |  | ||||||
|             BASE_IMAGE_ORG=${{ env.DOCKER_ORG_NAME }} |  | ||||||
|             BASE_IMAGE_NAME=${{ env.DOCKER_BASE_IMAGE_NAME }} |  | ||||||
|             BASE_IMAGE_TAG=${{ matrix.python-version }} |  | ||||||
|             SANIC_PYPI_VERSION=${{ needs.generate_info.outputs.pypi-version }} |  | ||||||
							
								
								
									
										56
									
								
								.github/workflows/tests.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										56
									
								
								.github/workflows/tests.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,56 +0,0 @@ | |||||||
| name: Tests |  | ||||||
|  |  | ||||||
| on: |  | ||||||
|   push: |  | ||||||
|     branches: |  | ||||||
|       - main |  | ||||||
|       - current-release |  | ||||||
|       - "*LTS" |  | ||||||
|     tags: |  | ||||||
|       - "!*" |  | ||||||
|   pull_request: |  | ||||||
|     branches: |  | ||||||
|       - main |  | ||||||
|       - current-release |  | ||||||
|       - "*LTS" |  | ||||||
|     types: [opened, synchronize, reopened, ready_for_review] |  | ||||||
|  |  | ||||||
| jobs: |  | ||||||
|   run_tests: |  | ||||||
|     name: "${{ matrix.config.platform == 'windows-latest' && 'Windows' || 'Linux' }} / Python ${{ matrix.config.python-version }} / tox -e ${{ matrix.config.tox-env }}" |  | ||||||
|     if: github.event.pull_request.draft == false |  | ||||||
|     runs-on: ${{ matrix.config.platform || 'ubuntu-latest' }} |  | ||||||
|     strategy: |  | ||||||
|       fail-fast: true |  | ||||||
|       matrix: |  | ||||||
|         config: |  | ||||||
|           - { python-version: "3.8",  tox-env: security } |  | ||||||
|           - { python-version: "3.9",  tox-env: security } |  | ||||||
|           - { python-version: "3.10", tox-env: security } |  | ||||||
|           - { python-version: "3.11", tox-env: security } |  | ||||||
|           - { python-version: "3.10", tox-env: lint } |  | ||||||
|           - { python-version: "3.10", tox-env: docs } |  | ||||||
|           - { python-version: "3.8",  tox-env: type-checking } |  | ||||||
|           - { python-version: "3.9",  tox-env: type-checking } |  | ||||||
|           - { python-version: "3.10", tox-env: type-checking } |  | ||||||
|           - { python-version: "3.11", tox-env: type-checking } |  | ||||||
|           - { python-version: "3.8",  tox-env: py38,          max-attempts: 3 } |  | ||||||
|           - { python-version: "3.8",  tox-env: py38-no-ext,   max-attempts: 3 } |  | ||||||
|           - { python-version: "3.9",  tox-env: py39,          max-attempts: 3 } |  | ||||||
|           - { python-version: "3.9",  tox-env: py39-no-ext,   max-attempts: 3 } |  | ||||||
|           - { 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.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 } |  | ||||||
|           - { python-version: "3.10", tox-env: py310-no-ext,  platform: windows-latest, ignore-errors: true } |  | ||||||
|           - { python-version: "3.11", tox-env: py310-no-ext,  platform: windows-latest, ignore-errors: true } |  | ||||||
|     steps: |  | ||||||
|       - name: Run tests |  | ||||||
|         uses: sanic-org/simple-tox-action@v1 |  | ||||||
|         with: |  | ||||||
|           python-version: ${{ matrix.config.python-version }} |  | ||||||
|           tox-env: ${{ matrix.config.tox-env }} |  | ||||||
|           max-attempts: ${{ matrix.config.max-attempts || 1 }} |  | ||||||
|           ignore-errors: ${{ matrix.config.ignore-errors || false }} |  | ||||||
							
								
								
									
										10
									
								
								README.rst
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								README.rst
									
									
									
									
									
								
							| @@ -11,7 +11,7 @@ Sanic | Build fast. Run fast. | |||||||
|     :stub-columns: 1 |     :stub-columns: 1 | ||||||
|  |  | ||||||
|     * - Build |     * - Build | ||||||
|       - | |Tests| |       - | |Py310Test| |Py39Test| |Py38Test| | ||||||
|     * - Docs |     * - Docs | ||||||
|       - | |UserGuide| |Documentation| |       - | |UserGuide| |Documentation| | ||||||
|     * - Package |     * - Package | ||||||
| @@ -27,8 +27,12 @@ Sanic | Build fast. Run fast. | |||||||
|    :target: https://community.sanicframework.org/ |    :target: https://community.sanicframework.org/ | ||||||
| .. |Discord| image:: https://img.shields.io/discord/812221182594121728?logo=discord | .. |Discord| image:: https://img.shields.io/discord/812221182594121728?logo=discord | ||||||
|    :target: https://discord.gg/FARQzAEMAA |    :target: https://discord.gg/FARQzAEMAA | ||||||
| .. |Tests| image:: https://github.com/sanic-org/sanic/actions/workflows/tests.yml/badge.svg?branch=main | .. |Py310Test| image:: https://github.com/sanic-org/sanic/actions/workflows/pr-python310.yml/badge.svg?branch=main | ||||||
|    :target: https://github.com/sanic-org/sanic/actions/workflows/tests.yml |    :target: https://github.com/sanic-org/sanic/actions/workflows/pr-python310.yml | ||||||
|  | .. |Py39Test| image:: https://github.com/sanic-org/sanic/actions/workflows/pr-python39.yml/badge.svg?branch=main | ||||||
|  |    :target: https://github.com/sanic-org/sanic/actions/workflows/pr-python39.yml | ||||||
|  | .. |Py38Test| image:: https://github.com/sanic-org/sanic/actions/workflows/pr-python38.yml/badge.svg?branch=main | ||||||
|  |    :target: https://github.com/sanic-org/sanic/actions/workflows/pr-python38.yml | ||||||
| .. |Documentation| image:: https://readthedocs.org/projects/sanic/badge/?version=latest | .. |Documentation| image:: https://readthedocs.org/projects/sanic/badge/?version=latest | ||||||
|    :target: http://sanic.readthedocs.io/en/latest/?badge=latest |    :target: http://sanic.readthedocs.io/en/latest/?badge=latest | ||||||
| .. |PyPI| image:: https://img.shields.io/pypi/v/sanic.svg | .. |PyPI| image:: https://img.shields.io/pypi/v/sanic.svg | ||||||
|   | |||||||
| @@ -1,13 +1,9 @@ | |||||||
| ARG BASE_IMAGE_ORG |  | ||||||
| ARG BASE_IMAGE_NAME |  | ||||||
| ARG BASE_IMAGE_TAG | ARG BASE_IMAGE_TAG | ||||||
|  |  | ||||||
| FROM ${BASE_IMAGE_ORG}/${BASE_IMAGE_NAME}:${BASE_IMAGE_TAG} | FROM sanicframework/sanic-build:${BASE_IMAGE_TAG} | ||||||
|  |  | ||||||
| RUN apk update | RUN apk update | ||||||
| RUN update-ca-certificates | RUN update-ca-certificates | ||||||
|  |  | ||||||
| ARG SANIC_PYPI_VERSION | RUN pip install sanic | ||||||
|  |  | ||||||
| RUN pip install -U pip && pip install sanic==${SANIC_PYPI_VERSION} |  | ||||||
| RUN apk del build-base | RUN apk del build-base | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								sanic/app.py
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								sanic/app.py
									
									
									
									
									
								
							| @@ -5,7 +5,6 @@ import logging | |||||||
| import logging.config | import logging.config | ||||||
| import re | import re | ||||||
| import sys | import sys | ||||||
|  |  | ||||||
| from asyncio import ( | from asyncio import ( | ||||||
|     AbstractEventLoop, |     AbstractEventLoop, | ||||||
|     CancelledError, |     CancelledError, | ||||||
| @@ -94,7 +93,6 @@ from sanic.worker.inspector import Inspector | |||||||
| from sanic.worker.loader import CertLoader | from sanic.worker.loader import CertLoader | ||||||
| from sanic.worker.manager import WorkerManager | from sanic.worker.manager import WorkerManager | ||||||
|  |  | ||||||
|  |  | ||||||
| if TYPE_CHECKING: | if TYPE_CHECKING: | ||||||
|     try: |     try: | ||||||
|         from sanic_ext import Extend  # type: ignore |         from sanic_ext import Extend  # type: ignore | ||||||
| @@ -1743,6 +1741,20 @@ class Sanic( | |||||||
|         if hasattr(self, "multiplexer"): |         if hasattr(self, "multiplexer"): | ||||||
|             self.multiplexer.ack() |             self.multiplexer.ack() | ||||||
|  |  | ||||||
|  |     def set_serving(self, serving: bool) -> None: | ||||||
|  |         """Set the serving state of the application. | ||||||
|  |  | ||||||
|  |         This method is used to set the serving state of the application. | ||||||
|  |         It is used internally by Sanic and should not typically be called | ||||||
|  |         manually. | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             serving (bool): Whether the application is serving. | ||||||
|  |         """ | ||||||
|  |         self.state.is_running = serving | ||||||
|  |         if hasattr(self, "multiplexer"): | ||||||
|  |             self.multiplexer.set_serving(serving) | ||||||
|  |  | ||||||
|     async def _server_event( |     async def _server_event( | ||||||
|         self, |         self, | ||||||
|         concern: str, |         concern: str, | ||||||
|   | |||||||
| @@ -3,7 +3,6 @@ from __future__ import annotations | |||||||
| import os | import os | ||||||
| import platform | import platform | ||||||
| import sys | import sys | ||||||
|  |  | ||||||
| from asyncio import ( | from asyncio import ( | ||||||
|     AbstractEventLoop, |     AbstractEventLoop, | ||||||
|     CancelledError, |     CancelledError, | ||||||
| @@ -49,7 +48,7 @@ from sanic.application.motd import MOTD | |||||||
| from sanic.application.state import ApplicationServerInfo, Mode, ServerStage | from sanic.application.state import ApplicationServerInfo, Mode, ServerStage | ||||||
| from sanic.base.meta import SanicMeta | from sanic.base.meta import SanicMeta | ||||||
| from sanic.compat import OS_IS_WINDOWS, StartMethod | from sanic.compat import OS_IS_WINDOWS, StartMethod | ||||||
| from sanic.exceptions import SanicException, ServerKilled | from sanic.exceptions import ServerKilled | ||||||
| from sanic.helpers import Default, _default, is_atty | from sanic.helpers import Default, _default, is_atty | ||||||
| from sanic.http.constants import HTTP | from sanic.http.constants import HTTP | ||||||
| from sanic.http.tls import get_ssl_context, process_to_context | from sanic.http.tls import get_ssl_context, process_to_context | ||||||
| @@ -65,13 +64,13 @@ from sanic.server.protocols.http_protocol import HttpProtocol | |||||||
| from sanic.server.protocols.websocket_protocol import WebSocketProtocol | from sanic.server.protocols.websocket_protocol import WebSocketProtocol | ||||||
| from sanic.server.runners import serve | from sanic.server.runners import serve | ||||||
| from sanic.server.socket import configure_socket, remove_unix_socket | from sanic.server.socket import configure_socket, remove_unix_socket | ||||||
|  | from sanic.worker.constants import ProcessState | ||||||
| from sanic.worker.loader import AppLoader | from sanic.worker.loader import AppLoader | ||||||
| from sanic.worker.manager import WorkerManager | from sanic.worker.manager import WorkerManager | ||||||
| from sanic.worker.multiplexer import WorkerMultiplexer | from sanic.worker.multiplexer import WorkerMultiplexer | ||||||
| from sanic.worker.reloader import Reloader | from sanic.worker.reloader import Reloader | ||||||
| from sanic.worker.serve import worker_serve | from sanic.worker.serve import worker_serve | ||||||
|  |  | ||||||
|  |  | ||||||
| if TYPE_CHECKING: | if TYPE_CHECKING: | ||||||
|     from sanic import Sanic |     from sanic import Sanic | ||||||
|     from sanic.application.state import ApplicationState |     from sanic.application.state import ApplicationState | ||||||
| @@ -880,18 +879,12 @@ class StartupMixin(metaclass=SanicMeta): | |||||||
|             manager.run() |             manager.run() | ||||||
|         except ServerKilled: |         except ServerKilled: | ||||||
|             exit_code = 1 |             exit_code = 1 | ||||||
|         except SanicException as e: |  | ||||||
|             exit_code = 1 |  | ||||||
|             kwargs = primary_server_info.settings |  | ||||||
|             if e.quiet: |  | ||||||
|                 error_logger.error(str(e)) |  | ||||||
|             else: |  | ||||||
|                 raise |  | ||||||
|         except BaseException: |         except BaseException: | ||||||
|             kwargs = primary_server_info.settings |             kwargs = primary_server_info.settings | ||||||
|             error_logger.exception( |             error_logger.exception( | ||||||
|                 "Experienced exception while trying to serve" |                 "Experienced exception while trying to serve" | ||||||
|             ) |             ) | ||||||
|  |             raise | ||||||
|         finally: |         finally: | ||||||
|             logger.info("Server Stopped") |             logger.info("Server Stopped") | ||||||
|             for app in apps: |             for app in apps: | ||||||
| @@ -899,7 +892,6 @@ class StartupMixin(metaclass=SanicMeta): | |||||||
|                 app.router.reset() |                 app.router.reset() | ||||||
|                 app.signal_router.reset() |                 app.signal_router.reset() | ||||||
|  |  | ||||||
|             sync_manager.shutdown() |  | ||||||
|             for sock in socks: |             for sock in socks: | ||||||
|                 try: |                 try: | ||||||
|                     sock.shutdown(SHUT_RDWR) |                     sock.shutdown(SHUT_RDWR) | ||||||
| @@ -911,12 +903,33 @@ class StartupMixin(metaclass=SanicMeta): | |||||||
|             loop.close() |             loop.close() | ||||||
|             cls._cleanup_env_vars() |             cls._cleanup_env_vars() | ||||||
|             cls._cleanup_apps() |             cls._cleanup_apps() | ||||||
|  |  | ||||||
|  |             from time import sleep | ||||||
|  |  | ||||||
|  |             limit = 100 | ||||||
|  |             while cls._get_process_states(worker_state): | ||||||
|  |                 sleep(0.1) | ||||||
|  |                 limit -= 1 | ||||||
|  |                 if limit <= 0: | ||||||
|  |                     error_logger.warning( | ||||||
|  |                         "Worker shutdown timed out. " | ||||||
|  |                         "Some processes may still be running." | ||||||
|  |                     ) | ||||||
|  |                     break | ||||||
|  |             sync_manager.shutdown() | ||||||
|             unix = kwargs.get("unix") |             unix = kwargs.get("unix") | ||||||
|             if unix: |             if unix: | ||||||
|                 remove_unix_socket(unix) |                 remove_unix_socket(unix) | ||||||
|  |             logger.info("Goodbye.") | ||||||
|         if exit_code: |         if exit_code: | ||||||
|             os._exit(exit_code) |             os._exit(exit_code) | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|  |     def _get_process_states(worker_state) -> List[str]: | ||||||
|  |         return [ | ||||||
|  |             state for s in worker_state.values() if (state := s.get("state")) | ||||||
|  |         ] | ||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def serve_single(cls, primary: Optional[Sanic] = None) -> None: |     def serve_single(cls, primary: Optional[Sanic] = None) -> None: | ||||||
|         os.environ["SANIC_MOTD_OUTPUT"] = "true" |         os.environ["SANIC_MOTD_OUTPUT"] = "true" | ||||||
|   | |||||||
| @@ -122,17 +122,15 @@ def _setup_system_signals( | |||||||
|     register_sys_signals: bool, |     register_sys_signals: bool, | ||||||
|     loop: asyncio.AbstractEventLoop, |     loop: asyncio.AbstractEventLoop, | ||||||
| ) -> None:  # no cov | ) -> None:  # no cov | ||||||
|     # Ignore SIGINT when run_multiple |     signal_func(SIGINT, SIG_IGN) | ||||||
|     if run_multiple: |     signal_func(SIGTERM, SIG_IGN) | ||||||
|         signal_func(SIGINT, SIG_IGN) |     os.environ["SANIC_WORKER_PROCESS"] = "true" | ||||||
|         os.environ["SANIC_WORKER_PROCESS"] = "true" |  | ||||||
|  |  | ||||||
|     # Register signals for graceful termination |     # Register signals for graceful termination | ||||||
|     if register_sys_signals: |     if register_sys_signals: | ||||||
|         if OS_IS_WINDOWS: |         if OS_IS_WINDOWS: | ||||||
|             ctrlc_workaround_for_windows(app) |             ctrlc_workaround_for_windows(app) | ||||||
|         else: |         else: | ||||||
|             for _signal in [SIGTERM] if run_multiple else [SIGINT, SIGTERM]: |             for _signal in [SIGINT, SIGTERM]: | ||||||
|                 loop.add_signal_handler( |                 loop.add_signal_handler( | ||||||
|                     _signal, partial(app.stop, terminate=False) |                     _signal, partial(app.stop, terminate=False) | ||||||
|                 ) |                 ) | ||||||
| @@ -143,8 +141,6 @@ def _run_server_forever(loop, before_stop, after_stop, cleanup, unix): | |||||||
|     try: |     try: | ||||||
|         server_logger.info("Starting worker [%s]", pid) |         server_logger.info("Starting worker [%s]", pid) | ||||||
|         loop.run_forever() |         loop.run_forever() | ||||||
|     except KeyboardInterrupt: |  | ||||||
|         pass |  | ||||||
|     finally: |     finally: | ||||||
|         server_logger.info("Stopping worker [%s]", pid) |         server_logger.info("Stopping worker [%s]", pid) | ||||||
|  |  | ||||||
| @@ -156,6 +152,7 @@ def _run_server_forever(loop, before_stop, after_stop, cleanup, unix): | |||||||
|         loop.run_until_complete(after_stop()) |         loop.run_until_complete(after_stop()) | ||||||
|         remove_unix_socket(unix) |         remove_unix_socket(unix) | ||||||
|         loop.close() |         loop.close() | ||||||
|  |         server_logger.info("Worker complete [%s]", pid) | ||||||
|  |  | ||||||
|  |  | ||||||
| def _serve_http_1( | def _serve_http_1( | ||||||
| @@ -259,8 +256,11 @@ def _serve_http_1( | |||||||
|             else: |             else: | ||||||
|                 conn.abort() |                 conn.abort() | ||||||
|  |  | ||||||
|  |         app.set_serving(False) | ||||||
|  |  | ||||||
|     _setup_system_signals(app, run_multiple, register_sys_signals, loop) |     _setup_system_signals(app, run_multiple, register_sys_signals, loop) | ||||||
|     loop.run_until_complete(app._server_event("init", "after")) |     loop.run_until_complete(app._server_event("init", "after")) | ||||||
|  |     app.set_serving(True) | ||||||
|     _run_server_forever( |     _run_server_forever( | ||||||
|         loop, |         loop, | ||||||
|         partial(app._server_event, "shutdown", "before"), |         partial(app._server_event, "shutdown", "before"), | ||||||
|   | |||||||
| @@ -47,10 +47,10 @@ def bind_unix_socket(path: str, *, mode=0o666, backlog=100) -> socket.socket: | |||||||
|     path = os.path.abspath(path) |     path = os.path.abspath(path) | ||||||
|     folder = os.path.dirname(path) |     folder = os.path.dirname(path) | ||||||
|     if not os.path.isdir(folder): |     if not os.path.isdir(folder): | ||||||
|         raise FileNotFoundError("Socket folder does not exist") |         raise FileNotFoundError(f"Socket folder does not exist: {folder}") | ||||||
|     try: |     try: | ||||||
|         if not stat.S_ISSOCK(os.stat(path, follow_symlinks=False).st_mode): |         if not stat.S_ISSOCK(os.stat(path, follow_symlinks=False).st_mode): | ||||||
|             raise FileExistsError("Existing file is not a socket") |             raise FileExistsError(f"Existing file is not a socket: {path}") | ||||||
|     except FileNotFoundError: |     except FileNotFoundError: | ||||||
|         pass |         pass | ||||||
|     # Create new socket with a random temporary name |     # Create new socket with a random temporary name | ||||||
| @@ -103,10 +103,7 @@ def configure_socket( | |||||||
|     unix = server_settings["unix"] |     unix = server_settings["unix"] | ||||||
|     backlog = server_settings["backlog"] |     backlog = server_settings["backlog"] | ||||||
|     if unix: |     if unix: | ||||||
|         try: |         sock = bind_unix_socket(unix, backlog=backlog) | ||||||
|             sock = bind_unix_socket(unix, backlog=backlog) |  | ||||||
|         except OSError as e: |  | ||||||
|             raise ServerError(f"Error binding {unix}: {e}", quiet=True) |  | ||||||
|         server_settings["unix"] = unix |         server_settings["unix"] = unix | ||||||
|     if sock is None: |     if sock is None: | ||||||
|         try: |         try: | ||||||
| @@ -115,17 +112,6 @@ def configure_socket( | |||||||
|                 server_settings["port"], |                 server_settings["port"], | ||||||
|                 backlog=backlog, |                 backlog=backlog, | ||||||
|             ) |             ) | ||||||
|         except PermissionError: |  | ||||||
|             p = server_settings["port"] |  | ||||||
|             if not p or p >= 1024: |  | ||||||
|                 raise |  | ||||||
|             addr = f"{server_settings['host']}:{p}" |  | ||||||
|             error = ServerError( |  | ||||||
|                 f"Permission denied binding to {addr}.\n\n" |  | ||||||
|                 "Use `sudo sanic` to run on a privileged port.\n" |  | ||||||
|             ) |  | ||||||
|             error.quiet = True |  | ||||||
|             raise error |  | ||||||
|         except OSError as e:  # no cov |         except OSError as e:  # no cov | ||||||
|             error = ServerError( |             error = ServerError( | ||||||
|                 f"Sanic server could not start: {e}.\n\n" |                 f"Sanic server could not start: {e}.\n\n" | ||||||
|   | |||||||
| @@ -532,11 +532,12 @@ class WebsocketImplProtocol: | |||||||
|             raise WebsocketClosed( |             raise WebsocketClosed( | ||||||
|                 "Cannot receive from websocket interface after it is closed." |                 "Cannot receive from websocket interface after it is closed." | ||||||
|             ) |             ) | ||||||
|         assembler_get: Optional[asyncio.Task] = None |  | ||||||
|         try: |         try: | ||||||
|             self.recv_cancel = asyncio.Future() |             self.recv_cancel = asyncio.Future() | ||||||
|             assembler_get = asyncio.create_task(self.assembler.get(timeout)) |             tasks = ( | ||||||
|             tasks = (self.recv_cancel, assembler_get) |                 self.recv_cancel, | ||||||
|  |                 asyncio.ensure_future(self.assembler.get(timeout)), | ||||||
|  |             ) | ||||||
|             done, pending = await asyncio.wait( |             done, pending = await asyncio.wait( | ||||||
|                 tasks, |                 tasks, | ||||||
|                 return_when=asyncio.FIRST_COMPLETED, |                 return_when=asyncio.FIRST_COMPLETED, | ||||||
| @@ -550,11 +551,6 @@ class WebsocketImplProtocol: | |||||||
|             else: |             else: | ||||||
|                 self.recv_cancel.cancel() |                 self.recv_cancel.cancel() | ||||||
|                 return done_task.result() |                 return done_task.result() | ||||||
|         except asyncio.CancelledError: |  | ||||||
|             # recv was cancelled |  | ||||||
|             if assembler_get: |  | ||||||
|                 assembler_get.cancel() |  | ||||||
|             raise |  | ||||||
|         finally: |         finally: | ||||||
|             self.recv_cancel = None |             self.recv_cancel = None | ||||||
|             self.recv_lock.release() |             self.recv_lock.release() | ||||||
| @@ -588,15 +584,16 @@ class WebsocketImplProtocol: | |||||||
|                 "Cannot receive from websocket interface after it is closed." |                 "Cannot receive from websocket interface after it is closed." | ||||||
|             ) |             ) | ||||||
|         messages = [] |         messages = [] | ||||||
|         assembler_get: Optional[asyncio.Task] = None |  | ||||||
|         try: |         try: | ||||||
|             # Prevent pausing the transport when we're |             # Prevent pausing the transport when we're | ||||||
|             # receiving a burst of messages |             # receiving a burst of messages | ||||||
|             self.can_pause = False |             self.can_pause = False | ||||||
|             self.recv_cancel = asyncio.Future() |             self.recv_cancel = asyncio.Future() | ||||||
|             while True: |             while True: | ||||||
|                 assembler_get = asyncio.create_task(self.assembler.get(0)) |                 tasks = ( | ||||||
|                 tasks = (self.recv_cancel, assembler_get) |                     self.recv_cancel, | ||||||
|  |                     asyncio.ensure_future(self.assembler.get(timeout=0)), | ||||||
|  |                 ) | ||||||
|                 done, pending = await asyncio.wait( |                 done, pending = await asyncio.wait( | ||||||
|                     tasks, |                     tasks, | ||||||
|                     return_when=asyncio.FIRST_COMPLETED, |                     return_when=asyncio.FIRST_COMPLETED, | ||||||
| @@ -619,11 +616,6 @@ class WebsocketImplProtocol: | |||||||
|                 # next message to pass into the Assembler |                 # next message to pass into the Assembler | ||||||
|                 await asyncio.sleep(0) |                 await asyncio.sleep(0) | ||||||
|             self.recv_cancel.cancel() |             self.recv_cancel.cancel() | ||||||
|         except asyncio.CancelledError: |  | ||||||
|             # recv_burst was cancelled |  | ||||||
|             if assembler_get: |  | ||||||
|                 assembler_get.cancel() |  | ||||||
|             raise |  | ||||||
|         finally: |         finally: | ||||||
|             self.recv_cancel = None |             self.recv_cancel = None | ||||||
|             self.can_pause = True |             self.can_pause = True | ||||||
|   | |||||||
| @@ -122,6 +122,7 @@ class WorkerManager: | |||||||
|         self.monitor() |         self.monitor() | ||||||
|         self.join() |         self.join() | ||||||
|         self.terminate() |         self.terminate() | ||||||
|  |         self.cleanup() | ||||||
|  |  | ||||||
|     def start(self): |     def start(self): | ||||||
|         for process in self.processes: |         for process in self.processes: | ||||||
| @@ -147,6 +148,11 @@ class WorkerManager: | |||||||
|             for process in self.processes: |             for process in self.processes: | ||||||
|                 process.terminate() |                 process.terminate() | ||||||
|  |  | ||||||
|  |     def cleanup(self): | ||||||
|  |         """Cleanup the worker processes.""" | ||||||
|  |         for process in self.processes: | ||||||
|  |             process.exit() | ||||||
|  |  | ||||||
|     def restart( |     def restart( | ||||||
|         self, |         self, | ||||||
|         process_names: Optional[List[str]] = None, |         process_names: Optional[List[str]] = None, | ||||||
|   | |||||||
| @@ -28,6 +28,24 @@ class WorkerMultiplexer: | |||||||
|             "state": ProcessState.ACKED.name, |             "state": ProcessState.ACKED.name, | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |     def set_serving(self, serving: bool) -> None: | ||||||
|  |         """Set the worker to serving. | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             serving (bool): Whether the worker is serving. | ||||||
|  |         """ | ||||||
|  |         self._state._state[self.name] = { | ||||||
|  |             **self._state._state[self.name], | ||||||
|  |             "serving": serving, | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     def exit(self): | ||||||
|  |         """Run cleanup at worker exit.""" | ||||||
|  |         try: | ||||||
|  |             del self._state._state[self.name] | ||||||
|  |         except ConnectionRefusedError: | ||||||
|  |             logger.debug("Monitor process has already exited.") | ||||||
|  |  | ||||||
|     def restart( |     def restart( | ||||||
|         self, |         self, | ||||||
|         name: str = "", |         name: str = "", | ||||||
|   | |||||||
| @@ -65,6 +65,20 @@ class WorkerProcess: | |||||||
|         self.set_state(ProcessState.JOINED) |         self.set_state(ProcessState.JOINED) | ||||||
|         self._current_process.join() |         self._current_process.join() | ||||||
|  |  | ||||||
|  |     def exit(self): | ||||||
|  |         limit = 100 | ||||||
|  |         while self.is_alive() and limit > 0: | ||||||
|  |             sleep(0.1) | ||||||
|  |             limit -= 1 | ||||||
|  |  | ||||||
|  |         if not self.is_alive(): | ||||||
|  |             try: | ||||||
|  |                 del self.worker_state[self.name] | ||||||
|  |             except ConnectionRefusedError: | ||||||
|  |                 logger.debug("Monitor process has already exited.") | ||||||
|  |             except KeyError: | ||||||
|  |                 logger.debug("Could not find worker state to delete.") | ||||||
|  |  | ||||||
|     def terminate(self): |     def terminate(self): | ||||||
|         if self.state is not ProcessState.TERMINATED: |         if self.state is not ProcessState.TERMINATED: | ||||||
|             logger.debug( |             logger.debug( | ||||||
| @@ -77,7 +91,6 @@ class WorkerProcess: | |||||||
|             self.set_state(ProcessState.TERMINATED, force=True) |             self.set_state(ProcessState.TERMINATED, force=True) | ||||||
|             try: |             try: | ||||||
|                 os.kill(self.pid, SIGINT) |                 os.kill(self.pid, SIGINT) | ||||||
|                 del self.worker_state[self.name] |  | ||||||
|             except (KeyError, AttributeError, ProcessLookupError): |             except (KeyError, AttributeError, ProcessLookupError): | ||||||
|                 ... |                 ... | ||||||
|  |  | ||||||
| @@ -118,6 +131,16 @@ class WorkerProcess: | |||||||
|         except AssertionError: |         except AssertionError: | ||||||
|             return False |             return False | ||||||
|  |  | ||||||
|  |     # def _run(self, **kwargs): | ||||||
|  |     #     atexit.register(self._exit) | ||||||
|  |     #     self.target(**kwargs) | ||||||
|  |  | ||||||
|  |     # def _exit(self): | ||||||
|  |     #     try: | ||||||
|  |     #         del self.worker_state[self.name] | ||||||
|  |     #     except ConnectionRefusedError: | ||||||
|  |     #         logger.debug("Monitor process has already exited.") | ||||||
|  |  | ||||||
|     def spawn(self): |     def spawn(self): | ||||||
|         if self.state not in (ProcessState.IDLE, ProcessState.RESTARTING): |         if self.state not in (ProcessState.IDLE, ProcessState.RESTARTING): | ||||||
|             raise Exception("Cannot spawn a worker process until it is idle.") |             raise Exception("Cannot spawn a worker process until it is idle.") | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user