Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,12 @@ def __call__(self, *args, **kwargs):
"matplotlib.pyplot",
"matplotlib.dates",
"matplotlib.figure",
"picamera2",
"picamera2",
"jinja2",
"seaborn",
"PyQt6",
"gpiod",
"picamera2",
"libcamera",
]

# Add the module path to sys.path here.
Expand Down Expand Up @@ -247,6 +249,4 @@ def __call__(self, *args, **kwargs):

autosectionlabel_prefix_document = True

autodoc_mock_imports = ["PyQt5", "PyQt6", "gpiod", "picamera2", "libcamera"]

suppress_warnings = ["docutils"]
1 change: 0 additions & 1 deletion village/calibration/sound_calibration.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,3 @@ def run_in_thread(self, daemon: bool = True) -> None:
def close(self) -> None:
"""Closes the calibration instance and releases resources."""
return

9 changes: 8 additions & 1 deletion village/classes/abstract_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class PyBpodBase:
session (Session | Any): Bpod session object.
connected (bool): Connection status.
"""

error: str = "Error connecting to the bpod "
session: Session | Any = None
connected: bool = False
Expand Down Expand Up @@ -182,6 +183,7 @@ class TelegramBotBase:
Attributes:
error (str): Error message.
"""

error: str = "Error connecting to the telegram_bot "

def alarm(self, message: str) -> None:
Expand All @@ -199,6 +201,7 @@ class ScaleBase:
Attributes:
error (str): Error message.
"""

error: str = "Error connecting to the scale "

def tare(self) -> None:
Expand Down Expand Up @@ -228,6 +231,7 @@ class TempSensorBase:
Attributes:
error (str): Error message.
"""

error: str = "Error connecting to the temp_sensor "

def start(self) -> None:
Expand All @@ -251,6 +255,7 @@ class MotorBase:
open_angle (int): Angle for open position.
close_angle (int): Angle for close position.
"""

error: str = "Error connecting to the motor "
open_angle: int = 0
close_angle: int = 0
Expand All @@ -271,6 +276,7 @@ class SoundDeviceBase:
samplerate (int): Audio sample rate.
error (str): Error message.
"""

