Add->add, restored context logging and validation

This commit is contained in:
Roger Maitland 2023-03-23 15:32:15 -04:00
parent cb05ee97b6
commit 92979fc29c
21 changed files with 210 additions and 239 deletions

View file

@ -60,7 +60,7 @@ if "show" in locals():
b = Box(1, 2, 3)
with BuildPart() as bp:
Add(b)
add(b)
if "show" in locals():
show(bp)
@ -70,7 +70,7 @@ if "show" in locals():
b = Box(1, 2, 3) + Cylinder(0.75, 2.5)
with BuildPart() as bp:
Add(b)
add(b)
Cylinder(0.4, 6, mode=Mode.SUBTRACT)
c = bp.part - Plane.YZ * Cylinder(0.2, 6)

View file

@ -59,7 +59,7 @@ if "show" in locals():
b = Rectangle(1, 2) + Circle(0.75)
with BuildSketch() as sk:
Add(b)
add(b)
Circle(0.1, mode=Mode.SUBTRACT)
c = sk.sketch - Pos(0, 0.5) * Circle(0.2)

View file

@ -75,9 +75,9 @@ with BuildLine() as extension_lines:
(logo_width, -ext_line_length - font_height * 0.1),
)
with Locations(l1 @ 0.5):
Add(*arrow_left.line)
add(*arrow_left.line)
with Locations(l2 @ 0.5):
Add(*arrow_left.line, rotation=180.0)
add(*arrow_left.line, rotation=180.0)
Line(l1 @ 0.5, l1 @ 0.5 + Vector(dim_line_length, 0))
Line(l2 @ 0.5, l2 @ 0.5 - Vector(dim_line_length, 0))
@ -87,12 +87,12 @@ with BuildSketch() as build:
(l1 @ 0.5 + l2 @ 0.5) / 2
- Vector((build_vertices[-1].X + build_vertices[0].X) / 2, 0)
):
Add(build_text.sketch)
add(build_text.sketch)
# add the customizable text to the build text sketch
with Locations(
(l1 @ 1 + l2 @ 1) / 2 - Vector((cust_vertices[-1].X + cust_vertices[0].X), 1.4)
):
Add(cust_text.sketch)
add(cust_text.sketch)
cmpd = Compound.make_compound(
[three_d.part, two.sketch, one.line, build.sketch, extension_lines.line]

View file

@ -64,9 +64,9 @@ with BuildLine() as extension_lines:
(logo_width, -ext_line_length - font_height * 0.1),
)
with Locations(l1 @ 0.5):
Add(*arrow_left.line)
add(*arrow_left.line)
with Locations(l2 @ 0.5):
Add(*arrow_left.line, rotation=180.0)
add(*arrow_left.line, rotation=180.0)
Line(l1 @ 0.5, l1 @ 0.5 + Vector(dim_line_length, 0))
Line(l2 @ 0.5, l2 @ 0.5 - Vector(dim_line_length, 0))
@ -76,7 +76,7 @@ with BuildSketch() as build:
(l1 @ 0.5 + l2 @ 0.5) / 2
- Vector((build_vertices[-1].X + build_vertices[0].X) / 2, 0)
):
Add(build_text.sketch)
add(build_text.sketch)
# logo = Assembly(None, name="logo")
# logo.add(one.wires()[0], name="one")

View file

@ -39,7 +39,7 @@ with BuildSketch() as minute_indicator:
with BuildSketch() as clock_face:
Circle(clock_radius)
with PolarLocations(0, 60):
Add(minute_indicator.sketch, mode=Mode.SUBTRACT)
add(minute_indicator.sketch, mode=Mode.SUBTRACT)
with PolarLocations(clock_radius * 0.875, 12):
SlotOverall(clock_radius * 0.05, clock_radius * 0.025, mode=Mode.SUBTRACT)
for hour in range(1, 13):

View file

@ -151,7 +151,7 @@ with BuildPart() as box_builder:
box = box_builder.part
with BuildPart() as lid_builder:
Add(box_plan.sketch)
add(box_plan.sketch)
extrude(amount=pocket_t / 2 + bottom_t)
with BuildSketch() as pocket:
offset(box_plan.sketch, amount=-(wall_t - lip_t), mode=Mode.ADD)

