sdgym 0.15.1.dev0__tar.gz → 0.15.2.dev0__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 (61) hide show
  1. {sdgym-0.15.1.dev0/sdgym.egg-info → sdgym-0.15.2.dev0}/PKG-INFO +13 -5
  2. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/pyproject.toml +14 -5
  3. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/__init__.py +1 -1
  4. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/_benchmark_launcher/utils.py +1 -0
  5. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/synthesizer_descriptions.yaml +11 -2
  6. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/synthesizers/__init__.py +2 -0
  7. sdgym-0.15.2.dev0/sdgym/synthesizers/data_designer.py +346 -0
  8. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/synthesizers/realtabformer.py +14 -0
  9. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0/sdgym.egg-info}/PKG-INFO +13 -5
  10. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym.egg-info/SOURCES.txt +1 -0
  11. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym.egg-info/requires.txt +14 -2
  12. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/tests/test_tasks.py +1 -1
  13. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/LICENSE +0 -0
  14. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/README.md +0 -0
  15. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/_benchmark/__init__.py +0 -0
  16. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/_benchmark/benchmark.py +0 -0
  17. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/_benchmark/credentials_utils.py +0 -0
  18. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/_benchmark_launcher/__init__.py +0 -0
  19. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/_benchmark_launcher/_instance_manager.py +0 -0
  20. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/_benchmark_launcher/_storage_manager.py +0 -0
  21. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/_benchmark_launcher/_validation.py +0 -0
  22. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/_benchmark_launcher/benchmark_base.yaml +0 -0
  23. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/_benchmark_launcher/benchmark_config.py +0 -0
  24. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/_benchmark_launcher/benchmark_launcher.py +0 -0
  25. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/_benchmark_launcher/script.py +0 -0
  26. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/_dataset_utils.py +0 -0
  27. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/benchmark.py +0 -0
  28. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/cli/__init__.py +0 -0
  29. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/cli/__main__.py +0 -0
  30. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/cli/collect.py +0 -0
  31. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/cli/summary.py +0 -0
  32. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/cli/utils.py +0 -0
  33. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/dataset_explorer.py +0 -0
  34. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/datasets.py +0 -0
  35. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/errors.py +0 -0
  36. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/metrics.py +0 -0
  37. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/progress.py +0 -0
  38. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/result_explorer/__init__.py +0 -0
  39. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/result_explorer/result_explorer.py +0 -0
  40. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/result_explorer/result_handler.py +0 -0
  41. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/result_writer.py +0 -0
  42. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/run_benchmark/__init__.py +0 -0
  43. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/run_benchmark/run_benchmark.py +0 -0
  44. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/run_benchmark/upload_benchmark_results.py +0 -0
  45. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/run_benchmark/utils.py +0 -0
  46. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/s3.py +0 -0
  47. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/synthesizers/base.py +0 -0
  48. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/synthesizers/clavaddpm.py +0 -0
  49. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/synthesizers/column.py +0 -0
  50. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/synthesizers/generate.py +0 -0
  51. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/synthesizers/identity.py +0 -0
  52. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/synthesizers/sdv.py +0 -0
  53. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/synthesizers/tabddpm.py +0 -0
  54. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/synthesizers/uniform.py +0 -0
  55. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/synthesizers/utils.py +0 -0
  56. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym/utils.py +0 -0
  57. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym.egg-info/dependency_links.txt +0 -0
  58. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym.egg-info/entry_points.txt +0 -0
  59. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/sdgym.egg-info/top_level.txt +0 -0
  60. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/setup.cfg +0 -0
  61. {sdgym-0.15.1.dev0 → sdgym-0.15.2.dev0}/tests/test_scripts.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sdgym
3
- Version: 0.15.1.dev0
3
+ Version: 0.15.2.dev0
4
4
  Summary: Benchmark tabular synthetic data generators using a variety of datasets
5
5
  Author-email: "DataCebo, Inc." <info@sdv.dev>
6
6
  License-Expression: BUSL-1.1
@@ -14,14 +14,13 @@ Classifier: Development Status :: 2 - Pre-Alpha
14
14
  Classifier: Intended Audience :: Developers
15
15
  Classifier: Natural Language :: English
16
16
  Classifier: Programming Language :: Python :: 3
17
- Classifier: Programming Language :: Python :: 3.9
18
17
  Classifier: Programming Language :: Python :: 3.10
19
18
  Classifier: Programming Language :: Python :: 3.11
20
19
  Classifier: Programming Language :: Python :: 3.12
21
20
  Classifier: Programming Language :: Python :: 3.13
22
21
  Classifier: Programming Language :: Python :: 3.14
23
22
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
24
- Requires-Python: <3.15,>=3.9
23
+ Requires-Python: <3.15,>=3.10
25
24
  Description-Content-Type: text/markdown
