outerproduct 0.2.0__tar.gz → 0.2.2__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 (24) hide show
  1. {outerproduct-0.2.0 → outerproduct-0.2.2}/PKG-INFO +2 -2
  2. {outerproduct-0.2.0 → outerproduct-0.2.2}/README.md +1 -1
  3. {outerproduct-0.2.0 → outerproduct-0.2.2}/pyproject.toml +1 -1
  4. {outerproduct-0.2.0 → outerproduct-0.2.2}/src/outerproduct/__init__.py +18 -5
  5. {outerproduct-0.2.0 → outerproduct-0.2.2}/src/outerproduct/agentic/documents.py +20 -17
  6. {outerproduct-0.2.0 → outerproduct-0.2.2}/src/outerproduct/client/apis.py +33 -7
  7. {outerproduct-0.2.0 → outerproduct-0.2.2}/src/outerproduct/client/client.py +7 -0
  8. {outerproduct-0.2.0 → outerproduct-0.2.2}/src/outerproduct/client/endpoints.py +31 -7
  9. {outerproduct-0.2.0 → outerproduct-0.2.2}/src/outerproduct/connector.py +28 -31
  10. outerproduct-0.2.2/src/outerproduct/dataset.py +460 -0
  11. {outerproduct-0.2.0 → outerproduct-0.2.2}/src/outerproduct/model.py +114 -81
  12. {outerproduct-0.2.0 → outerproduct-0.2.2}/src/outerproduct/reasoning/__init__.py +26 -39
  13. {outerproduct-0.2.0 → outerproduct-0.2.2}/src/outerproduct/reasoning/pattern_tracker.py +3 -18
  14. {outerproduct-0.2.0 → outerproduct-0.2.2}/src/outerproduct/trainer.py +48 -79
  15. outerproduct-0.2.0/src/outerproduct/dataset.py +0 -469
  16. {outerproduct-0.2.0 → outerproduct-0.2.2}/.gitignore +0 -0
  17. {outerproduct-0.2.0 → outerproduct-0.2.2}/LICENSE +0 -0
  18. {outerproduct-0.2.0 → outerproduct-0.2.2}/src/outerproduct/agentic/__init__.py +0 -0
  19. {outerproduct-0.2.0 → outerproduct-0.2.2}/src/outerproduct/client/__init__.py +0 -0
  20. {outerproduct-0.2.0 → outerproduct-0.2.2}/src/outerproduct/client/_http.py +0 -0
  21. {outerproduct-0.2.0 → outerproduct-0.2.2}/src/outerproduct/client/exceptions.py +0 -0
  22. {outerproduct-0.2.0 → outerproduct-0.2.2}/src/outerproduct/job.py +0 -0
  23. {outerproduct-0.2.0 → outerproduct-0.2.2}/src/outerproduct/py.typed +0 -0
  24. {outerproduct-0.2.0 → outerproduct-0.2.2}/src/outerproduct/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: outerproduct
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Python SDK for the OuterProduct API
5
5
  Project-URL: Documentation, https://docs.outerproduct.com
6
6
  Project-URL: Homepage, https://outerproduct.com
@@ -118,7 +118,7 @@ reasoning = rm.explain(X)
118
118
  predictions, reasoning = rm.predict_and_explain(X)
119
119
 
120
120
  # Global feature importance
121
- reasoning = rm.interpret()
121
+ reasoning = rm.get_global_drivers()
122
122
 
123
123
  # Counterfactual scenario search
124
124
  trace = rm.scenario(X, target_class=1, max_steps=10)
@@ -83,7 +83,7 @@ reasoning = rm.explain(X)
83
83
  predictions, reasoning = rm.predict_and_explain(X)
84
84
 
85
85
  # Global feature importance
86
- reasoning = rm.interpret()
86
+ reasoning = rm.get_global_drivers()
87
87
 
88
88
  # Counterfactual scenario search
89
89
  trace = rm.scenario(X, target_class=1, max_steps=10)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "outerproduct"
