"""HTTP client for Pipekit API.""" import requests from requests.auth import HTTPBasicAuth class PipekitClient: def __init__(self, base_url: str = "http://localhost:8100", username: str = "admin", password: str = "pipekit"): self.base_url = base_url.rstrip("/") self.auth = HTTPBasicAuth(username, password) def _get(self, path: str, params: dict = None) -> dict | list: r = requests.get(f"{self.base_url}{path}", auth=self.auth, params=params) r.raise_for_status() return r.json() def _post(self, path: str, json: dict = None) -> dict: r = requests.post(f"{self.base_url}{path}", auth=self.auth, json=json) r.raise_for_status() return r.json() def _put(self, path: str, json: dict = None) -> dict: r = requests.put(f"{self.base_url}{path}", auth=self.auth, json=json) r.raise_for_status() return r.json() def _delete(self, path: str) -> dict: r = requests.delete(f"{self.base_url}{path}", auth=self.auth) r.raise_for_status() return r.json() # Connections def list_connections(self): return self._get("/connections") def create_connection(self, data): return self._post("/connections", data) def get_connection(self, id): return self._get(f"/connections/{id}") def update_connection(self, id, data): return self._put(f"/connections/{id}", data) def delete_connection(self, id): return self._delete(f"/connections/{id}") def test_connection(self, id): return self._post(f"/connections/{id}/test") # Introspection def list_tables(self, conn_id, schema=None): params = {"schema": schema} if schema else None return self._get(f"/connections/{conn_id}/tables", params) def list_columns(self, conn_id, schema, table): return self._get(f"/connections/{conn_id}/tables/{schema}.{table}/columns") def propose_module(self, conn_id, schema, table, dest_schema=None, linked_server=None, linked_db=None): params = {} if dest_schema: params["dest_schema"] = dest_schema if linked_server: params["linked_server"] = linked_server if linked_db: params["linked_db"] = linked_db return self._get(f"/connections/{conn_id}/tables/{schema}.{table}/propose", params or None) # Modules def list_modules(self): return self._get("/modules") def create_module(self, data): return self._post("/modules", data) def get_module(self, id): return self._get(f"/modules/{id}") def update_module(self, id, data): return self._put(f"/modules/{id}", data) def delete_module(self, id): return self._delete(f"/modules/{id}") def preview_module(self, id): return self._get(f"/modules/{id}/preview") def run_module(self, id): return self._post(f"/modules/{id}/run") def run_module_stream(self, id): """Stream sync output. Yields lines, final line starts with __DONE__ or __ERROR__.""" r = requests.post(f"{self.base_url}/modules/{id}/run/stream", auth=self.auth, stream=True) r.raise_for_status() for line in r.iter_lines(decode_unicode=True): if line.startswith("data: "): yield line[6:] def module_history(self, id): return self._get(f"/modules/{id}/history") # Hooks def list_hooks(self, module_id): return self._get(f"/modules/{module_id}/hooks") def create_hook(self, data): return self._post("/hooks", data) def delete_hook(self, id): return self._delete(f"/hooks/{id}") # Groups def list_groups(self): return self._get("/groups") def create_group(self, data): return self._post("/groups", data) def get_group(self, id): return self._get(f"/groups/{id}") def delete_group(self, id): return self._delete(f"/groups/{id}") def add_group_member(self, group_id, data): return self._post(f"/groups/{group_id}/members", data) def remove_group_member(self, member_id): return self._delete(f"/groups/members/{member_id}") def run_group(self, id): return self._post(f"/groups/{id}/run") # Runs def list_runs(self, limit=50): return self._get("/runs", {"limit": limit}) def get_run(self, id): return self._get(f"/runs/{id}") # Schedules def list_schedules(self): return self._get("/schedules") def create_schedule(self, data): return self._post("/schedules", data) def update_schedule(self, id, data): return self._put(f"/schedules/{id}", data) def delete_schedule(self, id): return self._delete(f"/schedules/{id}") # Drivers def list_drivers(self): return self._get("/drivers") def create_driver(self, data): return self._post("/drivers", data) def delete_driver(self, id): return self._delete(f"/drivers/{id}")