5 puan yazan GN⁺ 2025-03-31 | 1 yorum | WhatsApp'ta paylaş
  • Küçük API test betiklerinde bile bağımlılıklar yüzünden çalışma ortamını eşleştirmek gerekir; uv çalıştırma shebang’i kullanıldığında kurulum adımları olmadan doğrudan çalıştırılabilir bir biçim elde edilebilir
  • Örnek jam_users.py, Go API’sinin /users endpoint’ini test etmek için httpx, IPython ve loguru ile kullanıcıları silip oluşturduktan sonra REPL’e girer
  • Geleneksel yöntemde paketleri sistem Python’una global olarak kurmak ya da sanal ortamı elle hazırlamak gerektiğinden, betiği paylaşmak ve yeniden çalıştırmak zahmetlidir
  • # /// script başlığında dependencies = ["ipython", "httpx", "loguru"] tanımlanıp uv run jam_users.py çalıştırıldığında uv, izole ortamı ve bağımlılık kurulumunu yönetir
  • #!/usr/bin/env -S uv run --script shebang’i ve çalıştırma izni eklendiğinde, Unix sistemlerde yalnızca uv kurulu olarak ./jam_users.py gibi çalıştırılabilir

Bağımlılıkları betiğin içinde tanımlama

  • Örnek jam_users.py, yerel API http://localhost:4000/v1/users üzerinde test kullanıcı verilerini hazırlar
    • httpx ile API istekleri gönderir
    • IPython REPL’ine girerek yanıtları inceler ve teste devam eder
    • loguru ile silme ve oluşturma logları bırakır
  • Temel betik akışı, kullanıcı listesini sıfırladıktan sonra test verilerini yeniden doldurur
    • GET /v1/users ile mevcut kullanıcı listesini alır
    • Her kullanıcı için DELETE /v1/users/{id} çağrısı yapar
    • Hazırlanan kullanıcı listesini JSON olarak POST /v1/users’a gönderir
    • Ardından IPython.embed() ile REPL’i açar
  • python jam_users.py ile çalıştırmak için httpx, IPython ve loguru’nun çalışma ortamında zaten kurulu olması gerekir
  • Sistem Python’una global kurulum yapmak veya ayrı bir sanal ortam oluşturmak da mümkündür, ancak ikisi de çalıştırmadan önce hazırlık gerektirir
    • Global kurulum, sistem Python’unu paketlerle karmaşık hale getirebilir
    • Sanal ortam yöntemi; oluşturma, etkinleştirme, kurulum ve çalıştırma süreçlerini elle yönetmeyi gerektirir
    • Her iki yöntemde de gerekli paketlerle uyumlu bir sistem Python’u bulunmalıdır

uv ile doğrudan çalıştırılabilir betik oluşturma

  • uv’nin # /// script etiketini betiğin üst kısmına koyarsanız dosya içinde bağımlılıkları tanımlayabilirsiniz
# /// script

# dependencies = ["ipython", "httpx", "loguru"]

# ///
  • Bu başlık varsa uv run jam_users.py ile çalıştırılabilir
    • uv, betik için izole bir sanal ortam oluşturur
    • Gerekli bağımlılıkları indirir ve kurar
    • Betiği ilgili sanal ortam bağlamında çalıştırır
  • Normal Python shebang’i olan #!/usr/bin/env python, Python # /// script yorumlarını yok saydığı için uv’nin betik başlığından yararlanamaz
  • Shebang’e uv çağrısını doğrudan koyarsanız betiği çalıştırılabilir dosya gibi ele alabilirsiniz
#!/usr/bin/env -S uv run --script

# /// script

# dependencies = ["ipython", "httpx", "loguru"]

# ///
  • env’in -S bayrağı, ardından gelen dizgenin ayrı argümanlara bölünerek env’e iletilmesini sağlar
  • chmod +x jam_users.py ile çalıştırma izni verdikten sonra şu şekilde doğrudan çalıştırılabilir
./jam_users.py
  • Bu yöntem, Unix sistemde uv kuruluysa ayrı bir bağımlılık kurulumu veya sanal ortam yönetimi olmadan betiğin çalıştırılmasını sağlar
  • Karmaşık Python betiklerini başka kullanıcılara iletirken, çalıştırma öncesi sistem hazırlık adımlarını uzun uzun anlatma yükünü azaltabilir

1 yorum

 
GN⁺ 2025-03-31
Hacker News yorumları
  • Özellikle uv özelinde değil, genel olarak yorumlarla kod yürütmesini kontrol etme yaklaşımı rahatsız edici
    Linter yönergeleri ya da geliştirici notları için yorum kullanmak sorun değil, ama ayar veya çalıştırmayla ilgili veriler söz konusuysa UV_ENV = { "dependencies": { "requests": "2.32.3", "pandas": "2.2.3" } } gibi bir biçim çok daha iyi olurdu
    Bu yaklaşım geçerli Python sözdizimidir, rastgele yorum ayrıştırması yerine standart veri yapıları kullandığı için üretmesi ve doğrulaması kolaydır ve her şeyden önemlisi tüm yorumlar kaldırılsa bile kod aynı şekilde çalışmalıdır ilkesine uyar

    • Katılıyorum ama bir adım daha ileri gitmek isterim
      Önerdiğiniz yaklaşım da çalışma zamanında hiçbir şey yapmayan, yalnızca statik analizle ayrıştırılan bir sihirli sabit; bu yüzden uv okumasa bile başka bir araç bunu kullanılmayan kod sanıp silebilir
      Bunun yerine import uv sonrasında uv.exec(dependencies=["clown"], python=">=3.10") gibi bir çağrıyla uv'ye ne yapacağını doğrudan söylemek mümkün olabilir
      İlk çalıştırma, bu varsayımsal uv paketini bulabilen herhangi bir Python çalışma zamanında yapılır; uv paketi sanal ortamı ve Python çalışma zamanını hazırladıktan sonra ortam değişkeni gibi bir bayrak ekleyip re-exec(3) yapar
      İkinci çalışma zamanında ise bayrağı algılayan uv.exec hiçbir şey yapmaz
    • Bunu uv icat etmedi; diğer araçlar gibi standart PEP 723 kullanılıyor
      https://peps.python.org/pep-0723/
    • Mantıklı, ama bu tür buyurgan kodu ayrıştırıp değerlendirmek, en az ayrıcalık ilkesi gereği bunu bildirimsel veri olarak tutmaktan çok daha zor ve daha az esnek olur
      Ayrıca shebang satırının kendisi de aslında yorum olarak çalışır
      Sadece 45 yıldır o kadar yerleşmiştir ki insanlar onun bir shell yorumu olduğunu pek fark etmez
    • “Yorumlar kaldırıldığında da kod aynı şekilde çalışmalı” şartı hâlâ sağlanıyor
      Aynı bağımlılıklar kurulduysa kod aynı şekilde çalışır
      Bu, kodun kendi anlamını değiştirmekten çok kodun çalıştığı ortamı değiştiriyor; bu açıdan shell script’in başındaki #!/bin/bash yorumundan farklı değil
    • Buna tamamen katılıyorum ve bu tür bir biçimin sonunda standartlaşmasını isterim
      Yine de uv muhtemelen bağımlılıkları anlamak için kodu çalıştırmak istemez; dolayısıyla bu, Python sözdiziminin çok sınırlı bir alt kümesi olmak zorunda kalırdı
      Zaten böyle bir şeye ihtiyaç duyulması, dilin zayıf yönünü gösteriyor
      import ifadesinin kendisi bağımlılıklarla ilgili tüm bilgiyi aktarabilmeliydi
  • Son birkaç ayda bu konu HN'de çok sık gündeme geldi; yakın tarihli örnekler şunlar:
    https://news.ycombinator.com/item?id=43500124
    https://news.ycombinator.com/item?id=42463975
    uv'yi seviyorum ama self-contained ifadesine iki açıdan katılmak zor
    Birincisi, script’i çalıştırmak için uv'nin zaten kurulu olması gerekiyor
    Bir shell script ile uv'nin kurulu olup olmadığını kontrol edip yoksa curlpipe ile kurdurabilirsiniz, ama bu hem ciddi miktarda boilerplate ekler hem de curlpipe yaklaşımının kendisi pek iyi değildir
    İkincisi, home dizininin bir yerinde otomatik olarak sanal ortam oluşturulması gerçekten self-contained sayılmaz
    Tek seferlik çalıştırıp script’i silseniz bile o sanal ortam kalır ve yer kaplamaya devam eder; uv belgelerinde de bu tür geçici sanal ortamların otomatik temizlendiğine dair bir garanti bulamadım

    • uv gerektiği ve yoksa elle kurmak ya da curl | sh kullanmak zorunda kalınması yönündeki şikâyet yerinde
      Yine de paket yöneticileri uv'yi depolarına almaya başladıkça bu daha az sorun olacaktır
      Örneğin uv zaten Alpine Linux ve Homebrew'de mevcut: https://repology.org/project/uv/versions
      Ayrıca satır içi script metadata Python standardının bir parçası
      Sistemde uv yoksa ve paketlenmemişse ama script için uygun bir Python sürümü varsa, pipx ile çalıştırılabilir: https://pipx.pypa.io/stable/examples/#pipx-run-examples
      pipx çok daha yaygın şekilde paketlenmiş durumda: https://repology.org/project/pipx/versions
    • Bu sorunu çözmek için docker+uv shebang yaklaşımını biraz zorlayarak bir araya getirdim ve bir ölçüde çalıştı
      Rastgele bir geliştirici makinesinde Docker, uv'den daha yaygın olabilir; üstelik orijinal yazı da bir şirket projesinden söz ettiği için kulağa makul geldi
      Ancak şu anda hiç önbellekleme yapmadığı için her çalıştırmada indirme olması tuhaf duruyor; muhtemelen volume ile düzeltilebilir
      Şöyle bir şey: https://hugojosefson.github.io/docker-shebang/#python
    • Normalde bir bilgisayarda program çalıştırmak için önce bir şeyler kurmak gerekir; bu yüzden uv kurma gerekliliği tek başına o kadar da kötü görünmüyor
      Yine de çalışma sırasında internetten kaynağı belirsiz bir şey indiriliyorsa buna self-contained demek zor; gerçekten tam self-contained olana en yakın şey AppImage gibi duruyor
    • %100 katılıyorum
      py2exe gibi araçlar kullanılarak self-contained bir “Python script'i” yapılabilir
      Geliştirici tarafında pek çok sorun çıkarır ama kullanıcı tarafındaki sorunları en aza indirir
    • Küçük bir ek not olarak, uv'nin paket tekilleştirmesi sayesinde benzersiz bağımlılıklar olmadığı sürece virtualenv disk alanı kaplamaz
  • Nix ile de aynı yaklaşım kullanılıyor ve shebang satırı şöyle görünüyor
    #! nix-shell -i python3 -p "python312.withPackages (pkgs: [ pkgs.boto3 pkgs.click ])"
    Bunu yapınca sistemde gerekli olan tek şey Nix oluyor; Python’ın kurulu olması bile gerekmiyor

    • Doğru, ama hâlâ PyPI paketlerinin çoğu nixpkgs içinde paketlenmiş değil; bu yüzden uv kadar genel amaçlı bir yaklaşım sayılmaz
    • Kaynak metinde de tam olarak dendiği gibi, uv gerektiğinde Python’ı anında kuruyor
    • Aynı teknik herhangi bir dile uygulanabilir
      En bariz örnek, tüm bağımlılıkların belirtildiği bash; ayrıca Nix shebang ile hızlı tek dosyalık Rust betikleri de yaptım
      https://nixos.wiki/wiki/Nix-shell_shebang
    • Nix’in kurulu olması şartı, uv’nin kurulu olması şartından çok daha ağır bir gereksinim
    • nix-shell yerine flake tabanlı nix shell komutuyla aynı işi nasıl yapabileceğimi merak ediyorum
  • Diğer yorumlarda da olduğu gibi, “self-contained” iddiası uv kurulu olmasına dayanıyor
    Gerçekten self-contained bir Python betiği istiyorsanız Nuitka derleyicisine bakmaya değer
    Bunu production’daki gRPC servislerinde sorunsuz kullanıyoruz ve tek yapmanız gereken nuitka --onefile run.py çalıştırmak
    Bir derleyici olduğu için ortaya çıkan ikili dosya, PyInstaller ile paketlenmiş özgün Python programından daha hızlı bile olabiliyor
    Yazarın GitHub sayfasında “Hayat misyonum, mümkün olan en iyi Python Compiler’ı yapmak için ölünceye kadar uğraşmak” yazıyor
    https://nuitka.net/
    https://github.com/kayhayen

  • Bu deseni gerçekten seviyorum ama ne yazık ki LSP ile düzgün çalıştıramadım
    Helix’te pyright kullanıyorum; editörü uv run hx script.py ile başlatsam da işe yaramıyor
    uv run --with whatever-it-is-i-need hx script.py gibi yapabiliyorum ama giderek daha fazla tekrar oluşuyor

    • Kendim yazdığım çirkin bir uve betiği kullanıyorum
      $ cat ~/.local/bin/uve
      #!/bin/bash
      temp=$(mktemp)
      uv export --script $1 --no-hashes > $temp
      uv run --with-requirements $temp vim $1
      unlink $temp
      Umarım editör yakında uv python find --script desteği ekler
  • Oldukça faydalı görünüyor
    Python tabanlı projeleri uzun vadeli dağıtırken uv’nin daha güvenli bir tercih olup olmadığını merak ediyorum
    Yaklaşık 5 yıl önce bağımlılık yönetimi için Anaconda kullanmıştım; sonra kurallar değişti ve 200’den fazla çalışanı olan kurumsal müşteriler artık Anaconda’yı ücretsiz kullanamaz, ticari lisans ödemek zorunda kalır oldu; bu rug pull olayını hatırlatıyor

    • uv, MIT veya Apache-2.0 lisanslı
      Geliştirmeyi durdurabilirler ya da gelecekteki çalışmayı başka lisanslı bir fork’a taşıyabilirler, ama geçmiş lisansları geriye dönük olarak değiştiremezler; yani şu anda var olan şeyin açık kaynak olduğu garanti
      Gerçekten endişeleniyorsanız bir fork oluşturup senkron tutabilirsiniz
      Pratikte bu, neredeyse tüm diğer OSS projeleri için de aynı şekilde geçerli; o yüzden çok dert etmezdim
      Bildiğim kadarıyla conda hiçbir zaman açık kaynak olmadı ve ikili dosya dağıtıyordu
      https://github.com/astral-sh/uv?tab=readme-ov-file#license
    • Bence Anaconda’daki rug pull depo tarafında oldu
      conda-forge paketleri hâlâ ücretsiz kullanılabiliyor
      uv zaten sadece PyPI kullanıyor; bir sorun çıkarsa uv’den pip veya Poetry gibi başka bir araca geçersiniz ve paketleri yine aynı yerden almaya devam edersiniz
    • Bir projede katkıcı lisans sözleşmesi (CLA) varsa ve katkı telif hakkını proje sahibine devrettiriyorsa yeniden lisanslama mümkün diye biliyorum
      Böyle bir sahip de eninde sonunda akla gelebilecek en kötü zengine satılır
      uv’nin katkı rehberine ve issue’larına göz attım ama CLA görmedim; PyTorch’un katkı rehberinin en üstünde ise CLA vardı
      Yine de Anaconda’nın son FOSS sürümü için bir topluluk fork’u olmalıydı
      Redis’te böyle oldu ve Redis de CLA kullanıyor: https://github.com/redis/redis/blob/unstable/CONTRIBUTING.md#redis-software-grant-and-contributor-license-agreement
      Asla CLA imzalamamalısınız
      Bana kalırsa sadece copyleft projelere katkı vermek daha iyi
      Bedava çalışmak için fazla para kazanıyoruz
  • Küçük yardımcı araçlar için container kullanmak yerine iyi bir paketleme alternatifi gibi görünüyor
    Şimdi bütün ekip arkadaşlarımı uv kurmaları için ikna etmem gerekecek

    • uv şaşırtıcı derecede hızlı, o yüzden yardımcı olacaktır
    • Bizim açımızdan engel, SCA zafiyet tarayıcımızın henüz uv ile çalışmıyor olması
  • Ruby tarafındaki bundler/inline’a benziyor
    Python’da da benzer bir şeyin gelmesine sevindim ve pratikte gerçekten çok kullanışlı
    https://bundler.io/guides/bundler_in_a_single_file_ruby_script.html

  • Bunu Windows'ta çalıştıran biri olup olmadığını merak ediyorum
    Üzerinde çalıştığım oyun modu aracı için bu hileyi kullanmak istedim ama shebang hilesini çalıştıramadım

  • Bu kullanım senaryosu sayesinde uv'yi sevdim ama resmi ve çok faydalı bir PEP'in resmi Python araçları tarafından desteklenmemesi bana Zen of Python'a aykırı geliyor
    Benim açımdan bu, Python'ın ilk kez “batteries included” olmadığı andı
    Artık sistemimde iki Python bağımlılık yöneticisi var
    Python bağımlılık yönetimi hakkında söylenecek çok şey olduğunu biliyorum ama son birkaç yıldır projede sadece requirements.txt varsa varsayılan pip+venv ile idare ediyordum

    • Python derleme spesifikasyonlarında buna benzer bir akış vardı
      pyproject.toml'ın tomllib kütüphanesinden önce çıktığını hatırlıyorum
      Bu yüzden birkaç sürüm boyunca modülleri Python'ın varsayılan olarak okuyamadığı bir dilde belirtmek gerekiyordu
      Bu, kullanılmayan meta veri içeren varsayılan bir yöntem olmasından daha kötü bir durum
      Zaten bu yüzden meta veri; aksi halde sadece Python sözdizimi olurdu