26
25
  License-File: LICENSE
27
26
  Requires-Dist: appdirs>=1.3
@@ -67,22 +66,31 @@ Requires-Dist: XlsxWriter>=1.2.8
67
66
  Requires-Dist: rdt>=1.18.2; python_version < "3.14"
68
67
  Requires-Dist: rdt>=1.20.0; python_version >= "3.14"
69
68
  Requires-Dist: sdmetrics>=0.29.0
70
- Requires-Dist: sdv>=1.37.0
69
+ Requires-Dist: sdv<2,>=1.37.0
71
70
  Provides-Extra: dask
72
71
  Requires-Dist: dask; extra == "dask"
73
72
  Requires-Dist: distributed; extra == "dask"
74
73
  Provides-Extra: realtabformer
75
74
  Requires-Dist: realtabformer!=0.2.4,>=0.2.3; extra == "realtabformer"
76
75
  Requires-Dist: torch>=2.6.0; extra == "realtabformer"
77
- Requires-Dist: transformers<4.51; extra == "realtabformer"
78
76
  Provides-Extra: clavaddpm
79
77
  Requires-Dist: faiss-cpu>=1.10.0; python_version < "3.14" and extra == "clavaddpm"
80
78
  Requires-Dist: faiss-cpu>=1.12.0; python_version >= "3.14" and extra == "clavaddpm"
81
79
  Requires-Dist: scipy>=1.9.2; extra == "clavaddpm"
82
80
  Requires-Dist: numpy>=1.25.0; extra == "clavaddpm"
81
+ Provides-Extra: data-designer
82
+ Requires-Dist: data-designer>=0.8; python_version >= "3.10" and extra == "data-designer"
83
+ Requires-Dist: google-api-core<2.36; python_version >= "3.10" and extra == "data-designer"
84
+ Requires-Dist: pandas>=2.3.3; python_version >= "3.10" and extra == "data-designer"
85
+ Requires-Dist: scipy>=1.11.0; python_version >= "3.10" and extra == "data-designer"
86
+ Requires-Dist: transformers>=5.0.0; python_version >= "3.10" and extra == "data-designer"
87
+ Requires-Dist: boto3>=1.34.63; python_version >= "3.10" and extra == "data-designer"
88
+ Requires-Dist: botocore>=1.34.63; python_version >= "3.10" and extra == "data-designer"
89
+ Requires-Dist: pyOpenSSL>=26.4.0; python_version >= "3.10" and extra == "data-designer"
83
90
  Provides-Extra: test
84
91
  Requires-Dist: sdgym[realtabformer]; extra == "test"
85
92
  Requires-Dist: sdgym[clavaddpm]; extra == "test"
93
+ Requires-Dist: sdgym[data_designer]; extra == "test"
86
94
  Requires-Dist: pytest>=6.2.5; extra == "test"
87
95
  Requires-Dist: pytest-cov>=2.6.0; extra == "test"
88
96
  Requires-Dist: jupyter<2,>=1.0.0; extra == "test"
