├── asgiref ├── .github │ └── workflows │ │ └── tests.yml ├── .gitignore ├── .pre-commit-config.yaml ├── CHANGELOG.txt ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.rst ├── asgiref │ ├── __init__.py │ ├── compatibility.py │ ├── current_thread_executor.py │ ├── local.py │ ├── py.typed │ ├── server.py │ ├── sync.py │ ├── testing.py │ ├── timeout.py │ ├── typing.py │ └── wsgi.py ├── docs │ ├── Makefile │ ├── conf.py │ ├── extensions.rst │ ├── implementations.rst │ ├── index.rst │ ├── introduction.rst │ └── specs │ │ ├── index.rst │ │ ├── lifespan.rst │ │ ├── main.rst │ │ ├── tls.rst │ │ └── www.rst ├── setup.cfg ├── setup.py ├── specs │ ├── asgi.rst │ ├── lifespan.rst │ ├── tls.rst │ └── www.rst ├── tests │ ├── test_compatibility.py │ ├── test_local.py │ ├── test_server.py │ ├── test_sync.py │ ├── test_sync_contextvars.py │ ├── test_testing.py │ └── test_wsgi.py └── tox.ini ├── django-asv ├── .github │ └── workflows │ │ ├── benchmark.yml │ │ └── publish-results.yml ├── .gitignore ├── .pre-commit-config.yaml ├── LICENSE ├── asv.conf.json ├── benchmarks │ ├── __init__.py │ ├── benchmarks.py │ ├── data_struct_benchmarks │ │ ├── __init__.py │ │ └── multi_value_dict │ │ │ ├── __init__.py │ │ │ └── benchmark.py │ ├── fixtures │ │ └── initial_data.json │ ├── form_benchmarks │ │ ├── __init__.py │ │ ├── form_clean │ │ │ ├── __init__.py │ │ │ └── benchmark.py │ │ ├── form_create │ │ │ ├── __init__.py │ │ │ └── benchmark.py │ │ ├── form_render │ │ │ ├── __init__.py │ │ │ └── benchmark.py │ │ ├── form_validate │ │ │ ├── __init__.py │ │ │ └── benchmark.py │ │ └── select_date_widget │ │ │ ├── __init__.py │ │ │ └── benchmark.py │ ├── model_benchmarks │ │ ├── __init__.py │ │ ├── model_create │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ └── models.py │ │ ├── model_delete │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ └── models.py │ │ ├── model_save_existing │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ └── models.py │ │ └── model_save_new │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ └── models.py │ ├── models.py │ ├── other_benchmarks │ │ ├── __init__.py │ │ └── raw_sql │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ └── models.py │ ├── query_benchmarks │ │ ├── __init__.py │ │ ├── query_aggregate │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ ├── fixtures │ │ │ │ └── initial_data.json │ │ │ └── models.py │ │ ├── query_all │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ └── models.py │ │ ├── query_all_conv │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ └── models.py │ │ ├── query_annotate │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ ├── fixtures │ │ │ │ └── initial_data.json │ │ │ └── models.py │ │ ├── query_complex_filter │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ ├── fixtures │ │ │ │ └── initial_data.json │ │ │ └── models.py │ │ ├── query_count │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ └── models.py │ │ ├── query_dates │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ └── models.py │ │ ├── query_delete │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ ├── fixtures │ │ │ │ └── initial_data.json │ │ │ └── models.py │ │ ├── query_delete_related │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ └── models.py │ │ ├── query_distinct │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ ├── fixtures │ │ │ │ └── initial_data.json │ │ │ └── models.py │ │ ├── query_exclude │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ ├── fixtures │ │ │ │ └── initial_data.json │ │ │ └── models.py │ │ ├── query_exists │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ ├── fixtures │ │ │ │ └── initial_data.json │ │ │ └── models.py │ │ ├── query_filter │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ ├── fixtures │ │ │ │ └── initial_data.json │ │ │ └── models.py │ │ ├── query_get │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ └── models.py │ │ ├── query_get_or_create │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ └── models.py │ │ ├── query_in_bulk │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ ├── fixtures │ │ │ │ └── initial_data.json │ │ │ └── models.py │ │ ├── query_latest │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ ├── fixtures │ │ │ │ └── initial_data.json │ │ │ └── models.py │ │ ├── query_none │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ └── models.py │ │ ├── query_order_by │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ ├── fixtures │ │ │ │ └── initial_data.json │ │ │ └── models.py │ │ ├── query_prefetch_related │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ └── models.py │ │ ├── query_raw │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ └── models.py │ │ ├── query_raw_deferred │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ └── models.py │ │ ├── query_select_related │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ ├── fixtures │ │ │ │ └── initial_data.json │ │ │ └── models.py │ │ ├── query_update │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ ├── fixtures │ │ │ │ └── initial_data.json │ │ │ └── models.py │ │ ├── query_values │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ ├── fixtures │ │ │ │ └── initial_data.json │ │ │ └── models.py │ │ ├── query_values_10000 │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ └── models.py │ │ ├── query_values_list │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ ├── fixtures │ │ │ │ └── initial_data.json │ │ │ └── models.py │ │ └── queryset_filter_chain │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ └── models.py │ ├── req_resp_benchmarks │ │ ├── __init__.py │ │ ├── default_middleware │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ ├── urls.py │ │ │ └── views.py │ │ └── http_methods │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ ├── urls.py │ │ │ └── views.py │ ├── settings.py │ ├── template_benchmarks │ │ ├── __init__.py │ │ ├── template_compilation │ │ │ ├── __init__.py │ │ │ └── benchmark.py │ │ └── template_render │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ ├── templates │ │ │ ├── base.html │ │ │ ├── confirmation_message.html │ │ │ ├── footer.html │ │ │ ├── for_loop.html │ │ │ ├── header.html │ │ │ ├── permalink.html │ │ │ ├── permalink_django_lte_40.html │ │ │ ├── sidebar.html │ │ │ └── somefile.js │ │ │ ├── urls.py │ │ │ └── views.py │ ├── url_benchmarks │ │ ├── __init__.py │ │ ├── url_resolve │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ ├── urls.py │ │ │ └── views.py │ │ ├── url_resolve_flat │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ └── urls.py │ │ ├── url_resolve_nested │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ └── urls.py │ │ └── url_reverse │ │ │ ├── __init__.py │ │ │ ├── benchmark.py │ │ │ ├── urls.py │ │ │ └── views.py │ ├── urls.py │ └── utils.py ├── requirements.txt └── setup.cfg └── dsf-working-groups ├── active ├── code-of-conduct.md ├── dceu.md ├── fellowship.md ├── fundraising.md └── social-media.md └── template.md /asgiref/.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | jobs: 10 | tests: 11 | name: Python ${{ matrix.python-version }} 12 | runs-on: ubuntu-latest 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | python-version: 17 | - 3.8 18 | - 3.9 19 | - '3.10' 20 | - '3.11' 21 | - '3.12' 22 | 23 | steps: 24 | - uses: actions/checkout@v4 25 | 26 | - name: Set up Python ${{ matrix.python-version }} 27 | uses: actions/setup-python@v4 28 | with: 29 | python-version: ${{ matrix.python-version }} 30 | 31 | - name: Install dependencies 32 | run: | 33 | python -m pip install --upgrade pip setuptools wheel 34 | python -m pip install --upgrade tox tox-py 35 | 36 | - name: Run tox targets for ${{ matrix.python-version }} 37 | run: tox --py current 38 | 39 | lint: 40 | name: Lint 41 | runs-on: ubuntu-latest 42 | steps: 43 | - uses: actions/checkout@v4 44 | - name: Set up Python 45 | uses: actions/setup-python@v4 46 | with: 47 | python-version: '3.12' 48 | - name: Install dependencies 49 | run: | 50 | python -m pip install --upgrade pip tox 51 | - name: Run lint 52 | run: tox -e qa 53 | -------------------------------------------------------------------------------- /asgiref/.gitignore: -------------------------------------------------------------------------------- 1 | *.egg-info 2 | dist/ 3 | build/ 4 | _build/ 5 | __pycache__/ 6 | *.pyc 7 | .tox/ 8 | *~ 9 | .cache 10 | .eggs 11 | .python-version 12 | .pytest_cache/ 13 | .vscode/ 14 | .venv 15 | -------------------------------------------------------------------------------- /asgiref/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/asottile/pyupgrade 3 | rev: v3.3.1 4 | hooks: 5 | - id: pyupgrade 6 | args: ["--py38-plus"] 7 | 8 | - repo: https://github.com/psf/black 9 | rev: 22.12.0 10 | hooks: 11 | - id: black 12 | args: ["--target-version=py38"] 13 | 14 | - repo: https://github.com/pycqa/isort 15 | rev: 5.11.5 16 | hooks: 17 | - id: isort 18 | args: ["--profile=black"] 19 | 20 | - repo: https://github.com/pycqa/flake8 21 | rev: 6.0.0 22 | hooks: 23 | - id: flake8 24 | 25 | - repo: https://github.com/asottile/yesqa 26 | rev: v1.4.0 27 | hooks: 28 | - id: yesqa 29 | 30 | - repo: https://github.com/pre-commit/pre-commit-hooks 31 | rev: v4.4.0 32 | hooks: 33 | - id: check-merge-conflict 34 | - id: check-toml 35 | - id: check-yaml 36 | - id: mixed-line-ending 37 | -------------------------------------------------------------------------------- /asgiref/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) Django Software Foundation and individual contributors. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of Django nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without 16 | specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 22 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 25 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /asgiref/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include asgiref/py.typed 3 | recursive-include tests *.py 4 | -------------------------------------------------------------------------------- /asgiref/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: release clean 2 | 3 | clean: 4 | rm -rf build/ dist/ asgiref.egg-info/ 5 | 6 | release: clean 7 | python3 -m build 8 | python3 -m twine upload dist/* 9 | -------------------------------------------------------------------------------- /asgiref/asgiref/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = "3.7.2" 2 | -------------------------------------------------------------------------------- /asgiref/asgiref/compatibility.py: -------------------------------------------------------------------------------- 1 | import inspect 2 | 3 | from .sync import iscoroutinefunction 4 | 5 | 6 | def is_double_callable(application): 7 | """ 8 | Tests to see if an application is a legacy-style (double-callable) application. 9 | """ 10 | # Look for a hint on the object first 11 | if getattr(application, "_asgi_single_callable", False): 12 | return False 13 | if getattr(application, "_asgi_double_callable", False): 14 | return True 15 | # Uninstanted classes are double-callable 16 | if inspect.isclass(application): 17 | return True 18 | # Instanted classes depend on their __call__ 19 | if hasattr(application, "__call__"): 20 | # We only check to see if its __call__ is a coroutine function - 21 | # if it's not, it still might be a coroutine function itself. 22 | if iscoroutinefunction(application.__call__): 23 | return False 24 | # Non-classes we just check directly 25 | return not iscoroutinefunction(application) 26 | 27 | 28 | def double_to_single_callable(application): 29 | """ 30 | Transforms a double-callable ASGI application into a single-callable one. 31 | """ 32 | 33 | async def new_application(scope, receive, send): 34 | instance = application(scope) 35 | return await instance(receive, send) 36 | 37 | return new_application 38 | 39 | 40 | def guarantee_single_callable(application): 41 | """ 42 | Takes either a single- or double-callable application and always returns it 43 | in single-callable style. Use this to add backwards compatibility for ASGI 44 | 2.0 applications to your server/test harness/etc. 45 | """ 46 | if is_double_callable(application): 47 | application = double_to_single_callable(application) 48 | return application 49 | -------------------------------------------------------------------------------- /asgiref/asgiref/current_thread_executor.py: -------------------------------------------------------------------------------- 1 | import queue 2 | import sys 3 | import threading 4 | from concurrent.futures import Executor, Future 5 | from typing import TYPE_CHECKING, Any, Callable, TypeVar, Union 6 | 7 | if sys.version_info >= (3, 10): 8 | from typing import ParamSpec 9 | else: 10 | from typing_extensions import ParamSpec 11 | 12 | _T = TypeVar("_T") 13 | _P = ParamSpec("_P") 14 | _R = TypeVar("_R") 15 | 16 | 17 | class _WorkItem: 18 | """ 19 | Represents an item needing to be run in the executor. 20 | Copied from ThreadPoolExecutor (but it's private, so we're not going to rely on importing it) 21 | """ 22 | 23 | def __init__( 24 | self, 25 | future: "Future[_R]", 26 | fn: Callable[_P, _R], 27 | *args: _P.args, 28 | **kwargs: _P.kwargs, 29 | ): 30 | self.future = future 31 | self.fn = fn 32 | self.args = args 33 | self.kwargs = kwargs 34 | 35 | def run(self) -> None: 36 | __traceback_hide__ = True # noqa: F841 37 | if not self.future.set_running_or_notify_cancel(): 38 | return 39 | try: 40 | result = self.fn(*self.args, **self.kwargs) 41 | except BaseException as exc: 42 | self.future.set_exception(exc) 43 | # Break a reference cycle with the exception 'exc' 44 | self = None # type: ignore[assignment] 45 | else: 46 | self.future.set_result(result) 47 | 48 | 49 | class CurrentThreadExecutor(Executor): 50 | """ 51 | An Executor that actually runs code in the thread it is instantiated in. 52 | Passed to other threads running async code, so they can run sync code in 53 | the thread they came from. 54 | """ 55 | 56 | def __init__(self) -> None: 57 | self._work_thread = threading.current_thread() 58 | self._work_queue: queue.Queue[Union[_WorkItem, "Future[Any]"]] = queue.Queue() 59 | self._broken = False 60 | 61 | def run_until_future(self, future: "Future[Any]") -> None: 62 | """ 63 | Runs the code in the work queue until a result is available from the future. 64 | Should be run from the thread the executor is initialised in. 65 | """ 66 | # Check we're in the right thread 67 | if threading.current_thread() != self._work_thread: 68 | raise RuntimeError( 69 | "You cannot run CurrentThreadExecutor from a different thread" 70 | ) 71 | future.add_done_callback(self._work_queue.put) 72 | # Keep getting and running work items until we get the future we're waiting for 73 | # back via the future's done callback. 74 | try: 75 | while True: 76 | # Get a work item and run it 77 | work_item = self._work_queue.get() 78 | if work_item is future: 79 | return 80 | assert isinstance(work_item, _WorkItem) 81 | work_item.run() 82 | del work_item 83 | finally: 84 | self._broken = True 85 | 86 | def _submit( 87 | self, 88 | fn: Callable[_P, _R], 89 | *args: _P.args, 90 | **kwargs: _P.kwargs, 91 | ) -> "Future[_R]": 92 | # Check they're not submitting from the same thread 93 | if threading.current_thread() == self._work_thread: 94 | raise RuntimeError( 95 | "You cannot submit onto CurrentThreadExecutor from its own thread" 96 | ) 97 | # Check they're not too late or the executor errored 98 | if self._broken: 99 | raise RuntimeError("CurrentThreadExecutor already quit or is broken") 100 | # Add to work queue 101 | f: "Future[_R]" = Future() 102 | work_item = _WorkItem(f, fn, *args, **kwargs) 103 | self._work_queue.put(work_item) 104 | # Return the future 105 | return f 106 | 107 | # Python 3.9+ has a new signature for submit with a "/" after `fn`, to enforce 108 | # it to be a positional argument. If we ignore[override] mypy on 3.9+ will be 109 | # happy but 3.8 will say that the ignore comment is unused, even when 110 | # defining them differently based on sys.version_info. 111 | # We should be able to remove this when we drop support for 3.8. 112 | if not TYPE_CHECKING: 113 | 114 | def submit(self, fn, *args, **kwargs): 115 | return self._submit(fn, *args, **kwargs) 116 | -------------------------------------------------------------------------------- /asgiref/asgiref/local.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import contextlib 3 | import contextvars 4 | import threading 5 | from typing import Any, Dict, Union 6 | 7 | 8 | class _CVar: 9 | """Storage utility for Local.""" 10 | 11 | def __init__(self) -> None: 12 | self._data: "contextvars.ContextVar[Dict[str, Any]]" = contextvars.ContextVar( 13 | "asgiref.local" 14 | ) 15 | 16 | def __getattr__(self, key): 17 | storage_object = self._data.get({}) 18 | try: 19 | return storage_object[key] 20 | except KeyError: 21 | raise AttributeError(f"{self!r} object has no attribute {key!r}") 22 | 23 | def __setattr__(self, key: str, value: Any) -> None: 24 | if key == "_data": 25 | return super().__setattr__(key, value) 26 | 27 | storage_object = self._data.get({}) 28 | storage_object[key] = value 29 | self._data.set(storage_object) 30 | 31 | def __delattr__(self, key: str) -> None: 32 | storage_object = self._data.get({}) 33 | if key in storage_object: 34 | del storage_object[key] 35 | self._data.set(storage_object) 36 | else: 37 | raise AttributeError(f"{self!r} object has no attribute {key!r}") 38 | 39 | 40 | class Local: 41 | """Local storage for async tasks. 42 | 43 | This is a namespace object (similar to `threading.local`) where data is 44 | also local to the current async task (if there is one). 45 | 46 | In async threads, local means in the same sense as the `contextvars` 47 | module - i.e. a value set in an async frame will be visible: 48 | 49 | - to other async code `await`-ed from this frame. 50 | - to tasks spawned using `asyncio` utilities (`create_task`, `wait_for`, 51 | `gather` and probably others). 52 | - to code scheduled in a sync thread using `sync_to_async` 53 | 54 | In "sync" threads (a thread with no async event loop running), the 55 | data is thread-local, but additionally shared with async code executed 56 | via the `async_to_sync` utility, which schedules async code in a new thread 57 | and copies context across to that thread. 58 | 59 | If `thread_critical` is True, then the local will only be visible per-thread, 60 | behaving exactly like `threading.local` if the thread is sync, and as 61 | `contextvars` if the thread is async. This allows genuinely thread-sensitive 62 | code (such as DB handles) to be kept stricly to their initial thread and 63 | disable the sharing across `sync_to_async` and `async_to_sync` wrapped calls. 64 | 65 | Unlike plain `contextvars` objects, this utility is threadsafe. 66 | """ 67 | 68 | def __init__(self, thread_critical: bool = False) -> None: 69 | self._thread_critical = thread_critical 70 | self._thread_lock = threading.RLock() 71 | 72 | self._storage: "Union[threading.local, _CVar]" 73 | 74 | if thread_critical: 75 | # Thread-local storage 76 | self._storage = threading.local() 77 | else: 78 | # Contextvar storage 79 | self._storage = _CVar() 80 | 81 | @contextlib.contextmanager 82 | def _lock_storage(self): 83 | # Thread safe access to storage 84 | if self._thread_critical: 85 | try: 86 | # this is a test for are we in a async or sync 87 | # thread - will raise RuntimeError if there is 88 | # no current loop 89 | asyncio.get_running_loop() 90 | except RuntimeError: 91 | # We are in a sync thread, the storage is 92 | # just the plain thread local (i.e, "global within 93 | # this thread" - it doesn't matter where you are 94 | # in a call stack you see the same storage) 95 | yield self._storage 96 | else: 97 | # We are in an async thread - storage is still 98 | # local to this thread, but additionally should 99 | # behave like a context var (is only visible with 100 | # the same async call stack) 101 | 102 | # Ensure context exists in the current thread 103 | if not hasattr(self._storage, "cvar"): 104 | self._storage.cvar = _CVar() 105 | 106 | # self._storage is a thread local, so the members 107 | # can't be accessed in another thread (we don't 108 | # need any locks) 109 | yield self._storage.cvar 110 | else: 111 | # Lock for thread_critical=False as other threads 112 | # can access the exact same storage object 113 | with self._thread_lock: 114 | yield self._storage 115 | 116 | def __getattr__(self, key): 117 | with self._lock_storage() as storage: 118 | return getattr(storage, key) 119 | 120 | def __setattr__(self, key, value): 121 | if key in ("_local", "_storage", "_thread_critical", "_thread_lock"): 122 | return super().__setattr__(key, value) 123 | with self._lock_storage() as storage: 124 | setattr(storage, key, value) 125 | 126 | def __delattr__(self, key): 127 | with self._lock_storage() as storage: 128 | delattr(storage, key) 129 | -------------------------------------------------------------------------------- /asgiref/asgiref/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/asgiref/asgiref/py.typed -------------------------------------------------------------------------------- /asgiref/asgiref/server.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import logging 3 | import time 4 | import traceback 5 | 6 | from .compatibility import guarantee_single_callable 7 | 8 | logger = logging.getLogger(__name__) 9 | 10 | 11 | class StatelessServer: 12 | """ 13 | Base server class that handles basic concepts like application instance 14 | creation/pooling, exception handling, and similar, for stateless protocols 15 | (i.e. ones without actual incoming connections to the process) 16 | 17 | Your code should override the handle() method, doing whatever it needs to, 18 | and calling get_or_create_application_instance with a unique `scope_id` 19 | and `scope` for the scope it wants to get. 20 | 21 | If an application instance is found with the same `scope_id`, you are 22 | given its input queue, otherwise one is made for you with the scope provided 23 | and you are given that fresh new input queue. Either way, you should do 24 | something like: 25 | 26 | input_queue = self.get_or_create_application_instance( 27 | "user-123456", 28 | {"type": "testprotocol", "user_id": "123456", "username": "andrew"}, 29 | ) 30 | input_queue.put_nowait(message) 31 | 32 | If you try and create an application instance and there are already 33 | `max_application` instances, the oldest/least recently used one will be 34 | reclaimed and shut down to make space. 35 | 36 | Application coroutines that error will be found periodically (every 100ms 37 | by default) and have their exceptions printed to the console. Override 38 | application_exception() if you want to do more when this happens. 39 | 40 | If you override run(), make sure you handle things like launching the 41 | application checker. 42 | """ 43 | 44 | application_checker_interval = 0.1 45 | 46 | def __init__(self, application, max_applications=1000): 47 | # Parameters 48 | self.application = application 49 | self.max_applications = max_applications 50 | # Initialisation 51 | self.application_instances = {} 52 | 53 | ### Mainloop and handling 54 | 55 | def run(self): 56 | """ 57 | Runs the asyncio event loop with our handler loop. 58 | """ 59 | event_loop = asyncio.get_event_loop() 60 | asyncio.ensure_future(self.application_checker()) 61 | try: 62 | event_loop.run_until_complete(self.handle()) 63 | except KeyboardInterrupt: 64 | logger.info("Exiting due to Ctrl-C/interrupt") 65 | 66 | async def handle(self): 67 | raise NotImplementedError("You must implement handle()") 68 | 69 | async def application_send(self, scope, message): 70 | """ 71 | Receives outbound sends from applications and handles them. 72 | """ 73 | raise NotImplementedError("You must implement application_send()") 74 | 75 | ### Application instance management 76 | 77 | def get_or_create_application_instance(self, scope_id, scope): 78 | """ 79 | Creates an application instance and returns its queue. 80 | """ 81 | if scope_id in self.application_instances: 82 | self.application_instances[scope_id]["last_used"] = time.time() 83 | return self.application_instances[scope_id]["input_queue"] 84 | # See if we need to delete an old one 85 | while len(self.application_instances) > self.max_applications: 86 | self.delete_oldest_application_instance() 87 | # Make an instance of the application 88 | input_queue = asyncio.Queue() 89 | application_instance = guarantee_single_callable(self.application) 90 | # Run it, and stash the future for later checking 91 | future = asyncio.ensure_future( 92 | application_instance( 93 | scope=scope, 94 | receive=input_queue.get, 95 | send=lambda message: self.application_send(scope, message), 96 | ), 97 | ) 98 | self.application_instances[scope_id] = { 99 | "input_queue": input_queue, 100 | "future": future, 101 | "scope": scope, 102 | "last_used": time.time(), 103 | } 104 | return input_queue 105 | 106 | def delete_oldest_application_instance(self): 107 | """ 108 | Finds and deletes the oldest application instance 109 | """ 110 | oldest_time = min( 111 | details["last_used"] for details in self.application_instances.values() 112 | ) 113 | for scope_id, details in self.application_instances.items(): 114 | if details["last_used"] == oldest_time: 115 | self.delete_application_instance(scope_id) 116 | # Return to make sure we only delete one in case two have 117 | # the same oldest time 118 | return 119 | 120 | def delete_application_instance(self, scope_id): 121 | """ 122 | Removes an application instance (makes sure its task is stopped, 123 | then removes it from the current set) 124 | """ 125 | details = self.application_instances[scope_id] 126 | del self.application_instances[scope_id] 127 | if not details["future"].done(): 128 | details["future"].cancel() 129 | 130 | async def application_checker(self): 131 | """ 132 | Goes through the set of current application instance Futures and cleans up 133 | any that are done/prints exceptions for any that errored. 134 | """ 135 | while True: 136 | await asyncio.sleep(self.application_checker_interval) 137 | for scope_id, details in list(self.application_instances.items()): 138 | if details["future"].done(): 139 | exception = details["future"].exception() 140 | if exception: 141 | await self.application_exception(exception, details) 142 | try: 143 | del self.application_instances[scope_id] 144 | except KeyError: 145 | # Exception handling might have already got here before us. That's fine. 146 | pass 147 | 148 | async def application_exception(self, exception, application_details): 149 | """ 150 | Called whenever an application coroutine has an exception. 151 | """ 152 | logging.error( 153 | "Exception inside application: %s\n%s%s", 154 | exception, 155 | "".join(traceback.format_tb(exception.__traceback__)), 156 | f" {exception}", 157 | ) 158 | -------------------------------------------------------------------------------- /asgiref/asgiref/testing.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import contextvars 3 | import time 4 | 5 | from .compatibility import guarantee_single_callable 6 | from .timeout import timeout as async_timeout 7 | 8 | 9 | class ApplicationCommunicator: 10 | """ 11 | Runs an ASGI application in a test mode, allowing sending of 12 | messages to it and retrieval of messages it sends. 13 | """ 14 | 15 | def __init__(self, application, scope): 16 | self.application = guarantee_single_callable(application) 17 | self.scope = scope 18 | self.input_queue = asyncio.Queue() 19 | self.output_queue = asyncio.Queue() 20 | # Clear context - this ensures that context vars set in the testing scope 21 | # are not "leaked" into the application which would normally begin with 22 | # an empty context. In Python >= 3.11 this could also be written as: 23 | # asyncio.create_task(..., context=contextvars.Context()) 24 | self.future = contextvars.Context().run( 25 | asyncio.create_task, 26 | self.application(scope, self.input_queue.get, self.output_queue.put), 27 | ) 28 | 29 | async def wait(self, timeout=1): 30 | """ 31 | Waits for the application to stop itself and returns any exceptions. 32 | """ 33 | try: 34 | async with async_timeout(timeout): 35 | try: 36 | await self.future 37 | self.future.result() 38 | except asyncio.CancelledError: 39 | pass 40 | finally: 41 | if not self.future.done(): 42 | self.future.cancel() 43 | try: 44 | await self.future 45 | except asyncio.CancelledError: 46 | pass 47 | 48 | def stop(self, exceptions=True): 49 | if not self.future.done(): 50 | self.future.cancel() 51 | elif exceptions: 52 | # Give a chance to raise any exceptions 53 | self.future.result() 54 | 55 | def __del__(self): 56 | # Clean up on deletion 57 | try: 58 | self.stop(exceptions=False) 59 | except RuntimeError: 60 | # Event loop already stopped 61 | pass 62 | 63 | async def send_input(self, message): 64 | """ 65 | Sends a single message to the application 66 | """ 67 | # Give it the message 68 | await self.input_queue.put(message) 69 | 70 | async def receive_output(self, timeout=1): 71 | """ 72 | Receives a single message from the application, with optional timeout. 73 | """ 74 | # Make sure there's not an exception to raise from the task 75 | if self.future.done(): 76 | self.future.result() 77 | # Wait and receive the message 78 | try: 79 | async with async_timeout(timeout): 80 | return await self.output_queue.get() 81 | except asyncio.TimeoutError as e: 82 | # See if we have another error to raise inside 83 | if self.future.done(): 84 | self.future.result() 85 | else: 86 | self.future.cancel() 87 | try: 88 | await self.future 89 | except asyncio.CancelledError: 90 | pass 91 | raise e 92 | 93 | async def receive_nothing(self, timeout=0.1, interval=0.01): 94 | """ 95 | Checks that there is no message to receive in the given time. 96 | """ 97 | # `interval` has precedence over `timeout` 98 | start = time.monotonic() 99 | while time.monotonic() - start < timeout: 100 | if not self.output_queue.empty(): 101 | return False 102 | await asyncio.sleep(interval) 103 | return self.output_queue.empty() 104 | -------------------------------------------------------------------------------- /asgiref/asgiref/timeout.py: -------------------------------------------------------------------------------- 1 | # This code is originally sourced from the aio-libs project "async_timeout", 2 | # under the Apache 2.0 license. You may see the original project at 3 | # https://github.com/aio-libs/async-timeout 4 | 5 | # It is vendored here to reduce chain-dependencies on this library, and 6 | # modified slightly to remove some features we don't use. 7 | 8 | 9 | import asyncio 10 | import warnings 11 | from types import TracebackType 12 | from typing import Any # noqa 13 | from typing import Optional, Type 14 | 15 | 16 | class timeout: 17 | """timeout context manager. 18 | 19 | Useful in cases when you want to apply timeout logic around block 20 | of code or in cases when asyncio.wait_for is not suitable. For example: 21 | 22 | >>> with timeout(0.001): 23 | ... async with aiohttp.get('https://github.com') as r: 24 | ... await r.text() 25 | 26 | 27 | timeout - value in seconds or None to disable timeout logic 28 | loop - asyncio compatible event loop 29 | """ 30 | 31 | def __init__( 32 | self, 33 | timeout: Optional[float], 34 | *, 35 | loop: Optional[asyncio.AbstractEventLoop] = None, 36 | ) -> None: 37 | self._timeout = timeout 38 | if loop is None: 39 | loop = asyncio.get_running_loop() 40 | else: 41 | warnings.warn( 42 | """The loop argument to timeout() is deprecated.""", DeprecationWarning 43 | ) 44 | self._loop = loop 45 | self._task = None # type: Optional[asyncio.Task[Any]] 46 | self._cancelled = False 47 | self._cancel_handler = None # type: Optional[asyncio.Handle] 48 | self._cancel_at = None # type: Optional[float] 49 | 50 | def __enter__(self) -> "timeout": 51 | return self._do_enter() 52 | 53 | def __exit__( 54 | self, 55 | exc_type: Type[BaseException], 56 | exc_val: BaseException, 57 | exc_tb: TracebackType, 58 | ) -> Optional[bool]: 59 | self._do_exit(exc_type) 60 | return None 61 | 62 | async def __aenter__(self) -> "timeout": 63 | return self._do_enter() 64 | 65 | async def __aexit__( 66 | self, 67 | exc_type: Type[BaseException], 68 | exc_val: BaseException, 69 | exc_tb: TracebackType, 70 | ) -> None: 71 | self._do_exit(exc_type) 72 | 73 | @property 74 | def expired(self) -> bool: 75 | return self._cancelled 76 | 77 | @property 78 | def remaining(self) -> Optional[float]: 79 | if self._cancel_at is not None: 80 | return max(self._cancel_at - self._loop.time(), 0.0) 81 | else: 82 | return None 83 | 84 | def _do_enter(self) -> "timeout": 85 | # Support Tornado 5- without timeout 86 | # Details: https://github.com/python/asyncio/issues/392 87 | if self._timeout is None: 88 | return self 89 | 90 | self._task = asyncio.current_task(self._loop) 91 | if self._task is None: 92 | raise RuntimeError( 93 | "Timeout context manager should be used " "inside a task" 94 | ) 95 | 96 | if self._timeout <= 0: 97 | self._loop.call_soon(self._cancel_task) 98 | return self 99 | 100 | self._cancel_at = self._loop.time() + self._timeout 101 | self._cancel_handler = self._loop.call_at(self._cancel_at, self._cancel_task) 102 | return self 103 | 104 | def _do_exit(self, exc_type: Type[BaseException]) -> None: 105 | if exc_type is asyncio.CancelledError and self._cancelled: 106 | self._cancel_handler = None 107 | self._task = None 108 | raise asyncio.TimeoutError 109 | if self._timeout is not None and self._cancel_handler is not None: 110 | self._cancel_handler.cancel() 111 | self._cancel_handler = None 112 | self._task = None 113 | return None 114 | 115 | def _cancel_task(self) -> None: 116 | if self._task is not None: 117 | self._task.cancel() 118 | self._cancelled = True 119 | -------------------------------------------------------------------------------- /asgiref/asgiref/typing.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from typing import ( 3 | Any, 4 | Awaitable, 5 | Callable, 6 | Dict, 7 | Iterable, 8 | Literal, 9 | Optional, 10 | Protocol, 11 | Tuple, 12 | Type, 13 | TypedDict, 14 | Union, 15 | ) 16 | 17 | if sys.version_info >= (3, 11): 18 | from typing import NotRequired 19 | else: 20 | from typing_extensions import NotRequired 21 | 22 | __all__ = ( 23 | "ASGIVersions", 24 | "HTTPScope", 25 | "WebSocketScope", 26 | "LifespanScope", 27 | "WWWScope", 28 | "Scope", 29 | "HTTPRequestEvent", 30 | "HTTPResponseStartEvent", 31 | "HTTPResponseBodyEvent", 32 | "HTTPResponseTrailersEvent", 33 | "HTTPResponsePathsendEvent", 34 | "HTTPServerPushEvent", 35 | "HTTPDisconnectEvent", 36 | "WebSocketConnectEvent", 37 | "WebSocketAcceptEvent", 38 | "WebSocketReceiveEvent", 39 | "WebSocketSendEvent", 40 | "WebSocketResponseStartEvent", 41 | "WebSocketResponseBodyEvent", 42 | "WebSocketDisconnectEvent", 43 | "WebSocketCloseEvent", 44 | "LifespanStartupEvent", 45 | "LifespanShutdownEvent", 46 | "LifespanStartupCompleteEvent", 47 | "LifespanStartupFailedEvent", 48 | "LifespanShutdownCompleteEvent", 49 | "LifespanShutdownFailedEvent", 50 | "ASGIReceiveEvent", 51 | "ASGISendEvent", 52 | "ASGIReceiveCallable", 53 | "ASGISendCallable", 54 | "ASGI2Protocol", 55 | "ASGI2Application", 56 | "ASGI3Application", 57 | "ASGIApplication", 58 | ) 59 | 60 | 61 | class ASGIVersions(TypedDict): 62 | spec_version: str 63 | version: Union[Literal["2.0"], Literal["3.0"]] 64 | 65 | 66 | class HTTPScope(TypedDict): 67 | type: Literal["http"] 68 | asgi: ASGIVersions 69 | http_version: str 70 | method: str 71 | scheme: str 72 | path: str 73 | raw_path: bytes 74 | query_string: bytes 75 | root_path: str 76 | headers: Iterable[Tuple[bytes, bytes]] 77 | client: Optional[Tuple[str, int]] 78 | server: Optional[Tuple[str, Optional[int]]] 79 | state: NotRequired[Dict[str, Any]] 80 | extensions: Optional[Dict[str, Dict[object, object]]] 81 | 82 | 83 | class WebSocketScope(TypedDict): 84 | type: Literal["websocket"] 85 | asgi: ASGIVersions 86 | http_version: str 87 | scheme: str 88 | path: str 89 | raw_path: bytes 90 | query_string: bytes 91 | root_path: str 92 | headers: Iterable[Tuple[bytes, bytes]] 93 | client: Optional[Tuple[str, int]] 94 | server: Optional[Tuple[str, Optional[int]]] 95 | subprotocols: Iterable[str] 96 | state: NotRequired[Dict[str, Any]] 97 | extensions: Optional[Dict[str, Dict[object, object]]] 98 | 99 | 100 | class LifespanScope(TypedDict): 101 | type: Literal["lifespan"] 102 | asgi: ASGIVersions 103 | state: NotRequired[Dict[str, Any]] 104 | 105 | 106 | WWWScope = Union[HTTPScope, WebSocketScope] 107 | Scope = Union[HTTPScope, WebSocketScope, LifespanScope] 108 | 109 | 110 | class HTTPRequestEvent(TypedDict): 111 | type: Literal["http.request"] 112 | body: bytes 113 | more_body: bool 114 | 115 | 116 | class HTTPResponseDebugEvent(TypedDict): 117 | type: Literal["http.response.debug"] 118 | info: Dict[str, object] 119 | 120 | 121 | class HTTPResponseStartEvent(TypedDict): 122 | type: Literal["http.response.start"] 123 | status: int 124 | headers: Iterable[Tuple[bytes, bytes]] 125 | trailers: bool 126 | 127 | 128 | class HTTPResponseBodyEvent(TypedDict): 129 | type: Literal["http.response.body"] 130 | body: bytes 131 | more_body: bool 132 | 133 | 134 | class HTTPResponseTrailersEvent(TypedDict): 135 | type: Literal["http.response.trailers"] 136 | headers: Iterable[Tuple[bytes, bytes]] 137 | more_trailers: bool 138 | 139 | 140 | class HTTPResponsePathsendEvent(TypedDict): 141 | type: Literal["http.response.pathsend"] 142 | path: str 143 | 144 | 145 | class HTTPServerPushEvent(TypedDict): 146 | type: Literal["http.response.push"] 147 | path: str 148 | headers: Iterable[Tuple[bytes, bytes]] 149 | 150 | 151 | class HTTPDisconnectEvent(TypedDict): 152 | type: Literal["http.disconnect"] 153 | 154 | 155 | class WebSocketConnectEvent(TypedDict): 156 | type: Literal["websocket.connect"] 157 | 158 | 159 | class WebSocketAcceptEvent(TypedDict): 160 | type: Literal["websocket.accept"] 161 | subprotocol: Optional[str] 162 | headers: Iterable[Tuple[bytes, bytes]] 163 | 164 | 165 | class WebSocketReceiveEvent(TypedDict): 166 | type: Literal["websocket.receive"] 167 | bytes: Optional[bytes] 168 | text: Optional[str] 169 | 170 | 171 | class WebSocketSendEvent(TypedDict): 172 | type: Literal["websocket.send"] 173 | bytes: Optional[bytes] 174 | text: Optional[str] 175 | 176 | 177 | class WebSocketResponseStartEvent(TypedDict): 178 | type: Literal["websocket.http.response.start"] 179 | status: int 180 | headers: Iterable[Tuple[bytes, bytes]] 181 | 182 | 183 | class WebSocketResponseBodyEvent(TypedDict): 184 | type: Literal["websocket.http.response.body"] 185 | body: bytes 186 | more_body: bool 187 | 188 | 189 | class WebSocketDisconnectEvent(TypedDict): 190 | type: Literal["websocket.disconnect"] 191 | code: int 192 | 193 | 194 | class WebSocketCloseEvent(TypedDict): 195 | type: Literal["websocket.close"] 196 | code: int 197 | reason: Optional[str] 198 | 199 | 200 | class LifespanStartupEvent(TypedDict): 201 | type: Literal["lifespan.startup"] 202 | 203 | 204 | class LifespanShutdownEvent(TypedDict): 205 | type: Literal["lifespan.shutdown"] 206 | 207 | 208 | class LifespanStartupCompleteEvent(TypedDict): 209 | type: Literal["lifespan.startup.complete"] 210 | 211 | 212 | class LifespanStartupFailedEvent(TypedDict): 213 | type: Literal["lifespan.startup.failed"] 214 | message: str 215 | 216 | 217 | class LifespanShutdownCompleteEvent(TypedDict): 218 | type: Literal["lifespan.shutdown.complete"] 219 | 220 | 221 | class LifespanShutdownFailedEvent(TypedDict): 222 | type: Literal["lifespan.shutdown.failed"] 223 | message: str 224 | 225 | 226 | ASGIReceiveEvent = Union[ 227 | HTTPRequestEvent, 228 | HTTPDisconnectEvent, 229 | WebSocketConnectEvent, 230 | WebSocketReceiveEvent, 231 | WebSocketDisconnectEvent, 232 | LifespanStartupEvent, 233 | LifespanShutdownEvent, 234 | ] 235 | 236 | 237 | ASGISendEvent = Union[ 238 | HTTPResponseStartEvent, 239 | HTTPResponseBodyEvent, 240 | HTTPResponseTrailersEvent, 241 | HTTPServerPushEvent, 242 | HTTPDisconnectEvent, 243 | WebSocketAcceptEvent, 244 | WebSocketSendEvent, 245 | WebSocketResponseStartEvent, 246 | WebSocketResponseBodyEvent, 247 | WebSocketCloseEvent, 248 | LifespanStartupCompleteEvent, 249 | LifespanStartupFailedEvent, 250 | LifespanShutdownCompleteEvent, 251 | LifespanShutdownFailedEvent, 252 | ] 253 | 254 | 255 | ASGIReceiveCallable = Callable[[], Awaitable[ASGIReceiveEvent]] 256 | ASGISendCallable = Callable[[ASGISendEvent], Awaitable[None]] 257 | 258 | 259 | class ASGI2Protocol(Protocol): 260 | def __init__(self, scope: Scope) -> None: 261 | ... 262 | 263 | async def __call__( 264 | self, receive: ASGIReceiveCallable, send: ASGISendCallable 265 | ) -> None: 266 | ... 267 | 268 | 269 | ASGI2Application = Type[ASGI2Protocol] 270 | ASGI3Application = Callable[ 271 | [ 272 | Scope, 273 | ASGIReceiveCallable, 274 | ASGISendCallable, 275 | ], 276 | Awaitable[None], 277 | ] 278 | ASGIApplication = Union[ASGI2Application, ASGI3Application] 279 | -------------------------------------------------------------------------------- /asgiref/asgiref/wsgi.py: -------------------------------------------------------------------------------- 1 | from io import BytesIO 2 | from tempfile import SpooledTemporaryFile 3 | 4 | from asgiref.sync import AsyncToSync, sync_to_async 5 | 6 | 7 | class WsgiToAsgi: 8 | """ 9 | Wraps a WSGI application to make it into an ASGI application. 10 | """ 11 | 12 | def __init__(self, wsgi_application): 13 | self.wsgi_application = wsgi_application 14 | 15 | async def __call__(self, scope, receive, send): 16 | """ 17 | ASGI application instantiation point. 18 | We return a new WsgiToAsgiInstance here with the WSGI app 19 | and the scope, ready to respond when it is __call__ed. 20 | """ 21 | await WsgiToAsgiInstance(self.wsgi_application)(scope, receive, send) 22 | 23 | 24 | class WsgiToAsgiInstance: 25 | """ 26 | Per-socket instance of a wrapped WSGI application 27 | """ 28 | 29 | def __init__(self, wsgi_application): 30 | self.wsgi_application = wsgi_application 31 | self.response_started = False 32 | self.response_content_length = None 33 | 34 | async def __call__(self, scope, receive, send): 35 | if scope["type"] != "http": 36 | raise ValueError("WSGI wrapper received a non-HTTP scope") 37 | self.scope = scope 38 | with SpooledTemporaryFile(max_size=65536) as body: 39 | # Alright, wait for the http.request messages 40 | while True: 41 | message = await receive() 42 | if message["type"] != "http.request": 43 | raise ValueError("WSGI wrapper received a non-HTTP-request message") 44 | body.write(message.get("body", b"")) 45 | if not message.get("more_body"): 46 | break 47 | body.seek(0) 48 | # Wrap send so it can be called from the subthread 49 | self.sync_send = AsyncToSync(send) 50 | # Call the WSGI app 51 | await self.run_wsgi_app(body) 52 | 53 | def build_environ(self, scope, body): 54 | """ 55 | Builds a scope and request body into a WSGI environ object. 56 | """ 57 | environ = { 58 | "REQUEST_METHOD": scope["method"], 59 | "SCRIPT_NAME": scope.get("root_path", "").encode("utf8").decode("latin1"), 60 | "PATH_INFO": scope["path"].encode("utf8").decode("latin1"), 61 | "QUERY_STRING": scope["query_string"].decode("ascii"), 62 | "SERVER_PROTOCOL": "HTTP/%s" % scope["http_version"], 63 | "wsgi.version": (1, 0), 64 | "wsgi.url_scheme": scope.get("scheme", "http"), 65 | "wsgi.input": body, 66 | "wsgi.errors": BytesIO(), 67 | "wsgi.multithread": True, 68 | "wsgi.multiprocess": True, 69 | "wsgi.run_once": False, 70 | } 71 | # Get server name and port - required in WSGI, not in ASGI 72 | if "server" in scope: 73 | environ["SERVER_NAME"] = scope["server"][0] 74 | environ["SERVER_PORT"] = str(scope["server"][1]) 75 | else: 76 | environ["SERVER_NAME"] = "localhost" 77 | environ["SERVER_PORT"] = "80" 78 | 79 | if scope.get("client") is not None: 80 | environ["REMOTE_ADDR"] = scope["client"][0] 81 | 82 | # Go through headers and make them into environ entries 83 | for name, value in self.scope.get("headers", []): 84 | name = name.decode("latin1") 85 | if name == "content-length": 86 | corrected_name = "CONTENT_LENGTH" 87 | elif name == "content-type": 88 | corrected_name = "CONTENT_TYPE" 89 | else: 90 | corrected_name = "HTTP_%s" % name.upper().replace("-", "_") 91 | # HTTPbis say only ASCII chars are allowed in headers, but we latin1 just in case 92 | value = value.decode("latin1") 93 | if corrected_name in environ: 94 | value = environ[corrected_name] + "," + value 95 | environ[corrected_name] = value 96 | return environ 97 | 98 | def start_response(self, status, response_headers, exc_info=None): 99 | """ 100 | WSGI start_response callable. 101 | """ 102 | # Don't allow re-calling once response has begun 103 | if self.response_started: 104 | raise exc_info[1].with_traceback(exc_info[2]) 105 | # Don't allow re-calling without exc_info 106 | if hasattr(self, "response_start") and exc_info is None: 107 | raise ValueError( 108 | "You cannot call start_response a second time without exc_info" 109 | ) 110 | # Extract status code 111 | status_code, _ = status.split(" ", 1) 112 | status_code = int(status_code) 113 | # Extract headers 114 | headers = [ 115 | (name.lower().encode("ascii"), value.encode("ascii")) 116 | for name, value in response_headers 117 | ] 118 | # Extract content-length 119 | self.response_content_length = None 120 | for name, value in response_headers: 121 | if name.lower() == "content-length": 122 | self.response_content_length = int(value) 123 | # Build and send response start message. 124 | self.response_start = { 125 | "type": "http.response.start", 126 | "status": status_code, 127 | "headers": headers, 128 | } 129 | 130 | @sync_to_async 131 | def run_wsgi_app(self, body): 132 | """ 133 | Called in a subthread to run the WSGI app. We encapsulate like 134 | this so that the start_response callable is called in the same thread. 135 | """ 136 | # Translate the scope and incoming request body into a WSGI environ 137 | environ = self.build_environ(self.scope, body) 138 | # Run the WSGI app 139 | bytes_sent = 0 140 | for output in self.wsgi_application(environ, self.start_response): 141 | # If this is the first response, include the response headers 142 | if not self.response_started: 143 | self.response_started = True 144 | self.sync_send(self.response_start) 145 | # If the application supplies a Content-Length header 146 | if self.response_content_length is not None: 147 | # The server should not transmit more bytes to the client than the header allows 148 | bytes_allowed = self.response_content_length - bytes_sent 149 | if len(output) > bytes_allowed: 150 | output = output[:bytes_allowed] 151 | self.sync_send( 152 | {"type": "http.response.body", "body": output, "more_body": True} 153 | ) 154 | bytes_sent += len(output) 155 | # The server should stop iterating over the response when enough data has been sent 156 | if bytes_sent == self.response_content_length: 157 | break 158 | # Close connection 159 | if not self.response_started: 160 | self.response_started = True 161 | self.sync_send(self.response_start) 162 | self.sync_send({"type": "http.response.body"}) 163 | -------------------------------------------------------------------------------- /asgiref/docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = ASGI 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /asgiref/docs/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from typing import Dict, List 3 | 4 | # 5 | # ASGI documentation build configuration file, created by 6 | # sphinx-quickstart on Thu May 17 21:22:10 2018. 7 | # 8 | # This file is execfile()d with the current directory set to its 9 | # containing dir. 10 | # 11 | # Note that not all possible configuration values are present in this 12 | # autogenerated file. 13 | # 14 | # All configuration values have a default; values that are commented out 15 | # serve to show the default. 16 | 17 | # If extensions (or modules to document with autodoc) are in another directory, 18 | # add these directories to sys.path here. If the directory is relative to the 19 | # documentation root, use os.path.abspath to make it absolute, like shown here. 20 | # 21 | # import os 22 | # import sys 23 | # sys.path.insert(0, os.path.abspath('.')) 24 | 25 | 26 | # -- General configuration ------------------------------------------------ 27 | 28 | # If your documentation needs a minimal Sphinx version, state it here. 29 | # 30 | # needs_sphinx = '1.0' 31 | 32 | # Add any Sphinx extension module names here, as strings. They can be 33 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 34 | # ones. 35 | extensions: List[str] = [] 36 | 37 | # Add any paths that contain templates here, relative to this directory. 38 | templates_path: List[str] = [] 39 | 40 | # The suffix(es) of source filenames. 41 | # You can specify multiple suffix as a list of string: 42 | # 43 | # source_suffix = ['.rst', '.md'] 44 | source_suffix = ".rst" 45 | 46 | # The master toctree document. 47 | master_doc = "index" 48 | 49 | # General information about the project. 50 | project = "ASGI" 51 | copyright = "2018, ASGI Team" 52 | author = "ASGI Team" 53 | 54 | # The version info for the project you're documenting, acts as replacement for 55 | # |version| and |release|, also used in various other places throughout the 56 | # built documents. 57 | # 58 | # The short X.Y version. 59 | version = "3.0" 60 | # The full version, including alpha/beta/rc tags. 61 | release = "3.0" 62 | 63 | # The language for content autogenerated by Sphinx. Refer to documentation 64 | # for a list of supported languages. 65 | # 66 | # This is also used if you do content translation via gettext catalogs. 67 | # Usually you set "language" from the command line for these cases. 68 | language = "en" 69 | 70 | # List of patterns, relative to source directory, that match files and 71 | # directories to ignore when looking for source files. 72 | # This patterns also effect to html_static_path and html_extra_path 73 | exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] 74 | 75 | # The name of the Pygments (syntax highlighting) style to use. 76 | pygments_style = "sphinx" 77 | 78 | # If true, `todo` and `todoList` produce output, else they produce nothing. 79 | todo_include_todos = False 80 | 81 | 82 | # -- Options for HTML output ---------------------------------------------- 83 | 84 | # The theme to use for HTML and HTML Help pages. See the documentation for 85 | # a list of builtin themes. 86 | # 87 | html_theme = "default" 88 | 89 | # Theme options are theme-specific and customize the look and feel of a theme 90 | # further. For a list of options available for each theme, see the 91 | # documentation. 92 | # 93 | # html_theme_options = {} 94 | 95 | # Add any paths that contain custom static files (such as style sheets) here, 96 | # relative to this directory. They are copied after the builtin static files, 97 | # so a file named "default.css" will overwrite the builtin "default.css". 98 | html_static_path: List[str] = [] 99 | 100 | # Custom sidebar templates, must be a dictionary that maps document names 101 | # to template names. 102 | # 103 | # This is required for the alabaster theme 104 | # refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars 105 | # html_sidebars = { 106 | # '**': [ 107 | # 'about.html', 108 | # 'navigation.html', 109 | # 'relations.html', 110 | # 'searchbox.html', 111 | # 'donate.html', 112 | # ] 113 | # } 114 | 115 | 116 | # -- Options for HTMLHelp output ------------------------------------------ 117 | 118 | # Output file base name for HTML help builder. 119 | htmlhelp_basename = "ASGIdoc" 120 | 121 | 122 | # -- Options for LaTeX output --------------------------------------------- 123 | 124 | latex_elements: Dict[str, str] = { 125 | # The paper size ('letterpaper' or 'a4paper'). 126 | # 127 | # 'papersize': 'letterpaper', 128 | # The font size ('10pt', '11pt' or '12pt'). 129 | # 130 | # 'pointsize': '10pt', 131 | # Additional stuff for the LaTeX preamble. 132 | # 133 | # 'preamble': '', 134 | # Latex figure (float) alignment 135 | # 136 | # 'figure_align': 'htbp', 137 | } 138 | 139 | # Grouping the document tree into LaTeX files. List of tuples 140 | # (source start file, target name, title, 141 | # author, documentclass [howto, manual, or own class]). 142 | latex_documents = [ 143 | (master_doc, "ASGI.tex", "ASGI Documentation", "ASGI Team", "manual"), 144 | ] 145 | 146 | 147 | # -- Options for manual page output --------------------------------------- 148 | 149 | # One entry per manual page. List of tuples 150 | # (source start file, name, description, authors, manual section). 151 | man_pages = [(master_doc, "asgi", "ASGI Documentation", [author], 1)] 152 | 153 | 154 | # -- Options for Texinfo output ------------------------------------------- 155 | 156 | # Grouping the document tree into Texinfo files. List of tuples 157 | # (source start file, target name, title, author, 158 | # dir menu entry, description, category) 159 | texinfo_documents = [ 160 | ( 161 | master_doc, 162 | "ASGI", 163 | "ASGI Documentation", 164 | author, 165 | "ASGI", 166 | "One line description of project.", 167 | "Miscellaneous", 168 | ), 169 | ] 170 | -------------------------------------------------------------------------------- /asgiref/docs/implementations.rst: -------------------------------------------------------------------------------- 1 | =============== 2 | Implementations 3 | =============== 4 | 5 | Complete or upcoming implementations of ASGI - servers, frameworks, and other 6 | useful pieces. 7 | 8 | Servers 9 | ======= 10 | 11 | Daphne 12 | ------ 13 | 14 | *Stable* / http://github.com/django/daphne 15 | 16 | The current ASGI reference server, written in Twisted and maintained as part 17 | of the Django Channels project. Supports HTTP/1, HTTP/2, and WebSockets. 18 | 19 | 20 | Granian 21 | ------- 22 | 23 | *Beta* / https://github.com/emmett-framework/granian 24 | 25 | A Rust HTTP server for Python applications. 26 | Supports ASGI/3, RSGI and WSGI interface applications. 27 | 28 | 29 | Hypercorn 30 | --------- 31 | 32 | *Beta* / https://pgjones.gitlab.io/hypercorn/index.html 33 | 34 | An ASGI server based on the sans-io hyper, h11, h2, and wsproto libraries. 35 | Supports HTTP/1, HTTP/2, and WebSockets. 36 | 37 | 38 | NGINX Unit 39 | ---------- 40 | 41 | *Stable* / https://unit.nginx.org/configuration/#configuration-python 42 | 43 | Unit is a lightweight and versatile open-source server that has three core capabilities: it is a web server for static media assets, an application server that runs code in multiple languages, and a reverse proxy. 44 | 45 | 46 | Uvicorn 47 | ------- 48 | 49 | *Stable* / https://www.uvicorn.org/ 50 | 51 | A fast ASGI server based on uvloop and httptools. 52 | Supports HTTP/1 and WebSockets. 53 | 54 | 55 | Application Frameworks 56 | ====================== 57 | 58 | BlackSheep 59 | ---------- 60 | 61 | *Stable* / https://github.com/Neoteroi/BlackSheep 62 | 63 | BlackSheep is typed, fast, minimal web framework. It has performant HTTP client, 64 | flexible dependency injection model, OpenID Connect integration, automatic 65 | OpenAPI documentation, dedicated test client and excellent authentication and 66 | authorization policy implementation. Supports HTTP and WebSockets. 67 | 68 | 69 | Connexion 70 | --------- 71 | 72 | *Stable* / https://github.com/spec-first/connexion 73 | 74 | Connexion is a modern Python web framework that makes spec-first and API-first development 75 | easy. You describe your API in an OpenAPI (or Swagger) specification with as much detail 76 | as you want and Connexion will guarantee that it works as you specified. 77 | 78 | You can use Connexion either standalone, or in combination with any ASGI or WSGI-compatible 79 | framework! 80 | 81 | 82 | Django/Channels 83 | --------------- 84 | 85 | *Stable* / http://channels.readthedocs.io 86 | 87 | Channels is the Django project to add asynchronous support to Django and is the 88 | original driving force behind the ASGI project. Supports HTTP and WebSockets 89 | with Django integration, and any protocol with ASGI-native code. 90 | 91 | 92 | Esmerald 93 | -------- 94 | 95 | *Stable* / https://esmerald.dev/ 96 | 97 | Esmerald is a modern, powerful, flexible, high performant web framework designed to build not only APIs but also full scalable applications from the smallest to enterprise level. Modular, elagant and pluggable at its core. 98 | 99 | 100 | FastAPI 101 | ------- 102 | 103 | *Beta* / https://github.com/tiangolo/fastapi 104 | 105 | FastAPI is an ASGI web framework (made with Starlette) for building web APIs based on 106 | standard Python type annotations and standards like OpenAPI, JSON Schema, and OAuth2. 107 | Supports HTTP and WebSockets. 108 | 109 | 110 | Litestar 111 | -------- 112 | 113 | *Stable* / https://litestar.dev/ 114 | 115 | Litestar is a powerful, performant, flexible and opinionated ASGI framework, offering 116 | first class typing support and a full Pydantic integration. Effortlessly Build Performant 117 | APIs. 118 | 119 | 120 | Quart 121 | ----- 122 | 123 | *Beta* / https://github.com/pgjones/quart 124 | 125 | Quart is a Python ASGI web microframework. It is intended to provide the easiest 126 | way to use asyncio functionality in a web context, especially with existing Flask apps. 127 | Supports HTTP. 128 | 129 | 130 | Sanic 131 | ----- 132 | 133 | *Beta* / https://sanicframework.org 134 | 135 | Sanic is an unopinionated and flexible web application server and framework that also 136 | has the ability to operate as an ASGI compatible framework. Therefore, it can be run 137 | using any of the ASGI web servers. Supports HTTP and WebSockets. 138 | 139 | 140 | rpc.py 141 | ------ 142 | 143 | *Beta* / https://github.com/abersheeran/rpc.py 144 | 145 | An easy-to-use and powerful RPC framework. RPC server base on WSGI & ASGI, client base 146 | on ``httpx``. Supports synchronous functions, asynchronous functions, synchronous 147 | generator functions, and asynchronous generator functions. Optional use of Type hint 148 | for type conversion. Optional OpenAPI document generation. 149 | 150 | 151 | Starlette 152 | --------- 153 | 154 | *Beta* / https://github.com/encode/starlette 155 | 156 | Starlette is a minimalist ASGI library for writing against basic but powerful 157 | ``Request`` and ``Response`` classes. Supports HTTP and WebSockets. 158 | 159 | 160 | Tools 161 | ===== 162 | 163 | a2wsgi 164 | ------ 165 | 166 | *Stable* / https://github.com/abersheeran/a2wsgi 167 | 168 | Convert WSGI application to ASGI application or ASGI application to WSGI application. 169 | Pure Python. Only depend on the standard library. 170 | -------------------------------------------------------------------------------- /asgiref/docs/index.rst: -------------------------------------------------------------------------------- 1 | 2 | ASGI Documentation 3 | ================== 4 | 5 | ASGI (*Asynchronous Server Gateway Interface*) is a spiritual successor to 6 | WSGI, intended to provide a standard interface between async-capable Python 7 | web servers, frameworks, and applications. 8 | 9 | Where WSGI provided a standard for synchronous Python apps, ASGI provides one 10 | for both asynchronous and synchronous apps, with a WSGI backwards-compatibility 11 | implementation and multiple servers and application frameworks. 12 | 13 | You can read more in the :doc:`introduction ` to ASGI, look 14 | through the :doc:`specifications `, and see what 15 | :doc:`implementations ` there already are or that are upcoming. 16 | 17 | Contribution and discussion about ASGI is welcome, and mostly happens on 18 | the `asgiref GitHub repository `_. 19 | 20 | .. toctree:: 21 | :maxdepth: 1 22 | 23 | introduction 24 | specs/index 25 | extensions 26 | implementations 27 | -------------------------------------------------------------------------------- /asgiref/docs/introduction.rst: -------------------------------------------------------------------------------- 1 | Introduction 2 | ============ 3 | 4 | ASGI is a spiritual successor to 5 | `WSGI `_, the long-standing Python 6 | standard for compatibility between web servers, frameworks, and applications. 7 | 8 | WSGI succeeded in allowing much more freedom and innovation in the Python 9 | web space, and ASGI's goal is to continue this onward into the land of 10 | asynchronous Python. 11 | 12 | 13 | What's wrong with WSGI? 14 | ----------------------- 15 | 16 | You may ask "why not just upgrade WSGI"? This has been asked many times over 17 | the years, and the problem usually ends up being that WSGI's single-callable 18 | interface just isn't suitable for more involved Web protocols like WebSocket. 19 | 20 | WSGI applications are a single, synchronous callable that takes a request and 21 | returns a response; this doesn't allow for long-lived connections, like you 22 | get with long-poll HTTP or WebSocket connections. 23 | 24 | Even if we made this callable asynchronous, it still only has a single path 25 | to provide a request, so protocols that have multiple incoming events (like 26 | receiving WebSocket frames) can't trigger this. 27 | 28 | 29 | How does ASGI work? 30 | ------------------- 31 | 32 | ASGI is structured as a single, asynchronous callable. It takes a ``scope``, 33 | which is a ``dict`` containing details about the specific connection, 34 | ``send``, an asynchronous callable, that lets the application send event messages 35 | to the client, and ``receive``, an asynchronous callable which lets the application 36 | receive event messages from the client. 37 | 38 | This not only allows multiple incoming events and outgoing events for each 39 | application, but also allows for a background coroutine so the application can 40 | do other things (such as listening for events on an external trigger, like a 41 | Redis queue). 42 | 43 | In its simplest form, an application can be written as an asynchronous function, 44 | like this:: 45 | 46 | async def application(scope, receive, send): 47 | event = await receive() 48 | ... 49 | await send({"type": "websocket.send", ...}) 50 | 51 | Every *event* that you send or receive is a Python ``dict``, with a predefined 52 | format. It's these event formats that form the basis of the standard, and allow 53 | applications to be swappable between servers. 54 | 55 | These *events* each have a defined ``type`` key, which can be used to infer 56 | the event's structure. Here's an example event that you might receive from 57 | ``receive`` with the body from a HTTP request:: 58 | 59 | { 60 | "type": "http.request", 61 | "body": b"Hello World", 62 | "more_body": False, 63 | } 64 | 65 | And here's an example of an event you might pass to ``send`` to send an 66 | outgoing WebSocket message:: 67 | 68 | { 69 | "type": "websocket.send", 70 | "text": "Hello world!", 71 | } 72 | 73 | 74 | WSGI compatibility 75 | ------------------ 76 | 77 | ASGI is also designed to be a superset of WSGI, and there's a defined way 78 | of translating between the two, allowing WSGI applications to be run inside 79 | ASGI servers through a translation wrapper (provided in the ``asgiref`` 80 | library). A threadpool can be used to run the synchronous WSGI applications 81 | away from the async event loop. 82 | -------------------------------------------------------------------------------- /asgiref/docs/specs/index.rst: -------------------------------------------------------------------------------- 1 | Specifications 2 | ============== 3 | 4 | These are the specifications for ASGI. The root specification outlines how 5 | applications are structured and called, and the protocol specifications outline 6 | the events that can be sent and received for each protocol. 7 | 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | 12 | ASGI Specification
13 | HTTP and WebSocket protocol 14 | Lifespan 15 | TLS Extension 16 | -------------------------------------------------------------------------------- /asgiref/docs/specs/lifespan.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../../specs/lifespan.rst 2 | -------------------------------------------------------------------------------- /asgiref/docs/specs/main.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../../specs/asgi.rst 2 | -------------------------------------------------------------------------------- /asgiref/docs/specs/tls.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../../specs/tls.rst 2 | -------------------------------------------------------------------------------- /asgiref/docs/specs/www.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../../specs/www.rst 2 | -------------------------------------------------------------------------------- /asgiref/setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = asgiref 3 | version = attr: asgiref.__version__ 4 | url = https://github.com/django/asgiref/ 5 | author = Django Software Foundation 6 | author_email = foundation@djangoproject.com 7 | description = ASGI specs, helper code, and adapters 8 | long_description = file: README.rst 9 | license = BSD-3-Clause 10 | classifiers = 11 | Development Status :: 5 - Production/Stable 12 | Environment :: Web Environment 13 | Intended Audience :: Developers 14 | License :: OSI Approved :: BSD License 15 | Operating System :: OS Independent 16 | Programming Language :: Python 17 | Programming Language :: Python :: 3 18 | Programming Language :: Python :: 3 :: Only 19 | Programming Language :: Python :: 3.8 20 | Programming Language :: Python :: 3.9 21 | Programming Language :: Python :: 3.10 22 | Programming Language :: Python :: 3.11 23 | Programming Language :: Python :: 3.12 24 | Topic :: Internet :: WWW/HTTP 25 | project_urls = 26 | Documentation = https://asgi.readthedocs.io/ 27 | Further Documentation = https://docs.djangoproject.com/en/stable/topics/async/#async-adapter-functions 28 | Changelog = https://github.com/django/asgiref/blob/master/CHANGELOG.txt 29 | 30 | [options] 31 | python_requires = >=3.8 32 | packages = find: 33 | include_package_data = true 34 | install_requires = 35 | typing_extensions>=4; python_version < "3.11" 36 | zip_safe = false 37 | 38 | [options.extras_require] 39 | tests = 40 | pytest 41 | pytest-asyncio 42 | mypy>=0.800 43 | 44 | [tool:pytest] 45 | testpaths = tests 46 | asyncio_mode = strict 47 | 48 | [flake8] 49 | exclude = venv/*,tox/*,specs/* 50 | ignore = E123,E128,E266,E402,W503,E731,W601 51 | max-line-length = 119 52 | 53 | [isort] 54 | profile = black 55 | multi_line_output = 3 56 | 57 | [mypy] 58 | warn_unused_ignores = True 59 | strict = True 60 | 61 | [mypy-asgiref.current_thread_executor] 62 | disallow_untyped_defs = False 63 | check_untyped_defs = False 64 | 65 | [mypy-asgiref.local] 66 | disallow_untyped_defs = False 67 | check_untyped_defs = False 68 | 69 | [mypy-asgiref.sync] 70 | disallow_untyped_defs = False 71 | check_untyped_defs = False 72 | 73 | [mypy-asgiref.compatibility] 74 | disallow_untyped_defs = False 75 | check_untyped_defs = False 76 | 77 | [mypy-asgiref.wsgi] 78 | disallow_untyped_defs = False 79 | check_untyped_defs = False 80 | 81 | [mypy-asgiref.testing] 82 | disallow_untyped_defs = False 83 | check_untyped_defs = False 84 | 85 | [mypy-asgiref.server] 86 | disallow_untyped_defs = False 87 | check_untyped_defs = False 88 | 89 | [mypy-test_server] 90 | disallow_untyped_defs = False 91 | check_untyped_defs = False 92 | 93 | [mypy-test_wsgi] 94 | disallow_untyped_defs = False 95 | check_untyped_defs = False 96 | 97 | [mypy-test_testing] 98 | disallow_untyped_defs = False 99 | check_untyped_defs = False 100 | 101 | [mypy-test_sync_contextvars] 102 | disallow_untyped_defs = False 103 | check_untyped_defs = False 104 | 105 | [mypy-test_sync] 106 | disallow_untyped_defs = False 107 | check_untyped_defs = False 108 | 109 | [mypy-test_local] 110 | disallow_untyped_defs = False 111 | check_untyped_defs = False 112 | 113 | [mypy-test_compatibility] 114 | disallow_untyped_defs = False 115 | check_untyped_defs = False 116 | -------------------------------------------------------------------------------- /asgiref/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup # type: ignore[import-untyped] 2 | 3 | setup() 4 | -------------------------------------------------------------------------------- /asgiref/specs/lifespan.rst: -------------------------------------------------------------------------------- 1 | ================= 2 | Lifespan Protocol 3 | ================= 4 | 5 | **Version**: 2.0 (2019-03-20) 6 | 7 | The Lifespan ASGI sub-specification outlines how to communicate 8 | lifespan events such as startup and shutdown within ASGI. 9 | 10 | The lifespan messages allow for an application to initialise and 11 | shutdown in the context of a running event loop. An example of this 12 | would be creating a connection pool and subsequently closing the 13 | connection pool to release the connections. 14 | 15 | Lifespans should be executed once per event loop that will be processing requests. 16 | In a multi-process environment there will be lifespan events in each process 17 | and in a multi-threaded environment there will be lifespans for each thread. 18 | The important part is that lifespans and requests are run in the same event loop 19 | to ensure that objects like database connection pools are not moved or shared across event loops. 20 | 21 | A possible implementation of this protocol is given below:: 22 | 23 | async def app(scope, receive, send): 24 | if scope['type'] == 'lifespan': 25 | while True: 26 | message = await receive() 27 | if message['type'] == 'lifespan.startup': 28 | ... # Do some startup here! 29 | await send({'type': 'lifespan.startup.complete'}) 30 | elif message['type'] == 'lifespan.shutdown': 31 | ... # Do some shutdown here! 32 | await send({'type': 'lifespan.shutdown.complete'}) 33 | return 34 | else: 35 | pass # Handle other types 36 | 37 | 38 | Scope 39 | ''''' 40 | 41 | The lifespan scope exists for the duration of the event loop. 42 | 43 | The scope information passed in ``scope`` contains basic metadata: 44 | 45 | * ``type`` (*Unicode string*) -- ``"lifespan"``. 46 | * ``asgi["version"]`` (*Unicode string*) -- The version of the ASGI spec. 47 | * ``asgi["spec_version"]`` (*Unicode string*) -- The version of this spec being 48 | used. Optional; if missing defaults to ``"1.0"``. 49 | * ``state`` Optional(*dict[Unicode string, Any]*) -- An empty namespace where 50 | the application can persist state to be used when handling subsequent requests. 51 | Optional; if missing the server does not support this feature. 52 | 53 | If an exception is raised when calling the application callable with a 54 | ``lifespan.startup`` message or a ``scope`` with type ``lifespan``, 55 | the server must continue but not send any lifespan events. 56 | 57 | This allows for compatibility with applications that do not support the 58 | lifespan protocol. If you want to log an error that occurs during lifespan 59 | startup and prevent the server from starting, then send back 60 | ``lifespan.startup.failed`` instead. 61 | 62 | Lifespan State 63 | -------------- 64 | 65 | Applications often want to persist data from the lifespan cycle to request/response handling. 66 | For example, a database connection can be established in the lifespan cycle and persisted to 67 | the request/response cycle. 68 | The ``scope["state"]`` namespace provides a place to store these sorts of things. 69 | The server will ensure that a *shallow copy* of the namespace is passed into each subsequent 70 | request/response call into the application. 71 | Since the server manages the application lifespan and often the event loop as well this 72 | ensures that the application is always accessing the database connection (or other stored object) 73 | that corresponds to the right event loop and lifecycle, without using context variables, 74 | global mutable state or having to worry about references to stale/closed connections. 75 | 76 | ASGI servers that implement this feature will provide 77 | ``state`` as part of the ``lifespan`` scope:: 78 | 79 | "scope": { 80 | ... 81 | "state": {}, 82 | } 83 | 84 | The namespace is controlled completely by the ASGI application, the server will not 85 | interact with it other than to copy it. 86 | Nonetheless applications should be cooperative by properly naming their keys such that they 87 | will not collide with other frameworks or middleware. 88 | 89 | Startup - ``receive`` event 90 | ''''''''''''''''''''''''''' 91 | 92 | Sent to the application when the server is ready to startup and receive connections, 93 | but before it has started to do so. 94 | 95 | Keys: 96 | 97 | * ``type`` (*Unicode string*) -- ``"lifespan.startup"``. 98 | 99 | 100 | Startup Complete - ``send`` event 101 | ''''''''''''''''''''''''''''''''' 102 | 103 | Sent by the application when it has completed its startup. A server 104 | must wait for this message before it starts processing connections. 105 | 106 | Keys: 107 | 108 | * ``type`` (*Unicode string*) -- ``"lifespan.startup.complete"``. 109 | 110 | 111 | Startup Failed - ``send`` event 112 | ''''''''''''''''''''''''''''''' 113 | 114 | Sent by the application when it has failed to complete its startup. If a server 115 | sees this it should log/print the message provided and then exit. 116 | 117 | Keys: 118 | 119 | * ``type`` (*Unicode string*) -- ``"lifespan.startup.failed"``. 120 | * ``message`` (*Unicode string*) -- Optional; if missing defaults to ``""``. 121 | 122 | 123 | Shutdown - ``receive`` event 124 | '''''''''''''''''''''''''''' 125 | 126 | Sent to the application when the server has stopped accepting connections and closed 127 | all active connections. 128 | 129 | Keys: 130 | 131 | * ``type`` (*Unicode string*) -- ``"lifespan.shutdown"``. 132 | 133 | 134 | Shutdown Complete - ``send`` event 135 | '''''''''''''''''''''''''''''''''' 136 | 137 | Sent by the application when it has completed its cleanup. A server 138 | must wait for this message before terminating. 139 | 140 | Keys: 141 | 142 | * ``type`` (*Unicode string*) -- ``"lifespan.shutdown.complete"``. 143 | 144 | 145 | Shutdown Failed - ``send`` event 146 | '''''''''''''''''''''''''''''''' 147 | 148 | Sent by the application when it has failed to complete its cleanup. If a server 149 | sees this it should log/print the message provided and then terminate. 150 | 151 | Keys: 152 | 153 | * ``type`` (*Unicode string*) -- ``"lifespan.shutdown.failed"``. 154 | * ``message`` (*Unicode string*) -- Optional; if missing defaults to ``""``. 155 | 156 | 157 | Version History 158 | ''''''''''''''' 159 | 160 | * 2.0 (2019-03-04): Added startup.failed and shutdown.failed, 161 | clarified exception handling during startup phase. 162 | * 1.0 (2018-09-06): Updated ASGI spec with a lifespan protocol. 163 | 164 | 165 | Copyright 166 | ''''''''' 167 | 168 | This document has been placed in the public domain. 169 | -------------------------------------------------------------------------------- /asgiref/tests/test_compatibility.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from asgiref.compatibility import double_to_single_callable, is_double_callable 4 | from asgiref.testing import ApplicationCommunicator 5 | 6 | 7 | def double_application_function(scope): 8 | """ 9 | A nested function based double-callable application. 10 | """ 11 | 12 | async def inner(receive, send): 13 | message = await receive() 14 | await send({"scope": scope["value"], "message": message["value"]}) 15 | 16 | return inner 17 | 18 | 19 | class DoubleApplicationClass: 20 | """ 21 | A classic class-based double-callable application. 22 | """ 23 | 24 | def __init__(self, scope): 25 | pass 26 | 27 | async def __call__(self, receive, send): 28 | pass 29 | 30 | 31 | class DoubleApplicationClassNestedFunction: 32 | """ 33 | A function closure inside a class! 34 | """ 35 | 36 | def __init__(self): 37 | pass 38 | 39 | def __call__(self, scope): 40 | async def inner(receive, send): 41 | pass 42 | 43 | return inner 44 | 45 | 46 | async def single_application_function(scope, receive, send): 47 | """ 48 | A single-function single-callable application 49 | """ 50 | pass 51 | 52 | 53 | class SingleApplicationClass: 54 | """ 55 | A single-callable class (where you'd pass the class instance in, 56 | e.g. middleware) 57 | """ 58 | 59 | def __init__(self): 60 | pass 61 | 62 | async def __call__(self, scope, receive, send): 63 | pass 64 | 65 | 66 | def test_is_double_callable(): 67 | """ 68 | Tests that the signature matcher works as expected. 69 | """ 70 | assert is_double_callable(double_application_function) is True 71 | assert is_double_callable(DoubleApplicationClass) is True 72 | assert is_double_callable(DoubleApplicationClassNestedFunction()) is True 73 | assert is_double_callable(single_application_function) is False 74 | assert is_double_callable(SingleApplicationClass()) is False 75 | 76 | 77 | def test_double_to_single_signature(): 78 | """ 79 | Test that the new object passes a signature test. 80 | """ 81 | assert ( 82 | is_double_callable(double_to_single_callable(double_application_function)) 83 | is False 84 | ) 85 | 86 | 87 | @pytest.mark.asyncio 88 | async def test_double_to_single_communicator(): 89 | """ 90 | Test that the new application works 91 | """ 92 | new_app = double_to_single_callable(double_application_function) 93 | instance = ApplicationCommunicator(new_app, {"value": "woohoo"}) 94 | await instance.send_input({"value": 42}) 95 | assert await instance.receive_output() == {"scope": "woohoo", "message": 42} 96 | -------------------------------------------------------------------------------- /asgiref/tests/test_server.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import socket as sock 3 | from functools import partial 4 | 5 | import pytest 6 | 7 | from asgiref.server import StatelessServer 8 | 9 | 10 | async def sock_recvfrom(sock, n): 11 | while True: 12 | try: 13 | return sock.recvfrom(n) 14 | except BlockingIOError: 15 | await asyncio.sleep(0) 16 | 17 | 18 | class Server(StatelessServer): 19 | def __init__(self, application, max_applications=1000): 20 | super().__init__( 21 | application, 22 | max_applications=max_applications, 23 | ) 24 | self._sock = sock.socket(sock.AF_INET, sock.SOCK_DGRAM) 25 | self._sock.setblocking(False) 26 | self._sock.bind(("127.0.0.1", 0)) 27 | 28 | @property 29 | def address(self): 30 | return self._sock.getsockname() 31 | 32 | async def handle(self): 33 | while True: 34 | data, addr = await sock_recvfrom(self._sock, 4096) 35 | data = data.decode("utf-8") 36 | 37 | if data.startswith("Register"): 38 | _, usr_name = data.split(" ") 39 | input_quene = self.get_or_create_application_instance(usr_name, addr) 40 | input_quene.put_nowait(b"Welcome") 41 | 42 | elif data.startswith("To"): 43 | _, usr_name, msg = data.split(" ", 2) 44 | input_quene = self.get_or_create_application_instance(usr_name, addr) 45 | input_quene.put_nowait(msg.encode("utf-8")) 46 | 47 | async def application_send(self, scope, message): 48 | self._sock.sendto(message, scope) 49 | 50 | def close(self): 51 | self._sock.close() 52 | for details in self.application_instances.values(): 53 | details["future"].cancel() 54 | 55 | 56 | class Client: 57 | def __init__(self, name): 58 | self._sock = sock.socket(sock.AF_INET, sock.SOCK_DGRAM) 59 | self._sock.setblocking(False) 60 | self.name = name 61 | 62 | async def register(self, server_addr, name=None): 63 | name = name or self.name 64 | self._sock.sendto(f"Register {name}".encode(), server_addr) 65 | 66 | async def send(self, server_addr, to, msg): 67 | self._sock.sendto(f"To {to} {msg}".encode(), server_addr) 68 | 69 | async def get_msg(self): 70 | msg, server_addr = await sock_recvfrom(self._sock, 4096) 71 | return msg, server_addr 72 | 73 | def close(self): 74 | self._sock.close() 75 | 76 | 77 | @pytest.fixture(scope="function") 78 | def server(): 79 | async def app(scope, receive, send): 80 | while True: 81 | msg = await receive() 82 | await send(msg) 83 | 84 | server = Server(app, 10) 85 | yield server 86 | server.close() 87 | 88 | 89 | async def check_client_msg(client, expected_address, expected_msg): 90 | msg, server_addr = await asyncio.wait_for(client.get_msg(), timeout=1.0) 91 | assert msg == expected_msg 92 | assert server_addr == expected_address 93 | 94 | 95 | async def server_auto_close(fut, timeout): 96 | """Server run based on run_until_complete. It will block forever with handle 97 | function because it is a while True loop without break. Use this method to close 98 | server automatically.""" 99 | loop = asyncio.get_running_loop() 100 | task = asyncio.ensure_future(fut, loop=loop) 101 | await asyncio.sleep(timeout) 102 | task.cancel() 103 | 104 | 105 | def test_stateless_server(server): 106 | """StatelessServer can be instantiated with an ASGI 3 application.""" 107 | """Create a UDP Server can register instance based on name from message of client. 108 | Clients can communicate to other client by name through server""" 109 | 110 | loop = asyncio.new_event_loop() 111 | asyncio.set_event_loop(loop) 112 | server.handle = partial(server_auto_close, fut=server.handle(), timeout=1.0) 113 | 114 | client1 = Client(name="client1") 115 | client2 = Client(name="client2") 116 | 117 | async def check_client1_behavior(): 118 | await client1.register(server.address) 119 | await check_client_msg(client1, server.address, b"Welcome") 120 | await client1.send(server.address, "client2", "Hello") 121 | 122 | async def check_client2_behavior(): 123 | await client2.register(server.address) 124 | await check_client_msg(client2, server.address, b"Welcome") 125 | await check_client_msg(client2, server.address, b"Hello") 126 | 127 | task1 = loop.create_task(check_client1_behavior()) 128 | task2 = loop.create_task(check_client2_behavior()) 129 | 130 | server.run() 131 | 132 | assert task1.done() 133 | assert task2.done() 134 | 135 | 136 | def test_server_delete_instance(server): 137 | """The max_applications of Server is 10. After 20 times register, application number should be 10.""" 138 | loop = asyncio.new_event_loop() 139 | asyncio.set_event_loop(loop) 140 | server.handle = partial(server_auto_close, fut=server.handle(), timeout=1.0) 141 | 142 | client1 = Client(name="client1") 143 | 144 | async def client1_multiple_register(): 145 | for i in range(20): 146 | await client1.register(server.address, name=f"client{i}") 147 | print(f"client{i}") 148 | await check_client_msg(client1, server.address, b"Welcome") 149 | 150 | task = loop.create_task(client1_multiple_register()) 151 | server.run() 152 | 153 | assert task.done() 154 | -------------------------------------------------------------------------------- /asgiref/tests/test_sync_contextvars.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import contextvars 3 | import threading 4 | import time 5 | 6 | import pytest 7 | 8 | from asgiref.sync import ThreadSensitiveContext, async_to_sync, sync_to_async 9 | 10 | foo: "contextvars.ContextVar[str]" = contextvars.ContextVar("foo") 11 | 12 | 13 | @pytest.mark.asyncio 14 | async def test_thread_sensitive_with_context_different(): 15 | result_1 = {} 16 | result_2 = {} 17 | 18 | @sync_to_async 19 | def store_thread(result): 20 | result["thread"] = threading.current_thread() 21 | 22 | async def fn(result): 23 | async with ThreadSensitiveContext(): 24 | await store_thread(result) 25 | 26 | # Run it (in true parallel!) 27 | await asyncio.wait( 28 | [asyncio.create_task(fn(result_1)), asyncio.create_task(fn(result_2))] 29 | ) 30 | 31 | # They should not have run in the main thread, and on different threads 32 | assert result_1["thread"] != threading.current_thread() 33 | assert result_1["thread"] != result_2["thread"] 34 | 35 | 36 | @pytest.mark.asyncio 37 | async def test_sync_to_async_contextvars(): 38 | """ 39 | Tests to make sure that contextvars from the calling context are 40 | present in the called context, and that any changes in the called context 41 | are then propagated back to the calling context. 42 | """ 43 | # Define sync function 44 | def sync_function(): 45 | time.sleep(1) 46 | assert foo.get() == "bar" 47 | foo.set("baz") 48 | return 42 49 | 50 | # Ensure outermost detection works 51 | # Wrap it 52 | foo.set("bar") 53 | async_function = sync_to_async(sync_function) 54 | assert await async_function() == 42 55 | assert foo.get() == "baz" 56 | 57 | 58 | def test_async_to_sync_contextvars(): 59 | """ 60 | Tests to make sure that contextvars from the calling context are 61 | present in the called context, and that any changes in the called context 62 | are then propagated back to the calling context. 63 | """ 64 | # Define sync function 65 | async def async_function(): 66 | await asyncio.sleep(1) 67 | assert foo.get() == "bar" 68 | foo.set("baz") 69 | return 42 70 | 71 | # Ensure outermost detection works 72 | # Wrap it 73 | foo.set("bar") 74 | sync_function = async_to_sync(async_function) 75 | assert sync_function() == 42 76 | assert foo.get() == "baz" 77 | -------------------------------------------------------------------------------- /asgiref/tests/test_testing.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from asgiref.testing import ApplicationCommunicator 4 | from asgiref.wsgi import WsgiToAsgi 5 | 6 | 7 | @pytest.mark.asyncio 8 | async def test_receive_nothing(): 9 | """ 10 | Tests ApplicationCommunicator.receive_nothing to return the correct value. 11 | """ 12 | # Get an ApplicationCommunicator instance 13 | def wsgi_application(environ, start_response): 14 | start_response("200 OK", []) 15 | yield b"content" 16 | 17 | application = WsgiToAsgi(wsgi_application) 18 | instance = ApplicationCommunicator( 19 | application, 20 | { 21 | "type": "http", 22 | "http_version": "1.0", 23 | "method": "GET", 24 | "path": "/foo/", 25 | "query_string": b"bar=baz", 26 | "headers": [], 27 | }, 28 | ) 29 | 30 | # No event 31 | assert await instance.receive_nothing() is True 32 | 33 | # Produce 3 events to receive 34 | await instance.send_input({"type": "http.request"}) 35 | # Start event of the response 36 | assert await instance.receive_nothing() is False 37 | await instance.receive_output() 38 | # First body event of the response announcing further body event 39 | assert await instance.receive_nothing() is False 40 | await instance.receive_output() 41 | # Last body event of the response 42 | assert await instance.receive_nothing() is False 43 | await instance.receive_output() 44 | # Response received completely 45 | assert await instance.receive_nothing(0.01) is True 46 | -------------------------------------------------------------------------------- /asgiref/tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = 3 | py{38,39,310,311,312}-{test,mypy} 4 | qa 5 | 6 | [testenv] 7 | usedevelop = true 8 | extras = tests 9 | commands = 10 | test: pytest -v {posargs} 11 | mypy: mypy . {posargs} 12 | deps = 13 | setuptools 14 | 15 | [testenv:qa] 16 | skip_install = true 17 | deps = 18 | pre-commit 19 | commands = 20 | pre-commit {posargs:run --all-files --show-diff-on-failure} 21 | -------------------------------------------------------------------------------- /django-asv/.github/workflows/benchmark.yml: -------------------------------------------------------------------------------- 1 | name: Benchmark 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - "main" 8 | schedule: 9 | - cron: '0 0 * * *' 10 | 11 | jobs: 12 | run_benchmarks: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v3 17 | - uses: actions/setup-python@v4 18 | with: 19 | python-version: '3.11' 20 | - name: Pull Changes 21 | if: github.event_name != 'pull_request' 22 | run: git pull origin 23 | - name: Install Requirements 24 | run: pip install -r requirements.txt 25 | - name: Cache Django 26 | uses: actions/cache@v3 27 | with: 28 | path: Django/* 29 | key: Django 30 | - name: Run Benchmarks 31 | shell: bash -l {0} 32 | run: |- 33 | asv machine --machine ubuntu-latest --yes 34 | echo '```' >> $GITHUB_STEP_SUMMARY 35 | asv continuous --interleave-processes -a processes=2 --split --show-stderr 'HEAD^' 'HEAD' |\ 36 | sed -n -E '/(before.*after.*ratio)|(BENCHMARKS)/,$p' >> out.txt 37 | cat out.txt >> $GITHUB_STEP_SUMMARY 38 | echo '```' >> $GITHUB_STEP_SUMMARY 39 | - name: Commit results 40 | if: github.event_name != 'pull_request' 41 | run: | 42 | git config user.name "Github Bot" 43 | git config user.email "results_bot@github.com" 44 | git add -f results/* 45 | git commit -m "Results for ubuntu-latest added [skip ci]" 46 | git push origin 47 | 48 | call_publish_results_workflow: 49 | needs: run_benchmarks 50 | if: github.event_name != 'pull_request' 51 | uses: django/django-asv/.github/workflows/publish-results.yml@main 52 | -------------------------------------------------------------------------------- /django-asv/.github/workflows/publish-results.yml: -------------------------------------------------------------------------------- 1 | name: Publish results 2 | 3 | on: workflow_call 4 | 5 | jobs: 6 | publish_results: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout 10 | uses: actions/checkout@v3 11 | - uses: actions/setup-python@v4 12 | with: 13 | python-version: '3.11' 14 | - name: Install Requirements 15 | run: pip install -r requirements.txt 16 | - name: Git config 17 | run: | 18 | git config --global user.name "gh-pages bot" 19 | git config --global user.email "gh-pages-bot@benchmarks.com" 20 | - name: Fetch changes in gh-pages branch 21 | run: git fetch origin gh-pages:gh-pages 22 | - name: Publish results 23 | run: | 24 | asv gh-pages 25 | -------------------------------------------------------------------------------- /django-asv/.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 98 | __pypackages__/ 99 | 100 | # Celery stuff 101 | celerybeat-schedule 102 | celerybeat.pid 103 | 104 | # SageMath parsed files 105 | *.sage.py 106 | 107 | # Environments 108 | .env 109 | .venv 110 | env/ 111 | venv/ 112 | ENV/ 113 | env.bak/ 114 | venv.bak/ 115 | 116 | # Spyder project settings 117 | .spyderproject 118 | .spyproject 119 | 120 | # Rope project settings 121 | .ropeproject 122 | 123 | # mkdocs documentation 124 | /site 125 | 126 | # mypy 127 | .mypy_cache/ 128 | .dmypy.json 129 | dmypy.json 130 | 131 | # Pyre type checker 132 | .pyre/ 133 | 134 | # pytype static type analyzer 135 | .pytype/ 136 | 137 | # Cython debug symbols 138 | cython_debug/ 139 | 140 | # asv 141 | Django/ 142 | html/ 143 | results/ 144 | 145 | # vscode 146 | settings.json 147 | -------------------------------------------------------------------------------- /django-asv/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | exclude: ^results/ 2 | 3 | repos: 4 | - repo: https://github.com/pre-commit/pre-commit-hooks 5 | rev: v4.4.0 6 | hooks: 7 | - id: check-added-large-files 8 | - id: check-case-conflict 9 | - id: check-json 10 | - id: check-merge-conflict 11 | - id: check-symlinks 12 | - id: check-toml 13 | - id: end-of-file-fixer 14 | - id: trailing-whitespace 15 | - repo: https://github.com/psf/black 16 | rev: 22.12.0 17 | hooks: 18 | - id: black 19 | - repo: https://github.com/pycqa/isort 20 | rev: 5.11.4 21 | hooks: 22 | - id: isort 23 | - repo: https://github.com/PyCQA/flake8 24 | rev: 6.0.0 25 | hooks: 26 | - id: flake8 27 | -------------------------------------------------------------------------------- /django-asv/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 David Smith 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /django-asv/asv.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "project": "Django", 4 | "project_url": "https://www.djangoproject.com/", 5 | "repo": "https://github.com/django/django.git", 6 | "branches": ["main"], 7 | "environment_type": "conda", 8 | "conda_channels": ["conda-forge", "defaults"], 9 | "show_commit_url": "http://github.com/django/django/commit/", 10 | "pythons": ["3.10", "3.9", "3.8"] 11 | } 12 | -------------------------------------------------------------------------------- /django-asv/benchmarks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/benchmarks.py: -------------------------------------------------------------------------------- 1 | # # Write the benchmarking functions here. 2 | # # See "Writing benchmarks" in the asv docs for more information. 3 | 4 | 5 | # class TimeSuite: 6 | # """ 7 | # An example benchmark that times the performance of various kinds 8 | # of iterating over dictionaries in Python. 9 | # """ 10 | # def setup(self): 11 | # self.d = {} 12 | # for x in range(500): 13 | # self.d[x] = None 14 | 15 | # def time_keys(self): 16 | # for key in self.d.keys(): 17 | # pass 18 | 19 | # def time_iterkeys(self): 20 | # for key in self.d.iterkeys(): 21 | # pass 22 | 23 | # def time_range(self): 24 | # d = self.d 25 | # for key in range(500): 26 | # x = d[key] 27 | 28 | # def time_xrange(self): 29 | # d = self.d 30 | # for key in xrange(500): 31 | # x = d[key] 32 | 33 | 34 | # class MemSuite: 35 | # def mem_list(self): 36 | # return [0] * 256 37 | -------------------------------------------------------------------------------- /django-asv/benchmarks/data_struct_benchmarks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/data_struct_benchmarks/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/data_struct_benchmarks/multi_value_dict/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/data_struct_benchmarks/multi_value_dict/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/data_struct_benchmarks/multi_value_dict/benchmark.py: -------------------------------------------------------------------------------- 1 | import copy 2 | 3 | from django.utils.datastructures import MultiValueDict 4 | 5 | from ...utils import bench_setup 6 | 7 | 8 | class MultiValueDictBench: 9 | def setup(self): 10 | bench_setup() 11 | self.case = {"a": ["a"], "b": ["a", "b"], "c": ["a", "b", "c"]} 12 | self.update = {"a": ["a"], "b": ["a", "b"], "c": ["a", "b", "c"]} 13 | 14 | def time_multi_value_dict(self): 15 | for i in range(1000): 16 | case_dict = MultiValueDict(self.case) 17 | 18 | case_dict["a"] 19 | case_dict["b"] 20 | case_dict["c"] 21 | 22 | case_dict.update(self.update) 23 | copy.copy(case_dict) 24 | copy.deepcopy(case_dict) 25 | 26 | case_dict.items() 27 | case_dict.lists() 28 | for i in case_dict: 29 | i 30 | 31 | case_dict["a"] = "A" 32 | case_dict["b"] = "B" 33 | case_dict["c"] = "C" 34 | -------------------------------------------------------------------------------- /django-asv/benchmarks/form_benchmarks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/form_benchmarks/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/form_benchmarks/form_clean/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/form_benchmarks/form_clean/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/form_benchmarks/form_clean/benchmark.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | 3 | from ...utils import bench_setup 4 | 5 | 6 | class BookForm(forms.Form): 7 | title = forms.CharField(max_length=100) 8 | form = None 9 | 10 | 11 | class FormClean: 12 | def setup(self): 13 | bench_setup() 14 | self.form_clean = BookForm({"title": "hi"}) 15 | 16 | def time_form_clean(self): 17 | self.form_clean.full_clean() 18 | self.form_clean.full_clean() 19 | self.form_clean.full_clean() 20 | self.form_clean.full_clean() 21 | self.form_clean.full_clean() 22 | self.form_clean.full_clean() 23 | self.form_clean.full_clean() 24 | self.form_clean.full_clean() 25 | self.form_clean.full_clean() 26 | -------------------------------------------------------------------------------- /django-asv/benchmarks/form_benchmarks/form_create/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/form_benchmarks/form_create/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/form_benchmarks/form_create/benchmark.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | 3 | from ...utils import bench_setup 4 | 5 | 6 | class BookForm(forms.Form): 7 | title = forms.CharField(max_length=100) 8 | form = None 9 | 10 | 11 | class FormCreate: 12 | def setup(self): 13 | bench_setup() 14 | 15 | def time_form_create(self): 16 | BookForm({"title": "a"}) 17 | BookForm({"title": "a"}) 18 | BookForm({"title": "a"}) 19 | BookForm({"title": "a"}) 20 | BookForm({"title": "a"}) 21 | BookForm({"title": "a"}) 22 | BookForm({"title": "a"}) 23 | BookForm({"title": "a"}) 24 | BookForm({"title": "a"}) 25 | BookForm({"title": "a"}) 26 | -------------------------------------------------------------------------------- /django-asv/benchmarks/form_benchmarks/form_render/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/form_benchmarks/form_render/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/form_benchmarks/form_render/benchmark.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | 3 | from ...utils import bench_setup 4 | 5 | 6 | class BookForm(forms.Form): 7 | title = forms.CharField(max_length=100) 8 | form = None 9 | 10 | 11 | class BookFormLarge(forms.Form): 12 | title0 = forms.CharField(max_length=100) 13 | title1 = forms.CharField(max_length=100) 14 | title2 = forms.CharField(max_length=100) 15 | title3 = forms.CharField(max_length=100) 16 | title4 = forms.CharField(max_length=100) 17 | title5 = forms.CharField(max_length=100) 18 | title6 = forms.CharField(max_length=100) 19 | title7 = forms.CharField(max_length=100) 20 | title8 = forms.CharField(max_length=100) 21 | title9 = forms.CharField(max_length=100) 22 | 23 | 24 | class FormRender: 25 | def setup(self): 26 | bench_setup() 27 | self.form_render_small = BookForm() 28 | self.form_render_large = BookFormLarge() 29 | 30 | def time_small_form_render(self): 31 | str(self.form_render_small) 32 | str(self.form_render_small) 33 | str(self.form_render_small) 34 | str(self.form_render_small) 35 | str(self.form_render_small) 36 | str(self.form_render_small) 37 | str(self.form_render_small) 38 | str(self.form_render_small) 39 | str(self.form_render_small) 40 | str(self.form_render_small) 41 | 42 | def time_large_form_render(self): 43 | str(self.form_render_large) 44 | str(self.form_render_large) 45 | str(self.form_render_large) 46 | str(self.form_render_large) 47 | str(self.form_render_large) 48 | str(self.form_render_large) 49 | str(self.form_render_large) 50 | str(self.form_render_large) 51 | str(self.form_render_large) 52 | str(self.form_render_large) 53 | -------------------------------------------------------------------------------- /django-asv/benchmarks/form_benchmarks/form_validate/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/form_benchmarks/form_validate/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/form_benchmarks/form_validate/benchmark.py: -------------------------------------------------------------------------------- 1 | from django.core.exceptions import ValidationError 2 | 3 | from django import forms 4 | 5 | from ...utils import bench_setup 6 | 7 | 8 | def form_validator(title): 9 | if title != "hi": 10 | raise ValidationError("title is not hi") 11 | 12 | 13 | class BookForm(forms.Form): 14 | title = forms.CharField(max_length=100, validators=[form_validator]) 15 | 16 | 17 | class FormValidate: 18 | def setup(self): 19 | bench_setup() 20 | self.form = BookForm({"title": "hi"}) 21 | self.invalid_form = BookForm({"title": "abc"}) 22 | 23 | def time_form_validate(self): 24 | self.form.is_valid() 25 | 26 | def time_form_invalid(self): 27 | self.invalid_form.is_valid() 28 | -------------------------------------------------------------------------------- /django-asv/benchmarks/form_benchmarks/select_date_widget/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/form_benchmarks/select_date_widget/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/form_benchmarks/select_date_widget/benchmark.py: -------------------------------------------------------------------------------- 1 | from django.forms.widgets import SelectDateWidget 2 | 3 | from ...utils import bench_setup 4 | 5 | 6 | class DateWidget: 7 | def setup(self): 8 | bench_setup() 9 | self.widget = SelectDateWidget(years=(2020,)) 10 | 11 | def time_selectdatewidget(self): 12 | self.widget.get_context("widget", "2020-10-10", {}) 13 | self.widget.get_context("widget", "2020-10-10", {}) 14 | self.widget.get_context("widget", "2020-10-10", {}) 15 | self.widget.get_context("widget", "2020-10-10", {}) 16 | self.widget.get_context("widget", "2020-10-10", {}) 17 | self.widget.get_context("widget", "2020-10-10", {}) 18 | self.widget.get_context("widget", "2020-10-10", {}) 19 | -------------------------------------------------------------------------------- /django-asv/benchmarks/model_benchmarks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/model_benchmarks/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/model_benchmarks/model_create/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/model_benchmarks/model_create/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/model_benchmarks/model_create/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import Book 3 | 4 | 5 | class ModelCreate: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | 9 | def time_model_creation(self): 10 | Book.objects.create(title="hi") 11 | Book.objects.create(title="Bye!") 12 | Book.objects.create(title="hi") 13 | Book.objects.create(title="Bye") 14 | -------------------------------------------------------------------------------- /django-asv/benchmarks/model_benchmarks/model_create/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class Book(models.Model): 9 | title = models.CharField(max_length=100) 10 | -------------------------------------------------------------------------------- /django-asv/benchmarks/model_benchmarks/model_delete/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/model_benchmarks/model_delete/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/model_benchmarks/model_delete/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import Book 3 | 4 | 5 | class ModelDelete: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | for i in range(10): 9 | Book.objects.create(title=f"foobar{i}") 10 | 11 | def time_delete(self): 12 | for i in range(10): 13 | Book.objects.filter(title=f"foobar{i}").delete() 14 | -------------------------------------------------------------------------------- /django-asv/benchmarks/model_benchmarks/model_delete/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class Book(models.Model): 9 | title = models.CharField(max_length=100) 10 | -------------------------------------------------------------------------------- /django-asv/benchmarks/model_benchmarks/model_save_existing/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/model_benchmarks/model_save_existing/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/model_benchmarks/model_save_existing/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import Book 3 | 4 | 5 | class SaveExisting: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | Book.objects.create(id=1, title="Foo") 9 | 10 | def teardown(self): 11 | Book.objects.all().delete() 12 | 13 | def time_save_existing(self): 14 | b = Book.objects.get(id=1) 15 | for i in range(0, 30): 16 | b.save() 17 | -------------------------------------------------------------------------------- /django-asv/benchmarks/model_benchmarks/model_save_existing/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class Book(models.Model): 9 | id = models.IntegerField(primary_key=True) 10 | title = models.CharField(max_length=100) 11 | -------------------------------------------------------------------------------- /django-asv/benchmarks/model_benchmarks/model_save_new/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/model_benchmarks/model_save_new/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/model_benchmarks/model_save_new/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import Book 3 | 4 | 5 | class SaveNew: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | 9 | def time_save_new(self): 10 | for i in range(0, 30): 11 | b = Book(id=i, title="Foo") 12 | b.save() 13 | -------------------------------------------------------------------------------- /django-asv/benchmarks/model_benchmarks/model_save_new/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class Book(models.Model): 9 | id = models.IntegerField(primary_key=True) 10 | title = models.CharField(max_length=100) 11 | -------------------------------------------------------------------------------- /django-asv/benchmarks/models.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from django.db import models 4 | 5 | import django 6 | 7 | try: 8 | os.environ["DJANGO_SETTINGS_MODULE"] = "benchmarks.settings" 9 | django.setup() 10 | except RuntimeError: 11 | pass 12 | 13 | 14 | class Book(models.Model): 15 | title = models.CharField(max_length=100) 16 | author = models.ForeignKey("Author", on_delete=models.CASCADE, null=True) 17 | 18 | 19 | class Author(models.Model): 20 | author = models.CharField(max_length=100) 21 | -------------------------------------------------------------------------------- /django-asv/benchmarks/other_benchmarks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/other_benchmarks/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/other_benchmarks/raw_sql/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/other_benchmarks/raw_sql/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/other_benchmarks/raw_sql/benchmark.py: -------------------------------------------------------------------------------- 1 | from django.db import connection 2 | 3 | from ...utils import bench_setup 4 | from .models import OneField 5 | 6 | 7 | class RawSql: 8 | def setup(self): 9 | bench_setup(migrate=True) 10 | for i in range(0, 10): 11 | OneField(field1=i).save() 12 | 13 | def time_raw_sql(self): 14 | for i in range(10): 15 | cursor = connection.cursor() 16 | cursor.execute("select field1 from raw_sql_onefield") 17 | list(cursor.fetchall()) 18 | -------------------------------------------------------------------------------- /django-asv/benchmarks/other_benchmarks/raw_sql/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class OneField(models.Model): 9 | field1 = models.CharField(max_length=100) 10 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_aggregate/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/query_aggregate/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_aggregate/benchmark.py: -------------------------------------------------------------------------------- 1 | from django.db.models import Count 2 | 3 | from ...utils import bench_setup 4 | from .models import Book 5 | 6 | 7 | class QueryAggr: 8 | def setup(self): 9 | bench_setup(migrate=True) 10 | 11 | def time_aggregate(self): 12 | Book.objects.all().aggregate(Count("title")) 13 | Book.objects.all().aggregate(Count("title")) 14 | Book.objects.all().aggregate(Count("title")) 15 | 16 | Book.objects.all().aggregate(Count("id")) 17 | Book.objects.all().aggregate(Count("id")) 18 | Book.objects.all().aggregate(Count("id")) 19 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_aggregate/fixtures/initial_data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "model": "query_aggregate.book", 4 | "pk": 1, 5 | "fields": { 6 | "title": "a" 7 | } 8 | }, 9 | { 10 | "model": "query_aggregate.book", 11 | "pk": 2, 12 | "fields": { 13 | "title": "b" 14 | } 15 | }, 16 | { 17 | "model": "query_aggregate.book", 18 | "pk": 3, 19 | "fields": { 20 | "title": "c" 21 | } 22 | }, 23 | { 24 | "model": "query_aggregate.book", 25 | "pk": 4, 26 | "fields": { 27 | "title": "d" 28 | } 29 | }, 30 | { 31 | "model": "query_aggregate.book", 32 | "pk": 5, 33 | "fields": { 34 | "title": "e" 35 | } 36 | }, 37 | { 38 | "model": "query_aggregate.book", 39 | "pk": 6, 40 | "fields": { 41 | "title": "f" 42 | } 43 | }, 44 | { 45 | "model": "query_aggregate.book", 46 | "pk": 7, 47 | "fields": { 48 | "title": "g" 49 | } 50 | }, 51 | { 52 | "model": "query_aggregate.book", 53 | "pk": 8, 54 | "fields": { 55 | "title": "h" 56 | } 57 | }, 58 | { 59 | "model": "query_aggregate.book", 60 | "pk": 9, 61 | "fields": { 62 | "title": "i" 63 | } 64 | }, 65 | { 66 | "model": "query_aggregate.book", 67 | "pk": 10, 68 | "fields": { 69 | "title": "j" 70 | } 71 | } 72 | ] 73 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_aggregate/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class Book(models.Model): 9 | title = models.CharField(max_length=100) 10 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_all/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/query_all/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_all/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import Book 3 | 4 | 5 | class QueryAll: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | for i in range(3000): 9 | Book(pk=i, title=f"foobar_{i}").save() 10 | 11 | def teardown(self): 12 | Book.objects.all().delete() 13 | 14 | def time_query_all(self): 15 | list(Book.objects.iterator()) 16 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_all/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class Book(models.Model): 9 | title = models.CharField(max_length=100) 10 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_all_conv/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/query_all_conv/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_all_conv/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import Converters 3 | 4 | 5 | class QueryAllConv: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | for i in range(100): 9 | Converters().save() 10 | 11 | def time_query_all_conv(self): 12 | list(Converters.objects.iterator()) 13 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_all_conv/models.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | from django.db import models 4 | 5 | from ...utils import bench_setup 6 | 7 | bench_setup() 8 | 9 | 10 | class Converters(models.Model): 11 | """Both these fields have converters for sqlite""" 12 | 13 | date = models.DateField(default=datetime.date.today) 14 | decimal = models.DecimalField(default=0, max_digits=4, decimal_places=2) 15 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_annotate/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/query_annotate/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_annotate/benchmark.py: -------------------------------------------------------------------------------- 1 | from django.db.models import Count 2 | 3 | from ...utils import bench_setup 4 | from .models import Book 5 | 6 | 7 | class QueryAnnotate: 8 | def setup(self): 9 | bench_setup(migrate=True) 10 | 11 | def time_annotate(self): 12 | list(Book.objects.values("title").annotate(books_total=Count("id"))) 13 | list(Book.objects.values("title").annotate(books_total=Count("id"))) 14 | list(Book.objects.values("title").annotate(books_total=Count("id"))) 15 | list(Book.objects.values("title").annotate(books_total=Count("id"))) 16 | list(Book.objects.values("title").annotate(books_total=Count("id"))) 17 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_annotate/fixtures/initial_data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "model": "query_annotate.book", 4 | "pk": 1, 5 | "fields": { 6 | "title": "a" 7 | } 8 | }, 9 | { 10 | "model": "query_annotate.book", 11 | "pk": 2, 12 | "fields": { 13 | "title": "b" 14 | } 15 | }, 16 | { 17 | "model": "query_annotate.book", 18 | "pk": 3, 19 | "fields": { 20 | "title": "c" 21 | } 22 | }, 23 | { 24 | "model": "query_annotate.book", 25 | "pk": 4, 26 | "fields": { 27 | "title": "d" 28 | } 29 | }, 30 | { 31 | "model": "query_annotate.book", 32 | "pk": 5, 33 | "fields": { 34 | "title": "e" 35 | } 36 | }, 37 | { 38 | "model": "query_annotate.book", 39 | "pk": 6, 40 | "fields": { 41 | "title": "f" 42 | } 43 | }, 44 | { 45 | "model": "query_annotate.book", 46 | "pk": 7, 47 | "fields": { 48 | "title": "g" 49 | } 50 | }, 51 | { 52 | "model": "query_annotate.book", 53 | "pk": 8, 54 | "fields": { 55 | "title": "h" 56 | } 57 | }, 58 | { 59 | "model": "query_annotate.book", 60 | "pk": 9, 61 | "fields": { 62 | "title": "i" 63 | } 64 | }, 65 | { 66 | "model": "query_annotate.book", 67 | "pk": 10, 68 | "fields": { 69 | "title": "j" 70 | } 71 | } 72 | ] 73 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_annotate/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class Book(models.Model): 9 | title = models.CharField(max_length=100) 10 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_complex_filter/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/query_complex_filter/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_complex_filter/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import Book 3 | 4 | 5 | class QueryCmplxFilter: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | 9 | def time_query_complex_filter(self): 10 | Book.objects.complex_filter({"pk": 1}) 11 | Book.objects.complex_filter({"pk": 2}) 12 | Book.objects.complex_filter({"pk": 3}) 13 | Book.objects.complex_filter({"pk": 4}) 14 | Book.objects.complex_filter({"pk": 5}) 15 | Book.objects.complex_filter({"pk": 6}) 16 | Book.objects.complex_filter({"pk": 7}) 17 | Book.objects.complex_filter({"pk": 8}) 18 | Book.objects.complex_filter({"pk": 9}) 19 | Book.objects.complex_filter({"pk": 10}) 20 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_complex_filter/fixtures/initial_data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "model": "query_complex_filter.book", 4 | "pk": 1, 5 | "fields": { 6 | "title": "a" 7 | } 8 | }, 9 | { 10 | "model": "query_complex_filter.book", 11 | "pk": 2, 12 | "fields": { 13 | "title": "b" 14 | } 15 | }, 16 | { 17 | "model": "query_complex_filter.book", 18 | "pk": 3, 19 | "fields": { 20 | "title": "c" 21 | } 22 | }, 23 | { 24 | "model": "query_complex_filter.book", 25 | "pk": 4, 26 | "fields": { 27 | "title": "d" 28 | } 29 | }, 30 | { 31 | "model": "query_complex_filter.book", 32 | "pk": 5, 33 | "fields": { 34 | "title": "e" 35 | } 36 | }, 37 | { 38 | "model": "query_complex_filter.book", 39 | "pk": 6, 40 | "fields": { 41 | "title": "f" 42 | } 43 | }, 44 | { 45 | "model": "query_complex_filter.book", 46 | "pk": 7, 47 | "fields": { 48 | "title": "g" 49 | } 50 | }, 51 | { 52 | "model": "query_complex_filter.book", 53 | "pk": 8, 54 | "fields": { 55 | "title": "h" 56 | } 57 | }, 58 | { 59 | "model": "query_complex_filter.book", 60 | "pk": 9, 61 | "fields": { 62 | "title": "i" 63 | } 64 | }, 65 | { 66 | "model": "query_complex_filter.book", 67 | "pk": 10, 68 | "fields": { 69 | "title": "j" 70 | } 71 | } 72 | ] 73 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_complex_filter/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class Book(models.Model): 9 | title = models.CharField(max_length=100) 10 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_count/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/query_count/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_count/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import Book 3 | 4 | 5 | class QueryCount: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | for i in range(10): 9 | Book(pk=i, title=f"foobar_{i}").save() 10 | 11 | def teardown(self): 12 | Book.objects.all().delete() 13 | 14 | def time_query_count(self): 15 | Book.objects.count() 16 | Book.objects.count() 17 | Book.objects.count() 18 | Book.objects.count() 19 | Book.objects.count() 20 | Book.objects.count() 21 | Book.objects.count() 22 | Book.objects.count() 23 | Book.objects.count() 24 | Book.objects.count() 25 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_count/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class Book(models.Model): 9 | title = models.CharField(max_length=100) 10 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_dates/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/query_dates/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_dates/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import Book 3 | 4 | 5 | class QueryDates: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | 9 | def time_query_dates(self): 10 | list(Book.objects.dates("created_date", "year", "ASC")) 11 | list(Book.objects.dates("created_date", "year", "DESC")) 12 | list(Book.objects.dates("created_date", "month", "ASC")) 13 | list(Book.objects.dates("created_date", "month", "DESC")) 14 | list(Book.objects.dates("created_date", "day", "ASC")) 15 | list(Book.objects.dates("created_date", "day", "DESC")) 16 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_dates/models.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | from django.db import models 4 | 5 | from ...utils import bench_setup 6 | 7 | bench_setup() 8 | 9 | 10 | class Book(models.Model): 11 | title = models.CharField(max_length=100) 12 | created_date = models.DateTimeField(default=datetime.datetime.now()) 13 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_delete/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/query_delete/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_delete/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import Book 3 | 4 | 5 | class QueryDelete: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | for i in range(10): 9 | Book(pk=i, title=f"foobar_{i}").save() 10 | 11 | def time_query_delete(self): 12 | Book.objects.all().delete() 13 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_delete/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class Book(models.Model): 9 | title = models.CharField(max_length=100) 10 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_delete_related/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/query_delete_related/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_delete_related/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import Artist, Song 3 | 4 | 5 | class QueryDeleteRel: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | self.a1 = Artist.objects.create(name="abc") 9 | self.a2 = Artist.objects.create(name="abc") 10 | self.a3 = Artist.objects.create(name="abc") 11 | self.a4 = Artist.objects.create(name="abc") 12 | self.a5 = Artist.objects.create(name="abc") 13 | self.a6 = Artist.objects.create(name="abc") 14 | self.a7 = Artist.objects.create(name="abc") 15 | self.a8 = Artist.objects.create(name="abc") 16 | self.a9 = Artist.objects.create(name="abc") 17 | self.a10 = Artist.objects.create(name="abc") 18 | for i in range(10): 19 | Song.objects.create(artist=self.a1, name=f"song{i}") 20 | Song.objects.create(artist=self.a2, name=f"song{i}") 21 | Song.objects.create(artist=self.a3, name=f"song{i}") 22 | Song.objects.create(artist=self.a4, name=f"song{i}") 23 | Song.objects.create(artist=self.a5, name=f"song{i}") 24 | Song.objects.create(artist=self.a6, name=f"song{i}") 25 | Song.objects.create(artist=self.a7, name=f"song{i}") 26 | Song.objects.create(artist=self.a8, name=f"song{i}") 27 | Song.objects.create(artist=self.a9, name=f"song{i}") 28 | Song.objects.create(artist=self.a10, name=f"song{i}") 29 | 30 | def time_query_del_rel(self): 31 | Artist.objects.all().delete() 32 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_delete_related/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class Artist(models.Model): 9 | name = models.CharField(max_length=100) 10 | 11 | 12 | class Song(models.Model): 13 | artist = models.ForeignKey(Artist, on_delete=models.CASCADE) 14 | name = models.CharField(max_length=100) 15 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_distinct/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/query_distinct/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_distinct/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import Book 3 | 4 | 5 | class QueryDistinct: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | 9 | def time_query_distinct(self): 10 | list(Book.objects.distinct()) 11 | list(Book.objects.distinct()) 12 | list(Book.objects.distinct()) 13 | list(Book.objects.distinct()) 14 | list(Book.objects.distinct()) 15 | list(Book.objects.distinct()) 16 | list(Book.objects.distinct()) 17 | list(Book.objects.distinct()) 18 | list(Book.objects.distinct()) 19 | list(Book.objects.distinct()) 20 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_distinct/fixtures/initial_data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "model": "query_distinct.book", 4 | "pk": 1, 5 | "fields": { 6 | "title": "a" 7 | } 8 | }, 9 | { 10 | "model": "query_distinct.book", 11 | "pk": 2, 12 | "fields": { 13 | "title": "b" 14 | } 15 | }, 16 | { 17 | "model": "query_distinct.book", 18 | "pk": 3, 19 | "fields": { 20 | "title": "c" 21 | } 22 | }, 23 | { 24 | "model": "query_distinct.book", 25 | "pk": 4, 26 | "fields": { 27 | "title": "d" 28 | } 29 | }, 30 | { 31 | "model": "query_distinct.book", 32 | "pk": 5, 33 | "fields": { 34 | "title": "e" 35 | } 36 | }, 37 | { 38 | "model": "query_distinct.book", 39 | "pk": 6, 40 | "fields": { 41 | "title": "f" 42 | } 43 | }, 44 | { 45 | "model": "query_distinct.book", 46 | "pk": 7, 47 | "fields": { 48 | "title": "g" 49 | } 50 | }, 51 | { 52 | "model": "query_distinct.book", 53 | "pk": 8, 54 | "fields": { 55 | "title": "h" 56 | } 57 | }, 58 | { 59 | "model": "query_distinct.book", 60 | "pk": 9, 61 | "fields": { 62 | "title": "i" 63 | } 64 | }, 65 | { 66 | "model": "query_distinct.book", 67 | "pk": 10, 68 | "fields": { 69 | "title": "j" 70 | } 71 | } 72 | ] 73 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_distinct/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class Book(models.Model): 9 | title = models.CharField(max_length=100) 10 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_exclude/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/query_exclude/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_exclude/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import Book 3 | 4 | 5 | class QueryExclude: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | 9 | def time_query_exclude(self): 10 | list(Book.objects.exclude(id=1)) 11 | list(Book.objects.exclude(id=2)) 12 | list(Book.objects.exclude(id=3)) 13 | list(Book.objects.exclude(id=4)) 14 | list(Book.objects.exclude(id=5)) 15 | list(Book.objects.exclude(id=6)) 16 | list(Book.objects.exclude(id=7)) 17 | list(Book.objects.exclude(id=8)) 18 | list(Book.objects.exclude(id=9)) 19 | list(Book.objects.exclude(id=10)) 20 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_exclude/fixtures/initial_data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "model": "query_exclude.book", 4 | "pk": 1, 5 | "fields": { 6 | "title": "a" 7 | } 8 | }, 9 | { 10 | "model": "query_exclude.book", 11 | "pk": 2, 12 | "fields": { 13 | "title": "b" 14 | } 15 | }, 16 | { 17 | "model": "query_exclude.book", 18 | "pk": 3, 19 | "fields": { 20 | "title": "c" 21 | } 22 | }, 23 | { 24 | "model": "query_exclude.book", 25 | "pk": 4, 26 | "fields": { 27 | "title": "d" 28 | } 29 | }, 30 | { 31 | "model": "query_exclude.book", 32 | "pk": 5, 33 | "fields": { 34 | "title": "e" 35 | } 36 | }, 37 | { 38 | "model": "query_exclude.book", 39 | "pk": 6, 40 | "fields": { 41 | "title": "f" 42 | } 43 | }, 44 | { 45 | "model": "query_exclude.book", 46 | "pk": 7, 47 | "fields": { 48 | "title": "g" 49 | } 50 | }, 51 | { 52 | "model": "query_exclude.book", 53 | "pk": 8, 54 | "fields": { 55 | "title": "h" 56 | } 57 | }, 58 | { 59 | "model": "query_exclude.book", 60 | "pk": 9, 61 | "fields": { 62 | "title": "i" 63 | } 64 | }, 65 | { 66 | "model": "query_exclude.book", 67 | "pk": 10, 68 | "fields": { 69 | "title": "j" 70 | } 71 | } 72 | ] 73 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_exclude/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class Book(models.Model): 9 | title = models.CharField(max_length=100) 10 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_exists/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/query_exists/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_exists/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import Book 3 | 4 | 5 | class QueryExists: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | 9 | def time_query_exists(self): 10 | # Checking for object that exists 11 | Book.objects.filter(id=1).exists() 12 | Book.objects.filter(id=2).exists() 13 | Book.objects.filter(id=3).exists() 14 | Book.objects.filter(id=4).exists() 15 | Book.objects.filter(id=5).exists() 16 | 17 | # Checking for object that does not exist 18 | Book.objects.filter(id=11).exists() 19 | Book.objects.filter(id=12).exists() 20 | Book.objects.filter(id=13).exists() 21 | Book.objects.filter(id=14).exists() 22 | Book.objects.filter(id=15).exists() 23 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_exists/fixtures/initial_data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "model": "query_exists.book", 4 | "pk": 1, 5 | "fields": { 6 | "title": "a" 7 | } 8 | }, 9 | { 10 | "model": "query_exists.book", 11 | "pk": 2, 12 | "fields": { 13 | "title": "b" 14 | } 15 | }, 16 | { 17 | "model": "query_exists.book", 18 | "pk": 3, 19 | "fields": { 20 | "title": "c" 21 | } 22 | }, 23 | { 24 | "model": "query_exists.book", 25 | "pk": 4, 26 | "fields": { 27 | "title": "d" 28 | } 29 | }, 30 | { 31 | "model": "query_exists.book", 32 | "pk": 5, 33 | "fields": { 34 | "title": "e" 35 | } 36 | }, 37 | { 38 | "model": "query_exists.book", 39 | "pk": 6, 40 | "fields": { 41 | "title": "f" 42 | } 43 | }, 44 | { 45 | "model": "query_exists.book", 46 | "pk": 7, 47 | "fields": { 48 | "title": "g" 49 | } 50 | }, 51 | { 52 | "model": "query_exists.book", 53 | "pk": 8, 54 | "fields": { 55 | "title": "h" 56 | } 57 | }, 58 | { 59 | "model": "query_exists.book", 60 | "pk": 9, 61 | "fields": { 62 | "title": "i" 63 | } 64 | }, 65 | { 66 | "model": "query_exists.book", 67 | "pk": 10, 68 | "fields": { 69 | "title": "j" 70 | } 71 | } 72 | ] 73 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_exists/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class Book(models.Model): 9 | title = models.CharField(max_length=100) 10 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_filter/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/query_filter/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_filter/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import Book 3 | 4 | 5 | class QueryFilter: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | 9 | def time_query_filter(self): 10 | list(Book.objects.filter(id=1)) 11 | list(Book.objects.filter(id=2)) 12 | list(Book.objects.filter(id=3)) 13 | list(Book.objects.filter(id=4)) 14 | list(Book.objects.filter(id=5)) 15 | list(Book.objects.filter(id=6)) 16 | list(Book.objects.filter(id=7)) 17 | list(Book.objects.filter(id=8)) 18 | list(Book.objects.filter(id=9)) 19 | list(Book.objects.filter(id=10)) 20 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_filter/fixtures/initial_data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "model": "query_filter.book", 4 | "pk": 1, 5 | "fields": { 6 | "title": "a" 7 | } 8 | }, 9 | { 10 | "model": "query_filter.book", 11 | "pk": 2, 12 | "fields": { 13 | "title": "b" 14 | } 15 | }, 16 | { 17 | "model": "query_filter.book", 18 | "pk": 3, 19 | "fields": { 20 | "title": "c" 21 | } 22 | }, 23 | { 24 | "model": "query_filter.book", 25 | "pk": 4, 26 | "fields": { 27 | "title": "d" 28 | } 29 | }, 30 | { 31 | "model": "query_filter.book", 32 | "pk": 5, 33 | "fields": { 34 | "title": "e" 35 | } 36 | }, 37 | { 38 | "model": "query_filter.book", 39 | "pk": 6, 40 | "fields": { 41 | "title": "f" 42 | } 43 | }, 44 | { 45 | "model": "query_filter.book", 46 | "pk": 7, 47 | "fields": { 48 | "title": "g" 49 | } 50 | }, 51 | { 52 | "model": "query_filter.book", 53 | "pk": 8, 54 | "fields": { 55 | "title": "h" 56 | } 57 | }, 58 | { 59 | "model": "query_filter.book", 60 | "pk": 9, 61 | "fields": { 62 | "title": "i" 63 | } 64 | }, 65 | { 66 | "model": "query_filter.book", 67 | "pk": 10, 68 | "fields": { 69 | "title": "j" 70 | } 71 | } 72 | ] 73 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_filter/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class Book(models.Model): 9 | title = models.CharField(max_length=100) 10 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_get/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/query_get/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_get/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import Book 3 | 4 | 5 | class QueryGet: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | for i in range(10): 9 | Book(pk=i, title=f"foobar_{i}").save() 10 | 11 | def teardown(self): 12 | Book.objects.all().delete() 13 | 14 | def time_query_get(self): 15 | for i in range(10): 16 | # This will succeed 17 | Book.objects.get(id=1) 18 | try: 19 | # This will fail, due to too many objects 20 | Book.objects.get() 21 | except Book.MultipleObjectsReturned: 22 | pass 23 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_get/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class Book(models.Model): 9 | title = models.CharField(max_length=100) 10 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_get_or_create/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/query_get_or_create/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_get_or_create/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import Book 3 | 4 | 5 | class QueryGetOrCreate: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | self.next_id = Book.objects.count() + 1 9 | 10 | def teardown(self): 11 | Book.objects.all().delete() 12 | 13 | def time_query_get_or_create(self): 14 | # This will do a create ... 15 | Book.objects.get_or_create(id=self.next_id, defaults={"title": "hi"}) 16 | Book.objects.get_or_create(id=self.next_id + 1, defaults={"title": "hi"}) 17 | Book.objects.get_or_create(id=self.next_id + 2, defaults={"title": "hi"}) 18 | 19 | # ... and this a get. 20 | Book.objects.get_or_create(id=self.next_id, defaults={"title": "hi"}) 21 | Book.objects.get_or_create(id=self.next_id + 1, defaults={"title": "hi"}) 22 | Book.objects.get_or_create(id=self.next_id + 2, defaults={"title": "hi"}) 23 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_get_or_create/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class Book(models.Model): 9 | title = models.CharField(max_length=100) 10 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_in_bulk/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/query_in_bulk/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_in_bulk/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import Book 3 | 4 | 5 | class QueryInBulk: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | 9 | def time_query_in_bulk(self): 10 | Book.objects.in_bulk([1]) 11 | Book.objects.in_bulk([1, 2]) 12 | Book.objects.in_bulk([1, 2, 3]) 13 | Book.objects.in_bulk([1, 2, 3, 4]) 14 | Book.objects.in_bulk([1, 2, 3, 4, 5]) 15 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_in_bulk/fixtures/initial_data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "model": "query_in_bulk.book", 4 | "pk": 1, 5 | "fields": { 6 | "title": "a" 7 | } 8 | }, 9 | { 10 | "model": "query_in_bulk.book", 11 | "pk": 2, 12 | "fields": { 13 | "title": "b" 14 | } 15 | }, 16 | { 17 | "model": "query_in_bulk.book", 18 | "pk": 3, 19 | "fields": { 20 | "title": "c" 21 | } 22 | }, 23 | { 24 | "model": "query_in_bulk.book", 25 | "pk": 4, 26 | "fields": { 27 | "title": "d" 28 | } 29 | }, 30 | { 31 | "model": "query_in_bulk.book", 32 | "pk": 5, 33 | "fields": { 34 | "title": "e" 35 | } 36 | }, 37 | { 38 | "model": "query_in_bulk.book", 39 | "pk": 6, 40 | "fields": { 41 | "title": "f" 42 | } 43 | }, 44 | { 45 | "model": "query_in_bulk.book", 46 | "pk": 7, 47 | "fields": { 48 | "title": "g" 49 | } 50 | }, 51 | { 52 | "model": "query_in_bulk.book", 53 | "pk": 8, 54 | "fields": { 55 | "title": "h" 56 | } 57 | }, 58 | { 59 | "model": "query_in_bulk.book", 60 | "pk": 9, 61 | "fields": { 62 | "title": "i" 63 | } 64 | }, 65 | { 66 | "model": "query_in_bulk.book", 67 | "pk": 10, 68 | "fields": { 69 | "title": "j" 70 | } 71 | } 72 | ] 73 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_in_bulk/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class Book(models.Model): 9 | title = models.CharField(max_length=100) 10 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_latest/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/query_latest/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_latest/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import Book 3 | 4 | 5 | class QueryLatest: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | 9 | def time_query_latest(self): 10 | Book.objects.latest() 11 | Book.objects.latest() 12 | Book.objects.latest() 13 | Book.objects.latest() 14 | Book.objects.latest() 15 | Book.objects.latest() 16 | Book.objects.latest() 17 | Book.objects.latest() 18 | Book.objects.latest() 19 | Book.objects.latest() 20 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_latest/fixtures/initial_data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "model": "query_latest.book", 4 | "pk": 1, 5 | "fields": { 6 | "title": "a" 7 | } 8 | }, 9 | { 10 | "model": "query_latest.book", 11 | "pk": 2, 12 | "fields": { 13 | "title": "b" 14 | } 15 | }, 16 | { 17 | "model": "query_latest.book", 18 | "pk": 3, 19 | "fields": { 20 | "title": "c" 21 | } 22 | }, 23 | { 24 | "model": "query_latest.book", 25 | "pk": 4, 26 | "fields": { 27 | "title": "d" 28 | } 29 | }, 30 | { 31 | "model": "query_latest.book", 32 | "pk": 5, 33 | "fields": { 34 | "title": "e" 35 | } 36 | }, 37 | { 38 | "model": "query_latest.book", 39 | "pk": 6, 40 | "fields": { 41 | "title": "f" 42 | } 43 | }, 44 | { 45 | "model": "query_latest.book", 46 | "pk": 7, 47 | "fields": { 48 | "title": "g" 49 | } 50 | }, 51 | { 52 | "model": "query_latest.book", 53 | "pk": 8, 54 | "fields": { 55 | "title": "h" 56 | } 57 | }, 58 | { 59 | "model": "query_latest.book", 60 | "pk": 9, 61 | "fields": { 62 | "title": "i" 63 | } 64 | }, 65 | { 66 | "model": "query_latest.book", 67 | "pk": 10, 68 | "fields": { 69 | "title": "j" 70 | } 71 | } 72 | ] 73 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_latest/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class Book(models.Model): 9 | title = models.CharField(max_length=100) 10 | 11 | class Meta: 12 | get_latest_by = "pk" 13 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_none/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/query_none/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_none/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import Book 3 | 4 | 5 | class QueryNone: 6 | def setup(self): 7 | bench_setup() 8 | 9 | def time_query_none(self): 10 | list(Book.objects.none()) 11 | list(Book.objects.none()) 12 | list(Book.objects.none()) 13 | list(Book.objects.none()) 14 | list(Book.objects.none()) 15 | list(Book.objects.none()) 16 | list(Book.objects.none()) 17 | list(Book.objects.none()) 18 | list(Book.objects.none()) 19 | list(Book.objects.none()) 20 | list(Book.objects.none()) 21 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_none/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class Book(models.Model): 9 | title = models.CharField(max_length=100) 10 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_order_by/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/query_order_by/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_order_by/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import Book 3 | 4 | 5 | class QueryOrderBy: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | 9 | def time_query_order_by(self): 10 | list(Book.objects.order_by("id")) 11 | list(Book.objects.order_by("id")) 12 | list(Book.objects.order_by("id")) 13 | 14 | list(Book.objects.order_by("title")) 15 | list(Book.objects.order_by("title")) 16 | list(Book.objects.order_by("title")) 17 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_order_by/fixtures/initial_data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "model": "query_order_by.book", 4 | "pk": 1, 5 | "fields": { 6 | "title": "a" 7 | } 8 | }, 9 | { 10 | "model": "query_order_by.book", 11 | "pk": 2, 12 | "fields": { 13 | "title": "b" 14 | } 15 | }, 16 | { 17 | "model": "query_order_by.book", 18 | "pk": 3, 19 | "fields": { 20 | "title": "c" 21 | } 22 | }, 23 | { 24 | "model": "query_order_by.book", 25 | "pk": 4, 26 | "fields": { 27 | "title": "d" 28 | } 29 | }, 30 | { 31 | "model": "query_order_by.book", 32 | "pk": 5, 33 | "fields": { 34 | "title": "e" 35 | } 36 | }, 37 | { 38 | "model": "query_order_by.book", 39 | "pk": 6, 40 | "fields": { 41 | "title": "f" 42 | } 43 | }, 44 | { 45 | "model": "query_order_by.book", 46 | "pk": 7, 47 | "fields": { 48 | "title": "g" 49 | } 50 | }, 51 | { 52 | "model": "query_order_by.book", 53 | "pk": 8, 54 | "fields": { 55 | "title": "h" 56 | } 57 | }, 58 | { 59 | "model": "query_order_by.book", 60 | "pk": 9, 61 | "fields": { 62 | "title": "i" 63 | } 64 | }, 65 | { 66 | "model": "query_order_by.book", 67 | "pk": 10, 68 | "fields": { 69 | "title": "j" 70 | } 71 | } 72 | ] 73 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_order_by/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class Book(models.Model): 9 | title = models.CharField(max_length=100) 10 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_prefetch_related/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/query_prefetch_related/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_prefetch_related/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import Author, Book 3 | 4 | 5 | class QueryPrefetch: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | for i in range(20): 9 | a = Author.objects.create(author=f"Author {i}") 10 | books = [Book.objects.create(title=f"Title {j}") for j in range(3)] 11 | a.books.add(*books) 12 | 13 | def time_query_prefetch(self): 14 | for i in range(10): 15 | for a in Author.objects.prefetch_related("books"): 16 | list(a.books.all()) 17 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_prefetch_related/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class Book(models.Model): 9 | title = models.CharField(max_length=100) 10 | 11 | 12 | class Author(models.Model): 13 | author = models.CharField(max_length=100) 14 | books = models.ManyToManyField(Book) 15 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_raw/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/query_raw/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_raw/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import MultiField 3 | 4 | 5 | class QueryRaw: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | for i in range(1000): 9 | kwargs = {f"field{j}": f"foobar_{i}_{j}" for j in range(1, 11)} 10 | MultiField(**kwargs).save() 11 | 12 | def teardown(self): 13 | MultiField.objects.all().delete() 14 | 15 | def time_query_raw(self): 16 | list(MultiField.objects.raw("select * from query_raw_multifield")) 17 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_raw/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class MultiField(models.Model): 9 | field1 = models.CharField(max_length=100) 10 | field2 = models.CharField(max_length=100) 11 | field3 = models.CharField(max_length=100) 12 | field4 = models.CharField(max_length=100) 13 | field5 = models.CharField(max_length=100) 14 | field6 = models.CharField(max_length=100) 15 | field7 = models.CharField(max_length=100) 16 | field8 = models.CharField(max_length=100) 17 | field9 = models.CharField(max_length=100) 18 | field10 = models.CharField(max_length=100) 19 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_raw_deferred/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/query_raw_deferred/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_raw_deferred/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import MultiField 3 | 4 | 5 | class QueryRawDeferred: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | for i in range(1000): 9 | kwargs = {f"field{j}": f"foobar_{i}_{j}" for j in range(1, 11)} 10 | MultiField(**kwargs).save() 11 | 12 | def teardown(self): 13 | MultiField.objects.all().delete() 14 | 15 | def time_query_raw_deferred(self): 16 | list(MultiField.objects.raw("select id from query_raw_deferred_multifield")) 17 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_raw_deferred/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class MultiField(models.Model): 9 | field1 = models.CharField(max_length=100) 10 | field2 = models.CharField(max_length=100) 11 | field3 = models.CharField(max_length=100) 12 | field4 = models.CharField(max_length=100) 13 | field5 = models.CharField(max_length=100) 14 | field6 = models.CharField(max_length=100) 15 | field7 = models.CharField(max_length=100) 16 | field8 = models.CharField(max_length=100) 17 | field9 = models.CharField(max_length=100) 18 | field10 = models.CharField(max_length=100) 19 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_select_related/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/query_select_related/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_select_related/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import Book 3 | 4 | 5 | class QuerySelectRelated: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | 9 | def teardown(self): 10 | Book.objects.all().delete() 11 | 12 | def time_query_select_related(self): 13 | for i in range(10): 14 | list(Book.objects.select_related("author")) 15 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_select_related/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class Author(models.Model): 9 | author = models.CharField(max_length=100) 10 | 11 | 12 | class Book(models.Model): 13 | title = models.CharField(max_length=100) 14 | author = models.ForeignKey("Author", on_delete=models.CASCADE, null=True) 15 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_update/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/query_update/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_update/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import Book 3 | 4 | 5 | class QueryUpdate: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | 9 | def teardown(self): 10 | Book.objects.all().delete() 11 | 12 | def time_query_update(self): 13 | for i in range(1, 11): 14 | Book.objects.all().update(title=f"{i}") 15 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_update/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class Book(models.Model): 9 | title = models.CharField(max_length=100) 10 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_values/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/query_values/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_values/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import Book 3 | 4 | 5 | class QueryValues: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | 9 | def teardown(self): 10 | Book.objects.all().delete() 11 | 12 | def time_query_values(self): 13 | list(Book.objects.values("title")) 14 | list(Book.objects.values("title")) 15 | list(Book.objects.values("title")) 16 | list(Book.objects.values("title")) 17 | list(Book.objects.values("title")) 18 | list(Book.objects.values("title")) 19 | list(Book.objects.values("title")) 20 | list(Book.objects.values("title")) 21 | list(Book.objects.values("title")) 22 | list(Book.objects.values("title")) 23 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_values/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class Book(models.Model): 9 | title = models.CharField(max_length=100) 10 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_values_10000/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/query_values_10000/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_values_10000/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import Book 3 | 4 | 5 | class QueryValues10000: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | Book.objects.bulk_create((Book(title="title") for x in range(10000))) 9 | 10 | def teardown(self): 11 | Book.objects.all().delete() 12 | 13 | def time_query_values_10000(self): 14 | list(Book.objects.values("title")) 15 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_values_10000/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class Book(models.Model): 9 | title = models.CharField(max_length=100) 10 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_values_list/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/query_values_list/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_values_list/benchmark.py: -------------------------------------------------------------------------------- 1 | from ...utils import bench_setup 2 | from .models import Book 3 | 4 | 5 | class QueryValuesList: 6 | def setup(self): 7 | bench_setup(migrate=True) 8 | 9 | def teardown(self): 10 | Book.objects.all().delete() 11 | 12 | def time_query_values_list(self): 13 | list(Book.objects.values_list("title")) 14 | list(Book.objects.values_list("title")) 15 | list(Book.objects.values_list("title")) 16 | list(Book.objects.values_list("title")) 17 | list(Book.objects.values_list("title")) 18 | list(Book.objects.values_list("title")) 19 | list(Book.objects.values_list("title")) 20 | list(Book.objects.values_list("title")) 21 | list(Book.objects.values_list("title")) 22 | list(Book.objects.values_list("title")) 23 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/query_values_list/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from ...utils import bench_setup 4 | 5 | bench_setup() 6 | 7 | 8 | class Book(models.Model): 9 | title = models.CharField(max_length=100) 10 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/queryset_filter_chain/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/query_benchmarks/queryset_filter_chain/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/queryset_filter_chain/benchmark.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | from ...utils import bench_setup 4 | from .models import Book 5 | 6 | 7 | class FilterChain: 8 | def setup(self): 9 | bench_setup(migrate=True) 10 | 11 | def time_filter_chain(self): 12 | Book.objects.filter(title="Talent").filter( 13 | description__icontains="top performers" 14 | ).filter(author_name__startswith="Geoff").filter( 15 | date_created__lt=datetime.datetime(year=2010, month=1, day=1) 16 | ).filter( 17 | date_created__gte=datetime.date(year=2007, month=1, day=1) 18 | ).filter( 19 | date_published=datetime.datetime.now() 20 | ).filter( 21 | enabled=True 22 | ) 23 | -------------------------------------------------------------------------------- /django-asv/benchmarks/query_benchmarks/queryset_filter_chain/models.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | from django.db import models 4 | 5 | from ...utils import bench_setup 6 | 7 | bench_setup() 8 | 9 | 10 | class Book(models.Model): 11 | title = models.CharField(max_length=100) 12 | description = models.TextField() 13 | author_name = models.TextField() 14 | date_created = models.DateTimeField(default=datetime.datetime.now) 15 | date_published = models.DateTimeField() 16 | enabled = models.BooleanField() 17 | -------------------------------------------------------------------------------- /django-asv/benchmarks/req_resp_benchmarks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/req_resp_benchmarks/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/req_resp_benchmarks/default_middleware/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/req_resp_benchmarks/default_middleware/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/req_resp_benchmarks/default_middleware/benchmark.py: -------------------------------------------------------------------------------- 1 | from django.core.handlers.asgi import ASGIHandler 2 | from django.core.handlers.wsgi import WSGIHandler 3 | from django.test import AsyncRequestFactory, RequestFactory 4 | 5 | from ...utils import bench_setup 6 | 7 | 8 | class DefaultMiddleWareBench: 9 | def setup(self): 10 | bench_setup() 11 | self.req_factory = RequestFactory() 12 | self.wsgi_handler = WSGIHandler() 13 | self.wsgi_handler.load_middleware() 14 | 15 | self.async_req_factory = AsyncRequestFactory() 16 | self.asgi_handler = ASGIHandler() 17 | self.asgi_handler.load_middleware() 18 | 19 | def time_wsgi_handler(self): 20 | self.wsgi_handler.get_response(self.req_factory.get("/inx-pg")) 21 | self.wsgi_handler.get_response(self.req_factory.get("/inx-pg")) 22 | self.wsgi_handler.get_response(self.req_factory.get("/inx-pg")) 23 | self.wsgi_handler.get_response(self.req_factory.get("/inx-pg")) 24 | self.wsgi_handler.get_response(self.req_factory.get("/inx-pg")) 25 | 26 | async def time_asgi_handler(self): 27 | await self.asgi_handler.get_response(self.async_req_factory.get("/inx-pg")) 28 | await self.asgi_handler.get_response(self.async_req_factory.get("/inx-pg")) 29 | await self.asgi_handler.get_response(self.async_req_factory.get("/inx-pg")) 30 | await self.asgi_handler.get_response(self.async_req_factory.get("/inx-pg")) 31 | await self.asgi_handler.get_response(self.async_req_factory.get("/inx-pg")) 32 | -------------------------------------------------------------------------------- /django-asv/benchmarks/req_resp_benchmarks/default_middleware/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from .views import index 4 | 5 | urlpatterns = [ 6 | path("inx-pg", index), 7 | ] 8 | -------------------------------------------------------------------------------- /django-asv/benchmarks/req_resp_benchmarks/default_middleware/views.py: -------------------------------------------------------------------------------- 1 | from django.http import HttpResponse 2 | 3 | 4 | def index(request): 5 | return HttpResponse("Hello World!") 6 | -------------------------------------------------------------------------------- /django-asv/benchmarks/req_resp_benchmarks/http_methods/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/req_resp_benchmarks/http_methods/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/req_resp_benchmarks/http_methods/benchmark.py: -------------------------------------------------------------------------------- 1 | from django.test import Client 2 | 3 | from ...utils import bench_setup 4 | 5 | 6 | class HttpMethods: 7 | def setup(self): 8 | bench_setup() 9 | self.client = Client() 10 | 11 | def time_get_method(self): 12 | self.client.get("/get") 13 | self.client.get("/get") 14 | self.client.get("/get") 15 | self.client.get("/get") 16 | self.client.get("/get") 17 | 18 | def time_post_method(self): 19 | self.client.post("/post") 20 | self.client.post("/post") 21 | self.client.post("/post") 22 | self.client.post("/post") 23 | self.client.post("/post") 24 | -------------------------------------------------------------------------------- /django-asv/benchmarks/req_resp_benchmarks/http_methods/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from .views import test_view 4 | 5 | urlpatterns = [path("/get", test_view), path("/post", test_view)] 6 | -------------------------------------------------------------------------------- /django-asv/benchmarks/req_resp_benchmarks/http_methods/views.py: -------------------------------------------------------------------------------- 1 | from django.http import HttpResponse 2 | 3 | 4 | def test_view(request): 5 | if request.method == "GET": 6 | return HttpResponse("GET method") 7 | if request.method == "POST": 8 | return HttpResponse("POST method") 9 | -------------------------------------------------------------------------------- /django-asv/benchmarks/settings.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | ALLOWED_HOSTS = ["*"] 4 | 5 | DATABASE_ENGINE = "sqlite3" 6 | DATABASE_NAME = ":memory:" 7 | 8 | DATABASES = { 9 | "default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}, 10 | } 11 | 12 | INSTALLED_APPS = [ 13 | "django.contrib.auth", 14 | "django.contrib.contenttypes", 15 | "benchmarks", 16 | "benchmarks.template_benchmarks.template_render", 17 | "benchmarks.template_benchmarks.template_compilation", 18 | "benchmarks.query_benchmarks.query_annotate", 19 | "benchmarks.query_benchmarks.query_all_conv", 20 | "benchmarks.query_benchmarks.query_complex_filter", 21 | "benchmarks.query_benchmarks.query_dates", 22 | "benchmarks.query_benchmarks.query_delete_related", 23 | "benchmarks.model_benchmarks.model_create", 24 | "benchmarks.model_benchmarks.model_save_new", 25 | "benchmarks.model_benchmarks.model_save_existing", 26 | "benchmarks.model_benchmarks.model_delete", 27 | "benchmarks.other_benchmarks.raw_sql", 28 | "benchmarks.query_benchmarks.query_distinct", 29 | "benchmarks.url_benchmarks.url_resolve", 30 | "benchmarks.url_benchmarks.url_resolve_flat", 31 | "benchmarks.url_benchmarks.url_resolve_nested", 32 | "benchmarks.url_benchmarks.url_reverse", 33 | "benchmarks.query_benchmarks.query_exclude", 34 | "benchmarks.query_benchmarks.query_exists", 35 | "benchmarks.query_benchmarks.query_filter", 36 | "benchmarks.query_benchmarks.query_in_bulk", 37 | "benchmarks.query_benchmarks.query_latest", 38 | "benchmarks.query_benchmarks.query_order_by", 39 | "benchmarks.query_benchmarks.query_none", 40 | "benchmarks.query_benchmarks.query_prefetch_related", 41 | "benchmarks.query_benchmarks.query_aggregate", 42 | "benchmarks.query_benchmarks.queryset_filter_chain", 43 | "benchmarks.query_benchmarks.query_all", 44 | "benchmarks.query_benchmarks.query_count", 45 | "benchmarks.query_benchmarks.query_delete", 46 | "benchmarks.query_benchmarks.query_get", 47 | "benchmarks.query_benchmarks.query_get_or_create", 48 | "benchmarks.query_benchmarks.query_values_list", 49 | "benchmarks.query_benchmarks.query_values", 50 | "benchmarks.query_benchmarks.query_values_10000", 51 | "benchmarks.query_benchmarks.query_update", 52 | "benchmarks.query_benchmarks.query_raw_deferred", 53 | "benchmarks.query_benchmarks.query_raw", 54 | "benchmarks.query_benchmarks.query_select_related", 55 | "benchmarks.req_resp_benchmarks.default_middleware", 56 | "benchmarks.req_resp_benchmarks.http_methods", 57 | ] 58 | 59 | SECRET_KEY = "NOT REALLY SECRET" 60 | 61 | ROOT_URLCONF = "benchmarks.urls" 62 | 63 | MIDDLEWARE = [] 64 | 65 | TEMPLATE_DIRS = (os.path.abspath(os.path.join(os.path.dirname(__file__), "templates")),) 66 | 67 | TEMPLATES = [ 68 | { 69 | "BACKEND": "django.template.backends.django.DjangoTemplates", 70 | "DIRS": [ 71 | os.path.abspath(os.path.join(os.path.dirname(__file__), "templates")), 72 | ], 73 | "APP_DIRS": True, 74 | "OPTIONS": { 75 | "context_processors": [ 76 | "django.contrib.auth.context_processors.auth", 77 | "django.template.context_processors.debug", 78 | "django.template.context_processors.i18n", 79 | "django.template.context_processors.media", 80 | "django.template.context_processors.static", 81 | "django.template.context_processors.tz", 82 | "django.contrib.messages.context_processors.messages", 83 | ], 84 | }, 85 | }, 86 | ] 87 | -------------------------------------------------------------------------------- /django-asv/benchmarks/template_benchmarks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/template_benchmarks/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/template_benchmarks/template_compilation/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/template_benchmarks/template_compilation/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/template_benchmarks/template_compilation/benchmark.py: -------------------------------------------------------------------------------- 1 | from django import template 2 | 3 | from ...utils import bench_setup 4 | 5 | 6 | class TemplateCompile: 7 | def setup(self): 8 | bench_setup() 9 | 10 | def time_template_compile(self): 11 | template.Template( 12 | """ 13 | {% for v in vals %} 14 | {{ v }} 15 | {{ v }} 16 | {{ v }} 17 | {{ v }} 18 | {{ v }} 19 | {{ v }} 20 | {{ v }} 21 | {{ v }} 22 | {{ v }} 23 | {{ v }} 24 | {{ v }} 25 | {{ v }} 26 | {{ v }} 27 | {{ v }} 28 | {{ v }} 29 | {% endfor %} 30 | """ 31 | ) 32 | -------------------------------------------------------------------------------- /django-asv/benchmarks/template_benchmarks/template_render/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/template_benchmarks/template_render/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/template_benchmarks/template_render/benchmark.py: -------------------------------------------------------------------------------- 1 | from django.http import HttpRequest 2 | from django.shortcuts import render 3 | 4 | from django import VERSION, template 5 | 6 | from ...utils import bench_setup 7 | 8 | 9 | class TemplateRender: 10 | def setup(self): 11 | bench_setup() 12 | self.context = { 13 | "objects1": [object(), object(), object(), object(), object()], 14 | "objects2": [object(), object(), object(), object(), object()], 15 | "object1": object(), 16 | "object2": object(), 17 | "object3": None, 18 | "num1": 1, 19 | "num2": 2, 20 | "boolean1": True, 21 | "SCRIPT_CONTENT_URL": "/some/prefix", 22 | "WEBSITE_DOMAIN": "http://www.somedomain.com", 23 | "SHOW_ALT_HEADER": "True", 24 | "base_template": "base.html", 25 | } 26 | 27 | def time_template_render(self): 28 | if VERSION >= (4, 0): 29 | render(HttpRequest(), "permalink.html", self.context) 30 | else: 31 | render(HttpRequest(), "permalink_django_lte_40.html", self.context) 32 | 33 | def time_render_simple(self): 34 | context = template.Context({"stuff": "something"}) 35 | t = template.Template("{{ stuff }}") 36 | for i in range(10): 37 | t.render(context) 38 | t.render(context) 39 | t.render(context) 40 | t.render(context) 41 | t.render(context) 42 | t.render(context) 43 | t.render(context) 44 | t.render(context) 45 | t.render(context) 46 | t.render(context) 47 | -------------------------------------------------------------------------------- /django-asv/benchmarks/template_benchmarks/template_render/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% spaceless %} 4 | 5 | 6 | {% block fulltitle %}{% block title %}Home{% endblock %}{% endblock %} 7 | 8 | {% block canonical %}{% endblock %} 9 | 10 | {% block meta_robots %} 11 | {% endblock %} 12 | 13 | {% block meta %} 14 | 15 | 16 | {% endblock %} 17 | 18 | 19 | 22 | 25 | 28 | {% block styles %} 29 | {% endblock %} 30 | 31 | {% block feeds %} 32 | {% endblock %} 33 | 34 | 35 | 36 | 44 | {% block scripts %} 45 | {% endblock %} 46 | {% include "somefile.js" %} 47 | 48 | {% endspaceless %} 49 | 50 | 51 | 52 | {% block alt_header %} 53 | {% if SHOW_ALT_HEADER %} 54 | {% include "header.html" %} 55 | {% endif %} 56 | {% endblock %} 57 | 58 | {% block header %} 59 | 73 | {% endblock %} 74 |
75 |
76 | {% if objects1 %} 77 | {% for obj in objects1 %} 78 | {{ object }} 79 |
80 | {% endfor %} 81 | {% endif %} 82 | 83 | {% block content %} 84 |
85 | {% block left_column %} 86 |
87 |
88 | {% endblock %} 89 | 90 | {% block right_column %} 91 |
92 |
93 | {% endblock %} 94 | 95 | {% block content_footer %} 96 | 104 | {% endblock %} 105 |
106 | {% endblock %} 107 |
108 |
109 | 110 | {% block footer %} 111 | {% include "footer.html" %} 112 | {% endblock %} 113 | 114 | {% if object3 %} 115 | 121 | {% endif %} 122 | 123 | {% block inline_js %} 124 | {% endblock %} 125 | 126 | 131 | 132 | 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /django-asv/benchmarks/template_benchmarks/template_render/templates/confirmation_message.html: -------------------------------------------------------------------------------- 1 |

You've been confirmed

2 | {% include "for_loop.html" %} 3 | -------------------------------------------------------------------------------- /django-asv/benchmarks/template_benchmarks/template_render/templates/footer.html: -------------------------------------------------------------------------------- 1 | {% for obj in objects2 %} 2 | {{ obj }} 3 | {% endfor %} 4 | -------------------------------------------------------------------------------- /django-asv/benchmarks/template_benchmarks/template_render/templates/for_loop.html: -------------------------------------------------------------------------------- 1 | {% for obj in objects2 %} 2 | {{ obj }} 3 | {% endfor %} 4 | -------------------------------------------------------------------------------- /django-asv/benchmarks/template_benchmarks/template_render/templates/header.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/template_benchmarks/template_render/templates/header.html -------------------------------------------------------------------------------- /django-asv/benchmarks/template_benchmarks/template_render/templates/permalink.html: -------------------------------------------------------------------------------- 1 | {% extends base_template %} 2 | {% load i18n %}{% load cache %} 3 | 4 | {% block canonical %} 5 | 6 | {% endblock %} 7 | 8 | {% block feeds %} 9 | 10 | {% endblock %} 11 | 12 | {% block meta_description %}{{ object2 }}{% endblock %} 13 | 14 | {% block title %}{{ object2 }}{% endblock %} 15 | 16 | {% block scripts %} 17 | 18 | {% endblock %} 19 | 20 | {% block bodyattr %}{% if object2 %} onload="initialize();" onunload="GUnload();"{% endif %}{% endblock %} 21 | 22 | {% block content %} 23 | 24 |
25 |
26 | {% include "confirmation_message.html" %} 27 | {% include "confirmation_message.html" %} 28 |
29 | 30 |