View file

@ -120,7 +120,7 @@ with BuildPart() as box_builder:
fillet(*plan.vertices(), radius=card_width / 15)
extrude(amount=wall / 2)
with BuildSketch(box_builder.faces().sort_by(Axis.Z)[-1]) as walls:
Add(plan.sketch)
add(plan.sketch)
offset(plan.sketch, amount=-wall, mode=Mode.SUBTRACT)
extrude(amount=deck / 2)
with BuildSketch(box_builder.faces().sort_by(Axis.Z)[-1]) as inset_walls:
@ -130,11 +130,11 @@ with BuildPart() as box_builder:
with BuildPart() as lid_builder:
with BuildSketch() as outset_walls:
Add(plan.sketch)
add(plan.sketch)
offset(plan.sketch, amount=-(wall - gap) / 2, mode=Mode.SUBTRACT)
extrude(amount=deck / 2)
with BuildSketch(lid_builder.faces().sort_by(Axis.Z)[-1]) as top:
Add(plan.sketch)
add(plan.sketch)
extrude(amount=wall / 2)
with BuildSketch(lid_builder.faces().sort_by(Axis.Z)[-1]):
holes = GridLocations(

View file

@ -3,10 +3,9 @@ from build123d.build_common import *
from build123d.build_line import *
from build123d.build_sketch import *
from build123d.build_part import *
from build123d.build_generic import *
from build123d.geometry import *
from build123d.topology import *
from build123d.build_enums import ApproxOption
from build123d.build_enums import *
from build123d.importers import *
from build123d.operations_generic import *
from build123d.operations_part import *
@ -41,7 +40,6 @@ __all__ = [
"Unit",
"Until",
# Builders,
"Add",
"HexLocations",
"PolarLocations",
"Locations",
@ -129,6 +127,7 @@ __all__ = [
# Other functions
"polar",
# Operations
"add",
"bounding_box",
"chamfer",
"extrude",

View file

@ -41,10 +41,13 @@ from build123d.build_enums import Align, Mode, Select
from build123d.geometry import Axis, Location, Plane, Vector, VectorLike
from build123d.topology import (
Compound,
Curve,
Edge,
Face,
Part,
Shape,
ShapeList,
Sketch,
Solid,
Vertex,
Wire,
@ -75,6 +78,25 @@ FT = 12 * IN
THOU = IN / 1000
operations_apply_to = {
"add": ["BuildPart", "BuildSketch", "BuildLine"],
"bounding_box": ["BuildPart", "BuildSketch", "BuildLine"],
"chamfer": ["BuildPart", "BuildSketch"],
"extrude": ["BuildPart"],
"fillet": ["BuildPart", "BuildSketch"],
"loft": ["BuildPart"],
"make_face": ["BuildSketch"],
"make_hull": ["BuildSketch"],
"mirror": ["BuildPart", "BuildSketch", "BuildLine"],
"offset": ["BuildPart", "BuildSketch", "BuildLine"],
"revolve": ["BuildPart"],
"scale": ["BuildPart", "BuildSketch", "BuildLine"],
"section": ["BuildPart"],
"split": ["BuildPart", "BuildSketch", "BuildLine"],
"sweep": ["BuildPart"],
}
class Builder(ABC):
"""Builder
@ -194,33 +216,19 @@ class Builder(ABC):
return NotImplementedError # pragma: no cover
@classmethod
def _get_context(cls, caller=None) -> Self:
def _get_context(cls, caller: Union[Builder, str] = None, log: bool = True) -> Self:
"""Return the instance of the current builder"""
result = cls._current.get(None)
context_name = "None" if result is None else type(result).__name__
current_builder = inspect.currentframe().f_back.f_locals.get("self", None)
if not isinstance(current_builder, Builder):
current_builder = None
if not isinstance(caller, Builder):
caller = None
# print(f"{result=}, {current_builder=}, {caller=}")
if current_builder is None:
logger.info("Context requested by None")
if log:
if isinstance(caller, (Part, Sketch, Curve, Wire)):
caller_name = caller.__class__.__name__
elif isinstance(caller, str):
caller_name = caller
else:
logger.info(
"Context requested by %s",
type(current_builder).__name__,
)
if caller is not None and result is None:
if hasattr(caller, "_applies_to"):
raise RuntimeError(
f"No valid context found, use one of {caller._applies_to}"
)
raise RuntimeError("No valid context found-common")
caller_name = "None"
logger.info("%s context requested by %s", context_name, caller_name)
return result
@ -322,14 +330,23 @@ class Builder(ABC):
objects = [objects]
if (
validating_class is not None
and not self._tag() in validating_class._applies_to
isinstance(validating_class, (Part, Sketch, Curve, Wire))
and self._tag() not in validating_class._applies_to
):
raise RuntimeError(
f"{self.__class__.__name__} doesn't have a "
f"{validating_class.__class__.__name__} object or operation "
f"({validating_class.__class__.__name__} applies to {validating_class._applies_to})"
)
elif (
isinstance(validating_class, str)
and self.__class__.__name__ not in operations_apply_to[validating_class]
):
raise RuntimeError(
f"{self.__class__.__name__} doesn't have a "
f"{validating_class} object or operation "
f"({validating_class} applies to {operations_apply_to[validating_class]})"
)
# Check for valid object inputs
for obj in objects:
if obj is None:

View file

@ -1,144 +0,0 @@
"""
BuildGeneric
name: build_generic.py
by: Gumyr
date: July 12th 2022
desc:
This python module is a library of generic classes used by other
build123d builders.
license:
Copyright 2022 Gumyr
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
import logging
from typing import Union
from build123d.build_common import Builder, LocationList, WorkplaneList, validate_inputs
from build123d.build_enums import Mode
from build123d.build_line import BuildLine
from build123d.build_part import BuildPart
from build123d.build_sketch import BuildSketch
from build123d.geometry import Axis, Rotation, RotationLike
from build123d.topology import Compound, Edge, Face, Solid, Wire
logging.getLogger("build123d").addHandler(logging.NullHandler())
logger = logging.getLogger("build123d")
#
# Objects
#
class Add(Compound):
"""Generic Object: Add Object to Part or Sketch
Add an object to the builder.
if BuildPart:
Edges and Wires are added to pending_edges. Compounds of Face are added to
pending_faces. Solids or Compounds of Solid are combined into the part.
elif BuildSketch:
Edges and Wires are added to pending_edges. Compounds of Face are added to sketch.
elif BuildLine:
Edges and Wires are added to line.
Args:
objects (Union[Edge, Wire, Face, Solid, Compound]): sequence of objects to add
rotation (Union[float, RotationLike], optional): rotation angle for sketch,
rotation about each axis for part. Defaults to None.
mode (Mode, optional): combine mode. Defaults to Mode.ADD.
"""
_applies_to = [BuildPart._tag(), BuildSketch._tag(), BuildLine._tag()]
def __init__(
self,
*objects: Union[Edge, Wire, Face, Solid, Compound],
rotation: Union[float, RotationLike] = None,
mode: Mode = Mode.ADD,
):
context: Builder = Builder._get_context(self)
if context is None:
raise RuntimeError("Add must have an active builder context")
validate_inputs(context, self, objects)
if isinstance(context, BuildPart):
if rotation is None:
rotation = Rotation(0, 0, 0)
elif isinstance(rotation, float):
raise ValueError("Float values of rotation are not valid for BuildPart")
elif isinstance(rotation, tuple):
rotation = Rotation(*rotation)
objects = [obj.moved(rotation) for obj in objects]
new_edges = [obj for obj in objects if isinstance(obj, Edge)]
new_wires = [obj for obj in objects if isinstance(obj, Wire)]
new_faces = [obj for obj in objects if isinstance(obj, Face)]
new_solids = [obj for obj in objects if isinstance(obj, Solid)]
for compound in filter(lambda o: isinstance(o, Compound), objects):
new_edges.extend(compound.get_type(Edge))
new_wires.extend(compound.get_type(Wire))
new_faces.extend(compound.get_type(Face))
new_solids.extend(compound.get_type(Solid))
for new_wire in new_wires:
new_edges.extend(new_wire.edges())
# Add the pending Edges in one group
if not LocationList._get_context():
raise RuntimeError("There is no active Locations context")
located_edges = [
edge.moved(location)
for edge in new_edges
for location in LocationList._get_context().locations
]
context._add_to_pending(*located_edges)
new_objects = located_edges
# Add to pending Faces batched by workplane
for workplane in WorkplaneList._get_context().workplanes:
faces_per_workplane = []
for location in LocationList._get_context().locations:
for face in new_faces:
faces_per_workplane.append(face.moved(location))
context._add_to_pending(*faces_per_workplane, face_plane=workplane)
new_objects.extend(faces_per_workplane)
# Add to context Solids
located_solids = [
solid.moved(location)
for solid in new_solids
for location in LocationList._get_context().locations
]
context._add_to_context(*located_solids, mode=mode)
new_objects.extend(located_solids)
elif isinstance(context, (BuildLine, BuildSketch)):
rotation_angle = rotation if isinstance(rotation, (int, float)) else 0.0
new_objects = []
for obj in objects:
new_objects.extend(
[
obj.rotate(Axis.Z, rotation_angle).moved(location)
for location in LocationList._get_context().local_locations
]
)
context._add_to_context(*new_objects, mode=mode)
super().__init__(Compound.make_compound(new_objects).wrapped)

View file

@ -63,7 +63,7 @@ class BuildLine(Builder):
@staticmethod
def _tag() -> str:
return BuildLine
return "BuildLine"
@property
def _obj(self):

View file

@ -52,7 +52,7 @@ class BuildPart(Builder):
@staticmethod
def _tag() -> str:
return BuildPart
return "BuildPart"
@property
def _obj(self):

View file

@ -55,7 +55,7 @@ class BaseLineObject(Wire):
curve: Union[Edge, Wire],
mode: Mode = Mode.ADD,
):
context: BuildLine = BuildLine._get_context(self)
context: BuildLine = BuildLine._get_context(self, log=False)
if context is not None:
context._add_to_context(*curve.edges(), mode=mode)

View file

@ -72,7 +72,7 @@ class BasePartObject(Part):
align_offset.append(-bbox.max.to_tuple()[i])
solid.move(Location(Vector(*align_offset)))
context: BuildPart = BuildPart._get_context(self)
context: BuildPart = BuildPart._get_context(self, log=False)
if context is None:
new_solids = [solid]

View file

@ -73,7 +73,7 @@ class BaseSketchObject(Sketch):
align_offset.append(-bbox.max.to_tuple()[i])
obj.move(Location(Vector(*align_offset)))
context: BuildSketch = BuildSketch._get_context(self)
context: BuildSketch = BuildSketch._get_context(self, log=False)
if context is None:
new_faces = obj.faces()

View file

@ -29,11 +29,19 @@ license:
import copy
import logging
from typing import Union
from build123d.build_enums import Mode, Kind, Keep
from build123d.build_common import Builder, LocationList, WorkplaneList, validate_inputs
from build123d.build_enums import Keep, Kind, Mode
from build123d.build_line import BuildLine
from build123d.build_part import BuildPart
from build123d.build_sketch import BuildSketch
from build123d.geometry import (
Axis,
Location,
Matrix,
Plane,
Rotation,
RotationLike,
Vector,
)
from build123d.topology import (
@ -41,9 +49,9 @@ from build123d.topology import (
Curve,
Edge,
Face,
Matrix,
Part,
Plane,
Matrix,
Shape,
Sketch,
Solid,
@ -51,15 +59,101 @@ from build123d.topology import (
Wire,
)
from build123d.build_common import Builder, validate_inputs
logging.getLogger("build123d").addHandler(logging.NullHandler())
logger = logging.getLogger("build123d")
#
# Operations
#
def add(
*objects: Union[Edge, Wire, Face, Solid, Compound],
rotation: Union[float, RotationLike] = None,
mode: Mode = Mode.ADD,
) -> Compound:
"""Generic Object: Add Object to Part or Sketch
Add an object to a builder.
if BuildPart:
Edges and Wires are added to pending_edges. Compounds of Face are added to
pending_faces. Solids or Compounds of Solid are combined into the part.
elif BuildSketch:
Edges and Wires are added to pending_edges. Compounds of Face are added to sketch.
elif BuildLine:
Edges and Wires are added to line.
Args:
objects (Union[Edge, Wire, Face, Solid, Compound]): sequence of objects to add
rotation (Union[float, RotationLike], optional): rotation angle for sketch,
rotation about each axis for part. Defaults to None.
mode (Mode, optional): combine mode. Defaults to Mode.ADD.
"""
context: Builder = Builder._get_context(None)
if context is None:
raise RuntimeError("Add must have an active builder context")
validate_inputs(context, None, objects)
if isinstance(context, BuildPart):
if rotation is None:
rotation = Rotation(0, 0, 0)
elif isinstance(rotation, float):
raise ValueError("Float values of rotation are not valid for BuildPart")
elif isinstance(rotation, tuple):
rotation = Rotation(*rotation)
objects = [obj.moved(rotation) for obj in objects]
new_edges = [obj for obj in objects if isinstance(obj, Edge)]
new_wires = [obj for obj in objects if isinstance(obj, Wire)]
new_faces = [obj for obj in objects if isinstance(obj, Face)]
new_solids = [obj for obj in objects if isinstance(obj, Solid)]
for compound in filter(lambda o: isinstance(o, Compound), objects):
new_edges.extend(compound.get_type(Edge))
new_wires.extend(compound.get_type(Wire))
new_faces.extend(compound.get_type(Face))
new_solids.extend(compound.get_type(Solid))
for new_wire in new_wires:
new_edges.extend(new_wire.edges())
# Add the pending Edges in one group
if not LocationList._get_context():
raise RuntimeError("There is no active Locations context")
located_edges = [
edge.moved(location)
for edge in new_edges
for location in LocationList._get_context().locations
]
context._add_to_pending(*located_edges)
new_objects = located_edges
# Add to pending Faces batched by workplane
for workplane in WorkplaneList._get_context().workplanes:
faces_per_workplane = []
for location in LocationList._get_context().locations:
for face in new_faces:
faces_per_workplane.append(face.moved(location))
context._add_to_pending(*faces_per_workplane, face_plane=workplane)
new_objects.extend(faces_per_workplane)
# Add to context Solids
located_solids = [
solid.moved(location)
for solid in new_solids
for location in LocationList._get_context().locations
]
context._add_to_context(*located_solids, mode=mode)
new_objects.extend(located_solids)
elif isinstance(context, (BuildLine, BuildSketch)):
rotation_angle = rotation if isinstance(rotation, (int, float)) else 0.0
new_objects = []
for obj in objects:
new_objects.extend(
[
obj.rotate(Axis.Z, rotation_angle).moved(location)
for location in LocationList._get_context().local_locations
]
)
context._add_to_context(*new_objects, mode=mode)
return Compound.make_compound(new_objects)
def bounding_box(
@ -76,8 +170,8 @@ def bounding_box(
objects (Shape): sequence of objects
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
context: Builder = Builder._get_context(None)
validate_inputs(context, None, objects)
context: Builder = Builder._get_context("bounding_box")
validate_inputs(context, "bounding_box", objects)
if (not objects and context is None) or (
not objects and context is not None and not context._obj
@ -141,12 +235,13 @@ def chamfer(
target (Union[Face, Sketch, Solid, Part], optional): object to chamfer. Defaults to None.
Raises:
ValueError: no objects provided
ValueError: objects must be Edges
ValueError: objects must be Vertices
ValueError: missing target object
"""
context: Builder = Builder._get_context(None)
validate_inputs(context, None, objects)
context: Builder = Builder._get_context("chamfer")
validate_inputs(context, "chamfer", objects)
if (not objects and context is None) or (
not objects and context is not None and not context._obj
@ -204,8 +299,8 @@ def fillet(
ValueError: objects must be Vertices
ValueError: missing target object
"""
context: Builder = Builder._get_context(None)
validate_inputs(context, None, objects)
context: Builder = Builder._get_context("fillet")
validate_inputs(context, "fillet", objects)
if (not objects and context is None) or (
not objects and context is not None and not context._obj
@ -262,8 +357,8 @@ def mirror(
Raises:
ValueError: missing objects
"""
context: Builder = Builder._get_context(None)
validate_inputs(context, None, objects)
context: Builder = Builder._get_context("mirror")
validate_inputs(context, "mirror", objects)
if not objects:
if context is None:
@ -314,8 +409,8 @@ def offset(
ValueError: missing objects
ValueError: Invalid object type
"""
context: Builder = Builder._get_context(None)
validate_inputs(context, None, objects)
context: Builder = Builder._get_context("offset")
validate_inputs(context, "offset", objects)
if not objects:
if context is None:
@ -404,8 +499,8 @@ def scale(
Raises:
ValueError: missing objects
"""
context: Builder = Builder._get_context(None)
validate_inputs(context, None, objects)
context: Builder = Builder._get_context("scale")
validate_inputs(context, "scale", objects)
if not objects:
if context is None:
@ -491,8 +586,8 @@ def split(
)
)
context: Builder = Builder._get_context(None)
validate_inputs(context, None, objects)
context: Builder = Builder._get_context("split")
validate_inputs(context, "split", objects)
if not objects:
if context is None:

View file

@ -89,8 +89,8 @@ def extrude(
Returns:
Part: extruded object
"""
context: BuildPart = BuildPart._get_context(None)
validate_inputs(context, None, to_extrude)
context: BuildPart = BuildPart._get_context("extrude")
validate_inputs(context, "extrude", to_extrude)
to_extrude_faces: list[Face]
@ -173,7 +173,8 @@ def loft(
clean (bool, optional): Remove extraneous internal structure. Defaults to True.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
context: BuildPart = BuildPart._get_context(None)
context: BuildPart = BuildPart._get_context("loft")
validate_inputs(context, "loft", sections)
if not sections:
loft_wires = [face.outer_wire() for face in context.pending_faces]
@ -222,7 +223,8 @@ def revolve(
Raises:
ValueError: Invalid axis of revolution
"""
context: BuildPart = BuildPart._get_context(None)
context: BuildPart = BuildPart._get_context("revolve")
validate_inputs(context, "revolve", profiles)
# Make sure we account for users specifying angles larger than 360 degrees, and
# for OCCT not assuming that a 0 degree revolve means a 360 degree revolve
@ -279,7 +281,8 @@ def section(
clean (bool, optional): Remove extraneous internal structure. Defaults to True.
mode (Mode, optional): combination mode. Defaults to Mode.INTERSECT.
"""
context: BuildPart = BuildPart._get_context(None)
context: BuildPart = BuildPart._get_context("section")
validate_inputs(context, "section", None)
if context is not None and obj is None:
max_size = context.part.bounding_box().diagonal
@ -341,7 +344,8 @@ def sweep(
clean (bool, optional): Remove extraneous internal structure. Defaults to True.
mode (Mode, optional): combination. Defaults to Mode.ADD.
"""
context: BuildPart = BuildPart._get_context(None)
context: BuildPart = BuildPart._get_context("sweep")
validate_inputs(context, "sweep", sections)
if path is None:
path_wire = context.pending_edges_as_wire

View file

@ -42,8 +42,8 @@ def make_face(*edges: Edge, mode: Mode = Mode.ADD) -> Sketch:
edges (Edge): sequence of perimeter edges
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
context: BuildSketch = BuildSketch._get_context(None)
validate_inputs(context, None, edges)
context: BuildSketch = BuildSketch._get_context("make_face")
validate_inputs(context, "make_face", edges)
if edges:
outer_edges = list(edges)
@ -71,8 +71,8 @@ def make_hull(*edges: Edge, mode: Mode = Mode.ADD) -> Sketch:
pending and sketch edges.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
context: BuildSketch = BuildSketch._get_context(None)
validate_inputs(context, None, edges)
context: BuildSketch = BuildSketch._get_context("make_hull")
validate_inputs(context, "make_hull", edges)
if edges:
hull_edges = list(edges)

View file

@ -381,7 +381,7 @@ class TestValidateInputs(unittest.TestCase):
with BuildPart() as p:
Box(1, 1, 1)
with BuildSketch():
Add(p)
add(p)
def test_no_sequence(self):
with self.assertRaises(RuntimeError):

View file

@ -67,28 +67,28 @@ class AddTests(unittest.TestCase):
def test_add_to_line(self):
# Add Edge
with BuildLine() as test:
Add(Edge.make_line((0, 0, 0), (1, 1, 1)))
add(Edge.make_line((0, 0, 0), (1, 1, 1)))
self.assertTupleAlmostEquals((test.wires()[0] @ 1).to_tuple(), (1, 1, 1), 5)
# Add Wire
with BuildLine() as wire:
Polyline((0, 0, 0), (1, 1, 1), (2, 0, 0), (3, 1, 1))
with BuildLine() as test:
Add(wire.wires()[0])
add(wire.wires()[0])
self.assertEqual(len(test.line.edges()), 3)
def test_add_to_sketch(self):
with BuildSketch() as test:
Add(Face.make_rect(10, 10))
add(Face.make_rect(10, 10))
self.assertAlmostEqual(test.sketch.area, 100, 5)
def test_add_to_part(self):
# Add Solid
with BuildPart() as test:
Add(Solid.make_box(10, 10, 10))
add(Solid.make_box(10, 10, 10))
self.assertAlmostEqual(test.part.volume, 1000, 5)
# Add Compound
with BuildPart() as test:
Add(
add(
Compound.make_compound(
[
Solid.make_box(10, 10, 10),
@ -101,17 +101,17 @@ class AddTests(unittest.TestCase):
with BuildLine() as wire:
Polyline((0, 0, 0), (1, 1, 1), (2, 0, 0), (3, 1, 1))
with BuildPart() as test:
Add(wire.wires()[0])
add(wire.wires()[0])
self.assertEqual(len(test.pending_edges), 3)
def test_errors(self):
with self.assertRaises(RuntimeError):
Add(Edge.make_line((0, 0, 0), (1, 1, 1)))
add(Edge.make_line((0, 0, 0), (1, 1, 1)))
def test_unsupported_builder(self):
with self.assertRaises(TypeError):
with _TestBuilder():
Add(Edge.make_line((0, 0, 0), (1, 1, 1)))
add(Edge.make_line((0, 0, 0), (1, 1, 1)))
def test_local_global_locations(self):
"""Check that add is using a local location list"""
@ -124,7 +124,7 @@ class AddTests(unittest.TestCase):
extrude(amount=10)
topf = mainp.faces().sort_by(Axis.Z)[-1]
with BuildSketch(topf):
Add(vertwalls.sketch)
add(vertwalls.sketch)
extrude(amount=15)
self.assertEqual(len(mainp.solids()), 1)
@ -135,7 +135,7 @@ class AddTests(unittest.TestCase):
]
with BuildPart(Plane.XY, Plane.YZ) as multiple:
with Locations((1, 1), (-1, -1)) as locs:
Add(*faces)
add(*faces)
self.assertEqual(len(multiple.pending_faces), 16)
@ -283,7 +283,7 @@ class ChamferTests(unittest.TestCase):
self.assertAlmostEqual(test.sketch.area, 200 - 4 * 0.5, 5)
def test_errors(self):
with self.assertRaises(ValueError):
with self.assertRaises(RuntimeError):
with BuildLine():
chamfer(length=1)
@ -321,7 +321,7 @@ class FilletTests(unittest.TestCase):
self.assertAlmostEqual(test.sketch.area, 200 - 4 + pi, 5)
def test_errors(self):
with self.assertRaises(ValueError):
with self.assertRaises(RuntimeError):
with BuildLine():
fillet(radius=1)

View file

@ -120,11 +120,11 @@ class TestBuildOnPlanes(unittest.TestCase):
def test_not_coplanar(self):
with self.assertRaises(ValueError):
with BuildSketch() as error:
Add(Face.make_rect(1, 1, Plane.XY.offset(1)))
add(Face.make_rect(1, 1, Plane.XY.offset(1)))
with self.assertRaises(ValueError):
with BuildSketch() as error:
Add(Face.make_rect(1, 1, Plane.XZ))
add(Face.make_rect(1, 1, Plane.XZ))
def test_changing_geometry(self):
with BuildSketch() as s: