sapiopycommons 2024.8.28a313__py3-none-any.whl → 2024.8.28a314__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.

Potentially problematic release.


This version of sapiopycommons might be problematic. Click here for more details.

@@ -0,0 +1,146 @@
1
+ # Multimodal registration client
2
+ from __future__ import annotations
3
+
4
+ import io
5
+ from weakref import WeakValueDictionary
6
+
7
+ from databind.json import dumps, loads
8
+ from sapiopylib.rest.User import SapioUser
9
+
10
+ from sapiopycommons.general.exceptions import SapioException
11
+ from sapiopycommons.multimodal.multimodal_data import *
12
+
13
+
14
+ class MultiModalManager:
15
+ _user: SapioUser
16
+
17
+ __instances: WeakValueDictionary[SapioUser, MultiModalManager] = WeakValueDictionary()
18
+ __initialized: bool
19
+
20
+ def __new__(cls, user: SapioUser):
21
+ """
22
+ Observes singleton pattern per record model manager object.
23
+
24
+ :param user: The user that will make the webservice request to the application.
25
+ """
26
+ obj = cls.__instances.get(user)
27
+ if not obj:
28
+ obj = object.__new__(cls)
29
+ obj.__initialized = False
30
+ cls.__instances[user] = obj
31
+ return obj
32
+
33
+ def __init__(self, user:SapioUser):
34
+ if self.__initialized:
35
+ return
36
+ self._user = user
37
+ self.__initialized = True
38
+
39
+ def load_image_data(self, request: ImageDataRequestPojo) -> list[str]:
40
+ """
41
+ Loading of image data of a compound or a reaction in Sapio's unified drawing format.
42
+ :param request:
43
+ :return:
44
+ """
45
+ payload = dumps(request, ImageDataRequestPojo)
46
+ response = self._user.plugin_post("chemistry/request_image_data",
47
+ payload=payload, is_payload_plain_text=True)
48
+ self._user.raise_for_status(response)
49
+ return response.json()
50
+
51
+ def load_compounds(self, request: CompoundLoadRequestPojo):
52
+ """
53
+ Load compounds from the provided data here.
54
+ The compounds will not be registered but returned to you "the script".
55
+ To complete registration, you need to call register_compounds method after obtaining result.
56
+ """
57
+ payload = dumps(request, CompoundLoadRequestPojo)
58
+ response = self._user.plugin_post("chemistry/load",
59
+ payload=payload, is_payload_plain_text=True)
60
+ self._user.raise_for_status(response)
61
+ return loads(response.text, PyMoleculeLoaderResult)
62
+
63
+ def register_compounds(self, request: ChemRegisterRequestPojo) -> ChemCompleteImportPojo:
64
+ """
65
+ Register the filled compounds that are previously loaded via load_compounds operation.
66
+ """
67
+ payload = dumps(request, ChemRegisterRequestPojo)
68
+ response = self._user.plugin_post("chemistry/register",
69
+ payload=payload, is_payload_plain_text=True)
70
+ self._user.raise_for_status(response)
71
+ return loads(response.text, ChemCompleteImportPojo)
72
+
73
+ def load_reactions(self, reaction_str: str) -> PyIndigoReactionPojo:
74
+ """
75
+ Load a reaction and return the loaded reaction result.
76
+ :param reaction_str: A reaction string, in format of mrv, rxn, or smiles.
77
+ """
78
+ response = self._user.plugin_post("chemistry/reaction/load",
79
+ payload=reaction_str, is_payload_plain_text=True)
80
+ self._user.raise_for_status(response)
81
+ return loads(response.text, PyIndigoReactionPojo)
82
+
83
+ def register_reactions(self, reaction_str: str) -> DataRecord:
84
+ """
85
+ Register a single reaction provided.
86
+ Note: if the rxn has already specified a 2D coordinate, it may not be recomputed when generating record image.
87
+ :param reaction_str: The rxn of a reaction.
88
+ :return: The registered data record. This can be a record that already exists or new.
89
+ """
90
+ response = self._user.plugin_post("chemistry/reaction/register",
91
+ payload=reaction_str, is_payload_plain_text=True)
92
+ self._user.raise_for_status(response)
93
+ return loads(response.text, DataRecord)
94
+
95
+ def search_structures(self, request: ChemSearchRequestPojo) -> ChemSearchResponsePojo:
96
+ """
97
+ Perform structure search against the Sapio registries.
98
+ An error can be thrown as exception if search is structurally invalid.
99
+ :param request: The request object containing the detailed context of this search.
100
+ :return: The response object of the result.
101
+ """
102
+ payload = dumps(request, ChemSearchRequestPojo)
103
+ response = self._user.plugin_post("chemistry/search",
104
+ payload=payload, is_payload_plain_text=True)
105
+ self._user.raise_for_status(response)
106
+ return loads(response.text, ChemSearchResponsePojo)
107
+
108
+ def run_multi_sequence_alignment(self, request: MultiSequenceAlignmentRequestPojo) -> list[MultiSequenceAlignmentSeqPojo]:
109
+ """
110
+ Run a multi-sequence alignment using the specified tool and strategy.
111
+ :param request: The request object containing the sequences and alignment parameters. The parameters inside it can be the pojo dict of one of the options.
112
+ :return: The result of the multi-sequence alignment.
113
+ """
114
+ payload = dumps(request, MultiSequenceAlignmentRequestPojo)
115
+ response = self._user.plugin_post("bio/multisequencealignment",
116
+ payload=payload, is_payload_plain_text=True)
117
+ self._user.raise_for_status(response)
118
+ return loads(response.text, list[MultiSequenceAlignmentSeqPojo])
119
+
120
+ def register_bio(self, request: BioFileRegistrationRequest) -> BioFileRegistrationResponse:
121
+ """
122
+ Register to bioregistry of a file.
123
+ """
124
+ payload = dumps(request, BioFileRegistrationRequest)
125
+ response = self._user.plugin_post("bio/register/file", payload=payload, is_payload_plain_text=True)
126
+ self._user.raise_for_status(response)
127
+ return loads(response.text, BioFileRegistrationResponse)
128
+
129
+ def export_to_sdf(self, request: ChemExportSDFRequest) -> str:
130
+ """
131
+ Export the SDF files
132
+ :param request: The request for exporting SDF file.
133
+ :return: the SDF plain text data.
134
+ """
135
+ payload = dumps(request, ChemExportSDFRequest)
136
+ response = self._user.plugin_post("chemistry/export_sdf", payload=payload, is_payload_plain_text=True)
137
+ self._user.raise_for_status(response)
138
+ gzip_base64: str = response.text
139
+ if not gzip_base64:
140
+ raise SapioException("Returning data from server is blank for export SDF.")
141
+ decoded_bytes = base64.b64decode(gzip_base64)
142
+ with io.BytesIO(decoded_bytes) as bytes_io:
143
+ import gzip
144
+ with gzip.GzipFile(fileobj=bytes_io, mode='rb') as f:
145
+ ret: str = f.read().decode()
146
+ return ret
@@ -0,0 +1,487 @@
1
+ # Includes general Multimodal registration data structures for specific endpoints.
2
+ # Author: yqiao
3
+ import base64
4
+ from enum import Enum
5
+ from typing import Any
6
+
7
+ from databind.core import ExtraKeys
8
+ from databind.core.dataclasses import dataclass
9
+ from sapiopylib.rest.pojo.DataRecord import DataRecord
10
+
11
+
12
+ @dataclass
13
+ class PySimpleMoleculePojo:
14
+ imageSVG: str | None
15
+ smiles: str
16
+ molBlock: str
17
+
18
+
19
+ @dataclass
20
+ @ExtraKeys()
21
+ class PyMolecule:
22
+ """
23
+ Describes a deserialized molecule for Java.
24
+ """
25
+ imageSVG: str | None
26
+ smiles: str
27
+ clogP: float
28
+ tpsa: float
29
+ amw: float
30
+ exactMass: float
31
+ numHBondDonors: int
32
+ numHBondAcceptors: int
33
+ molFormula: str
34
+ charge: int
35
+ molBlock: str
36
+ inchi: str
37
+ inchiKey: str
38
+ stereoisomers: list[PySimpleMoleculePojo] | None
39
+ normError: str | None
40
+ desaltError: str | None
41
+ desaltedList: list[str] | None
42
+
43
+
44
+ @dataclass
45
+ class PyCompound:
46
+ """
47
+ class PyCompound
48
+ """
49
+
50
+ # The original substance data.
51
+ originalMol: PyMolecule # since May 24, 2023
52
+
53
+ # The normalized, desalted abstract compound data.
54
+ canonicalMol: PyMolecule | None # since May 24, 2023
55
+
56
+ props: dict[str, object] | None
57
+
58
+
59
+ class ChemFileType(Enum):
60
+ CSV = 0
61
+ SDF = 1
62
+
63
+
64
+ class ChemLoadType(Enum):
65
+ SMILES_LIST = 0
66
+ INCHI_LIST = 1
67
+ MOL_BLOCK_LIST = 2
68
+ SDF_FILE = 3
69
+
70
+
71
+ class ChemSearchType(Enum):
72
+ """
73
+ All possible chemistry quicksearch types.
74
+ """
75
+ COMPOUND_SUBSTRUCTURE = 0
76
+ COMPOUND_SIMILARITY = 1
77
+ REACTION_SUBSTRUCTURE = 2
78
+
79
+
80
+ @dataclass
81
+ class ChemLoadingError:
82
+ """
83
+ Describes a single record of compound loading error, this will be produced by interactive loader of compounds.
84
+ Attributes:
85
+ original: The original data that makes up the molecule so user can find it in the file.
86
+ errorMsg: Why the import has failed. (normalization/desalting/sanitization/kekulize)
87
+ properties: The additional attributes in the import. (for mols in SDF)
88
+ """
89
+ original: str
90
+ errorMsg: str
91
+ properties: dict
92
+
93
+
94
+ @dataclass
95
+ class PyMoleculeLoaderResult:
96
+ """
97
+ The results of a loading operation.
98
+
99
+ Attributes:
100
+ compoundByStr: may be blank if irrelevant. The map of source data string to the compound loaded.
101
+ compoundList: the compounds successfully loaded.
102
+ errorList: an error record is added here for each one we failed to load in Sapio.
103
+ """
104
+ compoundByStr: dict[str, PyCompound]
105
+ compoundList: list[PyCompound]
106
+ errorList: list[ChemLoadingError]
107
+
108
+
109
+ @dataclass
110
+ class ChemCompleteImportPojo:
111
+ # Variables declaration with type hints
112
+ dataTypeName: str
113
+ successPartRecordIdList: list[int] | None
114
+ successSampleRecordIdList: list[int] | None
115
+ errors: list[ChemLoadingError] | None
116
+ registeredOriginalParts: list[int]
117
+ allRegisteredPartsNoDuplicates: list[int]
118
+ newPartList: list[int]
119
+ numOldParts: int
120
+
121
+
122
+ @dataclass
123
+ class ChemInteractiveRegisterRequestPojo:
124
+ dataType: str
125
+ fileType: ChemFileType
126
+ fileDataEncodedBase64: str | None
127
+ addingItems: bool
128
+
129
+ def __init__(self, data_type: str, file_type: ChemFileType, is_adding_items: bool, file_data: bytes):
130
+ self.dataType = data_type
131
+ self.fileType = file_type
132
+ self.addingItems = is_adding_items
133
+ self.fileDataEncodedBase64 = base64.b64encode(file_data).decode()
134
+
135
+
136
+ @dataclass
137
+ class CompoundLoadRequestPojo:
138
+ """
139
+ Describes a load request for the Load Compound Endpoint.
140
+
141
+ Attributes:
142
+ dataType: The data type of records to be registered in Sapio.
143
+ loadType: The source data's type you are loading.
144
+ dataList: If the source data is not a file, here you specify a list of string describing molecule for that src.
145
+ fileDataBase64: If the source data is a file, the file's base64 data content.
146
+ """
147
+ dataType: str
148
+ loadType: ChemLoadType
149
+ dataList: list[str] | None
150
+ fileDataBase64: str | None
151
+
152
+ def __init__(self, data_type: str, load_type: ChemLoadType, data_list: list[str] | None = None,
153
+ file_data: bytes | None = None):
154
+ self.dataType = data_type
155
+ self.loadType = load_type
156
+ if load_type is ChemLoadType.SDF_FILE:
157
+ self.dataList = None
158
+ if file_data is None:
159
+ raise ValueError("The file data must be specify the the load type is of a file type.")
160
+ self.fileDataBase64 = base64.b64encode(file_data).decode()
161
+ else:
162
+ self.dataList = data_list
163
+ self.fileDataBase64 = None
164
+
165
+
166
+ @dataclass
167
+ class ChemRegisterRequestPojo:
168
+ """
169
+ Data payload to send to webservice to request registration in RegisterCompoundEndpoint
170
+
171
+ Attributes:
172
+ dataType: The data type of records to be registered in Sapio.
173
+ registrationList: This list must be of correct data structure suitable for the type. For example, for CompoundPart data type the canonical form must be resolved by earlier call.
174
+ """
175
+ dataType: str
176
+ registrationList: list[PyCompound]
177
+
178
+ def __init__(self, data_type: str, registration_list: list[PyCompound]):
179
+ self.dataType = data_type
180
+ self.registrationList = registration_list
181
+
182
+
183
+ @dataclass
184
+ class ImageDataRequestPojo:
185
+ """
186
+ Payload to request in endpoint loading of image data of a compound or a reaction in Sapio's unified drawing format.
187
+
188
+ Attributes:
189
+ dataList: The list of data about the images of the molecules or reactions. This can be SMILES, MOL, or INCHI. SMILES is expected. INCHI can be ambiguous to chrality as well as tautomers.
190
+ isReaction: true if the underlying data is of RxN format of reaction.
191
+ """
192
+ dataList: list[str]
193
+ reaction: bool
194
+
195
+ def __init__(self, data_list: list[str], is_reaction: bool):
196
+ self.dataList = data_list
197
+ self.reaction = is_reaction
198
+
199
+
200
+ @dataclass
201
+ class PyIndigoReactionPojo:
202
+ """
203
+ The result of loading a reaction.
204
+
205
+ Attributes:
206
+ products: products of the reaction.
207
+ reactants: reactants of the reaction.
208
+ reactionSmiles: the SMILES representation of this reaction.
209
+ reactionRxn: the RxN of an arotmized reaction
210
+ reactionRenderRxn: the RxN of no-automapping, DE-aromotized reaction, with 2D coordinates of atoms computed.
211
+ """
212
+ products: list[PyCompound]
213
+ reactants: list[PyCompound]
214
+ reactionSmiles: str
215
+ reactionRxn: str
216
+ reactionRenderRxn: str
217
+
218
+
219
+ @dataclass
220
+ class ChemQuickSearchContextData:
221
+ """
222
+ Do not directly make use of this class. The only use for this class is to pass in the "next page"
223
+ produced by the endpoint.
224
+
225
+ When obtaining the first page, this parameter argument should not be passed at all (not created with default values).
226
+ """
227
+ previousPageSearchAfterJsonStack: list[str] | None
228
+ nextPageSearchAfter: str | None
229
+ pitId: str | None
230
+ query: str | None
231
+ joinSapioPartType: str | None
232
+ simUpperLimit: float | None
233
+
234
+
235
+ @dataclass
236
+ class ChemSearchRequestPojo:
237
+ """
238
+ Payload to send to endpoint to request a chemical search in Sapio.
239
+ This can be a substructure search or similarity search.
240
+
241
+ Attributes:
242
+ searchStr: The search string of SMILES or SMARTS you are searching
243
+ searchType: The type of search you are doing.
244
+ joinMethod: The registry you are using to join with Sapio record. This is not relevant for reactions.
245
+ contextData: The context data of the current page passed to you by result of previous page. If this is the first page you are querying, leave this as None.
246
+ simSearchUpperLimit: similarity search upper limit, between 0.0 to 1.0, valid only to similarity searches.
247
+ """
248
+ searchStr: str
249
+ searchType: ChemSearchType
250
+ joinSapioType: str | None
251
+ contextData: ChemQuickSearchContextData | None
252
+ simSearchUpperLimit: float | None
253
+
254
+ def __init__(self, search_str: str, search_type: ChemSearchType, join_sapio_type: str | None = None,
255
+ context_data: ChemQuickSearchContextData | None = None, sim_search_upper: float | None = None):
256
+ self.searchStr = search_str
257
+ self.searchType = search_type
258
+ self.joinSapioType = join_sapio_type
259
+ self.contextData = context_data
260
+ self.simSearchUpperLimit = sim_search_upper
261
+
262
+
263
+ @dataclass
264
+ class ChemSearchResponsePojo:
265
+ """
266
+ A response object of a chemistry quick search.
267
+ NOTE: It's possible to have next page while the current records list is blank (although without additional query conditions, this should be rare).
268
+
269
+ Attributes:
270
+ recordsOfPage: The records returned in this page.
271
+ nextPageAvailable: Whether there is still a next page to query. If this is filled, then the context to query next page is on nextPageContext.
272
+
273
+ """
274
+ recordIdListOfPage: list[int]
275
+ nextPageAvailable: bool
276
+ nextPageContext: ChemQuickSearchContextData
277
+
278
+
279
+ class MAFFTStrategy(Enum):
280
+ """
281
+ Select one of the strategies for MAFFT multi sequence alignment.
282
+ """
283
+ # Accuracy-Orientated options
284
+ L_INS_i = 0
285
+ G_INS_i = 1
286
+ E_INS_i = 2
287
+ # Speed-Orientated options
288
+ AUTO = 3
289
+ FFT_NS_i = 4
290
+ FFT_NS_2 = 5
291
+ FFT_NS_1 = 6
292
+ NW_NS_i = 7
293
+ NW_NS_2 = 8
294
+ NW_NS_PartTree_1 = 9
295
+
296
+
297
+ class MultiSequenceAlignmentTool(Enum):
298
+ MAFFT = 0
299
+
300
+
301
+ class MultiSeqAlignemntSeqType(Enum):
302
+ nucleic = 0
303
+ amino = 1
304
+
305
+
306
+ @dataclass
307
+ class MultiSequenceAlignmentSeqPojo:
308
+ seqId: str
309
+ seqString: str | None
310
+ hyphSeqString: str | None
311
+
312
+ @staticmethod
313
+ def create(id: str, seq: str):
314
+ ret = MultiSequenceAlignmentSeqPojo(seqId=id, seqString=seq, hyphSeqString=None)
315
+ return ret
316
+
317
+
318
+ class MAFFTRunOptions:
319
+ strategy: MAFFTStrategy
320
+ noScore: bool
321
+ op: float
322
+ lop: float
323
+ lep: float
324
+ lexp: float
325
+ LOP: float
326
+ LEXP: float
327
+ fmodel: bool
328
+
329
+ def __init__(self, strategy: MAFFTStrategy = MAFFTStrategy.AUTO, noScore: bool = True,
330
+ op: float = 1.53, lop: float = -2.0, lep: float = 0.1, lexp: float = -0.1,
331
+ LOP: float = -6.0, LEXP: float = 0.00, fmodel: bool = False):
332
+ self.strategy = strategy
333
+ self.noScore = noScore
334
+ self.op = op
335
+ self.lop = lop
336
+ self.lep = lep
337
+ self.lexp = lexp
338
+ self.LOP = LOP
339
+ self.LEXP = LEXP
340
+ self.fmodel = fmodel
341
+
342
+ def to_json(self) -> dict[str, Any]:
343
+ return {
344
+ "strategy": self.strategy.name,
345
+ "noScore": self.noScore,
346
+ "op": self.op,
347
+ "lop": self.lop,
348
+ "lep": self.lep,
349
+ "lexp": self.lexp,
350
+ "LOP": self.LOP,
351
+ "LEXP": self.LEXP,
352
+ "fmodel": self.fmodel
353
+ }
354
+
355
+
356
+ class ClustalOOptions:
357
+ dealign: bool
358
+ numCombinedIterations: int | None
359
+ numGuideTreeIterations: int | None
360
+ numHMMIterations: int | None
361
+
362
+ def __init__(self, dealign: bool = False, numCombinedIterations: int | None = None,
363
+ numGuideTreeIterations: int | None = None, numHMMIterations: int | None = None):
364
+ self.dealign = dealign
365
+ self.numCombinedIterations = numCombinedIterations
366
+ self.numGuideTreeIterations = numGuideTreeIterations
367
+ self.numHMMIterations = numHMMIterations
368
+
369
+ def to_json(self) -> dict[str, Any]:
370
+ return {
371
+ "dealign": self.dealign,
372
+ "numCombinedIterations": self.numCombinedIterations,
373
+ "numGuideTreeIterations": self.numGuideTreeIterations,
374
+ "numHMMIterations": self.numHMMIterations
375
+ }
376
+
377
+
378
+ class KAlignOptions:
379
+ gapOpenPenalty: float | None
380
+ gapExtensionPenalty: float | None
381
+ terminalGapPenalty: float | None
382
+
383
+ def __init__(self, gapOpenPenalty: float | None = None, gapExtensionPenalty: float | None = None,
384
+ terminalGapPenalty: float | None = None):
385
+ self.gapOpenPenalty = gapOpenPenalty
386
+ self.gapExtensionPenalty = gapExtensionPenalty
387
+ self.terminalGapPenalty = terminalGapPenalty
388
+
389
+ def to_json(self) -> dict[str, Any]:
390
+ return {
391
+ "gapOpenPenalty": self.gapOpenPenalty,
392
+ "gapExtensionPenalty": self.gapExtensionPenalty,
393
+ "terminalGapPenalty": self.terminalGapPenalty
394
+ }
395
+
396
+
397
+ class MuscleOptions:
398
+ consiters: int
399
+ refineiters: int
400
+
401
+ def __init__(self, consiters: int = 2, refineiters: int = 100):
402
+ self.consiters = consiters
403
+ self.refineiters = refineiters
404
+
405
+ def to_json(self) -> dict[str, Any]:
406
+ return {
407
+ "consiters": self.consiters,
408
+ "refineiters": self.refineiters
409
+ }
410
+
411
+
412
+ @dataclass
413
+ class MultiSequenceAlignmentRequestPojo:
414
+ tool: MultiSequenceAlignmentTool
415
+ seqType: MultiSeqAlignemntSeqType
416
+ inputSeqs: list[MultiSequenceAlignmentSeqPojo]
417
+ parameters: dict[str, Any] | None
418
+
419
+ def __init__(self, tool: MultiSequenceAlignmentTool, seq_type: MultiSeqAlignemntSeqType,
420
+ input_sequences: list[MultiSequenceAlignmentSeqPojo],
421
+ parameters: dict[str, Any]):
422
+ self.tool = tool
423
+ self.seqType = seq_type
424
+ self.inputSeqs = input_sequences
425
+ self.parameters = parameters
426
+
427
+
428
+ class BioFileType(Enum):
429
+ """
430
+ Different bio registry supported file types.
431
+ """
432
+ FASTA = 0
433
+ GENBANK = 1
434
+ PDB = 2
435
+
436
+
437
+ @dataclass
438
+ class BioFileRegistrationRequest:
439
+ """
440
+ A request object for a single bio-registration request on parts.
441
+ """
442
+ dataTypeName: str
443
+ fileType: BioFileType
444
+ prefilledFieldMapList: list[dict[str, Any]] | None
445
+ overwriteExisting: bool
446
+ fileContent: str
447
+
448
+ def __init__(self, data_type_name: str, file_type: BioFileType, file_content: str,
449
+ prefilled_field_map_list: list[dict[str, Any]] | None = None, overwrite: bool = False):
450
+ self.dataTypeName = data_type_name
451
+ self.fileType = file_type
452
+ self.fileContent = file_content
453
+ self.prefilledFieldMapList = prefilled_field_map_list
454
+ self.overwriteExisting = overwrite
455
+
456
+
457
+ @dataclass
458
+ class BioFileRegistrationResponse:
459
+ """
460
+ A response object for a single bio-registration request on parts.
461
+ """
462
+ newRecordIdList: list[int]
463
+ oldRecordIdList: list[int]
464
+
465
+
466
+ @dataclass
467
+ class ChemExportSDFRequest:
468
+ """
469
+ A request to export SDF data from Sapio to Python REST client.
470
+ """
471
+ partDataTypeName: str
472
+ partRecordIdList: list[int]
473
+
474
+ forceV3000: bool
475
+ fieldNameList: list[str] | None
476
+ assayNameList: list[str] | None
477
+ additionalPropertiesByRecordId: dict[int, dict[str, Any]] | None
478
+
479
+ def __init__(self, partDataTypeName: str, partRecordIdList: list[int], forceV3000: bool = True,
480
+ fieldNameList: list[str] | None = None, assayNameList: list[str] | None = None,
481
+ additionalPropertiesByRecordId: dict[int, dict[str, Any]] | None = None):
482
+ self.partDataTypeName = partDataTypeName
483
+ self.partRecordIdList = partRecordIdList
484
+ self.forceV3000 = forceV3000
485
+ self.fieldNameList = fieldNameList
486
+ self.assayNameList = assayNameList
487
+ self.additionalPropertiesByRecordId = additionalPropertiesByRecordId