pam-python 0.1.15__tar.gz → 0.1.17__tar.gz

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.
Files changed (35) hide show
  1. {pam_python-0.1.15 → pam_python-0.1.17}/PKG-INFO +3 -2
  2. {pam_python-0.1.15 → pam_python-0.1.17}/pam/api.py +37 -3
  3. {pam_python-0.1.15 → pam_python-0.1.17}/pam/models/request_command.py +8 -0
  4. {pam_python-0.1.15 → pam_python-0.1.17}/pam/service.py +64 -0
  5. {pam_python-0.1.15 → pam_python-0.1.17}/pam/tester_task.py +2 -0
  6. {pam_python-0.1.15 → pam_python-0.1.17}/pam_python.egg-info/PKG-INFO +3 -2
  7. {pam_python-0.1.15 → pam_python-0.1.17}/setup.py +1 -1
  8. {pam_python-0.1.15 → pam_python-0.1.17}/LICENSE.txt +0 -0
  9. {pam_python-0.1.15 → pam_python-0.1.17}/README.md +0 -0
  10. {pam_python-0.1.15 → pam_python-0.1.17}/pam/__init__.py +0 -0
  11. {pam_python-0.1.15 → pam_python-0.1.17}/pam/cli.py +0 -0
  12. {pam_python-0.1.15 → pam_python-0.1.17}/pam/interface_task_manager.py +0 -0
  13. {pam_python-0.1.15 → pam_python-0.1.17}/pam/models/__init__.py +0 -0
  14. {pam_python-0.1.15 → pam_python-0.1.17}/pam/server.py +0 -0
  15. {pam_python-0.1.15 → pam_python-0.1.17}/pam/task_manager.py +0 -0
  16. {pam_python-0.1.15 → pam_python-0.1.17}/pam/temp_file_utils.py +0 -0
  17. {pam_python-0.1.15 → pam_python-0.1.17}/pam/templates/buildcmd/pamb +0 -0
  18. {pam_python-0.1.15 → pam_python-0.1.17}/pam/templates/buildcmd/pamb-base.sh +0 -0
  19. {pam_python-0.1.15 → pam_python-0.1.17}/pam/templates/docker/Dockerfile +0 -0
  20. {pam_python-0.1.15 → pam_python-0.1.17}/pam/templates/init/dockerignore.tmpl +0 -0
  21. {pam_python-0.1.15 → pam_python-0.1.17}/pam/templates/init/gitignore.tmpl +0 -0
  22. {pam_python-0.1.15 → pam_python-0.1.17}/pam/templates/init/main.tmpl +0 -0
  23. {pam_python-0.1.15 → pam_python-0.1.17}/pam/templates/init/pylintrc.tmpl +0 -0
  24. {pam_python-0.1.15 → pam_python-0.1.17}/pam/templates/init/run_test.sh +0 -0
  25. {pam_python-0.1.15 → pam_python-0.1.17}/pam/templates/service/functions.tmpl +0 -0
  26. {pam_python-0.1.15 → pam_python-0.1.17}/pam/templates/service/service.test.tmpl +0 -0
  27. {pam_python-0.1.15 → pam_python-0.1.17}/pam/templates/service/service.yaml +0 -0
  28. {pam_python-0.1.15 → pam_python-0.1.17}/pam/templates/service/service_class.tmpl +0 -0
  29. {pam_python-0.1.15 → pam_python-0.1.17}/pam/utils.py +0 -0
  30. {pam_python-0.1.15 → pam_python-0.1.17}/pam_python.egg-info/SOURCES.txt +0 -0
  31. {pam_python-0.1.15 → pam_python-0.1.17}/pam_python.egg-info/dependency_links.txt +0 -0
  32. {pam_python-0.1.15 → pam_python-0.1.17}/pam_python.egg-info/entry_points.txt +0 -0
  33. {pam_python-0.1.15 → pam_python-0.1.17}/pam_python.egg-info/requires.txt +0 -0
  34. {pam_python-0.1.15 → pam_python-0.1.17}/pam_python.egg-info/top_level.txt +0 -0
  35. {pam_python-0.1.15 → pam_python-0.1.17}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: pam-python
3
- Version: 0.1.15
3
+ Version: 0.1.17
4
4
  Summary: Pam Python Library
5
5
  Home-page: https://github.com/heart/pam-python
6
6
  Author: Narongrit Kanhanoi
