---
title: Yayımlama
source: 'https://academia.sh/tr/kurslar/python-projeleri/yayimlama'
course: 'Python Projeleri: Paketleme ve Test'
language: tr
updated: '2026-08-17T18:10:32+00:00'
license: 'CC BY-SA 4.0'
---

# Yayımlama

Dokuz yayım girişimi üzerine yazılabilir bir kayıtta 9 kabul ve 2 sessiz değişiklik, değiştirilemez bir kayıtta 7 kabul ve 2 red üretir; aynı kilit dosyası ilk kayıtta 2 ayrı kurulum verir ve özet yazan bir kilit bu iki uyuşmazlığın ikisini de yakalayarak kurulumu durdurur.

Önceki ders dağıtımı üretti ve içeriğini bir özetle adlandırdı. O özet üretim tarafında
hesaplanan bir sayıydı ve orada kaldı; kurulan tarafın ondan haberi yoktu.

Paket bir **paket kaydına (package registry)** gönderildiğinde bu düzen değişir. Kurulan
taraf artık içeriği değil, **adı** ister: "`olcum` paketinin `1.2` sürümü". Adın karşılığını
kayıt verir. Bu dersin sorusu buradan doğar: **aynı ad iki ayrı içeriği taşıyabilir mi, ve
taşıyabiliyorsa kilit dosyasının yazdığı sürüm numarası neyi garanti eder?**

## Kayıt Ne Saklar

Paket kaydı, `(ad, sürüm)` çiftinden bir dağıtıma giden bir eşlemedir. Bu kurs kayıt ürün
adı yazmaz; kayıt burada tek bir sözlükle **modellenir** ve üzerinde tek bir işlem
tanımlanır: yayımla. Model gerçek bir kayda bağlanmaz, hiçbir şey gönderilmez ve hiçbir
paket indirilmez.

Sürüm işaretlemenin kendisi — etiketleme ve anlamlı sürümleme — **Sürüm Kontrolüne Giriş**
kursunda kurulmuştu ve burada tekrarlanmaz. Bu ders sürüm numarasının nasıl seçileceğini
sormaz; **seçilmiş bir numaranın ne kadar bağlayıcı olduğunu** sorar.

## İki İlke

Yayımla işleminin `(ad, sürüm)` çifti daha önce kullanılmışsa ne yapacağı bir ilke
sorusudur ve iki yanıtı vardır.

**Üzerine yazılabilir** kayıt, yeni gövdeyi eskisinin yerine koyar. Gönderim her zaman
başarılıdır. **Değiştirilemez** kayıt, aynı çifte **ayrı** bir gövde geldiğinde gönderimi
reddeder. Aynı gövdenin yeniden gönderilmesini reddetmez — o gönderim kaydı zaten
değiştirmez.

Ayrımın tam yeri budur: değiştirilemezlik **yeniden gönderimi** değil, **ayrı içerikle
yeniden gönderimi** yasaklar. Bir yayım akışında ikisi yan yana bulunabilir ve ölçüm
ikisini de içerir.

Ölçüm dokuz yayım girişimi tanımlar. Üçü ortak kurgunun kilit dosyasındaki sürümleri ilk kez
yayımlar, biri daha eski bir sürümü yayımlar, biri aynı gövdeyi yeniden gönderir, ikisi aynı
sürüme ayrı gövde gönderir, biri aynı gövdeyi bir kez daha gönderir, biri yeni bir sürüm
açar. İki zaman noktası okunur: beşinci girişimden sonra `t1`, dokuzuncudan sonra `t2`.

Ölçümün varsayımları:

- **KY22** — Kilit dosyası ortak tanımın "en yeni" çözümlemesinin sonucudur: `olcum 1.2`,
  `ortak 3.2`, `rapor 1.1`. Kilidin içeriği ölçüm boyunca değişmez.
- **KY23** — Dağıtımın içeriği tek bir gövde dizgisiyle temsil edilir; özeti kısaltılmış
  sekiz onaltılık basamaktır ve iki özetin eşitliği içeriğin eşitliği olarak okunur.
- **KY24** — Kurulum, kilit dosyasındaki üç sürümün kayıttaki özetlerini okumaktır. Kurulumun
  başka hiçbir yan etkisi modellenmez.
- **KY25** — `t1` ve `t2`, aynı kilit dosyasıyla yapılan iki ayrı kurulumdur. Aradaki tek
  fark, kayda bu sürede gelen yayım girişimleridir.
- **KY26** — Özet yazan kilit, kurulum anında beklenen ve gelen özeti karşılaştırır;
  uyuşmazlık bulursa kurulum **durur**. Uyuşmazlığı düzeltmeye çalışmaz.
- **KY27** — Geri çekme, sürümü **çözümlemeye kapatır** ama kayıttaki içeriğine dokunmaz;
  kilit dosyası sürümü doğrudan istediği için çözümlemeyi hiç çalıştırmaz.
- **KY28** — Süre ölçülmez, gerçek kayda gönderim yapılmaz. Sayılan şey **kabul**, **red**,
  **uyuşmazlık** ve **ayrı kurulum** sayısıdır.

## Ölçüm

```python
"""Yayimlama: ayni ad iki ayri icerigi tasiyabilir mi."""

import hashlib

KILIT = {"olcum": (1, 2), "ortak": (3, 2), "rapor": (1, 1)}
DEPO = {"rapor": [(0, 9), (1, 0), (1, 1)]}
BILDIRIM = {"rapor": ((1, 0), (2, 0))}
GERI_CEKILEN = {("rapor", (1, 1))}

GIRISIMLER = [
    ("rapor", (1, 0), "rapor-govde-0"),
    ("olcum", (1, 2), "olcum-govde-1"),
    ("ortak", (3, 2), "ortak-govde-1"),
    ("rapor", (1, 1), "rapor-govde-1"),
    ("olcum", (1, 2), "olcum-govde-1"),
    ("rapor", (1, 1), "rapor-govde-2"),
    ("olcum", (1, 2), "olcum-govde-2"),
    ("ortak", (3, 2), "ortak-govde-1"),
    ("olcum", (2, 0), "olcum-govde-3"),
]
T1 = 5
ILKELER = (("üzerine yazılabilir", False), ("değiştirilemez", True))


def ozet(metin):
    return hashlib.sha256(metin.encode()).hexdigest()[:8]


def yayimla(girisimler, degistirilemez):
    """Paket kaydi modeli: (ad, surum) -> dagitim ozeti."""
    kayit, kabul, red, cakisma = {}, 0, 0, []
    for paket, surum, govde in girisimler:
        anahtar, o = (paket, surum), ozet(govde)
        varsa = kayit.get(anahtar)
        if varsa is not None and varsa != o:
            cakisma.append(f"{paket} {surum[0]}.{surum[1]}")
            if degistirilemez:
                red += 1
                continue
        kayit[anahtar] = o
        kabul += 1
    return kayit, kabul, red, cakisma


def kurulum(kayit):
    """Kilit dosyasindaki surumler kayittan okunur."""
    return {p: kayit[(p, s)] for p, s in KILIT.items()}


print(f"{'ilke':<20s} {'kabul':>5s} {'red':>4s} {'t1 kurulum':>28s}"
      f" {'t2 kurulum':>28s} {'ayrı':>5s}")
for ad, kural in ILKELER:
    b = kurulum(yayimla(GIRISIMLER[:T1], kural)[0])
    kayit, kabul, red, cakisma = yayimla(GIRISIMLER, kural)
    g = kurulum(kayit)
    d1 = " ".join(b[p] for p in sorted(KILIT))
    d2 = " ".join(g[p] for p in sorted(KILIT))
    print(f"{ad:<20s} {kabul:5d} {red:4d} {d1:>28s} {d2:>28s}"
          f" {len({d1, d2}):5d}")
print(f"çakışan gönderim: {', '.join(yayimla(GIRISIMLER, True)[3])}")

print()
print(f"{'kilit biçimi':<15s} {'ilke':<20s} {'uyuşmazlık':>10s} "
      f"{'yakalanan':>9s} {'kurulum':>9s} {'ayrı içerik':>12s}")
for kb, ozetli in (("yalnız sürüm", False), ("sürüm ve özet", True)):
    for ad, kural in ILKELER:
        b = kurulum(yayimla(GIRISIMLER[:T1], kural)[0])
        g = kurulum(yayimla(GIRISIMLER, kural)[0])
        uyusmaz = sum(1 for p in KILIT if b[p] != g[p])
        yakalanan = uyusmaz if ozetli else 0
        durdu = yakalanan > 0
        kurulan = ({tuple(sorted(b.items()))} if durdu
                   else {tuple(sorted(b.items())), tuple(sorted(g.items()))})
        print(f"{kb:<15s} {ad:<20s} {uyusmaz:10d} {yakalanan:9d} "
              f"{'duruyor' if durdu else 'sürüyor':>9s} {len(kurulan):12d}")

print()


def coz(paket, geri_cekmeyi_uygula):
    alt, ust = BILDIRIM[paket]
    return [s for s in DEPO[paket] if alt <= s < ust
            and not (geri_cekmeyi_uygula and (paket, s) in GERI_CEKILEN)][-1]


kayit = yayimla(GIRISIMLER, True)[0]
print(f"{'kurulum yolu':<18s} {'geri çekmeden önce':>20s} {'sonra':>20s} "
      f"{'ayrı':>5s}")
for ad, secici in (("çözümleme ile", lambda gc: coz("rapor", gc)),
                   ("kilit dosyasıyla", lambda gc: KILIT["rapor"])):
    o = [f"{'.'.join(map(str, secici(gc)))}·{kayit[('rapor', secici(gc))]}"
         for gc in (False, True)]
    print(f"{ad:<18s} {o[0]:>20s} {o[1]:>20s} {len(set(o)):5d}")
```

```
ilke                 kabul  red                   t1 kurulum                   t2 kurulum  ayrı
üzerine yazılabilir      9    0   3d3f4bcd 69832227 acf4bf32   d032978b 69832227 3c8049dd     2
değiştirilemez           7    2   3d3f4bcd 69832227 acf4bf32   3d3f4bcd 69832227 acf4bf32     1
çakışan gönderim: rapor 1.1, olcum 1.2

kilit biçimi    ilke                 uyuşmazlık yakalanan   kurulum  ayrı içerik
yalnız sürüm    üzerine yazılabilir           2         0   sürüyor            2
yalnız sürüm    değiştirilemez                0         0   sürüyor            1
sürüm ve özet   üzerine yazılabilir           2         2   duruyor            1
sürüm ve özet   değiştirilemez                0         0   sürüyor            1

kurulum yolu         geri çekmeden önce                sonra  ayrı
çözümleme ile              1.1·acf4bf32         1.0·660f7f84     2
kilit dosyasıyla           1.1·acf4bf32         1.1·acf4bf32     1
```

## Dokuz Girişim, İki Red

Üst tablo iki ilkeyi aynı akış üzerinde karşılaştırıyor.

**Üzerine yazılabilir** kayıt dokuz girişimin dokuzunu da kabul ediyor: **9 kabul, 0 red**.
Hiçbir gönderim başarısız olmuyor, hiçbir uyarı çıkmıyor. Buna karşın kaydın içeriği
değişiyor ve bu değişim `t1` ile `t2` sütunlarında görünüyor: `olcum 1.2` özeti `3d3f4bcd`
iken `d032978b` oluyor, `rapor 1.1` özeti `acf4bf32` iken `3c8049dd` oluyor. Aynı kilit
dosyası **2 ayrı kurulum** veriyor.

**Değiştirilemez** kayıt aynı akışta **7 kabul, 2 red** üretiyor. Reddedilen ikisi
`rapor 1.1` ve `olcum 1.2`; ikisi de daha önce başka bir gövdeyle yayımlanmış çiftler. Aynı
gövdenin yeniden gönderildiği iki girişim ise kabul ediliyor — beşinci ve sekizinci
girişimler kaydı değiştirmedikleri için reddedilecek bir şey yok. `t1` ve `t2` sütunları
birebir aynı: **1 ayrı kurulum**.

Sayının okunuşu şudur: **9 kabul, 0 red** görüntüsü bir sağlık göstergesi değildir. İki
kayıt da aynı dokuz girişimi aldı; biri iki çakışmayı **sesli**, öbürü **sessiz** işledi.
Sessiz olanın raporu daha temiz görünüyor ve tam olarak bu yüzden daha az bilgi taşıyor.

Değiştirilemezliğin verdiği güvence tek cümleyle yazılabilir: **bir ad ve sürüm çifti,
ömrü boyunca en fazla bir içeriği adlandırır.** Bu güvence olmadan sürüm numarası bir
tanımlayıcı değil, yalnızca bir etikettir; aynı etiket iki ayrı kutuya yapıştırılabilir.

