Skip to content

ONVIFWSDL

WSDL file manager for ONVIF services.

This class manages WSDL (Web Services Description Language) file paths, bindings, and namespaces for all ONVIF services. It provides a centralized mapping between service names and their corresponding WSDL definitions.

The class supports both built-in WSDLs (bundled with the package) and custom WSDL directories for users who want to use their own WSDL files.

Attributes:

Name Type Description
BASE_DIR str

Default base directory for WSDL files (Built-in)

WSDL_MAP dict[str, dict[str, Any]] | None

Will be initialized when first accessed

_custom_wsdl_dir str | None

Global custom WSDL directory

Version History

Features

  • Centralized WSDL definition mapping for all ONVIF services
  • Support for multiple ONVIF versions (ver10, ver20)
  • Custom WSDL directory support (global and per-call)
  • Automatic path resolution for built-in and custom WSDLs
  • Service discovery with namespace and binding information
  • File existence validation

WSDL Structure

Built-in WSDLs are organized in the ONVIF standard directory structure:

onvif/
└── wsdl/
    ├── ver10/
    │   └── device/
    │       └── wsdl/
    │           └── devicemgmt.wsdl
    └── ver20/
        ├── media/
        │   └── wsdl/
        │       └── media.wsdl
        └── ptz/
            └── wsdl/
                └── ptz.wsdl

Custom WSDLs must use a flat structure:

custom/
└── path/
    ├── devicemgmt.wsdl
    ├── media.wsdl
    └── ptz.wsdl

Service Definition Format

Each service has a definition containing:

  • path: Full path to WSDL file
  • binding: SOAP binding name (e.g., "DeviceBinding")
  • namespace: XML namespace URI (e.g., "http://www.onvif.org/ver10/device/wsdl")
Custom WSDL Directory Priority
  1. Per-call custom_wsdl_dir parameter (highest priority)
  2. Global _custom_wsdl_dir setting
  3. Built-in BASE_DIR (default)
Notes
  • All methods are class methods - no need to instantiate
  • WSDL files are lazy-loaded and validated on access
  • Custom WSDL directories use flat file structure
  • Built-in WSDLs follow ONVIF standard directory structure
  • File existence is checked when getting definitions
  • Thread-safe for read operations
See Also
  • ONVIFOperator: Uses WSDL definitions to create SOAP clients
  • ONVIFClient: High-level client that uses this class internally
Source code in onvif\utils\wsdl.py
class ONVIFWSDL:
    """WSDL file manager for ONVIF services.

    This class manages WSDL (Web Services Description Language) file paths, bindings,
    and namespaces for all ONVIF services. It provides a centralized mapping between
    service names and their corresponding WSDL definitions.

    The class supports both built-in WSDLs (bundled with the package) and custom
    WSDL directories for users who want to use their own WSDL files.

    Attributes:
        BASE_DIR (str): Default base directory for WSDL files (Built-in)
        WSDL_MAP (dict[str, dict[str, Any]] | None): Will be initialized when first accessed
        _custom_wsdl_dir (str | None): Global custom WSDL directory

    !!! tip "Version History"
        - Available since [`>=v0.1.0`](/onvif-python/releases/#v0.1.0).

    !!! abstract "Features"
        - Centralized WSDL definition mapping for all ONVIF services
        - Support for multiple ONVIF versions (ver10, ver20)
        - Custom WSDL directory support (global and per-call)
        - Automatic path resolution for built-in and custom WSDLs
        - Service discovery with namespace and binding information
        - File existence validation

    !!! warning "WSDL Structure"
        Built-in WSDLs are organized in the ONVIF standard directory structure:

        ```text
        onvif/
        └── wsdl/
            ├── ver10/
            │   └── device/
            │       └── wsdl/
            │           └── devicemgmt.wsdl

            └── ver20/
                ├── media/
                │   └── wsdl/
                │       └── media.wsdl
                └── ptz/
                    └── wsdl/
                        └── ptz.wsdl
        ```

        Custom WSDLs must use a flat structure:

        ```text
        custom/
        └── path/
            ├── devicemgmt.wsdl
            ├── media.wsdl
            └── ptz.wsdl
        ```

    !!! question "Service Definition Format"
        Each service has a definition containing:

        - `path`: Full path to WSDL file
        - `binding`: SOAP binding name (e.g., "DeviceBinding")
        - `namespace`: XML namespace URI (e.g., "http://www.onvif.org/ver10/device/wsdl")

    ??? tip "Custom WSDL Directory Priority"
        1. Per-call `custom_wsdl_dir` parameter (highest priority)
        2. Global `_custom_wsdl_dir` setting
        3. Built-in `BASE_DIR` (default)

    ??? note "Notes"
        - All methods are class methods - no need to instantiate
        - WSDL files are lazy-loaded and validated on access
        - Custom WSDL directories use flat file structure
        - Built-in WSDLs follow ONVIF standard directory structure
        - File existence is checked when getting definitions
        - Thread-safe for read operations

    ??? note "See Also"
        - [`ONVIFOperator`](../core/onvif_operator.md): Uses WSDL definitions to create SOAP clients
        - [`ONVIFClient`](../core/onvif_client.md): High-level client that uses this class internally
    """

    # Default base directory for WSDL files (Built-in)
    # Included in the package
    BASE_DIR: str = os.path.join(os.path.dirname(os.path.dirname(__file__)), "wsdl")

    # Global custom WSDL directory - can be set once for all services
    _custom_wsdl_dir: str | None = None

    @classmethod
    def set_custom_wsdl_dir(cls, custom_dir) -> None:
        """Set global custom WSDL directory for all services.

        Args:
            custom_dir (str): Path to directory containing custom WSDL files

        Example:
            ```python linenums="1"
            from onvif import ONVIFWSDL

            ONVIFWSDL.set_custom_wsdl_dir("/home/user/my_wsdls")
            # All subsequent get_definition calls will use this directory
            ```
        """
        logger.info("Setting custom WSDL directory: %s", custom_dir)
        cls._custom_wsdl_dir = custom_dir

    @classmethod
    def get_custom_wsdl_dir(cls) -> str | None:
        """Get current global custom WSDL directory.

        Returns:
            str or None: Current custom WSDL directory, or None if using built-in

        Example:
            ```python linenums="1"
            from onvif import ONVIFWSDL

            ONVIFWSDL.set_custom_wsdl_dir("/custom/path")
            print(ONVIFWSDL.get_custom_wsdl_dir())  # /custom/path
            ```
        """
        return cls._custom_wsdl_dir

    @classmethod
    def clear_custom_wsdl_dir(cls) -> None:
        """Clear custom WSDL directory, revert to built-in WSDLs.

        Example:
            ```python linenums="1"
            from onvif import ONVIFWSDL

            ONVIFWSDL.set_custom_wsdl_dir("/custom/path")
            ONVIFWSDL.clear_custom_wsdl_dir()
            # Now using built-in WSDLs again
            ```
        """
        logger.info("Clearing custom WSDL directory, reverting to built-in WSDLs")
        cls._custom_wsdl_dir = None

    @classmethod
    def _get_base_dir(cls, custom_wsdl_dir=None) -> str | Any:
        """Get the base WSDL directory, using custom directory if provided.

        This method implements the priority chain for WSDL directory resolution.

        Args:
            custom_wsdl_dir (str, optional): Per-call custom directory

        Returns:
            str: Resolved WSDL base directory path

        Priority:
            1. `custom_wsdl_dir` parameter (highest)
            2. `cls._custom_wsdl_dir` global setting
            3. `cls.BASE_DIR` built-in default (lowest)
        """
        # Priority: parameter > global setting > default
        if custom_wsdl_dir:
            return custom_wsdl_dir

        if cls._custom_wsdl_dir:
            return cls._custom_wsdl_dir

        return cls.BASE_DIR

    @classmethod
    def _get_wsdl_map(cls, custom_wsdl_dir=None) -> dict[str, dict[str, Any]] | None:
        """Get WSDL map with proper base directory.

        Generates a complete mapping of all ONVIF services to their WSDL definitions.
        The structure differs based on whether custom WSDLs are used.

        Args:
            custom_wsdl_dir (str, optional): Custom WSDL directory path

        Returns:
            dict: Complete WSDL mapping for all services

            WSDL Map Structure:
                {
                    "{service_name}": {
                        "{version}": {
                            "path": "/full/path/to/service.wsdl",
                            "binding": "ServiceBinding",
                            "namespace": "http://www.onvif.org/ver10/service/wsdl"
                        }
                    }
                }

        Path Resolution:
            - Built-in: Uses ONVIF standard directory structure
              Example: ver10/device/wsdl/devicemgmt.wsdl
            - Custom: Uses flat structure with direct filename
              Example: devicemgmt.wsdl
        """
        base_dir = cls._get_base_dir(custom_wsdl_dir)

        # Determine if we should use flat structure
        # Use flat structure if custom_wsdl_dir is explicitly provided OR if global custom dir is set
        use_flat = custom_wsdl_dir is not None or cls._custom_wsdl_dir is not None

        # Default structure for WSDL files
        # If custom_wsdl_dir is provided, use flat structure (direct filename)
        # Otherwise, use the standard ONVIF directory structure
        return {
            "devicemgmt": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "devicemgmt.wsdl"
                            if use_flat
                            else "ver10/device/wsdl/devicemgmt.wsdl"
                        ),
                    ),
                    "binding": "DeviceBinding",
                    "namespace": "http://www.onvif.org/ver10/device/wsdl",
                }
            },
            "events": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "event-vs.wsdl"
                            if use_flat
                            else "ver10/events/wsdl/event-vs.wsdl"
                        ),
                    ),
                    "binding": "EventBinding",
                    "namespace": "http://www.onvif.org/ver10/events/wsdl",
                }
            },
            "pullpoint": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "event-vs.wsdl"
                            if use_flat
                            else "ver10/events/wsdl/event-vs.wsdl"
                        ),
                    ),
                    "binding": "PullPointSubscriptionBinding",
                    "namespace": "http://www.onvif.org/ver10/events/wsdl",
                }
            },
            "notification": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "event-vs.wsdl"
                            if use_flat
                            else "ver10/events/wsdl/event-vs.wsdl"
                        ),
                    ),
                    "binding": "NotificationProducerBinding",
                    "namespace": "http://www.onvif.org/ver10/events/wsdl",
                }
            },
            "subscription": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "event-vs.wsdl"
                            if use_flat
                            else "ver10/events/wsdl/event-vs.wsdl"
                        ),
                    ),
                    "binding": "SubscriptionManagerBinding",
                    "namespace": "http://www.onvif.org/ver10/events/wsdl",
                }
            },
            "pausable_subscription": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "event-vs.wsdl"
                            if use_flat
                            else "ver10/events/wsdl/event-vs.wsdl"
                        ),
                    ),
                    "binding": "PausableSubscriptionManagerBinding",
                    "namespace": "http://www.onvif.org/ver10/events/wsdl",
                }
            },
            "accesscontrol": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "accesscontrol.wsdl"
                            if use_flat
                            else "ver10/pacs/accesscontrol.wsdl"
                        ),
                    ),
                    "binding": "PACSBinding",
                    "namespace": "http://www.onvif.org/ver10/accesscontrol/wsdl",
                }
            },
            "accessrules": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "accessrules.wsdl"
                            if use_flat
                            else "ver10/accessrules/wsdl/accessrules.wsdl"
                        ),
                    ),
                    "binding": "AccessRulesBinding",
                    "namespace": "http://www.onvif.org/ver10/accessrules/wsdl",
                }
            },
            "actionengine": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "actionengine.wsdl"
                            if use_flat
                            else "ver10/actionengine.wsdl"
                        ),
                    ),
                    "binding": "ActionEngineBinding",
                    "namespace": "http://www.onvif.org/ver10/actionengine/wsdl",
                }
            },
            "advancedsecurity": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "advancedsecurity.wsdl"
                            if use_flat
                            else "ver10/advancedsecurity/wsdl/advancedsecurity.wsdl"
                        ),
                    ),
                    "binding": "AdvancedSecurityServiceBinding",
                    "namespace": "http://www.onvif.org/ver10/advancedsecurity/wsdl",
                }
            },
            "jwt": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "advancedsecurity.wsdl"
                            if use_flat
                            else "ver10/advancedsecurity/wsdl/advancedsecurity.wsdl"
                        ),
                    ),
                    "binding": "JWTBinding",
                    "namespace": "http://www.onvif.org/ver10/advancedsecurity/wsdl",
                }
            },
            "keystore": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "advancedsecurity.wsdl"
                            if use_flat
                            else "ver10/advancedsecurity/wsdl/advancedsecurity.wsdl"
                        ),
                    ),
                    "binding": "KeystoreBinding",
                    "namespace": "http://www.onvif.org/ver10/advancedsecurity/wsdl",
                }
            },
            "tlsserver": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "advancedsecurity.wsdl"
                            if use_flat
                            else "ver10/advancedsecurity/wsdl/advancedsecurity.wsdl"
                        ),
                    ),
                    "binding": "TLSServerBinding",
                    "namespace": "http://www.onvif.org/ver10/advancedsecurity/wsdl",
                }
            },
            "dot1x": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "advancedsecurity.wsdl"
                            if use_flat
                            else "ver10/advancedsecurity/wsdl/advancedsecurity.wsdl"
                        ),
                    ),
                    "binding": "Dot1XBinding",
                    "namespace": "http://www.onvif.org/ver10/advancedsecurity/wsdl",
                }
            },
            "authorizationserver": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "advancedsecurity.wsdl"
                            if use_flat
                            else "ver10/advancedsecurity/wsdl/advancedsecurity.wsdl"
                        ),
                    ),
                    "binding": "AuthorizationServerBinding",
                    "namespace": "http://www.onvif.org/ver10/advancedsecurity/wsdl",
                }
            },
            "mediasigning": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "advancedsecurity.wsdl"
                            if use_flat
                            else "ver10/advancedsecurity/wsdl/advancedsecurity.wsdl"
                        ),
                    ),
                    "binding": "MediaSigningBinding",
                    "namespace": "http://www.onvif.org/ver10/advancedsecurity/wsdl",
                }
            },
            "analytics": {
                "ver20": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "analytics.wsdl"
                            if use_flat
                            else "ver20/analytics/wsdl/analytics.wsdl"
                        ),
                    ),
                    "binding": "AnalyticsEngineBinding",
                    "namespace": "http://www.onvif.org/ver20/analytics/wsdl",
                }
            },
            "ruleengine": {
                "ver20": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "ruleengine.wsdl"
                            if use_flat
                            else "ver20/analytics/wsdl/analytics.wsdl"
                        ),
                    ),
                    "binding": "RuleEngineBinding",
                    "namespace": "http://www.onvif.org/ver20/analytics/wsdl",
                }
            },
            "analyticsdevice": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "analyticsdevice.wsdl"
                            if use_flat
                            else "ver10/analyticsdevice.wsdl"
                        ),
                    ),
                    "binding": "AnalyticsDeviceBinding",
                    "namespace": "http://www.onvif.org/ver10/analyticsdevice/wsdl",
                }
            },
            "appmgmt": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "appmgmt.wsdl"
                            if use_flat
                            else "ver10/appmgmt/wsdl/appmgmt.wsdl"
                        ),
                    ),
                    "binding": "AppManagementBinding",
                    "namespace": "http://www.onvif.org/ver10/appmgmt/wsdl",
                }
            },
            "authenticationbehavior": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "authenticationbehavior.wsdl"
                            if use_flat
                            else "ver10/authenticationbehavior/wsdl/authenticationbehavior.wsdl"
                        ),
                    ),
                    "binding": "AuthenticationBehaviorBinding",
                    "namespace": "http://www.onvif.org/ver10/authenticationbehavior/wsdl",
                }
            },
            "credential": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "credential.wsdl"
                            if use_flat
                            else "ver10/credential/wsdl/credential.wsdl"
                        ),
                    ),
                    "binding": "CredentialBinding",
                    "namespace": "http://www.onvif.org/ver10/credential/wsdl",
                }
            },
            "deviceio": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        "deviceio.wsdl" if use_flat else "ver10/deviceio.wsdl",
                    ),
                    "binding": "DeviceIOBinding",
                    "namespace": "http://www.onvif.org/ver10/deviceIO/wsdl",
                }
            },
            "display": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        "display.wsdl" if use_flat else "ver10/display.wsdl",
                    ),
                    "binding": "DisplayBinding",
                    "namespace": "http://www.onvif.org/ver10/display/wsdl",
                }
            },
            "doorcontrol": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "doorcontrol.wsdl"
                            if use_flat
                            else "ver10/pacs/doorcontrol.wsdl"
                        ),
                    ),
                    "binding": "DoorControlBinding",
                    "namespace": "http://www.onvif.org/ver10/doorcontrol/wsdl",
                }
            },
            "imaging": {
                "ver20": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "imaging.wsdl"
                            if use_flat
                            else "ver20/imaging/wsdl/imaging.wsdl"
                        ),
                    ),
                    "binding": "ImagingBinding",
                    "namespace": "http://www.onvif.org/ver20/imaging/wsdl",
                }
            },
            "media": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        ("media.wsdl" if use_flat else "ver10/media/wsdl/media.wsdl"),
                    ),
                    "binding": "MediaBinding",
                    "namespace": "http://www.onvif.org/ver10/media/wsdl",
                },
            },
            "media2": {
                "ver20": {
                    "path": os.path.join(
                        base_dir,
                        ("media2.wsdl" if use_flat else "ver20/media/wsdl/media.wsdl"),
                    ),
                    "binding": "Media2Binding",
                    "namespace": "http://www.onvif.org/ver20/media/wsdl",
                },
            },
            "provisioning": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "provisioning.wsdl"
                            if use_flat
                            else "ver10/provisioning/wsdl/provisioning.wsdl"
                        ),
                    ),
                    "binding": "ProvisioningBinding",
                    "namespace": "http://www.onvif.org/ver10/provisioning/wsdl",
                },
            },
            "ptz": {
                "ver20": {
                    "path": os.path.join(
                        base_dir,
                        "ptz.wsdl" if use_flat else "ver20/ptz/wsdl/ptz.wsdl",
                    ),
                    "binding": "PTZBinding",
                    "namespace": "http://www.onvif.org/ver20/ptz/wsdl",
                },
            },
            "receiver": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        "receiver.wsdl" if use_flat else "ver10/receiver.wsdl",
                    ),
                    "binding": "ReceiverBinding",
                    "namespace": "http://www.onvif.org/ver10/receiver/wsdl",
                },
            },
            "recording": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        "recording.wsdl" if use_flat else "ver10/recording.wsdl",
                    ),
                    "binding": "RecordingBinding",
                    "namespace": "http://www.onvif.org/ver10/recording/wsdl",
                },
            },
            "replay": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        "replay.wsdl" if use_flat else "ver10/replay.wsdl",
                    ),
                    "binding": "ReplayBinding",
                    "namespace": "http://www.onvif.org/ver10/replay/wsdl",
                },
            },
            "schedule": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "schedule.wsdl"
                            if use_flat
                            else "ver10/schedule/wsdl/schedule.wsdl"
                        ),
                    ),
                    "binding": "ScheduleBinding",
                    "namespace": "http://www.onvif.org/ver10/schedule/wsdl",
                },
            },
            "search": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        "search.wsdl" if use_flat else "ver10/search.wsdl",
                    ),
                    "binding": "SearchBinding",
                    "namespace": "http://www.onvif.org/ver10/search/wsdl",
                },
            },
            "thermal": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "thermal.wsdl"
                            if use_flat
                            else "ver10/thermal/wsdl/thermal.wsdl"
                        ),
                    ),
                    "binding": "ThermalBinding",
                    "namespace": "http://www.onvif.org/ver10/thermal/wsdl",
                },
            },
            "uplink": {
                "ver10": {
                    "path": os.path.join(
                        base_dir,
                        (
                            "uplink.wsdl"
                            if use_flat
                            else "ver10/uplink/wsdl/uplink.wsdl"
                        ),
                    ),
                    "binding": "UplinkBinding",
                    "namespace": "http://www.onvif.org/ver10/uplink/wsdl",
                },
            },
        }

    WSDL_MAP: dict[str, dict[str, Any]] | None = (
        None  # Will be initialized when first accessed
    )

    @classmethod
    def _ensure_wsdl_map_initialized(cls) -> None:
        """Ensure WSDL_MAP is initialized with default values.

        Lazy initialization of the default WSDL map. This is called automatically before
        accessing WSDL_MAP to ensure it's not None.
        """
        if cls.WSDL_MAP is None:
            cls.WSDL_MAP = cls._get_wsdl_map()

    @classmethod
    def get_wsdl_map(cls) -> dict[str, dict[str, Any]]:
        """Get the complete WSDL map for all services."""
        cls._ensure_wsdl_map_initialized()
        assert cls.WSDL_MAP is not None
        return cls.WSDL_MAP

    @classmethod
    def get_definition(
        cls, service: str, version: str = "ver10", custom_wsdl_dir=None
    ) -> dict:
        """Get WSDL definition for a specific ONVIF service.

        Returns complete WSDL definition including file path, SOAP binding name,
        and XML namespace for the requested service and version.

        Args:
            service (str): Service name (e.g., "devicemgmt", "media", "ptz").
            version (str): ONVIF version (default: "ver10").
                Common versions: "ver10", "ver20".
            custom_wsdl_dir (str | None): Custom WSDL directory path.
                Overrides global custom directory if provided.

        Returns:
            WSDL definition dictionary.

        !!! abstract "Definition dict"

            | Key | Type | Description |
            | --- | ---- | ----------- |
            | `path` | `str | None` | Full path to WSDL file |
            | `binding` | `str` | SOAP binding name |
            | `namespace` | `str` | XML namespace URI |

        ??? note
            - Most services use ver10, some newer ones use ver20
            - Media has both ver10 (media) and ver20 (media2)
            - Custom WSDLs must match the service name exactly
            - File existence is validated before returning definition
        """
        logger.debug("Getting WSDL definition for service: %s (%s)", service, version)

        # Use custom WSDL map if custom directory is provided
        if custom_wsdl_dir:
            logger.debug("Using custom WSDL directory: %s", custom_wsdl_dir)
            wsdl_map = cls._get_wsdl_map(custom_wsdl_dir)
        else:
            # Ensure default WSDL_MAP is initialized
            cls._ensure_wsdl_map_initialized()
            wsdl_map = cls.WSDL_MAP

        # Safety check for None wsdl_map
        if wsdl_map is None:
            logger.error("Failed to initialize WSDL map")
            raise RuntimeError("Failed to initialize WSDL map")

        if service not in wsdl_map:
            logger.error("Unknown service: %s", service)
            raise ValueError(f"Unknown service: {service}")
        if version not in wsdl_map[service]:
            logger.error("Version %s not available for %s", version, service)
            raise ValueError(f"Version {version} not available for {service}")

        definition = wsdl_map[service][version]
        if not os.path.exists(definition["path"]):
            logger.error("WSDL file not found: %s", definition["path"])
            raise FileNotFoundError(f"WSDL file not found: {definition['path']}")

        logger.debug("WSDL definition resolved: %s", definition["path"])
        return definition

