Source code for cycletls._global

"""Global session management for CycleTLS module-level functions."""

import atexit
import os
import threading
from typing import TYPE_CHECKING, Optional

if TYPE_CHECKING:
    from .api import CycleTLS

# Lazy import to avoid circular dependency
_CycleTLS = None


def _import_cycletls():
    """Lazy import to avoid circular dependency."""
    global _CycleTLS
    if _CycleTLS is None:
        from .api import CycleTLS

        _CycleTLS = CycleTLS


# Global state
_global_session: Optional["CycleTLS"] = None
_global_lock = threading.Lock()
_cleanup_registered = False
_parent_pid = os.getpid()


def get_global_session():
    """
    Get or create the global CycleTLS session.

    The session is lazily initialized on first use and automatically
    cleaned up on program exit.

    Returns:
        CycleTLS: The global session instance
    """
    global _global_session, _cleanup_registered, _parent_pid

    # Check if we're in a forked child process
    current_pid = os.getpid()
    if current_pid != _parent_pid:
        # We're in a forked child - reset to avoid sharing WebSocket
        _global_session = None
        _parent_pid = current_pid

    if _global_session is None:
        with _global_lock:  # Double-checked locking
            if _global_session is None:
                _import_cycletls()
                _global_session = _CycleTLS()

                # Register cleanup ONCE
                if not _cleanup_registered:
                    atexit.register(_cleanup_global_session)
                    _cleanup_registered = True

    return _global_session


def _cleanup_global_session():
    """
    Cleanup function called by atexit.

    Closes the global session and cleans up resources.
    """
    global _global_session
    if _global_session is not None:
        try:
            _global_session.close()
        except Exception:
            # Silently ignore cleanup errors during shutdown
            pass
        finally:
            _global_session = None


[docs] def close_global_session(): """ Manually close the global session. Useful for explicit cleanup in notebooks or when you want to reset the global session with different settings. Example: >>> import cycletls >>> response = cycletls.get('https://example.com') >>> cycletls.close_global_session() # Explicit cleanup >>> response = cycletls.get('https://example.com') # New session """ global _global_session if _global_session is not None: with _global_lock: if _global_session is not None: try: _global_session.close() except Exception: pass finally: _global_session = None