3
- version = "0.2.0"
3
+ version = "0.2.2"
4
4
  description = "Python SDK for the OuterProduct API"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -15,7 +15,7 @@ core concepts:
15
15
  prediction endpoint, used to hand black-box models into
16
16
  :func:`~outerproduct.reasoning.fit` for distillation.
17
17
  - :class:`~outerproduct.model.ReasoningModel` — a :class:`~outerproduct.model.Model` that also supports
18
- :meth:`~outerproduct.model.ReasoningModel.explain`, :meth:`~outerproduct.model.ReasoningModel.interpret`,
18
+ :meth:`~outerproduct.model.ReasoningModel.explain`, :meth:`~outerproduct.model.ReasoningModel.get_global_drivers`,
19
19
  and :meth:`~outerproduct.model.ReasoningModel.scenario`.
20
20
  Produced by :func:`~outerproduct.reasoning.fit`.
21
21
  - :class:`~outerproduct.reasoning.pattern_tracker.PatternTracker` —
@@ -33,10 +33,11 @@ Quickstart
33
33
 
34
34
  op.init(api_key="...")
35
35
  connector = op.FileUploadConnector()
36
- dataset = connector.upload("customers.csv", label_column="churn")
37
- reasoning_model = op.reasoning.fit(dataset)
38
- predictions = reasoning_model.predict(X_new)
39
- reasoning = reasoning_model.explain(X_new)
36
+ dataset = connector.upload("customers.csv")
37
+ reasoning_model = op.reasoning.fit(dataset, label_column="churn")
38
+ test_dataset = op.Dataset(X_new)
39
+ predictions = reasoning_model.predict(test_dataset)
40
+ reasoning = reasoning_model.explain(test_dataset)
40
41
  """
41
42
 
42
43
  from __future__ import annotations
@@ -124,9 +125,21 @@ def init(
124
125
  _state.hardware = hardware
125
126
 
126
127
 
128
+ def get_datasets() -> list[Dataset]:
129
+ """List datasets owned by the configured API key."""
130
+ from outerproduct.client import OuterProductClient
131
+
132
+ with OuterProductClient.from_credentials(_state.base_url, _state.api_key) as client:
133
+ response = client.datasets_api.list()
134
+ return [
135
+ Dataset._from_id(dataset.id, response=dataset) for dataset in response.datasets
136
+ ]
137
+
138
+
127
139
  __all__ = [
128
140
  # Bootstrap
129
141
  "init",
142
+ "get_datasets",
130
143
  "__version__",
131
144
  # Dataset
132
145
  "Dataset",
@@ -5,7 +5,7 @@ text) as a feature source: induce a frozen schema of survey questions
5
5
  for the use case, then have the agent extract every document against
6
6
  that schema. The tabularized rows live in object storage on the
7
7
  OuterProduct backend; the SDK returns a :class:`DocumentDataset` that
8
- references that remote table by ``model_id`` and slots into
8
+ references that remote table by ``dataset_id`` and slots into
9
9
  :meth:`outerproduct.Trainer.configure` and
10
10
  :func:`outerproduct.reasoning.fit` exactly like any other uploaded
11
11
  :class:`~outerproduct.Dataset`.
@@ -16,7 +16,7 @@ Typical flow::
16
16
  refs = upload(docs) # one-time upload
17
17
  schema = induce_schema(refs, use_case="audit", skill="invoice")
18
18
  ds = tabularize(refs, schema) # remote DocumentDataset
19
- trainer.run(ds) # uses data_uploaded=True
19
+ trainer.run(ds) # sends dataset_id
20
20
 
21
21
  ``upload`` is explicit so the same documents can feed both
22
22
  :func:`induce_schema` and :func:`tabularize` without re-uploading.
@@ -288,13 +288,10 @@ class DocumentDataset(Dataset):
288
288
  """A remote-handle :class:`Dataset` whose rows are tabularized