@@ -7,7 +7,6 @@ classifiers = [
7
7
  'Intended Audience :: Developers',
8
8
  'Natural Language :: English',
9
9
  'Programming Language :: Python :: 3',
10
- 'Programming Language :: Python :: 3.9',
11
10
  'Programming Language :: Python :: 3.10',
12
11
  'Programming Language :: Python :: 3.11',
13
12
  'Programming Language :: Python :: 3.12',
@@ -19,7 +18,7 @@ keywords = ['machine learning', 'synthetic data generation', 'benchmark', 'gener
19
18
  dynamic = ['version']
20
19
  license = 'BUSL-1.1'
21
20
  license-files = ['LICENSE']
22
- requires-python = '>=3.9,<3.15'
21
+ requires-python = '>=3.10,<3.15'
23
22
  readme = 'README.md'
24
23
  dependencies = [
25
24
  'appdirs>=1.3',
@@ -65,7 +64,7 @@ dependencies = [
65
64
  "rdt>=1.18.2;python_version<'3.14'",
66
65
  "rdt>=1.20.0;python_version>='3.14'",
67
66
  "sdmetrics>=0.29.0",
68
- "sdv>=1.37.0",
67
+ "sdv>=1.37.0,<2",
69
68
  ]
70
69
 
71
70
  [project.urls]
@@ -83,7 +82,6 @@ dask = ['dask', 'distributed']
83
82
  realtabformer = [
84
83
  'realtabformer>=0.2.3,!=0.2.4',
85
84
  "torch>=2.6.0",
86
- 'transformers<4.51',
87
85
  ]
88
86
  clavaddpm = [
89
87
  "faiss-cpu>=1.10.0;python_version<'3.14'",
@@ -91,9 +89,20 @@ clavaddpm = [
91
89
  'scipy>=1.9.2',
92
90
  'numpy>=1.25.0',
93
91
  ]
92
+ data_designer = [
93
+ "data-designer>=0.8;python_version>='3.10'",
94
+ "google-api-core<2.36;python_version>='3.10'", # requires opentelemetry-api<1.44
95
+ "pandas>=2.3.3;python_version>='3.10'",
96
+ "scipy>=1.11.0;python_version>='3.10'",
97
+ "transformers>=5.0.0;python_version>='3.10'", # requires huggingface-hub>=1
98
+ "boto3>=1.34.63;python_version>='3.10'", # requires urllib3>=2.7
99
+ "botocore>=1.34.63;python_version>='3.10'",
100
+ "pyOpenSSL>=26.4.0;python_version>='3.10'", # requires cryptography>=48
101
+ ]
94
102
  test = [
95
103
  'sdgym[realtabformer]',
96
104
  'sdgym[clavaddpm]',
105
+ 'sdgym[data_designer]',
97
106
  'pytest>=6.2.5',
98
107
  'pytest-cov>=2.6.0',
99
108
  'jupyter>=1.0.0,<2',
@@ -168,7 +177,7 @@ namespaces = false
168
177
  version = {attr = 'sdgym.__version__'}
169
178
 
170
179
  [tool.bumpversion]
171
- current_version = "0.15.1.dev0"
180
+ current_version = "0.15.2.dev0"
172
181
  parse = '(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\.(?P<release>[a-z]+)(?P<candidate>\d+))?'
173
182
  serialize = [
174
183
  '{major}.{minor}.{patch}.{release}{candidate}',
@@ -8,7 +8,7 @@ __author__ = 'DataCebo, Inc.'
8
8
  __copyright__ = 'Copyright (c) 2022 DataCebo, Inc.'
9
9
  __email__ = 'info@sdv.dev'
10
10
  __license__ = 'BSL-1.1'
11
- __version__ = '0.15.1.dev0'
11
+ __version__ = '0.15.2.dev0'
12
12
 
13
13
  import logging
14
14
 
@@ -43,6 +43,7 @@ MODALITY_TO_JOB_SETUP = {
43
43
  'BootstrapSynthesizer',
44
44
  'RealTabFormerSynthesizer',
45
45
  'TabDDPMSynthesizer',
46
+ 'DataDesignerSynthesizer',
46
47
  ],
47
48
  },
48
49
  'multi_table': {
@@ -134,7 +134,7 @@ XGCSynthesizer:
134
134
  to train a model and generate synthetic data similar to the GaussianCopulaSynthesizer.
135
135
  However, it contains some additional features for higher quality modeling.
136
136
 
137
- TabDDOMSynthesizer:
137
+ TabDDPMSynthesizer:
138
138
  library: sdgym
139
139
  organization: Yandex
140
140
  modality: single_table
@@ -152,4 +152,13 @@ ClavaDDPMSynthesizer:
152
152
  description: >
153
153
  The ClavaDDPM model is an extension of the TabDDPM model to handle multi-table datasets.
154
154
  It is based on clustering labels as intermediaries to model relationships between tables,
155
- specifically focusing on foreign key constraints.
155
+ specifically focusing on foreign key constraints.
156
+
157
+ DataDesignerSynthesizer:
158
+ library: data-designer
159
+ organization: Nvidia
160
+ modality: single_table
161
+ type: Statistical and Large Language Models
162
+ description: >
163
+ NVIDIA Data Designer is a configurable framework that uses LLMs, statistical models,
164
+ and customizable samplers to generate synthetic data.
@@ -7,6 +7,7 @@ from sdgym.synthesizers.generate import (
7
7
  )
8
8
  from sdgym.synthesizers.identity import DataIdentity
9
9
  from sdgym.synthesizers.column import ColumnSynthesizer
10
+ from sdgym.synthesizers.data_designer import DataDesignerSynthesizer
10
11
  from sdgym.synthesizers.realtabformer import RealTabFormerSynthesizer
11
12
  from sdgym.synthesizers.tabddpm import TabDDPMSynthesizer
12
13
  from sdgym.synthesizers.clavaddpm import ClavaDDPMSynthesizer
@@ -21,6 +22,7 @@ from sdgym.synthesizers.sdv import create_sdv_synthesizer_class, _get_all_sdv_sy
21
22
  __all__ = [
22
23
  'DataIdentity',
23
24
  'ColumnSynthesizer',
25
+ 'DataDesignerSynthesizer',
24
26
  'UniformSynthesizer',
25
27
  'RealTabFormerSynthesizer',
26
28
  'TabDDPMSynthesizer',
@@ -0,0 +1,346 @@
1
+ """NVIDIA Data Designer integration."""
2
+
3
+ import logging
4
+ import shutil
5
+ import sys
6
+ import tempfile
7
+ import uuid
8
+ from pathlib import Path
9
+
10
+ import numpy as np
11
+ import pandas as pd
12
+ from sdv.metadata import Metadata
13
+
14
+ from sdgym.synthesizers.base import BaselineSynthesizer
15
+
16
+ LOGGER = logging.getLogger(__name__)
17
+
18
+ MIN_PYTHON_VERSION = (3, 10)
19
+ DEFAULT_MODEL_ALIAS = 'text'
20
+ DEFAULT_MODEL_ID = 'nvidia/nvidia-nemotron-nano-9b-v2'
21
+ DEFAULT_MODEL_PROVIDER = 'nvidia'
22
+ DEFAULT_TEMPERATURE = 0.85
23
+ DEFAULT_TOP_P = 0.95
24
+ PII_PLACEHOLDER_PREFIX = 'sdgym-pii-'
25
+ MAX_TEXT_EXAMPLES = 3
26
+ MAX_TEXT_EXAMPLE_LENGTH = 100
27
+
28
+ MISSING_PROPORTION_ATTRIBUTES = (
29
+ 'missing_values_proportion',
30
+ 'missing_proportion',
31
+ 'null_proportion',
32
+ )
33
+ # sdtypes that can be useful as context
34
+ TEXT_CONTEXT_SDTYPES = {'numerical', 'categorical', 'boolean', 'datetime'}
35
+
36
+
37
+ def _import_data_designer():
38
+ if sys.version_info < MIN_PYTHON_VERSION:
39
+ raise ImportError('DataDesignerSynthesizer only supports python >= 3.10')
40
+
41
+ try:
42
+ import data_designer.config as data_designer_config
43
+ except ImportError as exception:
44
+ raise ImportError(
45
+ "To use 'DataDesignerSynthesizer' you have to install the extra "
46
+ "dependencies by running pip install sdgym['data_designer']"
47
+ ) from exception
48
+
49
+ return data_designer_config
50
+
51
+
52
+ def _get_table_metadata(metadata, table_name=None):
53
+ """Return the metadata of ``table_name`` from a ``Metadata`` object."""
54
+ if not isinstance(metadata, Metadata):
55
+ raise TypeError(f'Expected sdv.Metadata, got {type(metadata).__name__}. ')
56
+
57
+ if table_name is None:
58
+ if len(metadata.tables) != 1:
59
+ raise ValueError(
60
+ f'Metadata has {len(metadata.tables)} tables, please provide a `table_name`. '
61
+ 'DataDesignerSynthesizer only supports single table metadata.'
62
+ )
63
+
64
+ table_name = metadata._get_single_table_name()
65
+
66
+ if table_name not in metadata.tables:
67
+ raise ValueError(f"Table '{table_name}' is not present in the metadata.")
68
+
69
+ return metadata.tables[table_name]
70
+
71
+
72
+ def _create_default_model_config(
73
+ dd,
74
+ model_alias,
75
+ model=DEFAULT_MODEL_ID,
76
+ provider=DEFAULT_MODEL_PROVIDER,
77
+ temperature=DEFAULT_TEMPERATURE,
78
+ top_p=DEFAULT_TOP_P,
79
+ ):
80
+
81
+ return dd.ModelConfig(
82
+ alias=model_alias,
83
+ model=model,
84
+ provider=provider,
85
+ inference_parameters=dd.ChatCompletionInferenceParams(temperature=temperature, top_p=top_p),
86
+ )
87
+
88
+
89
+ def _create_categorical_config(dd, column_name, column_data, column_metadata):
90
+ """Map a categorical column to a weighted ``category`` sampler."""
91
+ value_counts = column_data.dropna().value_counts()
92
+ values = column_metadata.get('range_values')
93
+ if values is None:
94
+ values = list(value_counts.index)
95
+
96
+ if not values:
97
+ LOGGER.warning(
98
+ f"Column '{column_name}' has no observed values, using a placeholder sampler."
99
+ )
100
+ return _create_placeholder_config(dd, column_name)
101
+
102
+ values = [value.item() if isinstance(value, np.generic) else value for value in values]
103
+ weights = [float(value_counts.get(value, 0)) for value in values]
104
+ params = dd.CategorySamplerParams(values=values, weights=weights if sum(weights) else None)
105
+ return dd.SamplerColumnConfig(
106
+ name=column_name, sampler_type=dd.SamplerType.CATEGORY, params=params
107
+ )
108
+
109
+
110
+ def _create_boolean_config(dd, column_name, column_data):
111
+ """Map a boolean column to a ``bernoulli`` sampler."""
112
+ values = column_data.dropna()
113
+ probability = float(values.astype(bool).mean()) if not values.empty else 0.5
114
+ params = dd.BernoulliSamplerParams(p=probability)
115
+ return dd.SamplerColumnConfig(
116
+ name=column_name, sampler_type=dd.SamplerType.BERNOULLI, params=params
117
+ )
118
+
119
+
120
+ def _get_decimal_places(values):
121
+ """Return the largest number of decimal places observed in ``values``."""
122
+ decimals = 0
123
+ for value in values.head(1000):
124
+ _, _, fraction = repr(float(value)).partition('.')
125
+ if fraction and fraction != '0':
126
+ decimals = max(decimals, len(fraction))
127
+
128
+ return decimals
129
+
130
+
131
+ def _create_numerical_config(dd, column_name, column_data, column_metadata):
132
+ """Map a numerical column to a ``uniform`` sampler."""
133
+ values = pd.to_numeric(column_data, errors='coerce').dropna()
134
+ values_empty = values.empty
135
+ has_range = 'range_min' in column_metadata and 'range_max' in column_metadata
136
+ if values_empty and not has_range:
137
+ LOGGER.warning(
138
+ f"Column '{column_name}' has no numeric values, sampling from normal distribution."
139
+ )
140
+ return dd.SamplerColumnConfig(
141
+ name=column_name,
142
+ sampler_type=dd.SamplerType.GAUSSIAN,
143
+ params=dd.GaussianSamplerParams(mean=0, stddev=1),
144
+ )
145
+
146
+ low = column_metadata.get('range_min', values.min())
147
+ high = column_metadata.get('range_max', values.max())
148
+ decimal_places = column_metadata.get('decimal_places', _get_decimal_places(values))
149
+ is_integer = decimal_places == 0
150
+
151
+ params = dd.UniformSamplerParams(
152
+ low=float(low), high=float(high), decimal_places=decimal_places
153
+ )
154
+ return dd.SamplerColumnConfig(
155
+ name=column_name,
156
+ sampler_type=dd.SamplerType.UNIFORM,
157
+ params=params,
158
+ convert_to='int' if is_integer else None,
159
+ )
160
+
161
+
162
+ def _create_datetime_config(dd, column_name, column_data, column_metadata):
163
+ """Map a datetime column to a ``datetime`` sampler."""
164
+ datetime_format = column_metadata.get('datetime_format')
165
+ values = pd.to_datetime(column_data, format=datetime_format, errors='coerce').dropna()
166
+ start = pd.to_datetime(column_metadata.get('range_min', values.min()), format=datetime_format)
167
+ end = pd.to_datetime(column_metadata.get('range_max', values.max()), format=datetime_format)
168
+
169
+ if pd.isna(start) and pd.isna(end):
170
+ LOGGER.warning(
171
+ f"Column '{column_name}' has no parseable datetimes, using a placeholder sampler."
172
+ )
173
+ return _create_placeholder_config(dd, column_name)
174
+
175
+ elif pd.isna(start):
176
+ start = end
177
+ elif pd.isna(end):
178
+ end = start
179
+
180
+ output_format = datetime_format or '%Y-%m-%d %H:%M:%S'
181
+ params = dd.DatetimeSamplerParams(
182
+ start=start.strftime(output_format), end=end.strftime(output_format)
183
+ )
184
+ return dd.SamplerColumnConfig(
185
+ name=column_name, sampler_type=dd.SamplerType.DATETIME, params=params
186
+ )
187
+
188
+
189
+ def _create_id_config(dd, column_name):
190
+ """Map an id column to a ``uuid`` sampler, no other id sampler is available."""
191
+ return dd.SamplerColumnConfig(
192
+ name=column_name, sampler_type=dd.SamplerType.UUID, params=dd.UUIDSamplerParams()
193
+ )
194
+
195
+
196
+ def _create_placeholder_config(dd, column_name):
197
+ """Map unknown or unsupported pii columns to short anonymized placeholders."""
198
+ params = dd.UUIDSamplerParams(prefix=PII_PLACEHOLDER_PREFIX, short_form=True)
199
+ return dd.SamplerColumnConfig(name=column_name, sampler_type=dd.SamplerType.UUID, params=params)
200
+
201
+
202
+ def _create_text_config(dd, column_name, column_data, model_alias, context_columns):
203
+ """Map a text column to an LLM generated column conditioned on the rest of the row."""
204
+ examples = []
205
+ for value in column_data.dropna().astype(str).unique()[:MAX_TEXT_EXAMPLES]:
206
+ examples.append(repr(value[:MAX_TEXT_EXAMPLE_LENGTH]))
207
+
208
+ prompt = (
209
+ 'You are a helpful assistant that generates synthetic data.'
210
+ f"Generate a realistic value for the column '{column_name}' of a tabular dataset."
211
+ )
212
+ if examples:
213
+ prompt += f' Here are a few examples from this column: {", ".join(examples)}.'
214
+
215
+ if context_columns:
216
+ row = ', '.join(f'{{ {name} }}' for name in context_columns)
217
+ prompt += f' Refer to the values in these columns for context: {row}.'
218
+
219
+ prompt += ' Respond with the value only, without any explanation.'
220
+ return dd.LLMTextColumnConfig(name=column_name, prompt=prompt, model_alias=model_alias)
221
+
222
+
223
+ def create_data_designer_config(
224
+ data,
225
+ metadata,
226
+ table_name=None,
227
+ model_alias=DEFAULT_MODEL_ALIAS,
228
+ model=DEFAULT_MODEL_ID,
229
+ provider=DEFAULT_MODEL_PROVIDER,
230
+ temperature=DEFAULT_TEMPERATURE,
231
+ top_p=DEFAULT_TOP_P,
232
+ ):
233
+ """Map a single table dataset and its metadata to a Data Designer config builder.
234
+
235
+ Args:
236
+ data (pd.DataFrame):
237
+ The real data. Used to fit the sampler parameters that the metadata does not
238
+ provide (frequencies, ranges, boolean rates) and to pick text examples.
239
+ metadata (sdv.Metadata):
240
+ Metadata describing the data. If range values are not present, they are
241
+ extracted directly from data.
242
+ table_name (str or None):
243
+ The table to map when the metadata has more than one table. Defaults to the only
244
+ table.
245
+ model_alias (str):
246
+ The model alias used by LLM generated text columns. Defaults to 'text'.
247
+ model (str):
248
+ The model identifier used for inference. This must correspond to the
249
+ served model name configured by the specified provider.
250
+ provider (str):
251
+ The provider identifier used to route inference requests to the specified model.
252
+ temperature (float):
253
+ Sampling temperature of the model used by LLM generated text columns. Higher
254
+ values produce more varied text. Defaults to 0.85.
255
+ top_p (float):
256
+ Nucleus sampling probability of the model used by LLM generated text columns.
257
+ Defaults to 0.95.
258
+
259
+ Returns:
260
+ DataDesignerConfigBuilder:
261
+ A builder holding one column config per metadata column.
262
+ """
263
+ dd = _import_data_designer()
264
+ table_metadata = _get_table_metadata(metadata, table_name)
265
+ model_configs = [
266
+ _create_default_model_config(dd, model_alias, model, provider, temperature, top_p)
267
+ ]
268
+
269
+ context_columns = [
270
+ name
271
+ for name, column_meta in table_metadata.columns.items()
272
+ if column_meta['sdtype'] in TEXT_CONTEXT_SDTYPES
273
+ ]
274
+
275
+ column_configs = []
276
+ for column_name, column_metadata in table_metadata.columns.items():
277
+ sdtype = column_metadata['sdtype']
278
+ column_data = data[column_name]
279
+ if sdtype == 'boolean':
280
+ config = _create_boolean_config(dd, column_name, column_data)
281
+ elif sdtype == 'numerical':
282
+ config = _create_numerical_config(dd, column_name, column_data, column_metadata)
283
+ elif sdtype == 'datetime':
284
+ config = _create_datetime_config(dd, column_name, column_data, column_metadata)
285
+ elif sdtype == 'id':
286
+ config = _create_id_config(dd, column_name)
287
+ elif sdtype == 'text':
288
+ config = _create_text_config(dd, column_name, column_data, model_alias, context_columns)
289
+ else:
290
+ config = _create_categorical_config(dd, column_name, column_data, column_metadata)
291
+
292
+ column_configs.append(config)
293
+
294
+ builder = dd.DataDesignerConfigBuilder(model_configs=model_configs)
295
+ for config in column_configs:
296
+ builder.add_column(config)
297
+
298
+ return builder
299
+
300
+
301
+ class DataDesignerSynthesizer(BaselineSynthesizer):
302
+ """Custom wrapper for the DataDesigner synthesizer to make it work with SDGym."""
303
+
304
+ LOGGER = logging.getLogger(__name__)
305
+ _MODEL_KWARGS = None
306
+ _MODALITY_FLAG = 'single_table'
307
+
308
+ def _fit(self, data, metadata):
309
+ table_name = metadata._get_single_table_name()
310
+ metadata.validate()
311
+ metadata.validate_data({table_name: data})
312
+
313
+ model_kwargs = self._MODEL_KWARGS.copy() if self._MODEL_KWARGS else {}
314
+ self._artifact_path = model_kwargs.pop('artifact_path', None)
315
+ self._cleanup_artifacts = model_kwargs.pop('cleanup_artifacts', True)
316
+ self._config_builder = create_data_designer_config(data, metadata, **model_kwargs)
317
+
318
+ def _sample_from_synthesizer(self, synthesizer, n_sample):
319
+ """Sample synthetic data with specified sample count."""
320
+ try:
321
+ from data_designer.interface import DataDesigner
322
+ except Exception as exception:
323
+ raise ImportError(
324
+ "To use 'DataDesignerSynthesizer' you have to install the extra "
325
+ "dependencies by running pip install sdgym['data_designer']"
326
+ ) from exception
327
+
328
+ is_temporary = synthesizer._artifact_path is None
329
+ if is_temporary:
330
+ artifact_path = Path(tempfile.mkdtemp(prefix='sdgym-data-designer-'))
331
+ else:
332
+ artifact_path = Path(synthesizer._artifact_path)
333
+
334
+ # A unique name keeps concurrent or repeated sample calls from sharing a folder.
335
+ dataset_name = f'dataset-{uuid.uuid4().hex}'
336
+ try:
337
+ output = DataDesigner(artifact_path=artifact_path).create(
338
+ synthesizer._config_builder, num_records=n_sample, dataset_name=dataset_name
339
+ )
340
+ return output.load_dataset()
341
+ finally:
342
+ if synthesizer._cleanup_artifacts:
343
+ to_remove = artifact_path if is_temporary else artifact_path / dataset_name
344
+ shutil.rmtree(to_remove, ignore_errors=True)
345
+ else:
346
+ self.LOGGER.info(f'Data Designer artifacts kept in {artifact_path / dataset_name}')
@@ -1,6 +1,7 @@
1
1
  """REaLTabFormer integration."""
2
2
 
3
3
  import contextlib
4
+ import dataclasses
4
5
  import logging
5
6
  from functools import partialmethod
6
7
 
@@ -8,6 +9,8 @@ import tqdm
8
9
 
9
10
  from sdgym.synthesizers.base import BaselineSynthesizer
10
11
 
12
+ REMOVED_TRAINING_ARGS = ('overwrite_output_dir',)
13
+
11
14
 
12
15
  @contextlib.contextmanager
13
16
  def prevent_tqdm_output():
@@ -19,6 +22,16 @@ def prevent_tqdm_output():
19
22
  tqdm.__init__ = partialmethod(tqdm.__init__, disable=False)
20
23
 
21
24
 
25
+ def _remove_unsupported_training_args(model):
26
+ """Drop deprecated args that are no longer used by transformers."""
27
+ from transformers import TrainingArguments
28
+
29
+ supported = {field.name for field in dataclasses.fields(TrainingArguments)}
30
+ for name in REMOVED_TRAINING_ARGS:
31
+ if name not in supported:
32
+ model.training_args_kwargs.pop(name, None)
33
+
34
+
22
35
  class RealTabFormerSynthesizer(BaselineSynthesizer):
23
36
  """Custom wrapper for the REaLTabFormer synthesizer to make it work with SDGym."""
24
37
 
@@ -39,6 +52,7 @@ class RealTabFormerSynthesizer(BaselineSynthesizer):
39
52
  with prevent_tqdm_output():
40
53
  model_kwargs = self._MODEL_KWARGS.copy() if self._MODEL_KWARGS else {}
41
54
  model = REaLTabFormer(model_type='tabular', **model_kwargs)
55
+ _remove_unsupported_training_args(model)
42
56
  model.fit(data)
43
57
 
44
58
  self._internal_synthesizer = model
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sdgym
3
- Version: 0.15.1.dev0
3
+ Version: 0.15.2.dev0
4
4
  Summary: Benchmark tabular synthetic data generators using a variety of datasets
5
5
  Author-email: "DataCebo, Inc." <info@sdv.dev>
6
6
  License-Expression: BUSL-1.1
@@ -14,14 +14,13 @@ Classifier: Development Status :: 2 - Pre-Alpha
14
14
  Classifier: Intended Audience :: Developers
15
15
  Classifier: Natural Language :: English
16
16
  Classifier: Programming Language :: Python :: 3
17
- Classifier: Programming Language :: Python :: 3.9
18
17
  Classifier: Programming Language :: Python :: 3.10
19
18
  Classifier: Programming Language :: Python :: 3.11
20
19
  Classifier: Programming Language :: Python :: 3.12
21
20
  Classifier: Programming Language :: Python :: 3.13
22
21
  Classifier: Programming Language :: Python :: 3.14
23
22
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
24
- Requires-Python: <3.15,>=3.9
23
+ Requires-Python: <3.15,>=3.10
25
24
  Description-Content-Type: text/markdown
26
25
  License-File: LICENSE
27
26
  Requires-Dist: appdirs>=1.3
@@ -67,22 +66,31 @@ Requires-Dist: XlsxWriter>=1.2.8
67
66
  Requires-Dist: rdt>=1.18.2; python_version < "3.14"
68
67
  Requires-Dist: rdt>=1.20.0; python_version >= "3.14"
69
68
  Requires-Dist: sdmetrics>=0.29.0
70
- Requires-Dist: sdv>=1.37.0
69
+ Requires-Dist: sdv<2,>=1.37.0
71
70
  Provides-Extra: dask
72
71
  Requires-Dist: dask; extra == "dask"
73
72
  Requires-Dist: distributed; extra == "dask"
74
73
  Provides-Extra: realtabformer
75
74
  Requires-Dist: realtabformer!=0.2.4,>=0.2.3; extra == "realtabformer"
76
75
  Requires-Dist: torch>=2.6.0; extra == "realtabformer"
77
- Requires-Dist: transformers<4.51; extra == "realtabformer"
78
76
  Provides-Extra: clavaddpm
79
77
  Requires-Dist: faiss-cpu>=1.10.0; python_version < "3.14" and extra == "clavaddpm"
80
78
  Requires-Dist: faiss-cpu>=1.12.0; python_version >= "3.14" and extra == "clavaddpm"
81
79
  Requires-Dist: scipy>=1.9.2; extra == "clavaddpm"
82
80
  Requires-Dist: numpy>=1.25.0; extra == "clavaddpm"
81
+ Provides-Extra: data-designer
82
+ Requires-Dist: data-designer>=0.8; python_version >= "3.10" and extra == "data-designer"
83
+ Requires-Dist: google-api-core<2.36; python_version >= "3.10" and extra == "data-designer"
84
+ Requires-Dist: pandas>=2.3.3; python_version >= "3.10" and extra == "data-designer"
85
+ Requires-Dist: scipy>=1.11.0; python_version >= "3.10" and extra == "data-designer"
86
+ Requires-Dist: transformers>=5.0.0; python_version >= "3.10" and extra == "data-designer"
87
+ Requires-Dist: boto3>=1.34.63; python_version >= "3.10" and extra == "data-designer"
88
+ Requires-Dist: botocore>=1.34.63; python_version >= "3.10" and extra == "data-designer"
89
+ Requires-Dist: pyOpenSSL>=26.4.0; python_version >= "3.10" and extra == "data-designer"
83
90
  Provides-Extra: test
84
91
  Requires-Dist: sdgym[realtabformer]; extra == "test"
85
92
  Requires-Dist: sdgym[clavaddpm]; extra == "test"
93
+ Requires-Dist: sdgym[data_designer]; extra == "test"
86
94
  Requires-Dist: pytest>=6.2.5; extra == "test"
87
95
  Requires-Dist: pytest-cov>=2.6.0; extra == "test"
88
96
  Requires-Dist: jupyter<2,>=1.0.0; extra == "test"
@@ -47,6 +47,7 @@ sdgym/synthesizers/__init__.py
47
47
  sdgym/synthesizers/base.py
48
48
  sdgym/synthesizers/clavaddpm.py
49
49
  sdgym/synthesizers/column.py
50
+ sdgym/synthesizers/data_designer.py
50
51
  sdgym/synthesizers/generate.py
51
52
  sdgym/synthesizers/identity.py
52
53
  sdgym/synthesizers/realtabformer.py
@@ -11,7 +11,7 @@ tabulate<0.9,>=0.8.3
11
11
  tqdm>=4.66.3
12
12
  XlsxWriter>=1.2.8
13
13
  sdmetrics>=0.29.0
14
- sdv>=1.37.0
14
+ sdv<2,>=1.37.0
15
15
 
16
16
  [:python_version < "3.10"]
17
17
  numpy>=1.22.2
@@ -78,6 +78,18 @@ faiss-cpu>=1.12.0
78
78
  dask
79
79
  distributed
80
80
 
81
+ [data_designer]
82
+
83
+ [data_designer:python_version >= "3.10"]
84
+ data-designer>=0.8
85
+ google-api-core<2.36
86
+ pandas>=2.3.3
87
+ scipy>=1.11.0
88
+ transformers>=5.0.0
89
+ boto3>=1.34.63
90
+ botocore>=1.34.63
91
+ pyOpenSSL>=26.4.0
92
+
81
93
  [dev]
82
94
  sdgym[dask,test]
83
95
  build<2,>=1.0.0
@@ -97,11 +109,11 @@ rundoc<0.5,>=0.4.3
97
109
  [realtabformer]
98
110
  realtabformer!=0.2.4,>=0.2.3
99
111
  torch>=2.6.0
100
- transformers<4.51
101
112
 
102
113
  [test]
103
114
  sdgym[realtabformer]
104
115
  sdgym[clavaddpm]
116
+ sdgym[data_designer]
105
117
  pytest>=6.2.5
106
118
  pytest-cov>=2.6.0
107
119
  jupyter<2,>=1.0.0
@@ -121,7 +121,7 @@ def _get_example_pyproject_dict():
121
121
  ],
122
122
  },
123
123
  'readme': 'README.md',
124
- 'requires-python': '>=3.9,<3.15',
124
+ 'requires-python': '>=3.10,<3.15',
125
125
  },
126
126
  'tool': {
127
127
  'bumpversion': {
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes