Dynamischer Import von Modulen in Python / Sudo Null IT News

Stellen wir uns eine Situation vor, in der Sie ein bestimmtes Python-Paket auf allen virtuellen Maschinen (Build-Server-Agenten) installieren müssen. Sie können das Agent-Image jedoch nicht ändern, und das Herunterladen unverifizierter Pakete von beispielsweise pypi.org oder github.com ist eingeschränkt. Wie können Sie sich nicht an die neuesten Nachrichten erinnern? böswillige Änderungen im nmp-Paket oder neuere Informationen über PyPi.

Python verwendet einen Ansatz namens EAFP – Einfacher, um Vergebung zu bitten, als um Erlaubnis (es ist einfacher, um Vergebung als um Erlaubnis zu bitten). Dies bedeutet, dass es einfacher ist, anzunehmen, dass etwas existiert (z. B. ein Wörterbuch in einem Wörterbuch oder in unserem Fall ein Modul im System), oder andernfalls einen Fehler zu erhalten.

Dieser Ansatz entwickelt in PEP-0302ermöglicht es Ihnen, einen Modul-Import-Hook zu machen, was uns letztendlich dazu führt, den folgenden Code zu schreiben:

aus importiere

Da ich mich oft mit der Automatisierung von CI/CD-Bereitstellungen mit Bamboo beschäftige, war die natürliche Lösung für mich, den verifizierten Modulcode in JFrog-Artefakte zu platzieren und (gemäß PEP-0302) Finder- und Loader-Klassen zu schreiben, um Module zu laden und zu installieren. In meinem Fall sieht der Modulimportcode so aus:

aus importiere

Laut PEP-0302 nehmen zwei Klassen am Protokoll teil: Finder und Loader.

Ich werde das Modul amtImport.py demonstrieren, das die Arbeit dieser Klassen implementiert:

import sys import pip import os import reviews import shutdown class IntermediateModule: “”” Modul für Pfade wie `artifactory_local.path` “”” def __init__(self, fullname): self.__package__ = fullname self.__path__ = fullname.split(‘ .’) self.__name__ = fullname class ArtifactoryFinder: “”” Handles `artifactory_local….` module “”” def find_module(self, module_name, package_path): if module_name.startswith(‘artifactory_local’): return ArtifactoryLoader() Klasse ArtifactoryLoader: “”” Installiert und importiert Module von Artefakt “”” Artefakt_Module: Liste = []

def _is_installed(self, fullname): try: self._import_module(fullname) ArtifactoryLoader.artifactory_modules.append(fullname) true zurückgeben, außer ImportError: false zurückgeben def _import_module(self, fullname): aktueller_name=”.”.join(fullname.split.split (‘.’)[2:]) aktueller_name = aktueller_name.replace(‘_’, ‘.’).split(‘.’)[0]
return __import__(aktueller_Name) def _install_module(self, fullname): wenn nicht self._is_installed(fullname): aktueller_name=”.”.join(fullname.split(‘.’)[2:]) url = fullname.replace(‘artifactory_local’, ”).replace(aktueller_name, ”).replace(‘_’, ‘/’) aktueller_name = aktueller_name.replace(‘_’, ‘.’) url=” + url.replace(‘.’, ‘/’) + aktueller_name auth = (os.getenv(“bamboo_artifactory_user_name”), os.getenv(“bamboo_artifactory_access_token_secret”)) file_name = f”{os.getenv(‘bamboo_build_working_directory’)} /{tatsächlicher_name}” mit request.get(url=url, auth=auth, stream=True) als r: if r.status_code != 200: raise Exception(f”Status code {r.status_code}: {r.reason }”) mit open(file_name, ‘wb’) als f: shutdown.copyfileobj(r.raw, f) pip.main([‘install’, file_name]) ArtifactoryLoader.artifactory_modules.append(fullname) def _is_repository_path(self, fullname): return fullname.count(‘.’) == 2 def _is_intermediate_path(self, fullname): return fullname.count(‘.’) < 2 def load_module (self, fullname): if self._is_repository_path(fullname): self._install_module(fullname) if self._is_intermediate_path(fullname): module = IntermediateModule(fullname) else: module = self._import_module(fullname) sys.modules[fullname] = Modul sys.meta_path.append(ArtifactoryFinder())

(Code für Python 3.6 getestet)

Fazit: Der dynamische Import von Artefakten kann kurz und bündig mit dem folgenden Code durchgeführt werden:

from amtImport import ArtifactoryLoader # pyrright: reportMissingImports=false, reportUnusedImport=false from artifactory_local.artifactory_amt_Sealed import smbprotocol_1_9_0_tar_gz geladen, wenn “artifactory_local.artifactory_amt_Sealed.smbprotocol_1_9_0_tarack_gz” in Artifactory_Loader(printer_factory) erfolgreich gedruckt wird

Mit einem ähnlichen Ansatz können Sie Module aus jeder anderen Quelle importieren.

PS Grundlage für diesen Artikel war das Paket import_from_github_com.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *