Skip to content

Commit

Permalink
Support h5grove@2.0.0 and improve dtype parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
axelboc committed Jan 30, 2024
1 parent a4cc8de commit 80acdcc
Show file tree
Hide file tree
Showing 9 changed files with 1,014 additions and 199 deletions.

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/app/src/providers/h5grove/h5grove-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import type {
import { hasErrorMessage, parseEntity } from './utils';

export class H5GroveApi extends DataProviderApi {
/* API compatible with h5grove@1.3.0 */
/* API compatible with h5grove@2.0.0 */
public constructor(
url: string,
filepath: string,
Expand Down
89 changes: 81 additions & 8 deletions packages/app/src/providers/h5grove/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,39 +17,112 @@ export type H5GroveEntity =

export interface H5GroveBaseEntity {
name: string;
type: string;
kind: string;
}

export interface H5GroveGroup extends H5GroveBaseEntity {
type: EntityKind.Group;
kind: EntityKind.Group;
children?: H5GroveEntity[];
attributes: H5GroveAttribute[];
}

export interface H5GroveDataset extends H5GroveBaseEntity {
type: EntityKind.Dataset;
kind: EntityKind.Dataset;
shape: number[];
dtype: H5GroveDtype;
type: H5GroveType;
chunks: number[] | null;
filters: Filter[] | null;
attributes: H5GroveAttribute[];
}

export interface H5GroveSoftLink extends H5GroveBaseEntity {
type: 'soft_link';
kind: 'soft_link';
target_path: string;
}

export interface H5GroveExternalLink extends H5GroveBaseEntity {
type: 'external_link';
kind: 'external_link';
target_file: string;
target_path: string;
}

export interface H5GroveAttribute {
name: string;
shape: number[];
dtype: H5GroveDtype;
type: H5GroveType;
}

export type H5GroveDtype = string | { [k: string]: H5GroveDtype };
export type H5GroveType =
| H5GroveIntegerType
| H5GroveFloatType
| H5GroveTimeType
| H5GroveStringType
| H5GroveBitfieldType
| H5GroveOpaqueType
| H5GroveCompoundType
| H5GroveReferenceType
| H5GroveEnumType
| H5GroveVlenType
| H5GroveArrayType;

export interface H5GroveBaseType {
class: number;
size: number;
}

export interface H5GroveIntegerType extends H5GroveBaseType {
class: 0;
order: number;
sign: number;
}

export interface H5GroveFloatType extends H5GroveBaseType {
class: 1;
order: number;
}

export interface H5GroveTimeType extends H5GroveBaseType {
class: 2;
}

export interface H5GroveStringType extends H5GroveBaseType {
class: 3;
cset: number;
vlen: boolean;
}

export interface H5GroveBitfieldType extends H5GroveBaseType {
class: 4;
order: number;
}

export interface H5GroveOpaqueType extends H5GroveBaseType {
class: 5;
tag: string;
}

export interface H5GroveCompoundType extends H5GroveBaseType {
class: 6;
members: Record<string, H5GroveType>;
}

export interface H5GroveReferenceType extends H5GroveBaseType {
class: 7;
}

export interface H5GroveEnumType extends H5GroveBaseType {
class: 8;
members: Record<string, number>;
base: H5GroveType;
}

export interface H5GroveVlenType extends H5GroveBaseType {
class: 9;
base: H5GroveType;
}

export interface H5GroveArrayType extends H5GroveBaseType {
class: 10;
dims: number[];
base: H5GroveType;
}
126 changes: 99 additions & 27 deletions packages/app/src/providers/h5grove/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,61 +1,133 @@
import { Endianness } from '@h5web/shared/hdf5-models';
import {
arrayType,
bitfieldType,
boolType,
compoundType,
cplxType,
enumType,
floatType,
intType,
opaqueType,
referenceType,
strType,
timeType,
uintType,
unknownType,
} from '@h5web/shared/hdf5-utils';
import { describe, expect, it } from 'vitest';

import type { H5GroveType } from './models';
import { parseDType } from './utils';

describe('parseDType', () => {
it('should convert integer dtypes', () => {
expect(parseDType('<i4')).toStrictEqual(intType(32, Endianness.LE));
expect(parseDType('>u8')).toStrictEqual(uintType(64, Endianness.BE));
});

it('should convert float dtypes', () => {
expect(parseDType('<f4')).toStrictEqual(floatType(32, Endianness.LE));
expect(parseDType('>f8')).toStrictEqual(floatType(64, Endianness.BE));
it('should convert integer types', () => {
expect(parseDType({ class: 0, size: 1, order: 0, sign: 1 })).toStrictEqual(
intType(8, Endianness.LE),
);
expect(parseDType({ class: 0, size: 8, order: 1, sign: 0 })).toStrictEqual(
uintType(64, Endianness.BE),
);
});

it('should convert complex dtypes', () => {
expect(parseDType('<c8')).toStrictEqual(
cplxType(floatType(32, Endianness.LE), floatType(32, Endianness.LE)),
it('should convert float types', () => {
expect(parseDType({ class: 1, size: 4, order: 0 })).toStrictEqual(
floatType(32, Endianness.LE),
);
expect(parseDType({ class: 1, size: 8, order: 1 })).toStrictEqual(
floatType(64, Endianness.BE),
);
});

it('should convert bytes string dtypes', () => {
expect(parseDType('|S6')).toStrictEqual(strType('ASCII', 6));
it('should convert string types', () => {
expect(
parseDType({ class: 3, size: 6, cset: 0, vlen: false }),
).toStrictEqual(strType('ASCII', 6));
expect(
parseDType({ class: 3, size: 6, cset: 0, vlen: true }),
).toStrictEqual(strType('ASCII'));
expect(
parseDType({ class: 3, size: 6, cset: 1, vlen: false }),
).toStrictEqual(strType('UTF-8', 6));
expect(
parseDType({ class: 3, size: 6, cset: 1, vlen: true }),
).toStrictEqual(strType('UTF-8'));
});

it('should interpret objects as strings', () => {
expect(parseDType('|O')).toStrictEqual(strType('UTF-8'));
});
it('should convert compound and complex types', () => {
expect(
parseDType({
class: 6,
size: 4,
members: { foo: { class: 1, size: 4, order: 0 } },
}),
).toStrictEqual(compoundType({ foo: floatType() }));

it('should interpret |b1 as booleans', () => {
expect(parseDType('|b1')).toStrictEqual(boolType());
expect(
parseDType({
class: 6,
size: 8,
members: {
r: { class: 1, size: 4, order: 0 },
i: { class: 1, size: 4, order: 0 },
},
}),
).toStrictEqual(cplxType(floatType(), floatType()));
});

it('should handle "not applicable" endianness symbol', () => {
expect(parseDType('|f8')).toStrictEqual(floatType(64));
it('should convert enum and boolean types', () => {
expect(
parseDType({
class: 8,
size: 8,
base: { class: 0, size: 4, order: 0, sign: 0 },
members: { FOO: 41, BAR: 42 },
}),
).toStrictEqual(enumType(uintType(), { FOO: 41, BAR: 42 }));

expect(
parseDType({
class: 8,
size: 2,
base: { class: 0, size: 1, order: 0, sign: 0 },
members: { FALSE: 0, TRUE: 1 },
}),
).toStrictEqual(boolType());
});

it('should convert compound dtype', () => {
expect(parseDType({ country: '|S10', population: '<i4' })).toStrictEqual(
compoundType({
country: strType('ASCII', 10),
population: intType(32, Endianness.LE),
it('should convert array types', () => {
expect(
parseDType({
class: 9,
size: 1,
base: { class: 1, size: 4, order: 0 },
}),
).toStrictEqual(arrayType(floatType()));

expect(
parseDType({
class: 10,
size: 1,
base: { class: 1, size: 4, order: 0 },
dims: [2, 3],
}),
).toStrictEqual(arrayType(floatType(), [2, 3]));
});

it('should convert other types', () => {
expect(parseDType({ class: 2, size: 1 })).toStrictEqual(timeType());
expect(parseDType({ class: 4, size: 1, order: 0 })).toStrictEqual(
bitfieldType(Endianness.LE),
);
expect(parseDType({ class: 5, size: 1, tag: 'foo' })).toStrictEqual(
opaqueType('foo'),
);
expect(parseDType({ class: 7, size: 1 })).toStrictEqual(referenceType());
});

it('should handle unknown type', () => {
expect(parseDType('>notAType')).toStrictEqual(unknownType());
it('should handle unknown types', () => {
expect(
parseDType({ class: 100, size: 1 } as unknown as H5GroveType),
).toStrictEqual(unknownType());
});
});
Loading

0 comments on commit 80acdcc

Please sign in to comment.