@datagrok/sequence-translator 1.4.2 → 1.4.4

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.
@@ -9,9 +9,10 @@ import {getHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
9
9
  import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
10
10
  import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
11
11
  import {getSeqHelper, ISeqHelper} from '@datagrok-libraries/bio/src/utils/seq-helper';
12
+ import {SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
12
13
 
13
- import {getRules, RuleInputs, RULES_PATH, RULES_STORAGE_NAME} from './pt-rules';
14
- import {doPolyToolConvert} from './pt-conversion';
14
+ import {getRules, RuleInputs, Rules, RULES_PATH, RULES_STORAGE_NAME} from './pt-rules';
15
+ import {doPolyToolConvert, getOverriddenLibrary} from './pt-conversion';
15
16
  import {defaultErrorHandler} from '../utils/err-info';
16
17
  import {getLibrariesList} from './utils';
17
18
  import {getEnumerationChem, PT_CHEM_EXAMPLE} from './pt-enumeration-chem';
@@ -26,6 +27,7 @@ import {_package} from '../package';
26
27
  type PolyToolConvertSerialized = {
27
28
  generateHelm: boolean;
28
29
  chiralityEngine: boolean;
30
+ rules: string[];
29
31
  };
30
32
 
31
33
  type PolyToolEnumerateChemSerialized = {
@@ -55,35 +57,43 @@ export async function polyToolConvertUI(): Promise<void> {
55
57
  }
56
58
  }
57
59
 
58
- export async function getPolyToolConvertDialog(targetCol?: DG.Column): Promise<DG.Dialog> {
60
+ export async function getPolyToolConvertDialog(srcCol?: DG.Column): Promise<DG.Dialog> {
59
61
  const subs: Unsubscribable[] = [];
60
62
  const destroy = () => {
61
63
  for (const sub of subs) sub.unsubscribe();
62
64
  };
63
65
  try {
64
- const targetColumns = grok.shell.t.columns.bySemTypeAll(DG.SEMTYPE.MACROMOLECULE);
65
- if (!targetColumns)
66
- throw new Error(PT_ERROR_DATAFRAME);
67
-
68
- const targetColumnInput = ui.input.column('Column', {
69
- table: grok.shell.t, value: targetColumns[0],
70
- filter: (col: DG.Column) => col.semType === DG.SEMTYPE.MACROMOLECULE
66
+ let srcColVal: DG.Column<string> | undefined = srcCol;
67
+ if (!srcColVal) {
68
+ const srcColList = grok.shell.t.columns.bySemTypeAll(DG.SEMTYPE.MACROMOLECULE);
69
+ if (srcColList.length < 1)
70
+ throw new Error(PT_ERROR_DATAFRAME);
71
+ srcColVal = srcColList[0];
72
+ }
73
+ const srcColInput = ui.input.column('Column', {
74
+ table: srcColVal.dataFrame, value: srcColVal,
75
+ filter: (col: DG.Column) => {
76
+ if (col.semType !== DG.SEMTYPE.MACROMOLECULE) return false;
77
+ const sh = SeqHandler.forColumn(col);
78
+ return sh.notation === NOTATION.CUSTOM;
79
+ }
71
80
  });
72
81
 
73
- targetColumnInput.value = targetCol ? targetCol : targetColumnInput.value;
74
-
75
- const generateHelmChoiceInput = ui.input.bool(PT_UI_GET_HELM, {value: true});
76
- ui.tooltip.bind(generateHelmChoiceInput.root, PT_UI_ADD_HELM);
82
+ const generateHelmInput = ui.input.bool(PT_UI_GET_HELM, {value: true});
83
+ ui.tooltip.bind(generateHelmInput.root, PT_UI_ADD_HELM);
77
84
 
78
85
  const chiralityEngineInput = ui.input.bool(PT_UI_USE_CHIRALITY, {value: false});
79
- const ruleInputs = new RuleInputs(RULES_PATH, RULES_STORAGE_NAME, '.json');
86
+ let ruleFileList: string[];
87
+ const ruleInputs = new RuleInputs(RULES_PATH, RULES_STORAGE_NAME, '.json', {
88
+ onValueChanged: (value: string[]) => { ruleFileList = value; }
89
+ });
80
90
  const rulesHeader = ui.inlineText([PT_UI_RULES_USED]);
81
91
  ui.tooltip.bind(rulesHeader, 'Add or specify rules to use');
82
92
  const rulesForm = await ruleInputs.getForm();
83
93
 
84
- const div = ui.div([
85
- targetColumnInput,
86
- generateHelmChoiceInput,
94
+ const div = ui.divV([
95
+ srcColInput,
96
+ generateHelmInput,
87
97
  chiralityEngineInput,
88
98
  rulesHeader,
89
99
  rulesForm
@@ -92,7 +102,7 @@ export async function getPolyToolConvertDialog(targetCol?: DG.Column): Promise<D
92
102
  const exec = async (): Promise<void> => {
93
103
  try {
94
104
  const ruleFileList = await ruleInputs.getActive();
95
- await polyToolConvert(targetColumnInput.value!, generateHelmChoiceInput.value!, chiralityEngineInput.value!, ruleFileList);
105
+ await polyToolConvert(srcColInput.value!, generateHelmInput.value!, chiralityEngineInput.value!, ruleFileList);
96
106
  } catch (err: any) {
97
107
  defaultErrorHandler(err);
98
108
  }
@@ -107,13 +117,15 @@ export async function getPolyToolConvertDialog(targetCol?: DG.Column): Promise<D
107
117
  dialog.history(
108
118
  /* getInput */ (): PolyToolConvertSerialized => {
109
119
  return {
110
- generateHelm: generateHelmChoiceInput.value,
120
+ generateHelm: generateHelmInput.value,
111
121
  chiralityEngine: chiralityEngineInput.value,
122
+ rules: ruleFileList,
112
123
  };
113
124
  },
114
125
  /* applyInput */ (x: PolyToolConvertSerialized): void => {
115
- generateHelmChoiceInput.value = x.generateHelm;
126
+ generateHelmInput.value = x.generateHelm;
116
127
  chiralityEngineInput.value = x.chiralityEngine;
128
+ ruleInputs.setActive(ruleFileList);
117
129
  });
118
130
  return dialog;
119
131
  } catch (err: any) {
@@ -244,8 +256,11 @@ export async function polyToolConvert(
244
256
  if (generateHelm && table) table.columns.add(resHelmCol, true);
245
257
 
246
258
  const seqHelper: ISeqHelper = await getSeqHelper();
247
- const toAtomicLevelRes = await seqHelper.helmToAtomicLevel(resHelmCol, chiralityEngine, /* highlight */ generateHelm);
259
+ const lib = await getOverriddenLibrary(rules);
260
+ const toAtomicLevelRes =
261
+ await seqHelper.helmToAtomicLevel(resHelmCol, chiralityEngine, /* highlight */ generateHelm, lib);
248
262
  const resMolCol = toAtomicLevelRes.molCol!;
263
+
249
264
  resMolCol.name = getUnusedName(table, `molfile(${seqCol.name})`);
250
265
  resMolCol.semType = DG.SEMTYPE.MOLECULE;
251
266
  if (table) {
@@ -100,8 +100,8 @@ export class PolyToolPlaceholdersBreadthInput extends DG.JsInputBase<DG.DataFram
100
100
  export function dfToPlaceholdersBreadth(df: DG.DataFrame): PolyToolPlaceholdersBreadth {
101
101
  const res: PolyToolPlaceholdersBreadth = [];
102
102
  for (let rowI = 0; rowI < df.rowCount; rowI++) {
103
- const startPos = parseInt(df.get('Start', rowI));
104
- const endPos = parseInt(df.get('End', rowI));
103
+ const startPos = parseInt(df.get('Start', rowI)) - 1;
104
+ const endPos = parseInt(df.get('End', rowI)) - 1;
105
105
  if (!isNaN(startPos) && !isNaN(endPos)) {
106
106
  const monomerSymbolList = parseMonomerSymbolList(df.get('Monomers', rowI));
107
107
  res.push({start: startPos, end: endPos, monomers: monomerSymbolList});
@@ -111,7 +111,7 @@ export function getPlaceholdersFromText(src: string): PolyToolPlaceholders {
111
111
  export function dfToPlaceholders(df: DG.DataFrame): PolyToolPlaceholders {
112
112
  const res: PolyToolPlaceholders = [];
113
113
  for (let rowI = 0; rowI < df.rowCount; rowI++) {
114
- const pos = parseInt(df.get('Position', rowI));
114
+ const pos = parseInt(df.get('Position', rowI)) - 1;
115
115
  if (!isNaN(pos)) {
116
116
  const monomerSymbolList = parseMonomerSymbolList(df.get('Monomers', rowI));
117
117
  res.push({position: pos, monomers: monomerSymbolList});
@@ -5,19 +5,24 @@ import {ActiveFiles} from '@datagrok-libraries/utils/src/settings/active-files-b
5
5
  export const RULES_PATH = 'System:AppData/SequenceTranslator/polytool-rules/';
6
6
  export const RULES_STORAGE_NAME = 'Polytool';
7
7
  export const RULES_TYPE_LINK = 'link';
8
+ export const RULES_TYPE_REACTION = 'reaction';
8
9
  export const RULES_TYPE_HOMODIMER = 'fragmentDuplication';
9
10
  export const RULES_TYPE_HETERODIMER = 'differentFragments';
10
11
 
11
12
  export class RuleInputs extends ActiveFiles {
12
- constructor(path: string, userStorageName: string, ext: string ) {
13
- super(path, userStorageName, ext);
13
+ constructor(
14
+ path: string, userStorageName: string, ext: string,
15
+ options?: { onValueChanged: (value: string[]) => void }
16
+ ) {
17
+ super(path, userStorageName, ext, options);
14
18
  }
15
19
  }
16
20
 
17
21
  export type Rules = {
18
22
  homodimerCode: string | null,
19
23
  heterodimerCode: string | null,
20
- linkRules: RuleLink[]
24
+ linkRules: RuleLink[],
25
+ reactionRules: RuleReaction[]
21
26
  }
22
27
 
23
28
  export type RuleLink = {
@@ -30,10 +35,19 @@ export type RuleLink = {
30
35
  secondLinkingGroup: number
31
36
  }
32
37
 
38
+ export type RuleReaction = {
39
+ code: number,
40
+ firstMonomer: string,
41
+ secondMonomer: string,
42
+ reaction: string,
43
+ name: string
44
+ }
45
+
33
46
  export async function getRules(ruleFiles: string[]): Promise<Rules> {
34
47
  const fileSource = new DG.FileSource(RULES_PATH);
35
48
  const linkRules: RuleLink[] = [];
36
- const rules: Rules = {homodimerCode: null, heterodimerCode: null, linkRules: linkRules};
49
+ const reactionRules: RuleReaction[] = [];
50
+ const rules: Rules = {homodimerCode: null, heterodimerCode: null, linkRules: linkRules, reactionRules: reactionRules};
37
51
 
38
52
  for (let i = 0; i < ruleFiles.length; i++) {
39
53
  const rulesRaw = await fileSource.readAsText(ruleFiles[i].replace(RULES_PATH, ''));
@@ -47,6 +61,12 @@ export async function getRules(ruleFiles: string[]): Promise<Rules> {
47
61
  linkRules.push(rule);
48
62
  break;
49
63
  }
64
+ case RULES_TYPE_REACTION: {
65
+ const rule = ruleSingle[j].monomericSubstitution;
66
+ rule['code'] = ruleSingle[j].code;
67
+ reactionRules.push(rule);
68
+ break;
69
+ }
50
70
  case RULES_TYPE_HOMODIMER: {
51
71
  if (rules.homodimerCode)
52
72
  grok.shell.warning(`PolyTool: homodimer code is duplicated in rules.`);
@@ -0,0 +1,106 @@
1
+ import * as grok from 'datagrok-api/grok';
2
+ import * as ui from 'datagrok-api/ui';
3
+ import * as DG from 'datagrok-api/dg';
4
+
5
+ import {Unsubscribable} from 'rxjs';
6
+
7
+ import {SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
8
+ import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
9
+ import {getUnusedColName} from '@datagrok-libraries/bio/src/monomer-works/utils';
10
+
11
+ import {defaultErrorHandler} from '../utils/err-info';
12
+ import {doPolyToolUnrule} from './pt-unrule';
13
+ import {getRules, RuleInputs, RULES_PATH, RULES_STORAGE_NAME} from './pt-rules';
14
+ import {PT_ERROR_DATAFRAME, PT_UI_DIALOG_UNRULE, PT_UI_RULES_USED} from './const';
15
+
16
+ type PolyToolUnruleSerialized = {
17
+ rules: string[];
18
+ };
19
+
20
+ export async function getPolyToolUnruleDialog(srcCol?: DG.Column<string>): Promise<DG.Dialog> {
21
+ const subs: Unsubscribable[] = [];
22
+ const destroy = () => {
23
+ for (const sub of subs) sub.unsubscribe();
24
+ };
25
+ try {
26
+ let srcColVal: DG.Column<string> | undefined = srcCol;
27
+ if (!srcColVal) {
28
+ const srcColList = grok.shell.t.columns.bySemTypeAll(DG.SEMTYPE.MACROMOLECULE);
29
+ if (!srcColList)
30
+ throw new Error(PT_ERROR_DATAFRAME);
31
+ srcColVal = srcColList[0];
32
+ }
33
+ const srcColInput = ui.input.column('Column', {
34
+ table: srcColVal.dataFrame, value: srcColVal,
35
+ filter: (col: DG.Column) => {
36
+ if (col.semType !== DG.SEMTYPE.MACROMOLECULE) return false;
37
+ const sh = SeqHandler.forColumn(col);
38
+ return sh.notation === NOTATION.HELM;
39
+ }
40
+ });
41
+ let ruleFileList: string[];
42
+ const ruleInputs = new RuleInputs(RULES_PATH, RULES_STORAGE_NAME, '.json', {
43
+ onValueChanged: (value: string[]) => { ruleFileList = value;}
44
+ });
45
+ const rulesHeader = ui.inlineText([PT_UI_RULES_USED]);
46
+ const rulesForm = await ruleInputs.getForm();
47
+
48
+ const div = ui.divV([
49
+ srcColInput,
50
+ rulesHeader,
51
+ rulesForm
52
+ ]);
53
+
54
+ const exec = async (): Promise<void> => {
55
+ try {
56
+ const ruleFileList = await ruleInputs.getActive();
57
+ await polyToolUnrule(srcColInput.value!, ruleFileList);
58
+ } catch (err: any) {
59
+ defaultErrorHandler(err);
60
+ }
61
+ };
62
+
63
+ const dialog = ui.dialog(PT_UI_DIALOG_UNRULE)
64
+ .add(div)
65
+ .onOK(() => { exec(); });
66
+ subs.push(dialog.onClose.subscribe(() => {
67
+ destroy();
68
+ }));
69
+ dialog.history(
70
+ /* getInput */ (): PolyToolUnruleSerialized => {
71
+ return {
72
+ rules: ruleFileList,
73
+ };
74
+ },
75
+ /* applyInput */ (x: PolyToolUnruleSerialized): void => {
76
+ ruleInputs.setActive(ruleFileList);
77
+ });
78
+ return dialog;
79
+ } catch (err: any) {
80
+ destroy(); // on failing to build a dialog
81
+ throw err;
82
+ }
83
+ }
84
+
85
+ export async function polyToolUnrule(
86
+ srcCol: DG.Column<string>, ruleFiles: string[]
87
+ ): Promise<DG.Column> {
88
+ const pi = DG.TaskBarProgressIndicator.create('PolyTool unrule...');
89
+ try {
90
+ const table = srcCol.dataFrame;
91
+ const rules = await getRules(ruleFiles);
92
+ const resHelmList = doPolyToolUnrule(srcCol.toList(), rules);
93
+ const resHelmColName = `harmonized(srcCol.name)`;
94
+ const resHelmCol = DG.Column.fromList(DG.COLUMN_TYPE.STRING, resHelmColName, resHelmList,);
95
+ resHelmCol.semType = DG.SEMTYPE.MACROMOLECULE;
96
+ resHelmCol.meta.units = NOTATION.CUSTOM;
97
+ if (table) {
98
+ resHelmCol.name = getUnusedColName(table, resHelmColName);
99
+ table.columns.add(resHelmCol, true);
100
+ await grok.data.detectSemanticTypes(table);
101
+ }
102
+ return resHelmCol;
103
+ } finally {
104
+ pi.close();
105
+ }
106
+ }
@@ -0,0 +1,37 @@
1
+ import * as grok from 'datagrok-api/grok';
2
+ import * as ui from 'datagrok-api/ui';
3
+ import * as DG from 'datagrok-api/dg';
4
+
5
+ import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
6
+
7
+ import {Chain} from './pt-conversion';
8
+ import {getPolyToolUnruleDialog} from './pt-unrule-dialog';
9
+ import {Rules} from './pt-rules';
10
+
11
+ import {_package} from '../package';
12
+
13
+ export async function polyToolUnruleUI(): Promise<void> {
14
+ let dialog: DG.Dialog;
15
+ try {
16
+ dialog = await getPolyToolUnruleDialog();
17
+ dialog.show();
18
+ } catch (err: any) {
19
+ const [errMsg, errStack] = errInfo(err);
20
+ grok.shell.warning('To run PolyTool Unrule, open a dataframe with Helm');
21
+ _package.logger.error(errMsg, undefined, errStack);
22
+ }
23
+ }
24
+
25
+ /** Returns list of harmonized sequences. Covered with tests. */
26
+ export function doPolyToolUnrule(helms: string[], rules: Rules): string[] {
27
+ const resHrzSeqList = new Array<string>(helms.length);
28
+ for (let i = 0; i < helms.length; ++i) {
29
+ if (!helms[i])
30
+ resHrzSeqList[i] = '';
31
+ else {
32
+ const chain = Chain.fromHelm(helms[i]);
33
+ resHrzSeqList[i] = chain.getNotation(rules);
34
+ }
35
+ }
36
+ return resHrzSeqList;
37
+ }
@@ -2,6 +2,8 @@ import * as ui from 'datagrok-api/ui';
2
2
  import * as grok from 'datagrok-api/grok';
3
3
  import * as DG from 'datagrok-api/dg';
4
4
 
5
+ import {PolymerType} from '@datagrok-libraries/bio/src/helm/types';
6
+
5
7
  export enum PolyToolEnumeratorTypes {
6
8
  Single = 'single',
7
9
  Matrix = 'matrix',
@@ -21,3 +23,19 @@ export type PolyToolEnumeratorParams = {
21
23
  keepOriginal?: boolean;
22
24
  trivialName?: boolean;
23
25
  }
26
+
27
+ export class MonomerNotFoundError extends Error {
28
+ public type = 'MonomerNotFoundError';
29
+
30
+ constructor(polymerType: PolymerType, symbol: string, options?: ErrorOptions) {
31
+ super(`Monomer '${symbol}' of polymer type '${polymerType}' not found`, options);
32
+ }
33
+ }
34
+
35
+ export class InvalidReactionError extends Error {
36
+ public type = 'InvalidReactionError';
37
+
38
+ constructor(reaction: string, options?: ErrorOptions) {
39
+ super(`Invalid reaction '${reaction}'.`);
40
+ }
41
+ }
@@ -0,0 +1,45 @@
1
+ import * as grok from 'datagrok-api/grok';
2
+ import * as ui from 'datagrok-api/ui';
3
+ import * as DG from 'datagrok-api/dg';
4
+
5
+ import {before, after, category, expect, test, expectArray, testEvent, delay} from '@datagrok-libraries/utils/src/test';
6
+ import {Chain} from '../polytool/pt-conversion';
7
+ import {getRules} from '../polytool/pt-rules';
8
+
9
+ category('PolyTool: Chain: fromNotation', () => {
10
+ const tests = {
11
+ 'cyclized': {
12
+ src: {seq: 'R-F-C(1)-T-G-H-F-Y-P-C(1)-meI'},
13
+ tgt: {
14
+ monomerCount: [11], linkageCount: 1,
15
+ helm: 'PEPTIDE1{R.F.C.T.G.H.F.Y.P.C.[meI]}$PEPTIDE1,PEPTIDE1,3:R3-10:R3$$$',
16
+ },
17
+ },
18
+ 'reaction1': {
19
+ src: {seq: 'R-F-azG(3)-T-G-H-F-Y-P-aG(3)-meI'},
20
+ tgt: {
21
+ monomerCount: [9, 1], linkageCount: 2,
22
+ helm: 'PEPTIDE1{R.F.[GGaz].T.G.H.F.Y.P}|PEPTIDE2{[meI]}$PEPTIDE1,PEPTIDE1,3:R3-9:R2|PEPTIDE1,PEPTIDE2,3:R4-1:R1$$$',
23
+ }
24
+ },
25
+ 'reaction2': {
26
+ src: {seq: 'R-F-aG(3)-T-G-H-F-Y-P-azG(3)-meI'},
27
+ tgt: {
28
+ // TODO: Target test data requires clarification
29
+ monomerCount: [2, 8], linkageCount: 0,
30
+ helm: 'PEPTIDE1{R.F}|PEPTIDE2{T.G.H.F.Y.P.[GGaz].[meI]}$PEPTIDE1,PEPTIDE2,2:R2-7:R3|PEPTIDE2,PEPTIDE2,1:R1-7:R4,$$$',
31
+ }
32
+ }
33
+
34
+ };
35
+
36
+ for (const [testName, testData] of Object.entries(tests)) {
37
+ test(`${testName}`, async () => {
38
+ const rules = await getRules(['rules_example.json']);
39
+ const resChain = Chain.fromNotation(testData.src.seq, rules);
40
+ expectArray(resChain.monomers.map((mL) => mL.length), testData.tgt.monomerCount);
41
+ expect(resChain.linkages.length, testData.tgt.linkageCount);
42
+ expect(resChain.getHelm(), testData.tgt.helm);
43
+ }, testName == 'reaction2' ? {skipReason: 'reverse reaction'} : undefined);
44
+ }
45
+ });
@@ -6,7 +6,7 @@ import {before, after, category, expect, test, expectArray, testEvent, delay} fr
6
6
  import {getMonomerLibHelper, IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
7
7
  import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
8
8
  import {
9
- getUserLibSettings, setUserLibSettings, setUserLibSettingsForTests
9
+ getUserLibSettings, setUserLibSettings
10
10
  } from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
11
11
  import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
12
12
 
@@ -23,9 +23,8 @@ category('PolyTool: Convert', () => {
23
23
  before(async () => {
24
24
  monomerLibHelper = await getMonomerLibHelper();
25
25
  userLibSettings = await getUserLibSettings();
26
- // Clear settings to test default
27
- await setUserLibSettingsForTests();
28
- await monomerLibHelper.loadMonomerLib(true);
26
+
27
+ await monomerLibHelper.loadMonomerLibForTests();
29
28
  });
30
29
 
31
30
  after(async () => {
@@ -43,11 +42,11 @@ category('PolyTool: Convert', () => {
43
42
  'R-F-D(2)-T-G-H-F-Y-P-NH2(2)',
44
43
  ],
45
44
  tgt: [
46
- 'PEPTIDE1{[R].[F].[C].[T].[G].[H].[F].[Y].[P].[C].[meI]}$PEPTIDE1,PEPTIDE1,3:R3-10:R3$$$',
47
- 'PEPTIDE1{[C].[T].[G].[H].[F].[Y].[P].[C].[meI]}$PEPTIDE1,PEPTIDE1,1:R3-8:R3$$$',
48
- 'PEPTIDE1{[R].[F].[C].[T].[G].[H].[F].[Y].[P].[C]}$PEPTIDE1,PEPTIDE1,3:R3-10:R3$$$',
49
- 'PEPTIDE1{[C].[T].[G].[H].[F].[H].[P].[C]}$PEPTIDE1,PEPTIDE1,1:R3-8:R3$$$',
50
- 'PEPTIDE1{[R].[F].[D].[T].[G].[H].[F].[Y].[P].[NH2]}$PEPTIDE1,PEPTIDE1,10:R2-3:R3$$$',
45
+ 'PEPTIDE1{R.F.C.T.G.H.F.Y.P.C.[meI]}$PEPTIDE1,PEPTIDE1,3:R3-10:R3$$$',
46
+ 'PEPTIDE1{C.T.G.H.F.Y.P.C.[meI]}$PEPTIDE1,PEPTIDE1,1:R3-8:R3$$$',
47
+ 'PEPTIDE1{R.F.C.T.G.H.F.Y.P.C}$PEPTIDE1,PEPTIDE1,3:R3-10:R3$$$',
48
+ 'PEPTIDE1{C.T.G.H.F.H.P.C}$PEPTIDE1,PEPTIDE1,1:R3-8:R3$$$',
49
+ 'PEPTIDE1{R.F.D.T.G.H.F.Y.P.[NH2]}$PEPTIDE1,PEPTIDE1,10:R2-3:R3$$$',
51
50
  ]
52
51
  }
53
52
  };
@@ -7,7 +7,7 @@ import {getHelmHelper, IHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-
7
7
  import {getMonomerLibHelper, IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
8
8
  import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
9
9
  import {
10
- getUserLibSettings, setUserLibSettings, setUserLibSettingsForTests
10
+ getUserLibSettings, setUserLibSettings
11
11
  } from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
12
12
 
13
13
  import {PolyToolEnumeratorParams, PolyToolEnumeratorTypes} from '../polytool/types';
@@ -25,10 +25,8 @@ category('PolyTool: Enumerate', () => {
25
25
 
26
26
  monomerLibHelper = await getMonomerLibHelper();
27
27
  userLibSettings = await getUserLibSettings();
28
- // Clear settings to test default
29
- await setUserLibSettingsForTests();
30
- await monomerLibHelper.awaitLoaded();
31
- await monomerLibHelper.loadMonomerLib(true);
28
+
29
+ await monomerLibHelper.loadMonomerLibForTests();
32
30
  });
33
31
 
34
32
  after(async () => {
@@ -7,7 +7,7 @@ import {getHelmHelper, IHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-
7
7
  import {getMonomerLibHelper, IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
8
8
  import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
9
9
  import {
10
- getUserLibSettings, setUserLibSettings, setUserLibSettingsForTests
10
+ getUserLibSettings, setUserLibSettings
11
11
  } from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
12
12
 
13
13
  import {PolyToolEnumeratorParams, PolyToolEnumeratorTypes} from '../polytool/types';
@@ -26,9 +26,7 @@ category('PolyTool: Enumerate', () => {
26
26
  monomerLibHelper = await getMonomerLibHelper();
27
27
  userLibSettings = await getUserLibSettings();
28
28
  // Clear settings to test default
29
- await setUserLibSettingsForTests();
30
- await monomerLibHelper.awaitLoaded();
31
- await monomerLibHelper.loadMonomerLib(true);
29
+ await monomerLibHelper.loadMonomerLibForTests();
32
30
  });
33
31
 
34
32
  after(async () => {
@@ -0,0 +1,10 @@
1
+ import * as grok from 'datagrok-api/grok';
2
+ import * as ui from 'datagrok-api/ui';
3
+ import * as DG from 'datagrok-api/dg';
4
+
5
+ import {before, after, category, expect, test, expectArray, testEvent, delay} from '@datagrok-libraries/utils/src/test';
6
+
7
+ import {doPolyToolUnrule} from '../polytool/pt-unrule';
8
+ import {getRules} from '../polytool/pt-rules';
9
+
10
+ import {_package} from '../package-test';
@@ -0,0 +1,97 @@
1
+ import * as grok from 'datagrok-api/grok';
2
+ import * as ui from 'datagrok-api/ui';
3
+ import * as DG from 'datagrok-api/dg';
4
+
5
+ import {before, after, category, expect, test, expectArray, testEvent, delay} from '@datagrok-libraries/utils/src/test';
6
+ import {Monomer, MonomerLibData} from '@datagrok-libraries/bio/src/types/index';
7
+
8
+ import {PolymerTypes} from '@datagrok-libraries/bio/src/helm/consts';
9
+ import {getSeqHelper} from '@datagrok-libraries/bio/src/utils/seq-helper';
10
+ import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
11
+ import {getUserLibSettings, setUserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
12
+ import {getMonomerLibHelper, IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
13
+ import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
14
+ import {getRdKitModule} from '@datagrok-libraries/bio/src/chem/rdkit-module';
15
+ import {RDModule} from '@datagrok-libraries/chem-meta/src/rdkit-api';
16
+
17
+ import {_package} from '../package-test';
18
+ import {getNewMonomer} from '../polytool/pt-conversion';
19
+ import {getRules, RuleReaction} from '../polytool/pt-rules';
20
+
21
+ category('toAtomicLevel', () => {
22
+ let userLibSettings: UserLibSettings;
23
+ let monomerLibHelper: IMonomerLibHelper;
24
+ let rdKitModule: RDModule;
25
+
26
+ before(async () => {
27
+
28
+ monomerLibHelper = await getMonomerLibHelper();
29
+ userLibSettings = await getUserLibSettings();
30
+ rdKitModule = await getRdKitModule();
31
+
32
+ await monomerLibHelper.loadMonomerLibForTests();
33
+ });
34
+
35
+ after(async () => {
36
+ await setUserLibSettings(userLibSettings);
37
+ await monomerLibHelper.loadMonomerLib(true); // load user settings libraries
38
+ });
39
+
40
+ test('override', async () => {
41
+ const systemMonomerLib = monomerLibHelper.getMonomerLib();
42
+ const rLibStr = await _package.files.readAsText('tests/polytool-reaction-lib.json');
43
+ const rLib: Monomer[] = JSON.parse(rLibStr);
44
+ const ggazM = rLib.find((m) => m.symbol === 'GGaz')!;
45
+ expect(ggazM != null, true, `Monomer 'GGaz' not found.`);
46
+
47
+ const overrideMonomerLibData: MonomerLibData = {[PolymerTypes.PEPTIDE]: {'GGaz': ggazM}};
48
+ const overriddenMonomerLib = systemMonomerLib.override(overrideMonomerLibData);
49
+
50
+ const seqHelper = await getSeqHelper();
51
+
52
+ const helmCol = DG.Column.fromList(DG.COLUMN_TYPE.STRING, 'helm',
53
+ ['PEPTIDE1{F.P.Y.[GGaz].H.A.A.G.G.A.C}|PEPTIDE2{A.A.A}$PEPTIDE1,PEPTIDE2,4:R4-1:R1|PEPTIDE1,PEPTIDE1,11:R2-4:R3$$$V2.0']);
54
+ helmCol.semType = DG.SEMTYPE.MACROMOLECULE;
55
+ helmCol.meta.units = NOTATION.HELM;
56
+ const talRes = await seqHelper.helmToAtomicLevel(helmCol, false, false, overriddenMonomerLib);
57
+
58
+ expect(talRes.molCol != null, true, 'Result molCol is null');
59
+ const molfile = talRes.molCol!.get(0)!;
60
+ expect(!!molfile, true, 'Molfile is empty');
61
+
62
+ const mol = rdKitModule.get_mol(molfile);
63
+ try {
64
+ const molInchi = mol.get_inchi();
65
+ const molInchiKey = rdKitModule.get_inchikey_for_inchi(molInchi);
66
+
67
+ expect(mol.get_num_bonds(), 103);
68
+ expect(mol.get_num_atoms(), 98);
69
+ expect(molInchiKey, 'XPQUTLNSNIMERR-WKBTUBAPSA-N');
70
+ } finally {
71
+ mol.delete();
72
+ }
73
+ });
74
+
75
+ test('getNewMonomer', async () => {
76
+ const rdKitModule = await getRdKitModule();
77
+ const systemMonomerLib = monomerLibHelper.getMonomerLib();
78
+
79
+ const rules = await getRules(['rules_example.json']);
80
+ const reactionRule = rules.reactionRules.find((r) => r.name == 'GGaz')!;
81
+
82
+ const [newSymbol, newMonomer] = getNewMonomer(rdKitModule, systemMonomerLib, reactionRule);
83
+ expect(newSymbol, reactionRule.name);
84
+
85
+ const mol = rdKitModule.get_mol(newMonomer.molfile);
86
+ try {
87
+ const molInchi = mol.get_inchi();
88
+ const molInchiKey = rdKitModule.get_inchikey_for_inchi(molInchi);
89
+ expect(mol.get_num_bonds(), 18);
90
+ expect(mol.get_num_atoms(), 18);
91
+ // TODO: Check inchi key for the new monomer molfile
92
+ // expect(molInchiKey, 'V2H10N2O3S-UHFFFAOYSA-N');
93
+ } finally {
94
+ mol.delete();
95
+ }
96
+ });
97
+ });