Skip to content

ONVIFWSDL

onvif.utils.ONVIFWSDL

0.1.0 Utility class

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

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:

  • filename : WSDL file name
  • 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:
    """
    <!-- md:version 0.1.0 -->
    <!-- md:utility Utility class-->

    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

    !!! 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
        ```

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

        - `filename` : WSDL file name
        - `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")

    ??? question "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: str) -> None:
        """
        <!-- md:version 0.1.0 -->
        <!-- md:utility -->

        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:
        """
        <!-- md:version 0.1.0 -->
        <!-- md:utility -->

        Get current global custom WSDL directory.

        Returns:
            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:
        """
        <!-- md:version 0.1.0 -->
        <!-- md:utility -->

        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: str | None = 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 | None): 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: str | None = 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 | None): Custom WSDL directory path

        Returns:
            dict: Complete WSDL mapping for all services

            WSDL Map Structure:
                {
                    "{service_name}": {
                        "{version}": {
                            "filename": "service.wsdl",
                            "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)

        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
        wsdl_map: WSDLMap = {}

        for service, versions in ONVIF_WSDL_MAP.items():
            wsdl_map[service] = {}

            for version, definition in versions.items():
                filename = definition["filename"]
                relative_path = filename if use_flat else definition["path"]

                wsdl_map[service][version] = {
                    **definition,
                    "path": os.path.join(base_dir, relative_path),
                }

        return wsdl_map

    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]]:
        """
        <!-- md:version 0.2.11 -->
        <!-- md:utility -->

        Get the complete WSDL map for all services.
        """
        cls._ensure_wsdl_map_initialized()

        if cls.WSDL_MAP is None:
            raise RuntimeError("WSDL map was not initialized")

        return cls.WSDL_MAP

    @classmethod
    def get_definition(
        cls, service: str, version: str = "ver10", custom_wsdl_dir=None
    ) -> dict:
        """
        <!-- md:version 0.1.0 -->
        <!-- md:utility -->

        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 |
            | --- | ---- | ----------- |
            | `filename` | `str`  | WSDL file name |
            | `path` | `str | None` | Full path to WSDL file |
            | `binding` | `str` | SOAP binding name |
            | `namespace` | `str` | XML namespace URI |

            !!! tip "Version History"
                - Added in [`v0.4.5`](/onvif-python/releases/#v0.4.5): `filename`

        ??? 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 classmethod

set_custom_wsdl_dir(custom_dir: str) -> None

0.1.0

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: str) -> None:
    """
    <!-- md:version 0.1.0 -->
    <!-- md:utility -->

    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 classmethod

get_custom_wsdl_dir() -> str | None

0.1.0

Get current global custom WSDL directory.

Returns:

Type Description
str | 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:
    """
    <!-- md:version 0.1.0 -->
    <!-- md:utility -->

    Get current global custom WSDL directory.

    Returns:
        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 classmethod

clear_custom_wsdl_dir() -> None

0.1.0

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:
    """
    <!-- md:version 0.1.0 -->
    <!-- md:utility -->

    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 classmethod

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

0.2.11

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]]:
    """
    <!-- md:version 0.2.11 -->
    <!-- md:utility -->

    Get the complete WSDL map for all services.
    """
    cls._ensure_wsdl_map_initialized()

    if cls.WSDL_MAP is None:
        raise RuntimeError("WSDL map was not initialized")

    return cls.WSDL_MAP

get_definition classmethod

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

0.1.0

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
filename str WSDL file name
path str | None Full path to WSDL file
binding str SOAP binding name
namespace str XML namespace URI

Version History

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:
    """
    <!-- md:version 0.1.0 -->
    <!-- md:utility -->

    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 |
        | --- | ---- | ----------- |
        | `filename` | `str`  | WSDL file name |
        | `path` | `str | None` | Full path to WSDL file |
        | `binding` | `str` | SOAP binding name |
        | `namespace` | `str` | XML namespace URI |

        !!! tip "Version History"
            - Added in [`v0.4.5`](/onvif-python/releases/#v0.4.5): `filename`

    ??? 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

Comments