diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c5f9c774..47890f9f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.14.2 + rev: v0.15.0 hooks: # Run the linter. - id: ruff @@ -24,7 +24,7 @@ repos: - id: end-of-file-fixer - id: debug-statements - repo: https://github.com/asottile/pyupgrade - rev: v3.21.0 + rev: v3.21.2 hooks: - id: pyupgrade args: [--py3-plus, --py311-plus] diff --git a/wrapanapi/__init__.py b/wrapanapi/__init__.py index c6c1db54..25c66b2b 100644 --- a/wrapanapi/__init__.py +++ b/wrapanapi/__init__.py @@ -1,20 +1,5 @@ # Imports for convenience from .entities.vm import VmState -from .systems.container.podman import Podman -from .systems.container.rhopenshift import Openshift -from .systems.ec2 import EC2System -from .systems.google import GoogleCloudSystem -from .systems.hawkular import HawkularSystem -from .systems.lenovo import LenovoSystem -from .systems.msazure import AzureSystem -from .systems.nuage import NuageSystem -from .systems.openstack import OpenstackSystem -from .systems.openstack_infra import OpenstackInfraSystem -from .systems.redfish import RedfishSystem -from .systems.rhevm import RHEVMSystem -from .systems.scvmm import SCVMMSystem -from .systems.vcloud import VmwareCloudSystem -from .systems.virtualcenter import VMWareSystem __all__ = [ "EC2System", @@ -34,3 +19,68 @@ "Podman", "VmState", ] + + +def __getattr__(name): + """Lazy import system classes to avoid loading dependencies for unused providers.""" + if name == "EC2System": + from .systems.ec2 import EC2System + + return EC2System + elif name == "GoogleCloudSystem": + from .systems.google import GoogleCloudSystem + + return GoogleCloudSystem + elif name == "HawkularSystem": + from .systems.hawkular import HawkularSystem + + return HawkularSystem + elif name == "LenovoSystem": + from .systems.lenovo import LenovoSystem + + return LenovoSystem + elif name == "AzureSystem": + from .systems.msazure import AzureSystem + + return AzureSystem + elif name == "NuageSystem": + from .systems.nuage import NuageSystem + + return NuageSystem + elif name == "OpenstackSystem": + from .systems.openstack import OpenstackSystem + + return OpenstackSystem + elif name == "OpenstackInfraSystem": + from .systems.openstack_infra import OpenstackInfraSystem + + return OpenstackInfraSystem + elif name == "RedfishSystem": + from .systems.redfish import RedfishSystem + + return RedfishSystem + elif name == "RHEVMSystem": + from .systems.rhevm import RHEVMSystem + + return RHEVMSystem + elif name == "SCVMMSystem": + from .systems.scvmm import SCVMMSystem + + return SCVMMSystem + elif name == "VmwareCloudSystem": + from .systems.vcloud import VmwareCloudSystem + + return VmwareCloudSystem + elif name == "VMWareSystem": + from .systems.virtualcenter import VMWareSystem + + return VMWareSystem + elif name == "Openshift": + from .systems.container.rhopenshift import Openshift + + return Openshift + elif name == "Podman": + from .systems.container.podman import Podman + + return Podman + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/wrapanapi/systems/__init__.py b/wrapanapi/systems/__init__.py index fa0adf4f..f6010866 100644 --- a/wrapanapi/systems/__init__.py +++ b/wrapanapi/systems/__init__.py @@ -1,17 +1,3 @@ -from .ec2 import EC2System -from .google import GoogleCloudSystem -from .hawkular import HawkularSystem -from .lenovo import LenovoSystem -from .msazure import AzureSystem -from .nuage import NuageSystem -from .openstack import OpenstackSystem -from .openstack_infra import OpenstackInfraSystem -from .redfish import RedfishSystem -from .rhevm import RHEVMSystem -from .scvmm import SCVMMSystem -from .vcloud import VmwareCloudSystem -from .virtualcenter import VMWareSystem - __all__ = [ "EC2System", "GoogleCloudSystem", @@ -27,3 +13,60 @@ "VmwareCloudSystem", "VMWareSystem", ] + + +def __getattr__(name): + """Lazy import system classes to avoid loading dependencies for unused providers.""" + if name == "EC2System": + from .ec2 import EC2System + + return EC2System + elif name == "GoogleCloudSystem": + from .google import GoogleCloudSystem + + return GoogleCloudSystem + elif name == "HawkularSystem": + from .hawkular import HawkularSystem + + return HawkularSystem + elif name == "LenovoSystem": + from .lenovo import LenovoSystem + + return LenovoSystem + elif name == "AzureSystem": + from .msazure import AzureSystem + + return AzureSystem + elif name == "NuageSystem": + from .nuage import NuageSystem + + return NuageSystem + elif name == "OpenstackSystem": + from .openstack import OpenstackSystem + + return OpenstackSystem + elif name == "OpenstackInfraSystem": + from .openstack_infra import OpenstackInfraSystem + + return OpenstackInfraSystem + elif name == "RedfishSystem": + from .redfish import RedfishSystem + + return RedfishSystem + elif name == "RHEVMSystem": + from .rhevm import RHEVMSystem + + return RHEVMSystem + elif name == "SCVMMSystem": + from .scvmm import SCVMMSystem + + return SCVMMSystem + elif name == "VmwareCloudSystem": + from .vcloud import VmwareCloudSystem + + return VmwareCloudSystem + elif name == "VMWareSystem": + from .virtualcenter import VMWareSystem + + return VMWareSystem + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/wrapanapi/systems/msazure.py b/wrapanapi/systems/msazure.py index a7c32397..d544b9a4 100644 --- a/wrapanapi/systems/msazure.py +++ b/wrapanapi/systems/msazure.py @@ -8,25 +8,63 @@ from functools import cached_property import pytz -from azure.core.exceptions import HttpResponseError -from azure.identity import ClientSecretCredential -from azure.mgmt.compute import ComputeManagementClient -from azure.mgmt.iothub import IotHubClient -from azure.mgmt.network import NetworkManagementClient -from azure.mgmt.network.models import NetworkSecurityGroup, SecurityRule -from azure.mgmt.resource.resources import ResourceManagementClient -from azure.mgmt.storage import StorageManagementClient -from azure.mgmt.subscription import SubscriptionClient -from azure.mgmt.subscription.models import SubscriptionState -from azure.storage.blob import BlobServiceClient from dateutil import parser -from msrestazure.azure_exceptions import CloudError from wait_for import wait_for from wrapanapi.entities import Instance, Template, TemplateMixin, VmMixin, VmState from wrapanapi.exceptions import ImageNotFoundError, MultipleImagesError, VMInstanceNotFound from wrapanapi.systems.base import System +# Lazy imports for Azure dependencies to avoid import errors when Azure packages +# are not properly installed or when users don't need Azure functionality +_azure_imports_loaded = False + + +def _ensure_azure_imports(): + """Lazily import Azure dependencies only when needed.""" + global _azure_imports_loaded + global HttpResponseError, ClientSecretCredential, ComputeManagementClient + global IotHubClient, NetworkManagementClient, NetworkSecurityGroup, SecurityRule + global ResourceManagementClient, StorageManagementClient, SubscriptionClient + global SubscriptionState, BlobServiceClient, CloudError + + if not _azure_imports_loaded: + from azure.core.exceptions import HttpResponseError as _HttpResponseError + from azure.identity import ClientSecretCredential as _ClientSecretCredential + from azure.mgmt.compute import ComputeManagementClient as _ComputeManagementClient + from azure.mgmt.iothub import IotHubClient as _IotHubClient + from azure.mgmt.network import NetworkManagementClient as _NetworkManagementClient + from azure.mgmt.network.models import ( + NetworkSecurityGroup as _NetworkSecurityGroup, + ) + from azure.mgmt.network.models import ( + SecurityRule as _SecurityRule, + ) + from azure.mgmt.resource.resources import ( + ResourceManagementClient as _ResourceManagementClient, + ) + from azure.mgmt.storage import StorageManagementClient as _StorageManagementClient + from azure.mgmt.subscription import SubscriptionClient as _SubscriptionClient + from azure.mgmt.subscription.models import SubscriptionState as _SubscriptionState + from azure.storage.blob import BlobServiceClient as _BlobServiceClient + from msrestazure.azure_exceptions import CloudError as _CloudError + + HttpResponseError = _HttpResponseError + ClientSecretCredential = _ClientSecretCredential + ComputeManagementClient = _ComputeManagementClient + IotHubClient = _IotHubClient + NetworkManagementClient = _NetworkManagementClient + NetworkSecurityGroup = _NetworkSecurityGroup + SecurityRule = _SecurityRule + ResourceManagementClient = _ResourceManagementClient + StorageManagementClient = _StorageManagementClient + SubscriptionClient = _SubscriptionClient + SubscriptionState = _SubscriptionState + BlobServiceClient = _BlobServiceClient + CloudError = _CloudError + + _azure_imports_loaded = True + class AzureInstance(Instance): state_map = { @@ -47,6 +85,7 @@ def __init__(self, system, raw=None, **kwargs): name: name of instance resource_group: name of resource group this instance is in """ + _ensure_azure_imports() self._resource_group = kwargs.get("resource_group") self._name = kwargs.get("name") if not self._name or not self._resource_group: @@ -304,6 +343,7 @@ def __init__(self, system, raw=None, **kwargs): name: name of template container: container the template is stored in """ + _ensure_azure_imports() self._name = kwargs.get("name") self._container = kwargs.get("container") if not self._name or not self._container: @@ -488,6 +528,7 @@ class AzureSystem(System, VmMixin, TemplateMixin): } def __init__(self, **kwargs): + _ensure_azure_imports() super().__init__(**kwargs) self.client_id = kwargs.get("username") self.client_secret = kwargs.get("password") diff --git a/wrapanapi/systems/nuage.py b/wrapanapi/systems/nuage.py index 820c098b..f1dfbbf4 100644 --- a/wrapanapi/systems/nuage.py +++ b/wrapanapi/systems/nuage.py @@ -22,10 +22,10 @@ class NuageSystem(System): # entities.count() == (fetcher, served object, count of fetched objects) "num_security_group": lambda self: self.api.policy_groups.count()[2], # Filter out 'BackHaulSubnet' and combine it with l2_domains the same way CloudForms does - "num_cloud_subnet": lambda self: self.api.subnets.count(filter="name != 'BackHaulSubnet'")[ - 2 - ] - + self.api.l2_domains.count()[2], + "num_cloud_subnet": lambda self: ( + self.api.subnets.count(filter="name != 'BackHaulSubnet'")[2] + + self.api.l2_domains.count()[2] + ), "num_cloud_tenant": lambda self: self.api.enterprises.count()[2], "num_network_router": lambda self: self.api.domains.count()[2], "num_cloud_network": lambda self: len(self.list_floating_network_resources()),