IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

développement d'un framework modulaire


Sujet :

Python

  1. #1
    Membre chevronné
    Homme Profil pro
    BTS SN IR
    Inscrit en
    Mai 2017
    Messages
    514
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Saône et Loire (Bourgogne)

    Informations professionnelles :
    Activité : BTS SN IR

    Informations forums :
    Inscription : Mai 2017
    Messages : 514
    Par défaut développement d'un framework modulaire
    bonjour,

    J'essaye de créer un framework WEB API REST "coreless" par dessus Tornado et en y intégrant Gino, en faite le core du framework sera un système de loader de module, les modules seront interconnectés mais j'ai quelques problèmes d'import relatif.
    ça marche mais ... j'ai l'impression de ne pas m'y prendre correctement et qu'il s'agit plus d'un hack que d'autre chose. Mon linter me dit "Attempted relative import beyond top-level package" par exemple au niveau du main du module

    voici un cas reproduction minimal épuré de tout commentaire ou docstrings

    /main.py
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    # coding: utf-8
     
    import importlib
    import sys
    import types
     
     
    class MissingEntryPointError(Exception): pass
    class RequiredDependenciesNotEnabledError(Exception): pass
    class ModuleAlreadyLoadedError(Exception): pass
     
     
    class Application:
     
        def __init__(self, *args, **kwargs):
            self.__enabled_modules = kwargs.pop("enabled_modules", {})
            self.__dirmodule = kwargs.pop("dirmodule", "modules")
            self.__modules = {}
            # super().__init__(*args, **kwargs)
     
     
        def load_module(self, name, config):
            if name in self.__modules:
                raise ModuleAlreadyLoadedError(name)
     
            module = importlib.import_module("{0}.{1}.main".format(self.__dirmodule, name))
            try:
                entry_point = getattr(module, "setup")
            except AttributeError:
                raise MissingEntryPointError(name)
     
     
            try:
                entry_point(self, config)
            except Exception as e:
                raise e
            else:
                self.__modules[name] = module
     
        @property
        def enabled_modules(self):
            return types.MappingProxyType(self.__enabled_modules)
     
     
    enabled_modules = {"module_a": {}}
     
    app = Application(enabled_modules=enabled_modules)
     
    for module, config in app.enabled_modules.items():
       app.load_module(module, config)

    /modules/module_a/main.py
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    from .func.f import f
     
     
    dependencies = []
     
     
    def setup(app, module_config):
    	print("module loaded")
    	print(f())
    /modules/module_a/func/f.py

    Je me dis que retravailler mon idée mais en utilisant des packages serait plus simple (bien que je ne sache pas faire, ça doit pas être sorcier quand même) mais cela poserait un problème,
    Gino étant une ORM (basé sur SqlAlchemy) j'ai besoin de charger les modèles de tables, hors les modules pourrons dépendre d'autres modules, un exemple:
    une table parent avec une colonne: id
    une table enfant avec deux colonnes: id et parent_id (foreign key qui fait référence sur parent.id en delete on cascade )
    (toutes les modules que je compte faire serons avec des delete on cascade)

    imaginons que je crée un parent et en enfant, avec le module parent et enfant d'activés, puis que je désactive le module enfant (le contraire est impossible puisque le module enfant demande comme dépendance parent), donc à partir de là je n'est plus qu'un modèle de table, celui de parent. Maintenant supposons que je veuille supprimer le parent, pas de soucis, mais dans mon interface web je me dit que se serait bien de connaitre tous les enfants (et potentiel petits enfants) de façon récursive dans le popup disant "voulez vous vraiment supprimer X" (en supposant que j'ai la solution du coté de l'ORM pour charger tous les enfants de façon récursive avant le delete on cascade, je ne me suis pas encore penché sur les relationship loading techniques).

    L'avantage avec mes imports dynamiques c'est que je peux importer les fichiers avec tous les fichiers du nom de db_models.py avec un simple coup de glob récursif mais ça reste bancal...

    En parallèle je regarde si l'automap ne pourrais pas solutionner en partie se problème.

    Enfin voilà si quelqu'un à un conseil je suis preneur

  2. #2
    Membre Expert

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    pkg_name
    |   MANIFEST.in
    |   README.md
    |   setup.py
    |   versions.txt
    |
    +---pkg_name
        |   version.py
        |   __init__.py
        | 
        +---module1
        |       test1a.py
        |       __init__.py
        |
        +---module2
                test2a.py
                test2b.py
                __init__.py
    Si cela peut t'aider, voici la hiérarchie que j'utilise dans le package que je développe en ce moment.
    Les modules peuvent s'utiliser entre eux sans problème. Par contre à chaque fois que je fais un import je repars de la racine du package.

    Donc si par exemple module1/test1a utilise module2/test2b alors j'écris dans test1a.py :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    from pkg_name.module2 import test2b
    Pareil si test2b dépend de test2a par exemple, je repars aussi de la racine. J'écris donc dans test2b.py
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    from pkg_name.module2 import test2a
    Les fichiers __init__ sont obligatoires sinon les imports ne se passe pas bien. En principe ce sont des fichiers vides.

    NB: Tu noteras qu'il y a 2 fois pkg_name dans mon arbre. Celui de plus bas niveau regroupe tous les modules de ton package. Celui de plus haut niveau contient aussi le code nécessaire à la distribution et à l'installation du package (donc pas forcément obligatoire).

Discussions similaires

  1. [ZF 1.9] "atelier" graphique pour développer avec Zend Framework
    Par sheira dans le forum Zend Framework
    Réponses: 17
    Dernier message: 04/08/2010, 09h00
  2. Développement site / choix framework
    Par wkramps dans le forum Servlets/JSP
    Réponses: 6
    Dernier message: 09/07/2007, 12h56
  3. [Data] Développement avec la framework spring et ibatis
    Par ujoodha dans le forum Spring
    Réponses: 1
    Dernier message: 07/03/2005, 13h20
  4. Réponses: 16
    Dernier message: 12/11/2004, 00h05

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo