Python'da birim testi yazmak için ek kurulum gerektirmeyen araç standart kütüphanedeki unittest modülüdür: unittest.TestCase sınıfından türeyen bir sınıf yazarsınız, adı test ile başlayan her metot bir test olur, kontrolleri assertEqual(), assertRaises() gibi metotlarla yaparsınız ve testleri python -m unittest komutuyla çalıştırırsınız. Modül JUnit'ten esinlenmiştir; hazırlık ve temizlik kodunu paylaşmayı, testleri gruplamayı ve sonuçları raporlamayı nesne yönelimli biçimde sunar.
Bu yazıda gerçek bir küçük modül için test dosyası kuruyoruz, testleri komut satırından keşif (discovery) ile çalıştırıyoruz, başarısız bir testin çıktısını satır satır okuyoruz, setUp, addCleanup, subTest, atlama ve beklenen hata konularına giriyoruz. Sonda unittest.mock ve doctest modüllerine kısa birer giriş var. Gösterilen tüm test çıktıları Python 3.15.2 ile alındı; süre değerleri (0.001s gibi) her çalıştırmada değişebilir.
Temel kavramlar

unittest belgeleri dört kavram üzerine kuruludur. Bunları bilmek hem belgeleri okumayı hem de hata çıktılarını yorumlamayı kolaylaştırır:
| Kavram | Anlamı | unittest karşılığı |
|---|---|---|
| Test fixture | Testten önce yapılan hazırlık ve sonrasındaki temizlik | setUp, tearDown, addCleanup |
| Test case | Belirli bir girdiye verilen yanıtı kontrol eden tek test birimi | TestCase alt sınıfındaki test metodu |
| Test suite | Birlikte çalıştırılacak testlerin topluluğu | TestSuite |
| Test runner | Testleri çalıştırıp sonucu raporlayan bileşen | TextTestRunner, python -m unittest |
Her test metodu için yeni bir TestCase örneği oluşturulur; setUp() ve tearDown() her testte bir kez çalışır. Bu tasarım testlerin birbirinden bağımsız olmasını amaçlar: bir test diğerinin bıraktığı duruma güvenmemelidir. Testlerin çalışma sırası, metot adlarının metin olarak sıralanmasıyla belirlenir; bu sıraya dayanan bir test yazmak kırılgan olur.
İlk test dosyası
Test edeceğimiz hesap.py modülünde iki fonksiyon var: KDV ekleyen kdv_ekle() ve Türkçe karakterleri ASCII karşılıklarına çevirerek adres dostu metin üreten slug().
def kdv_ekle(tutar, oran=20):
"""Tutara KDV ekler ve 2 basamağa yuvarlar."""
if tutar < 0:
raise ValueError('tutar negatif olamaz')
return round(tutar * (1 + oran / 100), 2)
def slug(metin):
tablo = str.maketrans('çğıöşüÇĞİÖŞÜ', 'cgiosuCGIOSU')
return '-'.join(metin.translate(tablo).lower().split())Testleri ayrı bir test_hesap.py dosyasına yazıyoruz. Belgeler test kodunu ayrı modülde tutmanın avantajlarını sayar: test modülü tek başına çalıştırılabilir, dağıtılan koddan kolayca ayrılır ve test edilen kodu yeniden düzenlemek kolaylaşır.
import unittest
from hesap import kdv_ekle, slug
class KdvTest(unittest.TestCase):
def test_varsayilan_oran(self):
self.assertEqual(kdv_ekle(100), 120.0)
def test_ozel_oran(self):
self.assertEqual(kdv_ekle(50, oran=10), 55.0)
def test_negatif_tutar(self):
with self.assertRaises(ValueError) as cm:
kdv_ekle(-5)
self.assertIn('negatif', str(cm.exception))
class SlugTest(unittest.TestCase):
def test_turkce_karakter(self):
self.assertEqual(slug('Çay Şeker Ölçü'), 'cay-seker-olcu')
def test_buyuk_i(self):
self.assertEqual(slug('İzmir Iğdır'), 'izmir-igdir')
if __name__ == '__main__':
unittest.main()Dosya adının test ile başlaması önemlidir; keşif mekanizması varsayılan olarak test*.py desenine uyan dosyaları arar. Her iki dosya aynı klasördeyken şunları çalıştırabilirsiniz:
$ python -m unittest
.....
----------------------------------------------------------------------
Ran 5 tests in 0.000s
OK
$ python -m unittest -v
test_negatif_tutar (test_hesap.KdvTest.test_negatif_tutar) ... ok
test_ozel_oran (test_hesap.KdvTest.test_ozel_oran) ... ok
test_varsayilan_oran (test_hesap.KdvTest.test_varsayilan_oran) ... ok
test_buyuk_i (test_hesap.SlugTest.test_buyuk_i) ... ok
test_turkce_karakter (test_hesap.SlugTest.test_turkce_karakter) ... ok
----------------------------------------------------------------------
Ran 5 tests in 0.000s
OKAyrıntısız modda her başarılı test bir nokta olarak görünür. -v ile her testin tam adı (modül.Sınıf.metot) ve sonucu listelenir. Dosyanın sonundaki unittest.main() satırı sayesinde python test_hesap.py komutu da aynı testleri çalıştırır. test_negatif_tutar testinde assertRaises() bağlam yöneticisi olarak kullanıldı; as cm ile yakalanan istisna nesnesine cm.exception üzerinden ulaşıp mesajını da kontrol ettik.
Test metotlarında Python'un düz assert ifadesi yerine self.assert... metotları kullanılır. Belgeler bunun nedenini açıklar: test çalıştırıcı bu metotlar sayesinde tüm sonuçları toplayıp ayrıntılı rapor üretebilir. Örneğin assertEqual() iki liste farklıysa ilk farklı elemanı ve bir fark (diff) çıktısı gösterir.
Komut satırı seçenekleri ve test keşfi
python -m unittest komutu argümansız çalıştırıldığında python -m unittest discover ile aynı işi yapar: başlangıç klasöründen itibaren test dosyalarını bulup içe aktarır. Belirli bir modülü, sınıfı ya da tek bir metodu da çalıştırabilirsiniz:
python -m unittest test_hesap
python -m unittest test_hesap.KdvTest
python -m unittest test_hesap.KdvTest.test_ozel_oran
python -m unittest tests/test_hesap.py
python -m unittest discover -s tests -p "*_test.py"
python -m unittest -k slug -v| Seçenek | İşlevi |
|---|---|
| -v | Her testin adını ve sonucunu yazar |
| -f, --failfast | İlk hata ya da başarısızlıkta durur |
| -b, --buffer | Başarılı testlerin print çıktısını gizler, başarısızlarda gösterir |
| -k DESEN | Yalnızca adı desene uyan testleri çalıştırır (birden çok kez verilebilir) |
| -c, --catch | Ctrl-C ile mevcut test bitince o ana kadarki sonuçları raporlar |
| --locals | Traceback içinde yerel değişkenleri gösterir |
| --durations N | En yavaş N testi listeler (3.12 ile geldi) |
| discover -s KLASÖR | Keşfin başlayacağı klasör (varsayılan .) |
| discover -p DESEN | Test dosyası deseni (varsayılan test*.py) |
| discover -t KLASÖR | Projenin üst düzey klasörü |
-k deseninde * varsa fnmatch kuralıyla, yoksa büyük küçük harfe duyarlı alt metin olarak eşleşme yapılır; eşleşme testin tam adına göredir. Keşif için test dosyalarının proje kökünden içe aktarılabilir modüller olması, yani adlarının geçerli Python tanımlayıcısı olması gerekir. Python 3.14 ile ad alanı paketleri (namespace package) yeniden başlangıç klasörü olarak destekleniyor; ancak Python dışı klasörleri taramamak için __init__.py içermeyen alt klasörlerde test aranmıyor. Testleri tests/ gibi alt klasörlere koyuyorsanız bu klasörlere __init__.py eklemeyi unutmayın. Paket yapısı için modül ve paket yazısına bakabilirsiniz.
Python 3.14 ile test çıktısı terminalde varsayılan olarak renklidir. Renk, ortam değişkenleriyle (NO_COLOR, PYTHON_COLORS) kapatılabilir.
assert metotları
En çok kullanılan karşılaştırma metotları ve neyi kontrol ettikleri:
| Metot | Kontrol | Not |
|---|---|---|
| assertEqual(a, b) | a == b | Liste, sözlük, metin için ayrıntılı fark gösterir |
| assertNotEqual(a, b) | a != b | |
| assertTrue(x) / assertFalse(x) | bool(x) is True / False | Daha özel metot varsa onu tercih edin |
| assertIs(a, b) | a is b | Kimlik karşılaştırması |
| assertIsNone(x) | x is None | |
| assertIn(a, b) | a in b | |
| assertIsInstance(a, b) | isinstance(a, b) | |
| assertAlmostEqual(a, b) | round(a - b, 7) == 0 | Ondalık basamağa göre yuvarlar, delta da verilebilir |
| assertCountEqual(a, b) | Sıradan bağımsız aynı elemanlar | Tekrar sayıları da karşılaştırılır |
| assertRegex(metin, desen) | re.search eşleşir | |
| assertRaises(Hata) | Blok bu istisnayı fırlatır | Bağlam yöneticisi olarak kullanılabilir |
| assertLogs(logger, level) | Blok en az bir log kaydı üretir | 3.15: formatter parametresi |
| assertStartsWith / assertEndsWith | Önek ve sonek kontrolü | 3.14 ile geldi |
| assertHasAttr / assertIsSubclass | hasattr ve issubclass kontrolü | 3.14 ile geldi |
assertTrue(a == b) yazmak yerine assertEqual(a, b) yazmak, başarısızlıkta "False is not true" yerine iki değeri de gösteren bir mesaj üretir. Belgeler daha özel bir metot varsa onun kullanılmasını önerir. assertTrue(x) aslında bool(x) is True kontrolü yapar; değerin gerçekten True nesnesi olduğunu doğrulamak isterseniz assertIs(x, True) kullanın. Tüm assert metotları isteğe bağlı bir msg argümanı alır ve başarısızlık mesajına eklenir.
Başarısız testin çıktısını okumak

unittest iki tür olumsuz sonuç ayırır. FAIL, bir assert metodunun koşulunun sağlanmadığı, yani kodun yanlış sonuç verdiği durumdur. ERROR, test sırasında beklenmeyen başka bir istisnanın oluşmasıdır; çoğunlukla testin ya da test edilen kodun hata verdiğini gösterir. Aşağıdaki dosyada ikisinden de birer örnek var:
import unittest
class HataliTest(unittest.TestCase):
def test_liste(self):
self.assertEqual([1, 2, 3], [1, 2, 4])
def test_bolme(self):
sonuc = 10 / 0$ python -m unittest -v test_hata
test_bolme (test_hata.HataliTest.test_bolme) ... ERROR
test_liste (test_hata.HataliTest.test_liste) ... FAIL
======================================================================
ERROR: test_bolme (test_hata.HataliTest.test_bolme)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_hata.py", line 10, in test_bolme
sonuc = 10 / 0
~~~^~~
ZeroDivisionError: division by zero
======================================================================
FAIL: test_liste (test_hata.HataliTest.test_liste)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_hata.py", line 7, in test_liste
self.assertEqual([1, 2, 3], [1, 2, 4])
~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
AssertionError: Lists differ: [1, 2, 3] != [1, 2, 4]
First differing element 2:
3
4
- [1, 2, 3]
? ^
+ [1, 2, 4]
? ^
----------------------------------------------------------------------
Ran 2 tests in 0.001s
FAILED (failures=1, errors=1)(Çıktıdaki dosya yolunu kısalttık, başka bir şey değiştirmedik.) Raporun en altındaki satır özeti verir: bir başarısızlık, bir hata. assertEqual() listeler için ilk farklı elemanın indeksini (2) ve -, +, ? işaretli bir fark görünümü üretti. Komutun çıkış kodu, en az bir test başarısız olduğunda 0 değildir; sürekli entegrasyon sistemleri bu sayede hatalı bir değişikliği yakalar. Traceback satırlarını okumayı sık hata mesajları yazısında ayrıntılı anlattık.
Hazırlık ve temizlik: setUp, tearDown, addCleanup
Birden çok testin aynı hazırlığa ihtiyacı varsa bu kodu setUp() metoduna taşıyın; çerçeve her testten hemen önce onu çağırır. tearDown() her testten sonra, test başarısız olsa bile çalışır; ancak yalnızca setUp() başarıyla tamamlandıysa. addCleanup() ile eklenen temizlik fonksiyonları ise setUp() yarıda kalsa bile çağrılır ve eklenme sırasının tersiyle (son eklenen ilk) çalışır. Bu yüzden kaynak açtığınız satırın hemen arkasına temizliğini eklemek güvenli bir alışkanlıktır.
import os
import tempfile
import unittest
class DosyaTest(unittest.TestCase):
def setUp(self):
self.klasor = tempfile.TemporaryDirectory()
self.addCleanup(self.klasor.cleanup)
self.yol = os.path.join(self.klasor.name, 'not.txt')
def test_yaz_oku(self):
with open(self.yol, 'w', encoding='utf-8') as f:
f.write('günlük')
with open(self.yol, encoding='utf-8') as f:
self.assertEqual(f.read(), 'günlük')
def test_dosya_yok(self):
self.assertFalse(os.path.exists(self.yol))Her iki test de kendi geçici klasörünü alır; test_dosya_yok testi, diğer testin yazdığı dosyayı görmez. Tüm sınıf için bir kez yapılacak pahalı hazırlıklar (örneğin bir veritabanı bağlantısı) için @classmethod olarak tanımlanan setUpClass() ve tearDownClass(), modül düzeyinde setUpModule() ve tearDownModule() vardır. Python 3.11 ile gelen enterContext(), bir bağlam yöneticisine girip çıkışını otomatik temizlik olarak kaydeder; with ve context manager yazısında bu protokolü anlattık.
İstisna, uyarı ve log kontrolü
assertRaises() iki biçimde kullanılır: self.assertRaises(ValueError, kdv_ekle, -5) gibi fonksiyon ve argümanlarıyla, ya da yukarıda yaptığımız gibi with bloğuyla. Bağlam yöneticisi biçimi okunması daha kolay olduğu için genellikle tercih edilir. assertRaisesRegex() ek olarak istisna mesajının bir düzenli ifadeyle eşleşmesini ister. Kendi istisna sınıflarınızı yazmayı raise ve özel istisna yazısında bulabilirsiniz.
Log mesajlarını test etmek için assertLogs() kullanılır. Blok içinde belirtilen logger ya da alt logger'larından, verilen seviyede en az bir kayıt üretilmezse test başarısız olur. Dönen nesnenin output listesi biçimlenmiş mesajları, records listesi ise LogRecord nesnelerini tutar. Python 3.15 ile assertLogs() bir formatter parametresi kabul ediyor; verilmezse biçim %(levelname)s:%(name)s:%(message)s olur.
import logging
import unittest
def odeme_al(tutar):
log = logging.getLogger('odeme')
if tutar > 10_000:
log.warning('yüksek tutar: %s', tutar)
return True
class LogTest(unittest.TestCase):
def test_uyari(self):
with self.assertLogs('odeme', level='WARNING') as cm:
odeme_al(25_000)
self.assertEqual(cm.output, ['WARNING:odeme:yüksek tutar: 25000'])Bu test, Python 3.15.2 ile çalıştırıldığında OK sonucunu verdi. Python 3.15 ile assertWarns() ve assertWarnsRegex() davranışı da değişti: artık belirtilen kategoriye ya da desene uymayan uyarıları yutmuyorlar ve iç içe kullanılabiliyorlar. Sürüm notları, bu değişiklik nedeniyle önceden gizlenen bazı uyarıların test çıktısında görünmeye başlayabileceğini ve bunları uyarı filtreleriyle ya da ek assertWarns kontrolleriyle ele almak gerektiğini belirtiyor. Log yapılandırmasının kendisi için logging modülü yazısına bakın.
subTest ile parametreli testler
Aynı kontrolü farklı girdilerle yapmak için bir döngü yazmak doğaldır; ama döngüdeki ilk başarısızlık testi durdurur ve hangi değerde patladığını göstermez. subTest() bağlam yöneticisi her yinelemeyi ayrı bir alt test olarak raporlar ve verdiğiniz parametreleri hata mesajına ekler:
import unittest
def cift_mi(n):
return n % 2 == 0
class AltTest(unittest.TestCase):
def test_ciftler(self):
for n in (2, 4, 7, 10):
with self.subTest(n=n):
self.assertTrue(cift_mi(n))$ python -m unittest -v test_alt
test_ciftler (test_alt.AltTest.test_ciftler) ...
test_ciftler (test_alt.AltTest.test_ciftler) (n=7) ... FAIL
======================================================================
FAIL: test_ciftler (test_alt.AltTest.test_ciftler) (n=7)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_alt.py", line 13, in test_ciftler
self.assertTrue(cift_mi(n))
~~~~~~~~~~~~~~~^^^^^^^^^^^^
AssertionError: False is not true
----------------------------------------------------------------------
Ran 1 test in 0.001s
FAILED (failures=1)Rapor tek testi sayar ama başarısız yinelemeyi (n=7) etiketiyle gösterir; 2, 4 ve 10 değerleri de denenmiştir. Bu çıktı aynı zamanda assertTrue() mesajının ne kadar az bilgi verdiğini gösteriyor: burada assertEqual(n % 2, 0) yazmak "1 != 0" gibi daha açıklayıcı bir mesaj üretirdi.
Testleri atlamak ve beklenen hatalar
Bir testi koşulsuz atlamak için @unittest.skip(neden), koşula bağlı atlamak için skipIf ve skipUnless dekoratörleri kullanılır. Test içinde self.skipTest() çağırarak çalışma anında da atlayabilirsiniz. @unittest.expectedFailure bilinen bir hatayı işaretler: test başarısız olursa başarı sayılır, beklenmedik şekilde geçerse başarısızlık sayılır. Atlanan testlerde setUp() ve tearDown() çalışmaz.
import sys
import unittest
class AtlamaTest(unittest.TestCase):
@unittest.skip('henüz yazılmadı')
def test_rapor(self):
pass
@unittest.skipUnless(sys.platform.startswith('linux'), 'yalnızca Linux')
def test_linux(self):
pass
@unittest.expectedFailure
def test_bilinen_hata(self):
self.assertEqual(0.1 + 0.2, 0.3)
def test_yaklasik(self):
self.assertAlmostEqual(0.1 + 0.2, 0.3)$ python -m unittest -v test_atla
test_bilinen_hata (test_atla.AtlamaTest.test_bilinen_hata) ... expected failure
test_linux (test_atla.AtlamaTest.test_linux) ... skipped 'yalnızca Linux'
test_rapor (test_atla.AtlamaTest.test_rapor) ... skipped 'henüz yazılmadı'
test_yaklasik (test_atla.AtlamaTest.test_yaklasik) ... ok
----------------------------------------------------------------------
Ran 4 tests in 0.001s
OK (skipped=2, expected failures=1)Çıktı Windows üzerinde alındığı için Linux testi atlandı. Bu örnek ondalıklı sayılarla ilgili klasik bir tuzağı da gösteriyor: 0.1 + 0.2 == 0.3 karşılaştırması kayan nokta gösterimi yüzünden False verir, bu yüzden assertEqual başarısız olur. assertAlmostEqual() farkı varsayılan olarak 7 ondalık basamağa yuvarlayıp sıfırla karşılaştırdığı için geçer. Nedenini Python sayılar yazısında anlattık.
unittest.mock ile bağımlılıkları taklit etmek
Ağ isteği, veritabanı ya da saat gibi dış bağımlılıkları testte gerçekten çalıştırmak istemezsiniz. unittest.mock modülü, erişildikçe öznitelik ve metot üreten Mock nesneleri ve modül düzeyindeki nesneleri test süresince değiştiren patch() dekoratörünü sunar. Mock nesnesinin nasıl çağrıldığını sonradan kontrol edebilirsiniz:
import unittest
from unittest import mock
def kur_getir(istemci):
yanit = istemci.get('/kur/usd')
return yanit['satis']
class MockTest(unittest.TestCase):
def test_kur(self):
sahte = mock.Mock()
sahte.get.return_value = {'satis': 41.25}
self.assertEqual(kur_getir(sahte), 41.25)
sahte.get.assert_called_once_with('/kur/usd')Bu test de 3.15.2 ile OK verdi. return_value sahte metodun döndüreceği değeri belirler, assert_called_once_with() tam olarak bir kez ve bu argümanla çağrıldığını doğrular. Mock konusu kendi başına geniş olduğu için ayrıntılar için resmî Python belgeleri: unittest.mock sayfasına bakmanızı öneririz.
doctest: belgedeki örnekleri test etmek
doctest modülü docstring içindeki >>> ile başlayan etkileşimli oturum parçalarını bulur, çalıştırır ve çıktının yazılanla aynı olup olmadığını kontrol eder. Belgelerdeki örneklerin güncel kalmasını sağlamanın kolay bir yoludur:
def faktoriyel(n):
"""n! değerini döndürür.
>>> faktoriyel(5)
120
>>> [faktoriyel(i) for i in range(5)]
[1, 1, 2, 6, 24]
>>> faktoriyel(-1)
Traceback (most recent call last):
...
ValueError: n negatif olamaz
"""
if n < 0:
raise ValueError('n negatif olamaz')
sonuc = 1
for i in range(2, n + 1):
sonuc *= i
return sonuc
if __name__ == '__main__':
import doctest
doctest.testmod()$ python faktoriyel.py
$ python faktoriyel.py -v
Trying:
faktoriyel(5)
Expecting:
120
ok
Trying:
[faktoriyel(i) for i in range(5)]
Expecting:
[1, 1, 2, 6, 24]
ok
Trying:
faktoriyel(-1)
Expecting:
Traceback (most recent call last):
...
ValueError: n negatif olamaz
ok
1 item had no tests:
__main__
1 item passed all tests:
3 tests in __main__.faktoriyel
3 tests in 2 items.
3 passed.
Test passed.Tüm örnekler geçtiğinde doctest hiçbir şey yazmaz; -v ayrıntılı günlüğü açar. Çıktı karşılaştırması metin düzeyinde yapıldığı için sözlük gösterimi, bellek adresi içeren repr değerleri gibi değişebilen çıktılar doctest için uygun değildir. Mevcut doctest'leri unittest paketine bağlamak için doctest.DocTestSuite kullanılabilir.
Sık yapılan hatalar

- Metot adını
testile başlatmamak:kontrol_kdv()adlı metot test olarak çalıştırılmaz, hata da vermez. - Testlerin sırasına güvenmek: sıra metot adlarının alfabetik sıralamasıyla belirlenir; her test kendi hazırlığını yapmalıdır.
- Test dosyasına standart modülle aynı adı vermek:
unittest.pyya darandom.pyadlı dosya gerçek modülü gölgeler. - Alt klasörde
__init__.pyunutmak: keşif bu klasörlere inmez ve çıktıda "Ran 0 tests" ile "NO TESTS RAN" satırlarını görürsünüz (3.15.2 bu durumda 5 çıkış koduyla döner). - Test metodundan değer döndürmek: Python 3.11 ile
Nonedışında bir değer döndürmek kullanımdan kaldırılmak üzere işaretlendi. - Ondalıklı sayıları
assertEqualile karşılaştırmak:assertAlmostEqualkullanın.
Sık Sorulan Sorular
unittest mi, pytest mi?
unittest standart kütüphanededir ve ek kurulum gerektirmez. Python belgeleri, daha hafif söz dizimiyle (assert func(10) == 42 gibi) test yazmayı sağlayan üçüncü taraf bir çerçeve olarak pytest'e işaret eder. pytest ayrı bir paket olduğu için kurulumunu bir sanal ortam içinde yapmanız önerilir; API ayrıntıları bu yazının kapsamı dışında.
Testi çalıştırınca "NO TESTS RAN" görüyorum, neden?
En yaygın nedenler: dosya adı test*.py desenine uymuyor, metot adları test ile başlamıyor, sınıf unittest.TestCase sınıfından türemiyor ya da testler __init__.py içermeyen bir alt klasörde duruyor. -p ile deseni, -s ile başlangıç klasörünü belirtebilirsiniz.
Tek bir testi nasıl çalıştırırım?
Tam adını verin: python -m unittest test_hesap.KdvTest.test_ozel_oran. Ada göre filtrelemek için -k ozel da kullanılabilir.
Komut satırı aracımı nasıl test ederim?
Ayrıştırma mantığını bir fonksiyona koyup parse_args() metoduna liste verin; böylece sys.argv ile uğraşmadan test edebilirsiniz. Örnekler için argparse rehberine bakın.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: Python öğrenme rehberi · argparse ile komut satırı · try/except hata yönetimi · raise ve özel istisna · logging modülü · venv ve pip