amsdal_cli 0.4.14__py3-none-any.whl → 0.4.16__py3-none-any.whl

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.
@@ -1185,4 +1185,39 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1185
1185
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1186
1186
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1187
1187
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1188
- THE SOFTWARE.
1188
+ THE SOFTWARE.
1189
+
1190
+ ## click **v8**
1191
+
1192
+ ### [https://github.com/pallets/click/](https://github.com/pallets/click/)
1193
+
1194
+ ### **BSD-3-Clause license**
1195
+
1196
+ Copyright 2014 Pallets
1197
+
1198
+ Redistribution and use in source and binary forms, with or without
1199
+ modification, are permitted provided that the following conditions are
1200
+ met:
1201
+
1202
+ 1. Redistributions of source code must retain the above copyright
1203
+ notice, this list of conditions and the following disclaimer.
1204
+
1205
+ 2. Redistributions in binary form must reproduce the above copyright
1206
+ notice, this list of conditions and the following disclaimer in the
1207
+ documentation and/or other materials provided with the distribution.
1208
+
1209
+ 3. Neither the name of the copyright holder nor the names of its
1210
+ contributors may be used to endorse or promote products derived from
1211
+ this software without specific prior written permission.
1212
+
1213
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1214
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1215
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
1216
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1217
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1218
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
1219
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1220
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
1221
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
1222
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1223
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
amsdal_cli/__about__.py CHANGED
@@ -1,4 +1,4 @@
1
1
  # SPDX-FileCopyrightText: 2023-present
2
2
  #
3
3
  # SPDX-License-Identifier: AMSDAL End User License Agreement
