Salut,
Dans le cadre d'un mini-projet, je souhaite créer un module à partir de code Python sous forme de chaîne de caractère (str
). Après plusieurs essais à partir de trucs foireux j'ai réussi à importer un module depuis un site. Cependant j'arrive que à exécuter les fonctions depuis le scope actuel, c'est à dire que si j'importe ce script (alea.py):
1 2 3 4 5 6 7 | import string, random def random_string(length): res = '' for _ in range(length): res += random.choice(string.ascii_lowercase) return res |
… de cette manière:
1 2 3 4 5 | tele_import('http://telecode.esy.es/alea.py') # Je crée le module en RAM depuis un mini site créé pour l'occasion \o/ import alea print(alea.random_string(16)) |
… Python va crasher et me donner ce traceback:
1 2 3 4 5 | Traceback (most recent call last): File "C:/Users/*****/Desktop/Programmation/Python/TeleCode/main.py", line 13, in <module> print(alea.random_string(16)) File "<string>", line 7, in random_string NameError: name 'random' is not defined |
J'en déduis que j'exécute la fonction dans le scope dans lequel je l'appelle et non dans le module dans lequel elle est contenue.
Voici comment je procède actuellement pour importer le module:
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 | #!/usr/bin/env python3 # coding: utf-8 import sys import os from types import ModuleType, SimpleNamespace import urllib.request class TeleModule(ModuleType): def __new__(cls, name, doc, namespace, url): tm = super().__new__(cls, name, doc) namespace.__name__ = name namespace.__cached__ = name namespace.__file__ = url namespace.__doc__ = doc tm.namespace = namespace sys.modules[name] = tm return tm def __init__(self, name, doc, namespace, url): pass def __getattr__(self, item): return getattr(self.namespace, item) def __dir__(self): return dir(self.namespace) def __repr__(self): return '<module {!r} from {!r}>'.format(self.namespace.__name__, self.namespace.__file__) def tele_import(url): exec(compile(urllib.request.urlopen(url).read().decode('utf-8'), '<string>', 'exec')) tm = TeleModule(os.path.basename(url).split('.')[0], '', SimpleNamespace(**locals()), url) return tm |
Comme vous pouvez le voir c'est crade. J'aimerai donc savoir s'il existe un moyen plus propre et surtout qui marche pour créer des modules at runtime.
Merci d'avance,
AZ.
PS: Si quelqu'un saurait à quoi sert l'attribut __loader__
, je n'ai pas compris la doc