Serinin ikinci yazısını sıradaki işleri sayarak bitirmiştik. Bunlardan biri, GitHub’daki örnek kod deposunun bakımıydı. Bu yazıda o işi anlatıyoruz. 19 projenin README dosyasını, kodu gerçekten çalıştırarak baştan yazdık. İş sırasında README’lerdeki biçim hatalarından çok daha fazlasını bulduk: yanlış sürüm iddiaları, hiç çalışmayan döngüler, sessizce yutulan hatalar. Bir de 19 Ekim’de yayınlanan yazımızda yaptığımız yanlış bir teşhisi yakaladık.
Depo ve Sorun
gurmezin.com’daki Python yazılarının kodları practical-python-examples deposunda duruyor. Her proje v312/ altında numaralı bir klasörde bulunuyor ve klasörlerde iki README var: İngilizce README.md ve Türkçe README_TR.md.
23 ile 40 arasındaki projelerin README’leri bir yapay zekâ sohbet arayüzünde üretilmişti. Bozulmanın biçimine bakılırsa, metin oradan kopyalanırken Markdown işaretlerinin bir kısmı kaybolmuştu. Kod bloklarının kapanış işaretleri (```) kaybolmuş, bazılarının yerinde yalnızca “Bash” kelimesi kalmıştı. Bu yüzden GitHub, bir kod bloğu açıldıktan sonra dosyanın geri kalanını da kod olarak gösteriyordu.
Önce Ölçtük: Tarama Betiği
Düzeltmeye başlamadan önce sorunun ne kadar yaygın olduğunu görmek istedik. Claude, her README’yi okuyan küçük bir tarama betiği yazdı. Betik şunlara bakıyor:
- Kod bloğu işaretlerinin sayısı tek mi? Tek sayı, kapanmamış bir blok demek.
- Türkçe README’de İngilizce sözcükler Türkçelerden fazla mı?
- README’de adı geçen dosyalar (
requirements.txt,main.pygibi) klasörde gerçekten var mı? - İlgili blog yazısına bağlantı var mı?
Sonuç şöyleydi:
| Bulgu | Projeler |
|---|---|
| Kapanmamış kod bloğu | 24, 25, 26, 27, 29, 31, 32, 34, 37, 38, 39, 40 |
| Türkçe README’nin büyük kısmı İngilizce | 24, 37, 38, 39, 40 |
| Var olmayan dosyayı gösteren README | 34 (main.py, requirements.txt), 40 (requirements.txt) |
| Blog yazısı bağlantısı yok | 01–41 |
01–22 arasındaki projelerde tek eksik blog bağlantısıydı. Sorunlar 23 ile 40 arasında toplanıyordu. Taramanın temiz gösterdiği 23, 28, 30, 33, 35 ve 36 da aynı dönemde aynı yöntemle hazırlandığı için onları da kapsama aldık. Blog bağlantısı eklemek için 41’i de ekleyince 19 proje oldu.
Yöntem: Beş Ajan, Tek Talimat
Her projede yapılacak iş aynıydı. Kod çalıştırılacak, gerçek çıktı alınacak, README iki dilde yeniden yazılacaktı. Projeler birbirinden bağımsız olduğu için Claude işi beş alt ajana böldü. Her ajan üç ila beş projeyi aldı ve beşi aynı anda çalıştı.
Ajanların hepsi aynı talimat dosyasını okudu. Talimatın en önemli kuralları şunlardı:
- Koda dokunma. README, kodun ne yaptığını anlatır. Kodda hata bulursan düzeltme, raporla.
- Kodu gerçekten çalıştır. Örnek çıktı bölümüne yalnızca gerçek çıktı girer. Üçüncü taraf paketleri proje klasörüne değil geçici bir sanal ortama kur ve klasörde dosya bırakma.
- Sürüm iddialarını doğrula. “Python 3.12+ gerekli” deniyorsa hangi özellik yüzünden gerektiğini bul. Gerekirse eski sürümü Docker’da dene.
- Rapor ver. README’nin ne dediğini ve gerçekte ne olduğunu, kanıtıyla birlikte yaz.
Biçim için örnek olarak, daha önce elle düzelttiğimiz 40 numaralı projenin README’sini ve 42 numaralı projenin README’sini gösterdik. Her ajanın çalışma süresi 7 ile 13 dakika arasında değişti.
“Python 3.12+ Gerekli” İddiası Kaç Projede Doğruydu?
Eski README’lerin neredeyse hepsi “Python 3.12 veya üstü gerekli” diyordu. Ajanlar her projede bu iddiayı test etti:
| Proje | README’nin iddiası | Gerçek alt sınır | Nedeni |
|---|---|---|---|
| 24 Tip ipuçları | 3.12+ | 3.12 ✔ | type deyimi 3.11’de SyntaxError veriyor |
| 25 asyncio | 3.11+ | 3.11 ✔ | asyncio.TaskGroup 3.10’da yok |
| 26 Multiprocessing | 3.12+ | Herhangi bir Python 3 | Sürüme özgü bir özellik yok |
| 30 FastAPI | 3.12+ | 3.10 | Sınırı kod değil, güncel FastAPI ve Pydantic belirliyor |
| 31 Sıralama | 3.12+ | 3.9 | list[int] tip ipucu |
| 32 İkili ağaç | 3.12+ | 3.11 | Hiç kullanılmayan from typing import Self satırı |
| 38 Regex | 3.12+ | 3.9 | list[str] tip ipucu |
32’deki durum öğretici. README, 3.12 gerektiğini Node | None yazımına bağlıyordu, oysa bu yazım 3.10’da geldi. Asıl sınırı koyan, dosyanın başında unutulmuş ve hiç kullanılmayan bir içe aktarma satırıydı:
$ docker run --rm -v "$PWD":/app -w /app python:3.10-slim python main.py
ImportError: cannot import name 'Self' from 'typing'
Kod Çalıştırılınca Ortaya Çıkanlar
Sürümlerden daha ilginç olan, kodun README’de anlatılmayan davranışlarıydı. Aşağıdakiler ajanların raporlarından seçtiklerimiz. Hepsini yazıya koymadan önce kendimiz de yeniden çalıştırıp doğruladık.
Merge sort kararlı değil (31). Merge sort’un bilinen avantajlarından biri kararlı olması, yani eşit elemanların ilk sırasını korumasıdır. Projedeki uygulama, eşit elemanların sırasını tersine çeviriyor:
sorted() [0x, 1a, 1b, 1c]
merge_sort() [0x, 1c, 1b, 1a]
Nedeni tek karakter: birleştirme adımında <= yerine < kullanılmış.
İkili arama ağacı 1000 sıralı sayıda çöküyor (32). README aramanın O(log n) sürdüğünü söylüyor. Bu yalnızca dengeli bir ağaç için doğru. Sayılar sıralı eklenince ağaç bir listeye dönüşüyor. Metotlar özyinelemeli olduğu için de 900 sayıda çalışan kod, 1000 sayıda RecursionError veriyor.
Regex doğrulayıcı Arapça rakamları kabul ediyor (38). \d, Python’da yalnızca 0-9’u değil, bütün Unicode rakamlarını kapsıyor:
validate_turkish_phone('5٥٥١٢٣٤٥٦٧') -> True
[Sanitized Output] Extracted -> Area: (5٥٥) Number: ١٢٣-٤٥-٦٧
Aynı dosyada validate_email("a@x.com\n") de True döndürüyor. re.match ile kullanılan $, sondaki satır sonunu da kabul ediyor. İkisinin de çözümü bilinen yöntemler: re.fullmatch ve re.ASCII.
Web kazıyıcının asıl döngüsü hiç çalışmıyor (39). README programın sayfadaki makaleleri çıkardığını söylüyor. Varsayılan hedef olan example.com sayfasında hiç <article> öğesi yok. Program her çalıştığında yalnızca sayfa başlığını yazıp bitiyor. Ajan döngünün doğru çalıştığını sahte bir HTML sayfasıyla gösterdi ve README’ye bu çıktının sahte sayfadan alındığını açıkça yazdı.
FastAPI’de negatif sayfa boyutu (30). /items?limit=-1 isteği hata vermiyor. HTTP 200 ile iki kaydın yalnızca ilkini döndürüyor, çünkü değer doğrudan Python dilimlemesine gidiyor. Query(ge=0) ile önlenebilecek bir durum.
Poetry projesi README’deki adımlarla kurulmuyor (34). poetry install 13 paketi kurduktan sonra No file/folder found for package 34-poetry-package-management hatasıyla duruyor. README ayrıca klasördeki gerçek pyproject.toml dosyasını değil, yanında duran eski bir pyproject.toml.txt taslağını anlatıyordu. Lock dosyası da Poetry 2.3’ten eski sürümlerle açılmıyor.
Python 3.15 projesi eski sürümlerde mesaj vermiyor (41). README, betiğin eski Python sürümlerinde bir uyarı mesajıyla sonlandığını söylüyordu. Gerçekte Python 3.12 dosyayı derleyemiyor ve SyntaxError veriyor. Sürüm kontrolü kodun içinde olduğu için hiç çalışma fırsatı bulamıyor.
Ölçüm, ölçtüğünü sandığı şeyi ölçmüyor (26). Proje, ağ isteklerinde thread’lerin süreçlerden (multiprocessing) avantajlı olduğunu göstermeyi amaçlıyordu. Üç çalıştırmada da süreçler daha hızlı çıktı. Sırayı tersine çevirince fark kayboldu. Dört istek, ilk bağlantının ısınma maliyetini (DNS, TLS) aşacak kadar uzun sürmüyordu. Üstelik kod her ağ hatasını sessizce “404” sonucuna çeviriyor. İnternet bağlantısı olmasa bile bir süre yazdırıyor ve hiçbir uyarı vermiyor. Bu ölçümler sırasında makinede beş ajan aynı anda çalıştığı için mutlak süreleri README’ye “değişebilir” notuyla koyduk.
En Önemli Bulgu: 19 Ekim Yazımızdaki Yanlış Teşhis
19 Ekim’de yayınlanan yazımızda bir sqlite3 tuzağını anlatıyoruz: with conn: bloğu hata olduğunda işlemi geri almıyordu. 29 numaralı proje de sqlite3 kullandığı için ajana bu tuzağı ayrıca kontrol etmesini söyledik. Talimatta sorunun “Ubuntu 24.04’ün Python paketi ile SQLite sürümünün birleşiminden” kaynaklandığını yazmıştık. O sırada yazının taslağında da bu açıklama vardı.
Ajan bu açıklamayı olduğu gibi kabul etmedi, test etti. Aynı makinede yalnızca yerel ayarı (locale) değiştirdiğinde sorun kayboluyordu. Gerçek neden, bilgisayarın Türkçe olarak ayarlanmasıydı. Python 3.11 ve 3.12, INSERT kelimesini tanımak için yerel ayara bağlı bir karşılaştırma kullanıyor. Türkçede I harfinin küçüğü ı olduğu için INSERT, insert ile eşleşmiyor ve işlem hiç açılmıyor. Bulguyu Docker’da dört Python sürümünde ve CPython’ın kaynak kodunda ayrıca doğruladık. Sorun Python 3.13’te düzeltilmiş.
19 Ekim yazısı henüz zamanlanmış durumdaydı. Yayınlanmadan önce yazıyı, görselini ve sosyal medya metinlerini yeni bulguya göre güncelledik. Ayrıntıları o yazıda okuyabilirsiniz.
Burada dikkat çekmek istediğimiz nokta şu: Yanlış açıklama ajana bizim talimatımızla gitti. Ajan bunu bir veri gibi kabul etmedi, test edilecek bir iddia olarak ele aldı. Ajanlara verilen talimatta “iddiaları doğrula” kuralının yer alması, en çok bizim kendi iddiamızda işe yaradı.
Kodu Neden Düzeltmedik?
Bu çalışmada bulunan hataların hiçbiri koda yansıtılmadı. Bilerek böyle yaptık. Bu kodlar yayınlanmış yazılara bağlı. Kodu değiştirmek, yazıdaki kod parçalarının ve çıktıların da değişmesi demek. README’nin görevi ise kodu olduğu gibi anlatmak.
Bunun yerine README’lere kodun sınırlarını açıkça yazdık. Örneğin regex projesine bir “Sınırlamalar” bölümü, merge sort projesine kararlılık notu, sqlite3 projesine yerel ayar notu eklendi. Kod düzeltmeleri ayrı bir karar ve büyük olasılıkla ayrı bir yazı konusu olacak.
Sonuç: Sayılarla Bakım
| Yeniden yazılan README dosyası | 38 (19 proje × 2 dil) |
| Çalıştırılan Python sürümü | 3.10, 3.11, 3.12, 3.13, 3.14, 3.15 rc |
| Kodu çalıştırılarak doğrulanan proje | 19 |
| Bulunan ama düzeltilmeyen kod hatası | 15’ten fazla |
| Düzeltilen yayın öncesi yazı | 1 |
Bu çalışmadan çıkardığımız birkaç ders şunlar:
- Biçim bozukluğu, içeriğin kontrol edilmediğinin işareti olabilir. Kapanmamış bir kod bloğu fark edilmediyse, o README’deki iddialar da büyük olasılıkla denenmemiştir. Bizde de öyle çıktı.
- Yapay zekânın yazdığı belgeyi kodla karşılaştırın. Eski README’ler kodun yapmadığı şeyleri (“mikroservisler”, “iş parçacığı güvenliği”, “kıyaslama”) akıcı bir dille anlatıyordu.
- Paralel ajanlara iş verirken talimatı yazılı ve tek tutun. Beş ajan aynı kurallarla çalıştığı için 38 dosya aynı yapıda çıktı.
- Ajan raporlarını da doğrulayın. Yazıya giren her bulguyu kendimiz yeniden çalıştırdık. Bu sefer hepsi tuttu, ama bunun böyle olacağını önceden bilemezdik.
Sırada Ne Var?
- 01–22 arasındaki projeler: Bu projelerde yalnızca blog bağlantıları eksik.
- WebP dönüşümü ve kuyruk kontrolü: İkinci yazıda söz verdiğimiz iki iş hâlâ sırada bekliyor.
- Kod düzeltmeleri: Bu yazıda listelediğimiz hataların hangilerinin, nasıl düzeltileceğine karar vereceğiz.
Ahmet Aksoy & Claude
Not: Bu yazıda sözü geçen projelerin kaynak kodlarını ve güncellenmiş README dosyalarını https://github.com/ahmetax/practical-python-examples adresinde bulabilirsiniz.