samplerate: int = 44100
error: str = (
""
Expand Down Expand Up @@ -353,6 +359,7 @@ class CameraBase:
y_position (int): Y coordinate of tracked object.
chrono (time_utils.Chrono): Timer utility.
"""

area1: list[int] = []
area2: list[int] = []
area3: list[int] = []
Expand Down Expand Up @@ -477,6 +484,7 @@ class BehaviorWindowBase(QWidget):
Attributes:
background_color: The background color.
"""

background_color = None

def start_drawing(self) -> None:
Expand Down Expand Up @@ -525,4 +533,3 @@ def get_video_frame(self) -> Optional[QImage]:
Optional[QImage]: The current frame as a QImage.
"""
return None

1 change: 0 additions & 1 deletion village/classes/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,4 +381,3 @@ def convert_active(value) -> str:
)

return new_df

2 changes: 1 addition & 1 deletion village/classes/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ class AreaActive(SuperEnum):

class State(SuperEnum):
"""Enum representing the state of the village system."""

WAIT = "All subjects are at home, waiting for RFID detection"
DETECTION = "Gathering subject data, checking requirements to enter"
ACCESS = "Closing door1, opening door2"
Expand Down Expand Up @@ -226,4 +227,3 @@ class Save(SuperEnum):
NO = "NO"
ZERO = "ZERO"
ERROR = "ERROR"

4 changes: 2 additions & 2 deletions village/classes/settings_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,12 +193,12 @@ def get(self, key: str) -> Any:
val = self.saved_settings.value(key)
if val is None:
return setting.value

# If QSettings returns a QVariant/PyQt object/string that is not the value we expect
# but contains "QSettings", it's likely a Sphinx build artifact or mock issue.
val_str = str(val)
if "QSettings" in val_str or "PyQt5" in val_str:
return setting.value
return setting.value

str_value = str(val)
try:
Expand Down
1 change: 0 additions & 1 deletion village/classes/subject.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,3 @@ def minimum_time_ok(self) -> bool:
subject=self.name,
)
return False

3 changes: 1 addition & 2 deletions village/custom_classes/after_session_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

class AfterSessionBase:
"""Base class for operations performed after a session ends.

This class handles data synchronization (backup) to either a hard drive
or a remote server based on current settings.
"""
Expand Down Expand Up @@ -62,4 +62,3 @@ def run(self) -> None:
if __name__ == "__main__":
after_session = AfterSessionBase()
after_session.run()

9 changes: 4 additions & 5 deletions village/custom_classes/camera_trigger_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,21 @@

class CameraTriggerBase:
"""Base class for defining custom camera trigger behavior.

This class can be overridden to implement specific actions when detection areas
are triggered or to monitor subject position.
"""

def __init__(self) -> None:
"""Initializes the CameraTriggerBase instance."""
self.name = "Camera Trigger"

def trigger(self, cam: CameraBase) -> None:
"""Evaluates camera triggers and performs corresponding actions.

This method is called to check if any defined areas in the camera view
have been triggered (e.g., by the subject entering them).

Args:
cam (CameraBase): The camera instance providing the trigger status.
"""
Expand All @@ -37,4 +37,3 @@ def trigger(self, cam: CameraBase) -> None:
cam.write_text("Area 4 triggered")

# or you can check the position of the animal manually

3 changes: 1 addition & 2 deletions village/custom_classes/change_cycle_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

class ChangeCycleBase:
"""Base class for operations performed during the day/night cycle change.

This class handles cleanup tasks such as deleting old video files and ensuring
disk space is managed, potentially backing up data before deletion.
"""
Expand Down Expand Up @@ -64,4 +64,3 @@ def run(self) -> None:
if __name__ == "__main__":
change_cycle = ChangeCycleBase()
change_cycle.run()

1 change: 0 additions & 1 deletion village/custom_classes/online_plot_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,3 @@ def update_plot(self, df: pd.DataFrame) -> None:
return

df.plot(kind="scatter", x="TRIAL_START", y="trial", ax=self.ax)

1 change: 0 additions & 1 deletion village/custom_classes/session_plot_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,3 @@ def create_plot(
df.plot(kind="line", x="TRIAL_START", y="trial", ax=ax)
ax.scatter(df["TRIAL_START"], df["trial"], color="red")
return fig

1 change: 0 additions & 1 deletion village/custom_classes/subject_plot_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,3 @@ def create_plot(
ax.set_title("Subject Plot")
ax.set_ylabel("Number of trials")
return fig

4 changes: 3 additions & 1 deletion village/custom_classes/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@ def __init__(self, message) -> None:

class Event(EventName):
"""Enumeration of Bpod event names."""

pass


class Output(OutputChannel):
"""Enumeration of Bpod output channels."""

pass


Expand Down Expand Up @@ -117,6 +119,7 @@ def run_in_thread(self, daemon: bool = True) -> None:
Args:
daemon (bool, optional): Whether to run as a daemon thread. Defaults to True.
"""

def test_run():
self.create_paths()
self.start()
Expand Down Expand Up @@ -562,4 +565,3 @@ def create_paths(self) -> None:
self.video_path = str(Path(self.video_directory, self.filename + ".mp4"))
self.video_data_path = str(Path(self.video_directory, self.filename + ".csv"))
self.subject_path = str(Path(self.sessions_directory, self.subject + ".csv"))

1 change: 0 additions & 1 deletion village/custom_classes/training_protocol_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,4 +248,3 @@ def get_string(self) -> str:
dict = self.get_dict()
_, new_dict = self.correct_types_in_dict(dict)
return json.dumps(new_dict)

1 change: 0 additions & 1 deletion village/devices/bpod.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,4 +394,3 @@ def get_bpod() -> PyBpodBase:


bpod = get_bpod()

2 changes: 0 additions & 2 deletions village/devices/motor.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,6 @@ def get_motor(pin: int, angles: list[int]) -> MotorBase:
return MotorBase()



import sys

if "sphinx" in sys.modules:
Expand All @@ -166,4 +165,3 @@ def get_motor(pin: int, angles: list[int]) -> MotorBase:
else:
motor1 = get_motor(settings.get("MOTOR1_PIN"), settings.get("MOTOR1_VALUES"))
motor2 = get_motor(settings.get("MOTOR2_PIN"), settings.get("MOTOR2_VALUES"))

1 change: 0 additions & 1 deletion village/devices/rfid.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,3 @@ def get_id(self) -> tuple[str, bool]:


rfid = Rfid()

3 changes: 1 addition & 2 deletions village/devices/scale.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def get_value(self, samples: int = 1, interval_s: float = 0.005) -> int:
if interval_s > 0 and i < samples - 1:
time.sleep(interval_s)
if not values:
return 0
return 0
median = int(np.median(values))
if median == 0 and self.alarm_timer.has_elapsed():
log.alarm("Scale not responding, please check the connection.")
Expand Down Expand Up @@ -158,4 +158,3 @@ def real_weight_inference(weight_array, threshold) -> tuple[bool, float]:
return (True, median_weight)
else:
return (False, 0.0)

1 change: 0 additions & 1 deletion village/devices/sound_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,4 +232,3 @@ def get_sound_device() -> SoundDeviceBase:


sound_device = get_sound_device()

1 change: 0 additions & 1 deletion village/devices/telegram_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,4 +196,3 @@ def get_telegram_bot() -> TelegramBotBase:


telegram_bot = get_telegram_bot()

1 change: 0 additions & 1 deletion village/devices/temp_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,3 @@ def get_temp_sensor(address: str) -> TempSensorBase:


temp_sensor = get_temp_sensor(address=settings.get("TEMP_SENSOR_ADDRESS"))

3 changes: 1 addition & 2 deletions village/gui/data_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import cv2
import numpy as np
import pandas as pd
from village.classes.enums import State
from pandas import DataFrame
from PyQt5.QtCore import (
QAbstractTableModel,
Expand Down Expand Up @@ -40,7 +39,7 @@
QWidget,
)

from village.classes.enums import DataTable
from village.classes.enums import DataTable, State
from village.gui.layout import Layout
from village.manager import manager
from village.plots.sound_calibration_plot import sound_calibration_plot
Expand Down
1 change: 0 additions & 1 deletion village/gui/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,3 @@ def reload_app(self) -> None:
self.q_app.quit()
python = sys.executable
os.execv(python, [python] + sys.argv)

1 change: 0 additions & 1 deletion village/gui/gui_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,3 @@ def check_update_chrono(self) -> None:
"""
if self.update_chrono.get_seconds() > self.screensave_time:
self.layout.main_button_clicked(auto=True)

11 changes: 8 additions & 3 deletions village/gui/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from pathlib import Path
from typing import TYPE_CHECKING, Callable

from village.classes.enums import State
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from PyQt5.QtCore import Qt, QTime
from PyQt5.QtGui import QCloseEvent, QPixmap, QWheelEvent
Expand All @@ -21,7 +20,7 @@
QVBoxLayout,
)

from village.classes.enums import DataTable
from village.classes.enums import DataTable, State
from village.manager import manager
from village.scripts.log import log
from village.settings import settings
Expand All @@ -32,6 +31,7 @@

class Label(QLabel):
"""Custom styled QLabel."""

def __init__(
self,
text: str,
Expand Down Expand Up @@ -60,6 +60,7 @@ def __init__(

class LabelImage(QLabel):
"""QLabel for displaying an image from the resources directory."""

def __init__(self, file) -> None:
"""Initializes a LabelImage."""
super().__init__()
Expand All @@ -71,6 +72,7 @@ def __init__(self, file) -> None:

class LineEdit(QLineEdit):
"""Custom QLineEdit that triggers an action on text change."""

def __init__(self, text: str, action: Callable) -> None:
"""Initializes a LineEdit."""
super().__init__()
Expand All @@ -80,6 +82,7 @@ def __init__(self, text: str, action: Callable) -> None:

class TimeEdit(QTimeEdit):
"""Custom QTimeEdit with HH:mm format."""

def __init__(self, text: str, action: Callable) -> None:
"""Initializes a TimeEdit."""
super().__init__()
Expand All @@ -90,6 +93,7 @@ def __init__(self, text: str, action: Callable) -> None:

class PushButton(QPushButton):
"""Custom styled QPushButton."""

def __init__(
self, text: str, color: str, action: Callable, description: str
) -> None:
Expand All @@ -105,6 +109,7 @@ def __init__(

class ToggleButton(QPushButton):
"""Button that cycles through a list of values when pressed."""

def __init__(
self,
key: str,
Expand Down Expand Up @@ -151,6 +156,7 @@ def on_pressed(self) -> None:

class ComboBox(QComboBox):
"""Custom QComboBox linked to a setting or variable."""

def __init__(
self, key: str, possible_values: list[str], index: int, action: Callable
) -> None:
Expand Down Expand Up @@ -188,7 +194,6 @@ def wheelEvent(self, event: QWheelEvent) -> None:
event.ignore()



class Layout(QGridLayout):
"""Base class for all GUI layouts in the application.

Expand Down
Loading
Loading