Skip to content

Commit

Permalink
Fix Spec -> object conversion during JSON serialization by removing J…
Browse files Browse the repository at this point in the history
…SON serialization and implementing a custom deep-copy method.

PiperOrigin-RevId: 464929603
  • Loading branch information
cjqian authored and LIT team committed Aug 3, 2022
1 parent d54522a commit 853edd0
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 11 deletions.
4 changes: 2 additions & 2 deletions lit_nlp/client/lib/lit_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ type ScoredTextCandidates = Array<[text: string, score: number|null]>;
export class LitType {
// tslint:disable:enforce-name-casing
__name__: LitName = 'LitType';
readonly required: boolean = true;
readonly default: unknown;
required: boolean = true;
default: unknown = undefined;
// If this type is created from an Annotator.
annotated: boolean = false;
// TODO(b/162269499): Update to camel case once we've replaced old LitType.
Expand Down
11 changes: 11 additions & 0 deletions lit_nlp/client/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,17 @@ export function deserializeLitTypesInSpec(serializedSpec: SerializedSpec): Spec
return typedSpec;
}

/**
* Returns a deep copy of the given spec.
*/
export function cloneSpec(spec: Spec): Spec {
const newSpec: Spec = {};
for (const [key, fieldSpec] of Object.entries(spec)) {
newSpec[key] = createLitType(fieldSpec.__name__, fieldSpec as {});
}
return newSpec;
}

/**
* Converts serialized LitTypes within the LitMetadata into LitType instances.
*/
Expand Down
25 changes: 25 additions & 0 deletions lit_nlp/client/lib/utils_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,31 @@ describe('deserializeLitTypesInLitMetadata test', () => {
});
});

describe('cloneSpec test', () => {
const testSpec = {
'probabilities': utils.createLitType('MulticlassPreds', {
'required': true,
'vocab': ['0', '1'],
'null_idx': 0,
'parent': 'label'
})
};

it('deeply copies', () => {
const testSpec2 = utils.cloneSpec(testSpec);

const oldProbs = testSpec['probabilities'] as litTypes.MulticlassPreds;
const newProbs = testSpec2['probabilities'] as litTypes.MulticlassPreds;

newProbs.null_idx = 1;
expect(oldProbs.null_idx).toEqual(0);
expect(newProbs.null_idx).toEqual(1);

expect(testSpec2['probabilities'] instanceof litTypes.MulticlassPreds)
.toBe(true);
});
});

describe('isLitSubtype test', () => {
it('checks is lit subtype', () => {
const testType = utils.createLitType('StringLitType');
Expand Down
4 changes: 2 additions & 2 deletions lit_nlp/client/modules/generator_module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import {TableData, TableEntry} from '../elements/table';
import {FieldMatcher, LitName} from '../lib/lit_types';
import {styles as sharedStyles} from '../lib/shared_styles.css';
import {CallConfig, formatForDisplay, IndexedInput, Input, ModelInfoMap, Spec} from '../lib/types';
import {flatten, isLitSubtype} from '../lib/utils';
import {cloneSpec, flatten, isLitSubtype} from '../lib/utils';
import {GroupService} from '../services/group_service';
import {SelectionService, SliceService} from '../services/services';

Expand Down Expand Up @@ -453,7 +453,7 @@ export class GeneratorModule extends LitModule {
<div class="generators-panel">
${generators.map(genName => {
const spec = generatorsInfo[genName].configSpec;
const clonedSpec = JSON.parse(JSON.stringify(spec)) as Spec;
const clonedSpec = cloneSpec(spec);
const description = generatorsInfo[genName].description;
for (const fieldSpec of Object.values(clonedSpec)) {
// If the generator uses a field matcher, then get the matching
Expand Down
6 changes: 3 additions & 3 deletions lit_nlp/client/modules/salience_clustering_module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ import {InterpreterClick} from '../elements/interpreter_controls';
import {SortableTemplateResult, TableData} from '../elements/table';
import {FieldMatcher} from '../lib/lit_types';
import {styles as sharedStyles} from '../lib/shared_styles.css';
import {CallConfig, IndexedInput, Input, ModelInfoMap, Spec} from '../lib/types';
import {createLitType, findSpecKeys} from '../lib/utils';
import {CallConfig, IndexedInput, Input, ModelInfoMap} from '../lib/types';
import {cloneSpec, createLitType, findSpecKeys} from '../lib/utils';
import {ColumnData} from '../services/data_service';
import {DataService} from '../services/services';

Expand Down Expand Up @@ -382,7 +382,7 @@ export class SalienceClusteringModule extends LitModule {
// clang-format off
const renderInterpreterControls = (name: string) => {
const spec = this.appState.metadata.interpreters[name].configSpec;
const clonedSpec = JSON.parse(JSON.stringify(spec)) as Spec;
const clonedSpec = cloneSpec(spec);
for (const fieldSpec of Object.values(clonedSpec)) {
// If the generator uses a field matcher, then get the matching
// field names from the specified spec and use them as the vocab.
Expand Down
4 changes: 2 additions & 2 deletions lit_nlp/client/modules/salience_map_module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import {LitModule} from '../core/lit_module';
import {styles as sharedStyles} from '../lib/shared_styles.css';
import {LitName, FieldMatcher, Salience} from '../lib/lit_types';
import {CallConfig, ModelInfoMap, SCROLL_SYNC_CSS_CLASS, Spec} from '../lib/types';
import {findSpecKeys, isLitSubtype} from '../lib/utils';
import {cloneSpec, findSpecKeys, isLitSubtype} from '../lib/utils';
import {SalienceCmap, SignedSalienceCmap, UnsignedSalienceCmap} from '../services/color_service';
import {FocusData, FocusService} from '../services/focus_service';
import {AppState} from '../services/services';
Expand Down Expand Up @@ -365,7 +365,7 @@ export class SalienceMapModule extends LitModule {
// clang-format off
const renderMethodControls = (name: string) => {
const spec = this.appState.metadata.interpreters[name].configSpec;
const clonedSpec = JSON.parse(JSON.stringify(spec)) as Spec;
const clonedSpec = cloneSpec(spec);
for (const fieldSpec of Object.values(clonedSpec)) {
// If the generator uses a field matcher, then get the matching
// field names from the specified spec and use them as the vocab.
Expand Down
4 changes: 2 additions & 2 deletions lit_nlp/client/modules/tda_module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import {canonicalizeGenerationResults, GeneratedTextResult, GENERATION_TYPES, ge
import {styles as sharedStyles} from '../lib/shared_styles.css';
import {FieldMatcher, LitTypeWithParent} from '../lib/lit_types';
import {CallConfig, ComponentInfoMap, IndexedInput, Input, ModelInfoMap, Spec} from '../lib/types';
import {filterToKeys, findSpecKeys} from '../lib/utils';
import {cloneSpec, filterToKeys, findSpecKeys} from '../lib/utils';
import {AppState, SelectionService} from '../services/services';

import {styles} from './tda_module.css';
Expand Down Expand Up @@ -532,7 +532,7 @@ export class TrainingDataAttributionModule extends LitModule {

return this.compatibleGenerators.map((genName, i) => {
const spec = generatorsInfo[genName].configSpec;
const clonedSpec = JSON.parse(JSON.stringify(spec)) as Spec;
const clonedSpec = cloneSpec(spec);
const description = generatorsInfo[genName].description;
for (const fieldSpec of Object.values(clonedSpec)) {
// If the generator uses a field matcher, then get the matching
Expand Down

0 comments on commit 853edd0

Please sign in to comment.