2222from _pytask .console import get_file
2323from _pytask .console import is_jupyter
2424from _pytask .exceptions import CollectionError
25- from _pytask .mark import MarkGenerator
2625from _pytask .mark_utils import get_all_marks
2726from _pytask .mark_utils import has_mark
2827from _pytask .node_protocols import PNode
@@ -176,10 +175,7 @@ def pytask_collect_file(
176175
177176 collected_reports = []
178177 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 ):
183179 continue
184180
185181 # Ensures that tasks with this decorator are only collected once.
@@ -196,6 +192,26 @@ def pytask_collect_file(
196192 return None
197193
198194
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+
199215@hookimpl
200216def pytask_collect_task_protocol (
201217 session : Session , path : Path | None , name : str , obj : Any
@@ -279,7 +295,7 @@ def pytask_collect_task(
279295 markers = markers ,
280296 attributes = {"collection_id" : collection_id , "after" : after },
281297 )
282- if isinstance (obj , PTask ) and not inspect . isclass ( obj ) :
298+ if isinstance (obj , PTask ):
283299 return obj
284300 return None
285301
0 commit comments