Кроссплатформенное распространение приложений на Python

StackOverflow https://stackoverflow.com/questions/1688105

Вопрос

Я хочу распространять свое приложение на OSX (используя py2app) и в виде пакета Debian.

Структура моего приложения выглядит следующим образом:

app/
     debian/
            <lots of debian related stuff>
     scripts/
             app
     app/
         __init__.py
         app.py
         mod1/
              __init__.py
              a.py
         mod2/
              __init__.py
              b.py

Мой setup.py выглядит примерно так:

from setuptools import setup
import os
import os.path

osname = os.uname()[0]

if osname == 'Darwin':
    APP = ['app/app.py']
    DATA_FILES = []
    OPTIONS = {'argv_emulation': True}

    setup(
        app=APP,
        data_files=DATA_FILES,
        options={'py2app': OPTIONS},
        setup_requires=['py2app'],
    )
elif osname == 'Linux':
        setup(
        name = "app",
        version = "0.0.1",
        description = "foo bar",
        packages = ["app", "app.mod1", "app.mod2"],
        scripts = ["scripts/app"],
        data_files = [
            ("/usr/bin", ["scripts/app"]),
       ]
    )

Затем, в b.py (это на OSX):

from app.mod2.b import *

Я получаю:

ImportError: No module named mod2.b

Таким образом, в принципе, mod2 не может получить доступ к mod1.В Linux проблем нет, потому что модуль python 'app' установлен глобально в /usr/shared /pyshared.Но в OSX приложение, очевидно, будет автономным .app, созданным py2app.Интересно, если я подошел к этому совершенно неправильно, существуют ли какие-либо рекомендации при распространении приложений Python на OSX?

Редактировать:Я также попробовал подобный взлом в b.py:

from ..mod2.b import *

ValueError: Attempted relative import beyond toplevel package

Редактировать 2:Кажется, это связано с этим Как выполнить относительный импорт в Python?

Это было полезно?

Решение

Я не уверен, является ли это "наилучшей практикой" или нет (я не распространял много программного обеспечения на python надлежащим образом), но я бы просто убедился, что пакет приложений верхнего уровня был в sys.path.Что-то вроде помещения следующего на верхний уровень __init__.py:

try:
    import myapp
except ImportError:
    import sys
    from os.path import abspath, dirname, split
    parent_dir = split(dirname(abspath(__file__)))[0]
    sys.path.append(parent_dir)

Я думаю, что это должно быть правильно с точки зрения кроссплатформенности.

Редактировать:Как указывает kaizer.se , это может не сработать в __init__.py файл, в зависимости от того, как выполняется код, который вы вызываете.Это сработало бы только в том случае, если этот файл будет оценен.Главное - убедиться, что пакет верхнего уровня находится в sys.path из некоторого кода, который на самом деле запущен.

Часто, так что я выполняю отдельные файлы непосредственно внутри пакета (для тестирования с помощью if __name__ eq '__main__' идиома), я сделаю что-то вроде размещения заявления:

import _setup

В верхней части отдельного файла, о котором идет речь, а затем создайте файл _setup.py который выполняет сжатие пути по мере необходимости.Итак, что-то вроде:

package/
    __init__.py
    _setup.py
    mod1/
        __init__.py
        _setup.py
        somemodule.py

Если вы import _setup От somemodule.py, этот установочный файл может гарантировать, что пакет верхнего уровня находится в sys.path перед остальной частью кода в somemodule.py оценивается.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top