From 4ae757223eb4e42596e7c2b579be6e15ebac24c1 Mon Sep 17 00:00:00 2001 From: Jess Frazelle Date: Wed, 19 Jun 2024 17:31:37 -0700 Subject: [PATCH] updates Signed-off-by: Jess Frazelle --- Cargo.lock | 2 +- Cargo.toml | 2 +- files/lego.kcl | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 21 ++++++++--- tests/tests.py | 43 +++++++++++++++++++++- 5 files changed, 156 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5b5c374..1eb3ea3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3488,7 +3488,7 @@ dependencies = [ [[package]] name = "zoo-kcl" -version = "0.1.2" +version = "0.1.3" dependencies = [ "anyhow", "kcl-lib", diff --git a/Cargo.toml b/Cargo.toml index a55cc32..0858659 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zoo-kcl" -version = "0.1.2" +version = "0.1.3" edition = "2021" repository = "https://github.com/kittycad/kcl.py" diff --git a/files/lego.kcl b/files/lego.kcl index e69de29..65abac8 100644 --- a/files/lego.kcl +++ b/files/lego.kcl @@ -0,0 +1,96 @@ +// Lego Brick +// A standard Lego brick. This is a small, plastic construction block toy that can be interlocked with other blocks to build various structures, models, and figures. There are a lot of hacks used in this code. + +// Define constants +const lbumps = 5 // number of bumps long +const wbumps = 3 // number of bumps wide +const pitch = 8.0 +const clearance = 0.1 +const bumpDiam = 4.8 +const bumpHeight = 1.8 +const height = 3.2 +const t = (pitch - (2 * clearance) - bumpDiam) / 2.0 +const postDiam = pitch - t // works out to 6.5 +const totalLength = lbumps * pitch - (2.0 * clearance) +const totalWidth = wbumps * pitch - (2.0 * clearance) +const throw_lint = 0 + +const lSegments = totalLength / (lbumps) +const wSegments = totalWidth / (wbumps) + +// Create the plane for the pegs. This is a hack so that the pegs can be patterned along the face of the lego base. +const pegFace = { + plane: { + origin: { x: 0, y: 0, z: height }, + x_axis: { x: 1, y: 0, z: 0 }, + y_axis: { x: 0, y: 1, z: 0 }, + z_axis: { x: 0, y: 0, z: 1 } + } +} + +// Create the plane for the tubes underneath the lego. This is a hack so that the tubes can be patterned underneath the lego. +const tubeFace = { + plane: { + origin: { x: 0, y: 0, z: height - t }, + x_axis: { x: 1, y: 0, z: 0 }, + y_axis: { x: 0, y: 1, z: 0 }, + z_axis: { x: 0, y: 0, z: 1 } + } +} + +// Make the base +const s = startSketchOn('XY') + |> startProfileAt([-totalWidth / 2, -totalLength / 2], %) + |> line([totalWidth, 0], %) + |> line([0, totalLength], %) + |> line([-totalWidth, 0], %) + |> close(%) + |> extrude(height, %) + +// Sketch and extrude a rectangular shape to create the shell underneath the lego. This is a hack until we have a shell function. +const shellExtrude = startSketchOn(s, "start") + |> startProfileAt([ + -(totalWidth / 2 - t), + -(totalLength / 2 - t) + ], %) + |> line([totalWidth - (2 * t), 0], %) + |> line([0, totalLength - (2 * t)], %) + |> line([-(totalWidth - (2 * t)), 0], %) + |> close(%) + |> extrude(-(height - t), %) + +// Create the pegs on the top of the base +const peg = startSketchOn(s, 'end') + |> circle([ + -(pitch*(wbumps-1)/2), + -(pitch*(lbumps-1)/2) + ], bumpDiam / 2, %) + |> patternLinear2d({ + axis: [1, 0], + repetitions: wbumps-1, + distance: pitch + }, %) + |> patternLinear2d({ + axis: [0, 1], + repetitions: lbumps-1, + distance: pitch + }, %) + |> extrude(bumpHeight, %) + +// Create the pegs on the bottom of the base +const tubePattern = startSketchOn(tubeFace) + |> circle([ + -(pitch*(wbumps-1)/2-pitch/2), + -(pitch*(lbumps-1)/2-pitch/2) + ], bumpDiam/2, %) + |> patternLinear2d({ + axis: [1, 0], + repetitions: wbumps-2, + distance: pitch + }, %) + |> patternLinear2d({ + axis: [0, 1], + repetitions: lbumps-2, + distance: pitch + }, %) + |> extrude(-bumpHeight, %) diff --git a/src/lib.rs b/src/lib.rs index 8258a9a..65aef09 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,11 +1,10 @@ use anyhow::Result; use kcl_lib::{ - ast::types::FormatOptions, executor::{ExecutorContext, ExecutorSettings}, lint::{checks, Discovered}, settings::types::UnitLength, }; -use pyo3::{pyclass, pyfunction, pymodule, types::PyModule, wrap_pyfunction, Bound, PyErr, PyResult}; +use pyo3::{pyclass, pyfunction, pymethods, pymodule, types::PyModule, wrap_pyfunction, Bound, PyErr, PyResult}; use serde::{Deserialize, Serialize}; fn tokio() -> &'static tokio::runtime::Runtime { @@ -62,6 +61,19 @@ impl From for ExportFile { } } +#[pymethods] +impl ExportFile { + #[getter] + fn contents(&self) -> Vec { + self.contents.clone() + } + + #[getter] + fn name(&self) -> String { + self.name.clone() + } +} + /// The valid types of output file formats. #[derive(Serialize, Deserialize, PartialEq, Hash, Debug, Clone)] #[pyclass] @@ -286,11 +298,11 @@ async fn execute_and_export( /// Format the kcl code. #[pyfunction] -fn format(code: String, format_options: FormatOptions) -> PyResult { +fn format(code: String) -> PyResult { let tokens = kcl_lib::token::lexer(&code).map_err(PyErr::from)?; let parser = kcl_lib::parser::Parser::new(tokens); let program = parser.ast().map_err(PyErr::from)?; - let recasted = program.recast(&format_options, 0); + let recasted = program.recast(&Default::default(), 0); Ok(recasted) } @@ -316,7 +328,6 @@ fn kcl(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_class::()?; - m.add_class::()?; m.add_class::()?; // Add our functions to the module. diff --git a/tests/tests.py b/tests/tests.py index 4db47a2..7d50582 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -15,9 +15,50 @@ async def test_kcl_execute_and_snapshot(): # Read from a file. with open(os.path.join(kcl_dir_file_path, "lego.kcl"), "r") as f: code = str(f.read()) - print(code) + assert code is not None + assert len(code) > 0 image_bytes = await kcl.execute_and_snapshot( code, kcl.UnitLength.Mm, kcl.ImageFormat.Jpeg ) assert image_bytes is not None assert len(image_bytes) > 0 + +@pytest.mark.asyncio +async def test_kcl_execute_and_export(): + # Read from a file. + with open(os.path.join(kcl_dir_file_path, "lego.kcl"), "r") as f: + code = str(f.read()) + assert code is not None + assert len(code) > 0 + files = await kcl.execute_and_export( + code, kcl.UnitLength.Mm, kcl.FileExportFormat.Step + ) + assert files is not None + assert len(files) > 0 + assert files[0] is not None + assert files[0].name() is not None + assert len(files[0].name()) > 0 + assert files[0].contents() is not None + assert len(files[0].contents()) > 0 + +def test_kcl_format(): + # Read from a file. + with open(os.path.join(kcl_dir_file_path, "lego.kcl"), "r") as f: + code = str(f.read()) + assert code is not None + assert len(code) > 0 + formatted_code = kcl.format(code) + assert formatted_code is not None + assert len(formatted_code) > 0 + +def test_kcl_lint(): + # Read from a file. + with open(os.path.join(kcl_dir_file_path, "lego.kcl"), "r") as f: + code = str(f.read()) + assert code is not None + assert len(code) > 0 + lints = kcl.lint(code) + assert lints is not None + assert len(lints) > 0 + +