289
289
  documents and columns are :class:`DocumentSchema` questions.
290
290
 
291
- Holds no rows locally. The tabularized table lives on the
292
- OuterProduct backend under ``model_id`` (the same path used by
293
- pre-uploaded datasets), and the trainer/reasoning APIs fetch from
294
- that location server-side via the standard ``data_uploaded=True``
295
- wire mode.
291
+ Holds no rows locally. The tabularized table already exists on the
292
+ OuterProduct backend under ``dataset_id``.
296
293
 
297
- Construct directly when you already have a tabularize ``model_id``,
294
+ Construct directly when you already have a tabularize ``dataset_id``,
298
295
  or — more commonly — let :func:`tabularize` build one for you.
299
296
  """
300
297
 
@@ -303,15 +300,22 @@ class DocumentDataset(Dataset):
303
300
  *,
304
301
  schema: DocumentSchema,
305
302
  document_ids: list[str],
306
- model_id: str,
303
+ dataset_id: str,
307
304
  label_column: str | None = None,
308
305
  columns: list[Column] | None = None,
309
306
  ) -> None:
310
307
  import pandas as pd
311
308
 
312
309
  empty = pd.DataFrame(columns=pd.Index([q.id for q in schema.questions]))
313
- super().__init__(empty, label_column=label_column, columns=columns)
314
- self._upload_id = model_id
310
+ self._df = empty
311
+ self._label_column = label_column
312
+ self._explicit_columns = columns or [
313
+ Column(name=q.id) for q in schema.questions
314
+ ]
315
+ self._id = dataset_id
316
+ self._connector_id = None
317
+ self._table_name = None
318
+ self._remote_only = True
315
319
  self._schema = schema
316
320
  self._document_ids = list(document_ids)
317
321
 
@@ -324,10 +328,9 @@ class DocumentDataset(Dataset):
324
328
  return list(self._document_ids)
325
329
 
326
330
  @property
327
- def model_id(self) -> str:
328
- """The tabularize-job ``model_id`` that backs this dataset on the server."""
329
- assert self._upload_id is not None
330
- return self._upload_id
331
+ def dataset_id(self) -> str:
332
+ """The tabularize-job ``dataset_id`` that backs this dataset on the server."""
333
+ return self.id
331
334
 
332
335
  @property
333
336
  def n_samples(self) -> int:
@@ -476,7 +479,7 @@ def tabularize(
476
479
  The tabularized rows are written to object storage on the backend;
477
480
  the returned :class:`DocumentDataset` is a remote handle that
478
481
  :class:`~outerproduct.Trainer` and :func:`~outerproduct.reasoning.fit`
479
- consume directly via the standard ``data_uploaded=True`` wire mode.
482
+ consume directly via the standard ``dataset_id`` wire mode.
480
483
  No rows are downloaded to the client.
481
484
  """
482
485
  op = _resolve_client(client)
