1- from typing import Optional , Dict , Type
1+ from typing import Optional , Dict , Type , TYPE_CHECKING , Callable
22from abc import ABC , abstractmethod
33import platform
44import time
@@ -105,20 +105,24 @@ def register_backend(name: str, clazz):
105105 BACKENDS [name ] = clazz
106106
107107if platform .system () == 'Windows' :
108- from pyvirtualcam import _native_windows_obs , _native_windows_unity_capture
109- register_backend ('obs' , _native_windows_obs .Camera )
110- register_backend ('unitycapture' , _native_windows_unity_capture .Camera )
108+ if not TYPE_CHECKING :
109+ from pyvirtualcam import _native_windows_obs , _native_windows_unity_capture
110+ register_backend ('obs' , _native_windows_obs .Camera )
111+ register_backend ('unitycapture' , _native_windows_unity_capture .Camera )
111112elif platform .system () == 'Darwin' :
112113 # Darwin 22 is used on macOS 13
113114 if int (platform .release ().split ("." )[0 ]) >= 22 :
114- from pyvirtualcam import _native_macos_obs_cmioextension
115- register_backend ('obs' , _native_macos_obs_cmioextension .Camera )
115+ if not TYPE_CHECKING :
116+ from pyvirtualcam import _native_macos_obs_cmioextension
117+ register_backend ('obs' , _native_macos_obs_cmioextension .Camera )
116118 else :
117- from pyvirtualcam import _native_macos_obs_dal
118- register_backend ('obs' , _native_macos_obs_dal .Camera )
119+ if not TYPE_CHECKING :
120+ from pyvirtualcam import _native_macos_obs_dal
121+ register_backend ('obs' , _native_macos_obs_dal .Camera )
119122elif platform .system () == 'Linux' :
120- from pyvirtualcam import _native_linux_v4l2loopback
121- register_backend ('v4l2loopback' , _native_linux_v4l2loopback .Camera )
123+ if not TYPE_CHECKING :
124+ from pyvirtualcam import _native_linux_v4l2loopback
125+ register_backend ('v4l2loopback' , _native_linux_v4l2loopback .Camera )
122126
123127class PixelFormat (Enum ):
124128 """ Pixel formats.
@@ -206,28 +210,29 @@ def __init__(self, width: int, height: int, fps: float, *,
206210 backends = [(backend , BACKENDS [backend ])]
207211 else :
208212 backends = list (BACKENDS .items ())
209- self . _backend = None
213+ backend_instance : Optional [ Backend ] = None
210214 errors = []
211215 for name , clazz in backends :
212216 try :
213- self . _backend = clazz (
217+ backend_instance = clazz (
214218 width = width , height = height , fps = fps ,
215219 fourcc = encode_fourcc (fmt .value ),
216220 device = device ,
217221 ** kw )
218222 except Exception as e :
219223 errors .append (f"'{ name } ' backend: { e } " )
220224 else :
221- self ._backend_name = name
225+ self ._backend_name : str = name
222226 break
223- if self . _backend is None :
227+ if backend_instance is None :
224228 raise RuntimeError ('\n ' .join (errors ))
225-
226- self ._width = width
227- self ._height = height
228- self ._fps = fps
229- self ._fmt = fmt
230- self ._print_fps = print_fps
229+
230+ self ._backend : Backend = backend_instance
231+ self ._width : int = width
232+ self ._height : int = height
233+ self ._fps : float = fps
234+ self ._fmt : PixelFormat = fmt
235+ self ._print_fps : bool = print_fps
231236
232237 frame_shape = FrameShapes [fmt ](width , height )
233238 if isinstance (frame_shape , int ):
@@ -239,20 +244,20 @@ def check_frame_shape(frame: np.ndarray):
239244 if frame .shape != frame_shape :
240245 raise ValueError (f"unexpected frame shape: { frame .shape } != { frame_shape } " )
241246
242- self ._check_frame_shape = check_frame_shape
247+ self ._check_frame_shape : Callable [[ np . ndarray ], None ] = check_frame_shape
243248
244- self ._fps_counter = FPSCounter (fps )
245- self ._fps_last_printed = time .perf_counter ()
246- self ._frames_sent = 0
247- self ._last_frame_t = None
248- self ._extra_time_per_frame = 0
249+ self ._fps_counter : FPSCounter = FPSCounter (fps )
250+ self ._fps_last_printed : float = time .perf_counter ()
251+ self ._frames_sent : int = 0
252+ self ._last_frame_t : float = time .perf_counter ()
253+ self ._extra_time_per_frame : float = 0.0
254+ self ._closed : bool = False
249255
250256 def __enter__ (self ):
251257 return self
252258
253- def __exit__ (self , exc_type , exc_value , traceback ) -> bool :
259+ def __exit__ (self , exc_type , exc_value , traceback ) -> None :
254260 self .close ()
255- return False
256261
257262 def __del__ (self ):
258263 self .close ()
@@ -319,9 +324,9 @@ def close(self) -> None:
319324 This method is automatically called when using ``with`` or
320325 when this instance goes out of scope.
321326 """
322- if self . _backend is not None :
327+ if not self . _closed :
323328 self ._backend .close ()
324- self ._backend = None
329+ self ._closed = True
325330
326331 def send (self , frame : np .ndarray ) -> None :
327332 """Send a frame to the virtual camera device.
0 commit comments