@@ -32,6 +32,7 @@ Dynamic: classifier
32
32
  Dynamic: description
33
33
  Dynamic: description-content-type
34
34
  Dynamic: home-page
35
+ Dynamic: license-file
35
36
  Dynamic: requires-dist
36
37
  Dynamic: requires-python
37
38
  Dynamic: summary
@@ -26,12 +26,13 @@ class API:
26
26
  log(f"HTTP POST request failed. URL: {url}, Error: {e}")
27
27
  return None
28
28
 
29
- def http_upload(self, url: str, file_path: str) -> requests.Response | None:
29
+ def http_upload(self, url: str, file_path: str, payload: dict = None) -> requests.Response | None:
30
30
  """
31
- Uploads a file to the specified URL.
31
+ Uploads a file to the specified URL with optional form data (payload).
32
32
 
33
33
  :param url: The URL to upload the file to.
34
34
  :param file_path: The path to the file to be uploaded.
35
+ :param payload: Optional dictionary of form fields to include in the request.
35
36
  :return: The response from the server, or None if an error occurred.
36
37
  """
37
38
  if not Path(file_path).is_file():
@@ -41,13 +42,46 @@ class API:
41
42
  try:
42
43
  with open(file_path, 'rb') as file:
43
44
  files = {'file': file}
44
- response = self.session.post(url, files=files, timeout=300)
45
+ response = self.session.post(
46
+ url,
47
+ files=files,
48
+ data=payload or {}, # optional form data
49
+ timeout=300
50
+ )
45
51
  response.raise_for_status()
46
52
  return response
47
53
  except requests.RequestException as e:
48
54
  log(f"File upload failed. URL: {url}, File: {file_path}, Error: {e}")
49
55
  return None
50
56
 
57
+ def download_sqlite_from_post(self, url: str, data: dict, output_path: str) -> bool:
58
+ """
59
+ Sends a POST request with JSON data and expects a SQLite file in response.
60
+ Saves the response content as a .sqlite file.
61
+
62
+ :param url: The URL to send the POST request to.
63
+ :param data: Dictionary to send as JSON in the body.
64
+ :param output_path: File path to save the .sqlite file.
65
+ :return: True if successful, False otherwise.
66
+ """
67
+ headers = {'Content-Type': 'application/json'}
68
+ try:
69
+ response = self.session.post(url, json=data, timeout=60, headers=headers)
70
+ response.raise_for_status()
71
+
72
+ # Save response content to file
73
+ with open(output_path, "wb") as f:
74
+ f.write(response.content)
75
+
76
+ log(f"SQLite file saved to {output_path}")
77
+ return True
78
+ except requests.RequestException as e:
79
+ log(f"Failed to download SQLite. URL: {url}, Error: {e}")
80
+ return False
81
+ except IOError as e:
82
+ log(f"Failed to save SQLite file. Path: {output_path}, Error: {e}")
83
+ return False
84
+
51
85
  def close(self):
52
86
  """Close the session."""
53
87
  self.session.close()
@@ -31,6 +31,8 @@ class RequestCommand:
31
31
  """
32
32
  Wraps an HTTP request to simplify access to its parameters and files.
33
33
  """
34
+ sqlite_download: str
35
+ sqlite_upload: str
34
36
  runtime_parameters: dict
35
37
  token: str
36
38
  cmd: str
@@ -129,6 +131,10 @@ class RequestCommand:
129
131
  token = params.pop("token", "")
130
132
  cmd = params.pop("cmd", "")
131
133
  data_api = params.pop("data", "")
134
+
135
+ sqlite_upload = params.pop("sqlite_upload", "")
136
+ sqlite_download = params.pop("sqlite_download", "")
137
+
132
138
  response_api = params.pop("response", "")
133
139
  is_end = RequestCommand.__safe_str_to_bool(params.pop("is_end", "true"))
134
140
  next_page = params.pop("next", "")
@@ -148,6 +154,8 @@ class RequestCommand:
148
154
  )
149
155
 
150
156
  return RequestCommand(
157
+ sqlite_download=sqlite_download,
158
+ sqlite_upload=sqlite_upload,
151
159
  runtime_parameters=params,
152
160
  token=token,
153
161
  cmd=cmd,
@@ -1,4 +1,5 @@
1
1
  from abc import abstractmethod
2
+ from pathlib import Path
2
3
  import json
3
4
  from typing import TYPE_CHECKING, Union
4
5
  import pandas as pd
@@ -94,6 +95,69 @@ class Service:
94
95
  raise
95
96
 
96
97
  return report_csv_path
98
+
99
+ def _request_sqlite(self, file_name: str = "", is_shared: bool = False) -> None:
100
+ """Requests last sqlite file that this plugin has uploaded from the last time."""
101
+ log(f"{self.request.service_name}: Requesting sqlite for file_name={file_name}")
102
+
103
+ endpoint = self.request.sqlite_download
104
+ token = self.request.token
105
+ json_data = {"file_name": file_name, "is_shared": is_shared, "token": token}
106
+
107
+ # Create a temp file path for the downloaded .sqlite file
108
+ output_path = TempfileUtils.get_temp_file_name(
109
+ self.request.service_name,
110
+ token,
111
+ f"sqlite_{file_name or 'latest'}_",
112
+ ".sqlite"
113
+ )
114
+
115
+ # Download SQLite file
116
+ success = self.task_manager.api.download_sqlite_from_post(endpoint, json_data, output_path)
117
+
118
+ if success:
119
+ log(f"{self.request.service_name}: Successfully downloaded SQLite file to {output_path}")
120
+ else:
121
+ log(f"{self.request.service_name}: Failed to download SQLite file.")
122
+
123
+
124
+ def _upload_sqlite(self, file_name: str = "", is_shared: bool = False, sqlite_file: str = "") -> str:
125
+ """
126
+ Uploads the result SQLite file to CDP.
127
+
128
+ :param file_name: The logical file name being uploaded.
129
+ :param is_shared: Whether this file should be treated as shared.
130
+ :param sqlite_file: Path to the SQLite file to upload.
131
+ :return: The uploaded file name if successful, or empty string if failed.
132
+ """
133
+ if not sqlite_file:
134
+ log(f"{self.request.service_name}: No sqlite file provided for upload.")
135
+ return ""
136
+
137
+ if not Path(sqlite_file).is_file():
138
+ log(f"{self.request.service_name}: SQLite file does not exist: {sqlite_file}")
139
+ return ""
140
+
141
+ endpoint = self.request.sqlite_upload
142
+ payload = {
143
+ "file_name": file_name,
144
+ "is_shared": str(is_shared).lower(), # form data values must be string
145
+ "token": self.request.token
146
+ }
147
+
148
+ try:
149
+ log(f"{self.request.service_name}: Uploading sqlite file: {sqlite_file} with payload: {payload}")
150
+ response = self.task_manager.api.http_upload(endpoint, sqlite_file, payload)
151
+
152
+ if response and response.ok:
153
+ log(f"{self.request.service_name}: SQLite file uploaded successfully.")
154
+ return file_name or Path(sqlite_file).name
155
+ else:
156
+ log(f"{self.request.service_name}: Failed to upload sqlite. Status: {response.status_code if response else 'N/A'}")
157
+ return ""
158
+ except Exception as e:
159
+ log(f"{self.request.service_name}: Exception while uploading sqlite: {e}")
160
+ return ""
97
161
 
98
162
  def _exit(self) -> None:
99
163
  """Signals the task manager to exit the service."""
@@ -71,6 +71,8 @@ class TesterTask(ITaskManager):
71
71
  try:
72
72
  files, is_end, next_page = self.request_data_callback(page)
73
73
  req = RequestCommand(
74
+ sqlite_download="",
75
+ sqlite_upload="",
74
76
  runtime_parameters={},
75
77
  token=service.request.token,
76
78
  cmd="dataset",
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: pam-python
3
- Version: 0.1.15
3
+ Version: 0.1.17
4
4
  Summary: Pam Python Library
5
5
  Home-page: https://github.com/heart/pam-python
6
6
  Author: Narongrit Kanhanoi
@@ -32,6 +32,7 @@ Dynamic: classifier
32
32
  Dynamic: description
33
33
  Dynamic: description-content-type
34
34
  Dynamic: home-page
35
+ Dynamic: license-file
35
36
  Dynamic: requires-dist
36
37
  Dynamic: requires-python
37
38
  Dynamic: summary
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name="pam-python",
5
- version="0.1.15",
5
+ version="0.1.17",
6
6
  author="Narongrit Kanhanoi",
7
7
  author_email="narongrit@pams.ai",
8
8
  description="Pam Python Library",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes