mostlyai-mock 0.1.0__py3-none-any.whl → 0.1.2__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.
mostlyai/mock/__init__.py CHANGED
@@ -15,4 +15,4 @@
15
15
  from mostlyai.mock.core import sample
16
16
 
17
17
  __all__ = ["sample"]
18
- __version__ = "0.1.0" # Do not set this manually. Use poetry version [params].
18
+ __version__ = "0.1.2" # Do not set this manually. Use poetry version [params].
mostlyai/mock/core.py CHANGED
@@ -26,20 +26,25 @@ from pydantic import BaseModel, Field, RootModel, create_model, field_validator,
26
26
  from tqdm import tqdm
27
27
 
28
28
  SYSTEM_PROMPT = """
29
- You are a specialized synthetic data generator designed to create
30
- highly realistic, contextually appropriate data based on schema definitions. Your task is to:
29
+ You are a specialized mock data generator designed to create highly realistic, contextually appropriate data based on schema definitions.
30
+
31
+ Your task is to:
31
32
 
32
33
  1. Generate data that strictly adheres to the provided schema constraints (data types, ranges, formats)
33
34
  2. Ensure logical consistency across related tables and foreign key relationships
34
35
  3. Create contextually appropriate values that reflect real-world patterns and distributions
35
36
  4. Produce diverse, non-repetitive data that avoids obvious patterns
36
37
  5. Respect uniqueness constraints and other data integrity rules
37
- 6. Return well-formatted JSON output that can be directly parsed.
38
- 7. Don't use markdown formatting.
38
+ 6. When enriching existing data, ensure that new values are consistent with existing values
39
+ 7. Return well-formatted JSON output that can be directly parsed
40
+ 8. Don't use markdown formatting
39
41
 
40
42
  For numeric fields, generate realistic distributions rather than random values. For text fields, create contextually \
41
43
  appropriate content. For dates and timestamps, ensure logical chronology. Always maintain referential integrity \
42
44
  across tables.
45
+
46
+ When enriching existing data, carefully analyze the patterns and relationships in the existing columns \
47
+ to generate compatible and realistic values for the missing columns.
43
48
  """
44
49
 
45
50
 
