@@ -45,7 +45,27 @@ class ArgumentsDict(TypedDict):
4545 arguments : NotRequired [Sequence [Any ]]
4646
4747
48- def execute (args : ArgumentsDict ) -> Union [ifcopenshell .file , str ]:
48+ class BasePatcher :
49+ def __init__ (self , file : ifcopenshell .file , logger : Union [logging .Logger , None ]):
50+ self .file = file
51+ self .logger = ensure_logger (logger )
52+
53+ def patch (self ) -> None :
54+ raise NotImplementedError
55+
56+ def get_output (self ) -> Union [ifcopenshell .file , str , None ]:
57+ if hasattr (self , "file_patched" ):
58+ return self .file_patched # pyright: ignore[reportAttributeAccessIssue]
59+ return self .file
60+
61+
62+ def ensure_logger (logger : Union [logging .Logger , None ] = None ) -> logging .Logger :
63+ if logger is not None :
64+ return logger
65+ return logging .getLogger ("IFCPatch" )
66+
67+
68+ def execute (args : ArgumentsDict ) -> Union [ifcopenshell .file , str , None ]:
4969 """Execute a patch recipe
5070
5171 The details of how the patch recipe is executed depends on the definition of
@@ -88,7 +108,7 @@ def execute(args: ArgumentsDict) -> Union[ifcopenshell.file, str]:
88108 """
89109 if "log" in args :
90110 logging .basicConfig (filename = args ["log" ], filemode = "a" , level = logging .DEBUG )
91- logger = logging . getLogger ( "IFCPatch" )
111+ logger = ensure_logger ( )
92112 if recipe_dir := os .environ .get ("IFCPATCH_RECIPE_DIR" ):
93113 spec = importlib .util .spec_from_file_location (args ["recipe" ], os .path .join (recipe_dir , args ["recipe" ] + ".py" ))
94114 recipe = importlib .util .module_from_spec (spec )
@@ -103,17 +123,17 @@ def execute(args: ArgumentsDict) -> Union[ifcopenshell.file, str]:
103123 else :
104124 patcher = recipe .Patcher (args .get ("file" ), logger , arguments )
105125 patcher .patch ()
106- output = getattr (patcher , "file_patched" , patcher . file )
126+ output = BasePatcher . get_output (patcher )
107127 return output
108128
109129
110- def write (output : Union [ifcopenshell .file , str ], filepath : Union [Path , str ]) -> None :
130+ def write (output : Union [ifcopenshell .file , str , None ], filepath : Union [Path , str ]) -> None :
111131 """Write the output of an IFC patch to a file
112132
113133 Typically a patch output would be a patched IFC model file object, or as a
114134 string. This function lets you agnostically write that output to a filepath.
115135
116- :param output: The results from ifcpatch.execute()
136+ :param output: The results from `` ifcpatch.execute()`` / ``Patcher.get_output()``
117137 :param filepath: A filepath to where the results of the patched model should
118138 be written to.
119139 :return: None
0 commit comments