diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7ebb80efd..032db9c9c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -42,7 +42,12 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.8", "3.9", "3.10", "3.11"] + python-version: + - "3.12" + - "3.11" + - "3.10" + - "3.9" + - "3.8" pydantic-version: ["pydantic-v1", "pydantic-v2"] fail-fast: false steps: diff --git a/docs/bn/docs/index.md b/docs/bn/docs/index.md new file mode 100644 index 000000000..4f778e873 --- /dev/null +++ b/docs/bn/docs/index.md @@ -0,0 +1,464 @@ +
++ FastAPI উচ্চক্ষমতা সম্পন্ন, সহজে শেখার এবং দ্রুত কোড করে প্রোডাকশনের জন্য ফ্রামওয়ার্ক। +
+ + +--- + +**নির্দেশিকা নথি**: https://fastapi.tiangolo.com + +**সোর্স কোড**: https://github.com/tiangolo/fastapi + +--- + +FastAPI একটি আধুনিক, দ্রুত ( বেশি ক্ষমতা ) সম্পন্ন, Python 3.6+ দিয়ে API তৈরির জন্য স্ট্যান্ডার্ড পাইথন টাইপ ইঙ্গিত ভিত্তিক ওয়েব ফ্রেমওয়ার্ক। + +এর মূল বৈশিষ্ট্য গুলো হলঃ + +- **গতি**: এটি **NodeJS** এবং **Go** এর মত কার্যক্ষমতা সম্পন্ন (Starlette এবং Pydantic এর সাহায্যে)। [পাইথন এর দ্রুততম ফ্রেমওয়ার্ক গুলোর মধ্যে এটি একটি](#_11)। +- **দ্রুত কোড করা**:বৈশিষ্ট্য তৈরির গতি ২০০% থেকে ৩০০% বৃদ্ধি করে৷ \* +- **স্বল্প bugs**: মানুব (ডেভেলপার) সৃষ্ট ত্রুটির প্রায় ৪০% হ্রাস করে। \* +- **স্বজ্ঞাত**: দুর্দান্ত এডিটর সাহায্য Completion নামেও পরিচিত। দ্রুত ডিবাগ করা যায়। + +- **সহজ**: এটি এমন ভাবে সজানো হয়েছে যেন নির্দেশিকা নথি পড়ে সহজে শেখা এবং ব্যবহার করা যায়। +- **সংক্ষিপ্ত**: কোড পুনরাবৃত্তি কমানোর পাশাপাশি, bug কমায় এবং প্রতিটি প্যারামিটার ঘোষণা থেকে একাধিক ফিচার পাওয়া যায় । +- **জোরালো**: স্বয়ংক্রিয় ভাবে তৈরি ক্রিয়াশীল নির্দেশনা নথি (documentation) সহ উৎপাদন উপযোগি (Production-ready) কোড পাওয়া যায়। +- **মান-ভিত্তিক**: এর ভিত্তি OpenAPI (যা পুর্বে Swagger নামে পরিচিত ছিল) এবং JSON Schema এর আদর্শের মানের ওপর + +\* উৎপাদনমুখি এপ্লিকেশন বানানোর এক দল ডেভেলপার এর মতামত ভিত্তিক ফলাফল। + +## স্পনসর গণ + + + +{% if sponsors %} +{% for sponsor in sponsors.gold -%} +async def...uvicorn main:app --reload...ujson - দ্রুত JSON এর জন্য "parsing".
+- email_validator - ইমেল যাচাইকরণের জন্য।
+
+স্টারলেট দ্বারা ব্যবহৃত:
+
+- httpx - আপনি যদি `TestClient` ব্যবহার করতে চান তাহলে আবশ্যক।
+- jinja2 - আপনি যদি প্রদত্ত টেমপ্লেট রূপরেখা ব্যবহার করতে চান তাহলে প্রয়োজন।
+- python-multipart - আপনি যদি ফর্ম সহায়তা করতে চান তাহলে প্রয়োজন "parsing", `request.form()` সহ।
+- itsdangerous - `SessionMiddleware` সহায়তার জন্য প্রয়োজন।
+- pyyaml - স্টারলেটের SchemaGenerator সাপোর্ট এর জন্য প্রয়োজন (আপনার সম্ভাবত FastAPI প্রয়োজন নেই)।
+- graphene - `GraphQLApp` সহায়তার জন্য প্রয়োজন।
+- ujson - আপনি `UJSONResponse` ব্যবহার করতে চাইলে প্রয়োজন।
+
+FastAPI / Starlette দ্বারা ব্যবহৃত:
+
+- uvicorn - সার্ভারের জন্য যা আপনার অ্যাপ্লিকেশন লোড করে এবং পরিবেশন করে।
+- orjson - আপনি `ORJSONResponse` ব্যবহার করতে চাইলে প্রয়োজন।
+
+আপনি এই সব ইনস্টল করতে পারেন `pip install fastapi[all]` দিয়ে.
+
+## লাইসেন্স
+
+এই প্রজেক্ট MIT লাইসেন্স নীতিমালার অধীনে শর্তায়িত।
diff --git a/docs/bn/mkdocs.yml b/docs/bn/mkdocs.yml
new file mode 100644
index 000000000..de18856f4
--- /dev/null
+++ b/docs/bn/mkdocs.yml
@@ -0,0 +1 @@
+INHERIT: ../en/mkdocs.yml
diff --git a/docs/en/data/external_links.yml b/docs/en/data/external_links.yml
index d53afd7f9..f15560d1b 100644
--- a/docs/en/data/external_links.yml
+++ b/docs/en/data/external_links.yml
@@ -1,5 +1,13 @@
Articles:
English:
+ - author: Visual Studio Code Team
+ author_link: https://code.visualstudio.com/
+ link: https://code.visualstudio.com/docs/python/tutorial-fastapi
+ title: FastAPI Tutorial in Visual Studio Code
+ - author: Apitally
+ author_link: https://apitally.io
+ link: https://blog.apitally.io/fastapi-application-monitoring-made-easy
+ title: FastAPI application monitoring made easy
- author: John Philip
author_link: https://medium.com/@amjohnphilip
link: https://python.plainenglish.io/building-a-restful-api-with-fastapi-secure-signup-and-login-functionality-included-45cdbcb36106
diff --git a/docs/en/docs/how-to/async-sql-encode-databases.md b/docs/en/docs/how-to/async-sql-encode-databases.md
index 697167f79..0e2ccce78 100644
--- a/docs/en/docs/how-to/async-sql-encode-databases.md
+++ b/docs/en/docs/how-to/async-sql-encode-databases.md
@@ -114,6 +114,11 @@ Create the *path operation function* to create notes:
{!../../../docs_src/async_sql_databases/tutorial001.py!}
```
+!!! info
+ In Pydantic v1 the method was called `.dict()`, it was deprecated (but still supported) in Pydantic v2, and renamed to `.model_dump()`.
+
+ The examples here use `.dict()` for compatibility with Pydantic v1, but you should use `.model_dump()` instead if you can use Pydantic v2.
+
!!! Note
Notice that as we communicate with the database using `await`, the *path operation function* is declared with `async`.
diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md
index 59de429ab..b523be75d 100644
--- a/docs/en/docs/release-notes.md
+++ b/docs/en/docs/release-notes.md
@@ -7,8 +7,19 @@ hide:
## Latest Changes
+### Features
+
+* ✨ Add support for Python 3.12. PR [#10666](https://github.com/tiangolo/fastapi/pull/10666) by [@Jamim](https://github.com/Jamim).
+
### Docs
+* 📝 Add VS Code tutorial link. PR [#10592](https://github.com/tiangolo/fastapi/pull/10592) by [@nilslindemann](https://github.com/nilslindemann).
+* 📝 Add notes about Pydantic v2's new `.model_dump()`. PR [#10929](https://github.com/tiangolo/fastapi/pull/10929) by [@tiangolo](https://github.com/tiangolo).
+* 📝 Fix broken link in `docs/en/docs/tutorial/sql-databases.md`. PR [#10765](https://github.com/tiangolo/fastapi/pull/10765) by [@HurSungYun](https://github.com/HurSungYun).
+* 📝 Add External Link: FastAPI application monitoring made easy. PR [#10917](https://github.com/tiangolo/fastapi/pull/10917) by [@tiangolo](https://github.com/tiangolo).
+* ✨ Generate automatic language names for docs translations. PR [#5354](https://github.com/tiangolo/fastapi/pull/5354) by [@jakul](https://github.com/jakul).
+* ✏️ Fix typos in `docs/en/docs/alternatives.md` and `docs/en/docs/tutorial/dependencies/index.md`. PR [#10906](https://github.com/tiangolo/fastapi/pull/10906) by [@s111d](https://github.com/s111d).
+* ✏️ Fix typos in `docs/en/docs/tutorial/dependencies/dependencies-with-yield.md`. PR [#10834](https://github.com/tiangolo/fastapi/pull/10834) by [@Molkree](https://github.com/Molkree).
* 📝 Add article: "Building a RESTful API with FastAPI: Secure Signup and Login Functionality Included". PR [#9733](https://github.com/tiangolo/fastapi/pull/9733) by [@dxphilo](https://github.com/dxphilo).
* 📝 Add warning about lifecycle events with `AsyncClient`. PR [#4167](https://github.com/tiangolo/fastapi/pull/4167) by [@andrew-chang-dewitt](https://github.com/andrew-chang-dewitt).
* ✏️ Fix typos in `/docs/reference/exceptions.md` and `/en/docs/reference/status.md`. PR [#10809](https://github.com/tiangolo/fastapi/pull/10809) by [@clarencepenz](https://github.com/clarencepenz).
@@ -22,6 +33,7 @@ hide:
### Translations
+* 🌐 Add Bengali translation for `docs/bn/docs/index.md`. PR [#9177](https://github.com/tiangolo/fastapi/pull/9177) by [@Fahad-Md-Kamal](https://github.com/Fahad-Md-Kamal).
* ✏️ Update Python version in `index.md` in several languages. PR [#10711](https://github.com/tiangolo/fastapi/pull/10711) by [@tamago3keran](https://github.com/tamago3keran).
* 🌐 Add Russian translation for `docs/ru/docs/tutorial/request-forms-and-files.md`. PR [#10347](https://github.com/tiangolo/fastapi/pull/10347) by [@AlertRED](https://github.com/AlertRED).
* 🌐 Add Ukrainian translation for `docs/uk/docs/index.md`. PR [#10362](https://github.com/tiangolo/fastapi/pull/10362) by [@rostik1410](https://github.com/rostik1410).
@@ -51,6 +63,7 @@ hide:
### Internal
+* 👥 Update FastAPI People. PR [#10871](https://github.com/tiangolo/fastapi/pull/10871) by [@tiangolo](https://github.com/tiangolo).
* 👷 Upgrade custom GitHub Action comment-docs-preview-in-pr. PR [#10916](https://github.com/tiangolo/fastapi/pull/10916) by [@tiangolo](https://github.com/tiangolo).
* ⬆️ Upgrade GitHub Action latest-changes. PR [#10915](https://github.com/tiangolo/fastapi/pull/10915) by [@tiangolo](https://github.com/tiangolo).
* 👷 Upgrade GitHub Action label-approved. PR [#10913](https://github.com/tiangolo/fastapi/pull/10913) by [@tiangolo](https://github.com/tiangolo).
diff --git a/docs/en/docs/tutorial/body-updates.md b/docs/en/docs/tutorial/body-updates.md
index 3341f2d5d..39d133c55 100644
--- a/docs/en/docs/tutorial/body-updates.md
+++ b/docs/en/docs/tutorial/body-updates.md
@@ -59,9 +59,14 @@ This means that you can send only the data that you want to update, leaving the
### Using Pydantic's `exclude_unset` parameter
-If you want to receive partial updates, it's very useful to use the parameter `exclude_unset` in Pydantic's model's `.dict()`.
+If you want to receive partial updates, it's very useful to use the parameter `exclude_unset` in Pydantic's model's `.model_dump()`.
-Like `item.dict(exclude_unset=True)`.
+Like `item.model_dump(exclude_unset=True)`.
+
+!!! info
+ In Pydantic v1 the method was called `.dict()`, it was deprecated (but still supported) in Pydantic v2, and renamed to `.model_dump()`.
+
+ The examples here use `.dict()` for compatibility with Pydantic v1, but you should use `.model_dump()` instead if you can use Pydantic v2.
That would generate a `dict` with only the data that was set when creating the `item` model, excluding default values.
@@ -87,9 +92,14 @@ Then you can use this to generate a `dict` with only the data that was set (sent
### Using Pydantic's `update` parameter
-Now, you can create a copy of the existing model using `.copy()`, and pass the `update` parameter with a `dict` containing the data to update.
+Now, you can create a copy of the existing model using `.model_copy()`, and pass the `update` parameter with a `dict` containing the data to update.
-Like `stored_item_model.copy(update=update_data)`:
+!!! info
+ In Pydantic v1 the method was called `.copy()`, it was deprecated (but still supported) in Pydantic v2, and renamed to `.model_copy()`.
+
+ The examples here use `.copy()` for compatibility with Pydantic v1, but you should use `.model_copy()` instead if you can use Pydantic v2.
+
+Like `stored_item_model.model_copy(update=update_data)`:
=== "Python 3.10+"
@@ -120,7 +130,7 @@ In summary, to apply partial updates you would:
* This way you can update only the values actually set by the user, instead of overriding values already stored with default values in your model.
* Create a copy of the stored model, updating it's attributes with the received partial updates (using the `update` parameter).
* Convert the copied model to something that can be stored in your DB (for example, using the `jsonable_encoder`).
- * This is comparable to using the model's `.dict()` method again, but it makes sure (and converts) the values to data types that can be converted to JSON, for example, `datetime` to `str`.
+ * This is comparable to using the model's `.model_dump()` method again, but it makes sure (and converts) the values to data types that can be converted to JSON, for example, `datetime` to `str`.
* Save the data to your DB.
* Return the updated model.
diff --git a/docs/en/docs/tutorial/extra-models.md b/docs/en/docs/tutorial/extra-models.md
index 590d095bd..d83b6bc85 100644
--- a/docs/en/docs/tutorial/extra-models.md
+++ b/docs/en/docs/tutorial/extra-models.md
@@ -29,6 +29,11 @@ Here's a general idea of how the models could look like with their password fiel
{!> ../../../docs_src/extra_models/tutorial001.py!}
```
+!!! info
+ In Pydantic v1 the method was called `.dict()`, it was deprecated (but still supported) in Pydantic v2, and renamed to `.model_dump()`.
+
+ The examples here use `.dict()` for compatibility with Pydantic v1, but you should use `.model_dump()` instead if you can use Pydantic v2.
+
### About `**user_in.dict()`
#### Pydantic's `.dict()`
diff --git a/docs/en/docs/tutorial/response-model.md b/docs/en/docs/tutorial/response-model.md
index d6d3d61cb..d5683ac7f 100644
--- a/docs/en/docs/tutorial/response-model.md
+++ b/docs/en/docs/tutorial/response-model.md
@@ -377,6 +377,11 @@ So, if you send a request to that *path operation* for the item with ID `foo`, t
}
```
+!!! info
+ In Pydantic v1 the method was called `.dict()`, it was deprecated (but still supported) in Pydantic v2, and renamed to `.model_dump()`.
+
+ The examples here use `.dict()` for compatibility with Pydantic v1, but you should use `.model_dump()` instead if you can use Pydantic v2.
+
!!! info
FastAPI uses Pydantic model's `.dict()` with its `exclude_unset` parameter to achieve this.
diff --git a/docs/en/docs/tutorial/sql-databases.md b/docs/en/docs/tutorial/sql-databases.md
index 010244bbf..1bc87a702 100644
--- a/docs/en/docs/tutorial/sql-databases.md
+++ b/docs/en/docs/tutorial/sql-databases.md
@@ -451,6 +451,11 @@ The steps are:
{!../../../docs_src/sql_databases/sql_app/crud.py!}
```
+!!! info
+ In Pydantic v1 the method was called `.dict()`, it was deprecated (but still supported) in Pydantic v2, and renamed to `.model_dump()`.
+
+ The examples here use `.dict()` for compatibility with Pydantic v1, but you should use `.model_dump()` instead if you can use Pydantic v2.
+
!!! tip
The SQLAlchemy model for `User` contains a `hashed_password` that should contain a secure hashed version of the password.
@@ -624,7 +629,7 @@ def read_user(user_id: int, db: Session = Depends(get_db)):
```
!!! info
- If you need to connect to your relational database asynchronously, see [Async SQL (Relational) Databases](../advanced/async-sql-databases.md){.internal-link target=_blank}.
+ If you need to connect to your relational database asynchronously, see [Async SQL (Relational) Databases](../how-to/async-sql-encode-databases.md){.internal-link target=_blank}.
!!! note "Very Technical Details"
If you are curious and have a deep technical knowledge, you can check the very technical details of how this `async def` vs `def` is handled in the [Async](../async.md#very-technical-details){.internal-link target=_blank} docs.
diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml
index a64eff269..92d081aa1 100644
--- a/docs/en/mkdocs.yml
+++ b/docs/en/mkdocs.yml
@@ -58,15 +58,18 @@ plugins:
python:
options:
extensions:
- - griffe_typingdoc
+ - griffe_typingdoc
show_root_heading: true
show_if_no_docstring: true
- preload_modules: [httpx, starlette]
+ preload_modules:
+ - httpx
+ - starlette
inherited_members: true
members_order: source
separate_signature: true
unwrap_annotated: true
- filters: ["!^_"]
+ filters:
+ - '!^_'
merge_init_into_class: true
docstring_section_style: spacy
signature_crossrefs: true
@@ -264,25 +267,25 @@ extra:
- link: /
name: en - English
- link: /de/
- name: de
- - link: /em/
- name: 😉
+ name: de - Deutsch
- link: /es/
name: es - español
- link: /fa/
- name: fa
+ name: fa - فارسی
- link: /fr/
name: fr - français
- link: /he/
- name: he
+ name: he - עברית
+ - link: /hu/
+ name: hu - magyar
- link: /id/
- name: id
+ name: id - Bahasa Indonesia
- link: /ja/
name: ja - 日本語
- link: /ko/
name: ko - 한국어
- link: /pl/
- name: pl
+ name: pl - Polski
- link: /pt/
name: pt - português
- link: /ru/
@@ -290,15 +293,17 @@ extra:
- link: /tr/
name: tr - Türkçe
- link: /uk/
- name: uk
+ name: uk - українська мова
- link: /ur/
- name: ur
+ name: ur - اردو
- link: /vi/
name: vi - Tiếng Việt
- link: /yo/
name: yo - Yorùbá
- link: /zh/
name: zh - 汉语
+ - link: /em/
+ name: 😉
extra_css:
- css/termynal.css
- css/custom.css
diff --git a/docs/language_names.yml b/docs/language_names.yml
new file mode 100644
index 000000000..fbbbde303
--- /dev/null
+++ b/docs/language_names.yml
@@ -0,0 +1,182 @@
+aa: Afaraf
+ab: аҧсуа бызшәа
+ae: avesta
+af: Afrikaans
+ak: Akan
+am: አማርኛ
+an: aragonés
+ar: اللغة العربية
+as: অসমীয়া
+av: авар мацӀ
+ay: aymar aru
+az: azərbaycan dili
+ba: башҡорт теле
+be: беларуская мова
+bg: български език
+bh: भोजपुरी
+bi: Bislama
+bm: bamanankan
+bn: বাংলা
+bo: བོད་ཡིག
+br: brezhoneg
+bs: bosanski jezik
+ca: Català
+ce: нохчийн мотт
+ch: Chamoru
+co: corsu
+cr: ᓀᐦᐃᔭᐍᐏᐣ
+cs: čeština
+cu: ѩзыкъ словѣньскъ
+cv: чӑваш чӗлхи
+cy: Cymraeg
+da: dansk
+de: Deutsch
+dv: Dhivehi
+dz: རྫོང་ཁ
+ee: Eʋegbe
+el: Ελληνικά
+en: English
+eo: Esperanto
+es: español
+et: eesti
+eu: euskara
+fa: فارسی
+ff: Fulfulde
+fi: suomi
+fj: Vakaviti
+fo: føroyskt
+fr: français
+fy: Frysk
+ga: Gaeilge
+gd: Gàidhlig
+gl: galego
+gu: ગુજરાતી
+gv: Gaelg
+ha: هَوُسَ
+he: עברית
+hi: हिन्दी
+ho: Hiri Motu
+hr: Hrvatski
+ht: Kreyòl ayisyen
+hu: magyar
+hy: Հայերեն
+hz: Otjiherero
+ia: Interlingua
+id: Bahasa Indonesia
+ie: Interlingue
+ig: Asụsụ Igbo
+ii: ꆈꌠ꒿ Nuosuhxop
+ik: Iñupiaq
+io: Ido
+is: Íslenska
+it: italiano
+iu: ᐃᓄᒃᑎᑐᑦ
+ja: 日本語
+jv: basa Jawa
+ka: ქართული
+kg: Kikongo
+ki: Gĩkũyũ
+kj: Kuanyama
+kk: қазақ тілі
+kl: kalaallisut
+km: ខេមរភាសា
+kn: ಕನ್ನಡ
+ko: 한국어
+kr: Kanuri
+ks: कश्मीरी
+ku: Kurdî
+kv: коми кыв
+kw: Kernewek
+ky: Кыргызча
+la: latine
+lb: Lëtzebuergesch
+lg: Luganda
+li: Limburgs
+ln: Lingála
+lo: ພາສາ
+lt: lietuvių kalba
+lu: Tshiluba
+lv: latviešu valoda
+mg: fiteny malagasy
+mh: Kajin M̧ajeļ
+mi: te reo Māori
+mk: македонски јазик
+ml: മലയാളം
+mn: Монгол хэл
+mr: मराठी
+ms: Bahasa Malaysia
+mt: Malti
+my: ဗမာစာ
+na: Ekakairũ Naoero
+nb: Norsk bokmål
+nd: isiNdebele
+ne: नेपाली
+ng: Owambo
+nl: Nederlands
+nn: Norsk nynorsk
+'no': Norsk
+nr: isiNdebele
+nv: Diné bizaad
+ny: chiCheŵa
+oc: occitan
+oj: ᐊᓂᔑᓈᐯᒧᐎᓐ
+om: Afaan Oromoo
+or: ଓଡ଼ିଆ
+os: ирон æвзаг
+pa: ਪੰਜਾਬੀ
+pi: पाऴि
+pl: Polski
+ps: پښتو
+pt: português
+qu: Runa Simi
+rm: rumantsch grischun
+rn: Ikirundi
+ro: Română
+ru: русский язык
+rw: Ikinyarwanda
+sa: संस्कृतम्
+sc: sardu
+sd: सिन्धी
+se: Davvisámegiella
+sg: yângâ tî sängö
+si: සිංහල
+sk: slovenčina
+sl: slovenščina
+sn: chiShona
+so: Soomaaliga
+sq: shqip
+sr: српски језик
+ss: SiSwati
+st: Sesotho
+su: Basa Sunda
+sv: svenska
+sw: Kiswahili
+ta: தமிழ்
+te: తెలుగు
+tg: тоҷикӣ
+th: ไทย
+ti: ትግርኛ
+tk: Türkmen
+tl: Wikang Tagalog
+tn: Setswana
+to: faka Tonga
+tr: Türkçe
+ts: Xitsonga
+tt: татар теле
+tw: Twi
+ty: Reo Tahiti
+ug: ئۇيغۇرچە
+uk: українська мова
+ur: اردو
+uz: Ўзбек
+ve: Tshivenḓa
+vi: Tiếng Việt
+vo: Volapük
+wa: walon
+wo: Wollof
+xh: isiXhosa
+yi: ייִדיש
+yo: Yorùbá
+za: Saɯ cueŋƅ
+zh: 汉语
+zu: isiZulu
diff --git a/docs_src/security/tutorial004.py b/docs_src/security/tutorial004.py
index 64099abe9..134c15c5a 100644
--- a/docs_src/security/tutorial004.py
+++ b/docs_src/security/tutorial004.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timedelta
+from datetime import datetime, timedelta, timezone
from typing import Union
from fastapi import Depends, FastAPI, HTTPException, status
@@ -78,9 +78,9 @@ def authenticate_user(fake_db, username: str, password: str):
def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None):
to_encode = data.copy()
if expires_delta:
- expire = datetime.utcnow() + expires_delta
+ expire = datetime.now(timezone.utc) + expires_delta
else:
- expire = datetime.utcnow() + timedelta(minutes=15)
+ expire = datetime.now(timezone.utc) + timedelta(minutes=15)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
diff --git a/docs_src/security/tutorial004_an.py b/docs_src/security/tutorial004_an.py
index ca350343d..204151a56 100644
--- a/docs_src/security/tutorial004_an.py
+++ b/docs_src/security/tutorial004_an.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timedelta
+from datetime import datetime, timedelta, timezone
from typing import Union
from fastapi import Depends, FastAPI, HTTPException, status
@@ -79,9 +79,9 @@ def authenticate_user(fake_db, username: str, password: str):
def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None):
to_encode = data.copy()
if expires_delta:
- expire = datetime.utcnow() + expires_delta
+ expire = datetime.now(timezone.utc) + expires_delta
else:
- expire = datetime.utcnow() + timedelta(minutes=15)
+ expire = datetime.now(timezone.utc) + timedelta(minutes=15)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
diff --git a/docs_src/security/tutorial004_an_py310.py b/docs_src/security/tutorial004_an_py310.py
index 8bf5f3b71..64dfa15c6 100644
--- a/docs_src/security/tutorial004_an_py310.py
+++ b/docs_src/security/tutorial004_an_py310.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timedelta
+from datetime import datetime, timedelta, timezone
from typing import Annotated
from fastapi import Depends, FastAPI, HTTPException, status
@@ -78,9 +78,9 @@ def authenticate_user(fake_db, username: str, password: str):
def create_access_token(data: dict, expires_delta: timedelta | None = None):
to_encode = data.copy()
if expires_delta:
- expire = datetime.utcnow() + expires_delta
+ expire = datetime.now(timezone.utc) + expires_delta
else:
- expire = datetime.utcnow() + timedelta(minutes=15)
+ expire = datetime.now(timezone.utc) + timedelta(minutes=15)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
diff --git a/docs_src/security/tutorial004_an_py39.py b/docs_src/security/tutorial004_an_py39.py
index a634e23de..631a8366e 100644
--- a/docs_src/security/tutorial004_an_py39.py
+++ b/docs_src/security/tutorial004_an_py39.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timedelta
+from datetime import datetime, timedelta, timezone
from typing import Annotated, Union
from fastapi import Depends, FastAPI, HTTPException, status
@@ -78,9 +78,9 @@ def authenticate_user(fake_db, username: str, password: str):
def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None):
to_encode = data.copy()
if expires_delta:
- expire = datetime.utcnow() + expires_delta
+ expire = datetime.now(timezone.utc) + expires_delta
else:
- expire = datetime.utcnow() + timedelta(minutes=15)
+ expire = datetime.now(timezone.utc) + timedelta(minutes=15)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
diff --git a/docs_src/security/tutorial004_py310.py b/docs_src/security/tutorial004_py310.py
index 797d56d04..470f22e29 100644
--- a/docs_src/security/tutorial004_py310.py
+++ b/docs_src/security/tutorial004_py310.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timedelta
+from datetime import datetime, timedelta, timezone
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
@@ -77,9 +77,9 @@ def authenticate_user(fake_db, username: str, password: str):
def create_access_token(data: dict, expires_delta: timedelta | None = None):
to_encode = data.copy()
if expires_delta:
- expire = datetime.utcnow() + expires_delta
+ expire = datetime.now(timezone.utc) + expires_delta
else:
- expire = datetime.utcnow() + timedelta(minutes=15)
+ expire = datetime.now(timezone.utc) + timedelta(minutes=15)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
diff --git a/docs_src/security/tutorial005.py b/docs_src/security/tutorial005.py
index bd0a33581..ece461bc8 100644
--- a/docs_src/security/tutorial005.py
+++ b/docs_src/security/tutorial005.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timedelta
+from datetime import datetime, timedelta, timezone
from typing import List, Union
from fastapi import Depends, FastAPI, HTTPException, Security, status
@@ -93,9 +93,9 @@ def authenticate_user(fake_db, username: str, password: str):
def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None):
to_encode = data.copy()
if expires_delta:
- expire = datetime.utcnow() + expires_delta
+ expire = datetime.now(timezone.utc) + expires_delta
else:
- expire = datetime.utcnow() + timedelta(minutes=15)
+ expire = datetime.now(timezone.utc) + timedelta(minutes=15)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
diff --git a/docs_src/security/tutorial005_an.py b/docs_src/security/tutorial005_an.py
index ec4fa1a07..c5b5609e5 100644
--- a/docs_src/security/tutorial005_an.py
+++ b/docs_src/security/tutorial005_an.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timedelta
+from datetime import datetime, timedelta, timezone
from typing import List, Union
from fastapi import Depends, FastAPI, HTTPException, Security, status
@@ -94,9 +94,9 @@ def authenticate_user(fake_db, username: str, password: str):
def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None):
to_encode = data.copy()
if expires_delta:
- expire = datetime.utcnow() + expires_delta
+ expire = datetime.now(timezone.utc) + expires_delta
else:
- expire = datetime.utcnow() + timedelta(minutes=15)
+ expire = datetime.now(timezone.utc) + timedelta(minutes=15)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
diff --git a/docs_src/security/tutorial005_an_py310.py b/docs_src/security/tutorial005_an_py310.py
index 45f3fc0bd..5e81a50e1 100644
--- a/docs_src/security/tutorial005_an_py310.py
+++ b/docs_src/security/tutorial005_an_py310.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timedelta
+from datetime import datetime, timedelta, timezone
from typing import Annotated
from fastapi import Depends, FastAPI, HTTPException, Security, status
@@ -93,9 +93,9 @@ def authenticate_user(fake_db, username: str, password: str):
def create_access_token(data: dict, expires_delta: timedelta | None = None):
to_encode = data.copy()
if expires_delta:
- expire = datetime.utcnow() + expires_delta
+ expire = datetime.now(timezone.utc) + expires_delta
else:
- expire = datetime.utcnow() + timedelta(minutes=15)
+ expire = datetime.now(timezone.utc) + timedelta(minutes=15)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
diff --git a/docs_src/security/tutorial005_an_py39.py b/docs_src/security/tutorial005_an_py39.py
index ecb5ed516..ae9811c68 100644
--- a/docs_src/security/tutorial005_an_py39.py
+++ b/docs_src/security/tutorial005_an_py39.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timedelta
+from datetime import datetime, timedelta, timezone
from typing import Annotated, List, Union
from fastapi import Depends, FastAPI, HTTPException, Security, status
@@ -93,9 +93,9 @@ def authenticate_user(fake_db, username: str, password: str):
def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None):
to_encode = data.copy()
if expires_delta:
- expire = datetime.utcnow() + expires_delta
+ expire = datetime.now(timezone.utc) + expires_delta
else:
- expire = datetime.utcnow() + timedelta(minutes=15)
+ expire = datetime.now(timezone.utc) + timedelta(minutes=15)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
diff --git a/docs_src/security/tutorial005_py310.py b/docs_src/security/tutorial005_py310.py
index ba756ef4f..0fcdda4c0 100644
--- a/docs_src/security/tutorial005_py310.py
+++ b/docs_src/security/tutorial005_py310.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timedelta
+from datetime import datetime, timedelta, timezone
from fastapi import Depends, FastAPI, HTTPException, Security, status
from fastapi.security import (
@@ -92,9 +92,9 @@ def authenticate_user(fake_db, username: str, password: str):
def create_access_token(data: dict, expires_delta: timedelta | None = None):
to_encode = data.copy()
if expires_delta:
- expire = datetime.utcnow() + expires_delta
+ expire = datetime.now(timezone.utc) + expires_delta
else:
- expire = datetime.utcnow() + timedelta(minutes=15)
+ expire = datetime.now(timezone.utc) + timedelta(minutes=15)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
diff --git a/docs_src/security/tutorial005_py39.py b/docs_src/security/tutorial005_py39.py
index 9e4dbcffb..d756c0b6b 100644
--- a/docs_src/security/tutorial005_py39.py
+++ b/docs_src/security/tutorial005_py39.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timedelta
+from datetime import datetime, timedelta, timezone
from typing import Union
from fastapi import Depends, FastAPI, HTTPException, Security, status
@@ -93,9 +93,9 @@ def authenticate_user(fake_db, username: str, password: str):
def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None):
to_encode = data.copy()
if expires_delta:
- expire = datetime.utcnow() + expires_delta
+ expire = datetime.now(timezone.utc) + expires_delta
else:
- expire = datetime.utcnow() + timedelta(minutes=15)
+ expire = datetime.now(timezone.utc) + timedelta(minutes=15)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
diff --git a/pyproject.toml b/pyproject.toml
index 38728d99e..2fde7553a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -36,6 +36,7 @@ classifiers = [
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
+ "Programming Language :: Python :: 3.12",
"Topic :: Internet :: WWW/HTTP :: HTTP Servers",
"Topic :: Internet :: WWW/HTTP",
]
@@ -111,6 +112,15 @@ filterwarnings = [
"ignore::trio.TrioDeprecationWarning",
# TODO remove pytest-cov
'ignore::pytest.PytestDeprecationWarning:pytest_cov',
+ # TODO: remove after upgrading SQLAlchemy to a version that includes the following changes
+ # https://github.com/sqlalchemy/sqlalchemy/commit/59521abcc0676e936b31a523bd968fc157fef0c2
+ 'ignore:datetime\.datetime\.utcfromtimestamp\(\) is deprecated and scheduled for removal in a future version\..*:DeprecationWarning:sqlalchemy',
+ # TODO: remove after upgrading python-jose to a version that explicitly supports Python 3.12
+ # also, if it won't receive an update, consider replacing python-jose with some alternative
+ # related issues:
+ # - https://github.com/mpdavis/python-jose/issues/332
+ # - https://github.com/mpdavis/python-jose/issues/334
+ 'ignore:datetime\.datetime\.utcnow\(\) is deprecated and scheduled for removal in a future version\..*:DeprecationWarning:jose',
]
[tool.coverage.run]
diff --git a/scripts/docs.py b/scripts/docs.py
index 73e1900ad..a6710d7a5 100644
--- a/scripts/docs.py
+++ b/scripts/docs.py
@@ -274,22 +274,24 @@ def live(
def update_config() -> None:
config = get_en_config()
languages = [{"en": "/"}]
- alternate: List[Dict[str, str]] = config["extra"].get("alternate", [])
- alternate_dict = {alt["link"]: alt["name"] for alt in alternate}
new_alternate: List[Dict[str, str]] = []
+ # Language names sourced from https://quickref.me/iso-639-1
+ # Contributors may wish to update or change these, e.g. to fix capitalization.
+ language_names_path = Path(__file__).parent / "../docs/language_names.yml"
+ local_language_names: Dict[str, str] = mkdocs.utils.yaml_load(
+ language_names_path.read_text(encoding="utf-8")
+ )
for lang_path in get_lang_paths():
- if lang_path.name == "en" or not lang_path.is_dir():
+ if lang_path.name in {"en", "em"} or not lang_path.is_dir():
continue
- name = lang_path.name
- languages.append({name: f"/{name}/"})
+ code = lang_path.name
+ languages.append({code: f"/{code}/"})
for lang_dict in languages:
- name = list(lang_dict.keys())[0]
- url = lang_dict[name]
- if url not in alternate_dict:
- new_alternate.append({"link": url, "name": name})
- else:
- use_name = alternate_dict[url]
- new_alternate.append({"link": url, "name": use_name})
+ code = list(lang_dict.keys())[0]
+ url = lang_dict[code]
+ use_name = f"{code} - {local_language_names[code]}"
+ new_alternate.append({"link": url, "name": use_name})
+ new_alternate.append({"link": "/em/", "name": "😉"})
config["extra"]["alternate"] = new_alternate
en_config_path.write_text(
yaml.dump(config, sort_keys=False, width=200, allow_unicode=True),