4
- __version__ = '0.4.14'
4
+ __version__ = '0.4.16'
@@ -16,9 +16,9 @@ from amsdal_cli.commands.generate.enums import TestType
16
16
  def generate_tests(
17
17
  ctx: typer.Context,
18
18
  model_name: str = typer.Option(..., help='The model name. It should be provided in PascalCase.'),
19
- test_type: TestType = typer.Option(TestType.UNIT, help='The type of test to generate.'), # noqa: B008
19
+ test_type: TestType = typer.Option(TestType.UNIT.value, help='The type of test to generate.'), # noqa: B008
20
20
  test_data_type: TestDataType = typer.Option( # noqa: B008
21
- TestDataType.DYNAMIC,
21
+ TestDataType.DYNAMIC.value,
22
22
  help='The type of test data to generate.',
23
23
  ),
24
24
  config: Annotated[Path, typer.Option(..., '--config', '-c')] = None, # type: ignore # noqa: RUF013
@@ -108,7 +108,11 @@ def object_init_call(
108
108
  ) -> ast.Call:
109
109
  from amsdal_cli.commands.generate.utils.tests.type_utils import keywords_for_schema
110
110
 
111
- imports_set.add((f'models.{model_name_snake_case}', object_schema.title))
111
+ if cli_config.models_format == ModelsFormat.PY:
112
+ model_class = find_model_class('models', object_schema.title)
113
+ imports_set.add((model_class.__module__, object_schema.title))
114
+ else:
115
+ imports_set.add((f'models.{model_name_snake_case}', object_schema.title))
112
116
 
113
117
  return ast.Call(
114
118
  func=ast.Name(id=object_schema.title, ctx=ast.Load()),
@@ -211,7 +211,7 @@ def apply_migrations(
211
211
  ] = None, # type: ignore[assignment]
212
212
  build_dir: Annotated[Path, typer.Option(..., '--build-dir', '-b')] = Path('.'),
213
213
  *,
214
- module_type: Annotated[ModuleType, typer.Option(..., '--module', '-m')] = ModuleType.USER,
214
+ module_type: Annotated[ModuleType, typer.Option(..., '--module', '-m')] = ModuleType.USER.value, # type: ignore
215
215
  fake: Annotated[bool, typer.Option('--fake', '-f')] = False,
216
216
  config: Annotated[Path, typer.Option(..., '--config', '-c')] = None, # type: ignore # noqa: RUF013
217
217
  ) -> None:
@@ -122,7 +122,7 @@ def make_migrations(
122
122
  build_dir: Annotated[Path, typer.Option('--build-dir', '-b')] = Path('.'),
123
123
  *,
124
124
  name: Annotated[str, typer.Option('--name', '-n', help='Migration name')] = None, # type: ignore # noqa: RUF013
125
- is_data: Annotated[bool, typer.Option('--data', '-d', is_flag=True, help='Create data migration')] = False,
125
+ is_data: Annotated[bool, typer.Option('--data', '-d', help='Create data migration')] = False,
126
126
  config: Annotated[Path, typer.Option('--config', '-c')] = None, # type: ignore # noqa: RUF013
127
127
  ) -> None:
128
128
  """
@@ -264,6 +264,8 @@ async def _async_restore_models(app_source_path: Path, cli_config: 'CliConfig')
264
264
 
265
265
  def _restore_state_db(cli_config: 'CliConfig', config_path: Path | None) -> None:
266
266
  from amsdal_data.connections.constants import SECONDARY_PARTITION_KEY
267
+ from amsdal_data.connections.historical.data_query_transform import META_FOREIGN_KEYS
268
+ from amsdal_data.connections.historical.data_query_transform import META_PRIMARY_KEY_FIELDS
267
269
  from amsdal_data.utils import object_schema_to_glue_schema
268
270
  from amsdal_utils.config.manager import AmsdalConfigManager
269
271
 
@@ -277,6 +279,12 @@ def _restore_state_db(cli_config: 'CliConfig', config_path: Path | None) -> None
277
279
 
278
280
  class_object_ref, class_object_meta_ref = _get_class_object_reference(lakehouse_connection)
279
281
  model_pks, model_fks, model_m2ms = _fetch_model_pks_and_fks(lakehouse_connection, class_object_ref)
282
+
283
+ expected_m2m_tables: set[str] = set()
284
+ for model_name, m2m_list in model_m2ms.items():
285
+ for _, m2m_value in m2m_list.items():
286
+ expected_m2m_tables.add(f'{model_name}{m2m_value[1]}')
287
+
280
288
  user_schemas = _get_user_schemas(
281
289
  lakehouse_connection,
282
290
  class_object_ref,
@@ -287,7 +295,8 @@ def _restore_state_db(cli_config: 'CliConfig', config_path: Path | None) -> None
287
295
  user_scheams_with_tries = [(table_ref, schema, 0) for table_ref, schema in user_schemas]
288
296
  refs_by_name = {table_ref.name: table_ref for table_ref, _ in user_schemas}
289
297
 
290
- m2m_all_data = []
298
+ m2m_schemas = [schema for schema in user_schemas if schema[0].name in expected_m2m_tables]
299
+
291
300
  while user_scheams_with_tries:
292
301
  table_ref, schema, current_iteration = user_scheams_with_tries.pop(0)
293
302
  rprint(rich_info(f'Restoring {table_ref.name}'))
@@ -316,7 +325,7 @@ def _restore_state_db(cli_config: 'CliConfig', config_path: Path | None) -> None
316
325
 
317
326
  from amsdal_data.connections.historical.data_query_transform import META_CLASS_NAME
318
327
 
319
- data, m2m_data = _build_data(
328
+ data, _ = _build_data(
320
329
  item,
321
330
  model_name=table_ref.metadata[META_CLASS_NAME], # type: ignore[index]
322
331
  model_pks=model_pks,
@@ -325,7 +334,6 @@ def _restore_state_db(cli_config: 'CliConfig', config_path: Path | None) -> None
325
334
  refs_by_name=refs_by_name,
326
335
  )
327
336
 
328
- m2m_all_data.extend(m2m_data)
329
337
  state_connection.run_mutations(
330
338
  mutations=[
331
339
  glue.InsertData(
@@ -339,12 +347,79 @@ def _restore_state_db(cli_config: 'CliConfig', config_path: Path | None) -> None
339
347
  ],
340
348
  )
341
349
  rprint('.', end='')
350
+
342
351
  rprint('Inserting m2m data...')
352
+ m2m_all_data = []
353
+ for schema_ref, schema in m2m_schemas:
354
+ _datas = []
355
+ _objects = lakehouse_connection.query(glue.QueryStatement(table=schema_ref))
356
+ field1, field2 = schema.required
357
+ prop1 = schema.properties[field1] # type: ignore[index]
358
+ prop2 = schema.properties[field2] # type: ignore[index]
359
+
360
+ rprint(rich_info(f'Found {len(_objects)} m2m objects for {schema_ref.name}...'))
361
+ for _item in _objects:
362
+ obj_id_1 = _item.data[field1]['ref']['object_id']
363
+ obj_id_2 = _item.data[field2]['ref']['object_id']
364
+ _datas.append(
365
+ glue.Data(
366
+ data={
367
+ f'{field1}_partition_key': obj_id_1,
368
+ f'{field2}_partition_key': obj_id_2,
369
+ },
370
+ metadata={
371
+ META_PRIMARY_KEY_FIELDS: {
372
+ f'{field1}_partition_key': str,
373
+ f'{field2}_partition_key': str,
374
+ },
375
+ META_FOREIGN_KEYS: {
376
+ f'{field1}_partition_key': {
377
+ 'ref': {
378
+ 'resource': 'statedb',
379
+ 'class_name': prop1.type,
380
+ 'object_id': obj_id_1,
381
+ 'class_version': 'LATEST',
382
+ 'object_version': 'LATEST',
383
+ },
384
+ },
385
+ f'{field2}_partition_key': {
386
+ 'ref': {
387
+ 'resource': 'statedb',
388
+ 'class_name': prop2.type,
389
+ 'object_id': obj_id_2,
390
+ 'class_version': 'LATEST',
391
+ 'object_version': 'LATEST',
392
+ },
393
+ },
394
+ },
395
+ },
396
+ )
397
+ )
398
+
399
+ if _datas:
400
+ m2m_all_data.append(
401
+ glue.InsertData(
402
+ schema=glue.SchemaReference(
403
+ name=schema_ref.name,
404
+ version=glue.Version.LATEST,
405
+ metadata=schema_ref.metadata,
406
+ ),
407
+ data=_datas,
408
+ )
409
+ )
343
410
  for _m2m_data in m2m_all_data:
344
- try:
345
- state_connection.run_mutations(mutations=[_m2m_data])
346
- except Exception:
347
- rprint('Error inserting m2m data')
411
+ for data in _m2m_data.data:
412
+ try:
413
+ state_connection.run_mutations(
414
+ mutations=[
415
+ glue.InsertData(
416
+ schema=_m2m_data.schema,
417
+ data=[data],
418
+ ),
419
+ ]
420
+ )
421
+ except Exception:
422
+ rprint('Error inserting m2m data')
348
423
 
349
424
  rprint(rich_success('Done! All classes are restored.'))
350
425
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: amsdal_cli
3
- Version: 0.4.14
3
+ Version: 0.4.16
4
4
  Summary: CLI for AMSDAL framework
5
5
  Project-URL: Documentation, https://pypi.org/project/amsdal_cli/#readme
6
6
  Project-URL: Issues, https://pypi.org/project/amsdal_cli/
@@ -122,13 +122,14 @@ Classifier: Programming Language :: Python :: Implementation :: CPython
122
122
  Classifier: Programming Language :: Python :: Implementation :: PyPy
123
123
  Requires-Python: >=3.11
124
124
  Requires-Dist: amsdal-server==0.4.*
125
+ Requires-Dist: click<8.2.0
125
126
  Requires-Dist: faker==27.*
126
127
  Requires-Dist: gitpython~=3.1
127
128
  Requires-Dist: jinja2~=3.1
128
129
  Requires-Dist: pydantic-settings~=2.2
129
130
  Requires-Dist: pydantic~=2.3
130
- Requires-Dist: rich~=13.9
131
- Requires-Dist: typer~=0.15.2
131
+ Requires-Dist: rich~=14.0
132
+ Requires-Dist: typer~=0.15.3
132
133
  Requires-Dist: watchfiles~=0.21
133
134
  Description-Content-Type: text/markdown
134
135
 
@@ -1,5 +1,5 @@
1
- amsdal_cli/Third-Party Materials - AMSDAL Dependencies - License Notices.md,sha256=eHOIhsC6pZv3Wf8aKfaBNJhVi20gM6Rm2PakZTrdIOQ,66641
2
- amsdal_cli/__about__.py,sha256=wXplutfyWxsByTpCqDxH2K23UsxxTLWbEWChA8Fk9CE,125
1
+ amsdal_cli/Third-Party Materials - AMSDAL Dependencies - License Notices.md,sha256=uHJlGG0D4tbpUi8cq-497NNO9ltQ67a5448k-T14HTw,68241
2
+ amsdal_cli/__about__.py,sha256=CNkKcTivBzCdpiOZg2Fy-UDtB7Hu79U3tfy8RCNecAQ,125
3
3
  amsdal_cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  amsdal_cli/app.py,sha256=_ucuLT5ospf1ifFKEG0IMfVnxKjnvPUQ4iMhkvOfCrc,466
5
5
  amsdal_cli/main.py,sha256=LtH-BD1eJrAUecjKzC8Gx7kYFUstOMH1erdeJUVqFB8,144
@@ -108,7 +108,7 @@ amsdal_cli/commands/generate/sub_commands/generate_model.py,sha256=5IgbkMqPHBBHI
108
108
  amsdal_cli/commands/generate/sub_commands/generate_modifier.py,sha256=NyN7vMTBGaQv6u815WT1lqAlqI4xP1AmIZWq5edZ-5g,1426
109
109
  amsdal_cli/commands/generate/sub_commands/generate_permission.py,sha256=gfRhZsnNnd_m_HxdOCB8C22tbMkopg2FTKo-T68b13s,2824
110
110
  amsdal_cli/commands/generate/sub_commands/generate_property.py,sha256=XrCjf48oEzuMPqsTuC5Qsn1WbIQzUVW8BNOmXssfUM8,1599
111
- amsdal_cli/commands/generate/sub_commands/generate_tests.py,sha256=5AwhsfAFCOnV-R6FTW7cqECJbw36gK5ixEv7N7Do5zM,4606
111
+ amsdal_cli/commands/generate/sub_commands/generate_tests.py,sha256=9n237ZMWzxp9Bq-QooFeynG_jDmjA42EBJkRt4S3AsE,4618
112
112
  amsdal_cli/commands/generate/sub_commands/generate_transaction.py,sha256=hBHceRNqqxVVqIBmMkMOcRG5AM_PB3Pc7ABdm5oeytE,1640
113
113
  amsdal_cli/commands/generate/templates/async_transaction.pyt,sha256=HDnJpIzSuf5h0lYLXDYv_w4LqjJNEl6FMybeT9A19uI,173
114
114
  amsdal_cli/commands/generate/templates/hook.pyt,sha256=nqToFKu6GIxrXWlpg5IN9rK8nkZ07F4sH-aZEQaTfpY,261
@@ -125,7 +125,7 @@ amsdal_cli/commands/generate/utils/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5
125
125
  amsdal_cli/commands/generate/utils/tests/async_mode_utils.py,sha256=iub84Pj5TMa38W90Pr5HgkFQLXpUdbmcm9HOx98Oh6o,309
126
126
  amsdal_cli/commands/generate/utils/tests/conftest_utils.py,sha256=8KzHtDh7eQGghhj5aZkY7Mu2rrlkBgM4Khf857iGG1Y,838
127
127
  amsdal_cli/commands/generate/utils/tests/function_utils.py,sha256=Bkk9JDbANX2aSreNRr1Bste5rPwVKc2HV5xLFg2dQK4,496
128
- amsdal_cli/commands/generate/utils/tests/model_utils.py,sha256=EjxZ3AH8ElHndpwkfFa0GUw1cMgYBcHQuzMofusgb7A,3844
128
+ amsdal_cli/commands/generate/utils/tests/model_utils.py,sha256=CBfR9AcL6Q1boEejjmOD16F0kgJFdIjYYWNE3vQMkfE,4051
129
129
  amsdal_cli/commands/generate/utils/tests/type_utils.py,sha256=PkPmSvLCKOK5wWw1Q9oVMUZ0nUpHEtj6PlBsO7enmzY,9247
130
130
  amsdal_cli/commands/generate/utils/tests/unit.py,sha256=KRqBhk_jy_1vp0RZub7HdYxfhn3Bra2v0heDNNPldeE,27741
131
131
  amsdal_cli/commands/generate/utils/tests/templates/async/conftest.py,sha256=9GfoV_HzwuWtglI7uz0fP5_pOsPk2f56elaoinuPa80,1632
@@ -135,9 +135,9 @@ amsdal_cli/commands/migrations/app.py,sha256=0HsKjZ5D2j9xkOi2Fuvs3VdlhWyQnS8XJ6p
135
135
  amsdal_cli/commands/migrations/command.py,sha256=jlpdYZAc02ZUBxSdzGSzkDxEb1nlHNzoq05FdRCSzus,206
136
136
  amsdal_cli/commands/migrations/constants.py,sha256=846-DQ-Iqcxw2akd5aBAmbnXHDmRFqEKu6vai2ZFBkU,35
137
137
  amsdal_cli/commands/migrations/sub_commands/__init__.py,sha256=_rWbDyY3DPdN-6vE60djCtHejvSkl6d1e2Z4ScM52bo,976
138
- amsdal_cli/commands/migrations/sub_commands/apply.py,sha256=26wMVtzBpJawbFPpiXSUGItmzd1XORymcIBgbonVZgw,9475
138
+ amsdal_cli/commands/migrations/sub_commands/apply.py,sha256=S7gfkxhOfcjfXiBiiwH9dVMVrMmedlwe_SaMBS-YaD4,9497
139
139
  amsdal_cli/commands/migrations/sub_commands/list.py,sha256=xOfonot6JAs3ApXe-QRLKfJf2kVsj7TalEMwK3V_uC4,5439
140
- amsdal_cli/commands/migrations/sub_commands/make.py,sha256=y-SWaGzWx2apuTA57prStSo09VjH7Q9ZNjzEvbVzwo8,6272
140
+ amsdal_cli/commands/migrations/sub_commands/make.py,sha256=fLw4iC5lRxdksxg3yaf-qh0yPBNNlvfrdIZ-xxYG3Lk,6258
141
141
  amsdal_cli/commands/new/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
142
142
  amsdal_cli/commands/new/command.py,sha256=NDuDZNwreyuHsv4tbE-yrNOJViB8wk35IcKvGKQXPXo,3302
143
143
  amsdal_cli/commands/new/templates/.amsdal-cli,sha256=PdXPovcT8AfPhqwDLI_4EWFYAS6e3J5JcsHVityBdF8,304
@@ -160,7 +160,7 @@ amsdal_cli/commands/register_connection/utils/migrate_models.py,sha256=XN7pPE7Ks
160
160
  amsdal_cli/commands/register_connection/utils/model_generator.py,sha256=w0vz-i-tMdimcQYmFbtfpOZJF8heTTRIzu1yTdbKBpc,10853
161
161
  amsdal_cli/commands/register_connection/utils/tables.py,sha256=FOwbWOpEw485Leoqe8LXCVY5osGKTKlMqWD9oqosapk,474
162
162
  amsdal_cli/commands/restore/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
163
- amsdal_cli/commands/restore/command.py,sha256=ya3aHpMLpgF_vMAGSTbBuSHIUwC4FaHhMiwrD6AglTo,32833
163
+ amsdal_cli/commands/restore/command.py,sha256=DZ27U8BXkMsxhiqYfQ64wduC-0UYq7UPcZfYRHgZ8nA,36004
164
164
  amsdal_cli/commands/restore/enums.py,sha256=6SiKMRGlSjiLyepfbfQFXGAYqlM6Bkoeko2KscntTUQ,307
165
165
  amsdal_cli/commands/serve/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
166
166
  amsdal_cli/commands/serve/command.py,sha256=tjm1T0yrA2P6nlk_KDNv6Gih2Dkt5nMIN-_WUrLhn58,6541
@@ -199,8 +199,8 @@ amsdal_cli/utils/vcs/base.py,sha256=jC05ExJZDnyHAsW7_4IDf8gQcYgK4dXq3zNlFIX66T4,
199
199
  amsdal_cli/utils/vcs/dummy.py,sha256=Lk8MT-b0YlHHUsiXsq5cvmPwcl4jTYdo8piN5_C8ORA,434
200
200
  amsdal_cli/utils/vcs/enums.py,sha256=tYR9LN1IOr8BZFbSeX_vDlhn8fPl4IU-Yakii8lRDYs,69
201
201
  amsdal_cli/utils/vcs/git.py,sha256=xHynbZcV6p2D3RFCwu1MGGpV9D7eK-pGUtO8kVexTQM,1269
202
- amsdal_cli-0.4.14.dist-info/METADATA,sha256=SBk7ErSaRWFtW5SJNvmhag3LuXHPDXv1mw8fG2YnMX0,57050
203
- amsdal_cli-0.4.14.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
204
- amsdal_cli-0.4.14.dist-info/entry_points.txt,sha256=GC-8LZsD3W--Pd9_gD4W3tw3ZZyPbSvkZ-qWc9Fx0NI,47
205
- amsdal_cli-0.4.14.dist-info/licenses/LICENSE.txt,sha256=hG-541PFYfNJi9WRZi_hno91UyqNg7YLK8LR3vLblZA,27355
206
- amsdal_cli-0.4.14.dist-info/RECORD,,
202
+ amsdal_cli-0.4.16.dist-info/METADATA,sha256=TW0S3whObzI_H5FKzypEkSk53wd4IYvTX3jOoPCIs0s,57077
203
+ amsdal_cli-0.4.16.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
204
+ amsdal_cli-0.4.16.dist-info/entry_points.txt,sha256=GC-8LZsD3W--Pd9_gD4W3tw3ZZyPbSvkZ-qWc9Fx0NI,47
205
+ amsdal_cli-0.4.16.dist-info/licenses/LICENSE.txt,sha256=hG-541PFYfNJi9WRZi_hno91UyqNg7YLK8LR3vLblZA,27355
206
+ amsdal_cli-0.4.16.dist-info/RECORD,,