# coding: utf-8

"""
    Kubernetes

    No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)

    The version of the OpenAPI document: release-1.37
    Generated by OpenAPI Generator (https://openapi-generator.tech)

    Do not edit the class manually.
"""  # noqa: E501


from __future__ import annotations
import pprint
import re  # noqa: F401
import json

from collections.abc import Mapping as _Mapping
from pydantic import AliasChoices, BaseModel, ConfigDict, Field, StrictBool, StrictStr
from typing import Any, ClassVar, Dict, List, Optional, cast as _cast
from kubernetes.aio.client.models.v1_node_selector import V1NodeSelector
from kubernetes.aio.client.models.v1beta1_counter_set import V1beta1CounterSet
from kubernetes.aio.client.models.v1beta1_device import V1beta1Device
from kubernetes.aio.client.models.v1beta1_resource_pool import V1beta1ResourcePool
from typing import Optional, Set
from typing_extensions import Self
from pydantic_core import to_jsonable_python


_OPENAPI_GENERATOR_TO_DICT = "_openapi_generator_to_dict"


def _get_openapi_to_dict(value: Any) -> Any:
    # Reciprocal function references preserve inherited generated methods
    # without reserving model member names. Checking both directions also
    # rejects overrides whose decorators copy function attributes.
    to_dict = getattr(value, "to_dict", None)
    type_to_dict = getattr(type(value), "to_dict", None)
    if (
        not callable(to_dict)
        or getattr(to_dict, "__func__", None) is not type_to_dict
    ):
        return None

    openapi_to_dict = getattr(
        type_to_dict, _OPENAPI_GENERATOR_TO_DICT, None
    )
    if (
        not callable(openapi_to_dict)
        or getattr(
            openapi_to_dict,
            _OPENAPI_GENERATOR_TO_DICT,
            None,
        ) is not type_to_dict
    ):
        return None
    return openapi_to_dict


def _to_legacy_item(value: Any, serialize: bool) -> Any:
    to_dict = getattr(value, "to_dict", None)
    if _get_openapi_to_dict(value) is not None and callable(to_dict):
        return to_dict(serialize=serialize)
    if callable(to_dict):
        return to_dict()
    return value


def _to_legacy_value(value: Any, serialize: bool) -> Any:
    # python-legacy converted only immediate list elements or dictionary values:
    # https://github.com/OpenAPITools/openapi-generator/blob/c84b949df1a9ec04ba75989cb49b45c940c2f694/modules/openapi-generator/src/main/resources/python-legacy/model.mustache#L203-L231
    if isinstance(value, list):
        return [_to_legacy_item(item, serialize) for item in value]
    if isinstance(value, dict):
        return {
            key: _to_legacy_item(item, serialize)
            for key, item in value.items()
        }
    return _to_legacy_item(value, serialize)


def _to_openapi_value(value: Any) -> Any:
    if isinstance(value, list):
        return [_to_openapi_value(item) for item in value]
    if isinstance(value, dict):
        return {key: _to_openapi_value(item) for key, item in value.items()}

    to_openapi_dict = _get_openapi_to_dict(value)
    if to_openapi_dict is not None:
        return to_openapi_dict(value)

    to_dict = getattr(value, "to_dict", None)
    if callable(to_dict):
        return to_dict()
    return value


