py-client-cap 0.1.7__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.
@@ -0,0 +1,4 @@
1
+ from .crud_php_api import CrudPHPApi
2
+ from .crud_php_table import CrudPHPTable
3
+ from .manager import CrudPHPDB
4
+ from .models import *
@@ -0,0 +1,143 @@
1
+ import requests
2
+ from dataclasses import dataclass, asdict
3
+ from typing import Optional, Dict, Any, List
4
+ from .models import ApiResponse, Item, Column, Table
5
+
6
+ class CrudPHPApi:
7
+ def __init__(self, base_url: str, api_key: Optional[str] = None, timeout: int = 10):
8
+ self.base_url = base_url.rstrip("/")
9
+ self.timeout = timeout
10
+ self.session = requests.Session()
11
+ default_headers = {
12
+ 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36',
13
+ 'Content-Type': 'application/json',
14
+ 'Accept': 'application/json'
15
+ }
16
+ if api_key:
17
+ default_headers['Authorization'] = f"Bearer {api_key}"
18
+ default_headers['X-App-Token'] = api_key
19
+ self.session.headers.update(default_headers)
20
+
21
+ def _request(self, method: str, endpoint: str, data: Optional[Dict] = None, params: Optional[Dict] = None, headers: Optional[Dict] = None) -> ApiResponse:
22
+ url = f"{self.base_url}/{endpoint.lstrip('/')}"
23
+ try:
24
+ kwargs = {
25
+ "method": method.upper(),
26
+ "url": url,
27
+ "json": data,
28
+ "params": params,
29
+ "timeout": self.timeout
30
+ }
31
+ if headers is not None:
32
+ kwargs["headers"] = headers
33
+ res = self.session.request(**kwargs)
34
+ try:
35
+ payload = res.json() if res.content else None
36
+ except ValueError:
37
+ payload = res.text
38
+ if res.ok:
39
+ return ApiResponse(status_code=res.status_code, success=True, data=payload)
40
+ else:
41
+ error_msg = payload.get("message") if isinstance(payload, dict) and "message" in payload else res.text
42
+ return ApiResponse(status_code=res.status_code, success=False, error=error_msg, raw_response=payload)
43
+ except requests.exceptions.RequestException as err:
44
+ return ApiResponse(status_code=0, success=False, error=f"Connection Error: {str(err)}")
45
+
46
+ def create(self, endpoint: str, payload: Dict[str, Any], headers: Optional[Dict] = None) -> ApiResponse:
47
+ return self._request("POST", endpoint, data=payload, headers=headers)
48
+
49
+ def read(self, endpoint: str, item_id: Optional[int] = None, query_params: Optional[Dict] = None, headers: Optional[Dict] = None) -> ApiResponse:
50
+ return self._request("GET", f"{endpoint}/{item_id}" if item_id else endpoint, params=query_params, headers=headers)
51
+
52
+ def update(self, endpoint: str, item_id: int, payload: Dict[str, Any], headers: Optional[Dict] = None) -> ApiResponse:
53
+ return self._request("PUT", f"{endpoint}/{item_id}", data=payload, headers=headers)
54
+
55
+ def delete(self, endpoint: str, item_id: int, headers: Optional[Dict] = None) -> ApiResponse:
56
+ return self._request("DELETE", f"{endpoint}/{item_id}", headers=headers)
57
+
58
+ def export_table_structure(self, openapi_endpoint: str, table_name: str) -> ApiResponse:
59
+ response = self.read(openapi_endpoint)
60
+ if not response.success:
61
+ return response
62
+
63
+ openapi_data = response.data
64
+ if not isinstance(openapi_data, dict):
65
+ return ApiResponse(status_code=400, success=False, error="Invalid OpenAPI response")
66
+
67
+ schemas = openapi_data.get("components", {}).get("schemas", {})
68
+
69
+ table_schema = schemas.get(table_name)
70
+ if not table_schema:
71
+ table_schema = schemas.get(f"read-{table_name}")
72
+ if not table_schema:
73
+ list_schema = schemas.get(f"list-{table_name}")
74
+ if list_schema:
75
+ table_schema = list_schema.get("properties", {}).get("records", {}).get("items", {})
76
+
77
+ if not table_schema or "properties" not in table_schema:
78
+ return ApiResponse(status_code=404, success=False, error=f"Table schema for '{table_name}' not found in OpenAPI specification")
79
+
80
+ properties = table_schema["properties"]
81
+ columns = []
82
+ init_params = []
83
+
84
+ for col_name, col_details in properties.items():
85
+ openapi_type = col_details.get("type", "string")
86
+ type_mapping = {
87
+ "integer": "int",
88
+ "number": "float",
89
+ "boolean": "bool",
90
+ "string": "str"
91
+ }
92
+ py_type = type_mapping.get(openapi_type, "str")
93
+
94
+ default_value = col_details.get("default")
95
+
96
+ if default_value is not None:
97
+ if py_type == "str":
98
+ default_repr = f"'{default_value}'"
99
+ else:
100
+ default_repr = str(default_value)
101
+ init_param = f"{col_name}: {py_type} = {default_repr}"
102
+ else:
103
+ fallback = "''" if py_type == "str" else ("0" if py_type in ["int", "float"] else "False")
104
+ init_param = f"{col_name}: {py_type} = {fallback}"
105
+
106
+ columns.append(Column(name=col_name, data_type=py_type))
107
+ init_params.append(init_param)
108
+
109
+ class_name = f"{table_name.capitalize()}Table"
110
+ class_body = f"class {class_name}:\n"
111
+ for column in columns:
112
+ class_body += f" {column.name}: {column.data_type}\n"
113
+
114
+ class_body += " def __init__(self, " + ', '.join(init_params) + "):\n"
115
+ init_assignments = [f"self.{column.name} = {column.name}" for column in columns]
116
+ class_body += " " + "\n ".join(init_assignments) + "\n"
117
+
118
+ class_body += "\n def to_dict(self) -> Dict[str, Any]:\n"
119
+ class_body += " return {\n"
120
+ for column in columns:
121
+ class_body += f" '{column.name}': self.{column.name},\n"
122
+ class_body += " }"
123
+
124
+ return ApiResponse(status_code=200, success=True, data={
125
+ "class_name": class_name,
126
+ "class_body": class_body
127
+ })
128
+
129
+ def list_tables(self) -> List[str]:
130
+ """Estrae e normalizza la lista univoca di tutte le tabelle dai path OpenAPI."""
131
+ response = self.read('openapi')
132
+
133
+ if not response.success or not isinstance(response.data, dict):
134
+ return []
135
+
136
+ paths = response.data.get("paths", {})
137
+ tables = set()
138
+ for path in paths.keys():
139
+ parts = path.strip("/").split("/")
140
+ if len(parts) >= 2 and parts[0] == "records":
141
+ tables.add(parts[1])
142
+
143
+ return sorted(list(tables))
@@ -0,0 +1,87 @@
1
+ from typing import Optional, Dict, Any, List, Union
2
+ from .models import ApiResponse
3
+ from py_client_cap import CrudPHPApi
4
+
5
+ class CrudPHPTable(CrudPHPApi):
6
+ def __init__(self, base_url: str, table_name: str, api_key: Optional[str] = None, timeout: int = 10):
7
+ super().__init__(base_url=base_url, api_key=api_key, timeout=timeout)
8
+ self.table_name = table_name.strip("/")
9
+ self.last_total_count: Optional[int] = None
10
+
11
+ def _build_table_endpoint(self, action_path: str = "") -> str:
12
+ parts = ["records", self.table_name]
13
+ if action_path:
14
+ parts.append(str(action_path).lstrip("/"))
15
+ return "/".join(parts)
16
+
17
+ def list_rows(
18
+ self,
19
+ filters: Optional[Union[str, List[str]]] = None,
20
+ logic: str = "and", # "and" oppure "or"
21
+ order: Optional[Union[str, List[str]]] = None,
22
+ page: Optional[int] = None,
23
+ size: Optional[int] = None,
24
+ query_params: Optional[Dict[str, Any]] = None,
25
+ headers: Optional[Dict[str, str]] = None
26
+ ) -> ApiResponse:
27
+ endpoint = self._build_table_endpoint()
28
+ params = dict(query_params) if query_params else {}
29
+
30
+ if filters:
31
+ if isinstance(filters, list):
32
+ if logic.lower() == "or":
33
+ for i, f in enumerate(filters, start=1):
34
+ params[f"filter{i}"] = f
35
+ else:
36
+ params["filter[]"] = filters
37
+ else:
38
+ params["filter"] = filters
39
+
40
+ if order:
41
+ if isinstance(order, list):
42
+ params["order[]"] = order
43
+ else:
44
+ params["order"] = order
45
+
46
+ if page is not None:
47
+ params["page"] = page
48
+ if size is not None:
49
+ params["size"] = size
50
+
51
+ response = self._request("GET", endpoint, params=params, headers=headers)
52
+
53
+ # --- PARTE CORRETTA ---
54
+ if response.success and isinstance(response.data, dict):
55
+ # Prima verifica se c'è la chiave metadata "results" (totale assoluto)
56
+ if "results" in response.data:
57
+ self.last_total_count = response.data.get("results")
58
+ else:
59
+ # Fallback: conta i record fisici ricevuti nella pagina
60
+ records = response.data.get("records")
61
+ if isinstance(records, list):
62
+ self.last_total_count = len(records)
63
+ else:
64
+ self.last_total_count = 0
65
+ elif response.success and isinstance(response.data, list):
66
+ self.last_total_count = len(response.data)
67
+
68
+ return response
69
+
70
+ def get_row(self, row_id: Any, query_params: Optional[Dict] = None, headers: Optional[Dict] = None) -> ApiResponse:
71
+ endpoint = self._build_table_endpoint(row_id)
72
+ return self._request("GET", endpoint, params=query_params, headers=headers)
73
+
74
+ def insert_row(self, payload: Dict[str, Any], headers: Optional[Dict] = None) -> ApiResponse:
75
+ endpoint = self._build_table_endpoint()
76
+ return self._request("POST", endpoint, data=payload, headers=headers)
77
+
78
+ def update_row(self, row_id: Any, payload: Dict[str, Any], headers: Optional[Dict] = None) -> ApiResponse:
79
+ endpoint = self._build_table_endpoint(row_id)
80
+ return self._request("PUT", endpoint, data=payload, headers=headers)
81
+
82
+ def delete_row(self, row_id: Any, headers: Optional[Dict] = None) -> ApiResponse:
83
+ endpoint = self._build_table_endpoint(row_id)
84
+ return self._request("DELETE", endpoint, headers=headers)
85
+
86
+ def to_class(self, headers: Optional[Dict] = None) -> ApiResponse:
87
+ return self.export_table_structure('openapi', self.table_name)
@@ -0,0 +1,28 @@
1
+ from typing import List, Optional
2
+ from py_client_cap import CrudPHPApi, CrudPHPTable
3
+
4
+ class CrudPHPDB:
5
+ def __init__(self, base_url: str, api_key: Optional[str] = None, timeout: int = 10):
6
+ self.api = CrudPHPApi(base_url=base_url, api_key=api_key, timeout=timeout)
7
+ self._tables_cache: Optional[List[str]] = None
8
+ self._base_url = base_url
9
+ self._api_key = api_key
10
+ self._timeout = timeout
11
+
12
+ def list_tables(self) -> List[str]:
13
+ if self._tables_cache is None:
14
+ self._tables_cache = self.api.list_tables()
15
+ return self._tables_cache
16
+
17
+ def table(self, table_name: str, raise_if_not_found: bool = False) -> Optional[CrudPHPTable]:
18
+ tables = self.list_tables()
19
+ if table_name not in tables:
20
+ if raise_if_not_found:
21
+ raise KeyError(f"La tabella '{table_name}' non è stata trovata.")
22
+ return None
23
+ return CrudPHPTable(
24
+ base_url=self._base_url,
25
+ table_name=table_name,
26
+ api_key=self._api_key,
27
+ timeout=self._timeout
28
+ )
@@ -0,0 +1,4 @@
1
+ from .item import Item
2
+ from .apiresponse import ApiResponse
3
+ from .column import Column
4
+ from .table import Table
@@ -0,0 +1,18 @@
1
+ from typing import Optional, Dict, Any
2
+ from dataclasses import dataclass, asdict
3
+
4
+ @dataclass
5
+ class ApiResponse:
6
+ status_code: int
7
+ success: bool
8
+ data: Optional[Any] = None
9
+ error: Optional[str] = None
10
+ raw_response: Optional[Dict] = None
11
+
12
+ def to_dict(self) -> Dict[str, Any]:
13
+ return {
14
+ "status_code": self.status_code,
15
+ "success": self.success,
16
+ "data": self.data,
17
+ "error": self.error
18
+ }
@@ -0,0 +1,8 @@
1
+ from dataclasses import dataclass
2
+ from typing import Any, Optional
3
+
4
+ @dataclass
5
+ class Column:
6
+ name: str
7
+ data_type: str
8
+ default: Optional[Any] = None
@@ -0,0 +1,12 @@
1
+ from dataclasses import dataclass, asdict
2
+ from typing import Optional
3
+
4
+ @dataclass
5
+ class Item:
6
+ id: Optional[int] = None
7
+ title: str = ""
8
+ description: str = ""
9
+ status: str = "active"
10
+
11
+ def to_dict(self):
12
+ return {k: v for k, v in asdict(self).items() if v is not None}
@@ -0,0 +1,30 @@
1
+ from dataclasses import dataclass
2
+ from typing import Any, List, Optional
3
+ from .column import Column
4
+
5
+ @dataclass
6
+ class Table:
7
+ name: str
8
+ columns: List[Column]
9
+
10
+ def export_table_structure(self) -> str:
11
+ # Implementazione della funzione per esportare la struttura della tabella
12
+ class_name = f"{self.name.capitalize()}Table"
13
+ class_body = f"class {class_name}:\n"
14
+
15
+ # Aggiungi gli attributi delle colonne
16
+ for column in self.columns:
17
+ class_body += f" {column.name}: {column.data_type}\n"
18
+
19
+ # Aggiungi il metodo per creare un oggetto della tabella
20
+ class_body += " def __init__(self, " + ', '.join([f"{column.name}: {column.data_type}" for column in self.columns]) + "):\n"
21
+ class_body += " self." + ', '.join([f"{column.name} = {column.name}" for column in self.columns])
22
+
23
+ # Aggiungi il metodo per esportare la struttura della tabella
24
+ class_body += "\n def to_dict(self) -> Dict[str, Any]:\n"
25
+ class_body += " return {\n"
26
+ for column in self.columns:
27
+ class_body += f" '{column.name}': self.{column.name},\n"
28
+ class_body += " }"
29
+
30
+ return class_body
@@ -0,0 +1,228 @@
1
+ Metadata-Version: 2.4
2
+ Name: py_client_cap
3
+ Version: 0.1.7
4
+ Summary: Client Python e libreria REST API per la gestione automatizzata di database tramite backend PHP CRUD (codice su Git). Integrazione rapida via HTTP e JSON
5
+ Home-page: https://www.newstechnology.eu
6
+ Author: Daniele Frulla
7
+ Author-email: daniele.frulla@newstechnology.eu
8
+ Keywords: python,php,crud,rest-api,database-manager,git-repo,php-crud-api
9
+ Description-Content-Type: text/markdown
10
+ Requires-Dist: requests==2.34.2
11
+ Dynamic: author
12
+ Dynamic: author-email
13
+ Dynamic: description
14
+ Dynamic: description-content-type
15
+ Dynamic: home-page
16
+ Dynamic: keywords
17
+ Dynamic: requires-dist
18
+ Dynamic: summary
19
+
20
+ # Libreria Python Client CRUD PHP API
21
+
22
+ Questo documento racchiude tutto il necessario per utilizzare la libreria: le istruzioni d'uso (README), il codice sorgente completo e la suite di test unitari con mock.
23
+ Le api che si andranno ad utilizzare sono quelle create con la libreria [PHPCrudApi](https://github.com/mevdschee/php-crud-api)
24
+
25
+ ## Installazione
26
+
27
+ 1. **PIP**:
28
+ ```python
29
+ pip install py_client_cap
30
+ ```
31
+ ## Uso
32
+
33
+ ### 1. Utilizzo della libreria
34
+
35
+ ```python
36
+ from py_client_cap import CrudPHPDB
37
+
38
+ base_url = "http://127.0.0.1:8082/modules/api/index.php"
39
+ api_key = "test-token"
40
+
41
+ db = CrudPHPDB(base_url=base_url, api_key=api_key)
42
+
43
+ # Ritorna le tabelle
44
+ tables = db.list_tables()
45
+
46
+ # Usa le tabelle
47
+ table_client = db.table( 'Tabella1', raise_if_not_found=True)
48
+ response_records = table_client.list_rows(page=1,size=1)
49
+ records_count = table_client.last_total_count
50
+
51
+ #Il totale delle tabelle viene restituito solo se la ricerca e' con page=x
52
+ ```
53
+
54
+ # Gestire le Tabelle
55
+
56
+ ## Classe CrudPHPTable
57
+
58
+ La classe `CrudPHPTable` è stata creata per gestire le operazioni su una tabella PHP API. Questa classe estende la classe base `CrudPHPApi` e aggiunge funzionalità per elencare i record, selezionare un singolo record, inserire un nuovo record, aggiornare un record esistente e eliminare un record.
59
+
60
+ ### Costruttore
61
+
62
+ ```python
63
+ def __init__(self, base_url: str, table_name: str, api_key: Optional[str] = None, timeout: int = 10):
64
+ """
65
+ Inizializza la classe CrudPHPTable.
66
+
67
+ Args:
68
+ base_url (str): URL base del server PHP API.
69
+ table_name (str): Nome della tabella a cui si intende accedere.
70
+ api_key (str, optional): Chiave API per autenticazione. Default è None.
71
+ timeout (int, optional): Timeout per le richieste HTTP. Default è 10.
72
+ """
73
+ ```
74
+
75
+ ### Metodi
76
+
77
+ #### `_build_table_endpoint`
78
+
79
+ ```python
80
+ def _build_table_endpoint(self, action_path: str = "") -> str:
81
+ """
82
+ Costruisce l'endpoint della tabella.
83
+
84
+ Args:
85
+ action_path (str, optional): Percorso di azione specifico. Default è None.
86
+
87
+ Returns:
88
+ str: Endpoint della tabella.
89
+ """
90
+ ```
91
+
92
+ #### `list_rows`
93
+
94
+ ```python
95
+ def list_rows(
96
+ self,
97
+ filters: Optional[Union[str, List[str]]] = None,
98
+ logic: str = "and", # "and" oppure "or"
99
+ order: Optional[Union[str, List[str]]] = None,
100
+ page: Optional[int] = None,
101
+ size: Optional[int] = None,
102
+ query_params: Optional[Dict[str, Any]] = None,
103
+ headers: Optional[Dict[str, str]] = None
104
+ ) -> ApiResponse:
105
+ """
106
+ Effettua una richiesta GET per elencare i record della tabella.
107
+
108
+ Args:
109
+ filters (Union[str, List[str]], optional): Filtro da applicare alle query. Default è None.
110
+ logic (str, optional): Logica di filtre ("and" o "or"). Default è "and".
111
+ order (Union[str, List[str]], optional): Ordinamento delle risposte. Default è None.
112
+ page (int, optional): Pagina di risposta da ottenere. Default è None.
113
+ size (int, optional): Numero di record per pagina. Default è None.
114
+ query_params (Dict[str, Any], optional): Parametri di query. Default è None.
115
+ headers (Dict[str, str], optional): Header HTTP. Default è None.
116
+
117
+ Returns:
118
+ ApiResponse: Risposta della richiesta.
119
+ """
120
+ ```
121
+
122
+ #### `get_row`
123
+
124
+ ```python
125
+ def get_row(self, row_id: Any, query_params: Optional[Dict[str, Any]] = None, headers: Optional[Dict[str, str]] = None) -> ApiResponse:
126
+ """
127
+ Effettua una richiesta GET per selezionare un singolo record della tabella.
128
+
129
+ Args:
130
+ row_id (Any): Identificatore del record.
131
+ query_params (Dict[str, Any], optional): Parametri di query. Default è None.
132
+ headers (Dict[str, str], optional): Header HTTP. Default è None.
133
+
134
+ Returns:
135
+ ApiResponse: Risposta della richiesta.
136
+ """
137
+ ```
138
+
139
+ #### `insert_row`
140
+
141
+ ```python
142
+ def insert_row(self, payload: Dict[str, Any], headers: Optional[Dict[str, str]] = None) -> ApiResponse:
143
+ """
144
+ Effettua una richiesta POST per inserire un nuovo record nella tabella.
145
+
146
+ Args:
147
+ payload (Dict[str, Any]): Payload del nuovo record.
148
+ headers (Dict[str, str], optional): Header HTTP. Default è None.
149
+
150
+ Returns:
151
+ ApiResponse: Risposta della richiesta.
152
+ """
153
+ ```
154
+
155
+ #### `update_row`
156
+
157
+ ```python
158
+ def update_row(self, row_id: Any, payload: Dict[str, Any], headers: Optional[Dict[str, str]] = None) -> ApiResponse:
159
+ """
160
+ Effettua una richiesta PUT per aggiornare un record esistente nella tabella.
161
+
162
+ Args:
163
+ row_id (Any): Identificatore del record.
164
+ payload (Dict[str, Any]): Payload dell'aggiornamento.
165
+ headers (Dict[str, str], optional): Header HTTP. Default è None.
166
+
167
+ Returns:
168
+ ApiResponse: Risposta della richiesta.
169
+ """
170
+ ```
171
+
172
+ #### `delete_row`
173
+
174
+ ```python
175
+ def delete_row(self, row_id: Any, headers: Optional[Dict[str, str]] = None) -> ApiResponse:
176
+ """
177
+ Effettua una richiesta DELETE per eliminare un record dalla tabella.
178
+
179
+ Args:
180
+ row_id (Any): Identificatore del record.
181
+ headers (Dict[str, str], optional): Header HTTP. Default è None.
182
+
183
+ Returns:
184
+ ApiResponse: Risposta della richiesta.
185
+ """
186
+ ```
187
+
188
+ #### `to_class`
189
+
190
+ ```python
191
+ def to_class(self, headers: Optional[Dict] = None) -> ApiResponse:
192
+ """
193
+ Effettua una richiesta GET per esportare la struttura della tabella in formato OpenAPI.
194
+
195
+ Args:
196
+ headers (Dict[str, str], optional): Header HTTP. Default è None.
197
+
198
+ Returns:
199
+ ApiResponse: Risposta della richiesta.
200
+ """
201
+ ```
202
+
203
+ ### Note
204
+
205
+ - L'API REST è gestita automaticamente dalla classe `CrudPHPApi`, che estende `requests.Session`.
206
+ - Il metodo `_build_table_endpoint` costruisce l'endpoint della tabella.
207
+ - I metodi `list_rows`, `get_row`, `insert_row`, `update_row`, `delete_row` effettuano richieste HTTP GET, POST, PUT e DELETE rispettivamente.
208
+ - Il metodo `to_class` effettua una richiesta GET per esportare la struttura della tabella in formato OpenAPI.
209
+ - L'API REST richiede autenticazione tramite una chiave API se specificata.
210
+
211
+ ## Esempio di utilizzo
212
+
213
+ ```python
214
+ # Importazione della classe CrudPHPTable
215
+ from py_client_cap import CrudPHPTable
216
+
217
+ # Configurazione del client
218
+ base_url = "http://example.com/api"
219
+ api_key = "your_api_key_here"
220
+
221
+ # Creazione dell'oggetto CrudPHPTable
222
+ table_client = CrudPHPTable(base_url=base_url, api_key=api_key)
223
+
224
+ # Elenco dei record della tabella
225
+ response = table_client.list_rows()
226
+ print(response)
227
+
228
+ Questo esempio mostra come utilizzare la classe 'CrudPHPTable' per effettuare operazioni di liste e selezione di record su una tabella PHP API.
@@ -0,0 +1,13 @@
1
+ py_client_cap/__init__.py,sha256=RV6Jph8QIp0NHnxj8ykvzZHWs5rG8r1-Y_MfxWYtUkc,160
2
+ py_client_cap/crud_php_api.py,sha256=sNy3uUTuI0IKNw-fhTr5XSpoS6tfcn1CwJ-gqxuOyL4,6661
3
+ py_client_cap/crud_php_table.py,sha256=UERZvDs_tHarWKmRg-qDaiPsddOBNNo3CRShKg4Ub9g,3751
4
+ py_client_cap/manager.py,sha256=FxEQh9tc6N4jFNgOLG0CKALpDd3_B3HyTrPHcCKGtr8,1091
5
+ py_client_cap/models/__init__.py,sha256=aVKe51v5ve_nfsoA1iqGh02pIvqCZ-LJ16paZenHwDY,141
6
+ py_client_cap/models/apiresponse.py,sha256=hsKKa8Y1BNRIPuI8I7ZCgCgzSGM1cvutIa-YlNrFvus,467
7
+ py_client_cap/models/column.py,sha256=Bj1NeWOp0DEojIdD6O4P49--nJX9RgBJXZXKrSckxcQ,160
8
+ py_client_cap/models/item.py,sha256=BAoBlf2RVX1N-fWMd6G1MCvzy34eSXs6uERHKrEvoyY,291
9
+ py_client_cap/models/table.py,sha256=hLUpzcIh3LPUJZ8jkDGaZgDnLfjnDiieJzl1dJQzj2E,1248
10
+ py_client_cap-0.1.7.dist-info/METADATA,sha256=St2xdlEiO6pTkuFYtwjbjOYCb6TQjrDa3pC65-gU5r4,7198
11
+ py_client_cap-0.1.7.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
12
+ py_client_cap-0.1.7.dist-info/top_level.txt,sha256=-0C4bPZLCM4dW6HC_6VrL2WSWXjjeakObCd3sB-_fgI,14
13
+ py_client_cap-0.1.7.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ py_client_cap