2727"""
2828
2929from __future__ import annotations
30- from typing import Union
30+ from typing import cast
3131
3232from collections .abc import Iterable
3333from build123d .build_enums import Mode , Until , Kind , Side
5656
5757
5858def extrude (
59- to_extrude : Face | Sketch = None ,
60- amount : float = None ,
61- dir : VectorLike = None , # pylint: disable=redefined-builtin
62- until : Until = None ,
63- target : Compound | Solid = None ,
59+ to_extrude : Face | Sketch | None = None ,
60+ amount : float | None = None ,
61+ dir : VectorLike | None = None , # pylint: disable=redefined-builtin
62+ until : Until | None = None ,
63+ target : Compound | Solid | None = None ,
6464 both : bool = False ,
6565 taper : float = 0.0 ,
6666 clean : bool = True ,
@@ -89,7 +89,7 @@ def extrude(
8989 Part: extruded object
9090 """
9191 # pylint: disable=too-many-locals, too-many-branches
92- context : BuildPart = BuildPart ._get_context ("extrude" )
92+ context : BuildPart | None = BuildPart ._get_context ("extrude" )
9393 validate_inputs (context , "extrude" , to_extrude )
9494
9595 to_extrude_faces : list [Face ]
@@ -130,12 +130,6 @@ def extrude(
130130 if len (face_planes ) != len (to_extrude_faces ):
131131 raise ValueError ("dir must be provided when extruding non-planar faces" )
132132
133- if until is not None :
134- if target is None and context is None :
135- raise ValueError ("A target object must be provided" )
136- if target is None :
137- target = context .part
138-
139133 logger .info (
140134 "%d face(s) to extrude on %d face plane(s)" ,
141135 len (to_extrude_faces ),
@@ -144,7 +138,7 @@ def extrude(
144138
145139 for face , plane in zip (to_extrude_faces , face_planes ):
146140 for direction in [1 , - 1 ] if both else [1 ]:
147- if amount :
141+ if amount is not None :
148142 if taper == 0 :
149143 new_solids .append (
150144 Solid .extrude (
@@ -162,10 +156,19 @@ def extrude(
162156 )
163157
164158 else :
159+ if until is None :
160+ raise ValueError ("Either amount or until must be provided" )
161+ if target is None :
162+ if context is None :
163+ raise ValueError ("A target object must be provided" )
164+ target_object = context .part
165+ else :
166+ target_object = target
167+
165168 new_solids .append (
166169 Solid .extrude_until (
167170 section = face ,
168- target_object = target ,
171+ target_object = target_object ,
169172 direction = plane .z_dir * direction ,
170173 until = until ,
171174 )
@@ -186,7 +189,7 @@ def extrude(
186189
187190
188191def loft (
189- sections : Face | Sketch | Iterable [Vertex | Face | Sketch ] = None ,
192+ sections : Face | Sketch | Iterable [Vertex | Face | Sketch ] | None = None ,
190193 ruled : bool = False ,
191194 clean : bool = True ,
192195 mode : Mode = Mode .ADD ,
@@ -203,7 +206,7 @@ def loft(
203206 clean (bool, optional): Remove extraneous internal structure. Defaults to True.
204207 mode (Mode, optional): combination mode. Defaults to Mode.ADD.
205208 """
206- context : BuildPart = BuildPart ._get_context ("loft" )
209+ context : BuildPart | None = BuildPart ._get_context ("loft" )
207210
208211 section_list = flatten_sequence (sections )
209212 validate_inputs (context , "loft" , section_list )
@@ -235,10 +238,11 @@ def loft(
235238 elif isinstance (s , Face ):
236239 loft_wires .append (s .outer_wire ())
237240 elif isinstance (s , Sketch ):
238- loft_wires .append ( s . face (). outer_wire () )
241+ loft_wires .extend ([ f . outer_wire () for f in s . faces ()] )
239242 elif all (isinstance (s , Vertex ) for s in section_list ):
240243 raise ValueError (
241- "At least one face/sketch is required if vertices are the first, last, or first and last elements"
244+ "At least one face/sketch is required if vertices are the first, last, "
245+ "or first and last elements"
242246 )
243247
244248 new_solid = Solid .make_loft (loft_wires , ruled )
@@ -262,7 +266,7 @@ def loft(
262266def make_brake_formed (
263267 thickness : float ,
264268 station_widths : float | Iterable [float ],
265- line : Edge | Wire | Curve = None ,
269+ line : Edge | Wire | Curve | None = None ,
266270 side : Side = Side .LEFT ,
267271 kind : Kind = Kind .ARC ,
268272 clean : bool = True ,
@@ -298,7 +302,7 @@ def make_brake_formed(
298302 Part: sheet metal part
299303 """
300304 # pylint: disable=too-many-locals, too-many-branches
301- context : BuildPart = BuildPart ._get_context ("make_brake_formed" )
305+ context : BuildPart | None = BuildPart ._get_context ("make_brake_formed" )
302306 validate_inputs (context , "make_brake_formed" )
303307
304308 if line is not None :
@@ -321,8 +325,16 @@ def make_brake_formed(
321325 raise ValueError ("line not suitable - probably straight" ) from exc
322326
323327 # Make edge pairs
324- station_edges = ShapeList ()
328+ station_edges : ShapeList [ Edge ] = ShapeList ()
325329 line_vertices = line .vertices ()
330+
331+ if isinstance (station_widths , (float , int )):
332+ station_widths_list = [station_widths ] * len (line_vertices )
333+ elif isinstance (station_widths , Iterable ):
334+ station_widths_list = list (station_widths )
335+ else :
336+ raise TypeError ("station_widths must be either a single number or an iterable" )
337+
326338 for vertex in line_vertices :
327339 others = offset_vertices .sort_by_distance (Vector (vertex .X , vertex .Y , vertex .Z ))
328340 for other in others [1 :]:
@@ -333,27 +345,25 @@ def make_brake_formed(
333345 break
334346 station_edges = station_edges .sort_by (line )
335347
336- if isinstance (station_widths , (float , int )):
337- station_widths = [station_widths ] * len (line_vertices )
338- if len (station_widths ) != len (line_vertices ):
348+ if len (station_widths_list ) != len (line_vertices ):
339349 raise ValueError (
340350 f"widths must either be a single number or an iterable with "
341351 f"a length of the # vertices in line ({ len (line_vertices )} )"
342352 )
343353 station_faces = [
344354 Face .extrude (obj = e , direction = plane .z_dir * w )
345- for e , w in zip (station_edges , station_widths )
355+ for e , w in zip (station_edges , station_widths_list )
346356 ]
347357 sweep_paths = line .edges ().sort_by (line )
348- sections = []
358+ sections : list [ Solid ] = []
349359 for i in range (len (station_faces ) - 1 ):
350360 sections .append (
351361 Solid .sweep_multi (
352362 [station_faces [i ], station_faces [i + 1 ]], path = sweep_paths [i ]
353363 )
354364 )
355365 if len (sections ) > 1 :
356- new_solid = sections . pop () .fuse (* sections )
366+ new_solid = cast ( Part , Part .fuse (* sections ) )
357367 else :
358368 new_solid = sections [0 ]
359369
@@ -391,7 +401,7 @@ def project_workplane(
391401 Returns:
392402 Plane: workplane aligned for projection
393403 """
394- context : BuildPart = BuildPart ._get_context ("project_workplane" )
404+ context : BuildPart | None = BuildPart ._get_context ("project_workplane" )
395405
396406 if context is not None and not isinstance (context , BuildPart ):
397407 raise RuntimeError (
@@ -422,7 +432,7 @@ def project_workplane(
422432
423433
424434def revolve (
425- profiles : Face | Iterable [Face ] = None ,
435+ profiles : Face | Iterable [Face ] | None = None ,
426436 axis : Axis = Axis .Z ,
427437 revolution_arc : float = 360.0 ,
428438 clean : bool = True ,
@@ -444,7 +454,7 @@ def revolve(
444454 Raises:
445455 ValueError: Invalid axis of revolution
446456 """
447- context : BuildPart = BuildPart ._get_context ("revolve" )
457+ context : BuildPart | None = BuildPart ._get_context ("revolve" )
448458
449459 profile_list = flatten_sequence (profiles )
450460
@@ -458,16 +468,13 @@ def revolve(
458468 if all ([s is None for s in profile_list ]):
459469 if context is None or (context is not None and not context .pending_faces ):
460470 raise ValueError ("No profiles provided" )
461- profile_list = context .pending_faces
471+ profile_faces = context .pending_faces
462472 context .pending_faces = []
463473 context .pending_face_planes = []
464474 else :
465- p_list = []
466- for profile in profile_list :
467- p_list .extend (profile .faces ())
468- profile_list = p_list
475+ profile_faces = profile_list .faces ()
469476
470- new_solids = [Solid .revolve (profile , angle , axis ) for profile in profile_list ]
477+ new_solids = [Solid .revolve (profile , angle , axis ) for profile in profile_faces ]
471478
472479 new_solid = Compound (new_solids )
473480 if context is not None :
@@ -479,7 +486,7 @@ def revolve(
479486
480487
481488def section (
482- obj : Part = None ,
489+ obj : Part | None = None ,
483490 section_by : Plane | Iterable [Plane ] = Plane .XZ ,
484491 height : float = 0.0 ,
485492 clean : bool = True ,
@@ -497,13 +504,17 @@ def section(
497504 clean (bool, optional): Remove extraneous internal structure. Defaults to True.
498505 mode (Mode, optional): combination mode. Defaults to Mode.INTERSECT.
499506 """
500- context : BuildPart = BuildPart ._get_context ("section" )
507+ context : BuildPart | None = BuildPart ._get_context ("section" )
501508 validate_inputs (context , "section" , None )
502509
503- if context is not None and obj is None :
504- max_size = context .part .bounding_box (optimal = False ).diagonal
510+ if obj is not None :
511+ to_section = obj
512+ elif context is not None :
513+ to_section = context .part
505514 else :
506- max_size = obj .bounding_box (optimal = False ).diagonal
515+ raise ValueError ("No object to section" )
516+
517+ max_size = to_section .bounding_box (optimal = False ).diagonal
507518
508519 if section_by is not None :
509520 section_planes = (
@@ -528,7 +539,13 @@ def section(
528539 else :
529540 raise ValueError ("obj must be provided" )
530541
531- new_objects = [obj .intersect (plane ) for plane in planes ]
542+ new_objects : list [Face | Shell ] = []
543+ for plane in planes :
544+ intersection = to_section .intersect (plane )
545+ if isinstance (intersection , ShapeList ):
546+ new_objects .extend (intersection )
547+ elif intersection is not None :
548+ new_objects .append (intersection )
532549
533550 if context is not None :
534551 context ._add_to_context (
@@ -542,9 +559,9 @@ def section(
542559
543560
544561def thicken (
545- to_thicken : Face | Sketch = None ,
546- amount : float = None ,
547- normal_override : VectorLike = None ,
562+ to_thicken : Face | Sketch | None = None ,
563+ amount : float | None = None ,
564+ normal_override : VectorLike | None = None ,
548565 both : bool = False ,
549566 clean : bool = True ,
550567 mode : Mode = Mode .ADD ,
@@ -555,7 +572,7 @@ def thicken(
555572
556573 Args:
557574 to_thicken (Union[Face, Sketch], optional): object to thicken. Defaults to None.
558- amount (float, optional ): distance to extrude, sign controls direction. Defaults to None .
575+ amount (float): distance to extrude, sign controls direction.
559576 normal_override (Vector, optional): The normal_override vector can be used to
560577 indicate which way is 'up', potentially flipping the face normal direction
561578 such that many faces with different normals all go in the same direction
@@ -571,11 +588,14 @@ def thicken(
571588 Returns:
572589 Part: extruded object
573590 """
574- context : BuildPart = BuildPart ._get_context ("thicken" )
591+ context : BuildPart | None = BuildPart ._get_context ("thicken" )
575592 validate_inputs (context , "thicken" , to_thicken )
576593
577594 to_thicken_faces : list [Face ]
578595
596+ if amount is None :
597+ raise ValueError ("An amount must be provided" )
598+
579599 if to_thicken is None :
580600 if context is not None and context .pending_faces :
581601 # Get pending faces and face planes
@@ -603,15 +623,15 @@ def thicken(
603623 for direction in [1 , - 1 ] if both else [1 ]:
604624 new_solids .append (
605625 Solid .thicken (
606- face , depth = amount , normal_override = face_normal * direction
626+ face , depth = amount , normal_override = Vector ( face_normal ) * direction
607627 )
608628 )
609629
610630 if context is not None :
611631 context ._add_to_context (* new_solids , clean = clean , mode = mode )
612632 else :
613633 if len (new_solids ) > 1 :
614- new_solids = [new_solids . pop () .fuse (* new_solids )]
634+ new_solids = [cast ( Part , Part .fuse (* new_solids ) )]
615635 if clean :
616636 new_solids = [solid .clean () for solid in new_solids ]
617637
0 commit comments