22
22
from _pytask .console import get_file
23
23
from _pytask .console import is_jupyter
24
24
from _pytask .exceptions import CollectionError
25
- from _pytask .mark import MarkGenerator
26
25
from _pytask .mark_utils import get_all_marks
27
26
from _pytask .mark_utils import has_mark
28
27
from _pytask .node_protocols import PNode
@@ -176,10 +175,7 @@ def pytask_collect_file(
176
175
177
176
collected_reports = []
178
177
for name , obj in inspect .getmembers (mod ):
179
- # Skip mark generator since it overrides __getattr__ and seems like any
180
- # object. Happens when people do ``from pytask import mark`` and
181
- # ``@mark.x``.
182
- if isinstance (obj , MarkGenerator ):
178
+ if _is_filtered_object (obj ):
183
179
continue
184
180
185
181
# Ensures that tasks with this decorator are only collected once.
@@ -196,6 +192,26 @@ def pytask_collect_file(
196
192
return None
197
193
198
194
195
+ def _is_filtered_object (obj : Any ) -> bool :
196
+ """Filter some objects that are only causing harm later on.
197
+
198
+ See :issue:`507`.
199
+
200
+ """
201
+ # Filter :class:`pytask.Task` and :class:`pytask.TaskWithoutPath` objects.
202
+ if isinstance (obj , PTask ) and inspect .isclass (obj ):
203
+ return True
204
+
205
+ # Filter objects overwriting the ``__getattr__`` method like :class:`pytask.mark` or
206
+ # ``from ibis import _``.
207
+ attr_name = "attr_that_definitely_does_not_exist"
208
+ if hasattr (obj , attr_name ) and not bool (
209
+ inspect .getattr_static (obj , attr_name , False )
210
+ ):
211
+ return True
212
+ return False
213
+
214
+
199
215
@hookimpl
200
216
def pytask_collect_task_protocol (
201
217
session : Session , path : Path | None , name : str , obj : Any
@@ -279,7 +295,7 @@ def pytask_collect_task(
279
295
markers = markers ,
280
296
attributes = {"collection_id" : collection_id , "after" : after },
281
297
)
282
- if isinstance (obj , PTask ) and not inspect . isclass ( obj ) :
298
+ if isinstance (obj , PTask ):
283
299
return obj
284
300
return None
285
301
0 commit comments