diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..bc22ecb24 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +version: 2 +updates: + - package-ecosystem: "uv" + directory: "/" + schedule: + interval: "weekly" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..7bca521b0 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,20 @@ +name: CI + +on: + push: + branches: + - main + pull_request: + +jobs: + smoke-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: astral-sh/setup-uv@v7 + + - name: Install dependencies + run: uv sync --locked + + - name: Run Django check + run: uv run manage.py check diff --git a/.gitignore b/.gitignore index 4ed369eb9..82e5b9469 100644 --- a/.gitignore +++ b/.gitignore @@ -2,8 +2,8 @@ *.sqlite3 *.pyc *~ -.* -env +.venv +venv # Accept these files in the repository !.gitignore diff --git a/.python-version b/.python-version new file mode 100644 index 000000000..24ee5b1be --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.13 diff --git a/README.md b/README.md index 05418145c..de291ac4c 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,4 @@ Source code for the [Django REST framework tutorial][tut]. [tut]: http://www.django-rest-framework.org/tutorial/1-serialization -[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) +[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://www.heroku.com/deploy?template=https://github.com/encode/rest-framework-tutorial) diff --git a/manage.py b/manage.py index 02401187d..a1a766399 100755 --- a/manage.py +++ b/manage.py @@ -1,22 +1,22 @@ #!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" import os import sys -if __name__ == "__main__": + +def main(): + """Run administrative tasks.""" os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tutorial.settings") try: from django.core.management import execute_from_command_line - except ImportError: - # The above import may fail for some other reason. Ensure that the - # issue is really that Django is missing to avoid masking other - # exceptions on Python 2. - try: - import django - except ImportError: - raise ImportError( - "Couldn't import Django. Are you sure it's installed and " - "available on your PYTHONPATH environment variable? Did you " - "forget to activate a virtual environment?" - ) - raise + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc execute_from_command_line(sys.argv) + + +if __name__ == "__main__": + main() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..179c9f8d0 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,19 @@ +[project] +name = "rest-framework-tutorial" +version = "1.0.0" +description = "The Django REST framework tutorial. 🎓" +readme = "README.md" +requires-python = "==3.13.*" +dependencies = [ + "dj-database-url==3.1.2", + "django==6.0.5", + "djangorestframework==3.17.1", + "drf-spectacular==0.29.0", + "gunicorn==26.0.0", + "inflection==0.5.1", + "markdown==3.10.2", + "psycopg[binary]==3.3.4", + "pygments==2.20.0", + "pyyaml==6.0.3", + "whitenoise==6.12.0", +] diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 65b8c5908..000000000 --- a/requirements.txt +++ /dev/null @@ -1,10 +0,0 @@ -djangorestframework==3.9.2 -Django==2.2.10 -Pygments==2.3.1 -Markdown==3.1 -coreapi==2.3.3 -psycopg2-binary==2.7.7 -dj-database-url==0.5.0 -gunicorn==19.9.0 -whitenoise==4.1.2 -PyYAML==5.1 diff --git a/runtime.txt b/runtime.txt deleted file mode 100644 index 02d0df5e8..000000000 --- a/runtime.txt +++ /dev/null @@ -1 +0,0 @@ -python-3.6.3 diff --git a/snippets/apps.py b/snippets/apps.py index 1caadce55..c598a6743 100644 --- a/snippets/apps.py +++ b/snippets/apps.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - from django.apps import AppConfig diff --git a/snippets/migrations/0001_initial.py b/snippets/migrations/0001_initial.py index 1919afbc2..3884b2bdd 100644 --- a/snippets/migrations/0001_initial.py +++ b/snippets/migrations/0001_initial.py @@ -1,7 +1,3 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.11.7 on 2017-11-24 18:20 -from __future__ import unicode_literals - from django.conf import settings from django.db import migrations, models import django.db.models.deletion @@ -19,9 +15,9 @@ class Migration(migrations.Migration): migrations.CreateModel( name='Snippet', fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('created', models.DateTimeField(auto_now_add=True)), - ('title', models.CharField(blank=True, default=b'', max_length=100)), + ('title', models.CharField(blank=True, default="", max_length=100)), ('code', models.TextField()), ('linenos', models.BooleanField(default=False)), ('language', models.CharField(choices=[(b'abap', b'ABAP'), (b'abnf', b'ABNF'), (b'ada', b'Ada'), (b'adl', b'ADL'), (b'agda', b'Agda'), (b'aheui', b'Aheui'), (b'ahk', b'autohotkey'), (b'alloy', b'Alloy'), (b'ampl', b'Ampl'), (b'antlr', b'ANTLR'), (b'antlr-as', b'ANTLR With ActionScript Target'), (b'antlr-cpp', b'ANTLR With CPP Target'), (b'antlr-csharp', b'ANTLR With C# Target'), (b'antlr-java', b'ANTLR With Java Target'), (b'antlr-objc', b'ANTLR With ObjectiveC Target'), (b'antlr-perl', b'ANTLR With Perl Target'), (b'antlr-python', b'ANTLR With Python Target'), (b'antlr-ruby', b'ANTLR With Ruby Target'), (b'apacheconf', b'ApacheConf'), (b'apl', b'APL'), (b'applescript', b'AppleScript'), (b'arduino', b'Arduino'), (b'as', b'ActionScript'), (b'as3', b'ActionScript 3'), (b'aspectj', b'AspectJ'), (b'aspx-cs', b'aspx-cs'), (b'aspx-vb', b'aspx-vb'), (b'asy', b'Asymptote'), (b'at', b'AmbientTalk'), (b'autoit', b'AutoIt'), (b'awk', b'Awk'), (b'basemake', b'Base Makefile'), (b'bash', b'Bash'), (b'bat', b'Batchfile'), (b'bbcode', b'BBCode'), (b'bc', b'BC'), (b'befunge', b'Befunge'), (b'bib', b'BibTeX'), (b'blitzbasic', b'BlitzBasic'), (b'blitzmax', b'BlitzMax'), (b'bnf', b'BNF'), (b'boo', b'Boo'), (b'boogie', b'Boogie'), (b'brainfuck', b'Brainfuck'), (b'bro', b'Bro'), (b'bst', b'BST'), (b'bugs', b'BUGS'), (b'c', b'C'), (b'c-objdump', b'c-objdump'), (b'ca65', b'ca65 assembler'), (b'cadl', b'cADL'), (b'camkes', b'CAmkES'), (b'capdl', b'CapDL'), (b'capnp', b"Cap'n Proto"), (b'cbmbas', b'CBM BASIC V2'), (b'ceylon', b'Ceylon'), (b'cfc', b'Coldfusion CFC'), (b'cfengine3', b'CFEngine3'), (b'cfm', b'Coldfusion HTML'), (b'cfs', b'cfstatement'), (b'chai', b'ChaiScript'), (b'chapel', b'Chapel'), (b'cheetah', b'Cheetah'), (b'cirru', b'Cirru'), (b'clay', b'Clay'), (b'clean', b'Clean'), (b'clojure', b'Clojure'), (b'clojurescript', b'ClojureScript'), (b'cmake', b'CMake'), (b'cobol', b'COBOL'), (b'cobolfree', b'COBOLFree'), (b'coffee-script', b'CoffeeScript'), (b'common-lisp', b'Common Lisp'), (b'componentpascal', b'Component Pascal'), (b'console', b'Bash Session'), (b'control', b'Debian Control file'), (b'coq', b'Coq'), (b'cpp', b'C++'), (b'cpp-objdump', b'cpp-objdump'), (b'cpsa', b'CPSA'), (b'cr', b'Crystal'), (b'crmsh', b'Crmsh'), (b'croc', b'Croc'), (b'cryptol', b'Cryptol'), (b'csharp', b'C#'), (b'csound', b'Csound Orchestra'), (b'csound-document', b'Csound Document'), (b'csound-score', b'Csound Score'), (b'css', b'CSS'), (b'css+django', b'CSS+Django/Jinja'), (b'css+erb', b'CSS+Ruby'), (b'css+genshitext', b'CSS+Genshi Text'), (b'css+lasso', b'CSS+Lasso'), (b'css+mako', b'CSS+Mako'), (b'css+mozpreproc', b'CSS+mozpreproc'), (b'css+myghty', b'CSS+Myghty'), (b'css+php', b'CSS+PHP'), (b'css+smarty', b'CSS+Smarty'), (b'cucumber', b'Gherkin'), (b'cuda', b'CUDA'), (b'cypher', b'Cypher'), (b'cython', b'Cython'), (b'd', b'D'), (b'd-objdump', b'd-objdump'), (b'dart', b'Dart'), (b'delphi', b'Delphi'), (b'dg', b'dg'), (b'diff', b'Diff'), (b'django', b'Django/Jinja'), (b'docker', b'Docker'), (b'doscon', b'MSDOS Session'), (b'dpatch', b'Darcs Patch'), (b'dtd', b'DTD'), (b'duel', b'Duel'), (b'dylan', b'Dylan'), (b'dylan-console', b'Dylan session'), (b'dylan-lid', b'DylanLID'), (b'earl-grey', b'Earl Grey'), (b'easytrieve', b'Easytrieve'), (b'ebnf', b'EBNF'), (b'ec', b'eC'), (b'ecl', b'ECL'), (b'eiffel', b'Eiffel'), (b'elixir', b'Elixir'), (b'elm', b'Elm'), (b'emacs', b'EmacsLisp'), (b'erb', b'ERB'), (b'erl', b'Erlang erl session'), (b'erlang', b'Erlang'), (b'evoque', b'Evoque'), (b'extempore', b'xtlang'), (b'ezhil', b'Ezhil'), (b'factor', b'Factor'), (b'fan', b'Fantom'), (b'fancy', b'Fancy'), (b'felix', b'Felix'), (b'fish', b'Fish'), (b'flatline', b'Flatline'), (b'forth', b'Forth'), (b'fortran', b'Fortran'), (b'fortranfixed', b'FortranFixed'), (b'foxpro', b'FoxPro'), (b'fsharp', b'FSharp'), (b'gap', b'GAP'), (b'gas', b'GAS'), (b'genshi', b'Genshi'), (b'genshitext', b'Genshi Text'), (b'glsl', b'GLSL'), (b'gnuplot', b'Gnuplot'), (b'go', b'Go'), (b'golo', b'Golo'), (b'gooddata-cl', b'GoodData-CL'), (b'gosu', b'Gosu'), (b'groff', b'Groff'), (b'groovy', b'Groovy'), (b'gst', b'Gosu Template'), (b'haml', b'Haml'), (b'handlebars', b'Handlebars'), (b'haskell', b'Haskell'), (b'haxeml', b'Hxml'), (b'hexdump', b'Hexdump'), (b'hsail', b'HSAIL'), (b'html', b'HTML'), (b'html+cheetah', b'HTML+Cheetah'), (b'html+django', b'HTML+Django/Jinja'), (b'html+evoque', b'HTML+Evoque'), (b'html+genshi', b'HTML+Genshi'), (b'html+handlebars', b'HTML+Handlebars'), (b'html+lasso', b'HTML+Lasso'), (b'html+mako', b'HTML+Mako'), (b'html+myghty', b'HTML+Myghty'), (b'html+ng2', b'HTML + Angular2'), (b'html+php', b'HTML+PHP'), (b'html+smarty', b'HTML+Smarty'), (b'html+twig', b'HTML+Twig'), (b'html+velocity', b'HTML+Velocity'), (b'http', b'HTTP'), (b'hx', b'Haxe'), (b'hybris', b'Hybris'), (b'hylang', b'Hy'), (b'i6t', b'Inform 6 template'), (b'idl', b'IDL'), (b'idris', b'Idris'), (b'iex', b'Elixir iex session'), (b'igor', b'Igor'), (b'inform6', b'Inform 6'), (b'inform7', b'Inform 7'), (b'ini', b'INI'), (b'io', b'Io'), (b'ioke', b'Ioke'), (b'irc', b'IRC logs'), (b'isabelle', b'Isabelle'), (b'j', b'J'), (b'jags', b'JAGS'), (b'jasmin', b'Jasmin'), (b'java', b'Java'), (b'javascript+mozpreproc', b'Javascript+mozpreproc'), (b'jcl', b'JCL'), (b'jlcon', b'Julia console'), (b'js', b'JavaScript'), (b'js+cheetah', b'JavaScript+Cheetah'), (b'js+django', b'JavaScript+Django/Jinja'), (b'js+erb', b'JavaScript+Ruby'), (b'js+genshitext', b'JavaScript+Genshi Text'), (b'js+lasso', b'JavaScript+Lasso'), (b'js+mako', b'JavaScript+Mako'), (b'js+myghty', b'JavaScript+Myghty'), (b'js+php', b'JavaScript+PHP'), (b'js+smarty', b'JavaScript+Smarty'), (b'jsgf', b'JSGF'), (b'json', b'JSON'), (b'json-object', b'JSONBareObject'), (b'jsonld', b'JSON-LD'), (b'jsp', b'Java Server Page'), (b'julia', b'Julia'), (b'juttle', b'Juttle'), (b'kal', b'Kal'), (b'kconfig', b'Kconfig'), (b'koka', b'Koka'), (b'kotlin', b'Kotlin'), (b'lagda', b'Literate Agda'), (b'lasso', b'Lasso'), (b'lcry', b'Literate Cryptol'), (b'lean', b'Lean'), (b'less', b'LessCss'), (b'lhs', b'Literate Haskell'), (b'lidr', b'Literate Idris'), (b'lighty', b'Lighttpd configuration file'), (b'limbo', b'Limbo'), (b'liquid', b'liquid'), (b'live-script', b'LiveScript'), (b'llvm', b'LLVM'), (b'logos', b'Logos'), (b'logtalk', b'Logtalk'), (b'lsl', b'LSL'), (b'lua', b'Lua'), (b'make', b'Makefile'), (b'mako', b'Mako'), (b'maql', b'MAQL'), (b'mask', b'Mask'), (b'mason', b'Mason'), (b'mathematica', b'Mathematica'), (b'matlab', b'Matlab'), (b'matlabsession', b'Matlab session'), (b'md', b'markdown'), (b'minid', b'MiniD'), (b'modelica', b'Modelica'), (b'modula2', b'Modula-2'), (b'monkey', b'Monkey'), (b'monte', b'Monte'), (b'moocode', b'MOOCode'), (b'moon', b'MoonScript'), (b'mozhashpreproc', b'mozhashpreproc'), (b'mozpercentpreproc', b'mozpercentpreproc'), (b'mql', b'MQL'), (b'mscgen', b'Mscgen'), (b'mupad', b'MuPAD'), (b'mxml', b'MXML'), (b'myghty', b'Myghty'), (b'mysql', b'MySQL'), (b'nasm', b'NASM'), (b'ncl', b'NCL'), (b'nemerle', b'Nemerle'), (b'nesc', b'nesC'), (b'newlisp', b'NewLisp'), (b'newspeak', b'Newspeak'), (b'ng2', b'Angular2'), (b'nginx', b'Nginx configuration file'), (b'nim', b'Nimrod'), (b'nit', b'Nit'), (b'nixos', b'Nix'), (b'nsis', b'NSIS'), (b'numpy', b'NumPy'), (b'nusmv', b'NuSMV'), (b'objdump', b'objdump'), (b'objdump-nasm', b'objdump-nasm'), (b'objective-c', b'Objective-C'), (b'objective-c++', b'Objective-C++'), (b'objective-j', b'Objective-J'), (b'ocaml', b'OCaml'), (b'octave', b'Octave'), (b'odin', b'ODIN'), (b'ooc', b'Ooc'), (b'opa', b'Opa'), (b'openedge', b'OpenEdge ABL'), (b'pacmanconf', b'PacmanConf'), (b'pan', b'Pan'), (b'parasail', b'ParaSail'), (b'pawn', b'Pawn'), (b'perl', b'Perl'), (b'perl6', b'Perl6'), (b'php', b'PHP'), (b'pig', b'Pig'), (b'pike', b'Pike'), (b'pkgconfig', b'PkgConfig'), (b'plpgsql', b'PL/pgSQL'), (b'postgresql', b'PostgreSQL SQL dialect'), (b'postscript', b'PostScript'), (b'pot', b'Gettext Catalog'), (b'pov', b'POVRay'), (b'powershell', b'PowerShell'), (b'praat', b'Praat'), (b'prolog', b'Prolog'), (b'properties', b'Properties'), (b'protobuf', b'Protocol Buffer'), (b'ps1con', b'PowerShell Session'), (b'psql', b'PostgreSQL console (psql)'), (b'pug', b'Pug'), (b'puppet', b'Puppet'), (b'py3tb', b'Python 3.0 Traceback'), (b'pycon', b'Python console session'), (b'pypylog', b'PyPy Log'), (b'pytb', b'Python Traceback'), (b'python', b'Python'), (b'python3', b'Python 3'), (b'qbasic', b'QBasic'), (b'qml', b'QML'), (b'qvto', b'QVTO'), (b'racket', b'Racket'), (b'ragel', b'Ragel'), (b'ragel-c', b'Ragel in C Host'), (b'ragel-cpp', b'Ragel in CPP Host'), (b'ragel-d', b'Ragel in D Host'), (b'ragel-em', b'Embedded Ragel'), (b'ragel-java', b'Ragel in Java Host'), (b'ragel-objc', b'Ragel in Objective C Host'), (b'ragel-ruby', b'Ragel in Ruby Host'), (b'raw', b'Raw token data'), (b'rb', b'Ruby'), (b'rbcon', b'Ruby irb session'), (b'rconsole', b'RConsole'), (b'rd', b'Rd'), (b'rebol', b'REBOL'), (b'red', b'Red'), (b'redcode', b'Redcode'), (b'registry', b'reg'), (b'resource', b'ResourceBundle'), (b'rexx', b'Rexx'), (b'rhtml', b'RHTML'), (b'rnc', b'Relax-NG Compact'), (b'roboconf-graph', b'Roboconf Graph'), (b'roboconf-instances', b'Roboconf Instances'), (b'robotframework', b'RobotFramework'), (b'rql', b'RQL'), (b'rsl', b'RSL'), (b'rst', b'reStructuredText'), (b'rts', b'TrafficScript'), (b'rust', b'Rust'), (b'sas', b'SAS'), (b'sass', b'Sass'), (b'sc', b'SuperCollider'), (b'scala', b'Scala'), (b'scaml', b'Scaml'), (b'scheme', b'Scheme'), (b'scilab', b'Scilab'), (b'scss', b'SCSS'), (b'shen', b'Shen'), (b'silver', b'Silver'), (b'slim', b'Slim'), (b'smali', b'Smali'), (b'smalltalk', b'Smalltalk'), (b'smarty', b'Smarty'), (b'sml', b'Standard ML'), (b'snobol', b'Snobol'), (b'snowball', b'Snowball'), (b'sourceslist', b'Debian Sourcelist'), (b'sp', b'SourcePawn'), (b'sparql', b'SPARQL'), (b'spec', b'RPMSpec'), (b'splus', b'S'), (b'sql', b'SQL'), (b'sqlite3', b'sqlite3con'), (b'squidconf', b'SquidConf'), (b'ssp', b'Scalate Server Page'), (b'stan', b'Stan'), (b'stata', b'Stata'), (b'swift', b'Swift'), (b'swig', b'SWIG'), (b'systemverilog', b'systemverilog'), (b'tads3', b'TADS 3'), (b'tap', b'TAP'), (b'tasm', b'TASM'), (b'tcl', b'Tcl'), (b'tcsh', b'Tcsh'), (b'tcshcon', b'Tcsh Session'), (b'tea', b'Tea'), (b'termcap', b'Termcap'), (b'terminfo', b'Terminfo'), (b'terraform', b'Terraform'), (b'tex', b'TeX'), (b'text', b'Text only'), (b'thrift', b'Thrift'), (b'todotxt', b'Todotxt'), (b'trac-wiki', b'MoinMoin/Trac Wiki markup'), (b'treetop', b'Treetop'), (b'ts', b'TypeScript'), (b'tsql', b'Transact-SQL'), (b'turtle', b'Turtle'), (b'twig', b'Twig'), (b'typoscript', b'TypoScript'), (b'typoscriptcssdata', b'TypoScriptCssData'), (b'typoscripthtmldata', b'TypoScriptHtmlData'), (b'urbiscript', b'UrbiScript'), (b'vala', b'Vala'), (b'vb.net', b'VB.net'), (b'vcl', b'VCL'), (b'vclsnippets', b'VCLSnippets'), (b'vctreestatus', b'VCTreeStatus'), (b'velocity', b'Velocity'), (b'verilog', b'verilog'), (b'vgl', b'VGL'), (b'vhdl', b'vhdl'), (b'vim', b'VimL'), (b'wdiff', b'WDiff'), (b'whiley', b'Whiley'), (b'x10', b'X10'), (b'xml', b'XML'), (b'xml+cheetah', b'XML+Cheetah'), (b'xml+django', b'XML+Django/Jinja'), (b'xml+erb', b'XML+Ruby'), (b'xml+evoque', b'XML+Evoque'), (b'xml+lasso', b'XML+Lasso'), (b'xml+mako', b'XML+Mako'), (b'xml+myghty', b'XML+Myghty'), (b'xml+php', b'XML+PHP'), (b'xml+smarty', b'XML+Smarty'), (b'xml+velocity', b'XML+Velocity'), (b'xquery', b'XQuery'), (b'xslt', b'XSLT'), (b'xtend', b'Xtend'), (b'xul+mozpreproc', b'XUL+mozpreproc'), (b'yaml', b'YAML'), (b'yaml+jinja', b'YAML+Jinja'), (b'zephir', b'Zephir')], default=b'python', max_length=100)), diff --git a/snippets/urls.py b/snippets/urls.py index af10ee5b9..5ad33a1a0 100644 --- a/snippets/urls.py +++ b/snippets/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls import include, url +from django.urls import include, path from rest_framework.routers import DefaultRouter from snippets import views @@ -11,5 +11,5 @@ # The API URLs are now determined automatically by the router. # Additionally, we include the login URLs for the browsable API. urlpatterns = [ - url(r'^', include(router.urls)) + path('', include(router.urls)) ] diff --git a/snippets/views.py b/snippets/views.py index e7ede113c..33c9aa9a2 100644 --- a/snippets/views.py +++ b/snippets/views.py @@ -1,6 +1,6 @@ from django.contrib.auth.models import User from rest_framework import permissions, renderers, viewsets -from rest_framework.decorators import detail_route +from rest_framework.decorators import action from rest_framework.response import Response from snippets.models import Snippet @@ -21,7 +21,7 @@ class SnippetViewSet(viewsets.ModelViewSet): permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly, ) - @detail_route(renderer_classes=[renderers.StaticHTMLRenderer]) + @action(detail=True, renderer_classes=[renderers.StaticHTMLRenderer]) def highlight(self, request, *args, **kwargs): snippet = self.get_object() return Response(snippet.highlighted) diff --git a/tutorial/asgi.py b/tutorial/asgi.py new file mode 100644 index 000000000..ec8a88069 --- /dev/null +++ b/tutorial/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for tutorial project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/stable/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tutorial.settings") + +application = get_asgi_application() diff --git a/tutorial/settings.py b/tutorial/settings.py index e2b5663f2..feb2a9c1f 100644 --- a/tutorial/settings.py +++ b/tutorial/settings.py @@ -1,13 +1,11 @@ """ Django settings for tutorial project. -Generated by 'django-admin startproject' using Django 1.11.7. - For more information on this file, see -https://docs.djangoproject.com/en/1.11/topics/settings/ +https://docs.djangoproject.com/en/stable/topics/settings/ For the full list of settings and their values, see -https://docs.djangoproject.com/en/1.11/ref/settings/ +https://docs.djangoproject.com/en/stable/ref/settings/ """ import os @@ -19,7 +17,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ +# See https://docs.djangoproject.com/en/stable/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = '^+%!mnsrflamqkz!)dv&7kxt%zct-^)_c41+e59nxx$#%r0z*u' @@ -40,6 +38,7 @@ 'whitenoise.runserver_nostatic', 'django.contrib.staticfiles', 'rest_framework', + 'drf_spectacular', 'snippets.apps.SnippetsConfig', ] @@ -75,7 +74,7 @@ WSGI_APPLICATION = 'tutorial.wsgi.application' # Database -# https://docs.djangoproject.com/en/1.11/ref/settings/#databases +# https://docs.djangoproject.com/en/stable/ref/settings/#databases DATABASES = { 'default': @@ -83,9 +82,10 @@ default='sqlite:///{}'.format(os.path.join(BASE_DIR, 'db.sqlite3')) ) } +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" # Password validation -# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators +# https://docs.djangoproject.com/en/stable/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { @@ -107,20 +107,18 @@ ] # Internationalization -# https://docs.djangoproject.com/en/1.11/topics/i18n/ +# https://docs.djangoproject.com/en/stable/topics/i18n/ LANGUAGE_CODE = 'en-us' +USE_TZ = True TIME_ZONE = 'UTC' USE_I18N = True -USE_L10N = True - -USE_TZ = True # Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/1.11/howto/static-files/ +# https://docs.djangoproject.com/en/stable/howto/static-files/ STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') @@ -130,6 +128,15 @@ 'PAGE_SIZE': 10, 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', + 'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema', +} + +# DRF Spectacular settings +SPECTACULAR_SETTINGS = { + 'TITLE': 'Pastebin API', + 'DESCRIPTION': 'A Web API for creating and viewing highlighted code snippets.', + 'VERSION': '1.0.0', + 'SERVE_INCLUDE_SCHEMA': False, } if ENVIRONMENT == 'production': diff --git a/tutorial/urls.py b/tutorial/urls.py index 254041929..3a5330e09 100644 --- a/tutorial/urls.py +++ b/tutorial/urls.py @@ -1,14 +1,9 @@ -from django.conf.urls import include, url -from rest_framework.schemas import get_schema_view -from rest_framework.documentation import include_docs_urls - -API_TITLE = 'Pastebin API' -API_DESCRIPTION = 'A Web API for creating and viewing highlighted code snippets.' -schema_view = get_schema_view(title=API_TITLE) +from django.urls import include, path +from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView urlpatterns = [ - url(r'^', include('snippets.urls')), - url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), - url(r'^schema/$', schema_view), - url(r'^docs/', include_docs_urls(title=API_TITLE, description=API_DESCRIPTION)) + path('', include('snippets.urls')), + path('api-auth/', include('rest_framework.urls', namespace='rest_framework')), + path('schema/', SpectacularAPIView.as_view(), name='schema'), + path('docs/', SpectacularSwaggerView.as_view(url_name='schema')) ] diff --git a/tutorial/wsgi.py b/tutorial/wsgi.py index 16ffe0915..6e3564966 100644 --- a/tutorial/wsgi.py +++ b/tutorial/wsgi.py @@ -4,7 +4,7 @@ It exposes the WSGI callable as a module-level variable named ``application``. For more information on this file, see -https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/ +https://docs.djangoproject.com/en/stable/howto/deployment/wsgi/ """ import os diff --git a/uv.lock b/uv.lock new file mode 100644 index 000000000..65c52b2f8 --- /dev/null +++ b/uv.lock @@ -0,0 +1,323 @@ +version = 1 +revision = 3 +requires-python = "==3.13.*" + +[[package]] +name = "asgiref" +version = "3.11.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/63/40/f03da1264ae8f7cfdbf9146542e5e7e8100a4c66ab48e791df9a03d3f6c0/asgiref-3.11.1.tar.gz", hash = "sha256:5f184dc43b7e763efe848065441eac62229c9f7b0475f41f80e207a114eda4ce", size = 38550, upload-time = "2026-02-03T13:30:14.33Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/0a/a72d10ed65068e115044937873362e6e32fab1b7dce0046aeb224682c989/asgiref-3.11.1-py3-none-any.whl", hash = "sha256:e8667a091e69529631969fd45dc268fa79b99c92c5fcdda727757e52146ec133", size = 24345, upload-time = "2026-02-03T13:30:13.039Z" }, +] + +[[package]] +name = "attrs" +version = "25.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" }, +] + +[[package]] +name = "dj-database-url" +version = "3.1.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/03/f6/00b625e9d371b980aa261011d0dc906a16444cb688f94215e0dc86996eb5/dj_database_url-3.1.2.tar.gz", hash = "sha256:63c20e4bbaa51690dfd4c8d189521f6bf6bc9da9fcdb23d95d2ee8ee87f9ec62", size = 11490, upload-time = "2026-02-19T15:30:23.638Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cf/a9/57c66006373381f1d3e5bd94216f1d371228a89f443d3030e010f73dd198/dj_database_url-3.1.2-py3-none-any.whl", hash = "sha256:544e015fee3efa5127a1eb1cca465f4ace578265b3671fe61d0ed7dbafb5ec8a", size = 8953, upload-time = "2026-02-19T15:30:39.37Z" }, +] + +[[package]] +name = "django" +version = "6.0.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asgiref" }, + { name = "sqlparse" }, + { name = "tzdata", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/f1/bf85f0d29ef76abf901f193fe8fef4769d3da7794197832bc30151c071d8/django-6.0.5.tar.gz", hash = "sha256:bc6d6872e98a2864c836e42edd644b362db311147dd5aa8d5b82ba7a032f5269", size = 10924131, upload-time = "2026-05-05T13:54:39.329Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/5b/1328f8b84fce040c404f76822bf8c57d254e368e8cbd8bd67ec2b26d75f5/django-6.0.5-py3-none-any.whl", hash = "sha256:9d58a7cb49244e74c8e161d5e403a46d6209f1009ba40f5a66d6aa0d0786a8f0", size = 8368680, upload-time = "2026-05-05T13:54:33.532Z" }, +] + +[[package]] +name = "djangorestframework" +version = "3.17.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ca/d7/c016e69fac19ff8afdc89db9d31d9ae43ae031e4d1993b20aca179b8301a/djangorestframework-3.17.1.tar.gz", hash = "sha256:a6def5f447fe78ff853bff1d47a3c59bf38f5434b031780b351b0c73a62db1a5", size = 905742, upload-time = "2026-03-24T16:58:33.705Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/e1/2c516bdc83652b1a60c6119366ac2c0607b479ed05cd6093f916ca8928f8/djangorestframework-3.17.1-py3-none-any.whl", hash = "sha256:c3c74dd3e83a5a3efc37b3c18d92bd6f86a6791c7b7d4dff62bb068500e76457", size = 898844, upload-time = "2026-03-24T16:58:31.845Z" }, +] + +[[package]] +name = "drf-spectacular" +version = "0.29.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, + { name = "djangorestframework" }, + { name = "inflection" }, + { name = "jsonschema" }, + { name = "pyyaml" }, + { name = "uritemplate" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/0e/a4f50d83e76cbe797eda88fc0083c8ca970cfa362b5586359ef06ec6f70a/drf_spectacular-0.29.0.tar.gz", hash = "sha256:0a069339ea390ce7f14a75e8b5af4a0860a46e833fd4af027411a3e94fc1a0cc", size = 241722, upload-time = "2025-11-02T03:40:26.348Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/d9/502c56fc3ca960075d00956283f1c44e8cafe433dada03f9ed2821f3073b/drf_spectacular-0.29.0-py3-none-any.whl", hash = "sha256:d1ee7c9535d89848affb4427347f7c4a22c5d22530b8842ef133d7b72e19b41a", size = 105433, upload-time = "2025-11-02T03:40:24.823Z" }, +] + +[[package]] +name = "gunicorn" +version = "26.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6d/b7/a4a3f632f823e432ce6bc65f62961b7980c898c77f075a2f7118cb3846fe/gunicorn-26.0.0.tar.gz", hash = "sha256:ca9346f85e3a4aeeb64d491045c16b9a35647abd37ea15efe53080eb8b090baf", size = 727286, upload-time = "2026-05-05T06:38:25.529Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/40/9c2384fc2be4ad25dd4a49decd5ad9ea5a3639814c11bd40ab77cb9f0a14/gunicorn-26.0.0-py3-none-any.whl", hash = "sha256:40233d26a5f0d1872916188c276e21641155111c2853f0c2cd55260aec0d24fc", size = 212009, upload-time = "2026-05-05T06:38:23.007Z" }, +] + +[[package]] +name = "inflection" +version = "0.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e1/7e/691d061b7329bc8d54edbf0ec22fbfb2afe61facb681f9aaa9bff7a27d04/inflection-0.5.1.tar.gz", hash = "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417", size = 15091, upload-time = "2020-08-22T08:16:29.139Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/59/91/aa6bde563e0085a02a435aa99b49ef75b0a4b062635e606dab23ce18d720/inflection-0.5.1-py2.py3-none-any.whl", hash = "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2", size = 9454, upload-time = "2020-08-22T08:16:27.816Z" }, +] + +[[package]] +name = "jsonschema" +version = "4.26.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583, upload-time = "2026-01-07T13:41:07.246Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630, upload-time = "2026-01-07T13:41:05.306Z" }, +] + +[[package]] +name = "jsonschema-specifications" +version = "2025.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "referencing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, +] + +[[package]] +name = "markdown" +version = "3.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2b/f4/69fa6ed85ae003c2378ffa8f6d2e3234662abd02c10d216c0ba96081a238/markdown-3.10.2.tar.gz", hash = "sha256:994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950", size = 368805, upload-time = "2026-02-09T14:57:26.942Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl", hash = "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36", size = 108180, upload-time = "2026-02-09T14:57:25.787Z" }, +] + +[[package]] +name = "packaging" +version = "26.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" }, +] + +[[package]] +name = "psycopg" +version = "3.3.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tzdata", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/db/2f/cb91e5502ec9de1de6f1b76cfbf69531932725361168bb06963620c77e2e/psycopg-3.3.4.tar.gz", hash = "sha256:e21207764952cff81b6b8bdacad9a3939f2793367fdac2987b3aac36a651b5bc", size = 165799, upload-time = "2026-05-01T23:31:55.179Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/e0/7b3dee031daae7743609ce3c746565d4a3ed7c2c186479eb48e34e838c64/psycopg-3.3.4-py3-none-any.whl", hash = "sha256:b6bbc25ccf05c8fad3b061d9db2ef0909a555171b84b07f29458a447253d679a", size = 213001, upload-time = "2026-05-01T23:20:50.816Z" }, +] + +[package.optional-dependencies] +binary = [ + { name = "psycopg-binary", marker = "implementation_name != 'pypy'" }, +] + +[[package]] +name = "psycopg-binary" +version = "3.3.4" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/09/43/13e9c406fbbf354580476e248a16b64802a376873ebe6339e30bb655572d/psycopg_binary-3.3.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fbd1d4ed566895ad2d3bf4ddfd8bae90026930ddf29df3b9d91d32c8c47866a7", size = 4590377, upload-time = "2026-05-01T23:29:18.782Z" }, + { url = "https://files.pythonhosted.org/packages/22/be/2923cd7c3683e7afdecf4f10796a18de02f5c5ddc0969aa2ad0a8cdd3bbd/psycopg_binary-3.3.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:75a9067e236f9b9ae3535b66fe99bddb33d39c0de10112e49b9ab11eee53dc31", size = 4669023, upload-time = "2026-05-01T23:29:25.884Z" }, + { url = "https://files.pythonhosted.org/packages/96/a0/2c913d6fe13d6a8bd13597d36739bf47af063ad9399e402cfecab16f3c1e/psycopg_binary-3.3.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:b56b603ebcea8aa10b46228b8410ba7f13e7c2ee54389d4d9be0927fd8ce2a70", size = 5467423, upload-time = "2026-05-01T23:29:33.416Z" }, + { url = "https://files.pythonhosted.org/packages/e7/38/205d10bc1ad0df4a21c5c51659126bd3ea0ef98fcad1e852f78c249bb9c3/psycopg_binary-3.3.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c677c4ad433cb7150c8cd304a0769ae3bcfbe5ea0676eb53faa7b1443b16d0d3", size = 5151137, upload-time = "2026-05-01T23:29:42.013Z" }, + { url = "https://files.pythonhosted.org/packages/36/fc/f0381ddcd45eff3bb70dbca6823a996048d7f507b2ec3fc92c6fabc0fe87/psycopg_binary-3.3.4-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:26df2717e59c0473e4465a97dfb1b7afebaa479277870fd5784d1436470db47c", size = 6736671, upload-time = "2026-05-01T23:29:51.626Z" }, + { url = "https://files.pythonhosted.org/packages/95/40/fa545ae152c24327651e5624e4902121e808270be36c10b12e9939be09bc/psycopg_binary-3.3.4-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1dc1f79fd16bb1f3f4421417a514607539f17804d95c7ed617265369d1981cae", size = 4979601, upload-time = "2026-05-01T23:29:56.961Z" }, + { url = "https://files.pythonhosted.org/packages/86/e4/2f8a47ee97f90cd2b933d0463081d35631ff419de2b8c984a5f369857de0/psycopg_binary-3.3.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:136f199a407b5348b9b857c504aff60c77622a28482e7195839ce1b51238c4cc", size = 4510513, upload-time = "2026-05-01T23:30:07.243Z" }, + { url = "https://files.pythonhosted.org/packages/0e/0e/94e842ff4a7f98ed162580ca2e8b8864b28c1e0350f2443f8ee47f821167/psycopg_binary-3.3.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b6f5a29e9c775b9f12a1a717aa7a2c80f9e1db6f27ba44a5b59c80ac61d2ffcf", size = 4187243, upload-time = "2026-05-01T23:30:15.352Z" }, + { url = "https://files.pythonhosted.org/packages/d0/83/fc6c174b672e29b7de996ea77b6cbddf46c891751c3355f6974292baa6b4/psycopg_binary-3.3.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:ee17a2cf4943cde261adfad1bbc5bf38d6b3776d7afff74c7cabcbeaeb08c260", size = 3927347, upload-time = "2026-05-01T23:30:21.186Z" }, + { url = "https://files.pythonhosted.org/packages/e9/65/768364d4a97a15b1a7f47ba52688c1686f22941d8332a8398cefc468e25f/psycopg_binary-3.3.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5c4ab71be17bdca30cb34c34c4e1496e2f5d6f20c199c12bad226070b22ef9bf", size = 4236393, upload-time = "2026-05-01T23:30:26.211Z" }, + { url = "https://files.pythonhosted.org/packages/bd/3b/218efbc9e645becd80cdf651acda05f85cfe546b7a9c0458c7cbc8fe1f74/psycopg_binary-3.3.4-cp313-cp313-win_amd64.whl", hash = "sha256:dbfdb9b6cc79f31104a7b162a2b921b765fcc62af6c00540a167a8de47e4ed38", size = 3564592, upload-time = "2026-05-01T23:30:31.764Z" }, +] + +[[package]] +name = "pygments" +version = "2.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, +] + +[[package]] +name = "referencing" +version = "0.37.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" }, +] + +[[package]] +name = "rest-framework-tutorial" +version = "1.0.0" +source = { virtual = "." } +dependencies = [ + { name = "dj-database-url" }, + { name = "django" }, + { name = "djangorestframework" }, + { name = "drf-spectacular" }, + { name = "gunicorn" }, + { name = "inflection" }, + { name = "markdown" }, + { name = "psycopg", extra = ["binary"] }, + { name = "pygments" }, + { name = "pyyaml" }, + { name = "whitenoise" }, +] + +[package.metadata] +requires-dist = [ + { name = "dj-database-url", specifier = "==3.1.2" }, + { name = "django", specifier = "==6.0.5" }, + { name = "djangorestframework", specifier = "==3.17.1" }, + { name = "drf-spectacular", specifier = "==0.29.0" }, + { name = "gunicorn", specifier = "==26.0.0" }, + { name = "inflection", specifier = "==0.5.1" }, + { name = "markdown", specifier = "==3.10.2" }, + { name = "psycopg", extras = ["binary"], specifier = "==3.3.4" }, + { name = "pygments", specifier = "==2.20.0" }, + { name = "pyyaml", specifier = "==6.0.3" }, + { name = "whitenoise", specifier = "==6.12.0" }, +] + +[[package]] +name = "rpds-py" +version = "0.30.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469, upload-time = "2025-11-30T20:24:38.837Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/dc/d61221eb88ff410de3c49143407f6f3147acf2538c86f2ab7ce65ae7d5f9/rpds_py-0.30.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f83424d738204d9770830d35290ff3273fbb02b41f919870479fab14b9d303b2", size = 374887, upload-time = "2025-11-30T20:22:41.812Z" }, + { url = "https://files.pythonhosted.org/packages/fd/32/55fb50ae104061dbc564ef15cc43c013dc4a9f4527a1f4d99baddf56fe5f/rpds_py-0.30.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7536cd91353c5273434b4e003cbda89034d67e7710eab8761fd918ec6c69cf8", size = 358904, upload-time = "2025-11-30T20:22:43.479Z" }, + { url = "https://files.pythonhosted.org/packages/58/70/faed8186300e3b9bdd138d0273109784eea2396c68458ed580f885dfe7ad/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2771c6c15973347f50fece41fc447c054b7ac2ae0502388ce3b6738cd366e3d4", size = 389945, upload-time = "2025-11-30T20:22:44.819Z" }, + { url = "https://files.pythonhosted.org/packages/bd/a8/073cac3ed2c6387df38f71296d002ab43496a96b92c823e76f46b8af0543/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a59119fc6e3f460315fe9d08149f8102aa322299deaa5cab5b40092345c2136", size = 407783, upload-time = "2025-11-30T20:22:46.103Z" }, + { url = "https://files.pythonhosted.org/packages/77/57/5999eb8c58671f1c11eba084115e77a8899d6e694d2a18f69f0ba471ec8b/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76fec018282b4ead0364022e3c54b60bf368b9d926877957a8624b58419169b7", size = 515021, upload-time = "2025-11-30T20:22:47.458Z" }, + { url = "https://files.pythonhosted.org/packages/e0/af/5ab4833eadc36c0a8ed2bc5c0de0493c04f6c06de223170bd0798ff98ced/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:692bef75a5525db97318e8cd061542b5a79812d711ea03dbc1f6f8dbb0c5f0d2", size = 414589, upload-time = "2025-11-30T20:22:48.872Z" }, + { url = "https://files.pythonhosted.org/packages/b7/de/f7192e12b21b9e9a68a6d0f249b4af3fdcdff8418be0767a627564afa1f1/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9027da1ce107104c50c81383cae773ef5c24d296dd11c99e2629dbd7967a20c6", size = 394025, upload-time = "2025-11-30T20:22:50.196Z" }, + { url = "https://files.pythonhosted.org/packages/91/c4/fc70cd0249496493500e7cc2de87504f5aa6509de1e88623431fec76d4b6/rpds_py-0.30.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:9cf69cdda1f5968a30a359aba2f7f9aa648a9ce4b580d6826437f2b291cfc86e", size = 408895, upload-time = "2025-11-30T20:22:51.87Z" }, + { url = "https://files.pythonhosted.org/packages/58/95/d9275b05ab96556fefff73a385813eb66032e4c99f411d0795372d9abcea/rpds_py-0.30.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a4796a717bf12b9da9d3ad002519a86063dcac8988b030e405704ef7d74d2d9d", size = 422799, upload-time = "2025-11-30T20:22:53.341Z" }, + { url = "https://files.pythonhosted.org/packages/06/c1/3088fc04b6624eb12a57eb814f0d4997a44b0d208d6cace713033ff1a6ba/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d4c2aa7c50ad4728a094ebd5eb46c452e9cb7edbfdb18f9e1221f597a73e1e7", size = 572731, upload-time = "2025-11-30T20:22:54.778Z" }, + { url = "https://files.pythonhosted.org/packages/d8/42/c612a833183b39774e8ac8fecae81263a68b9583ee343db33ab571a7ce55/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ba81a9203d07805435eb06f536d95a266c21e5b2dfbf6517748ca40c98d19e31", size = 599027, upload-time = "2025-11-30T20:22:56.212Z" }, + { url = "https://files.pythonhosted.org/packages/5f/60/525a50f45b01d70005403ae0e25f43c0384369ad24ffe46e8d9068b50086/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:945dccface01af02675628334f7cf49c2af4c1c904748efc5cf7bbdf0b579f95", size = 563020, upload-time = "2025-11-30T20:22:58.2Z" }, + { url = "https://files.pythonhosted.org/packages/0b/5d/47c4655e9bcd5ca907148535c10e7d489044243cc9941c16ed7cd53be91d/rpds_py-0.30.0-cp313-cp313-win32.whl", hash = "sha256:b40fb160a2db369a194cb27943582b38f79fc4887291417685f3ad693c5a1d5d", size = 223139, upload-time = "2025-11-30T20:23:00.209Z" }, + { url = "https://files.pythonhosted.org/packages/f2/e1/485132437d20aa4d3e1d8b3fb5a5e65aa8139f1e097080c2a8443201742c/rpds_py-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:806f36b1b605e2d6a72716f321f20036b9489d29c51c91f4dd29a3e3afb73b15", size = 240224, upload-time = "2025-11-30T20:23:02.008Z" }, + { url = "https://files.pythonhosted.org/packages/24/95/ffd128ed1146a153d928617b0ef673960130be0009c77d8fbf0abe306713/rpds_py-0.30.0-cp313-cp313-win_arm64.whl", hash = "sha256:d96c2086587c7c30d44f31f42eae4eac89b60dabbac18c7669be3700f13c3ce1", size = 230645, upload-time = "2025-11-30T20:23:03.43Z" }, + { url = "https://files.pythonhosted.org/packages/ff/1b/b10de890a0def2a319a2626334a7f0ae388215eb60914dbac8a3bae54435/rpds_py-0.30.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:eb0b93f2e5c2189ee831ee43f156ed34e2a89a78a66b98cadad955972548be5a", size = 364443, upload-time = "2025-11-30T20:23:04.878Z" }, + { url = "https://files.pythonhosted.org/packages/0d/bf/27e39f5971dc4f305a4fb9c672ca06f290f7c4e261c568f3dea16a410d47/rpds_py-0.30.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:922e10f31f303c7c920da8981051ff6d8c1a56207dbdf330d9047f6d30b70e5e", size = 353375, upload-time = "2025-11-30T20:23:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/40/58/442ada3bba6e8e6615fc00483135c14a7538d2ffac30e2d933ccf6852232/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdc62c8286ba9bf7f47befdcea13ea0e26bf294bda99758fd90535cbaf408000", size = 383850, upload-time = "2025-11-30T20:23:07.825Z" }, + { url = "https://files.pythonhosted.org/packages/14/14/f59b0127409a33c6ef6f5c1ebd5ad8e32d7861c9c7adfa9a624fc3889f6c/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47f9a91efc418b54fb8190a6b4aa7813a23fb79c51f4bb84e418f5476c38b8db", size = 392812, upload-time = "2025-11-30T20:23:09.228Z" }, + { url = "https://files.pythonhosted.org/packages/b3/66/e0be3e162ac299b3a22527e8913767d869e6cc75c46bd844aa43fb81ab62/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f3587eb9b17f3789ad50824084fa6f81921bbf9a795826570bda82cb3ed91f2", size = 517841, upload-time = "2025-11-30T20:23:11.186Z" }, + { url = "https://files.pythonhosted.org/packages/3d/55/fa3b9cf31d0c963ecf1ba777f7cf4b2a2c976795ac430d24a1f43d25a6ba/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39c02563fc592411c2c61d26b6c5fe1e51eaa44a75aa2c8735ca88b0d9599daa", size = 408149, upload-time = "2025-11-30T20:23:12.864Z" }, + { url = "https://files.pythonhosted.org/packages/60/ca/780cf3b1a32b18c0f05c441958d3758f02544f1d613abf9488cd78876378/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51a1234d8febafdfd33a42d97da7a43f5dcb120c1060e352a3fbc0c6d36e2083", size = 383843, upload-time = "2025-11-30T20:23:14.638Z" }, + { url = "https://files.pythonhosted.org/packages/82/86/d5f2e04f2aa6247c613da0c1dd87fcd08fa17107e858193566048a1e2f0a/rpds_py-0.30.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:eb2c4071ab598733724c08221091e8d80e89064cd472819285a9ab0f24bcedb9", size = 396507, upload-time = "2025-11-30T20:23:16.105Z" }, + { url = "https://files.pythonhosted.org/packages/4b/9a/453255d2f769fe44e07ea9785c8347edaf867f7026872e76c1ad9f7bed92/rpds_py-0.30.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bdfdb946967d816e6adf9a3d8201bfad269c67efe6cefd7093ef959683c8de0", size = 414949, upload-time = "2025-11-30T20:23:17.539Z" }, + { url = "https://files.pythonhosted.org/packages/a3/31/622a86cdc0c45d6df0e9ccb6becdba5074735e7033c20e401a6d9d0e2ca0/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c77afbd5f5250bf27bf516c7c4a016813eb2d3e116139aed0096940c5982da94", size = 565790, upload-time = "2025-11-30T20:23:19.029Z" }, + { url = "https://files.pythonhosted.org/packages/1c/5d/15bbf0fb4a3f58a3b1c67855ec1efcc4ceaef4e86644665fff03e1b66d8d/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:61046904275472a76c8c90c9ccee9013d70a6d0f73eecefd38c1ae7c39045a08", size = 590217, upload-time = "2025-11-30T20:23:20.885Z" }, + { url = "https://files.pythonhosted.org/packages/6d/61/21b8c41f68e60c8cc3b2e25644f0e3681926020f11d06ab0b78e3c6bbff1/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c5f36a861bc4b7da6516dbdf302c55313afa09b81931e8280361a4f6c9a2d27", size = 555806, upload-time = "2025-11-30T20:23:22.488Z" }, + { url = "https://files.pythonhosted.org/packages/f9/39/7e067bb06c31de48de3eb200f9fc7c58982a4d3db44b07e73963e10d3be9/rpds_py-0.30.0-cp313-cp313t-win32.whl", hash = "sha256:3d4a69de7a3e50ffc214ae16d79d8fbb0922972da0356dcf4d0fdca2878559c6", size = 211341, upload-time = "2025-11-30T20:23:24.449Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4d/222ef0b46443cf4cf46764d9c630f3fe4abaa7245be9417e56e9f52b8f65/rpds_py-0.30.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f14fc5df50a716f7ece6a80b6c78bb35ea2ca47c499e422aa4463455dd96d56d", size = 225768, upload-time = "2025-11-30T20:23:25.908Z" }, +] + +[[package]] +name = "sqlparse" +version = "0.5.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/90/76/437d71068094df0726366574cf3432a4ed754217b436eb7429415cf2d480/sqlparse-0.5.5.tar.gz", hash = "sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e", size = 120815, upload-time = "2025-12-19T07:17:45.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl", hash = "sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba", size = 46138, upload-time = "2025-12-19T07:17:46.573Z" }, +] + +[[package]] +name = "tzdata" +version = "2025.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772, upload-time = "2025-12-13T17:45:35.667Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" }, +] + +[[package]] +name = "uritemplate" +version = "4.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/98/60/f174043244c5306c9988380d2cb10009f91563fc4b31293d27e17201af56/uritemplate-4.2.0.tar.gz", hash = "sha256:480c2ed180878955863323eea31b0ede668795de182617fef9c6ca09e6ec9d0e", size = 33267, upload-time = "2025-06-02T15:12:06.318Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/99/3ae339466c9183ea5b8ae87b34c0b897eda475d2aec2307cae60e5cd4f29/uritemplate-4.2.0-py3-none-any.whl", hash = "sha256:962201ba1c4edcab02e60f9a0d3821e82dfc5d2d6662a21abd533879bdb8a686", size = 11488, upload-time = "2025-06-02T15:12:03.405Z" }, +] + +[[package]] +name = "whitenoise" +version = "6.12.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cb/2a/55b3f3a4ec326cd077c1c3defeee656b9298372a69229134d930151acd01/whitenoise-6.12.0.tar.gz", hash = "sha256:f723ebb76a112e98816ff80fcea0a6c9b8ecde835f8ddda25df7a30a3c2db6ad", size = 26841, upload-time = "2026-02-27T00:05:42.028Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/eb/d5583a11486211f3ebd4b385545ae787f32363d453c19fffd81106c9c138/whitenoise-6.12.0-py3-none-any.whl", hash = "sha256:fc5e8c572e33ebf24795b47b6a7da8da3c00cff2349f5b04c02f28d0cc5a3cc2", size = 20302, upload-time = "2026-02-27T00:05:40.086Z" }, +]