Fix examples and start testing them (#609)
* Fix examples * Added test for examples * Fix example testing code * Sweep example fix * Reformat examples * Test examples from the docs too * Add docutils to the test requirements * Example test fix on win+cleanup * Use union
This commit is contained in:
@ -25,7 +25,8 @@ requirements:
|
|||||||
|
|
||||||
test:
|
test:
|
||||||
requires:
|
requires:
|
||||||
- pytest
|
- pytest
|
||||||
|
- docutils
|
||||||
source_files:
|
source_files:
|
||||||
- tests/
|
- tests/
|
||||||
commands:
|
commands:
|
||||||
|
@ -874,7 +874,7 @@ A Parametric Enclosure
|
|||||||
topOfLid = topOfLid.rotateAboutCenter((1,0,0),180)
|
topOfLid = topOfLid.rotateAboutCenter((1,0,0),180)
|
||||||
|
|
||||||
#return the combined result
|
#return the combined result
|
||||||
result =topOfLid.combineSolids(bottom)
|
result =topOfLid.union(bottom)
|
||||||
|
|
||||||
|
|
||||||
.. topic:: Api References
|
.. topic:: Api References
|
||||||
@ -893,7 +893,7 @@ A Parametric Enclosure
|
|||||||
* :py:meth:`Workplane.workplane`
|
* :py:meth:`Workplane.workplane`
|
||||||
* :py:meth:`Workplane.fillet`
|
* :py:meth:`Workplane.fillet`
|
||||||
* :py:meth:`Workplane.cut`
|
* :py:meth:`Workplane.cut`
|
||||||
* :py:meth:`Workplane.combineSolids`
|
* :py:meth:`Workplane.union`
|
||||||
* :py:meth:`Workplane.rotateAboutCenter`
|
* :py:meth:`Workplane.rotateAboutCenter`
|
||||||
* :py:meth:`Workplane.cboreHole`
|
* :py:meth:`Workplane.cboreHole`
|
||||||
* :py:meth:`Workplane.cskHole`
|
* :py:meth:`Workplane.cskHole`
|
||||||
|
@ -6,6 +6,7 @@ import cadquery as cq
|
|||||||
|
|
||||||
# Define the points that the polyline will be drawn to/thru
|
# Define the points that the polyline will be drawn to/thru
|
||||||
pts = [
|
pts = [
|
||||||
|
(0, H / 2.0),
|
||||||
(W / 2.0, H / 2.0),
|
(W / 2.0, H / 2.0),
|
||||||
(W / 2.0, (H / 2.0 - t)),
|
(W / 2.0, (H / 2.0 - t)),
|
||||||
(t / 2.0, (H / 2.0 - t)),
|
(t / 2.0, (H / 2.0 - t)),
|
||||||
@ -30,7 +31,7 @@ pts = [
|
|||||||
# 3. Only half of the I-beam profile has been drawn so far. That half is
|
# 3. Only half of the I-beam profile has been drawn so far. That half is
|
||||||
# mirrored around the Y-axis to create the complete I-beam profile.
|
# mirrored around the Y-axis to create the complete I-beam profile.
|
||||||
# 4. The I-beam profile is extruded to the final length of the beam.
|
# 4. The I-beam profile is extruded to the final length of the beam.
|
||||||
result = cq.Workplane("front").moveTo(0, H / 2.0).polyline(pts).mirrorY().extrude(L)
|
result = cq.Workplane("front").polyline(pts).mirrorY().extrude(L)
|
||||||
|
|
||||||
# Displays the result of this script
|
# Displays the result of this script
|
||||||
show_object(result)
|
show_object(result)
|
||||||
|
@ -18,7 +18,7 @@ sPnts = [
|
|||||||
|
|
||||||
# 2. Generate our plate with the spline feature and make sure it is a
|
# 2. Generate our plate with the spline feature and make sure it is a
|
||||||
# closed entity
|
# closed entity
|
||||||
r = s.lineTo(3.0, 0).lineTo(3.0, 1.0).spline(sPnts).close()
|
r = s.lineTo(3.0, 0).lineTo(3.0, 1.0).spline(sPnts, includeCurrent=True).close()
|
||||||
|
|
||||||
# 3. Extrude to turn the wire into a plate
|
# 3. Extrude to turn the wire into a plate
|
||||||
result = r.extrude(0.5)
|
result = r.extrude(0.5)
|
||||||
|
@ -11,7 +11,7 @@ result = cq.Workplane("front").box(3, 2, 0.5)
|
|||||||
# 3a. The top-most Z face is selected using the >Z selector.
|
# 3a. The top-most Z face is selected using the >Z selector.
|
||||||
# 3b. The lower-left vertex of the faces is selected with the <XY selector.
|
# 3b. The lower-left vertex of the faces is selected with the <XY selector.
|
||||||
# 3c. A new workplane is created on the vertex to build future geometry on.
|
# 3c. A new workplane is created on the vertex to build future geometry on.
|
||||||
result = result.faces(">Z").vertices("<XY").workplane()
|
result = result.faces(">Z").vertices("<XY").workplane(centerOption="CenterOfMass")
|
||||||
|
|
||||||
# 4. A circle is drawn with the selected vertex as its center.
|
# 4. A circle is drawn with the selected vertex as its center.
|
||||||
# 4a. The circle is cut down through the box to cut the corner out.
|
# 4a. The circle is cut down through the box to cut the corner out.
|
||||||
|
@ -17,7 +17,7 @@ frenetShell = cq.Workplane("XY").circle(1.0).sweep(path, makeSolid=True, isFrene
|
|||||||
defaultRect = cq.Workplane("XY").rect(1.0, 1.0).sweep(path)
|
defaultRect = cq.Workplane("XY").rect(1.0, 1.0).sweep(path)
|
||||||
|
|
||||||
# Switch to a polyline path, but have it use the same points as the spline
|
# Switch to a polyline path, but have it use the same points as the spline
|
||||||
path = cq.Workplane("XZ").polyline(pts)
|
path = cq.Workplane("XZ").polyline(pts, includeCurrent=True)
|
||||||
|
|
||||||
# Using a polyline path leads to the resulting solid having segments rather than a single swept outer face
|
# Using a polyline path leads to the resulting solid having segments rather than a single swept outer face
|
||||||
plineSweep = cq.Workplane("XY").circle(1.0).sweep(path)
|
plineSweep = cq.Workplane("XY").circle(1.0).sweep(path)
|
||||||
@ -32,5 +32,5 @@ arcSweep = cq.Workplane("XY").circle(0.5).sweep(path)
|
|||||||
show_object(defaultSweep)
|
show_object(defaultSweep)
|
||||||
show_object(frenetShell.translate((5, 0, 0)))
|
show_object(frenetShell.translate((5, 0, 0)))
|
||||||
show_object(defaultRect.translate((10, 0, 0)))
|
show_object(defaultRect.translate((10, 0, 0)))
|
||||||
show_object(plineSweep.translate((15, 0, 0)))
|
show_object(plineSweep)
|
||||||
show_object(arcSweep.translate((20, 0, 0)))
|
show_object(arcSweep.translate((20, 0, 0)))
|
||||||
|
@ -70,11 +70,11 @@ arcSweep = (
|
|||||||
.workplane(offset=-5)
|
.workplane(offset=-5)
|
||||||
.moveTo(0, 4)
|
.moveTo(0, 4)
|
||||||
.circle(1.5)
|
.circle(1.5)
|
||||||
.workplane(offset=5)
|
.workplane(offset=5, centerOption="CenterOfMass")
|
||||||
.circle(1.5)
|
.circle(1.5)
|
||||||
.moveTo(0, -8)
|
.moveTo(0, -8)
|
||||||
.circle(1.0)
|
.circle(1.0)
|
||||||
.workplane(offset=-5)
|
.workplane(offset=-5, centerOption="CenterOfMass")
|
||||||
.circle(1.0)
|
.circle(1.0)
|
||||||
.sweep(path, multisection=True)
|
.sweep(path, multisection=True)
|
||||||
)
|
)
|
||||||
|
72
tests/test_examples.py
Executable file
72
tests/test_examples.py
Executable file
@ -0,0 +1,72 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from glob import glob
|
||||||
|
from itertools import chain, count
|
||||||
|
|
||||||
|
from docutils.parsers.rst import directives, Directive
|
||||||
|
from docutils.core import publish_doctree
|
||||||
|
from docutils.utils import Reporter
|
||||||
|
|
||||||
|
import cadquery as cq
|
||||||
|
from cadquery import cqgi
|
||||||
|
from cadquery.cq_directive import cq_directive
|
||||||
|
|
||||||
|
|
||||||
|
def find_examples(pattern="examples/*.py"):
|
||||||
|
|
||||||
|
for p in glob(pattern):
|
||||||
|
with open(p, encoding="UTF-8") as f:
|
||||||
|
code = f.read()
|
||||||
|
|
||||||
|
yield code
|
||||||
|
|
||||||
|
|
||||||
|
def find_examples_in_docs(pattern="doc/*.rst"):
|
||||||
|
|
||||||
|
# dummy CQ directive for code
|
||||||
|
class dummy_cq_directive(cq_directive):
|
||||||
|
|
||||||
|
codes = []
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
|
||||||
|
self.codes.append("\n".join(self.content))
|
||||||
|
|
||||||
|
return []
|
||||||
|
|
||||||
|
directives.register_directive("cadquery", dummy_cq_directive)
|
||||||
|
|
||||||
|
# read and parse all rst files
|
||||||
|
for p in glob(pattern):
|
||||||
|
with open(p, encoding="UTF-8") as f:
|
||||||
|
doc = f.read()
|
||||||
|
|
||||||
|
publish_doctree(
|
||||||
|
doc, settings_overrides={"report_level": Reporter.SEVERE_LEVEL + 1}
|
||||||
|
)
|
||||||
|
|
||||||
|
# yield all code snippets
|
||||||
|
for c in dummy_cq_directive.codes:
|
||||||
|
|
||||||
|
yield c
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"code", chain(find_examples(), find_examples_in_docs()), ids=count(0)
|
||||||
|
)
|
||||||
|
def test_example(code):
|
||||||
|
|
||||||
|
# build
|
||||||
|
res = cqgi.parse(code).build()
|
||||||
|
|
||||||
|
assert res.exception is None
|
||||||
|
|
||||||
|
# check if the resulting objects are valid
|
||||||
|
for r in res.results:
|
||||||
|
r = r.shape
|
||||||
|
if isinstance(r, cq.Workplane):
|
||||||
|
for v in r.vals():
|
||||||
|
if isinstance(v, cq.Shape):
|
||||||
|
assert v.isValid()
|
||||||
|
elif isinstance(r, cq.Shape):
|
||||||
|
assert r.isValid()
|
Reference in New Issue
Block a user