Saya punya proyek python dengan file konfigurasi di root proyek. File konfigurasi perlu diakses di beberapa file berbeda di seluruh proyek.
Sehingga terlihat seperti: <ROOT>/configuration.conf
<ROOT>/A/a.py
, <ROOT>/A/B/b.py
(ketika b, akses a.py file konfigurasi).
Apa cara terbaik / termudah untuk mendapatkan jalur ke root proyek dan file konfigurasi tanpa bergantung pada file mana di dalam proyek yang saya ikuti? yaitu tanpa menggunakan ../../
? Tidak masalah untuk berasumsi bahwa kita mengetahui nama root proyek.
<ROOT>/__init__.py
ada?os.path.expanduser('~/.myproject/myproject.conf')
. Ia bekerja pada Unix dan Windows.Jawaban:
Anda dapat melakukan ini bagaimana Django melakukannya: tentukan variabel ke Akar Proyek dari berkas yang ada di tingkat atas proyek. Misalnya, jika seperti ini struktur proyek Anda:
Di
definitions.py
Anda dapat menentukan (ini membutuhkanimport os
):Jadi, dengan Project Root diketahui, Anda dapat membuat variabel yang menunjuk ke lokasi konfigurasi (ini dapat didefinisikan di mana saja, tetapi tempat yang logis adalah meletakkannya di lokasi di mana konstanta ditentukan - misalnya
definitions.py
):Kemudian, Anda dapat dengan mudah mengakses konstan (dalam salah satu file lainnya) dengan pernyataan impor (misalnya dalam
utils.py
):from definitions import CONFIG_PATH
.sumber
__init__.py
file ke direktori proyek root juga? Haruskah itu benar? Saya baru saja mulai dengan python dan tidak yakin tentang praktik terbaik. Terima kasih.__init__.py
tidak akan diperlukan, karena file yang hanya diperlukan ketika mendefinisikan paket: The__init__.py
file yang diperlukan untuk membuat Python memperlakukan direktori sebagai mengandung paket; ini dilakukan untuk mencegah direktori dengan nama umum, seperti string, menyembunyikan modul valid yang terjadi kemudian di jalur pencarian modul secara tidak sengaja. Dalam kasus yang paling sederhana,__init__.py
dapat berupa file kosong, tetapi juga dapat menjalankan kode inisialisasi untuk paket atau mengatur__all__
variabel, dijelaskan nanti. Lihat: docs.python.org/3/tutorial/modules.html#packages__init.py__
paket root. Ini akan menghemat pembuatan file lain, serta memungkinkan sintaks yang lebih baikfrom root_pack import ROOT_DIR, CONFIG_PATH
.__init__.py
kosong, tapi itu tidak sepenuhnya benar (bagaimanapun juga itu adalah konvensi). Lihat ini untuk lebih lanjut: stackoverflow.com/questions/2361124/using-init-pyos.path.abspath
memanggil string'__file__'
,. Ingat itu__file__
sebenarnya adalah atribut import yang ditentukan untuk modul Python. Dalam hal ini,__file__
akan mengembalikan nama jalur tempat modul dimuat. Baca lebih lanjut di sini (lihat bagian modul): docs.python.org/3/reference/datamodel.htmlJawaban lain saran untuk menggunakan file di tingkat atas proyek. Ini tidak diperlukan jika Anda menggunakan
pathlib.Path
danparent
(Python 3.4 dan yang lebih baru). Pertimbangkan struktur direktori berikut di mana semua file kecualiREADME.md
danutils.py
telah dihilangkan.Dalam
utils.py
kita mendefinisikan fungsi berikut.Dalam modul mana pun dalam proyek ini, kita sekarang bisa mendapatkan root proyek sebagai berikut.
Manfaat : Setiap modul yang dipanggil
get_project_root
dapat dipindahkan tanpa mengubah perilaku program. Hanya ketika modulutils.py
dipindahkan kita harus memperbaruiget_project_root
dan mengimpor (alat refactoring dapat digunakan untuk mengotomatiskan ini).sumber
Semua solusi sebelumnya tampaknya terlalu rumit untuk apa yang menurut saya Anda butuhkan, dan seringkali tidak berhasil untuk saya. Perintah satu baris berikut melakukan apa yang Anda inginkan:
sumber
Untuk mendapatkan jalur modul "root", Anda dapat menggunakan:
Tetapi yang lebih menarik jika Anda memiliki konfigurasi "objek" di modul paling atas Anda, Anda bisa -membaca- darinya seperti ini:
sumber
os
tidak tersedia secara default. Perlu mengimporos
. Jadi menambahkan garisimport os
akan membuat jawaban menjadi lebih lengkap.python3 -m topmodule.submodule.script
akan memberi/path/to/topmodule/submodule
alih-alih/path/to/topmodule
.Cara standar untuk mencapai ini adalah dengan menggunakan
pkg_resources
modul yang merupakan bagian darisetuptools
paket.setuptools
digunakan untuk membuat paket python yang dapat diinstal.Anda dapat menggunakan
pkg_resources
untuk mengembalikan konten file yang Anda inginkan sebagai string dan Anda dapat menggunakanpkg_resources
untuk mendapatkan jalur sebenarnya dari file yang diinginkan di sistem Anda.Katakanlah Anda memiliki sebuah paket bernama
stackoverflow
.Sekarang katakanlah Anda ingin mengakses file Rush dari modul
app.run
. Gunakanpkg_resources.resouces_filename
untuk mendapatkan jalur ke Rush danpkg_resources.resource_string
untuk mendapatkan konten Rush; demikian:Hasil:
Ini berfungsi untuk semua paket di jalur python Anda. Jadi jika Anda ingin tahu di mana
lxml.etree
ada di sistem Anda:keluaran:
Intinya adalah Anda dapat menggunakan metode standar ini untuk mengakses file yang diinstal pada sistem Anda (misalnya pip install xxx atau yum -y install python-xxx) dan file yang ada di dalam modul yang sedang Anda kerjakan.
sumber
Di Bawah Kode Mengembalikan jalur sampai root proyek Anda
sumber
Mencoba:
sumber
Saya berjuang dengan masalah ini juga sampai saya menemukan solusi ini. Ini adalah solusi terbersih menurut saya.
Di setup.py Anda tambahkan "paket"
Di python_script.py Anda
sumber
python3 setup.py install
dengannya tidak lagi mengarah ke folder kode sumber, tetapi ke telur di dalamnya~./virtualenv/..../app.egg
. Jadi saya harus memasukkan file konfigurasi ke dalam paket instalasi.Sebagai contoh: Saya ingin menjalankan runio.py dari dalam helper1.py
Contoh pohon proyek:
Dapatkan root proyek:
Bangun jalur ke skrip:
sumber
Ini bekerja untuk saya menggunakan proyek PyCharm standar dengan lingkungan virtual saya (venv) di bawah direktori root proyek.
Kode di bawah ini bukan yang tercantik, tetapi secara konsisten mendapatkan root proyek. Ia mengembalikan path direktori lengkap ke venv dari
VIRTUAL_ENV
variabel lingkungan misalnya/Users/NAME/documents/PROJECT/venv
Itu kemudian membagi jalur pada akhirnya
/
, memberikan sebuah array dengan dua elemen. Elemen pertama akan menjadi jalur proyek misalnya/Users/NAME/documents/PROJECT
sumber
Saya baru-baru ini mencoba melakukan sesuatu yang serupa dan saya menemukan jawaban ini tidak memadai untuk kasus penggunaan saya (perpustakaan terdistribusi yang perlu mendeteksi root proyek). Terutama saya telah berjuang melawan lingkungan dan platform yang berbeda, dan masih belum menemukan sesuatu yang sangat universal.
Kode lokal untuk proyek
Saya telah melihat contoh ini disebutkan dan digunakan di beberapa tempat, Django, dll.
Sesederhana ini, ini hanya berfungsi jika file tempat cuplikan sebenarnya adalah bagian dari proyek. Kami tidak mengambil direktori proyek, melainkan direktori cuplikan
Demikian pula, pendekatan sys.modules rusak ketika dipanggil dari luar titik masuk aplikasi, khususnya saya telah mengamati utas anak tidak dapat menentukan ini tanpa hubungannya kembali ke modul ' utama '. Saya secara eksplisit meletakkan impor di dalam fungsi untuk mendemonstrasikan impor dari utas anak, memindahkannya ke tingkat atas app.py akan memperbaikinya.
app.py
settings.py
Menjalankan program ini menghasilkan kesalahan atribut:
... maka solusi berbasis threading
Lokasi independen
Menggunakan struktur aplikasi yang sama seperti sebelumnya tetapi memodifikasi settings.py
Menguraikannya: Pertama, kami ingin menemukan ID utas utas utama secara akurat. Dalam Python3.4 + perpustakaan threading
threading.main_thread()
bagaimanapun, semua orang tidak menggunakan 3.4+ jadi kami mencari melalui semua utas mencari utas utama simpan ID-nya. Jika utas utama sudah keluar, utas tidak akan terdaftar dithreading.enumerate()
. Kami meningkatkan aRuntimeError()
dalam kasus ini sampai saya menemukan solusi yang lebih baik.Selanjutnya kita menemukan bingkai tumpukan pertama dari utas utama. Dengan menggunakan fungsi spesifik cPython,
sys._current_frames()
kami mendapatkan kamus bingkai tumpukan setiap utas saat ini. Kemudian dengan memanfaatkannya,inspect.getouterframes()
kita dapat mengambil seluruh tumpukan untuk utas utama dan bingkai pertama. current_main_frame = sys._current_frames () [main_id] base_frame = inspect.getouterframes (current_main_frame) [- 1] Akhirnya, perbedaan antara implementasi Windows dan Linuxinspect.getouterframes()
perlu ditangani. Menggunakan nama file yang dibersihkan,os.path.abspath()
danos.path.dirname()
membersihkan semuanya.Sejauh ini saya telah menguji ini di Python2.7 dan 3.6 di Windows serta Python3.4 di WSL
sumber
Jika Anda bekerja dengan proyek anaconda, Anda dapat meminta PROJECT_ROOT dari variabel lingkungan -> os.getenv ('PROJECT_ROOT'). Ini hanya berfungsi jika skrip dijalankan melalui anaconda-project run.
Jika Anda tidak ingin skrip Anda dijalankan oleh proyek-anaconda, Anda dapat menanyakan jalur absolut dari biner yang dapat dieksekusi dari interpreter Python yang Anda gunakan dan mengekstrak string jalur ke direktori envs eksklusif. Misalnya: Penerjemah python dari conda env saya berada di:
Ini bekerja hanya dengan proyek-konda dengan struktur proyek tetap dari proyek anaconda
sumber
Saya menggunakan metode ../ untuk mengambil jalur proyek saat ini.
Contoh: Project1 - D: \ projects
src
ConfigurationFiles
Configuration.cfg
Path = "../ src / ConfigurationFiles / Configuration.cfg"
sumber
Pada saat penulisan, tidak ada solusi lain yang sangat mandiri. Mereka bergantung pada variabel lingkungan atau posisi modul dalam struktur paket. Jawaban teratas dengan solusi 'Django' menjadi korban dari yang terakhir dengan membutuhkan impor relatif. Ini juga memiliki kerugian karena harus memodifikasi modul di tingkat atas.
Ini harus menjadi pendekatan yang tepat untuk menemukan jalur direktori dari paket tingkat atas:
Ia bekerja dengan mengambil komponen pertama dalam string bertitik yang ada di dalamnya
__name__
dan menggunakannya sebagai kuncisys.modules
yang mengembalikan objek modul dari paket tingkat atas. Its__file__
atribut berisi jalan yang kita inginkan setelah pemangkasan off/__init__.py
menggunakanos.path.dirname()
.Solusi ini berdiri sendiri. Ini berfungsi di mana saja di modul apa pun dari paket, termasuk di
__init__.py
file tingkat atas .sumber
Saya harus menerapkan solusi khusus karena tidak sesederhana yang Anda bayangkan. Solusi saya didasarkan pada pemeriksaan jejak tumpukan (
inspect.stack()
) +sys.path
dan berfungsi dengan baik di mana pun lokasi modul python di mana fungsi tersebut dipanggil atau penerjemah (saya mencoba dengan menjalankannya di PyCharm, di shell puisi dan lainnya ... ). Ini adalah implementasi lengkap dengan komentar:sumber
Ada banyak jawaban di sini tetapi saya tidak dapat menemukan sesuatu yang sederhana yang mencakup semua kasus, jadi izinkan saya untuk menyarankan solusi saya juga:
sumber