set_custom_wsdl_dir(custom_dir) -> None classmethod

Set global custom WSDL directory for all services.

Parameters:

Name Type Description Default
custom_dir str

Path to directory containing custom WSDL files

required
Example
from onvif import ONVIFWSDL

ONVIFWSDL.set_custom_wsdl_dir("/home/user/my_wsdls")
# All subsequent get_definition calls will use this directory
Source code in onvif\utils\wsdl.py
@classmethod
def set_custom_wsdl_dir(cls, custom_dir) -> None:
    """Set global custom WSDL directory for all services.

    Args:
        custom_dir (str): Path to directory containing custom WSDL files

    Example:
        ```python linenums="1"
        from onvif import ONVIFWSDL

        ONVIFWSDL.set_custom_wsdl_dir("/home/user/my_wsdls")
        # All subsequent get_definition calls will use this directory
        ```
    """
    logger.info("Setting custom WSDL directory: %s", custom_dir)
    cls._custom_wsdl_dir = custom_dir

get_custom_wsdl_dir() -> str | None classmethod

Get current global custom WSDL directory.

Returns:

Type Description
str | None

str or None: Current custom WSDL directory, or None if using built-in

Example
from onvif import ONVIFWSDL

ONVIFWSDL.set_custom_wsdl_dir("/custom/path")
print(ONVIFWSDL.get_custom_wsdl_dir())  # /custom/path
Source code in onvif\utils\wsdl.py
@classmethod
def get_custom_wsdl_dir(cls) -> str | None:
    """Get current global custom WSDL directory.

    Returns:
        str or None: Current custom WSDL directory, or None if using built-in

    Example:
        ```python linenums="1"
        from onvif import ONVIFWSDL

        ONVIFWSDL.set_custom_wsdl_dir("/custom/path")
        print(ONVIFWSDL.get_custom_wsdl_dir())  # /custom/path
        ```
    """
    return cls._custom_wsdl_dir

