pam-python 0.2.6__tar.gz → 0.2.7__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.
- {pam_python-0.2.6 → pam_python-0.2.7}/PKG-INFO +1 -1
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/__init__.py +1 -1
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/cli.py +24 -49
- {pam_python-0.2.6 → pam_python-0.2.7}/pam_python.egg-info/PKG-INFO +1 -1
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_cli_templates.py +11 -5
- {pam_python-0.2.6 → pam_python-0.2.7}/LICENSE.txt +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/README.md +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/api.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/interface_task_manager.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/logger.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/models/__init__.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/models/data_input_v2.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/models/request_command.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/models/sqlite_download.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/__init__.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/area.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/axis.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/bar.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/box_plot.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/bubble.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/candlestick.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/collection.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/definition.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/donut.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/errors.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/fields.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/heatmap.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/line.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/manager.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/metric.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/pie.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/polar_area.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/radar.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/radial_bar.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/range_area.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/range_bar.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/range_transform.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/record.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/report.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/scatter.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/schema.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/store.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/table.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/transport.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/reports/treemap.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/request_file_format.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/result_batch_uploader.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/server.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/service.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/sqlite.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/task_manager.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/temp_file_utils.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/templates/buildcmd/pamb +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/templates/buildcmd/pamb-base.sh +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/templates/init/AGENT.md +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/templates/init/REPORTS.md +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/templates/init/dockerignore.tmpl +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/templates/init/gitignore.tmpl +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/templates/init/main.tmpl +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/templates/init/pylintrc.tmpl +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/templates/init/run_unit_test.bat +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/templates/init/run_unit_test.ps1 +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/templates/init/run_unit_test.sh +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/templates/project/pip/Dockerfile +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/templates/project/pip/requirements.txt +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/templates/project/uv/Dockerfile +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/templates/project/uv/pyproject.toml +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/templates/project/uv/python-version +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/templates/service/common/service.yaml +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/templates/service/pandas/functions.tmpl +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/templates/service/pandas/service.test.tmpl +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/templates/service/pandas/service_class.tmpl +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/templates/service/polars/functions.tmpl +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/templates/service/polars/service.test.tmpl +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/templates/service/polars/service_class.tmpl +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/tester_task.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam/utils.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam_python.egg-info/SOURCES.txt +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam_python.egg-info/dependency_links.txt +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam_python.egg-info/entry_points.txt +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam_python.egg-info/requires.txt +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pam_python.egg-info/top_level.txt +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/pyproject.toml +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/setup.cfg +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_api.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_data_error_v2.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_data_input_v2.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_data_timeout_v2.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_range_transform.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_report_store.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_request_data_v2.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_result_batch_uploader.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_service_dataframe_output.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_sqlite_download_v2.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_temp_file_utils.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_typed_area_report.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_typed_bar_report.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_typed_box_plot_report.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_typed_bubble_report.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_typed_candlestick_report.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_typed_donut_report.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_typed_heatmap_report.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_typed_line_report.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_typed_metric_report.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_typed_pie_report.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_typed_polar_area_report.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_typed_radar_report.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_typed_radial_bar_report.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_typed_range_area_report.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_typed_range_bar_report.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_typed_scatter_report.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_typed_table_report.py +0 -0
- {pam_python-0.2.6 → pam_python-0.2.7}/tests/test_typed_treemap_report.py +0 -0
|
@@ -145,19 +145,10 @@ def _project_name(directory: Path) -> str:
|
|
|
145
145
|
|
|
146
146
|
|
|
147
147
|
def _assert_new_project(directory: Path):
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
conflicts = [
|
|
153
|
-
name for name in sorted(known_project_files)
|
|
154
|
-
if (directory / name).exists()
|
|
155
|
-
]
|
|
156
|
-
if conflicts:
|
|
157
|
-
raise FileExistsError(
|
|
158
|
-
"pam init only supports a new project directory; existing files: "
|
|
159
|
-
+ ", ".join(conflicts)
|
|
160
|
-
)
|
|
148
|
+
# Kept for backward compatibility; collision handling is now in init_project
|
|
149
|
+
# via _prompt_overwrite_if_needed. Do not enforce allow-list here so
|
|
150
|
+
# unrelated files like .DS_Store are ignored.
|
|
151
|
+
return
|
|
161
152
|
|
|
162
153
|
|
|
163
154
|
def _requirement_name(requirement: str) -> str:
|
|
@@ -180,45 +171,26 @@ def _assert_fresh_uv_project(directory: Path):
|
|
|
180
171
|
"Run `uv add pam-python` before `uv run pam init`"
|
|
181
172
|
)
|
|
182
173
|
|
|
183
|
-
python_version = directory / ".python-version"
|
|
184
|
-
if not python_version.is_file() or not python_version.read_text().strip().startswith("3.12"):
|
|
185
|
-
raise FileExistsError(
|
|
186
|
-
"A fresh uv project must pin Python 3.12; run `uv init --python 3.12`"
|
|
187
|
-
)
|
|
188
174
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
"
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
unexpected = sorted(path.name for path in directory.iterdir() if path.name not in allowed)
|
|
200
|
-
if unexpected:
|
|
175
|
+
def _prompt_overwrite_if_needed(directory: Path, templates: dict[str, str]) -> bool:
|
|
176
|
+
dest_names = set(templates.values()) | {PROJECT_MARKER, "__init__.py"}
|
|
177
|
+
conflicts = sorted(name for name in dest_names if (directory / name).exists())
|
|
178
|
+
if not conflicts:
|
|
179
|
+
return True
|
|
180
|
+
print("The following files will be overwritten:")
|
|
181
|
+
for name in conflicts:
|
|
182
|
+
print(f" - {name}")
|
|
183
|
+
# Single confirmation round as requested: list collisions once, ask once.
|
|
184
|
+
if not sys.stdin.isatty():
|
|
201
185
|
raise FileExistsError(
|
|
202
|
-
"pam init
|
|
203
|
-
|
|
204
|
-
)
|
|
205
|
-
|
|
206
|
-
readme = directory / "README.md"
|
|
207
|
-
if readme.is_file() and readme.read_text(encoding="utf-8").strip():
|
|
208
|
-
raise FileExistsError("pam init will not overwrite a non-empty README.md")
|
|
209
|
-
|
|
210
|
-
main_file = directory / "main.py"
|
|
211
|
-
if main_file.is_file():
|
|
212
|
-
source = main_file.read_text(encoding="utf-8")
|
|
213
|
-
uv_placeholder = re.fullmatch(
|
|
214
|
-
r'def main\(\):\n'
|
|
215
|
-
r' print\("Hello from [a-z0-9-]+!"\)\n\n\n'
|
|
216
|
-
r'if __name__ == "__main__":\n'
|
|
217
|
-
r' main\(\)\n?',
|
|
218
|
-
source,
|
|
186
|
+
"pam init will overwrite existing files: " + ", ".join(conflicts) + ". "
|
|
187
|
+
"Run in an interactive terminal and confirm to overwrite."
|
|
219
188
|
)
|
|
220
|
-
|
|
221
|
-
|
|
189
|
+
response = input("มีไฟล์ที่จะถูกเขียนทับตามรายการข้างบน ดำเนินการต่อหรือไม่? (y/N): ").strip().lower()
|
|
190
|
+
if response != "y":
|
|
191
|
+
print("Cancelled.")
|
|
192
|
+
return False
|
|
193
|
+
return True
|
|
222
194
|
|
|
223
195
|
|
|
224
196
|
def _run_uv(args: list[str], cwd: Path):
|
|
@@ -263,6 +235,9 @@ def init_project(package_manager: str | None = None):
|
|
|
263
235
|
if dest not in preserved_uv_files
|
|
264
236
|
}
|
|
265
237
|
|
|
238
|
+
if not _prompt_overwrite_if_needed(destination, templates):
|
|
239
|
+
return
|
|
240
|
+
|
|
266
241
|
with tempfile.TemporaryDirectory(prefix=".pam-init-", dir=destination) as temp_dir:
|
|
267
242
|
staging = Path(temp_dir)
|
|
268
243
|
for src, dest in templates.items():
|
|
@@ -186,6 +186,8 @@ if __name__ == "__main__":
|
|
|
186
186
|
|
|
187
187
|
with mock.patch.object(cli.shutil, "which", return_value="/usr/bin/uv"), mock.patch.object(
|
|
188
188
|
cli, "_run_uv", side_effect=lambda args, cwd: calls.append(list(args))
|
|
189
|
+
), mock.patch.object(cli.sys.stdin, "isatty", return_value=True), mock.patch(
|
|
190
|
+
"builtins.input", return_value="y"
|
|
189
191
|
):
|
|
190
192
|
cli.init_project()
|
|
191
193
|
|
|
@@ -217,7 +219,9 @@ if __name__ == "__main__":
|
|
|
217
219
|
(root / "README.md").touch()
|
|
218
220
|
(root / "main.py").write_text(uv_main)
|
|
219
221
|
|
|
220
|
-
with mock.patch.object(cli.shutil, "which", return_value="/usr/bin/uv")
|
|
222
|
+
with mock.patch.object(cli.shutil, "which", return_value="/usr/bin/uv"), mock.patch.object(
|
|
223
|
+
cli.sys.stdin, "isatty", return_value=True
|
|
224
|
+
), mock.patch("builtins.input", return_value="y"):
|
|
221
225
|
cli.init_project()
|
|
222
226
|
|
|
223
227
|
gitignore = (root / ".gitignore").read_text()
|
|
@@ -242,15 +246,17 @@ if __name__ == "__main__":
|
|
|
242
246
|
(root / ".python-version").write_text("3.12\n")
|
|
243
247
|
(root / "main.py").write_text("print('real code')\n")
|
|
244
248
|
|
|
245
|
-
with
|
|
246
|
-
|
|
249
|
+
with mock.patch.object(cli.sys.stdin, "isatty", return_value=False):
|
|
250
|
+
with self.assertRaisesRegex(FileExistsError, "will overwrite existing files: main.py"):
|
|
251
|
+
cli.init_project()
|
|
247
252
|
|
|
248
253
|
def test_init_rejects_an_existing_project_without_overwriting(self):
|
|
249
254
|
with tempfile.TemporaryDirectory() as temp_dir, WorkingDirectory(temp_dir):
|
|
250
255
|
original = Path("main.py")
|
|
251
256
|
original.write_text("keep me\n")
|
|
252
|
-
with
|
|
253
|
-
|
|
257
|
+
with mock.patch.object(cli.sys.stdin, "isatty", return_value=False):
|
|
258
|
+
with self.assertRaises(FileExistsError):
|
|
259
|
+
cli.init_project("pip")
|
|
254
260
|
self.assertEqual("keep me\n", original.read_text())
|
|
255
261
|
|
|
256
262
|
def test_service_name_validation_rejects_paths_and_hyphens(self):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|