@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.
- package/.eslintrc.json +1 -1
- package/CHANGELOG.md +27 -0
- package/dist/package-test.js +2 -1
- package/dist/package-test.js.LICENSE.txt +8 -0
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +1 -1
- package/dist/package.js.map +1 -1
- package/files/polytool-rules/rules_example.json +10 -0
- package/files/samples/cyclized.csv +2 -0
- package/files/tests/polytool-reaction-lib.json +40 -0
- package/package.json +7 -7
- package/src/package-test.ts +3 -1
- package/src/package.ts +8 -0
- package/src/polytool/const.ts +1 -0
- package/src/polytool/pt-conversion.ts +314 -43
- package/src/polytool/pt-dialog.ts +37 -22
- package/src/polytool/pt-placeholders-breadth-input.ts +2 -2
- package/src/polytool/pt-placeholders-input.ts +1 -1
- package/src/polytool/pt-rules.ts +24 -4
- package/src/polytool/pt-unrule-dialog.ts +106 -0
- package/src/polytool/pt-unrule.ts +37 -0
- package/src/polytool/types.ts +18 -0
- package/src/tests/polytool-chain-from-notation-tests.ts +45 -0
- package/src/tests/polytool-convert-tests.ts +8 -9
- package/src/tests/polytool-enumerate-breadth-tests.ts +3 -5
- package/src/tests/polytool-enumerate-tests.ts +2 -4
- package/src/tests/polytool-unrule-tests.ts +10 -0
- package/src/tests/toAtomicLevel-tests.ts +97 -0
|
@@ -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(
|
|
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
|
-
|
|
65
|
-
if (!
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
85
|
-
|
|
86
|
-
|
|
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(
|
|
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:
|
|
120
|
+
generateHelm: generateHelmInput.value,
|
|
111
121
|
chiralityEngine: chiralityEngineInput.value,
|
|
122
|
+
rules: ruleFileList,
|
|
112
123
|
};
|
|
113
124
|
},
|
|
114
125
|
/* applyInput */ (x: PolyToolConvertSerialized): void => {
|
|
115
|
-
|
|
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
|
|
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});
|
package/src/polytool/pt-rules.ts
CHANGED
|
@@ -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(
|
|
13
|
-
|
|
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
|
|
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
|
+
}
|
package/src/polytool/types.ts
CHANGED
|
@@ -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
|
|
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
|
-
|
|
27
|
-
await
|
|
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{
|
|
47
|
-
'PEPTIDE1{
|
|
48
|
-
'PEPTIDE1{
|
|
49
|
-
'PEPTIDE1{
|
|
50
|
-
'PEPTIDE1{
|
|
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
|
|
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
|
-
|
|
29
|
-
await
|
|
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
|
|
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
|
|
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
|
+
});
|