31 | {% if object3 %} 32 | {{ object3 }} 33 | {% else %} 34 | {{ object2 }} 35 | {% endif %} 36 |

37 | 38 |
39 | 40 | {% include "for_loop.html" %} 41 | 42 | {% if not object2 and objects2 %} 43 |
44 | {{ object2 }} 45 |
46 | {% endif %} 47 |
48 | 49 | {% if num1 != 1 %} 50 | {% if not object3 %} 51 | {% if 1 != num2 %} 52 | {{ num2 }} 53 | {% else %} 54 |

Nothing

55 | {% endif %} 56 | {% else %} 57 | {{ num1 }} 58 | {% endif %} 59 | {% endif %} 60 |
61 | 62 | {% if num2 != 0 %} 63 | {% if not object3 %} 64 | {% if 1 != num2 %} 65 | {{ num2 }} 66 | {% else %} 67 |

Nothing

68 | {% endif %} 69 | {% else %} 70 | {{ num1 }} 71 | {% endif %} 72 | {% endif %} 73 |
74 | 75 | 76 | {% if num1 != 0 %} 77 | {% if not object3 %} 78 | {% if 1 != num2 %} 79 | {{ num2 }} 80 | {% else %} 81 |

Nothing

82 | {% endif %} 83 | {% else %} 84 | {{ num1 }} 85 | {% endif %} 86 | {% endif %} 87 |
88 | 89 | {% include "for_loop.html" %} 90 | 91 |
92 | {% include "sidebar.html" %} 93 |
94 |
95 | 96 | {% endblock %} 97 | -------------------------------------------------------------------------------- /django-asv/benchmarks/template_benchmarks/template_render/templates/permalink_django_lte_40.html: -------------------------------------------------------------------------------- 1 | {% extends base_template %} 2 | {% load i18n %}{% load cache %} 3 | 4 | {% block canonical %} 5 | 6 | {% endblock %} 7 | 8 | {% block feeds %} 9 | 10 | {% endblock %} 11 | 12 | {% block meta_description %}{{ object2 }}{% endblock %} 13 | 14 | {% block title %}{{ object2 }}{% endblock %} 15 | 16 | {% block scripts %} 17 | 18 | {% endblock %} 19 | 20 | {% block bodyattr %}{% if object2 %} onload="initialize();" onunload="GUnload();"{% endif %}{% endblock %} 21 | 22 | {% block content %} 23 | 24 |
25 |
26 | {% include "confirmation_message.html" %} 27 | {% include "confirmation_message.html" %} 28 |
29 | 30 |

31 | {% if object3 %} 32 | {{ object3 }} 33 | {% else %} 34 | {{ object2 }} 35 | {% endif %} 36 |

37 | 38 |
39 | 40 | {% include "for_loop.html" %} 41 | 42 | {% if not object2 and objects2 %} 43 |
44 | {{ object2 }} 45 |
46 | {% endif %} 47 |
48 | 49 | {% ifnotequal num1 1 %} 50 | {% if not object3 %} 51 | {% ifnotequal 1 num2 %} 52 | {{ num2 }} 53 | {% else %} 54 |

Nothing

55 | {% endifnotequal %} 56 | {% else %} 57 | {{ num1 }} 58 | {% endif %} 59 | {% endifnotequal %} 60 |
61 | 62 | {% ifnotequal num2 0 %} 63 | {% if not object3 %} 64 | {% ifnotequal 1 num2 %} 65 | {{ num2 }} 66 | {% else %} 67 |

Nothing

68 | {% endifnotequal %} 69 | {% else %} 70 | {{ num1 }} 71 | {% endif %} 72 | {% endifnotequal %} 73 |
74 | 75 | 76 | {% ifnotequal num1 0 %} 77 | {% if not object3 %} 78 | {% ifnotequal 1 num2 %} 79 | {{ num2 }} 80 | {% else %} 81 |