Aynı gövdenin iki kez kabul edilmesi bu güvenceyle çelişmez ve pratikte gereklidir. Bir
gönderim yarıda kesilebilir, sonucu gönderen tarafa ulaşmayabilir; gönderen o zaman aynı
gövdeyi yeniden gönderir. Değiştirilemez kayıt bunu reddetseydi, gönderen tarafın
gönderimin gerçekleşip gerçekleşmediğini önce sorması gerekirdi. Kural içeriğe bakarak
kurulduğu için ikinci gönderim kaydı değiştirmez ve reddedilecek bir şey doğmaz —
ölçümdeki **7 kabul** sayısının içinde bu iki gönderim de vardır. Yasaklanan işlem
"yeniden göndermek" değil, **kaydı değiştirmek**tir.

## Sürüm Numarasının Taşıdığı İki Söz

Bir sürüm numarası iki ayrı söz verir ve ikisi sık sık tek bir söz sanılır.

**Birinci söz uyumlulukla ilgilidir:** numaranın hangi bölümünün arttığı, değişikliğin
geriye dönük uyumlu olup olmadığını bildirir. Bu söz **Sürüm Kontrolüne Giriş** kursunun
etiketleme dersinde kuruldu ve burada tekrarlanmaz.

**İkinci söz kimlikle ilgilidir:** numara **tek bir içeriği** adlandırır. Bu ders yalnız
ikinci sözü ölçer, ve ölçüm gösteriyor ki bu söz numaranın kendisinden gelmez; kaydın
ilkesinden gelir. Üzerine yazılabilir bir kayıtta numara birinci sözü verebilir ama ikincisini
veremez.

İkisinin bağımsız olduğu, ölçümün üst tablosunda doğrudan görülüyor. Reddedilen iki gönderim
de mevcut bir çifte ayrı gövde göndermeye çalışıyor; ikisinin de uyumluluk sözüyle ilgisi
yok. Gövde tümüyle uyumlu bir düzeltme bile olsa red aynı olurdu, çünkü denetlenen şey
uyumluluk değil **kimliktir**.

Reddin yayımlayan tarafa ödettiği bedel de bellidir: değişiklik yayımlanacaksa **yeni bir
sürüm numarası açılmak zorundadır**. Ölçümün dokuzuncu girişimi tam olarak bunu yapıyor ve
`olcum 2.0` olarak kabul ediliyor. Değiştirilemezlik bir yasak değil, bir yönlendirmedir:
düzeltmeyi engellemez, düzeltmenin **adlandırılmasını** zorunlu kılar. Bunun karşılığında
kurulan taraf, elindeki numaranın anlamının zamanla değişmediğini bilir.

## Kilidin Yazdığı Şey

Orta tablo, kurulan tarafın kendini bu duruma karşı ne kadar koruyabildiğini ölçüyor.

**Yalnız sürüm yazan kilit**, üzerine yazılabilir kayıtta **2 uyuşmazlık** karşısında **0**
yakalıyor. Kurulum sürüyor ve **2 ayrı içerik** kuruluyor. Kilit dosyası burada işini
yapmış sayılır — istenen sürümler kuruldu — ama kurduğu şey iki ayrı koşumda iki ayrı
şeydi. Kilit çözümlemeyi tekleştirdi, **içeriği tekleştirmedi.**

**Sürüm ve özet yazan kilit**, aynı kayıtta **2 uyuşmazlığın 2'sini** yakalıyor ve kurulum
**duruyor**. Kurulan ayrı içerik sayısı **1**'e iniyor, çünkü ikinci kurulum hiç
tamamlanmıyor. Burada kazanılan şey bir kurulumun başarısı değil, **başarısızlığın
görünürlüğüdür**: kayıt sessiz kaldığında kilit sesli olur.

Alt iki satır ilkenin doğru kurulduğu durumu gösteriyor: değiştirilemez kayıtta uyuşmazlık
**0**, yakalanan **0**, kurulum sürüyor, ayrı içerik **1**. Özet yazmanın burada bir
maliyeti yok ve bir kazancı da görünmüyor — çünkü yakalayacak bir şey yok.

Buradan iki ayrı güvencenin bağımsız olduğu çıkar. Değiştirilemezlik **kaydın** verdiği bir
güvencedir ve kurulan taraf onu doğrulayamaz. Özet ise **kurulan tarafın** kendi
doğrulamasıdır ve kaydın ilkesinden bağımsız çalışır. İkisi birlikte kurulduğunda kurulan
taraf kayda güvenmek zorunda kalmaz; yalnız birincisi varsa güvenmek zorundadır, yalnız
ikincisi varsa güvenmez ama sık sık durur.

## Geri Çekme Silme Değildir

Alt tablo üçüncü bir işlemi ölçüyor. Bir sürüm yayımlandıktan sonra kullanılmaması
gerektiği anlaşılabilir. **Geri çekme**, sürümü çözümlemeye kapatır ama kayıttaki içeriğine
dokunmaz.

Ölçüm ikisini ayırıyor. **Çözümleme ile** kurulan taraf, geri çekmeden önce `rapor 1.1`
sürümünü ve `acf4bf32` özetini alıyor; sonra `rapor 1.0` sürümünü ve `660f7f84` özetini
alıyor. **2 ayrı sürüm.** **Kilit dosyasıyla** kurulan taraf ise iki durumda da
`1.1·acf4bf32` alıyor: **1**.

Fark, kilit dosyasının çözümlemeyi hiç çalıştırmamasından gelir. Geri çekme çözümlemenin
aday listesini değiştirir; kilit dosyası aday listesi kullanmaz, doğrudan sürümü ister ve
kayıt onu vermeye devam eder. Bu, kilidin hem gücü hem sınırıdır: geri çekilmiş bir sürümü
kullanmayı **sürdürür** ve bunu sessizce yapar.

Silme ayrı bir işlemdir ve ayrı bir sonuç verir: silinmiş bir sürümde kilit dosyasıyla
kurulum da başarısız olur. Üç işlem — üzerine yazma, geri çekme, silme — üç ayrı sonuç
üretir, ve yalnız ikisi kurulan tarafa haber verir.

Üçünü yan yana koymak, kaydın kurulan tarafa ne borçlu olduğunu tanımlar. **Üzerine yazma**
içeriği değiştirir ve hiçbir şey söylemez; kurulan taraf ancak kendi tuttuğu özetle fark
eder. **Geri çekme** içeriği değiştirmez ve yalnız yeni çözümlemelere görünür; kilitli
kurulum etkilenmez. **Silme** içeriği ortadan kaldırır ve her iki yolu da durdurur.
Sıralama bir sertlik sırası değil, bir **görünürlük** sırasıdır: en sessiz işlem en çok
zarar veren işlemdir, çünkü ötekilerin ikisinde de kurulan taraf bir yanıt alır.

Geri çekmenin sessiz kaldığı yerin de bir adı vardır. Kilit dosyasını yenilemeyen bir proje
geri çekilmiş sürümü kullanmayı sürdürür ve bunu bir hata iletisi olmadan yapar; geri
çekme kararı ancak kilit yenilendiğinde o projeye ulaşır. Kilit, çözümlemenin sonucunu
donduran bir karardır — ve dondurduğu şeye sonradan verilen kararları da dışarıda bırakır.

## Özet

- Paket kaydı `(ad, sürüm)` çiftinden bir dağıtıma giden eşlemedir; üzerine yazılabilir ve
  değiştirilemez olmak üzere iki ilkeyle kurulabilir.
- Aynı dokuz girişim ilk kayıtta **9 kabul, 0 red**, ikincisinde **7 kabul, 2 red** verir;
  değiştirilemezlik yeniden gönderimi değil, **ayrı içerikle** yeniden gönderimi yasaklar.
- Aynı kilit dosyası üzerine yazılabilir kayıtta **2 ayrı kurulum**, değiştirilemez kayıtta
  **1** verir; sürüm numarası tek başına içeriği belirlemez.
- Yalnız sürüm yazan kilit **2 uyuşmazlığın 0'ını**, özet de yazan kilit **2'sini** yakalar
  ve kurulumu durdurur; kaydın ilkesi ile kurulan tarafın doğrulaması bağımsız güvencelerdir.
- Geri çekme çözümlemeyi etkiler, kilidi etkilemez: çözümleme ile kurulan taraf **2 ayrı
  sürüm**, kilitle kurulan taraf **1** görür.

## Sonraki Adım

Yayımlanmış paket kurulan tarafa kodu taşır. Kodun **nasıl kullanılacağını** taşımaz. O
bilgi belgeden gelir, ve belge iki yoldan üretilebilir: elle yazılarak ya da kaynaktan
üretilerek. İki yol arasındaki fark bu kursun bütün derslerinde sorulan soruyla ölçülebilir.
Son ders bunu sorar: kaynaktan belge üretimi hangi sonucu tekleştirir, hangisini
tekleştirmez, ve tekleştirmediği yerde neyin yerini alamaz?
