Skip to content

Commit

Permalink
Use descriptor protocol for Param (#83)
Browse files Browse the repository at this point in the history
- Converted Param to use descriptor protocol
- Added --destination to vsk save
- Updated all examples
- Added a test to run all examples
- vsk commands now have exit status of 1 on error condition
  • Loading branch information
abey79 authored Feb 17, 2021
1 parent 0fa373b commit bd2da99
Show file tree
Hide file tree
Showing 15 changed files with 127 additions and 93 deletions.
2 changes: 1 addition & 1 deletion .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#### Checklist

- [ ] feature/fix implemented
- [ ] `mypy vsketch tests` returns no error
- [ ] `mypy` returns no error
- [ ] tests added/updated and `pytest --runslow` succeeds
- [ ] documentation added/updated and building with no error (`make clean && make html` in `docs/`)
- [ ] examples added/updated
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,4 @@ dmypy.json

/mywork/
/profile
.idea
8 changes: 4 additions & 4 deletions examples/bezier_bugs/sketch_bezier_bugs.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ class BezierBugSketch(vsketch.Vsketch):
def draw(self) -> None:
self.size("10in", "10in")

for row in range(self.row_count()):
for col in range(self.column_count()):
x = col * self.column_offset()
y = row * self.row_offset()
for row in range(self.row_count):
for col in range(self.column_count):
x = col * self.column_offset
y = row * self.row_offset
bug(self, x, y)

def finalize(self) -> None:
Expand Down
4 changes: 2 additions & 2 deletions examples/detail/sketch_detail.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@


class DetailSketch(vsketch.Vsketch):
detail_mm = vsketch.Param(1, 1, 50)
detail_value = vsketch.Param(1, 1, 50, unit="mm")

def draw(self) -> None:
self.size("a5", landscape=True)
self.scale("1.5cm")

self.detail(f"{self.detail_mm()}mm")
self.detail(self.detail_value)

self.circle(0, 0, 1)
self.circle(0, 0, 2)
Expand Down
6 changes: 3 additions & 3 deletions examples/noise_bezier/sketch_noise_bezier.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ def draw(self) -> None:
self.size("a4", landscape=False)
self.scale("cm")

for i in range(self.N()):
t = i * self.freq()
v = i * self.drift()
for i in range(self.N):
t = i * self.freq
v = i * self.drift
self.bezier(
self.noise(t, 0) * 10 + v,
self.noise(t, 1000) * 10 + v,
Expand Down
4 changes: 2 additions & 2 deletions examples/prime_circles/sketch_prime_circles.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ def draw(self) -> None:
self.size("10in", "10in")
self.scale("3mm")

for i, prime in enumerate(get_primes(self.N())):
for i, prime in enumerate(get_primes(self.N)):
self.circle(0, 0, 2 * (i + 1))

if self.random_phase():
if self.random_phase:
phase = np.random.random() * 2 * math.pi
else:
phase = -math.pi / 2
Expand Down
26 changes: 12 additions & 14 deletions examples/quick_draw/sketch_quick_draw.py
Original file line number Diff line number Diff line change
Expand Up @@ -417,11 +417,11 @@ class QuickDrawSketch(vsketch.Vsketch):
scale_factor = vsketch.Param(3.0)

def draw(self) -> None:
self.size(self.page_size(), landscape=self.landscape())
self.size(self.page_size, landscape=self.landscape)
self.penWidth("0.5mm")

# obtain the datafile
file_name = self.category() + ".bin"
file_name = self.category + ".bin"
file_path = pathlib.Path(file_name)
url = "https://storage.googleapis.com/quickdraw_dataset/full/binary/"
url += file_name.replace(" ", "%20")
Expand All @@ -434,25 +434,23 @@ def draw(self) -> None:

# draw stuff

width = self.width - 2 * self.margins()
height = self.height - 2 * self.margins()
width = self.width - 2 * self.margins
height = self.height - 2 * self.margins

n = self.columns() * self.rows()
n = self.columns * self.rows
samples = random.sample(drawing_subset, n)
for j in range(self.rows()):
for j in range(self.rows):
with self.pushMatrix():
for i in range(self.columns()):
idx = j * self.columns() + i
for i in range(self.columns):
idx = j * self.columns + i
with self.pushMatrix():
self.scale(
self.scale_factor() * min(1 / self.columns(), 1 / self.rows())
)
self.scale(self.scale_factor * min(1 / self.columns, 1 / self.rows))
drawing = quickdraw_to_linestring(samples[idx])
self.stroke((idx % self.layer_count()) + 1)
self.stroke((idx % self.layer_count) + 1)
self.geometry(drawing)
self.translate(width / self.columns(), 0)
self.translate(width / self.columns, 0)

self.translate(0, height / self.rows())
self.translate(0, height / self.rows)

def finalize(self) -> None:
self.vpype("linemerge linesort")
Expand Down
8 changes: 4 additions & 4 deletions examples/random_flower/sketch_random_flower.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@ def draw(self) -> None:

self.rotate(-90, degrees=True)

noise_coord = np.linspace(0, 1, self.point_per_line())
noise_coord = np.linspace(0, 1, self.point_per_line)

dirs = np.linspace(0, 2 * math.pi, self.num_line())
dirs = np.linspace(0, 2 * math.pi, self.num_line)

for direction in dirs:
rdir = self.map(
np.array([self.noise(x, direction) for x in noise_coord]),
0,
1,
direction - self.rdir_range(),
direction + self.rdir_range(),
direction - self.rdir_range,
direction + self.rdir_range,
)
roffset = self.map(
np.array([self.noise(x, direction, 100) for x in noise_coord]),
Expand Down
6 changes: 3 additions & 3 deletions examples/random_lines/sketch_random_lines.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ def draw(self) -> None:

x_coords = np.linspace(0, 25, 1000)

for i in range(self.num_line()):
for i in range(self.num_line):
y_coords = (
np.array(
[
self.noise(x * self.x_freq(), i / self.num_line() * self.y_freq())
self.noise(x * self.x_freq, i / self.num_line * self.y_freq)
for x in x_coords
]
)
+ self.y_offset() / self.num_line() * i
+ self.y_offset / self.num_line * i
)
self.polygon(x_coords, y_coords)

Expand Down
10 changes: 5 additions & 5 deletions examples/schotter/sketch_schotter.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ def draw(self) -> None:
self.size("a4", landscape=False)
self.scale("cm")

for j in range(self.rows()):
for j in range(self.rows):
with self.pushMatrix():
for i in range(self.columns()):
for i in range(self.columns):
with self.pushMatrix():
self.rotate(self.fuzziness() * 0.03 * self.random(-j, j))
self.rotate(self.fuzziness * 0.03 * self.random(-j, j))
self.translate(
self.fuzziness() * 0.01 * self.randomGaussian() * j,
self.fuzziness() * 0.01 * self.randomGaussian() * j,
self.fuzziness * 0.01 * self.randomGaussian() * j,
self.fuzziness * 0.01 * self.randomGaussian() * j,
)
self.rect(0, 0, 1, 1)
self.translate(1, 0)
Expand Down
77 changes: 39 additions & 38 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 18 additions & 4 deletions tests/test_examples.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,31 @@
import glob
import pathlib

import nbformat
import pytest
from nbconvert.preprocessors import ExecutePreprocessor
from typer.testing import CliRunner
from vsketch_cli.cli import cli

EXAMPLES = str(pathlib.Path(__file__).parent.parent.absolute()) + "/examples/_notebooks/"
EXAMPLES = pathlib.Path(__file__).parent.parent.absolute() / "examples"
NOTEBOOKS = EXAMPLES / "_notebooks"

runner = CliRunner()


@pytest.mark.slow
@pytest.mark.parametrize("ipynb", glob.glob(EXAMPLES + "*.ipynb"))
def test_example_detail(tmp_path, ipynb):
@pytest.mark.parametrize("ipynb", NOTEBOOKS.glob("*.ipynb"))
def test_example_notebooks(tmp_path, ipynb):
with open(ipynb) as f:
nb = nbformat.read(f, as_version=4)
ep = ExecutePreprocessor(timeout=600, kernel_name="python3")
ep.preprocess(nb, {"metadata": {"path": tmp_path}})


@pytest.mark.parametrize("path", EXAMPLES.glob("[!._]*[!.md]"))
def test_examples(tmp_path, path):
# Note: split is needed to avoid `invoke`'s preprocessor to eat Windows' path backslashes
res = runner.invoke(
cli, f"save --name test_output --destination {tmp_path} {str(path)}".split()
)
assert res.exit_code == 0
assert (pathlib.Path(tmp_path) / "test_output.svg").exists()
2 changes: 1 addition & 1 deletion tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def bounds_equal(
"""Asserts that sketch bounds are approximately equal to those provided"""

bounds = vsk.document.bounds()
return (
return bool(
bounds is not None
and np.isclose(bounds[0], xmin, rtol=1e-03)
and np.isclose(bounds[1], ymin, rtol=1e-03)
Expand Down
5 changes: 4 additions & 1 deletion vsketch/param.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,10 @@ def set_value_with_validation(self, v: Any) -> None:

self.value = value

def __call__(self) -> ParamType:
def __get__(self, instance: Any, owner: Any = None) -> Any:
if instance is None:
return self

if self.factor is None:
return self.value
else:
Expand Down
Loading

0 comments on commit bd2da99

Please sign in to comment.