@@ -197,7 +202,7 @@ def _sample_table(
197
202
  columns: dict[str, ColumnConfig],
198
203
  foreign_keys: list[ForeignKeyConfig] | None,
199
204
  primary_keys: dict[str, str] | None,
200
- generated_data: dict[str, pd.DataFrame] | None,
205
+ data: dict[str, pd.DataFrame],
201
206
  sample_size: int,
202
207
  batch_size: int,
203
208
  previous_rows_size: int,
@@ -210,7 +215,7 @@ def _sample_table(
210
215
  columns=columns,
211
216
  primary_keys=primary_keys,
212
217
  foreign_keys=foreign_keys,
213
- generated_data=generated_data,
218
+ data=data,
214
219
  sample_size=sample_size,
215
220
  batch_size=batch_size,
216
221
  previous_rows_size=previous_rows_size,
@@ -230,6 +235,7 @@ def _create_table_prompt(
230
235
  primary_keys: dict[str, str] | None,
231
236
  batch_size: int | None,
232
237
  foreign_keys: list[ForeignKeyConfig] | None,
238
+ existing_data: pd.DataFrame | None,
233
239
  context_data: pd.DataFrame | None,
234
240
  non_context_data: dict[str, pd.DataFrame] | None,
235
241
  previous_rows: list[dict] | None,
@@ -251,6 +257,11 @@ def _create_table_prompt(
251
257
  prompt += f"\n## Previous {len(previous_rows)} Rows:\n\n"
252
258
  prompt += f"{json.dumps(previous_rows, indent=2)}\n\n"
253
259
 
260
+ # add existing data to augment
261
+ if existing_data is not None:
262
+ prompt += f"\n## Existing Data to Augment:\n\n"
263
+ prompt += f"{existing_data.to_json(orient='records', date_format='iso', indent=2)}\n\n"
264
+
254
265
  # define foreign keys
255
266
  if foreign_keys:
256
267
  prompt += "## Foreign Keys:\n\n"
@@ -285,26 +296,46 @@ def _create_table_prompt(
285
296
 
286
297
  # add instructions
287
298
  prompt += "\n## Instructions:\n\n"
288
- if not foreign_keys:
299
+
300
+ verb = "generate" if existing_data is None else "augment"
301
+
302
+ n_rows = None
303
+ if existing_data is not None:
304
+ n_rows = len(existing_data)
305
+ elif not foreign_keys:
289
306
  assert batch_size is not None
290
- prompt += f"Generate {batch_size} rows for the `{name}` table.\n\n"
291
- else:
307
+ n_rows = batch_size
308
+
309
+ prompt += f"{verb.capitalize()} data for the `{name}` table.\n\n"
310
+ if n_rows is not None:
311
+ prompt += f"Number of rows to {verb}: `{n_rows}`.\n\n"
312
+
313
+ if foreign_keys:
292
314
  prompt += (
293
- f"Generate data for the `{name}` table. "
294
315
  f"The first Foreign Key column from Foreign Keys section may only contain values from Context Table Data. "
295
316
  f"The following Foreign Key columns from Foreign Keys section (if exists) may only contain values from Non-Context Table Data sections. "
296
317
  f"If either relevant Context Table Data or Non-Context Table Data is not present, this means that table has self-dependency. "
297
- f"In this case, ensure that the generated foreign keys are consistent with generated primary keys of the table. "
318
+ f"In this case, ensure that the foreign keys are consistent with primary keys of the table. "
298
319
  f"Pay attention to prompt of the Foreign Key column to understand the relationship.\n\n"
299
320
  )
300
321
 
322
+ if existing_data is not None:
323
+ prompt += (
324
+ f"You are given existing data for the `{name}` table and asked to generate "
325
+ f"values for the missing columns. The existing data contains column(s): {', '.join(existing_data.columns)}. "
326
+ f"You need to generate values for column(s): {', '.join(columns.keys() - existing_data.columns)}. "
327
+ f"Ensure that the generated values are contextually appropriate and consistent with the existing data. "
328
+ f"Use the existing columns' values to inform the generation of new values. "
329
+ f"Don't generate new rows, only augment the existing data.\n\n"
330
+ )
331
+
301
332
  if previous_rows:
302
333
  prompt += (
303
- "Generate new rows that maintain consistency with the previous rows where appropriate. "
334
+ f"{verb.capitalize()} new rows that maintain consistency with the previous rows where appropriate. "
304
335
  "Don't copy previous rows in the output. "
305
336
  "Don't pay attention to the number of previous rows; there might have been more generated than provided.\n\n"
306
337
  )
307
- prompt += "Do not use code to generate the data.\n\n"
338
+ prompt += f"Do not use code to {verb} the data.\n\n"
308
339
  prompt += "Return the full data as a JSON string.\n"
309
340
 
310
341
  return prompt
@@ -317,7 +348,7 @@ def _create_table_rows_generator(
317
348
  columns: dict[str, ColumnConfig],
318
349
  foreign_keys: list[ForeignKeyConfig] | None,
319
350
  primary_keys: dict[str, str] | None,
320
- generated_data: dict[str, pd.DataFrame] | None,
351
+ data: dict[str, pd.DataFrame],
321
352
  sample_size: int,
322
353
  batch_size: int,
323
354
  previous_rows_size: int,
@@ -393,27 +424,31 @@ def _create_table_rows_generator(
393
424
  "The model does not support structured output / JSON mode."
394
425
  )
395
426
 
427
+ # derive data for augmentation
428
+ existing_data: pd.DataFrame | None = None
429
+ if name in data:
430
+ existing_data = data[name]
431
+ sample_size = len(existing_data)
432
+
396
433
  # derive context data (if first foreign key is present) and harmonize sample size accordingly
397
434
  context_data: pd.DataFrame | None = None
398
435
  if foreign_keys and foreign_keys[0].referenced_table != name: # self-dependency is not considered as context
399
436
  context_table_name = foreign_keys[0].referenced_table
400
- assert generated_data is not None
401
- assert context_table_name in generated_data
402
- context_data = generated_data[context_table_name]
437
+ assert context_table_name in data
438
+ context_data = data[context_table_name]
403
439
  batch_size = 1 # generate one sequence at a time
404
440
  sample_size = len(context_data)
405
441
 
406
442
  # derive non-context data (if more than one foreign key is present)
407
443
  non_context_data: dict[str, pd.DataFrame] = {}
408
444
  if foreign_keys and len(foreign_keys) > 1:
409
- assert generated_data is not None
410
445
  assert non_context_size is not None
411
446
  for fk in foreign_keys[1:]:
412
447
  if fk.referenced_table == name: # self-dependency is not considered as non-context
413
448
  continue
414
449
  non_context_table_name = fk.referenced_table
415
- assert non_context_table_name in generated_data
416
- non_context_data[non_context_table_name] = generated_data[non_context_table_name]
450
+ assert non_context_table_name in data
451
+ non_context_data[non_context_table_name] = data[non_context_table_name]
417
452
 
418
453
  litellm_kwargs = {
419
454
  "response_format": create_table_response_format(columns=columns),
@@ -424,26 +459,46 @@ def _create_table_rows_generator(
424
459
  "stream": True,
425
460
  }
426
461
 
462
+ batch_idx = 0
427
463
  yielded_sequences = 0
428
464
  previous_rows = deque(maxlen=previous_rows_size)
429
465
  for context_batch in batch_infinitely(context_data):
430
- non_context_batch = (
431
- {table_name: df.sample(frac=1.0).head(non_context_size) for table_name, df in non_context_data.items()}
432
- if non_context_data
433
- else None
434
- )
435
- prompt = _create_table_prompt(
466
+ # pick existing rows for current batch
467
+ existing_batch: pd.DataFrame | None = None
468
+ if existing_data is not None:
469
+ if context_batch is None:
470
+ # progressively pick portions of existing data in case of root tables
471
+ assert batch_size is not None
472
+ existing_batch = existing_data.iloc[batch_idx * batch_size : (batch_idx + 1) * batch_size]
473
+ else:
474
+ # pick existing rows that match current context batch
475
+ assert foreign_keys is not None
476
+ context_table_name, foreign_key = foreign_keys[0].referenced_table, foreign_keys[0].column
477
+ context_primary_key = primary_keys[context_table_name]
478
+ existing_batch = existing_data[existing_data[foreign_key].isin(context_batch[context_primary_key])]
479
+ if existing_batch.empty:
480
+ existing_batch = None
481
+
482
+ # sample candidate rows from non-context tables for current batch
483
+ non_context_batch: dict[str, pd.DataFrame] | None = None
484
+ if non_context_data:
485
+ non_context_batch = {
486
+ table_name: df.sample(frac=1.0).head(non_context_size) for table_name, df in non_context_data.items()
487
+ }
488
+
489
+ llm_prompt = _create_table_prompt(
436
490
  name=name,
437
491
  prompt=prompt,
438
492
  columns=columns,
439
493
  primary_keys=primary_keys,
440
494
  batch_size=batch_size,
441
495
  foreign_keys=foreign_keys,
496
+ existing_data=existing_batch,
442
497
  context_data=context_batch,
443
498
  non_context_data=non_context_batch,
444
499
  previous_rows=list(previous_rows),
445
500
  )
446
- messages = [{"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": prompt}]
501
+ messages = [{"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": llm_prompt}]
447
502
 
448
503
  response = litellm.completion(messages=messages, **litellm_kwargs)
449
504
  rows_stream = yield_rows_from_json_chunks_stream(response)
@@ -466,6 +521,8 @@ def _create_table_rows_generator(
466
521
  if yielded_sequences >= sample_size:
467
522
  return # move to next table
468
523
 
524
+ batch_idx += 1
525
+
469
526
 
470
527
  def _convert_table_rows_generator_to_df(
471
528
  table_rows_generator: Generator[dict],
@@ -559,6 +616,7 @@ def sample(
559
616
  *,
560
617
  tables: dict[str, dict],
561
618
  sample_size: int | dict[str, int] = 10,
619
+ existing_data: dict[str, pd.DataFrame] | None = None,
562
620
  model: str = "openai/gpt-4.1-nano",
563
621
  api_key: str | None = None,
564
622
  temperature: float = 1.0,
@@ -574,7 +632,9 @@ def sample(
574
632
  If a single integer is provided, the same number of rows will be generated for each subject table.
575
633
  If a dictionary is provided, the number of rows to generate for each subject table can be specified
576
634
  individually.
577
- Default is 10.
635
+ Default is 10. Ignored if existing_data is provided.
636
+ existing_data (dict[str, pd.DataFrame] | None): Existing data to augment. If provided, the sample_size argument is ignored.
637
+ Default is None.
578
638
  model (str): The LiteLLM chat completion model to be used. Requires support for structured output / JSON mode.
579
639
  Examples include:
580
640
  - `openai/gpt-4.1-nano` (default)
@@ -683,17 +743,73 @@ def sample(
683
743
  df_orders = data["orders"]
684
744
  df_items = data["items"]
685
745
  ```
746
+
747
+ Example of data augmentation:
748
+ ```python
749
+ from mostlyai import mock
750
+ import pandas as pd
751
+
752
+ tables = {
753
+ "customers": {
754
+ "prompt": "Customers of a hardware store",
755
+ "columns": {
756
+ "customer_id": {"prompt": "the unique id of the customer", "dtype": "integer"},
757
+ "name": {"prompt": "first name and last name of the customer", "dtype": "string"},
758
+ "email": {"prompt": "email address of the customer", "dtype": "string"},
759
+ "phone": {"prompt": "phone number of the customer", "dtype": "string"},
760
+ "loyalty_level": {"dtype": "category", "values": ["bronze", "silver", "gold", "platinum"]},
761
+ },
762
+ "primary_key": "customer_id",
763
+ },
764
+ "orders": {
765
+ "prompt": "Orders of a Customer",
766
+ "columns": {
767
+ "order_id": {"prompt": "the unique id of the order", "dtype": "string"},
768
+ "customer_id": {"prompt": "the customer id for that order", "dtype": "integer"},
769
+ "order_date": {"prompt": "the date when the order was placed", "dtype": "date"},
770
+ "total_amount": {"prompt": "order amount in USD", "dtype": "float"},
771
+ "status": {"dtype": "category", "values": ["pending", "shipped", "delivered", "cancelled"]},
772
+ },
773
+ "primary_key": "order_id",
774
+ "foreign_keys": [
775
+ {
776
+ "column": "customer_id",
777
+ "referenced_table": "customers",
778
+ "prompt": "each customer has anywhere between 1 and 3 orders",
779
+ },
780
+ ],
781
+ },
782
+ }
783
+ existing_customers = pd.DataFrame({
784
+ "customer_id": [101, 102, 103],
785
+ "name": ["John Davis", "Maria Garcia", "Wei Chen"],
786
+ })
787
+ existing_orders = pd.DataFrame({
788
+ "order_id": ["ORD-001", "ORD-002"],
789
+ "customer_id": [101, 101],
790
+ })
791
+ data = mock.sample(
792
+ tables=tables,
793
+ existing_data={
794
+ "customers": existing_customers,
795
+ "orders": existing_orders,
796
+ },
797
+ model="openai/gpt-4.1-nano"
798
+ )
799
+ df_customers = data["customers"]
800
+ df_orders = data["orders"]
801
+ ```
686
802
  """
687
803
 
688
804
  config = MockConfig(tables)
689
805
  llm_config = LLMConfig(model=model, api_key=api_key, temperature=temperature, top_p=top_p)
690
806
 
691
- sample_size = _harmonize_sample_size(sample_size, config)
807
+ sample_size: dict[str, int] = _harmonize_sample_size(sample_size, config)
692
808
  primary_keys = {table_name: table_config.primary_key for table_name, table_config in config.root.items()}
693
809
 
694
810
  execution_plan: list[str] = _build_execution_plan(config)
695
811
 
696
- data: dict[str, pd.DataFrame] = {}
812
+ data: dict[str, pd.DataFrame] = existing_data or {}
697
813
 
698
814
  for table_name in execution_plan:
699
815
  table_config = config.root[table_name]
@@ -703,7 +819,7 @@ def sample(
703
819
  columns=table_config.columns,
704
820
  foreign_keys=table_config.foreign_keys,
705
821
  primary_keys=primary_keys,
706
- generated_data=data,
822
+ data=data,
707
823
  sample_size=sample_size[table_name],
708
824
  batch_size=30, # generate 30 root table rows at a time
709
825
  previous_rows_size=10, # present 10 previously generated rows to the LLM
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mostlyai-mock
3
- Version: 0.1.0
4
- Summary: Synthetic Mock Data
3
+ Version: 0.1.2
4
+ Summary: LLM-generated Mock Data
5
5
  Project-URL: homepage, https://github.com/mostly-ai/mostlyai-mock
6
6
  Project-URL: repository, https://github.com/mostly-ai/mostlyai-mock
7
7
  Project-URL: documentation, https://mostly-ai.github.io/mostlyai-mock/
@@ -32,7 +32,7 @@ Requires-Dist: pyarrow>=14.0.0
32
32
  Requires-Dist: pydantic<3.0.0,>=2.0.0
33
33
  Description-Content-Type: text/markdown
34
34
 
35
- # Synthetic Mock Data 🔮
35
+ # LLM-generated Mock Data 🔮
36
36
 
37
37
  [![Documentation](https://img.shields.io/badge/docs-latest-green)](https://mostly-ai.github.io/mostlyai-mock/) [![stats](https://pepy.tech/badge/mostlyai-mock)](https://pypi.org/project/mostlyai-mock/) ![license](https://img.shields.io/github/license/mostly-ai/mostlyai-mock) ![GitHub Release](https://img.shields.io/github/v/release/mostly-ai/mostlyai-mock)
38
38
 
@@ -66,7 +66,7 @@ os.environ["OPENAI_API_KEY"] = "your-api-key"
66
66
 
67
67
  Note: You will need to obtain your API key directly from the LLM service provider (e.g. for Open AI from [here](https://platform.openai.com/api-keys)). The LLM endpoint will be determined by the chosen `model` when making calls to `mock.sample`.
68
68
 
69
- 3. Create your first basic synthetic table from scratch
69
+ 3. Create your first basic mock table from scratch
70
70
 
71
71
  ```python
72
72
  from mostlyai import mock
@@ -88,7 +88,7 @@ tables = {
88
88
  }
89
89
  }
90
90
  df = mock.sample(
91
- tables=tables, # provide table and column definitions
91
+ tables=tables, # provide table and column definitions
92
92
  sample_size=10, # generate 10 records
93
93
  model="openai/gpt-4.1-nano", # select the LLM model (optional)
94
94
  )
@@ -106,7 +106,7 @@ print(df)
106
106
  # 9 FR Louis Martin male 44 1980-12-05 2025-01-07 10:40:00 False 270.0 103
107
107
  ```
108
108
 
109
- 4. Create your first multi-table synthetic dataset
109
+ 4. Create your first multi-table mock dataset
110
110
 
111
111
  ```python
112
112
  from mostlyai import mock
@@ -168,7 +168,7 @@ tables = {
168
168
  },
169
169
  }
170
170
  data = mock.sample(
171
- tables=tables,
171
+ tables=tables,
172
172
  sample_size=2,
173
173
  model="openai/gpt-4.1"
174
174
  )
@@ -201,7 +201,7 @@ print(data["items"])
201
201
  # 9 ITM-84312 ORD-11385 Standard Delivery Service 48.5
202
202
  ```
203
203
 
204
- 6. Create your first self-referencing synthetic table
204
+ 6. Create your first self-referencing mock table
205
205
 
206
206
  ```python
207
207
  from mostlyai import mock
@@ -225,7 +225,7 @@ tables = {
225
225
  ],
226
226
  }
227
227
  }
228
- df = sample(tables=tables, sample_size=10, model="openai/gpt-4.1")
228
+ df = mock.sample(tables=tables, sample_size=10, model="openai/gpt-4.1")
229
229
  print(df)
230
230
  # employee_id name boss_id role
231
231
  # 0 1 Sandra Phillips <NA> President
@@ -240,6 +240,44 @@ print(df)
240
240
  # 9 10 Felix Bennett 3 Senior Systems Analyst
241
241
  ```
242
242
 
243
+ 7. Enrich existing data with additional columns
244
+
245
+ ```python
246
+ from mostlyai import mock
247
+ import pandas as pd
248
+
249
+ tables = {
250
+ "guests": {
251
+ "prompt": "Guests of an Alpine ski hotel in Austria",
252
+ "columns": {
253
+ "guest_id": {"prompt": "the unique id of the guest", "dtype": "integer"},
254
+ "name": {"prompt": "first name and last name of the guest", "dtype": "string"},
255
+ "nationality": {"prompt": "2-letter code for the nationality", "dtype": "string"},
256
+ "gender": {"dtype": "category", "values": ["male", "female"]},
257
+ "age": {"prompt": "age in years; min: 18, max: 80; avg: 25", "dtype": "integer"},
258
+ "room_number": {"prompt": "room number", "dtype": "integer"},
259
+ "is_vip": {"prompt": "is the guest a VIP", "dtype": "boolean"},
260
+ },
261
+ "primary_key": "guest_id",
262
+ }
263
+ }
264
+ existing_guests = pd.DataFrame({
265
+ "guest_id": [1, 2, 3],
266
+ "name": ["Anna Schmidt", "Marco Rossi", "Sophie Dupont"],
267
+ "nationality": ["DE", "IT", "FR"],
268
+ })
269
+ df = mock.sample(
270
+ tables=tables,
271
+ existing_data={"guests": existing_guests},
272
+ model="openai/gpt-4.1-nano"
273
+ )
274
+ print(df)
275
+ # guest_id name nationality gender age room_number is_vip
276
+ # 0 1 Anna Schmidt DE female 29 101 True
277
+ # 1 2 Marco Rossi IT male 34 102 False
278
+ # 2 3 Sophie Dupont FR female 27 103 False
279
+ ```
280
+
243
281
  ## MCP Server
244
282
 
245
283
  This repo comes with MCP Server. It can be easily consumed by any MCP Client by providing the following configuration:
@@ -0,0 +1,8 @@
1
+ mostlyai/mock/__init__.py,sha256=eeJjZ-XPDr-e4iE44SBNNt_xYQKnT6OVm75Xr52CYWc,714
2
+ mostlyai/mock/core.py,sha256=buDLbuCIGbNP91TtCnN-dg3wlHLtRcvzzlGQWm-7j8k,35183
3
+ mostlyai/mock/mcp_server.py,sha256=Vp0bWzE8wUyA6k4PHLa0TbkuI9s07E48xPrAUgf_5qU,1563
4
+ mostlyai_mock-0.1.2.dist-info/METADATA,sha256=pSjJ6D5ckyBdvpk_-5SjfF9-c6PXrEOjEc4oW5IE-g4,14161
5
+ mostlyai_mock-0.1.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
6
+ mostlyai_mock-0.1.2.dist-info/entry_points.txt,sha256=XDbppUIAaCWW0nresVep8zb71pkzZuFA16jCBHq8CU8,61
7
+ mostlyai_mock-0.1.2.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
8
+ mostlyai_mock-0.1.2.dist-info/RECORD,,
@@ -1,8 +0,0 @@
1
- mostlyai/mock/__init__.py,sha256=ozv-XYJlW9RYYfDXVWDKJxMxqEif6MOC0HXCY3nX0eA,714
2
- mostlyai/mock/core.py,sha256=g00md01vP-xyI6FKDUB-PCCzOmtpeN8Bm8jXQEwclJA,30130
3
- mostlyai/mock/mcp_server.py,sha256=Vp0bWzE8wUyA6k4PHLa0TbkuI9s07E48xPrAUgf_5qU,1563
4
- mostlyai_mock-0.1.0.dist-info/METADATA,sha256=rbHAHWTMQDrcJjio0DT8_sstVaVa7B0NGPMqACFoXUY,12708
5
- mostlyai_mock-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
6
- mostlyai_mock-0.1.0.dist-info/entry_points.txt,sha256=XDbppUIAaCWW0nresVep8zb71pkzZuFA16jCBHq8CU8,61
7
- mostlyai_mock-0.1.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
8
- mostlyai_mock-0.1.0.dist-info/RECORD,,