@@ -496,7 +499,7 @@ def tabularize(
496
499
  return DocumentDataset(
497
500
  schema=_schema_from_payload(result.schema_),
498
501
  document_ids=list(result.document_ids),
499
- model_id=result.model_id,
502
+ dataset_id=result.dataset_id,
500
503
  label_column=label_column,
501
504
  )
502
505
 
@@ -18,14 +18,17 @@ from outerproduct_http_types import (
18
18
  CreateDocumentUploadResponse,
19
19
  CreateUploadRequest,
20
20
  CreateUploadResponse,
21
+ Dataset,
22
+ DatasetResponse,
21
23
  DeleteConnectorResponse,
22
24
  ExplainRequest,
23
25
  ExplainResponse,
26
+ GlobalDriversRequest,
27
+ GlobalDriversResponse,
24
28
  InduceSchemaJobResponse,
25
29
  InduceSchemaRequest,
26
- InterpretRequest,
27
- InterpretResponse,
28
30
  ListConnectorsResponse,
31
+ ListDatasetsResponse,
29
32
  ListTablesRequest,
30
33
  ListTablesResponse,
31
34
  PatternTrackerApplyRequest,
@@ -54,16 +57,19 @@ from outerproduct_http_types import (
54
57
 
55
58
  from outerproduct.client.endpoints import (
56
59
  CREATE_CONNECTOR,
60
+ CREATE_DATASET,
57
61
  CREATE_DOCUMENT_UPLOAD,
58
62
  CREATE_UPLOAD,
59
63
  DELETE_CONNECTOR,
60
64
  EXPLAIN,
61
65
  GET_CONNECTOR,
66
+ GET_DATASET,
62
67
  GET_DOCUMENT_SCHEMA,
63
68
  GET_DOCUMENT_TABLE,
69
+ GLOBAL_DRIVERS,
64
70
  INDUCE_DOCUMENT_SCHEMA,
65
- INTERPRET,
66
71
  LIST_CONNECTORS,
72
+ LIST_DATASETS,
67
73
  LIST_TABLES,
68
74
  PATTERN_TRACKER_DISTRIBUTION,
69
75
  PATTERN_TRACKER_FIT,
@@ -145,6 +151,25 @@ class ReasoningAPI:
145
151
  return self._client._post(REASONING_FIT, request)
146
152
 
147
153
 
154
+ class DatasetsAPI:
155
+ """CRUD for first-class datasets."""
156
+
157
+ def __init__(self, client: OuterProductClient) -> None:
158
+ self._client = client
159
+
160
+ def create(self, request: Dataset) -> DatasetResponse:
161
+ return self._client._post( # ty: ignore[invalid-return-type]
162
+ CREATE_DATASET, # ty: ignore[invalid-argument-type]
163
+ request,
164
+ )
165
+
166
+ def list(self) -> ListDatasetsResponse:
167
+ return self._client._get(LIST_DATASETS)
168
+
169
+ def get(self, dataset_id: str) -> DatasetResponse:
170
+ return self._client._get(GET_DATASET, dataset_id=dataset_id)
171
+
172
+
148
173
  class InferenceAPI:
149
174
  """Synchronous inference on ``/v1/models/{model_id}/...``."""
150
175
 
@@ -162,11 +187,11 @@ class InferenceAPI:
162
187
  ) -> PredictAndExplainResponse:
163
188
  return self._client._post(PREDICT_AND_EXPLAIN, request, model_id=model_id)
164
189
 
165
- def interpret(
166
- self, model_id: str, request: InterpretRequest | None = None
167
- ) -> InterpretResponse:
190
+ def get_global_drivers(
191
+ self, model_id: str, request: GlobalDriversRequest | None = None
192
+ ) -> GlobalDriversResponse:
168
193
  return self._client._post(
169
- INTERPRET, request or InterpretRequest(), model_id=model_id
194
+ GLOBAL_DRIVERS, request or GlobalDriversRequest(), model_id=model_id
170
195
  )
171
196
 
172
197
  def scenario(self, model_id: str, request: ScenarioRequest) -> ScenarioResponse:
@@ -285,6 +310,7 @@ class ConnectorsAPI:
285
310
  __all__ = [
286
311
  "AgenticDocumentsAPI",
287
312
  "ConnectorsAPI",
313
+ "DatasetsAPI",
288
314
  "InferenceAPI",
289
315
  "PatternTrackerAPI",
290
316
  "ReasoningAPI",
@@ -30,6 +30,7 @@ if TYPE_CHECKING:
30
30
  from outerproduct.client.apis import (
31
31
  AgenticDocumentsAPI,
32
32
  ConnectorsAPI,
33
+ DatasetsAPI,
33
34
  InferenceAPI,
34
35
  PatternTrackerAPI,
35
36
  ReasoningAPI,
@@ -180,6 +181,12 @@ class OuterProductClient:
180
181
 
181
182
  return ConnectorsAPI(self)
182
183
 
184
+ @property
185
+ def datasets_api(self) -> DatasetsAPI:
186
+ from outerproduct.client.apis import DatasetsAPI
187
+
188
+ return DatasetsAPI(self)
189
+
183
190
  @property
184
191
  def agentic_documents_api(self) -> AgenticDocumentsAPI:
185
192
  from outerproduct.client.apis import AgenticDocumentsAPI
@@ -24,14 +24,17 @@ from outerproduct_http_types import (
24
24
  CreateDocumentUploadResponse,
25
25
  CreateUploadRequest,
26
26
  CreateUploadResponse,
27
+ Dataset,
28
+ DatasetResponse,
27
29
  DeleteConnectorResponse,
28
30
  ExplainRequest,
29
31
  ExplainResponse,
32
+ GlobalDriversRequest,
33
+ GlobalDriversResponse,
30
34
  InduceSchemaJobResponse,
31
35
  InduceSchemaRequest,
32
- InterpretRequest,
33
- InterpretResponse,
34
36
  ListConnectorsResponse,
37
+ ListDatasetsResponse,
35
38
  ListTablesRequest,
36
39
  ListTablesResponse,
37
40
  PatternTrackerApplyRequest,
@@ -151,6 +154,24 @@ REASONING_FIT = PostEndpoint(
151
154
  response_type=ReasoningFitResponse,
152
155
  )
153
156
 
157
+ # --------------------------------------------------------------------------- #
158
+ # Datasets #
159
+ # --------------------------------------------------------------------------- #
160
+
161
+ CREATE_DATASET = PostEndpoint(
162
+ path="datasets",
163
+ request_type=Dataset, # ty: ignore[invalid-argument-type]
164
+ response_type=DatasetResponse,
165
+ )
166
+ LIST_DATASETS = GetEndpoint(
167
+ path="datasets",
168
+ response_type=ListDatasetsResponse,
169
+ )
170
+ GET_DATASET = GetEndpoint(
171
+ path="datasets/{dataset_id}",
172
+ response_type=DatasetResponse,
173
+ )
174
+
154
175
  # --------------------------------------------------------------------------- #
155
176
  # Status (cross-cutting; covers fit / fit-distill / segment) #
156
177
  # --------------------------------------------------------------------------- #
@@ -179,10 +200,10 @@ PREDICT_AND_EXPLAIN = PostEndpoint(
179
200
  request_type=PredictAndExplainRequest,
180
201
  response_type=PredictAndExplainResponse,
181
202
  )
182
- INTERPRET = PostEndpoint(
183
- path="models/{model_id}/interpret",
184
- request_type=InterpretRequest,
185
- response_type=InterpretResponse,
203
+ GLOBAL_DRIVERS = PostEndpoint(
204
+ path="models/{model_id}/global_drivers",
205
+ request_type=GlobalDriversRequest,
206
+ response_type=GlobalDriversResponse,
186
207
  )
187
208
  SCENARIO = PostEndpoint(
188
209
  path="models/{model_id}/scenario",
@@ -257,18 +278,21 @@ VALIDATE_CONNECTOR = PostEndpoint(
257
278
 
258
279
  __all__ = [
259
280
  "CREATE_CONNECTOR",
281
+ "CREATE_DATASET",
260
282
  "CREATE_DOCUMENT_UPLOAD",
261
283
  "CREATE_UPLOAD",
262
284
  "DELETE_CONNECTOR",
263
285
  "DeleteEndpoint",
264
286
  "EXPLAIN",
265
287
  "GET_CONNECTOR",
288
+ "GET_DATASET",
266
289
  "GET_DOCUMENT_SCHEMA",
267
290
  "GET_DOCUMENT_TABLE",
291
+ "GLOBAL_DRIVERS",
268
292
  "GetEndpoint",
269
293
  "INDUCE_DOCUMENT_SCHEMA",
270
- "INTERPRET",
271
294
  "LIST_CONNECTORS",
295
+ "LIST_DATASETS",
272
296
  "LIST_TABLES",
273
297
  "PATTERN_TRACKER_DISTRIBUTION",
274
298
  "PATTERN_TRACKER_FIT",
@@ -17,11 +17,11 @@ Examples
17
17
 
18
18
  # File upload (local files):
19
19
  connector = op.FileUploadConnector()
20
- dataset = connector.upload("data.csv", label_column="churn")
20
+ dataset = connector.upload("data.csv")
21
21
 
22
22
  # S3 connector (registered with backend):
23
23
  s3 = op.S3Connector("my-s3", root_dir="s3://bucket/prefix")
24
- dataset = s3.table("customers.csv", label_column="churn")
24
+ dataset = s3.table("customers.csv")
25
25
 
26
26
  # Snowflake connector:
27
27
  sf = op.SnowflakeConnector(
@@ -32,7 +32,7 @@ Examples
32
32
  schema_name="PUBLIC",
33
33
  credentials={"user": "admin", "password": "secret"},
34
34
  )
35
- dataset = sf.table("customers", label_column="churn")
35
+ dataset = sf.table("customers")
36
36
 
37
37
  # Databricks connector:
38
38
  db = op.DatabricksConnector(
@@ -43,7 +43,7 @@ Examples
43
43
  schema="default",
44
44
  credentials={"access_token": "dapi-..."},
45
45
  )
46
- dataset = db.table("customers", label_column="churn")
46
+ dataset = db.table("customers")
47
47
 
48
48
  Credentials handling
49
49
  --------------------
@@ -177,24 +177,18 @@ class Connector(ABC):
177
177
  """
178
178
  return name in self.table_names()
179
179
 
180
- def table(self, name: str, *, label_column: str | None = None) -> Dataset:
181
- """Return a :class:`~outerproduct.dataset.Dataset` referencing a table in this connector.
180
+ def table(self, name: str) -> Dataset:
181
+ """Build a connector-backed :class:`~outerproduct.dataset.Dataset` spec.
182
182
 
183
- The returned dataset is *lazy* — it holds a connector reference rather
184
- than local data. The backend reads the actual data at training time.
183
+ The dataset rides inline on fit/predict requests; the target
184
+ column is selected at fit time via the ``label_column`` parameter
185
+ on :func:`~outerproduct.reasoning.fit` /
186
+ :meth:`~outerproduct.trainer.Trainer.configure`, not on the dataset.
185
187
 
186
188
  Parameters
187
189
  ----------
188
190
  name : str
189
191
  Table name or object path within the connector.
190
- label_column : str, optional
191
- Name of the target column for supervised training.
192
-
193
- Returns
194
- -------
195
- :class:`~outerproduct.dataset.Dataset`
196
- A connector-backed dataset ready for :class:`~outerproduct.trainer.Trainer`
197
- or :func:`~outerproduct.reasoning.fit`.
198
192
  """
199
193
  from outerproduct.dataset import Dataset
200
194
 
@@ -204,7 +198,6 @@ class Connector(ABC):
204
198
  return Dataset._from_connector_ref(
205
199
  connector_id=self._connector_id,
206
200
  table_name=name,
207
- label_column=label_column,
208
201
  )
209
202
 
210
203
  def validate(self) -> bool:
@@ -352,7 +345,7 @@ class Connector(ABC):
352
345
 
353
346
 
354
347
  # ---------------------------------------------------------------------------
355
- # File upload connector (stateless, unchanged)
348
+ # File upload connector (local file -> uploaded dataset)
356
349
  # ---------------------------------------------------------------------------
357
350
 
358
351
 
@@ -363,10 +356,11 @@ class FileUploadConnector:
363
356
 
364
357
  1. Request a presigned upload URL from the server.
365
358
  2. ``PUT`` the raw file bytes to that URL.
366
- 3. Return a :class:`~outerproduct.dataset.Dataset` referring to the uploaded data.
359
+ 3. Register the uploaded object as a first-class dataset row.
360
+ 4. Return a :class:`~outerproduct.dataset.Dataset` referring to that row.
367
361
 
368
- This connector does *not* register with the backend — it is a stateless
369
- upload helper. Use the other connectors for registered external data sources.
362
+ This connector itself does not create a persistent connector config; it is
363
+ a local-file helper that produces dataset rows.
370
364
 
371
365
  Examples
372
366
  --------
@@ -374,7 +368,7 @@ class FileUploadConnector:
374
368
 
375
369
  import outerproduct as op
376
370
  connector = op.FileUploadConnector()
377
- dataset = connector.upload("data.csv", label_column="churn")
371
+ dataset = connector.upload("data.csv")
378
372
  """
379
373
 
380
374
  _FORMAT_MAP: dict[str, str] = {
@@ -389,7 +383,6 @@ class FileUploadConnector:
389
383
  self,
390
384
  path: str | Path,
391
385
  *,
392
- label_column: str | None = None,
393
386
  name: str | None = None,
394
387
  ) -> Dataset:
395
388
  """Upload a local data file and return a :class:`~outerproduct.dataset.Dataset`.
@@ -399,8 +392,6 @@ class FileUploadConnector:
399
392
  path : str or pathlib.Path
400
393
  Path to a local file. Supported formats: ``.csv``,
401
394
  ``.parquet``, ``.pkl``.
402
- label_column : str, optional
403
- Name of the target column, if any.
404
395
  name : str, optional
405
396
  Caller-supplied label, retained for display.
406
397
 
@@ -488,6 +479,7 @@ class FileUploadConnector:
488
479
  put_resp.raise_for_status()
489
480
 
490
481
  # 4. Parse the same bytes into a DataFrame for the local Dataset.
482
+ # The spec rides inline on fit/predict requests; no POST /v1/datasets.
491
483
  if file_format == "csv":
492
484
  df = pd.read_csv(io.BytesIO(file_bytes))
493
485
  elif file_format == "parquet":
@@ -496,9 +488,14 @@ class FileUploadConnector:
496
488
  raw = pd.read_pickle(io.BytesIO(file_bytes))
497
489
  df = pd.DataFrame(raw) if not isinstance(raw, pd.DataFrame) else raw
498
490
 
499
- dataset = Dataset(df, label_column=label_column)
500
- dataset._upload_id = upload_resp.dataset_id
501
- return dataset
491
+ wire_columns = Dataset._http_columns_from_dataframe(df)
492
+ return Dataset._from_registered_dataframe(
493
+ df,
494
+ dataset_id=None,
495
+ columns=Dataset._columns_from_http(wire_columns),
496
+ data_uri=upload_resp.data_uri,
497
+ file_format=file_format,
498
+ )
502
499
 
503
500
 
504
501
  # ---------------------------------------------------------------------------
@@ -530,7 +527,7 @@ class S3Connector(Connector):
530
527
  import outerproduct as op
531
528
  connector = op.S3Connector("my-s3", root_dir="s3://bucket/prefix")
532
529
  print(connector.table_names())
533
- dataset = connector.table("customers.csv", label_column="churn")
530
+ dataset = connector.table("customers.csv")
534
531
 
535
532
  Parameters
536
533
  ----------
@@ -592,7 +589,7 @@ class SnowflakeConnector(Connector):
592
589
  credentials={"user": "admin", "password": "secret"},
593
590
  )
594
591
  print(connector.table_names())
595
- dataset = connector.table("customers", label_column="churn")
592
+ dataset = connector.table("customers")
596
593
 
597
594
  Parameters
598
595
  ----------
@@ -682,7 +679,7 @@ class DatabricksConnector(Connector):
682
679
  http_path="/sql/1.0/warehouses/abc",
683
680
  credentials={"access_token": "dapi..."},
684
681
  )
685
- dataset = connector.table("customers", label_column="churn")
682
+ dataset = connector.table("customers")
686
683
 
687
684
  Parameters
688
685
  ----------