class V1beta1ResourceSliceSpec(BaseModel):
    """
    ResourceSliceSpec contains the information published by the driver in one ResourceSlice.

    Attributes:
      openapi_types (dict): The key is attribute name
                            and the value is attribute type.
      attribute_map (dict): The key is attribute name
                            and the value is json key in definition.
    """ # noqa: E501
    all_nodes: Optional[StrictBool] = Field(default=None, validation_alias=AliasChoices("allNodes", "all_nodes"), serialization_alias="allNodes", description="AllNodes indicates that all nodes have access to the resources in the pool.  Exactly one of NodeName, NodeSelector, AllNodes, and PerDeviceNodeSelection must be set.")
    devices: Optional[List[V1beta1Device]] = Field(default=None, description="Devices lists some or all of the devices in this pool.  Must not have more than 128 entries. If any device uses taints or consumes counters the limit is 64.  Only one of Devices and SharedCounters can be set in a ResourceSlice.")
    driver: StrictStr = Field(description="Driver identifies the DRA driver providing the capacity information. A field selector can be used to list only ResourceSlice objects with a certain driver name.  Must be a DNS subdomain and should end with a DNS domain owned by the vendor of the driver. It should use only lower case characters. This field is immutable.")
    node_name: Optional[StrictStr] = Field(default=None, validation_alias=AliasChoices("nodeName", "node_name"), serialization_alias="nodeName", description="NodeName identifies the node which provides the resources in this pool. A field selector can be used to list only ResourceSlice objects belonging to a certain node.  This field can be used to limit access from nodes to ResourceSlices with the same node name. It also indicates to autoscalers that adding new nodes of the same type as some old node might also make new resources available.  Exactly one of NodeName, NodeSelector, AllNodes, and PerDeviceNodeSelection must be set. This field is immutable.")
    node_selector: Optional[V1NodeSelector] = Field(default=None, validation_alias=AliasChoices("nodeSelector", "node_selector"), serialization_alias="nodeSelector")
    partition_type_attribute: Optional[StrictStr] = Field(default=None, validation_alias=AliasChoices("partitionTypeAttribute", "partition_type_attribute"), serialization_alias="partitionTypeAttribute", description="PartitionTypeAttribute names a string device attribute (by fully qualified name, e.g. \"gpu.example.com/profile\") whose value labels each device with its partition type, such as \"Full\" or \"Half\" for a MIG-style GPU.  When set, every partitionable device in the slice must carry the attribute and devices sharing a value must share the same ConsumesCounters cost.")
    per_device_node_selection: Optional[StrictBool] = Field(default=None, validation_alias=AliasChoices("perDeviceNodeSelection", "per_device_node_selection"), serialization_alias="perDeviceNodeSelection", description="PerDeviceNodeSelection defines whether the access from nodes to resources in the pool is set on the ResourceSlice level or on each device. If it is set to true, every device defined the ResourceSlice must specify this individually.  Exactly one of NodeName, NodeSelector, AllNodes, and PerDeviceNodeSelection must be set.")
    pool: V1beta1ResourcePool
    shared_counters: Optional[List[V1beta1CounterSet]] = Field(default=None, validation_alias=AliasChoices("sharedCounters", "shared_counters"), serialization_alias="sharedCounters", description="SharedCounters defines a list of counter sets, each of which has a name and a list of counters available.  The names of the counter sets must be unique in the ResourcePool.  Only one of Devices and SharedCounters can be set in a ResourceSlice.  The maximum number of counter sets is 8.")
    skip_node_operations: Optional[List[StrictStr]] = Field(default=None, validation_alias=AliasChoices("skipNodeOperations", "skip_node_operations"), serialization_alias="skipNodeOperations", description="SkipNodeOperations lists node-local resource operations (gRPC calls) that will be skipped for the devices in this slice when determining whether operations are necessary on the node. If all allocated devices for a driver in a claim skip an operation, that gRPC call will be skipped. Valid values are:  - \"NodePrepareResources\": NodePrepareResources gRPC calls are skipped. This   value cannot be specified unless \"NodeUnprepareResources\" is also listed   (or \"*\" is specified). - \"NodeUnprepareResources\": NodeUnprepareResources gRPC calls are skipped. - \"*\": All node-local resource operations are skipped.  Other values may be added in the future. The kubelet must ignore unknown values.")
    openapi_types: ClassVar[Dict[str, str]] = {
        "all_nodes": "bool",
        "devices": "List[V1beta1Device]",
        "driver": "str",
        "node_name": "str",
        "node_selector": "V1NodeSelector",
        "partition_type_attribute": "str",
        "per_device_node_selection": "bool",
        "pool": "V1beta1ResourcePool",
        "shared_counters": "List[V1beta1CounterSet]",
        "skip_node_operations": "List[str]"
    }

    attribute_map: ClassVar[Dict[str, str]] = {
        "all_nodes": "allNodes",
        "devices": "devices",
        "driver": "driver",
        "node_name": "nodeName",
        "node_selector": "nodeSelector",
        "partition_type_attribute": "partitionTypeAttribute",
        "per_device_node_selection": "perDeviceNodeSelection",
        "pool": "pool",
        "shared_counters": "sharedCounters",
        "skip_node_operations": "skipNodeOperations"
    }
    __properties: ClassVar[List[str]] = ["allNodes", "devices", "driver", "nodeName", "nodeSelector", "partitionTypeAttribute", "perDeviceNodeSelection", "pool", "sharedCounters", "skipNodeOperations"]

    @classmethod
    def __preprocess_input_names(
        cls,
        obj: Any,
        remove_hidden_storage_names: bool = True,
    ) -> Any:
        if not isinstance(obj, _Mapping):
            return obj
        obj = dict(obj)
        if "allNodes" not in obj and "all_nodes" in obj:
            obj["allNodes"] = obj["all_nodes"]
        obj.pop("all_nodes", None)
        if "nodeName" not in obj and "node_name" in obj:
            obj["nodeName"] = obj["node_name"]
        obj.pop("node_name", None)
        if "nodeSelector" not in obj and "node_selector" in obj:
            obj["nodeSelector"] = obj["node_selector"]
        obj.pop("node_selector", None)
        if "partitionTypeAttribute" not in obj and "partition_type_attribute" in obj:
            obj["partitionTypeAttribute"] = obj["partition_type_attribute"]
        obj.pop("partition_type_attribute", None)
        if "perDeviceNodeSelection" not in obj and "per_device_node_selection" in obj:
            obj["perDeviceNodeSelection"] = obj["per_device_node_selection"]
        obj.pop("per_device_node_selection", None)
        if "sharedCounters" not in obj and "shared_counters" in obj:
            obj["sharedCounters"] = obj["shared_counters"]
        obj.pop("shared_counters", None)
        if "skipNodeOperations" not in obj and "skip_node_operations" in obj:
            obj["skipNodeOperations"] = obj["skip_node_operations"]
        obj.pop("skip_node_operations", None)
        return obj

    model_config = ConfigDict(
        validate_by_name=True,
        validate_by_alias=True,
        validate_assignment=True,
        extra="forbid",
        protected_namespaces=(),
    )


    def to_str(self) -> str:
        """Returns the string representation of the model"""
        return pprint.pformat(self.to_dict())

    def __repr__(self) -> str:
        """For print and pprint"""
        return self.to_str()

    def __eq__(self, other: object) -> bool:
        """Returns true if both objects are equal"""
        if not isinstance(other, V1beta1ResourceSliceSpec):
            return False

        return self.to_dict() == other.to_dict()

    def __ne__(self, other: object) -> bool:
        """Returns true if both objects are not equal"""
        if not isinstance(other, V1beta1ResourceSliceSpec):
            return True

        return not (self == other)


    def to_json(self) -> str:
        """Returns the JSON representation of the model using alias"""
        to_openapi_dict = _get_openapi_to_dict(self)
        if to_openapi_dict is not None:
            return json.dumps(to_jsonable_python(to_openapi_dict(self)))
        return json.dumps(to_jsonable_python(self.to_dict()))

    @classmethod
    def from_json(cls, json_str: str) -> Optional[Self]:
        """Create an instance of V1beta1ResourceSliceSpec from a JSON string"""
        return cls.from_dict(json.loads(json_str))

    def to_dict(self, serialize: bool = False) -> Dict[str, Any]:
        """Return all declared model fields using public or wire names."""
        return {
            ("allNodes" if serialize else "all_nodes"): _to_legacy_value(getattr(self, "all_nodes", None), serialize),
            ("devices" if serialize else "devices"): _to_legacy_value(getattr(self, "devices", None), serialize),
            ("driver" if serialize else "driver"): _to_legacy_value(getattr(self, "driver", None), serialize),
            ("nodeName" if serialize else "node_name"): _to_legacy_value(getattr(self, "node_name", None), serialize),
            ("nodeSelector" if serialize else "node_selector"): _to_legacy_value(getattr(self, "node_selector", None), serialize),
            ("partitionTypeAttribute" if serialize else "partition_type_attribute"): _to_legacy_value(getattr(self, "partition_type_attribute", None), serialize),
            ("perDeviceNodeSelection" if serialize else "per_device_node_selection"): _to_legacy_value(getattr(self, "per_device_node_selection", None), serialize),
            ("pool" if serialize else "pool"): _to_legacy_value(getattr(self, "pool", None), serialize),
            ("sharedCounters" if serialize else "shared_counters"): _to_legacy_value(getattr(self, "shared_counters", None), serialize),
            ("skipNodeOperations" if serialize else "skip_node_operations"): _to_legacy_value(getattr(self, "skip_node_operations", None), serialize),
        }

    def __openapi_generator_modern_projection(self) -> Dict[str, Any]:
        """Return the dictionary representation of the model using alias.

        This has the following differences from calling pydantic's
        `self.model_dump(by_alias=True)`:

        * `None` is only added to the output dict for nullable fields that
          were set at model initialization. Other fields with value `None`
          are ignored.
        """
        excluded_fields: Set[str] = set([
        ])

        _dict = self.model_dump(
            by_alias=True,
            exclude=excluded_fields,
            exclude_none=True,
        )
        # override the default output from pydantic by calling `to_dict()` of each item in devices (list)
        _items = []
        if self.devices:
            for _item_devices in self.devices:
                _items.append(_to_openapi_value(_item_devices) if _item_devices is not None else None)
            _dict['devices'] = _items
        # override the default output from pydantic by calling `to_dict()` of node_selector
        if self.node_selector:
            _dict['nodeSelector'] = _to_openapi_value(self.node_selector)
        # override the default output from pydantic by calling `to_dict()` of pool
        if self.pool:
            _dict['pool'] = _to_openapi_value(self.pool)
        # override the default output from pydantic by calling `to_dict()` of each item in shared_counters (list)
        _items = []
        if self.shared_counters:
            for _item_shared_counters in self.shared_counters:
                _items.append(_to_openapi_value(_item_shared_counters) if _item_shared_counters is not None else None)
            _dict['sharedCounters'] = _items
        return _dict

    setattr(
        to_dict,
        _OPENAPI_GENERATOR_TO_DICT,
        __openapi_generator_modern_projection,
    )
    setattr(
        __openapi_generator_modern_projection,
        _OPENAPI_GENERATOR_TO_DICT,
        to_dict,
    )
    del __openapi_generator_modern_projection

    @classmethod
    def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
        """Create an instance of V1beta1ResourceSliceSpec from a dict"""
        if obj is None:
            return None

        if not isinstance(obj, dict):
            return cls.model_validate(obj)

        obj = _cast(
            Dict[str, Any],
            cls.__preprocess_input_names(
                obj,
                remove_hidden_storage_names=True,
            ),
        )

        _obj = cls.model_validate({
            "allNodes": obj.get("allNodes"),
            "devices": [V1beta1Device.from_dict(_item) for _item in obj["devices"]] if obj.get("devices") is not None else None,
            "driver": obj.get("driver"),
            "nodeName": obj.get("nodeName"),
            "nodeSelector": V1NodeSelector.from_dict(obj["nodeSelector"]) if obj.get("nodeSelector") is not None else None,
            "partitionTypeAttribute": obj.get("partitionTypeAttribute"),
            "perDeviceNodeSelection": obj.get("perDeviceNodeSelection"),
            "pool": V1beta1ResourcePool.from_dict(obj["pool"]) if obj.get("pool") is not None else None,
            "sharedCounters": [V1beta1CounterSet.from_dict(_item) for _item in obj["sharedCounters"]] if obj.get("sharedCounters") is not None else None,
            "skipNodeOperations": obj.get("skipNodeOperations")
        })
        return _obj
