enkryptai-sdk 1.0.7__py3-none-any.whl → 1.0.9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
enkryptai_sdk/__init__.py CHANGED
@@ -1,6 +1,7 @@
1
1
  from .evals import EvalsClient
2
2
  from .config import GuardrailsConfig
3
3
  from .guardrails import GuardrailsClient, GuardrailsClientError
4
+ from .coc import CoCClient, CoCClientError
4
5
  from .models import ModelClient, ModelClientError
5
6
  from .red_team import RedTeamClient, RedTeamClientError
6
7
  from .datasets import DatasetClient, DatasetClientError
@@ -11,6 +12,8 @@ __all__ = [
11
12
  "GuardrailsClient",
12
13
  "GuardrailsClientError",
13
14
  "GuardrailsConfig",
15
+ "CoCClient",
16
+ "CoCClientError",
14
17
  "EvalsClient",
15
18
  "ModelClient",
16
19
  "RedTeamClient",
enkryptai_sdk/ai_proxy.py CHANGED
@@ -60,7 +60,7 @@ class AIProxyClient(BaseClient):
60
60
  # # As json.loads is not working with literal string representation of dict
61
61
  # parsed_error = json.loads(error_message.replace("'", '"'))
62
62
  # # Convert Python string representation to proper dict
63
- parsed_error = ast.literal_eval(response["error"])
63
+ parsed_error = ast.literal_eval(f"API Error: {str(response)}")
64
64
  # # Preserve both error and enkrypt_policy_detections fields
65
65
  response["error"] = parsed_error.get("error", parsed_error)
66
66
  if "enkrypt_policy_detections" in parsed_error:
@@ -84,6 +84,6 @@ class AIProxyClient(BaseClient):
84
84
  # Fallback to direct error if error object can't be parsed
85
85
  # print("Failed to parse error response: ", response)
86
86
  return ChatCompletionDirectErrorResponse.from_dict(response)
87
- raise AIProxyClientError(response["error"])
87
+ raise AIProxyClientError(f"API Error: {str(response)}")
88
88
 
89
89
  return ChatCompletionResponse.from_dict(response)
enkryptai_sdk/base.py CHANGED
@@ -11,17 +11,65 @@ class BaseClient:
11
11
  self.http = urllib3.PoolManager()
12
12
  self.headers = {"apikey": self.api_key}
13
13
 
14
- def _request(self, method, endpoint, payload=None, headers=None, **kwargs):
14
+ # def _request(self, method, endpoint, payload=None, headers=None, **kwargs):
15
+ # url = self.base_url + endpoint
16
+ # request_headers = {
17
+ # "Accept-Encoding": "gzip", # Add required gzip encoding
18
+ # **self.headers,
19
+ # }
20
+ # if headers:
21
+ # request_headers.update(headers)
22
+
23
+ # try:
24
+ # response = self.http.request(method, url, headers=request_headers, **kwargs)
25
+
26
+ # if response.status >= 400:
27
+ # error_data = (
28
+ # response.json()
29
+ # if response.data
30
+ # else {"message": f"HTTP {response.status}"}
31
+ # )
32
+ # error_message = error_data.get("message", str(error_data))
33
+ # raise urllib3.exceptions.HTTPError(error_message)
34
+ # return response.json()
35
+ # except urllib3.exceptions.HTTPError as e:
36
+ # return {"error": str(e)}
37
+
38
+ def _request(self, method, endpoint, payload=None, headers=None, form_data=None, **kwargs):
15
39
  url = self.base_url + endpoint
16
40
  request_headers = {
17
- "Accept-Encoding": "gzip", # Add required gzip encoding
41
+ "Accept-Encoding": "gzip",
18
42
  **self.headers,
19
43
  }
20
44
  if headers:
21
45
  request_headers.update(headers)
22
46
 
23
47
  try:
24
- response = self.http.request(method, url, headers=request_headers, **kwargs)
48
+ if form_data:
49
+ # Handle multipart form data
50
+ fields = {}
51
+ for key, value in form_data.items():
52
+ if isinstance(value, tuple):
53
+ # Handle file upload tuple (filename, content, content_type)
54
+ filename, file_data, content_type = value
55
+ fields[key] = (filename, file_data, content_type)
56
+ else:
57
+ fields[key] = value
58
+
59
+ response = self.http.request(
60
+ method,
61
+ url,
62
+ headers=request_headers,
63
+ fields=fields,
64
+ **kwargs
65
+ )
66
+ else:
67
+ response = self.http.request(
68
+ method,
69
+ url,
70
+ headers=request_headers,
71
+ **kwargs
72
+ )
25
73
 
26
74
  if response.status >= 400:
27
75
  error_data = (
@@ -34,3 +82,4 @@ class BaseClient:
34
82
  return response.json()
35
83
  except urllib3.exceptions.HTTPError as e:
36
84
  return {"error": str(e)}
85
+
enkryptai_sdk/coc.py ADDED
@@ -0,0 +1,203 @@
1
+ import os
2
+ # import requests
3
+ from .base import BaseClient
4
+ from .dto import (
5
+ CoCPolicyData,
6
+ CoCPolicyResponse,
7
+ CoCDeletePolicyResponse,
8
+ CoCListPoliciesResponse,
9
+ )
10
+
11
+
12
+ class CoCClientError(Exception):
13
+ """
14
+ A custom exception for CoCClient errors.
15
+ """
16
+
17
+ pass
18
+
19
+
20
+ class CoCClient(BaseClient):
21
+ """
22
+ A client for interacting with Enkrypt AI CoC API endpoints.
23
+ """
24
+ def __init__(self, api_key: str, base_url: str = "https://api.enkryptai.com:443"):
25
+ super().__init__(api_key, base_url)
26
+
27
+ def add_policy(self, policy_name, policy_rules=None, total_rules=None, policy_file=None, policy_text=None):
28
+ """
29
+ Create a new policy with policy_rules.
30
+
31
+ Parameters:
32
+ - policy_name (str): Name of the policy
33
+ - policy_rules (List or Str): List of rules for the policy
34
+ - total_rules (int): Total number of rules
35
+ - policy_file (str, optional): Path to the policy file (PDF)
36
+ - policy_text (str, optional): Policy text content
37
+
38
+ Returns:
39
+ - CoCPolicyResponse
40
+
41
+ Raises:
42
+ - CoCClientError: If validation fails or API returns an error
43
+ """
44
+ try:
45
+ if not policy_file and not policy_text:
46
+ raise CoCClientError("Must provide either policy_file or policy_text")
47
+ if policy_file and policy_text:
48
+ raise CoCClientError("Cannot provide both policy_file and policy_text")
49
+
50
+ if isinstance(policy_rules, list):
51
+ policy_rules = "\n".join(policy_rules)
52
+ elif isinstance(policy_rules, str):
53
+ policy_rules = policy_rules.strip()
54
+ else:
55
+ raise CoCClientError("policy_rules must be a string or list of strings")
56
+
57
+ form_data = {
58
+ 'name': policy_name,
59
+ 'policy_rules': policy_rules,
60
+ 'total_rules': total_rules
61
+ }
62
+
63
+ if policy_file:
64
+ # Normalize file path and check existence
65
+ file_path = os.path.abspath(policy_file)
66
+ file_name = os.path.basename(file_path)
67
+
68
+ if not os.path.exists(file_path):
69
+ raise CoCClientError(f"File not found: {file_path}")
70
+
71
+ # Check file extension
72
+ if not file_path.lower().endswith('.pdf'):
73
+ raise CoCClientError("Only PDF files are supported")
74
+
75
+ with open(file_path, 'rb') as f:
76
+ file_content = f.read()
77
+ form_data['policy_file'] = (file_name, file_content, 'application/pdf')
78
+ else:
79
+ form_data['policy_text'] = policy_text
80
+
81
+ response = self._request(
82
+ "POST",
83
+ "/code-of-conduct/add-policy",
84
+ form_data=form_data
85
+ )
86
+
87
+ if isinstance(response, dict) and response.get("error"):
88
+ raise CoCClientError(f"API Error: {str(response)}")
89
+
90
+ return CoCPolicyResponse.from_dict(response)
91
+ except Exception as e:
92
+ raise CoCClientError(str(e))
93
+
94
+ def get_policy(self, policy_name):
95
+ """
96
+ Retrieve an existing policy by providing its header identifier.
97
+ """
98
+ headers = {"X-Enkrypt-Policy": policy_name}
99
+
100
+ try:
101
+ response = self._request("GET", "/code-of-conduct/get-policy", headers=headers)
102
+ if response.get("error"):
103
+ raise CoCClientError(f"API Error: {str(response)}")
104
+ return CoCPolicyData.from_dict(response)
105
+ except Exception as e:
106
+ raise CoCClientError(str(e))
107
+
108
+ def modify_policy(self, policy_name, policy_rules=None, total_rules=None, policy_file=None, policy_text=None):
109
+ """
110
+ Modify a policy with policy_rules.
111
+
112
+ Parameters:
113
+ - policy_name (str): Name of the policy
114
+ - policy_rules (List or Str): List of rules for the policy
115
+ - total_rules (int): Total number of rules
116
+ - policy_file (str, optional): Path to the policy file (PDF)
117
+ - policy_text (str, optional): Policy text content
118
+
119
+ Returns:
120
+ - CoCPolicyResponse
121
+
122
+ Raises:
123
+ - CoCClientError: If validation fails or API returns an error
124
+ """
125
+ try:
126
+ if not policy_file and not policy_text:
127
+ raise CoCClientError("Must provide either policy_file or policy_text")
128
+ if policy_file and policy_text:
129
+ raise CoCClientError("Cannot provide both policy_file and policy_text")
130
+
131
+ if isinstance(policy_rules, list):
132
+ policy_rules = "\n".join(policy_rules)
133
+ elif isinstance(policy_rules, str):
134
+ policy_rules = policy_rules.strip()
135
+ else:
136
+ raise CoCClientError("policy_rules must be a string or list of strings")
137
+
138
+ form_data = {
139
+ 'name': policy_name,
140
+ 'policy_rules': policy_rules,
141
+ 'total_rules': total_rules
142
+ }
143
+
144
+ if policy_file:
145
+ # Normalize file path and check existence
146
+ file_path = os.path.abspath(policy_file)
147
+ file_name = os.path.basename(file_path)
148
+
149
+ if not os.path.exists(file_path):
150
+ raise CoCClientError(f"File not found: {file_path}")
151
+
152
+ # Check file extension
153
+ if not file_path.lower().endswith('.pdf'):
154
+ raise CoCClientError("Only PDF files are supported")
155
+
156
+ with open(file_path, 'rb') as f:
157
+ file_content = f.read()
158
+ form_data['policy_file'] = (file_name, file_content, 'application/pdf')
159
+ else:
160
+ form_data['policy_text'] = policy_text
161
+
162
+ headers = {"X-Enkrypt-Policy": policy_name}
163
+
164
+ response = self._request(
165
+ "PATCH",
166
+ "/code-of-conduct/modify-policy",
167
+ form_data=form_data,
168
+ headers=headers
169
+ )
170
+
171
+ if isinstance(response, dict) and response.get("error"):
172
+ raise CoCClientError(f"API Error: {str(response)}")
173
+
174
+ return CoCPolicyResponse.from_dict(response)
175
+ except Exception as e:
176
+ raise CoCClientError(str(e))
177
+
178
+ def delete_policy(self, policy_name):
179
+ """
180
+ Delete a policy.
181
+ """
182
+ headers = {"X-Enkrypt-Policy": policy_name}
183
+
184
+ try:
185
+ response = self._request("DELETE", "/code-of-conduct/delete-policy", headers=headers)
186
+ if response.get("error"):
187
+ raise CoCClientError(f"API Error: {str(response)}")
188
+ return CoCDeletePolicyResponse.from_dict(response)
189
+ except Exception as e:
190
+ raise CoCClientError(str(e))
191
+
192
+ def get_policy_list(self):
193
+ """
194
+ List all policies.
195
+ """
196
+
197
+ try:
198
+ response = self._request("GET", "/code-of-conduct/list-policies")
199
+ if isinstance(response, dict) and response.get("error"):
200
+ raise CoCClientError(f"API Error: {str(response)}")
201
+ return CoCListPoliciesResponse.from_dict(response)
202
+ except Exception as e:
203
+ raise CoCClientError(str(e))
enkryptai_sdk/datasets.py CHANGED
@@ -19,6 +19,32 @@ class DatasetClient(BaseClient):
19
19
  def __init__(self, api_key: str, base_url: str = "https://api.enkryptai.com"):
20
20
  super().__init__(api_key, base_url)
21
21
 
22
+ @staticmethod
23
+ def prepare_dataset_payload(config: DatasetConfig | dict, is_custom: bool = False) -> dict:
24
+ """
25
+ Prepare the payload for dataset operations from a config object.
26
+
27
+ Args:
28
+ config (Union[DatasetConfig, dict]): Configuration object or dictionary containing dataset details
29
+
30
+ Returns:
31
+ dict: Processed payload ready for API submission
32
+ """
33
+ if isinstance(config, dict):
34
+ config = DatasetConfig.from_dict(config)
35
+
36
+ payload = config.to_dict()
37
+
38
+ if not is_custom:
39
+ # Remove empty tools configuration
40
+ if (payload.get("tools") is None or
41
+ payload["tools"] == [] or
42
+ payload["tools"] == [{}] or
43
+ payload["tools"] == [{"name": "", "description": ""}]):
44
+ del payload["tools"]
45
+
46
+ return payload
47
+
22
48
  def add_dataset(self, config: DatasetConfig):
23
49
  """
24
50
  Add a new dataset to the system.
@@ -34,14 +60,7 @@ class DatasetClient(BaseClient):
34
60
  if isinstance(config, dict):
35
61
  config = DatasetConfig.from_dict(config)
36
62
 
37
- payload = config.to_dict()
38
-
39
- # If payload["tools"] is None or is an empty list [] or [{}], remove it from the payload
40
- if (payload.get("tools") is None or
41
- payload["tools"] == [] or
42
- payload["tools"] == [{}] or
43
- payload["tools"] == [{"name": "", "description": ""}]):
44
- del payload["tools"]
63
+ payload = self.prepare_dataset_payload(config)
45
64
 
46
65
  # Print payload
47
66
  # print(f"\nAdd Dataset Payload: {payload}")
@@ -54,7 +73,7 @@ class DatasetClient(BaseClient):
54
73
  # print(f"\nAdd Dataset Response: {response}")
55
74
 
56
75
  if response.get("error"):
57
- raise DatasetClientError(response["error"])
76
+ raise DatasetClientError(f"API Error: {str(response)}")
58
77
  return DatasetAddTaskResponse.from_dict(response)
59
78
 
60
79
  def get_dataset_task_status(self, dataset_name: str):
@@ -70,7 +89,7 @@ class DatasetClient(BaseClient):
70
89
  headers = {"X-Enkrypt-Dataset": dataset_name}
71
90
  response = self._request("GET", "/datasets/task-status", headers=headers)
72
91
  if response.get("error"):
73
- raise DatasetClientError(response["error"])
92
+ raise DatasetClientError(f"API Error: {str(response)}")
74
93
  response["dataset_name"] = dataset_name
75
94
  return DatasetTaskStatus.from_dict(response)
76
95
 
@@ -87,7 +106,7 @@ class DatasetClient(BaseClient):
87
106
  headers = {"X-Enkrypt-Dataset": dataset_name}
88
107
  response = self._request("GET", "/datasets/get-task", headers=headers)
89
108
  if response.get("error"):
90
- raise DatasetClientError(response["error"])
109
+ raise DatasetClientError(f"API Error: {str(response)}")
91
110
  response["dataset_name"] = dataset_name
92
111
  return DatasetTask.from_dict(response)
93
112
 
@@ -104,7 +123,7 @@ class DatasetClient(BaseClient):
104
123
  headers = {"X-Enkrypt-Dataset": dataset_name}
105
124
  response = self._request("GET", "/datasets/get-datacard", headers=headers)
106
125
  if response.get("error"):
107
- raise DatasetClientError(response["error"])
126
+ raise DatasetClientError(f"API Error: {str(response)}")
108
127
  response["dataset_name"] = dataset_name
109
128
  return DatasetCard.from_dict(response)
110
129
 
@@ -121,7 +140,7 @@ class DatasetClient(BaseClient):
121
140
  headers = {"X-Enkrypt-Dataset": dataset_name}
122
141
  response = self._request("GET", "/datasets/get-dataset", headers=headers)
123
142
  if response.get("error"):
124
- raise DatasetClientError(response["error"])
143
+ raise DatasetClientError(f"API Error: {str(response)}")
125
144
  response["dataset_name"] = dataset_name
126
145
  return DatasetResponse.from_dict(response)
127
146
 
@@ -138,7 +157,7 @@ class DatasetClient(BaseClient):
138
157
  headers = {"X-Enkrypt-Dataset": dataset_name}
139
158
  response = self._request("GET", "/datasets/get-summary", headers=headers)
140
159
  if response.get("error"):
141
- raise DatasetClientError(response["error"])
160
+ raise DatasetClientError(f"API Error: {str(response)}")
142
161
  response["dataset_name"] = dataset_name
143
162
  return DatasetSummary.from_dict(response)
144
163
 
@@ -158,5 +177,5 @@ class DatasetClient(BaseClient):
158
177
  url += f"?status={status}"
159
178
  response = self._request("GET", url)
160
179
  if response.get("error"):
161
- raise DatasetClientError(response["error"])
180
+ raise DatasetClientError(f"API Error: {str(response)}")
162
181
  return DatasetCollection.from_dict(response)
@@ -46,7 +46,7 @@ class DeploymentClient(BaseClient):
46
46
  "POST", "/deployments/add-deployment", headers=headers, json=payload
47
47
  )
48
48
  if response.get("error"):
49
- raise DeploymentClientError(response["error"])
49
+ raise DeploymentClientError(f"API Error: {str(response)}")
50
50
  return DeploymentAddTaskResponse.from_dict(response)
51
51
 
52
52
  def get_deployment(self, deployment_name: str, refresh_cache: bool = False):
@@ -64,7 +64,7 @@ class DeploymentClient(BaseClient):
64
64
  headers["X-Enkrypt-Refresh-Cache"] = "true" if refresh_cache else "false"
65
65
  response = self._request("GET", "/deployments/get-deployment", headers=headers)
66
66
  if response.get("error"):
67
- raise DeploymentClientError(response["error"])
67
+ raise DeploymentClientError(f"API Error: {str(response)}")
68
68
  return GetDeploymentResponse.from_dict(response)
69
69
 
70
70
  def modify_deployment(self, deployment_name: str, config: DeploymentInput):
@@ -88,7 +88,7 @@ class DeploymentClient(BaseClient):
88
88
  "PATCH", "/deployments/modify-deployment", headers=headers, json=payload
89
89
  )
90
90
  if response.get("error"):
91
- raise DeploymentClientError(response["error"])
91
+ raise DeploymentClientError(f"API Error: {str(response)}")
92
92
  return ModifyDeploymentResponse.from_dict(response)
93
93
 
94
94
  def delete_deployment(self, deployment_name: str):
@@ -104,7 +104,7 @@ class DeploymentClient(BaseClient):
104
104
  headers = {"X-Enkrypt-Deployment": deployment_name}
105
105
  response = self._request("DELETE", "/deployments/delete-deployment", headers=headers)
106
106
  if response.get("error"):
107
- raise DeploymentClientError(response["error"])
107
+ raise DeploymentClientError(f"API Error: {str(response)}")
108
108
  return DeleteDeploymentResponse.from_dict(response)
109
109
 
110
110
  def list_deployments(self):
@@ -117,5 +117,5 @@ class DeploymentClient(BaseClient):
117
117
 
118
118
  response = self._request("GET", "/deployments/list-deployments")
119
119
  if response.get("error"):
120
- raise DeploymentClientError(response["error"])
120
+ raise DeploymentClientError(f"API Error: {str(response)}")
121
121
  return DeploymentCollection.from_dict(response)
@@ -4,6 +4,7 @@ from .datasets import *
4
4
  from .deployments import *
5
5
  from .ai_proxy import *
6
6
  from .guardrails import *
7
+ from .coc import *
7
8
 
8
9
 
9
10
  __all__ = [
@@ -22,6 +23,8 @@ __all__ = [
22
23
  "Metadata",
23
24
  "DEFAULT_REDTEAM_CONFIG",
24
25
  "DEFAULT_REDTEAM_CONFIG_WITH_SAVED_MODEL",
26
+ "DEFAULT_CUSTOM_REDTEAM_CONFIG",
27
+ "DEFAULT_CUSTOM_REDTEAM_CONFIG_WITH_SAVED_MODEL",
25
28
  "ADVANCED_REDTEAM_TESTS",
26
29
  "DETAIL_MODEL_CONFIG",
27
30
  "DatasetConfig",
@@ -79,8 +82,16 @@ __all__ = [
79
82
  "GuardrailsRelevancyResponse",
80
83
  "GuardrailsPolicyRequest",
81
84
  "GuardrailsPolicyData",
82
- "GuardrailsaPolicyResponse",
85
+ "GuardrailsPolicyResponse",
83
86
  "GuardrailsDeletePolicyData",
84
87
  "GuardrailsDeletePolicyResponse",
85
88
  "GuardrailsListPoliciesResponse",
89
+ "GuardrailsPolicyAtomizerRequest",
90
+ "GuardrailsPolicyAtomizerResponse",
91
+ "CoCPolicyRequest",
92
+ "CoCPolicyData",
93
+ "CoCPolicyResponse",
94
+ "CoCDeletePolicyData",
95
+ "CoCDeletePolicyResponse",
96
+ "CoCListPoliciesResponse",
86
97
  ]
@@ -0,0 +1,159 @@
1
+ from enum import Enum
2
+ from .base import BaseDTO
3
+ from dataclasses import dataclass, field
4
+ from typing import List, Dict, Any, Set, Optional, BinaryIO
5
+
6
+
7
+ @dataclass
8
+ class CoCPolicyData(BaseDTO):
9
+ created_at: str
10
+ name: str
11
+ updated_at: str
12
+ policy_id: int
13
+ project_name: str = "default"
14
+ policy_rules: str = ""
15
+ total_rules: int = 0
16
+ pdf_name: str = ""
17
+ _extra_fields: Dict[str, Any] = field(default_factory=dict)
18
+
19
+ @classmethod
20
+ def from_dict(cls, data: Dict[str, Any]) -> "CoCPolicyData":
21
+ return cls(
22
+ created_at=data.get("created_at", ""),
23
+ name=data.get("name", ""),
24
+ updated_at=data.get("updated_at", ""),
25
+ policy_id=data.get("policy_id", 0),
26
+ project_name=data.get("project_name", "default"),
27
+ policy_rules=data.get("policy_rules", ""),
28
+ total_rules=data.get("total_rules", 0),
29
+ pdf_name=data.get("pdf_name", "")
30
+ )
31
+
32
+ def to_dict(self) -> Dict[str, Any]:
33
+ result = {
34
+ "created_at": self.created_at,
35
+ "name": self.name,
36
+ "updated_at": self.updated_at,
37
+ "policy_id": self.policy_id,
38
+ "project_name": self.project_name,
39
+ "policy_rules": self.policy_rules,
40
+ "total_rules": self.total_rules,
41
+ "pdf_name": self.pdf_name
42
+ }
43
+ result.update(self._extra_fields)
44
+ return result
45
+
46
+ def get_rules_list(self) -> List[str]:
47
+ """
48
+ Get the policy rules as a list of strings.
49
+
50
+ Returns:
51
+ List[str]: List of individual policy rules
52
+ """
53
+ if not self.policy_rules:
54
+ return []
55
+ return [rule.strip() for rule in self.policy_rules.split('\n') if rule.strip()]
56
+
57
+ def __str__(self) -> str:
58
+ """
59
+ String representation of the response.
60
+
61
+ Returns:
62
+ str: A formatted string
63
+ """
64
+ return (
65
+ f"Policy Name: {self.name}\n"
66
+ f"Created At: {self.created_at}\n"
67
+ f"Updated At: {self.updated_at}\n"
68
+ f"Policy ID: {self.policy_id}\n"
69
+ f"total_rules: {self.total_rules}\n"
70
+ )
71
+
72
+
73
+ @dataclass
74
+ class CoCPolicyResponse(BaseDTO):
75
+ message: str
76
+ data: CoCPolicyData
77
+ _extra_fields: Dict[str, Any] = field(default_factory=dict)
78
+
79
+ @classmethod
80
+ def from_dict(cls, data: Dict[str, Any]) -> "CoCPolicyResponse":
81
+ policy_data = data.get("data", {})
82
+ return cls(
83
+ message=data.get("message", ""),
84
+ data=CoCPolicyData.from_dict(policy_data)
85
+ )
86
+
87
+ def to_dict(self) -> Dict[str, Any]:
88
+ result = {
89
+ "message": self.message,
90
+ "data": self.data.to_dict()
91
+ }
92
+ result.update(self._extra_fields)
93
+ return result
94
+
95
+
96
+ @dataclass
97
+ class CoCDeletePolicyData(BaseDTO):
98
+ policy_id: int
99
+ project_name: str = ""
100
+ _extra_fields: Dict[str, Any] = field(default_factory=dict)
101
+
102
+ @classmethod
103
+ def from_dict(cls, data: Dict[str, Any]) -> "CoCDeletePolicyData":
104
+ return cls(
105
+ policy_id=data.get("policy_id", 0),
106
+ project_name=data.get("project_name", "")
107
+ )
108
+
109
+ def to_dict(self) -> Dict[str, Any]:
110
+ result = {
111
+ "policy_id": self.policy_id,
112
+ "project_name": self.project
113
+ }
114
+ result.update(self._extra_fields)
115
+ return result
116
+
117
+
118
+ @dataclass
119
+ class CoCDeletePolicyResponse(BaseDTO):
120
+ message: str
121
+ data: CoCDeletePolicyData
122
+ _extra_fields: Dict[str, Any] = field(default_factory=dict)
123
+
124
+ @classmethod
125
+ def from_dict(cls, data: Dict[str, Any]) -> "CoCDeletePolicyResponse":
126
+ policy_data = data.get("data", {})
127
+ return cls(
128
+ message=data.get("message", ""),
129
+ data=CoCDeletePolicyData.from_dict(policy_data)
130
+ )
131
+
132
+ def to_dict(self) -> Dict[str, Any]:
133
+ result = {
134
+ "message": self.message,
135
+ "data": self.data.to_dict()
136
+ }
137
+ result.update(self._extra_fields)
138
+ return result
139
+
140
+
141
+ @dataclass
142
+ class CoCListPoliciesResponse(BaseDTO):
143
+ policies: List[CoCPolicyData] = field(default_factory=list)
144
+ _extra_fields: Dict[str, Any] = field(default_factory=dict)
145
+
146
+ @classmethod
147
+ def from_dict(cls, data: Dict[str, Any]) -> "CoCListPoliciesResponse":
148
+ policies_data = data.get("policies", [])
149
+ return cls(
150
+ policies=[CoCPolicyData.from_dict(policy) for policy in policies_data]
151
+ )
152
+
153
+ def to_dict(self) -> Dict[str, Any]:
154
+ result = {
155
+ "policies": [policy.to_dict() for policy in self.policies]
156
+ }
157
+ result.update(self._extra_fields)
158
+ return result
159
+