Umieszczanie oddzielnych pakietów Pythona w tej samej przestrzeni nazw?

Rozwijam Framework Pythona, który miałby "addony" napisane jako oddzielne pakiety. Tj.:

import myframework
from myframework.addons import foo, bar

Teraz, to co staram się zorganizować jest tak, że te dodatki mogą być dystrybuowane oddzielnie od core framework i wtryskiwane do myframework.addons przestrzeni nazw.

Obecnie moim najlepszym rozwiązaniem jest następujące. Dodatek zostałby wdrożony (najprawdopodobniej do {python_version}/site-packages/ w ten sposób:

fooext/
fooext/__init__.py
fooext/myframework/
fooext/myframework/__init__.py
fooext/myframework/addons/
fooext/myframework/addons/__init__.py
fooext/myframework/addons/foo.py

fooext/myframework/addons/__init__.py będzie miał kod rozszerzenia ścieżki pkgutil:

import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)

Problem aby to zadziałało, PYTHONPATH musi mieć w sobie fooext/, jednak jedyną rzeczą, jaką musi mieć, jest macierzysty katalog instalacyjny(najprawdopodobniej wyżej wymieniony site-packages).

Rozwiązaniem jest posiadanie dodatkowego kodu w myframework/addons/__init__.py, który zmieniłby sys.path i szukał dowolnych modułów z podpakietem myframework, w którym to przypadku dodaje go do sys.path i wszystko działa.

Innym pomysłem jaki miałem jest zapisanie plików dodatków bezpośrednio do myframework/addons/ miejsca instalacji, ale wtedy zmieniłoby rozwój i wdrożoną przestrzeń nazw.

Czy istnieje lepszy sposób, aby to osiągnąć, a może zupełnie inne podejście do powyższego problemu dystrybucji?

Author: Taryn, 2009-01-18

5 answers

Czy istnieje lepszy sposób, aby to osiągnąć, a może zupełnie inne podejście do powyższego problemu dystrybucji?

Możliwe. Konfiguracja modułu/pakietu Pythona jest zazwyczaj trudna do dynamicznego manipulowania, ale jego system obiektów / klas jest otwarty i rozszerzalny w dobrze zdefiniowany sposób. Gdy moduły i pakiety nie mają do końca funkcji potrzebnych do ładnego hermetyzowania projektu, możesz użyć klas.

Na przykład możesz mieć rozszerzenie funkcjonalności w zupełnie innym pakiecie, ale pozwala na wprowadzanie klas do podstawowego frameworka przez określony interfejs. np. myframework/__init__.py zawiera podstawowe opakowanie aplikacji:

class MyFramework(object):
    """A bare MyFramework, I only hold a person's name
    """
    _addons= {}
    @staticmethod
    def addAddon(name, addon):
        MyFramework._addons[name]= addon

    def __init__(self, person):
        self.person= person
        for name, addon in MyFramework._addons.items():
            setattr(self, name, addon(self))

Wtedy można mieć funkcjonalność rozszerzenia w myexts/helloer.py, który przechowuje odniesienie do swojej' owner 'lub' outer ' instancji klasy MyFramework:

class Helloer(object):
    def __init__(self, owner):
        self.owner= owner
    def hello(self):
        print 'hello '+self.owner.person

import myframework
myframework.MyFramework.addAddon('helloer', Helloer)

Więc teraz, jeśli tylko "zaimportujesz myframework", otrzymasz tylko podstawową funkcjonalność. Ale jeśli również "import myexts.helloer " otrzymujesz również możliwość wywołania MyFramework.Witam.Witam;) Oczywiście można również zdefiniować protokoły dla addonów do interakcji z podstawowym zachowaniem frameworka i ze sobą nawzajem. Można również robić takie rzeczy, jak Klasy wewnętrzne, które podklasa frameworka może nadpisać w celu dostosowania bez konieczności malpowania-patch klas, które mogą mieć wpływ na inne aplikacje, jeśli potrzebujesz tego poziomu złożoności.

Takie zachowanie może być użyteczne, ale zazwyczaj irytująca praca nad dostosowaniem kodu na poziomie modułu, który już musisz dopasować do tego modelu.

 4
Author: bobince,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-24 15:37:15
 6
Author: user190071,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-12 02:27:51

Setuptools ma możliwość wyszukiwania pakietów "punkty wejścia" (funkcje, obiekty, cokolwiek) według nazwy. Trac używa tego mechanizmu załadować swoje wtyczki, i działa dobrze.

 4
Author: Alec Thomas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-19 05:35:28

Wygląda na to, że to, czego szukasz, można osiągnąć dość starannie za pomocą importowanych hooków.

Jest to sposób pisania niestandardowego kodu ładowania, który może być powiązany z pakietem (lub w Twoim przypadku frameworkiem), aby wykonać ładowanie wszystkich pod-pakietów i modułów, zamiast używać domyślnego mechanizmu ładowania Pythona. Następnie możesz zainstalować loader w site-packages jako pakiet podstawowy lub w ramach swojego frameworka.

Gdy okaże się, że pakiet jest skojarzony z loaderem (który może być po prostu zakodowany na twardo do ścieżki względnej, jeśli to konieczne), wtedy zawsze użyje loadera, aby załadować wszystkie dodatki na przykład. Ma to tę zaletę, że nie wymaga żadnego manipulowania ścieżką PYTHONPATH, co na ogół warto zachować tak krótko, jak to możliwe.

Alternatywą jest użycie plików init do przekierowania wywołania importu sub-modułu do tego, który chcesz odebrać, ale jest to trochę bałagan.

Więcej informacji na temat haków importowych można znaleźć tutaj:

Http://www.python.org/dev/peps/pep-0302/

 0
Author: Dan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-18 12:06:18

Istnieje zupełnie nowa konfiguracja dla przestrzeni nazw. Spójrz na packaging namespace packages . Krótko mówiąc, masz trzy opcje, w zależności od tego, jak bardzo chcesz, aby Twój kod był zgodny wstecz. Istnieje również odpowiedni PEP, który zastępuje te wymienione w innych odpowiedziach: PEP 420 .

 0
Author: jgbarah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-24 18:23:01