clear_custom_wsdl_dir() -> None classmethod

Clear custom WSDL directory, revert to built-in WSDLs.

Example
from onvif import ONVIFWSDL

ONVIFWSDL.set_custom_wsdl_dir("/custom/path")
ONVIFWSDL.clear_custom_wsdl_dir()
# Now using built-in WSDLs again
Source code in onvif\utils\wsdl.py
@classmethod
def clear_custom_wsdl_dir(cls) -> None:
    """Clear custom WSDL directory, revert to built-in WSDLs.

    Example:
        ```python linenums="1"
        from onvif import ONVIFWSDL

        ONVIFWSDL.set_custom_wsdl_dir("/custom/path")
        ONVIFWSDL.clear_custom_wsdl_dir()
        # Now using built-in WSDLs again
        ```
    """
    logger.info("Clearing custom WSDL directory, reverting to built-in WSDLs")
    cls._custom_wsdl_dir = None

get_wsdl_map() -> dict[str, dict[str, Any]] classmethod

Get the complete WSDL map for all services.

Source code in onvif\utils\wsdl.py
@classmethod
def get_wsdl_map(cls) -> dict[str, dict[str, Any]]:
    """Get the complete WSDL map for all services."""
    cls._ensure_wsdl_map_initialized()
    assert cls.WSDL_MAP is not None
    return cls.WSDL_MAP

get_definition(service: str, version: str = 'ver10', custom_wsdl_dir=None) -> dict classmethod

Get WSDL definition for a specific ONVIF service.

Returns complete WSDL definition including file path, SOAP binding name, and XML namespace for the requested service and version.

Parameters:

Name Type Description Default
service str

Service name (e.g., "devicemgmt", "media", "ptz").

required
version str

ONVIF version (default: "ver10"). Common versions: "ver10", "ver20".

'ver10'
custom_wsdl_dir str | None

Custom WSDL directory path. Overrides global custom directory if provided.

None

Returns:

Type Description
dict

WSDL definition dictionary.

Definition dict

Key Type Description
path str | None Full path to WSDL file
binding str SOAP binding name
namespace str XML namespace URI
Note
  • Most services use ver10, some newer ones use ver20
  • Media has both ver10 (media) and ver20 (media2)
  • Custom WSDLs must match the service name exactly
  • File existence is validated before returning definition
Source code in onvif\utils\wsdl.py
@classmethod
def get_definition(
    cls, service: str, version: str = "ver10", custom_wsdl_dir=None
) -> dict:
    """Get WSDL definition for a specific ONVIF service.

    Returns complete WSDL definition including file path, SOAP binding name,
    and XML namespace for the requested service and version.

    Args:
        service (str): Service name (e.g., "devicemgmt", "media", "ptz").
        version (str): ONVIF version (default: "ver10").
            Common versions: "ver10", "ver20".
        custom_wsdl_dir (str | None): Custom WSDL directory path.
            Overrides global custom directory if provided.

    Returns:
        WSDL definition dictionary.

    !!! abstract "Definition dict"

        | Key | Type | Description |
        | --- | ---- | ----------- |
        | `path` | `str | None` | Full path to WSDL file |
        | `binding` | `str` | SOAP binding name |
        | `namespace` | `str` | XML namespace URI |

    ??? note
        - Most services use ver10, some newer ones use ver20
        - Media has both ver10 (media) and ver20 (media2)
        - Custom WSDLs must match the service name exactly
        - File existence is validated before returning definition
    """
    logger.debug("Getting WSDL definition for service: %s (%s)", service, version)

    # Use custom WSDL map if custom directory is provided
    if custom_wsdl_dir:
        logger.debug("Using custom WSDL directory: %s", custom_wsdl_dir)
        wsdl_map = cls._get_wsdl_map(custom_wsdl_dir)
    else:
        # Ensure default WSDL_MAP is initialized
        cls._ensure_wsdl_map_initialized()
        wsdl_map = cls.WSDL_MAP

    # Safety check for None wsdl_map
    if wsdl_map is None:
        logger.error("Failed to initialize WSDL map")
        raise RuntimeError("Failed to initialize WSDL map")

    if service not in wsdl_map:
        logger.error("Unknown service: %s", service)
        raise ValueError(f"Unknown service: {service}")
    if version not in wsdl_map[service]:
        logger.error("Version %s not available for %s", version, service)
        raise ValueError(f"Version {version} not available for {service}")

    definition = wsdl_map[service][version]
    if not os.path.exists(definition["path"]):
        logger.error("WSDL file not found: %s", definition["path"])
        raise FileNotFoundError(f"WSDL file not found: {definition['path']}")

    logger.debug("WSDL definition resolved: %s", definition["path"])
    return definition