1616def _install_fake_detector_module ():
1717 """
1818 Install a lightweight fake 'detector' module into sys.modules BEFORE importing app.py,
19- so that `from detector import Detector` pulls this fake and avoids loading YOLO.
19+ so that `from .detector import Detector` or `from backend.detector import Detector`
20+ pulls this fake and avoids loading YOLO models.
2021 """
2122 fake_detector = types .ModuleType ("detector" )
2223
24+ # === Mock classes ===
2325 class _TensorLike :
24- """Mimics a tensor with tolist() method """
26+ """Mimics a tensor with . tolist(), __float__, and __int__ """
2527 def __init__ (self , data ):
2628 self ._data = data
27-
29+
2830 def tolist (self ):
2931 return self ._data if isinstance (self ._data , list ) else [self ._data ]
30-
32+
3133 def __float__ (self ):
3234 return float (self ._data )
33-
35+
3436 def __int__ (self ):
3537 return int (self ._data )
3638
3739 class _SeqWithToList :
40+ """Mimics torch.Tensor sequences like boxes.xyxy, boxes.conf, boxes.cls"""
3841 def __init__ (self , data ):
3942 self ._data = data
4043
4144 def tolist (self ):
4245 return list (self ._data )
43-
46+
4447 def __iter__ (self ):
4548 # Wrap each item in _TensorLike so it has .tolist()
4649 for item in self ._data :
4750 yield _TensorLike (item )
4851
4952 class _FakeBoxes :
53+ """Fake bounding boxes data"""
5054 def __init__ (self ):
51- # Match the new API: xyxy format ( x1, y1, x2, y2), conf, cls
52- self .xyxy = _SeqWithToList ([[10 , 20 , 40 , 60 ]]) # x1, y1, x2, y2
53- self .conf = _SeqWithToList ([0.95 ]) # confidence score
54- self .cls = _SeqWithToList ([0 ]) # class id
55+ # xyxy = x1, y1, x2, y2
56+ self .xyxy = _SeqWithToList ([[10 , 20 , 40 , 60 ]])
57+ self .conf = _SeqWithToList ([0.95 ])
58+ self .cls = _SeqWithToList ([0 ])
5559
5660 class _FakeResult :
61+ """Fake YOLO result"""
5762 def __init__ (self ):
5863 self .boxes = _FakeBoxes ()
59- self .names = {0 : "ក" } # Fake class names mapping
64+ self .names = {0 : "ក" } # Fake Khmer class name
6065
61- class Detector : # noqa: N801 - match name imported in app.py
66+ # === Mock Detector class ===
67+ class Detector :
6268 instance = None
6369
6470 def __new__ (cls ):
@@ -67,19 +73,25 @@ def __new__(cls):
6773 return cls .instance
6874
6975 def _initialize (self ):
70- # no-op in tests
76+ # no-op (avoid model loading)
7177 pass
7278
73- def detection (self , model_name , image ): # signature match
79+ def detection (self , model_name , image ):
80+ # return fake YOLO-like result
7481 return _FakeResult ()
7582
83+ # Register fake module under both names
7684 fake_detector .Detector = Detector
7785 sys .modules ["detector" ] = fake_detector
86+ sys .modules ["backend.detector" ] = fake_detector # <— important line
7887
7988
8089@pytest .fixture (scope = "session" )
8190def client ():
82- # Install fake detector before importing app
91+ """
92+ Creates a FastAPI TestClient that uses the fake detector
93+ so tests run without actual YOLO model loading.
94+ """
8395 _install_fake_detector_module ()
8496 app_module = import_module ("app" )
8597 return TestClient (app_module .app )
0 commit comments