Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: python API #10

Draft
wants to merge 101 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
46f8722
Addition of reference folder and schemapi reference files
Hamzu24 Sep 10, 2024
eb2682e
Created example-api-usage file
Hamzu24 Sep 14, 2024
de5fb5b
Moved example-api-usgae
Hamzu24 Sep 15, 2024
21acdda
Initial comments
Hamzu24 Sep 15, 2024
e5fb1c7
reference/generate_schema_wrapper_commented.py
Hamzu24 Sep 15, 2024
03ef6cf
Added first round of comments
Hamzu24 Sep 15, 2024
589140a
add comments
Xinyue-Yang Sep 16, 2024
aacac75
add comments (#1)
Xinyue-Yang Sep 16, 2024
4d8a839
Adding generate_mosaic_schema_wrapper.py
mhli1260 Sep 20, 2024
89b5c18
Creating generate_mosaic_schema_wrapper.py
mhli1260 Sep 20, 2024
8567d66
creating general outline for file
mhli1260 Sep 20, 2024
ebaa400
Merge branch 'main' of github.com:Hamzu24/mosaic
Hamzu24 Sep 23, 2024
248abdf
More comments
Hamzu24 Sep 24, 2024
3c2503d
Initial draft of the schema generator
Hamzu24 Sep 25, 2024
64704b4
adding recursive_dict_update and get_field_datum_value_defs
mhli1260 Sep 25, 2024
77b5954
Merge pull request #4 from mhli1260/patch-2
mhli1260 Sep 25, 2024
e481186
simple schema
Xinyue-Yang Sep 26, 2024
8f2e673
Merge branch 'main' of https://github.com/Hamzu24/mosaic
Xinyue-Yang Sep 26, 2024
80e06ea
Merge pull request #2 from mhli1260/main
mhli1260 Sep 26, 2024
d544c28
delete extra file
mhli1260 Sep 26, 2024
fb033ef
add part of utils
Xinyue-Yang Sep 26, 2024
7272f86
Merge branch 'main' of https://github.com/Hamzu24/mosaic
Xinyue-Yang Sep 26, 2024
3ede84d
anyOf and ref handles
mhli1260 Oct 2, 2024
bcb8861
deleting extra comments
mhli1260 Oct 2, 2024
ed36a29
Merge pull request #6 from Hamzu24/mia-branch
mhli1260 Oct 2, 2024
b1768d6
Up to date for meeting on 2/10/24
Hamzu24 Oct 2, 2024
21c1aa9
Small update
Hamzu24 Oct 2, 2024
4b6586d
build package for generator
Xinyue-Yang Oct 8, 2024
aea01d4
Made the schema wrapper into a python package plus a few other features
Hamzu24 Oct 8, 2024
cb3d58e
add get_valid_identifier
Xinyue-Yang Oct 8, 2024
9f2fa00
Cleaned up the package
Hamzu24 Oct 8, 2024
ae585e2
Merge branch 'main' of github.com:Hamzu24/mosaic
mhli1260 Oct 9, 2024
86d148f
Moved functions to utils from main file
Hamzu24 Oct 9, 2024
5092821
implemented get_valid_identifiers
Hamzu24 Oct 9, 2024
066616f
Fixed error in ensuring valid identifiers and cleaned up
Hamzu24 Oct 9, 2024
7d98293
Final fix
Hamzu24 Oct 9, 2024
03172e5
Merge branch 'main' of github.com:Hamzu24/mosaic
mhli1260 Oct 9, 2024
d8451d8
changing path of output file generated_classes.py
mhli1260 Oct 9, 2024
29af85f
Moving the package to packages folder
Hamzu24 Oct 18, 2024
9d7acf9
Amended path to generated classes
Hamzu24 Oct 18, 2024
a94a495
Amended path to parent
Hamzu24 Oct 18, 2024
efdc54d
Merge branch 'main' of github.com:Hamzu24/mosaic
mhli1260 Oct 18, 2024
c516246
fix importing dict bug,delete legacy code
Xinyue-Yang Oct 18, 2024
9c87fa7
fix quoting around references
mhli1260 Oct 18, 2024
3f89e2c
Merge branch 'main' of github.com:Hamzu24/mosaic
mhli1260 Oct 18, 2024
c1dde0f
Added a list as a type which can be generated
Hamzu24 Oct 18, 2024
e2cff16
Removed a lot of redundancy
Hamzu24 Oct 18, 2024
8b8ea00
add test cases
Xinyue-Yang Oct 20, 2024
c877a78
Removed unnecessary comments
Hamzu24 Oct 22, 2024
d40d937
Merged others changes to my local ones
Hamzu24 Oct 22, 2024
231f6f6
Refined the typing system further
Hamzu24 Oct 22, 2024
4a2aae0
adding test cases
mhli1260 Oct 22, 2024
c5c33fc
Merge branch 'main' of github.com:Hamzu24/mosaic
mhli1260 Oct 22, 2024
9c0b1c0
Fixed negligence
Hamzu24 Oct 22, 2024
48eadc6
Merge branch 'main' of github.com:Hamzu24/mosaic
mhli1260 Oct 22, 2024
5a69500
Finalised the typing
Hamzu24 Oct 22, 2024
c04f379
fixing parameter type errors
mhli1260 Oct 23, 2024
af3ec06
fixing parameter type errors
mhli1260 Oct 23, 2024
c39832e
fixing parameter type errors
mhli1260 Oct 23, 2024
fe1125a
additional test cases
mhli1260 Oct 23, 2024
550e204
add pytest
Xinyue-Yang Oct 28, 2024
785a0f5
add automated testing in github workflow
Xinyue-Yang Oct 28, 2024
34272fe
create virtual environment
Xinyue-Yang Nov 5, 2024
58b7efc
to_dict function
Hamzu24 Nov 5, 2024
1e3b019
Merge branch 'main' of github.com:Hamzu24/mosaic
Hamzu24 Nov 5, 2024
eeb9d1a
can now create a spec usable by mosaic_widget
Hamzu24 Nov 6, 2024
441c55d
switched to hatch test framework
Xinyue-Yang Nov 6, 2024
cf221e3
Merge branch 'main' of https://github.com/Hamzu24/mosaic
Xinyue-Yang Nov 6, 2024
e0b2b94
switched to hatch testing framework
Xinyue-Yang Nov 6, 2024
4f6a09a
add testing widget plot
Xinyue-Yang Nov 12, 2024
f563bff
Updated files
Hamzu24 Nov 12, 2024
7337f89
one more file
Hamzu24 Nov 12, 2024
5a2fa6f
Updated utils
Hamzu24 Nov 12, 2024
798e762
Corrected schema wrapper function
Hamzu24 Nov 12, 2024
5ba32b5
final version updated
Hamzu24 Nov 12, 2024
31f7b9e
updating spec tests
mhli1260 Nov 12, 2024
7e792bd
Updated to use SchemaBase parent class
Hamzu24 Nov 12, 2024
998297b
Final commit
Hamzu24 Nov 12, 2024
e347d79
final commit
Hamzu24 Nov 12, 2024
4f0be93
Took changes from origin/main for tools/schemapi/schemapi.py
mhli1260 Nov 20, 2024
8613764
Resolved conflicts and kept .gitignore from upstream/main
mhli1260 Nov 20, 2024
91ea687
lint fixes
mhli1260 Nov 20, 2024
c6565db
delete tools
mhli1260 Nov 20, 2024
30521cc
atomated testing
Xinyue-Yang Nov 20, 2024
bc10d61
Merge branch 'main' of https://github.com/Hamzu24/mosaic
Xinyue-Yang Nov 20, 2024
d6ad7a5
create ast to python and convert all examples into python
Xinyue-Yang Nov 20, 2024
70f87cf
ast-to-python with invalid mark
Xinyue-Yang Nov 20, 2024
c04da0c
Merge branch 'main' of github.com:Hamzu24/mosaic
Hamzu24 Dec 3, 2024
86380f9
fixes
Hamzu24 Dec 3, 2024
03aa838
git ignore update
Hamzu24 Dec 3, 2024
f128540
Up to date with main
Hamzu24 Dec 3, 2024
d887971
Tracking everything
Hamzu24 Dec 3, 2024
af9370a
Merged latest changes, including SchemaBase class, AST conversion and…
Hamzu24 Dec 3, 2024
1c182e1
Inheritance fix
Hamzu24 Dec 3, 2024
0577d28
Fixed the merge
Hamzu24 Dec 3, 2024
a100659
Fixing errors in imports in the schema
Hamzu24 Dec 3, 2024
f856af6
Fixed empty dictionary error
Hamzu24 Dec 3, 2024
b47a24f
fix node errors
mhli1260 Dec 4, 2024
061a2f8
Merge branch 'main' into pythonAPI
mhli1260 Dec 4, 2024
513d4a6
options node test error fix
mhli1260 Dec 4, 2024
3a1e1ca
Delete tools directory
mhli1260 Dec 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ jobs:

- name: Format and lint
run: |
python -m pip install --upgrade pip
pip install hatch pytest pytest-cov
uv run ruff check
uv run ruff format --check

Expand All @@ -63,6 +65,12 @@ jobs:
uv run mypy
uv run --with pytest-cov pytest --cov-report=term-missing --color=yes --cov=pkg

- name: Build and test Schema Wrapper
run: |
cd packages/schema_wrapper
pip install -e .
pytest test/ --cov=schema_wrapper --cov-report=term-missing

rust:
name: Test in Rust

Expand Down
19 changes: 19 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,22 @@ packages/*/test-output
**/.mypy_cache
**/.coverage
**/.venv
transitionFolder

# Virtual environment
venv/
.env/

# Conda environment
conda-env/

# Python cache
__pycache__/
*.pyc

# Test cache
.pytest_cache/
.coverage

# Python API Generated classes
packages/schema_wrapper/generated_classes.py
154 changes: 82 additions & 72 deletions bin/prepare-examples.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
#!/usr/bin/env node
import { basename, extname, join, resolve } from 'node:path';
import { copyFile, readdir, readFile, writeFile } from 'node:fs/promises';
import { parseSpec, astToESM } from '@uwdata/mosaic-spec';
import { parse } from 'yaml';
import { basename, extname, join, resolve } from "node:path";
import {
copyFile,
readdir,
readFile,
writeFile,
mkdir,
} from "node:fs/promises";
import { parseSpec, astToESM, astToPython } from "@uwdata/mosaic-spec";
import { parse } from "yaml";

// This script prepares all Mosaic example specifications
// ...AND WILL OVERWRITE EXISTING TEST CASE DATA AND DOCS!
Expand All @@ -11,86 +17,90 @@ import { parse } from 'yaml';
// - YAML, non-parsed JSON, and ESM code written to /docs/public/specs
// - Example Markdown pages written to /docs/examples

const specDir = join('specs', 'yaml');
const esmTestDir = join('specs', 'esm');
const jsonTestDir = join('specs', 'json');
const tsTestDir = join('specs', 'ts');
const specDir = join("specs", "yaml");
const esmTestDir = join("specs", "esm");
const jsonTestDir = join("specs", "json");
const tsTestDir = join("specs", "ts");
const pythonTestDir = join("specs", "python");

const docsDir = 'docs';
const yamlDocsDir = join(docsDir, 'public', 'specs', 'yaml');
const jsonDocsDir = join(docsDir, 'public', 'specs', 'json');
const esmDocsDir = join(docsDir, 'public', 'specs', 'esm');
const exampleDir = join(docsDir, 'examples');
const docsDir = "docs";
const yamlDocsDir = join(docsDir, "public", "specs", "yaml");
const jsonDocsDir = join(docsDir, "public", "specs", "json");
const esmDocsDir = join(docsDir, "public", "specs", "esm");
const exampleDir = join(docsDir, "examples");
const pythonDocsDir = join(docsDir, "public", "specs", "python");

const specToTS = spec => {
const specToTS = (spec) => {
return `import { Spec } from '@uwdata/mosaic-spec';

export const spec : Spec = ${JSON.stringify(spec, 0, 2)};
`;
}
};

const files = await Promise.allSettled((await readdir(specDir))
.filter(name => extname(name) === '.yaml')
.map(async name => {
const base = basename(name, '.yaml');
const file = resolve(specDir, name);
const text = await readFile(file, 'utf8');
// Create directories if they don't exist
await Promise.all([
mkdir(pythonTestDir, { recursive: true }),
mkdir(pythonDocsDir, { recursive: true }),
]).catch(console.error);

// parse spec and perform code generation
// do this first to catch any errors
const spec = parse(text);
const ast = parseSpec(spec);
const code = astToESM(ast);
const files = await Promise.allSettled(
(
await readdir(specDir)
)
.filter((name) => extname(name) === ".yaml")
.map(async (name) => {
const base = basename(name, ".yaml");
const file = resolve(specDir, name);
const text = await readFile(file, "utf8");

try {
await Promise.all([
// write ESM DSL spec to tests
writeFile(resolve(esmTestDir, `${base}.js`), code),
// write JSON spec to tests
writeFile(
resolve(jsonTestDir, `${base}.json`),
JSON.stringify(ast.toJSON(), 0, 2)
),
// write TS JSON spec to tests
writeFile(
resolve(tsTestDir, `${base}.ts`),
specToTS(spec)
),
// copy YAML file to docs
copyFile(file, resolve(yamlDocsDir, `${base}.yaml`)),
// write JSON spec to docs
writeFile(
resolve(jsonDocsDir, `${base}.json`),
JSON.stringify(spec, 0, 2)
),
// write ESM DSL spec to docs
writeFile(resolve(esmDocsDir, `${base}.js`), code),
// write examples page to docs
writeFile(
resolve(exampleDir, `${base}.md`),
examplePage(base, spec.meta)
)
]);
} catch (err) {
console.error(err);
}
// parse spec and perform code generation
// do this first to catch any errors
const spec = parse(text);
const ast = parseSpec(spec);
const code = astToESM(ast);

return base;
})
);
try {
await Promise.all([
// write ESM DSL spec to tests
writeFile(resolve(esmTestDir, `${base}.js`), code),
// write JSON spec to tests
writeFile(
resolve(jsonTestDir, `${base}.json`),
JSON.stringify(ast.toJSON(), 0, 2)
),
// write TS JSON spec to tests
writeFile(resolve(tsTestDir, `${base}.ts`), specToTS(spec)),
// copy YAML file to docs
copyFile(file, resolve(yamlDocsDir, `${base}.yaml`)),
// write JSON spec to docs
writeFile(
resolve(jsonDocsDir, `${base}.json`),
JSON.stringify(spec, 0, 2)
),
// write ESM DSL spec to docs
writeFile(resolve(esmDocsDir, `${base}.js`), code),
// write examples page to docs
writeFile(
resolve(exampleDir, `${base}.md`),
examplePage(base, spec.meta)
),
// write Python spec to tests
writeFile(resolve(pythonTestDir, `${base}.py`), astToPython(ast)),
// write Python spec to docs
writeFile(resolve(pythonDocsDir, `${base}.py`), astToPython(ast)),
]);
} catch (err) {
console.error(err);
}

// output successfully written examples
console.log(JSON.stringify(
files
.filter(x => x.status === 'fulfilled')
.map(x => x.value),
0, 2
));
return base;
})
);

// output unsuccessful example errors
files
.filter(x => x.status === 'rejected')
.forEach(x => console.error(x.reason));
.filter((x) => x.status === "rejected")
.forEach((x) => console.error(x.reason));

function examplePage(spec, { title = spec, description, credit } = {}) {
return `<script setup>
Expand All @@ -99,9 +109,9 @@ function examplePage(spec, { title = spec, description, credit } = {}) {
</script>

# ${title}
${description ? `\n${description.trim()}\n` : ''}
${description ? `\n${description.trim()}\n` : ""}
<Example spec="/specs/yaml/${spec}.yaml" />
${credit ? `\n**Credit**: ${credit}\n` : ''}
${credit ? `\n**Credit**: ${credit}\n` : ""}
## Specification

::: code-group
Expand Down
19 changes: 19 additions & 0 deletions docs/public/specs/python/aeromagnetic-survey.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from mosaic import *
from mosaic.spec import *
from mosaic.generated_classes import *
from typing import Dict, Any, Union


ca55 = DataSource(
type="parquet",
file="data/ca55-south.parquet",
where=""
)

spec = Plot(
plot=[
PlotMark(Raster(mark="raster", data=PlotFrom(from_="ca55"), x=ChannelValueSpec(ChannelValue("LONGITUDE")), y=ChannelValueSpec(ChannelValue("LATITUDE")), fill=ChannelValueSpec(ChannelValue({"max":"MAG_IGRF90"}))))
],
width=None,
height=None
)
28 changes: 28 additions & 0 deletions docs/public/specs/python/airline-travelers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from mosaic import *
from mosaic.spec import *
from mosaic.generated_classes import *
from typing import Dict, Any, Union


travelers = DataSource(
type="parquet",
file="data/travelers.parquet",
where=""
)
endpoint = DataSource(
type="table",
file="undefined",
where=""
)

spec = Plot(
plot=[
PlotMark(RuleY(mark="ruleY")),
PlotMark(LineY(mark="lineY", data=PlotFrom(from_="travelers"), x=ChannelValueSpec(ChannelValue("date")), y=ChannelValueSpec(ChannelValue("previous")), strokeOpacity=0.35)),
PlotMark(LineY(mark="lineY", data=PlotFrom(from_="travelers"), x=ChannelValueSpec(ChannelValue("date")), y=ChannelValueSpec(ChannelValue("current")))),
PlotMark(Text(mark="text", data=PlotFrom(from_="endpoint"), x=ChannelValueSpec(ChannelValue("date")), y=ChannelValueSpec(ChannelValue("previous")), fillOpacity=0.5, dy=-6)),
PlotMark(Text(mark="text", data=PlotFrom(from_="endpoint"), x=ChannelValueSpec(ChannelValue("date")), y=ChannelValueSpec(ChannelValue("current")), dy=6))
],
width=None,
height=None
)
20 changes: 20 additions & 0 deletions docs/public/specs/python/athlete-height.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from mosaic import *
from mosaic.spec import *
from mosaic.generated_classes import *
from typing import Dict, Any, Union


athletesBatched = DataSource(
type="parquet",
file="data/athletes.parquet",
where="height IS NOT NULL"
)

spec = Plot(
plot=[
PlotMark(ErrorbarX(mark="errorbarX", data=PlotFrom(from_="athletesBatched", filterBy=$query), x=ChannelValueSpec(ChannelValue("height")), y=ChannelValueSpec(ChannelValue("sport")), stroke=ChannelValueSpec(ChannelValue("sex")), strokeWidth=1)),
PlotMark(Text(mark="text", data=PlotFrom(from_="athletesBatched"), y=ChannelValueSpec(ChannelValue("sport")), fill=ChannelValueSpec(ChannelValue("#999")), frameAnchor="right"))
],
width=None,
height=420
)
22 changes: 22 additions & 0 deletions docs/public/specs/python/athletes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from mosaic import *
from mosaic.spec import *
from mosaic.generated_classes import *
from typing import Dict, Any, Union


athletes = DataSource(
type="parquet",
file="data/athletes.parquet",
where=""
)

spec = Plot(
plot=[
PlotMark(Dot(mark="dot", data=PlotFrom(from_="athletes", filterBy=$query), x=ChannelValueSpec(ChannelValue("weight")), y=ChannelValueSpec(ChannelValue("height")), fill=ChannelValueSpec(ChannelValue("sex")), r=2)),
PlotMark(RegressionY(mark="regressionY", data=PlotFrom(from_="athletes", filterBy=$query), x=ChannelValueSpec(ChannelValue("weight")), y=ChannelValueSpec(ChannelValue("height")), stroke=ChannelValueSpec(ChannelValue("sex")))),
PlotMark(),
PlotMark(Dot(mark="dot", data=PlotFrom(from_="athletes", filterBy=$hover), x=ChannelValueSpec(ChannelValue("weight")), y=ChannelValueSpec(ChannelValue("height")), fill=ChannelValueSpec(ChannelValue("sex")), stroke=ChannelValueSpec(ChannelValue("currentColor")), strokeWidth=1, r=3))
],
width=570,
height=350
)
19 changes: 19 additions & 0 deletions docs/public/specs/python/axes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from mosaic import *
from mosaic.spec import *
from mosaic.generated_classes import *
from typing import Dict, Any, Union



spec = Plot(
plot=[
PlotMark(GridY(mark="gridY", strokeOpacity=1)),
PlotMark(AxisY(mark="axisY", dy=-4)),
PlotMark(AxisY(mark="axisY")),
PlotMark(AxisX(mark="axisX")),
PlotMark(GridX(mark="gridX")),
PlotMark(RuleY(mark="ruleY"))
],
width=680,
height=None
)
19 changes: 19 additions & 0 deletions docs/public/specs/python/bias.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from mosaic import *
from mosaic.spec import *
from mosaic.generated_classes import *
from typing import Dict, Any, Union


walk = DataSource(
type="parquet",
file="data/random-walk.parquet",
where=""
)

spec = Plot(
plot=[
PlotMark(AreaY(mark="areaY", data=PlotFrom(from_="walk"), x=ChannelValueSpec(ChannelValue("t")), y=ChannelValueSpec(ChannelValue(sql="v + $point")), fill=ChannelValueSpec(ChannelValue("steelblue"))))
],
width=680,
height=200
)
21 changes: 21 additions & 0 deletions docs/public/specs/python/contours.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from mosaic import *
from mosaic.spec import *
from mosaic.generated_classes import *
from typing import Dict, Any, Union


penguins = DataSource(
type="parquet",
file="data/penguins.parquet",
where=""
)

spec = Plot(
plot=[
PlotMark(Heatmap(mark="heatmap", data=PlotFrom(from_="penguins"), x=ChannelValueSpec(ChannelValue("bill_length")), y=ChannelValueSpec(ChannelValue("bill_depth")), fill=ChannelValueSpec(ChannelValue("species")))),
PlotMark(Contour(mark="contour", data=PlotFrom(from_="penguins"), x=ChannelValueSpec(ChannelValue("bill_length")), y=ChannelValueSpec(ChannelValue("bill_depth")), stroke=ChannelValueSpec(ChannelValue("species")))),
PlotMark(Dot(mark="dot", data=PlotFrom(from_="penguins"), x=ChannelValueSpec(ChannelValue("bill_length")), y=ChannelValueSpec(ChannelValue("bill_depth")), fill=ChannelValueSpec(ChannelValue("currentColor")), r=1))
],
width=700,
height=480
)
Loading
Loading