Improve loading times in client
This commit is contained in:
		@@ -19,6 +19,15 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
###############################################################################
 | 
					###############################################################################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Import only the essential parts of click for CLI definition
 | 
				
			||||||
 | 
					from click import group, command, option, argument, pass_context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Import minimal required modules
 | 
				
			||||||
 | 
					from pvc.lib.common import call_api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Use lazy imports for modules not needed during initial CLI parsing
 | 
				
			||||||
 | 
					from pvc.lib.lazy_imports import yaml, click_advanced
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from colorama import Fore
 | 
					from colorama import Fore
 | 
				
			||||||
from difflib import unified_diff
 | 
					from difflib import unified_diff
 | 
				
			||||||
from functools import wraps
 | 
					from functools import wraps
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,10 +23,254 @@ from ast import literal_eval
 | 
				
			|||||||
from click import echo, progressbar
 | 
					from click import echo, progressbar
 | 
				
			||||||
from math import ceil
 | 
					from math import ceil
 | 
				
			||||||
from os.path import getsize
 | 
					from os.path import getsize
 | 
				
			||||||
from requests import get, post, put, patch, delete, Response
 | 
					 | 
				
			||||||
from requests.exceptions import ConnectionError
 | 
					 | 
				
			||||||
from time import time
 | 
					from time import time
 | 
				
			||||||
