Pydantic ile Python'da Ortam Değişkenlerini Zarif Bir Şekilde Yönetin

Python'da yazmak bir gereklilik değildir, ancak farklı kaynaklardan gelen girdileri işlerken gerçek bir rahatlama olabilir. Ortam değişkenleri, neredeyse her yerde kullanıldıklarından, özellikle gerçek dünyadaki dağıtımlarda programlara değişken enjekte etmek için bilinmesi gereken bir yaklaşımdır. Python ve Docker'da bu değişkenleri nasıl idare edebileceğiniz hakkında daha önce bir makale yazmıştım:
Python ve Docker'daki ortam değişkenleriO makalede, -modül ile ortam değişkenlerine erişmenin temel yöntemini kullandım os
:
# get the environment variable MY_ENV_VARIABLE
# or return None if it doesn't exist
my_env_variable = os.getenv("MY_ENV_VARIABLE")
Pydantic'e girin
Pydantic , Python'da tür ipuçlarını kullanarak veri doğrulamayı sağlayan bir Python kitaplığıdır. Genellikle , gelen isteklerin verilerini doğrulamak için kullanıldığı web çerçevesi FastAPI ile birlikte kullanılır . Ek olarak, burada inceleyeceğimiz başka durumlarda da kullanılabilir (yani ortam değişkenleri).
Daha önce tip ipuçlarını kullandıysanız, Pydantic'i kullanmaya başlamak kolay olacaktır. Kütüphaneyi kurarak başlayalım:
pip install pydantic
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class SomeData(BaseModel):
name: str
age: int
@app.post("/data/")
async def post_data(data: SomeData):
print(data)
print(data.dict())
uvicorn main:app
Bu web sunucusu (dosya adının olduğu varsayılarak main.py
) ile başlatılır . Pydantic'in nasıl çalıştığını görmek için bazı istekler gönderelim:
import requests
requests.post("http://localhost:8000/data/", json={"name": "John", "age": 42})
# => SERVER OUTPUT:
# name='John' age=42
# {'name': 'John', 'age': 42}
requests.post("http://localhost:8000/data/", json={"name": 5, "age": "42"})
# => SERVER OUTPUT:
# name='5' age=42
# {'name': '5', 'age': 42}
requests.post("http://localhost:8000/data/", json={"name": "John", "age": { "foo": "bar"}})
# => SERVER ERROR:
# HTTP Status 422 Unprocessable Entity
İkinci istekte, değerler doğru türler değil, bunun yerine doğru biçime dönüştürülür, yani int -> str
ve str -> int
. Bu davranış istenmiyorsa katı tipler kullanılabilir .
Son olarak, son istekte, veri işlenemez (JSON nesnesini int'ye dönüştüremez) ve işlenemeyen varlık olan HTTP durumu 422 döndürülür.
FastAPI'den hareketle, ortam değişkenlerini yönetme durumunda aynı işlevselliği kullanabiliriz. Bu durumda yerine , BaseModel
kullanılır BaseSettings
.
Burada bir dosyadan değişkenler yükleyeceğim .env
. Bu dosya hakkında daha fazla bilgi için önceki makaleme bakın . Dosya aşağıdakileri içerir:
NAME = "John"
AGE = 42
pip install python-dotenv
from pydantic import BaseSettings
class Envs(BaseSettings):
name: str
age: int
class Config:
env_file = '.env'
envs = Envs()
print(envs)
# => name='John' age=42
from pydantic import BaseSettings
class Envs(BaseSettings):
name: str
age: int
envs = Envs(_env_file='.env')
print(envs)
# => name='John' age=42
...
class Config:
case_sensitive = True
Karmaşık tipler
.env
Yeni bir -file ( ) oluşturalım .env2
:
my_array = '["hi", "how", "are", "you?"]'
my_object = '{"some_key": "some_value", "another_key": ["a", "b", "c"]}'
nested = '{"a": "a", "b": 1}'
from pydantic import BaseSettings, BaseModel
from typing import List
class NestedEnvs(BaseModel):
a: str
b: int
class Envs(BaseSettings):
my_array: List[str]
my_object: dict
nested: NestedEnvs
envs = Envs(_env_file='.env2')
print(envs)
# => my_array=['hi', 'how', 'are', 'you?'] my_object={'some_key': 'some_value', 'another_key': ['a', 'b', 'c']} nested=NestedEnvs(a='a', b=1)
Karmaşık veri türleri JSON olarak yorumlanır, bu nedenle JSON nesnesini tek tırnak işaretleri içine almalısınız ve ardından JSON nesnesi içindeki değerler ve anahtarlar için çift tırnak kullanmalısınız. Sonuç olarak, bu işe yaramaz:
my_array = "['hi', 'how', 'are', 'you?']"
class Envs(BaseSettings):
...
class Config:
env_nested_delimiter = '__'
Ardından, - dosyasını genişletin .env
:
my_array = '["hi", "how", "are", "you?"]'
my_object = '{"some_key": "some_value", "another_key": ["a", "b", "c"]}'
my_object__some_other_property = 'some_other_value'
nested = '{"a": "a", "b": 1}'
...
my_object={'some_key': 'some_value', 'another_key': ['a', 'b', 'c'], 'some_other_property': 'some_other_value'}
...
Varsayılan değerler
Bir ortam değişkeni eksikse, varsayılan bir değer eklemek önemsizdir:
from pydantic import BaseSettings
class Envs(BaseSettings):
some_property: str = "default value"
envs = Envs()
print(envs)
# => some_property='default value'
Tıpkı sınıf gibi, yöntemi ve dekoratörü BaseModel
kullanarak değerleri doğrulayabilir ve sonradan işleyebilirsiniz . Bir örnek verelim:Field()
@validator
from pydantic import BaseSettings, Field, validator
class Envs(BaseSettings):
between_0_and_10: int = Field(..., ge=0, le=10)
prime: int
@validator('prime')
def is_prime(cls, n: int) -> int:
if n <= 1:
raise ValueError("Prime numbers must be greater than 1")
for i in range(2, int(n**0.5) + 1):
if n % i == 0:
raise ValueError(f"{n} is not a prime number.")
return n
envs = Envs(_env_file='.env3')
print(envs)
Çözüm
Ortam değişkenleri orijinal olarak diziler olarak saklansa da, genellikle bunların belirli veya daha karmaşık veri türlerine dönüştürülmesi istenir. Pydantic, ortam değişkenlerini yönetmek için kısa ve standart bir yaklaşımla sonuçlanan, tam da bunu yapmanın kusursuz bir yolunu sunar. Pydantic hakkında burada ele alınandan çok daha fazlası var ve daha fazlasını öğrenmek için resmi belgeleri okumanızı tavsiye ederim.
Bu makaleyi beğendiyseniz:
- Alkış, bu okuyucularımın neyi sevdiğini ve daha fazlasını istediğini anlamama yardımcı olacak.
- Takip edin veya abone olun, her hafta yeni gelecek yazılarımı okumak isterseniz!
- Daha fazla içerik arıyorsanız, AI , Python veya Data Science'daki okuma listelerime göz atın .