Nothing

82 | {% endifnotequal %} 83 | {% else %} 84 | {{ num1 }} 85 | {% endif %} 86 | {% endifnotequal %} 87 |
88 | 89 | {% include "for_loop.html" %} 90 | 91 |
92 | {% include "sidebar.html" %} 93 |
94 |
95 | 96 | {% endblock %} 97 | -------------------------------------------------------------------------------- /django-asv/benchmarks/template_benchmarks/template_render/templates/sidebar.html: -------------------------------------------------------------------------------- 1 | {% for obj in objects2 %} 2 | {{ obj }} 3 | {{ obj }} 4 | {{ obj }} 5 | {% endfor %} 6 | {% for obj in objects2 %} 7 | {{ obj }} 8 | {{ obj }} 9 | {{ obj }} 10 | {% endfor %} 11 | {% for obj in objects2 %} 12 | {{ obj }} 13 | {{ obj }} 14 | {{ obj }} 15 | {% endfor %} 16 | -------------------------------------------------------------------------------- /django-asv/benchmarks/template_benchmarks/template_render/templates/somefile.js: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /django-asv/benchmarks/template_benchmarks/template_render/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import re_path 2 | 3 | from .views import join, login, logout 4 | 5 | urlpatterns = [ 6 | re_path(r"/join/?$", join, name="join"), 7 | re_path(r"/login/?$", login, name="login"), 8 | re_path(r"/logout/?$", logout, name="logout"), 9 | ] 10 | -------------------------------------------------------------------------------- /django-asv/benchmarks/template_benchmarks/template_render/views.py: -------------------------------------------------------------------------------- 1 | from django.http import HttpResponse 2 | 3 | 4 | # some dummy classes for the url reverse 5 | def join(request): 6 | return HttpResponse() 7 | 8 | 9 | def login(request): 10 | return HttpResponse() 11 | 12 | 13 | def logout(request): 14 | return HttpResponse() 15 | -------------------------------------------------------------------------------- /django-asv/benchmarks/url_benchmarks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/url_benchmarks/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/url_benchmarks/url_resolve/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/url_benchmarks/url_resolve/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/url_benchmarks/url_resolve/benchmark.py: -------------------------------------------------------------------------------- 1 | from django.urls import resolve 2 | 3 | from ...utils import bench_setup 4 | 5 | 6 | class UrlResolve: 7 | def setup(self): 8 | bench_setup() 9 | 10 | def time_resolve(self): 11 | for i in range(100): 12 | resolve("/url-resolve/basic/") 13 | resolve("/url-resolve/fallthroughview/") 14 | resolve("/url-resolve/replace/1") 15 | -------------------------------------------------------------------------------- /django-asv/benchmarks/url_benchmarks/url_resolve/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import re_path 2 | 3 | from . import views 4 | 5 | 6 | def generate_filler_patterns(num=1): 7 | """Returns a list of url pattern inputs for garbage views""" 8 | for n in range(num): 9 | yield re_path(r"".join((r"^", r"x" * 3 * n, r"/$")), views.basic) 10 | 11 | 12 | urlpatterns = list(generate_filler_patterns(10)) 13 | urlpatterns.append(re_path(r"^basic/$", views.basic, name="basic")) 14 | urlpatterns.append(re_path(r"^[a-z]*/$", views.catchall, name="catchall")) 15 | urlpatterns.append(re_path(r"^replace/(?P.*?)", views.vars, name="vars")) 16 | -------------------------------------------------------------------------------- /django-asv/benchmarks/url_benchmarks/url_resolve/views.py: -------------------------------------------------------------------------------- 1 | from django.http import HttpResponse 2 | 3 | 4 | def basic(request): 5 | return HttpResponse() 6 | 7 | 8 | def catchall(request): 9 | return HttpResponse() 10 | 11 | 12 | def vars(request, var=None): 13 | return HttpResponse() 14 | -------------------------------------------------------------------------------- /django-asv/benchmarks/url_benchmarks/url_resolve_flat/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/url_benchmarks/url_resolve_flat/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/url_benchmarks/url_resolve_flat/benchmark.py: -------------------------------------------------------------------------------- 1 | from django.urls import Resolver404, resolve 2 | 3 | from ...utils import bench_setup 4 | 5 | 6 | class UrlResolveFlat: 7 | def setup(self): 8 | bench_setup() 9 | 10 | def time_resolve_flat(self): 11 | paths = ( 12 | "/url-resolve-flat/user/repo/feature19", 13 | "/url-resolve-flat/section0/feature0", 14 | "/url-resolve-flat/en/feature10", 15 | "/url-resolve-flat/ru/feature10", 16 | "/url-resolve-flat/missing", 17 | ) 18 | for i in range(100): 19 | for path in paths: 20 | try: 21 | resolve(path) 22 | except Resolver404: 23 | pass 24 | -------------------------------------------------------------------------------- /django-asv/benchmarks/url_benchmarks/url_resolve_flat/urls.py: -------------------------------------------------------------------------------- 1 | from django.http import HttpResponse 2 | from django.urls import re_path 3 | 4 | 5 | def ok_view(request, *a, **kw): 6 | return HttpResponse() 7 | 8 | 9 | def handler404(request): 10 | return HttpResponse() 11 | 12 | 13 | sections = ["section%d" % i for i in range(10)] 14 | features = ["feature%d" % i for i in range(20)] 15 | 16 | urlpatterns = [re_path("^%s/%s$" % (s, f), ok_view) for s in sections for f in features] 17 | 18 | urlpatterns += [re_path(r"^(?Pen|ru)/%s$" % f, ok_view) for f in features] 19 | 20 | urlpatterns += [ 21 | re_path(r"^(?P\w+)/(?P\w+)/%s$" % f, ok_view) for f in features 22 | ] 23 | -------------------------------------------------------------------------------- /django-asv/benchmarks/url_benchmarks/url_resolve_nested/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/url_benchmarks/url_resolve_nested/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/url_benchmarks/url_resolve_nested/benchmark.py: -------------------------------------------------------------------------------- 1 | from django.urls import resolve 2 | 3 | from ...utils import bench_setup 4 | 5 | 6 | class UrlResolveNested: 7 | def setup(self): 8 | bench_setup() 9 | 10 | def time_resolve_nested(self): 11 | resolve("/url-resolve-nested/0/00/000/0000/00000/000000/0000000/00000000/leaf") 12 | -------------------------------------------------------------------------------- /django-asv/benchmarks/url_benchmarks/url_resolve_nested/urls.py: -------------------------------------------------------------------------------- 1 | import string 2 | 3 | from django.http import HttpResponse 4 | from django.urls import include, re_path 5 | 6 | 7 | def ok_view(request, *a, **kw): 8 | return HttpResponse() 9 | 10 | 11 | def handler500(request): 12 | return HttpResponse() 13 | 14 | 15 | leaf_patterns = [re_path(r"^leaf$", ok_view)] 16 | 17 | 18 | def int2ascii(x, mod, alphabet=string.digits + string.ascii_letters): 19 | alphabet = alphabet[:mod] 20 | result = [] 21 | while x: 22 | x, rem = divmod(x, mod) 23 | result.append(alphabet[rem]) 24 | return ("".join(reversed(result))).rjust(1, alphabet[0]) 25 | 26 | 27 | def pattern_tree(parent, height, level): 28 | if height == 0: 29 | return leaf_patterns 30 | ids = [parent + int2ascii(i, level) for i in range(level)] 31 | return [ 32 | re_path("^%s/" % id_, include(pattern_tree(id_, height - 1, level))) 33 | for id_ in ids 34 | ] 35 | 36 | 37 | urlpatterns = pattern_tree("", 8, 2) 38 | # Total: 2**8 = 256 leafs, 511 nodes 39 | -------------------------------------------------------------------------------- /django-asv/benchmarks/url_benchmarks/url_reverse/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodWork0903/Django/c0e295aadf3ab50bf66d8f3d2e0a222e0345f4dc/django-asv/benchmarks/url_benchmarks/url_reverse/__init__.py -------------------------------------------------------------------------------- /django-asv/benchmarks/url_benchmarks/url_reverse/benchmark.py: -------------------------------------------------------------------------------- 1 | from django.urls import reverse 2 | 3 | from ...utils import bench_setup 4 | 5 | 6 | class UrlReverse: 7 | def setup(self): 8 | bench_setup() 9 | 10 | def time_reverse(self): 11 | reverse("url_reverse:basic") 12 | reverse("url_reverse:catchall") 13 | reverse("url_reverse:vars", args=[1]) 14 | reverse("url_reverse:vars", kwargs={"var": 1}) 15 | -------------------------------------------------------------------------------- /django-asv/benchmarks/url_benchmarks/url_reverse/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import re_path 2 | 3 | from . import views 4 | 5 | 6 | def generate_filler_patterns(num=1): 7 | """Returns a list of url pattern inputs for garbage views""" 8 | for n in range(num): 9 | yield re_path(r"".join((r"^", r"x" * 3 * n, r"/$")), views.basic) 10 | 11 | 12 | app_name = "url_reverse" 13 | 14 | urlpatterns = list(generate_filler_patterns(10)) 15 | urlpatterns.append(re_path(r"^basic/$", views.basic, name="basic")) 16 | urlpatterns.append(re_path(r"^[a-z]*/$", views.catchall, name="catchall")) 17 | urlpatterns.append(re_path(r"^replace/(?P.*?)", views.vars, name="vars")) 18 | -------------------------------------------------------------------------------- /django-asv/benchmarks/url_benchmarks/url_reverse/views.py: -------------------------------------------------------------------------------- 1 | from django.http import HttpResponse 2 | 3 | 4 | def basic(request): 5 | return HttpResponse() 6 | 7 | 8 | def catchall(request): 9 | return HttpResponse() 10 | 11 | 12 | def vars(request, var=None): 13 | return HttpResponse() 14 | -------------------------------------------------------------------------------- /django-asv/benchmarks/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import include, path 2 | 3 | # url_resolve 4 | urlpatterns = [ 5 | path("url-resolve/", include("benchmarks.url_benchmarks.url_resolve.urls")) 6 | ] 7 | 8 | # url_reverse 9 | urlpatterns.append( 10 | path( 11 | "url-reverse/", 12 | include("benchmarks.url_benchmarks.url_reverse.urls", namespace="url_reverse"), 13 | ) 14 | ) 15 | 16 | # url_resolve_flat 17 | urlpatterns.append( 18 | path( 19 | "url-resolve-flat/", include("benchmarks.url_benchmarks.url_resolve_flat.urls") 20 | ) 21 | ) 22 | 23 | # url_resolve_nested 24 | urlpatterns.append( 25 | path( 26 | "url-resolve-nested/", 27 | include("benchmarks.url_benchmarks.url_resolve_nested.urls"), 28 | ) 29 | ) 30 | 31 | # template_render 32 | urlpatterns.append( 33 | path( 34 | "template-render/", 35 | include("benchmarks.template_benchmarks.template_render.urls"), 36 | ) 37 | ) 38 | 39 | # default_middleware 40 | urlpatterns.append( 41 | path("", include("benchmarks.req_resp_benchmarks.default_middleware.urls")) 42 | ) 43 | 44 | # http methods 45 | urlpatterns.append( 46 | path("", include("benchmarks.req_resp_benchmarks.http_methods.urls")) 47 | ) 48 | -------------------------------------------------------------------------------- /django-asv/benchmarks/utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from django.core.management import CommandError, call_command 4 | 5 | import django 6 | 7 | 8 | def bench_setup(migrate=False): 9 | try: 10 | os.environ["DJANGO_SETTINGS_MODULE"] = "benchmarks.settings" 11 | django.setup() 12 | except RuntimeError: 13 | pass 14 | 15 | if migrate is True: 16 | call_command("migrate", run_syncdb=True, verbosity=0) 17 | try: 18 | call_command("loaddata", "initial_data", verbosity=0) 19 | except CommandError as exc: 20 | # Django 1.10+ raises if the file doesn't exist and not 21 | # all benchmarks have files. 22 | if "No fixture named" not in str(exc): 23 | raise 24 | -------------------------------------------------------------------------------- /django-asv/requirements.txt: -------------------------------------------------------------------------------- 1 | asv==0.5.1 2 | pre-commit 3 | -------------------------------------------------------------------------------- /django-asv/setup.cfg: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = E302 E305 3 | max-line-length = 90 4 | exclude = Django, env, results 5 | 6 | [isort] 7 | combine_as_imports = true 8 | include_trailing_comma = true 9 | line_length = 79 10 | multi_line_output = 5 11 | -------------------------------------------------------------------------------- /dsf-working-groups/active/code-of-conduct.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct Working Group 2 | 3 | ## Scope of responsibilities 4 | 5 | The Code of Conduct WG handles reports of violations to the [Django Code of Conduct](https://djangoproject.com/conduct). 6 | 7 | See https://github.com/django/code-of-conduct for full details. 8 | 9 | ## Membership 10 | 11 | - Chair: Brian Moloney 12 | - Board Liaison: DSF President (currently Chaim Kirby) 13 | - Other members: 14 | - Jeff Triplett 15 | - Olumide Bakare 16 | - Joseph V. Cardenas 17 | - Michael Clark 18 | - Tibbs Hefflin 19 | 20 | ## Future membership 21 | 22 | Membership is open to volunteers. To volunteer to join the working group, email `conduct@djangoproject.com` and express your interest. 23 | 24 | Membership is self-managed: volunteers are screened and inducted by the current WG membership. The membership likewise elects its own chair (via 50%+ voting). See https://github.com/django/code-of-conduct/blob/main/membership.md for more details. 25 | 26 | The DSF President is always a member of the CoC WG, and its board liaison. 27 | 28 | ## Budget 29 | 30 | The CoC-WG has no directly appropriated budget. 31 | 32 | ## Comms 33 | 34 | See https://github.com/django/code-of-conduct/blob/main/communications.md 35 | 36 | ## Reporting 37 | 38 | The DSF President (aka Board Liaison), will be responsible for formal reporting back to the board. This is an as-needed reporting structure: the President will report on activities as they are relevant to the board, which may mean no reports if nothing is happening. 39 | 40 | Additionally, the CoC-WG will publish its own public reports, including a transparency report. See https://github.com/django/code-of-conduct/blob/main/transparency.md and https://github.com/django/code-of-conduct/blob/main/statistics.md. 41 | -------------------------------------------------------------------------------- /dsf-working-groups/active/dceu.md: -------------------------------------------------------------------------------- 1 | # DjangoCon Europe Support 2 | 3 | ## Scope of responsibilities 4 | 5 | Supports organizers of DjangoCon Europe. 6 | 7 | Delegated responsibilities TBD. 8 | 9 | ## Initial membership 10 | 11 | - Chair: TBD 12 | - Co-Chair: TBD 13 | - Board Liaison (must be an active Board member; may be the same as Chair/Co-Chair): TBD 14 | - Other members: TBD 15 | 16 | ## Future membership 17 | 18 | Membership is open to former organizers of DjangoCon EUs. Contact TBD if this is you and you want to join. [Contact the board](https://www.djangoproject.com/contact/foundation/) to express interest. 19 | 20 | Membership is self-managed: new members may self-nominate; the WG will vote (50%+1) to approve/deny new members; the WG will directly vote on new Chair/Co-Chairs. 21 | 22 | ## Budget 23 | 24 | TBD 25 | 26 | ## Comms 27 | 28 | TBD 29 | 30 | ## Reporting 31 | 32 | TBD 33 | -------------------------------------------------------------------------------- /dsf-working-groups/active/fellowship.md: -------------------------------------------------------------------------------- 1 | # Fellowship Working Group 2 | 3 | ## Scope of responsibilities 4 | 5 | The Fellowship Working Group manages the operation of the [Django Fellowship Program](https://www.djangoproject.com/fundraising/#fellowship-program). They select candidates to fill the fellowship, and act as line managers during the operation of the program. 6 | 7 | ## Initial membership 8 | 9 | - Chair: Brian Moloney 10 | - Board liaison: TBD 11 | - Other members: 12 | - Andrew Godwin 13 | - Frank Wiles 14 | 15 | ## Future membership 16 | 17 | Board-managed: the DSF Board appoints members of this WG. 18 | 19 | Membership is open to volunteers, subject to board approval. [Contact the board](https://www.djangoproject.com/contact/foundation/) to express interest. 20 | 21 | ## Budget 22 | 23 | The DSF Board sets the Fellowship compensation, but the WG then has the power to select who fills the position. 24 | 25 | ## Comms 26 | 27 | TBD 28 | 29 | ## Reporting 30 | 31 | TBD 32 | -------------------------------------------------------------------------------- /dsf-working-groups/active/fundraising.md: -------------------------------------------------------------------------------- 1 | # Fundraising Working Group 2 | 3 | ## Scope of responsibilities 4 | 5 | Coordinates fundraising efforts, particularly around corporate and major donations. 6 | 7 | Delegated responsibilities TBD. 8 | 9 | ## Initial membership 10 | 11 | - Chair: TBD 12 | - Co-Chair: TBD 13 | - Board Liaison (must be an active Board member; may be the same as Chair/Co-Chair): TBD 14 | - Other members: TBD 15 | 16 | ## Future membership 17 | 18 | Direct membership: new members may self-nominate; the WG will vote (50%+1) to approve/deny new members; the WG will directly vote on new Chair/Co-Chairs. 19 | 20 | This committee is currently forming and seeking volinteers, including chair and co-chair. 21 | 22 | ## Budget 23 | 24 | No allocated funds. 25 | 26 | ## Comms 27 | 28 | TBD 29 | 30 | ## Reporting 31 | 32 | TBD 33 | -------------------------------------------------------------------------------- /dsf-working-groups/active/social-media.md: -------------------------------------------------------------------------------- 1 | # Social Media Working Group 2 | 3 | ## Scope of responsibilities 4 | 5 | This working group will manage Django's official social media profiles on behalf of the Django Software Foundation. 6 | 7 | The goals of the group are: 8 | - Promote the use of Django among the World Wide Web development community. 9 | - Protect the framework's long-term viability through campaigns and sponsor relations. 10 | - Ensure the DSF’s Code of Conduct is maintained on its media channels. 11 | - Assist the board in posting official news and updates from the DSF. 12 | 13 | The group opts to manage platforms that best achieve these goals. 14 | This may be a subset of those for which Django has accounts. 15 | 16 | Delegated responsibilities: 17 | - The Chair, Co-Chair and Board Liaison can grant access to Django's official social media profiles to other group 18 | members as needed. 19 | - Members can post content to Django's official social media profiles, in alignment with the working group's agreed 20 | goals, without a board review. 21 | - Members can perform actions such as “like”, “repost” or “comment” as Django, when it aligns with the working group's 22 | agreed goals, without a board review. 23 | - Members can perform maintenance and monitor the automations which post DSF news and updates to social media channels. 24 | - Members can enforce the Code of Conduct. This may include moderating comments that do not meet our CoC or blocking 25 | users that grossly or repeatedly violate the CoC. 26 | 27 | Actions to take back to the DSF Board for votes: 28 | - Amendments to the working group's goals. 29 | - Approval on content that is outside the agreed group's goals. 30 | - Proposals of social media campaigns for our sponsors. 31 | - Proposal to have a new social media profile on a platform. 32 | - Proposal to retire a social media profile from a platform. 33 | 34 | ## Initial membership 35 | 36 | - Chair: Benjamin Balder Bach 37 | - Co-Chair: Bhuvnesh Sharma 38 | - Board Liaison (must be an active Board member; may be the same as Chair/Co-Chair): Thibaud Colas 39 | - Other members: 40 | - Cory Zue 41 | - Jason Judkins 42 | - Sarah Boyce 43 | 44 | ## Future membership 45 | 46 | ### Who is eligible to join? Any volunteer, or are there specific requirements? 47 | 48 | Members must have demonstrable experience with social media platforms, and be registered as a Django Software Foundation 49 | Individual Member. 50 | 51 | ### How do people who want to join sign up / volunteer / express interest? 52 | 53 | A form will be made available in a public space (once created this will be linked to here also). 54 | 55 | This form will include questions confirming: 56 | - their DSF membership 57 | - why they want to join 58 | - what experience and skills they bring to the role 59 | - links to their social media profiles 60 | 61 | ### How will decisions on adding/removing members be handled? 62 | 63 | The working group will discuss and vote (50%+1) to approve new members. 64 | 65 | Members join the group for a 6-month term. At the end of this term, they need to opt into staying involved to keep being 66 | a member of the group. 67 | 68 | If any member wishes to leave the group before the end of their term, they can do so without a vote. 69 | 70 | Members can propose a vote on removing a member from the working group. This needs 50%+1 agreement. 71 | 72 | ## Budget 73 | 74 | The working group will have no allocated budget. 75 | 76 | ## Comms within the group 77 | 78 | - Fortnightly synchronous meeting 79 | - Collaborative documents when creating a content plan and/our campaign 80 | - Private channel in the DSF slack 81 | 82 | ## Reporting 83 | 84 | We'll email a written report to the board every quarter. 85 | -------------------------------------------------------------------------------- /dsf-working-groups/template.md: -------------------------------------------------------------------------------- 1 | # WG Charter Template 2 | 3 | _This is a template charter for a working group. You'll need all the following for a proposal to be considered complete. See the [README](README.md) for more information on each field._ 4 | 5 | ## Scope of responsibilities 6 | 7 | Write a paragraph or a few bullet points describing the WG here. 8 | 9 | - What powers are you asking the board to delegate to you? 10 | - What actions are you proposing the WG be allowed to take directly? 11 | - Which actions will the WG take back to the Board for votes? 12 | 13 | ## Initial membership 14 | 15 | - Chair: 16 | - Co-Chair: 17 | - Board Liaison (must be an active Board member; may be the same as Chair/Co-Chair): 18 | - Other members: 19 | 20 | ## Future membership 21 | 22 | Answer the following questions here: 23 | 24 | - Who is eligible to join? Any volunteer, or are there specific requirements? 25 | - How do people who want to join sign up / volunteer / express interest? 26 | - How will decisions on adding/removing members be handled? 27 | 28 | For the last question, we suggest picking one of the following: 29 | 30 | - Direct membership: new members may self-nominate; the WG will vote (50%+1) to approve/deny new members; the WG will directly vote on new Chair/Co-Chairs. (This is the appropriate model for most WGs). 31 | - Board-managed: new members may self-nominate, but must be voted in by the Board. The Board must approve changes to the Chair/Co-Chair. (This is the appropriate model for sensitive WGs, such as the Conduct WG, or WGs with large budgets ($thousands/year).) 32 | 33 | ## Budget 34 | 35 | - How much money or spending discretion do you need? 36 | - How do you want that money allocated -- e.g. once yearly, quarterly, etc. 37 | 38 | ## Comms 39 | 40 | Where will discussions and activities take place? 41 | 42 | Suggestions: 43 | 44 | - A mailing list that we'll create, `some-wg@djangoproject.com` 45 | - The DSF Slack 46 | 47 | Meetings: we also suggest synchronous meetings via Meet/Zoom/Whereby/etc at least monthly. 48 | 49 | ## Reporting 50 | 51 | How and how often will the WG report back to the board? 52 | 53 | Suggestion: we'll email a written report to the board [monthly/every two months/every quarter]. 54 | --------------------------------------------------------------------------------