2009-04-22 37 views
65

Tôi đang viết một gói python với các mô-đun cần mở tệp dữ liệu trong thư mục con ./data/. Ngay bây giờ tôi có các đường dẫn đến các tệp được mã hóa cứng vào các lớp và các hàm của tôi. Tôi muốn viết mã mạnh mẽ hơn có thể truy cập vào thư mục phụ bất kể nó được cài đặt ở đâu trên hệ thống của người dùng.Truy cập Python dữ liệu trong gói Subdirectory

Tôi đã thử một loạt các phương pháp, nhưng cho đến nay tôi đã không có may mắn. Dường như hầu hết các lệnh "thư mục hiện tại" trả về thư mục của trình thông dịch python của hệ thống, chứ không phải thư mục của mô-đun.

Điều này có vẻ như nó phải là một vấn đề thường gặp. Nhưng tôi không thể hình dung ra được. Một phần của vấn đề là các tệp dữ liệu của tôi không phải là các tệp .py, vì vậy tôi không thể sử dụng các chức năng nhập và các chức năng tương tự.

Mọi đề xuất?

Ngay bây giờ thư mục gói của tôi trông giống như:

/ 
__init__.py 
module1.py 
module2.py 
data/ 
    data.txt 

tôi đang cố gắng để truy cập data.txt từ module*.py

Cảm ơn!

Trả lời

24

Bạn có thể sử dụng gạch-underscore- tệp-gạch dưới-gạch dưới (__file__) để nhận đường dẫn đến gói, như sau:

import os 
this_dir, this_filename = os.path.split(__file__) 
DATA_PATH = os.path.join(this_dir, "data", "data.txt") 
print open(DATA_PATH).read() 
+24

Điều này sẽ không hoạt động nếu các tệp nằm trong bản phân phối (trứng của IE). Sử dụng pkg_resources để lấy tệp dữ liệu. – Chris

+0

Thật vậy, điều này bị hỏng. – Federico

6

Tôi nghĩ rằng tôi đã tìm kiếm câu trả lời.

tôi thực hiện một data_path.py mô-đun, mà tôi nhập vào các module khác của tôi có chứa:

data_path = os.path.join(os.path.dirname(__file__),'data') 

Và sau đó tôi mở tất cả các file của tôi với

open(os.path.join(data_path,'filename'), <param>) 
+0

Điều này sẽ không hoạt động khi tài nguyên nằm trong bản phân phối lưu trữ (chẳng hạn như trứng nén). Thích một cái gì đó như thế: 'pkg_resources.resource_string ('pkg_name', 'data/file.txt')' – ankostis

+0

@ankostis setuptools đủ thông minh để trích xuất kho lưu trữ nếu nó phát hiện rằng bạn đã sử dụng '__file__' ở đâu đó. Trong trường hợp của tôi, tôi sử dụng một thư viện mà thực sự muốn con đường và không phải dòng. Tất nhiên tôi có thể ghi các tập tin tạm thời vào đĩa nhưng bị lười, tôi chỉ sử dụng tính năng của setuptools. – letmaik

95

Cách tiêu chuẩn để thực hiện điều này là với các gói setuptools và pkg_resources.

Bạn có thể đặt ra gói của bạn theo thứ bậc sau, và cấu hình các tập tin cài đặt gói để trỏ nó nguồn dữ liệu của bạn, theo liên kết này:

http://docs.python.org/distutils/setupscript.html#installing-package-data

Bạn có thể sau đó lại tìm và sử dụng các tập tin sử dụng pkg_resources, theo liên kết này:

http://peak.telecommunity.com/DevCenter/PkgResources#basic-resource-access

import pkg_resources 

DATA_PATH = pkg_resources.resource_filename('<package name>', 'data/') 
DB_FILE = pkg_resources.resource_filename('<package name>', 'data/sqlite.db') 
+0

Tôi nghĩ rằng đây là cách ưa thích, tôi không hoàn toàn chắc chắn về lý do nhưng dự án hiển thị cảnh báo khi bạn tham khảo gói/mô-đun với '__file__'. – lukecampbell

+1

Sẽ không * pkg_resources * tạo phụ thuộc vào thời gian chạy trên * setuptools *? Ví dụ, tôi phân phối lại một gói Debian vậy tại sao tôi lại phụ thuộc vào 'python-setuptools' chỉ cho điều đó? Cho đến nay '__file__' hoạt động tốt cho tôi. – mlt

+3

Tại sao điều này tốt hơn: Lớp ResourceManager cung cấp quyền truy cập thống nhất vào tài nguyên gói, cho dù các tài nguyên đó tồn tại dưới dạng tệp và thư mục hay được nén trong một kho lưu trữ của một số loại – vrdhn

11

Để cung cấp một giải pháp làm việc ngày hôm nay. Chắc chắn sử dụng API này để không phát minh lại tất cả các bánh xe đó.

Tên tệp hệ thống tệp thực sự là cần thiết. Trứng nén sẽ được trích xuất vào thư mục bộ nhớ cache:

from pkg_resources import resource_filename, Requirement 

path_to_vik_logo = resource_filename(Requirement.parse("enb.portals"), "enb/portals/reports/VIK_logo.png") 

Trả về một đối tượng giống như tệp cho tài nguyên được chỉ định; nó có thể là một tập tin thực tế, một StringIO, hoặc một số đối tượng tương tự. Luồng đang ở trong "chế độ nhị phân", theo nghĩa là bất kỳ byte nào trong tài nguyên sẽ được đọc dưới dạng.

from pkg_resources import resource_stream, Requirement 

vik_logo_as_stream = resource_stream(Requirement.parse("enb.portals"), "enb/portals/reports/VIK_logo.png") 

Gói Discovery và Resource truy cập sử dụng pkg_resources

3

Bạn cần một cái tên cho toàn bộ mô-đun của bạn, bạn đang đưa ra cây thư mục không làm danh sách chi tiết đó, đối với tôi điều này đã làm việc:

import pkg_resources 
print( 
    pkg_resources.resource_filename(__name__, 'data/data.txt') 
) 

Các trình cài đặt không rõ ràng dường như không giải quyết các tệp dựa trên tên khớp với các tệp dữ liệu được đóng gói, bạn cần phải bao gồm tiền tố data/ nhiều bất kể là gì. Bạn có thể sử dụng os.path.join('data', 'data.txt) nếu bạn cần bộ tách thư mục thay thế, Nói chung tôi không tìm thấy vấn đề tương thích với phân cách thư mục phong cách unix mã hóa cứng mặc dù.

Các vấn đề liên quan