@@ -28,6 +28,9 @@ class ExtraCollectedInfo:
2828 module_dependencies : typing .DefaultDict [str , set [str ]] = dataclasses .field (
2929 default_factory = lambda : collections .defaultdict (set )
3030 )
31+ line_numbers : dict [QtCore .Signal | typing .Callable | type , int ] = dataclasses .field (
32+ default_factory = dict
33+ )
3134
3235 def lookup_cls_module (self , cls : type [QtCore .QObject ]) -> str | None :
3336 for (uri , major , minor ), clses in self .registered_classes .items ():
@@ -41,8 +44,10 @@ def add_cls(
4144 version_major : int ,
4245 version_minor : int ,
4346 type_obj : type [QtCore .QObject ],
47+ line_number : int ,
4448 ) -> None :
4549 self .registered_classes [uri , version_major , version_minor ].add (type_obj )
50+ self .line_numbers [type_obj ] = line_number
4651 for base_cls in type_obj .__mro__ :
4752 if isinstance (base_cls , type ) and issubclass (base_cls , QtCore .QObject ):
4853 self .delayed_registrations [type_obj ].add (base_cls )
@@ -57,6 +62,21 @@ def resolve_delayed(self) -> None:
5762 self .registered_classes [module ].add (linked_cls )
5863 self .delayed_registrations .clear ()
5964
65+ def find_line_number (self , obj : QtCore .Signal | typing .Callable | type ) -> int :
66+ if obj in self .line_numbers :
67+ return self .line_numbers [obj ]
68+ elif isinstance (obj , types .FunctionType ):
69+ return obj .__code__ .co_firstlineno
70+ elif isinstance (obj , type ):
71+ if lineno := getattr (obj , "__firstlineno__" , None ):
72+ return lineno
73+ try :
74+ return inspect .getsourcelines (obj )[1 ]
75+ except OSError :
76+ return 0
77+ else :
78+ return 0
79+
6080
6181def patch_with (mod : types .ModuleType ) -> typing .Callable [[typing .Callable ], None ]:
6282 def w (fn : typing .Callable ) -> None :
@@ -67,6 +87,18 @@ def w(fn: typing.Callable) -> None:
6787 return w
6888
6989
90+ def go_up (frame : types .FrameType | None , levels : int ) -> types .FrameType | None :
91+ if levels == 0 :
92+ return frame
93+ return go_up (frame .f_back , levels - 1 ) if frame else None
94+
95+
96+ def get_line_number (stack_levels : int = 3 ) -> int :
97+ frame = go_up (inspect .currentframe (), stack_levels )
98+ assert frame is not None , "No caller frame"
99+ return frame .f_lineno
100+
101+
70102def patch_functions (info : ExtraCollectedInfo ) -> None :
71103 @patch_with (QtQml )
72104 def qmlRegisterSingletonInstance (
@@ -81,7 +113,7 @@ def qmlRegisterSingletonInstance(
81113 ) -> None :
82114 info .extra_class_infos [type_obj ].append (("QML.Singleton" , "true" ))
83115 info .extra_class_infos [type_obj ].append (("QML.Element" , qml_name ))
84- info .add_cls (uri , version_major , version_minor , type_obj )
116+ info .add_cls (uri , version_major , version_minor , type_obj , get_line_number () )
85117 old_fn (type_obj , uri , version_major , version_minor , qml_name , callback )
86118
87119 @patch_with (QtQml )
@@ -97,7 +129,7 @@ def qmlRegisterSingletonType(
97129 ) -> None :
98130 info .extra_class_infos [type_obj ].append (("QML.Singleton" , "true" ))
99131 info .extra_class_infos [type_obj ].append (("QML.Element" , qml_name ))
100- info .add_cls (uri , version_major , version_minor , type_obj )
132+ info .add_cls (uri , version_major , version_minor , type_obj , get_line_number () )
101133 old_fn (
102134 type_obj ,
103135 uri ,
@@ -118,7 +150,7 @@ def qmlRegisterType(
118150 old_fn : typing .Callable ,
119151 ) -> None :
120152 info .extra_class_infos [type_obj ].append (("QML.Element" , qml_name ))
121- info .add_cls (uri , version_major , version_minor , type_obj )
153+ info .add_cls (uri , version_major , version_minor , type_obj , get_line_number () )
122154 old_fn (type_obj , uri , version_major , version_minor , qml_name )
123155
124156 @patch_with (QtQml )
@@ -148,16 +180,11 @@ def qmlRegisterUncreatableType(
148180 info .extra_class_infos [type_obj ].append (("QML.Creatable" , "false" ))
149181 info .extra_class_infos [type_obj ].append (("QML.UncreatableReason" , message ))
150182 info .extra_class_infos [type_obj ].append (("QML.Element" , qml_name ))
151- info .add_cls (uri , version_major , version_minor , type_obj )
183+ info .add_cls (uri , version_major , version_minor , type_obj , get_line_number () )
152184 old_fn (type_obj , uri , version_major , version_minor , qml_name , message )
153185
154186
155187def patch_class_decorators (info : ExtraCollectedInfo ) -> None :
156- def go_up (frame : types .FrameType | None , levels : int ) -> types .FrameType | None :
157- if levels == 0 :
158- return frame
159- return go_up (frame .f_back , levels - 1 ) if frame else None
160-
161188 def get_module (stack_levels : int = 3 ) -> tuple [str , int , int ]:
162189 frame = go_up (inspect .currentframe (), stack_levels )
163190 assert frame is not None , "No caller frame"
@@ -192,7 +219,7 @@ def QmlElement(
192219 ) -> type [T_TypeQObject ]:
193220 info .extra_class_infos [cls ].append (("QML.Element" , "auto" ))
194221 mod_info = get_module ()
195- info .add_cls (* mod_info , cls )
222+ info .add_cls (* mod_info , cls , get_line_number () )
196223 with module_in_globals (* mod_info ):
197224 return old_fn (cls )
198225
@@ -202,7 +229,7 @@ def QmlAnonymous(
202229 ) -> type [T_TypeQObject ]:
203230 info .extra_class_infos [cls ].append (("QML.Element" , "anonymous" ))
204231 mod_info = get_module ()
205- info .add_cls (* mod_info , cls )
232+ info .add_cls (* mod_info , cls , get_line_number () )
206233 with module_in_globals (* mod_info ):
207234 return old_fn (cls )
208235
@@ -213,7 +240,7 @@ def QmlNamedElement(
213240 def w (cls : type [T_TypeQObject ]) -> type [T_TypeQObject ]:
214241 info .extra_class_infos [cls ].append (("QML.Element" , name ))
215242 mod_info = get_module (stack_levels = 2 )
216- info .add_cls (* mod_info , cls )
243+ info .add_cls (* mod_info , cls , get_line_number ( stack_levels = 2 ) )
217244 with module_in_globals (* mod_info ):
218245 return old_fn (name )(cls )
219246
@@ -242,7 +269,7 @@ def w(cls: type[T_TypeQObject]) -> type[T_TypeQObject]:
242269 except KeyError :
243270 info .delayed_registrations [cls ].add (type_obj )
244271 else :
245- info .add_cls (* module , cls )
272+ info .add_cls (* module , cls , get_line_number ( stack_levels = 4 ) )
246273 info .extra_class_infos [cls ].append (
247274 ("QML.Foreign" , type_obj .staticMetaObject .className ()) # type: ignore[attr-defined]
248275 )
@@ -260,7 +287,7 @@ def w(cls: type[T_TypeQObject]) -> type[T_TypeQObject]:
260287 except KeyError :
261288 info .delayed_registrations [cls ].add (type_obj )
262289 else :
263- info .add_cls (* module , cls )
290+ info .add_cls (* module , cls , get_line_number ( stack_levels = 4 ) )
264291 info .extra_class_infos [cls ].append (
265292 ("QML.Extended" , type_obj .staticMetaObject .className ()) # type: ignore[attr-defined]
266293 )
@@ -278,7 +305,7 @@ def w(cls: type[T_TypeQObject]) -> type[T_TypeQObject]:
278305 except KeyError :
279306 info .delayed_registrations [cls ].add (type_obj )
280307 else :
281- info .add_cls (* module , cls )
308+ info .add_cls (* module , cls , get_line_number ( stack_levels = 4 ) )
282309 info .extra_class_infos [cls ].append (
283310 ("QML.Attached" , type_obj .staticMetaObject .className ()) # type: ignore[attr-defined]
284311 )
@@ -344,6 +371,7 @@ def __subclasscheck__(self, subclass: type) -> bool:
344371 def __call__ (self , * types : type | str , ** kwargs : typing .Any ) -> QtCore .Signal :
345372 sig = QtSignal (* types , ** kwargs ) # type: ignore[arg-type]
346373 info .signal_types [sig ] = (types , None )
374+ info .line_numbers [sig ] = get_line_number (stack_levels = 2 )
347375
348376 return sig
349377
0 commit comments