from urllib3 import disable_warnings
 | 
					import json
 | 
				
			||||||
 | 
					import socket
 | 
				
			||||||
 | 
					import ssl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Define a Response class to mimic requests.Response
 | 
				
			||||||
 | 
					class Response:
 | 
				
			||||||
 | 
					    def __init__(self, status_code, headers, content):
 | 
				
			||||||
 | 
					        self.status_code = status_code
 | 
				
			||||||
 | 
					        self.headers = headers
 | 
				
			||||||
 | 
					        self.content = content
 | 
				
			||||||
 | 
					        self._json = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def json(self):
 | 
				
			||||||
 | 
					        if self._json is None:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                self._json = json.loads(self.content.decode('utf-8'))
 | 
				
			||||||
 | 
					            except json.JSONDecodeError:
 | 
				
			||||||
 | 
					                self._json = {}
 | 
				
			||||||
 | 
					        return self._json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Define ConnectionError to mimic requests.exceptions.ConnectionError
 | 
				
			||||||
 | 
					class ConnectionError(Exception):
 | 
				
			||||||
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ErrorResponse(Response):
 | 
				
			||||||
 | 
					    def __init__(self, json_data, status_code, headers):
 | 
				
			||||||
 | 
					        self.status_code = status_code
 | 
				
			||||||
 | 
					        self.headers = headers
 | 
				
			||||||
 | 
					        self._json = json_data
 | 
				
			||||||
 | 
					        self.content = json.dumps(json_data).encode('utf-8') if json_data else b''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def json(self):
 | 
				
			||||||
 | 
					        return self._json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _encode_params(params):
 | 
				
			||||||
 | 
					    """Simple URL parameter encoder"""
 | 
				
			||||||
 | 
					    if not params:
 | 
				
			||||||
 | 
					        return ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    parts = []
 | 
				
			||||||
 | 
					    for key, value in params.items():
 | 
				
			||||||
 | 
					        if isinstance(value, bool):
 | 
				
			||||||
 | 
					            value = str(value).lower()
 | 
				
			||||||
 | 
					        elif value is None:
 | 
				
			||||||
 | 
					            value = ''
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            value = str(value)
 | 
				
			||||||
 | 
					        parts.append(f"{key}={value}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return '?' + '&'.join(parts)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def call_api(
 | 
				
			||||||
 | 
					    config,
 | 
				
			||||||
 | 
					    operation,
 | 
				
			||||||
 | 
					    request_uri,
 | 
				
			||||||
 | 
					    headers={},
 | 
				
			||||||
 | 
					    params=None,
 | 
				
			||||||
 | 
					    data=None,
 | 
				
			||||||
 | 
					    files=None,
 | 
				
			||||||
 | 
					):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Make an API call to the PVC API using native Python libraries.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    # Set the connect timeout to 2 seconds
 | 
				
			||||||
 | 
					    timeout = 2.05
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Craft the URI
 | 
				
			||||||
 | 
					    uri = "{}://{}{}{}".format(
 | 
				
			||||||
 | 
					        config["api_scheme"], config["api_host"], config["api_prefix"], request_uri
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Parse the URI without using urllib
 | 
				
			||||||
 | 
					    if '://' in uri:
 | 
				
			||||||
 | 
					        scheme, rest = uri.split('://', 1)
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        scheme = 'http'
 | 
				
			||||||
 | 
					        rest = uri
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if '/' in rest:
 | 
				
			||||||
 | 
					        netloc, path = rest.split('/', 1)
 | 
				
			||||||
 | 
					        path = '/' + path
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        netloc = rest
 | 
				
			||||||
 | 
					        path = '/'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Extract host and port
 | 
				
			||||||
 | 
					    if ':' in netloc:
 | 
				
			||||||
 | 
					        host, port_str = netloc.split(':', 1)
 | 
				
			||||||
 | 
					        port = int(port_str)
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        host = netloc
 | 
				
			||||||
 | 
					        port = 443 if scheme == 'https' else 80
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Craft the authentication header if required
 | 
				
			||||||
 | 
					    if config["api_key"]:
 | 
				
			||||||
 | 
					        headers["X-Api-Key"] = config["api_key"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Add content type if not present
 | 
				
			||||||
 | 
					    if "Content-Type" not in headers and data is not None and files is None:
 | 
				
			||||||
 | 
					        headers["Content-Type"] = "application/json"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Prepare query string
 | 
				
			||||||
 | 
					    query_string = _encode_params(params)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Prepare path with query string
 | 
				
			||||||
 | 
					    full_path = path + query_string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Prepare body
 | 
				
			||||||
 | 
					    body = None
 | 
				
			||||||
 | 
					    if data is not None and files is None:
 | 
				
			||||||
 | 
					        if isinstance(data, dict):
 | 
				
			||||||
 | 
					            body = json.dumps(data).encode('utf-8')
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            body = data.encode('utf-8') if isinstance(data, str) else data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Handle file uploads (multipart/form-data)
 | 
				
			||||||
 | 
					    if files:
 | 
				
			||||||
 | 
					        boundary = '----WebKitFormBoundary' + str(int(time()))
 | 
				
			||||||
 | 
					        headers['Content-Type'] = f'multipart/form-data; boundary={boundary}'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        body = b''
 | 
				
			||||||
 | 
					        # Add form fields
 | 
				
			||||||
 | 
					        if data:
 | 
				
			||||||
 | 
					            for key, value in data.items():
 | 
				
			||||||
 | 
					                body += f'--{boundary}\r\n'.encode()
 | 
				
			||||||
 | 
					                body += f'Content-Disposition: form-data; name="{key}"\r\n\r\n'.encode()
 | 
				
			||||||
 | 
					                body += f'{value}\r\n'.encode()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Add files
 | 
				
			||||||
 | 
					        for key, file_tuple in files.items():
 | 
				
			||||||
 | 
					            filename, fileobj, content_type = file_tuple
 | 
				
			||||||
 | 
					            body += f'--{boundary}\r\n'.encode()
 | 
				
			||||||
 | 
					            body += f'Content-Disposition: form-data; name="{key}"; filename="{filename}"\r\n'.encode()
 | 
				
			||||||
 | 
					            body += f'Content-Type: {content_type}\r\n\r\n'.encode()
 | 
				
			||||||
 | 
					            body += fileobj.read()
 | 
				
			||||||
 | 
					            body += b'\r\n'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        body += f'--{boundary}--\r\n'.encode()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Use http.client instead of raw sockets for better HTTP protocol handling
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        # Special handling for GET with retries
 | 
				
			||||||
 | 
					        if operation == "get":
 | 
				
			||||||
 | 
					            retry_on_code = [429, 500, 502, 503, 504]
 | 
				
			||||||
 | 
					            for i in range(3):
 | 
				
			||||||
 | 
					                failed = False
 | 
				
			||||||
 | 
					                try:
 | 
				
			||||||
 | 
					                    # Create the appropriate connection
 | 
				
			||||||
 | 
					                    if scheme == 'https':
 | 
				
			||||||
 | 
					                        import ssl
 | 
				
			||||||
 | 
					                        context = None
 | 
				
			||||||
 | 
					                        if not config["verify_ssl"]:
 | 
				
			||||||
 | 
					                            context = ssl._create_unverified_context()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        import http.client
 | 
				
			||||||
 | 
					                        conn = http.client.HTTPSConnection(
 | 
				
			||||||
 | 
					                            host, 
 | 
				
			||||||
 | 
					                            port=port,
 | 
				
			||||||
 | 
					                            timeout=timeout,
 | 
				
			||||||
 | 
					                            context=context
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                    else:
 | 
				
			||||||
 | 
					                        import http.client
 | 
				
			||||||
 | 
					                        conn = http.client.HTTPConnection(
 | 
				
			||||||
 | 
					                            host,
 | 
				
			||||||
 | 
					                            port=port,
 | 
				
			||||||
 | 
					                            timeout=timeout
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    # Make the request
 | 
				
			||||||
 | 
					                    conn.request(operation.upper(), full_path, body=body, headers=headers)
 | 
				
			||||||
 | 
					                    http_response = conn.getresponse()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    # Read response data
 | 
				
			||||||
 | 
					                    status_code = http_response.status
 | 
				
			||||||
 | 
					                    response_headers = dict(http_response.getheaders())
 | 
				
			||||||
 | 
					                    response_data = http_response.read()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    conn.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    # Create a Response object
 | 
				
			||||||
 | 
					                    response = Response(status_code, response_headers, response_data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if response.status_code in retry_on_code:
 | 
				
			||||||
 | 
					                        failed = True
 | 
				
			||||||
 | 
					                        continue
 | 
				
			||||||
 | 
					                    break
 | 
				
			||||||
 | 
					                except Exception as e:
 | 
				
			||||||
 | 
					                    failed = True
 | 
				
			||||||
 | 
					                    if 'conn' in locals():
 | 
				
			||||||
 | 
					                        conn.close()
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if failed:
 | 
				
			||||||
 | 
					                error = f"Code {response.status_code}" if response else "Timeout"
 | 
				
			||||||
 | 
					                raise ConnectionError(f"Failed to connect after 3 tries ({error})")
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            # Handle other HTTP methods
 | 
				
			||||||
 | 
					            if scheme == 'https':
 | 
				
			||||||
 | 
					                import ssl
 | 
				
			||||||
 | 
					                context = None
 | 
				
			||||||
 | 
					                if not config["verify_ssl"]:
 | 
				
			||||||
 | 
					                    context = ssl._create_unverified_context()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                import http.client
 | 
				
			||||||
 | 
					                conn = http.client.HTTPSConnection(
 | 
				
			||||||
 | 
					                    host, 
 | 
				
			||||||
 | 
					                    port=port,
 | 
				
			||||||
 | 
					                    timeout=timeout,
 | 
				
			||||||
 | 
					                    context=context
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                import http.client
 | 
				
			||||||
 | 
					                conn = http.client.HTTPConnection(
 | 
				
			||||||
 | 
					                    host,
 | 
				
			||||||
 | 
					                    port=port,
 | 
				
			||||||
 | 
					                    timeout=timeout
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Make the request
 | 
				
			||||||
 | 
					            conn.request(operation.upper(), full_path, body=body, headers=headers)
 | 
				
			||||||
 | 
					            http_response = conn.getresponse()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Read response data
 | 
				
			||||||
 | 
					            status_code = http_response.status
 | 
				
			||||||
 | 
					            response_headers = dict(http_response.getheaders())
 | 
				
			||||||
 | 
					            response_data = http_response.read()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            conn.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Create a Response object
 | 
				
			||||||
 | 
					            response = Response(status_code, response_headers, response_data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    except Exception as e:
 | 
				
			||||||
 | 
					        message = f"Failed to connect to the API: {e}"
 | 
				
			||||||
 | 
					        code = getattr(response, 'status_code', 504) if 'response' in locals() else 504
 | 
				
			||||||
 | 
					        response = ErrorResponse({"message": message}, code, None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Display debug output
 | 
				
			||||||
 | 
					    if config["debug"]:
 | 
				
			||||||
 | 
					        echo("API endpoint: {}".format(uri), err=True)
 | 
				
			||||||
 | 
					        echo("Response code: {}".format(response.status_code), err=True)
 | 
				
			||||||
 | 
					        echo("Response headers: {}".format(response.headers), err=True)
 | 
				
			||||||
 | 
					        echo(err=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Return the response object
 | 
				
			||||||
 | 
					    return response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def format_bytes(size_bytes):
 | 
					def format_bytes(size_bytes):
 | 
				
			||||||
@@ -139,118 +383,6 @@ class UploadProgressBar(object):
 | 
				
			|||||||
                echo(self.end_message + self.end_suffix, nl=self.end_nl)
 | 
					                echo(self.end_message + self.end_suffix, nl=self.end_nl)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ErrorResponse(Response):
 | 
					 | 
				
			||||||
    def __init__(self, json_data, status_code, headers):
 | 
					 | 
				
			||||||
        self.json_data = json_data
 | 
					 | 
				
			||||||
        self.status_code = status_code
 | 
					 | 
				
			||||||
        self.headers = headers
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def json(self):
 | 
					 | 
				
			||||||
        return self.json_data
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def call_api(
 | 
					 | 
				
			||||||
    config,
 | 
					 | 
				
			||||||
    operation,
 | 
					 | 
				
			||||||
    request_uri,
 | 
					 | 
				
			||||||
    headers={},
 | 
					 | 
				
			||||||
    params=None,
 | 
					 | 
				
			||||||
    data=None,
 | 
					 | 
				
			||||||
    files=None,
 | 
					 | 
				
			||||||
):
 | 
					 | 
				
			||||||
    # Set the connect timeout to 2 seconds but extremely long (48 hour) data timeout
 | 
					 | 
				
			||||||
    timeout = (2.05, 172800)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Craft the URI
 | 
					 | 
				
			||||||
    uri = "{}://{}{}{}".format(
 | 
					 | 
				
			||||||
        config["api_scheme"], config["api_host"], config["api_prefix"], request_uri
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Craft the authentication header if required
 | 
					 | 
				
			||||||
    if config["api_key"]:
 | 
					 | 
				
			||||||
        headers["X-Api-Key"] = config["api_key"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Determine the request type and hit the API
 | 
					 | 
				
			||||||
    disable_warnings()
 | 
					 | 
				
			||||||
    try:
 | 
					 | 
				
			||||||
        response = None
 | 
					 | 
				
			||||||
        if operation == "get":
 | 
					 | 
				
			||||||
            retry_on_code = [429, 500, 502, 503, 504]
 | 
					 | 
				
			||||||
            for i in range(3):
 | 
					 | 
				
			||||||
                failed = False
 | 
					 | 
				
			||||||
                try:
 | 
					 | 
				
			||||||
                    response = get(
 | 
					 | 
				
			||||||
                        uri,
 | 
					 | 
				
			||||||
                        timeout=timeout,
 | 
					 | 
				
			||||||
                        headers=headers,
 | 
					 | 
				
			||||||
                        params=params,
 | 
					 | 
				
			||||||
                        data=data,
 | 
					 | 
				
			||||||
                        verify=config["verify_ssl"],
 | 
					 | 
				
			||||||
                    )
 | 
					 | 
				
			||||||
                    if response.status_code in retry_on_code:
 | 
					 | 
				
			||||||
                        failed = True
 | 
					 | 
				
			||||||
                        continue
 | 
					 | 
				
			||||||
                    break
 | 
					 | 
				
			||||||
                except ConnectionError:
 | 
					 | 
				
			||||||
                    failed = True
 | 
					 | 
				
			||||||
                    continue
 | 
					 | 
				
			||||||
            if failed:
 | 
					 | 
				
			||||||
                error = f"Code {response.status_code}" if response else "Timeout"
 | 
					 | 
				
			||||||
                raise ConnectionError(f"Failed to connect after 3 tries ({error})")
 | 
					 | 
				
			||||||
        if operation == "post":
 | 
					 | 
				
			||||||
            response = post(
 | 
					 | 
				
			||||||
                uri,
 | 
					 | 
				
			||||||
                timeout=timeout,
 | 
					 | 
				
			||||||
                headers=headers,
 | 
					 | 
				
			||||||
                params=params,
 | 
					 | 
				
			||||||
                data=data,
 | 
					 | 
				
			||||||
                files=files,
 | 
					 | 
				
			||||||
                verify=config["verify_ssl"],
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        if operation == "put":
 | 
					 | 
				
			||||||
            response = put(
 | 
					 | 
				
			||||||
                uri,
 | 
					 | 
				
			||||||
                timeout=timeout,
 | 
					 | 
				
			||||||
                headers=headers,
 | 
					 | 
				
			||||||
                params=params,
 | 
					 | 
				
			||||||
                data=data,
 | 
					 | 
				
			||||||
                files=files,
 | 
					 | 
				
			||||||
                verify=config["verify_ssl"],
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        if operation == "patch":
 | 
					 | 
				
			||||||
            response = patch(
 | 
					 | 
				
			||||||
                uri,
 | 
					 | 
				
			||||||
                timeout=timeout,
 | 
					 | 
				
			||||||
                headers=headers,
 | 
					 | 
				
			||||||
                params=params,
 | 
					 | 
				
			||||||
                data=data,
 | 
					 | 
				
			||||||
                verify=config["verify_ssl"],
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        if operation == "delete":
 | 
					 | 
				
			||||||
            response = patch, delete(
 | 
					 | 
				
			||||||
                uri,
 | 
					 | 
				
			||||||
                timeout=timeout,
 | 
					 | 
				
			||||||
                headers=headers,
 | 
					 | 
				
			||||||
                params=params,
 | 
					 | 
				
			||||||
                data=data,
 | 
					 | 
				
			||||||
                verify=config["verify_ssl"],
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
    except Exception as e:
 | 
					 | 
				
			||||||
        message = "Failed to connect to the API: {}".format(e)
 | 
					 | 
				
			||||||
        code = response.status_code if response else 504
 | 
					 | 
				
			||||||
        response = ErrorResponse({"message": message}, code, None)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Display debug output
 | 
					 | 
				
			||||||
    if config["debug"]:
 | 
					 | 
				
			||||||
        echo("API endpoint: {}".format(uri), err=True)
 | 
					 | 
				
			||||||
        echo("Response code: {}".format(response.status_code), err=True)
 | 
					 | 
				
			||||||
        echo("Response headers: {}".format(response.headers), err=True)
 | 
					 | 
				
			||||||
        echo(err=True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Return the response object
 | 
					 | 
				
			||||||
    return response
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def get_wait_retdata(response, wait_flag):
 | 
					def get_wait_retdata(response, wait_flag):
 | 
				
			||||||
    if response.status_code == 202:
 | 
					    if response.status_code == 202:
 | 
				
			||||||
        retvalue = True
 | 
					        retvalue = True
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										38
									
								
								client-cli/pvc/lib/lazy_imports.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								client-cli/pvc/lib/lazy_imports.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env python3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# lazy_imports.py - Lazy module importer library
 | 
				
			||||||
 | 
					# Part of the Parallel Virtual Cluster (PVC) system
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#    Copyright (C) 2018-2024 Joshua M. Boniface <joshua@boniface.me>
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#    This program is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					#    it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					#    the Free Software Foundation, version 3.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#    This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					#    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					#    GNU General Public License for more details.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#    You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					#    along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					###############################################################################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LazyModule:
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    A proxy for a module that is loaded only when actually used
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    def __init__(self, name):
 | 
				
			||||||
 | 
					        self.name = name
 | 
				
			||||||
 | 
					        self._module = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __getattr__(self, attr):
 | 
				
			||||||
 | 
					        if self._module is None:
 | 
				
			||||||
 | 
					            import importlib
 | 
				
			||||||
 | 
					            self._module = importlib.import_module(self.name)
 | 
				
			||||||
 | 
					        return getattr(self._module, attr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Create lazy module proxies
 | 
				
			||||||
 | 
					yaml = LazyModule('yaml')
 | 
				
			||||||
 | 
					click_advanced = LazyModule('click')  # For advanced click features not used at startup
 | 
				
			||||||
		Reference in New Issue
	
	Block a user