Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(sensors): endpoints for sensors #52

Merged
merged 4 commits into from
Mar 24, 2025
Merged

Conversation

24Victor
Copy link
Contributor

This pull request introduces new functionality to the src/api/v1/endpoints/sensors.py file by adding endpoints for retrieving sensor data. The most important changes include the addition of new imports, and the implementation of two new GET endpoints.

New functionality:

@24Victor 24Victor requested a review from a team as a code owner March 20, 2025 16:08
@24Victor 24Victor requested review from Ism1tha and albert1413 March 20, 2025 16:08
@github-actions github-actions bot added the kind/feature Categorizes issue or PR as related to a new feature. label Mar 20, 2025
Copy link

codecov bot commented Mar 20, 2025

❌ 7 Tests Failed:

Tests completed Failed Passed Skipped
7 7 0 0
View the top 3 failed test(s) by shortest run time
tests.unit.test_main::test_get_sensors
Stack Traces | 0.001s run time
self = <pymysql.connections.Connection object at 0x7efc7ec45d30>, sock = None

    def connect(self, sock=None):
        self._closed = False
        try:
            if sock is None:
                if self.unix_socket:
                    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
                    sock.settimeout(self.connect_timeout)
                    sock.connect(self.unix_socket)
                    self.host_info = "Localhost via UNIX socket"
                    self._secure = True
                    if DEBUG:
                        print("connected using unix_socket")
                else:
                    kwargs = {}
                    if self.bind_address is not None:
                        kwargs["source_address"] = (self.bind_address, 0)
                    while True:
                        try:
>                           sock = socket.create_connection(
                                (self.host, self.port), self.connect_timeout, **kwargs
                            )

.../local/lib/python3.13.............../site-packages/pymysql/connections.py:649: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../local/lib/python3.13/socket.py:864: in create_connection
    raise exceptions[0]
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

address = ('localhost', 3306), timeout = 10, source_address = None

    def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT,
                          source_address=None, *, all_errors=False):
        """Connect to *address* and return the socket object.
    
        Convenience function.  Connect to *address* (a 2-tuple ``(host,
        port)``) and return the socket object.  Passing the optional
        *timeout* parameter will set the timeout on the socket instance
        before attempting to connect.  If no *timeout* is supplied, the
        global default timeout setting returned by :func:`getdefaulttimeout`
        is used.  If *source_address* is set it must be a tuple of (host, port)
        for the socket to bind as a source address before making the connection.
        A host of '' or port 0 tells the OS to use the default. When a connection
        cannot be created, raises the last error if *all_errors* is False,
        and an ExceptionGroup of all errors if *all_errors* is True.
        """
    
        host, port = address
        exceptions = []
        for res in getaddrinfo(host, port, 0, SOCK_STREAM):
            af, socktype, proto, canonname, sa = res
            sock = None
            try:
                sock = socket(af, socktype, proto)
                if timeout is not _GLOBAL_DEFAULT_TIMEOUT:
                    sock.settimeout(timeout)
                if source_address:
                    sock.bind(source_address)
>               sock.connect(sa)
E               ConnectionRefusedError: [Errno 111] Connection refused

.../local/lib/python3.13/socket.py:849: ConnectionRefusedError

During handling of the above exception, another exception occurred:

self = <sqlalchemy.engine.base.Connection object at 0x7efc7ec45be0>
engine = Engine(mysql+pymysql://root:***@localhost:3306/microservice)
connection = None, _has_events = None, _allow_revalidate = True
_allow_autobegin = True

    def __init__(
        self,
        engine: Engine,
        connection: Optional[PoolProxiedConnection] = None,
        _has_events: Optional[bool] = None,
        _allow_revalidate: bool = True,
        _allow_autobegin: bool = True,
    ):
        """Construct a new Connection."""
        self.engine = engine
        self.dialect = dialect = engine.dialect
    
        if connection is None:
            try:
>               self._dbapi_connection = engine.raw_connection()

.../local/lib/python3.13.../sqlalchemy/engine/base.py:146: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../local/lib/python3.13.../sqlalchemy/engine/base.py:3298: in raw_connection
    return self.pool.connect()
.../local/lib/python3.13.../sqlalchemy/pool/base.py:449: in connect
    return _ConnectionFairy._checkout(self)
.../local/lib/python3.13.../sqlalchemy/pool/base.py:1264: in _checkout
    fairy = _ConnectionRecord.checkout(pool)
.../local/lib/python3.13.../sqlalchemy/pool/base.py:713: in checkout
    rec = pool._do_get()
.../local/lib/python3.13.../sqlalchemy/pool/impl.py:308: in _do_get
    return self._create_connection()
.../local/lib/python3.13.../sqlalchemy/pool/base.py:390: in _create_connection
    return _ConnectionRecord(self)
.../local/lib/python3.13.../sqlalchemy/pool/base.py:675: in __init__
    self.__connect()
.../local/lib/python3.13.../sqlalchemy/pool/base.py:901: in __connect
    with util.safe_reraise():
.../local/lib/python3.13.../sqlalchemy/util/langhelpers.py:146: in __exit__
    raise exc_value.with_traceback(exc_tb)
.../local/lib/python3.13.../sqlalchemy/pool/base.py:897: in __connect
    self.dbapi_connection = connection = pool._invoke_creator(self)
.../local/lib/python3.13.../sqlalchemy/engine/create.py:646: in connect
    return dialect.connect(*cargs, **cparams)
.../local/lib/python3.13.../sqlalchemy/engine/default.py:622: in connect
    return self.loaded_dbapi.connect(*cargs, **cparams)
.../local/lib/python3.13.............../site-packages/pymysql/connections.py:361: in __init__
    self.connect()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <pymysql.connections.Connection object at 0x7efc7ec45d30>, sock = None

    def connect(self, sock=None):
        self._closed = False
        try:
            if sock is None:
                if self.unix_socket:
                    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
                    sock.settimeout(self.connect_timeout)
                    sock.connect(self.unix_socket)
                    self.host_info = "Localhost via UNIX socket"
                    self._secure = True
                    if DEBUG:
                        print("connected using unix_socket")
                else:
                    kwargs = {}
                    if self.bind_address is not None:
                        kwargs["source_address"] = (self.bind_address, 0)
                    while True:
                        try:
                            sock = socket.create_connection(
                                (self.host, self.port), self.connect_timeout, **kwargs
                            )
                            break
                        except OSError as e:
                            if e.errno == errno.EINTR:
                                continue
                            raise
                    self.host_info = "socket %s:%d" % (self.host, self.port)
                    if DEBUG:
                        print("connected using socket")
                    sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
                    sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
                sock.settimeout(None)
    
            self._sock = sock
            self._rfile = sock.makefile("rb")
            self._next_seq_id = 0
    
            self._get_server_information()
            self._request_authentication()
    
            # Send "SET NAMES" query on init for:
            # - Ensure charaset (and collation) is set to the server.
            #   - collation_id in handshake packet may be ignored.
            # - If collation is not specified, we don't know what is server's
            #   default collation for the charset. For example, default collation
            #   of utf8mb4 is:
            #   - MySQL 5.7, MariaDB 10.x: utf8mb4_general_ci
            #   - MySQL 8.0: utf8mb4_0900_ai_ci
            #
            # Reference:
            # - https://github..../PyMySQL/issues/1092
            # - https://github..../wagtail/issues/9477
            # - https://zenn..../methane/articles/2023-mysql-collation (Japanese)
            self.set_character_set(self.charset, self.collation)
    
            if self.sql_mode is not None:
                c = self.cursor()
                c.execute("SET sql_mode=%s", (self.sql_mode,))
                c.close()
    
            if self.init_command is not None:
                c = self.cursor()
                c.execute(self.init_command)
                c.close()
    
            if self.autocommit_mode is not None:
                self.autocommit(self.autocommit_mode)
        except BaseException as e:
            self._rfile = None
            if sock is not None:
                try:
                    sock.close()
                except:  # noqa
                    pass
    
            if isinstance(e, (OSError, IOError)):
                exc = err.OperationalError(
                    CR.CR_CONN_HOST_ERROR,
                    f"Can't connect to MySQL server on {self.host!r} ({e})",
                )
                # Keep original exception and traceback to investigate error.
                exc.original_exception = e
                exc.traceback = traceback.format_exc()
                if DEBUG:
                    print(exc.traceback)
>               raise exc
E               pymysql.err.OperationalError: (2003, "Can't connect to MySQL server on 'localhost' ([Errno 111] Connection refused)")

.../local/lib/python3.13.............../site-packages/pymysql/connections.py:716: OperationalError

The above exception was the direct cause of the following exception:

    @pytest.fixture(scope="session", autouse=True)
    def apply_migrations():
        base_dir = os.path.dirname(os.path.dirname(__file__))
        alembic_cfg = Config(os.path.join(base_dir, "alembic.ini"))
>       command.upgrade(alembic_cfg, "head")

tests/conftest.py:11: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../local/lib/python3.13.../site-packages/alembic/command.py:406: in upgrade
    script.run_env()
.../local/lib/python3.13.../alembic/script/base.py:586: in run_env
    util.load_python_file(self.dir, "env.py")
.../local/lib/python3.13.../alembic/util/pyfiles.py:95: in load_python_file
    module = load_module_py(module_id, path)
.../local/lib/python3.13.../alembic/util/pyfiles.py:113: in load_module_py
    spec.loader.exec_module(module)  # type: ignore
alembic/env.py:62: in <module>
    run_migrations_online()
alembic/env.py:50: in run_migrations_online
    with connectable.connect() as connection:
.../local/lib/python3.13.../sqlalchemy/engine/base.py:3274: in connect
    return self._connection_cls(self)
.../local/lib/python3.13.../sqlalchemy/engine/base.py:148: in __init__
    Connection._handle_dbapi_exception_noconnection(
.../local/lib/python3.13.../sqlalchemy/engine/base.py:2439: in _handle_dbapi_exception_noconnection
    raise sqlalchemy_exception.with_traceback(exc_info[2]) from e
.../local/lib/python3.13.../sqlalchemy/engine/base.py:146: in __init__
    self._dbapi_connection = engine.raw_connection()
.../local/lib/python3.13.../sqlalchemy/engine/base.py:3298: in raw_connection
    return self.pool.connect()
.../local/lib/python3.13.../sqlalchemy/pool/base.py:449: in connect
    return _ConnectionFairy._checkout(self)
.../local/lib/python3.13.../sqlalchemy/pool/base.py:1264: in _checkout
    fairy = _ConnectionRecord.checkout(pool)
.../local/lib/python3.13.../sqlalchemy/pool/base.py:713: in checkout
    rec = pool._do_get()
.../local/lib/python3.13.../sqlalchemy/pool/impl.py:308: in _do_get
    return self._create_connection()
.../local/lib/python3.13.../sqlalchemy/pool/base.py:390: in _create_connection
    return _ConnectionRecord(self)
.../local/lib/python3.13.../sqlalchemy/pool/base.py:675: in __init__
    self.__connect()
.../local/lib/python3.13.../sqlalchemy/pool/base.py:901: in __connect
    with util.safe_reraise():
.../local/lib/python3.13.../sqlalchemy/util/langhelpers.py:146: in __exit__
    raise exc_value.with_traceback(exc_tb)
.../local/lib/python3.13.../sqlalchemy/pool/base.py:897: in __connect
    self.dbapi_connection = connection = pool._invoke_creator(self)
.../local/lib/python3.13.../sqlalchemy/engine/create.py:646: in connect
    return dialect.connect(*cargs, **cparams)
.../local/lib/python3.13.../sqlalchemy/engine/default.py:622: in connect
    return self.loaded_dbapi.connect(*cargs, **cparams)
.../local/lib/python3.13.............../site-packages/pymysql/connections.py:361: in __init__
    self.connect()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <pymysql.connections.Connection object at 0x7efc7ec45d30>, sock = None

    def connect(self, sock=None):
        self._closed = False
        try:
            if sock is None:
                if self.unix_socket:
                    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
                    sock.settimeout(self.connect_timeout)
                    sock.connect(self.unix_socket)
                    self.host_info = "Localhost via UNIX socket"
                    self._secure = True
                    if DEBUG:
                        print("connected using unix_socket")
                else:
                    kwargs = {}
                    if self.bind_address is not None:
                        kwargs["source_address"] = (self.bind_address, 0)
                    while True:
                        try:
                            sock = socket.create_connection(
                                (self.host, self.port), self.connect_timeout, **kwargs
                            )
                            break
                        except OSError as e:
                            if e.errno == errno.EINTR:
                                continue
                            raise
                    self.host_info = "socket %s:%d" % (self.host, self.port)
                    if DEBUG:
                        print("connected using socket")
                    sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
                    sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
                sock.settimeout(None)
    
            self._sock = sock
            self._rfile = sock.makefile("rb")
            self._next_seq_id = 0
    
            self._get_server_information()
            self._request_authentication()
    
            # Send "SET NAMES" query on init for:
            # - Ensure charaset (and collation) is set to the server.
            #   - collation_id in handshake packet may be ignored.
            # - If collation is not specified, we don't know what is server's
            #   default collation for the charset. For example, default collation
            #   of utf8mb4 is:
            #   - MySQL 5.7, MariaDB 10.x: utf8mb4_general_ci
            #   - MySQL 8.0: utf8mb4_0900_ai_ci
            #
            # Reference:
            # - https://github..../PyMySQL/issues/1092
            # - https://github..../wagtail/issues/9477
            # - https://zenn..../methane/articles/2023-mysql-collation (Japanese)
            self.set_character_set(self.charset, self.collation)
    
            if self.sql_mode is not None:
                c = self.cursor()
                c.execute("SET sql_mode=%s", (self.sql_mode,))
                c.close()
    
            if self.init_command is not None:
                c = self.cursor()
                c.execute(self.init_command)
                c.close()
    
            if self.autocommit_mode is not None:
                self.autocommit(self.autocommit_mode)
        except BaseException as e:
            self._rfile = None
            if sock is not None:
                try:
                    sock.close()
                except:  # noqa
                    pass
    
            if isinstance(e, (OSError, IOError)):
                exc = err.OperationalError(
                    CR.CR_CONN_HOST_ERROR,
                    f"Can't connect to MySQL server on {self.host!r} ({e})",
                )
                # Keep original exception and traceback to investigate error.
                exc.original_exception = e
                exc.traceback = traceback.format_exc()
                if DEBUG:
                    print(exc.traceback)
>               raise exc
E               sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (2003, "Can't connect to MySQL server on 'localhost' ([Errno 111] Connection refused)")
E               (Background on this error at: https://sqlalche..../e/20/e3q8)

.../local/lib/python3.13.............../site-packages/pymysql/connections.py:716: OperationalError
tests.unit.test_main::test_upload_file_saves_correctly
Stack Traces | 0.001s run time
self = <pymysql.connections.Connection object at 0x7efc7ec45d30>, sock = None

    def connect(self, sock=None):
        self._closed = False
        try:
            if sock is None:
                if self.unix_socket:
                    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
                    sock.settimeout(self.connect_timeout)
                    sock.connect(self.unix_socket)
                    self.host_info = "Localhost via UNIX socket"
                    self._secure = True
                    if DEBUG:
                        print("connected using unix_socket")
                else:
                    kwargs = {}
                    if self.bind_address is not None:
                        kwargs["source_address"] = (self.bind_address, 0)
                    while True:
                        try:
>                           sock = socket.create_connection(
                                (self.host, self.port), self.connect_timeout, **kwargs
                            )

.../local/lib/python3.13.............../site-packages/pymysql/connections.py:649: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../local/lib/python3.13/socket.py:864: in create_connection
    raise exceptions[0]
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

address = ('localhost', 3306), timeout = 10, source_address = None

    def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT,
                          source_address=None, *, all_errors=False):
        """Connect to *address* and return the socket object.
    
        Convenience function.  Connect to *address* (a 2-tuple ``(host,
        port)``) and return the socket object.  Passing the optional
        *timeout* parameter will set the timeout on the socket instance
        before attempting to connect.  If no *timeout* is supplied, the
        global default timeout setting returned by :func:`getdefaulttimeout`
        is used.  If *source_address* is set it must be a tuple of (host, port)
        for the socket to bind as a source address before making the connection.
        A host of '' or port 0 tells the OS to use the default. When a connection
        cannot be created, raises the last error if *all_errors* is False,
        and an ExceptionGroup of all errors if *all_errors* is True.
        """
    
        host, port = address
        exceptions = []
        for res in getaddrinfo(host, port, 0, SOCK_STREAM):
            af, socktype, proto, canonname, sa = res
            sock = None
            try:
                sock = socket(af, socktype, proto)
                if timeout is not _GLOBAL_DEFAULT_TIMEOUT:
                    sock.settimeout(timeout)
                if source_address:
                    sock.bind(source_address)
>               sock.connect(sa)
E               ConnectionRefusedError: [Errno 111] Connection refused

.../local/lib/python3.13/socket.py:849: ConnectionRefusedError

During handling of the above exception, another exception occurred:

self = <sqlalchemy.engine.base.Connection object at 0x7efc7ec45be0>
engine = Engine(mysql+pymysql://root:***@localhost:3306/microservice)
connection = None, _has_events = None, _allow_revalidate = True
_allow_autobegin = True

    def __init__(
        self,
        engine: Engine,
        connection: Optional[PoolProxiedConnection] = None,
        _has_events: Optional[bool] = None,
        _allow_revalidate: bool = True,
        _allow_autobegin: bool = True,
    ):
        """Construct a new Connection."""
        self.engine = engine
        self.dialect = dialect = engine.dialect
    
        if connection is None:
            try:
>               self._dbapi_connection = engine.raw_connection()

.../local/lib/python3.13.../sqlalchemy/engine/base.py:146: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../local/lib/python3.13.../sqlalchemy/engine/base.py:3298: in raw_connection
    return self.pool.connect()
.../local/lib/python3.13.../sqlalchemy/pool/base.py:449: in connect
    return _ConnectionFairy._checkout(self)
.../local/lib/python3.13.../sqlalchemy/pool/base.py:1264: in _checkout
    fairy = _ConnectionRecord.checkout(pool)
.../local/lib/python3.13.../sqlalchemy/pool/base.py:713: in checkout
    rec = pool._do_get()
.../local/lib/python3.13.../sqlalchemy/pool/impl.py:308: in _do_get
    return self._create_connection()
.../local/lib/python3.13.../sqlalchemy/pool/base.py:390: in _create_connection
    return _ConnectionRecord(self)
.../local/lib/python3.13.../sqlalchemy/pool/base.py:675: in __init__
    self.__connect()
.../local/lib/python3.13.../sqlalchemy/pool/base.py:901: in __connect
    with util.safe_reraise():
.../local/lib/python3.13.../sqlalchemy/util/langhelpers.py:146: in __exit__
    raise exc_value.with_traceback(exc_tb)
.../local/lib/python3.13.../sqlalchemy/pool/base.py:897: in __connect
    self.dbapi_connection = connection = pool._invoke_creator(self)
.../local/lib/python3.13.../sqlalchemy/engine/create.py:646: in connect
    return dialect.connect(*cargs, **cparams)
.../local/lib/python3.13.../sqlalchemy/engine/default.py:622: in connect
    return self.loaded_dbapi.connect(*cargs, **cparams)
.../local/lib/python3.13.............../site-packages/pymysql/connections.py:361: in __init__
    self.connect()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <pymysql.connections.Connection object at 0x7efc7ec45d30>, sock = None

    def connect(self, sock=None):
        self._closed = False
        try:
            if sock is None:
                if self.unix_socket:
                    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
                    sock.settimeout(self.connect_timeout)
                    sock.connect(self.unix_socket)
                    self.host_info = "Localhost via UNIX socket"
                    self._secure = True
                    if DEBUG:
                        print("connected using unix_socket")
                else:
                    kwargs = {}
                    if self.bind_address is not None:
                        kwargs["source_address"] = (self.bind_address, 0)
                    while True:
                        try:
                            sock = socket.create_connection(
                                (self.host, self.port), self.connect_timeout, **kwargs
                            )
                            break
                        except OSError as e:
                            if e.errno == errno.EINTR:
                                continue
                            raise
                    self.host_info = "socket %s:%d" % (self.host, self.port)
                    if DEBUG:
                        print("connected using socket")
                    sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
                    sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
                sock.settimeout(None)
    
            self._sock = sock
            self._rfile = sock.makefile("rb")
            self._next_seq_id = 0
    
            self._get_server_information()
            self._request_authentication()
    
            # Send "SET NAMES" query on init for:
            # - Ensure charaset (and collation) is set to the server.
            #   - collation_id in handshake packet may be ignored.
            # - If collation is not specified, we don't know what is server's
            #   default collation for the charset. For example, default collation
            #   of utf8mb4 is:
            #   - MySQL 5.7, MariaDB 10.x: utf8mb4_general_ci
            #   - MySQL 8.0: utf8mb4_0900_ai_ci
            #
            # Reference:
            # - https://github..../PyMySQL/issues/1092
            # - https://github..../wagtail/issues/9477
            # - https://zenn..../methane/articles/2023-mysql-collation (Japanese)
            self.set_character_set(self.charset, self.collation)
    
            if self.sql_mode is not None:
                c = self.cursor()
                c.execute("SET sql_mode=%s", (self.sql_mode,))
                c.close()
    
            if self.init_command is not None:
                c = self.cursor()
                c.execute(self.init_command)
                c.close()
    
            if self.autocommit_mode is not None:
                self.autocommit(self.autocommit_mode)
        except BaseException as e:
            self._rfile = None
            if sock is not None:
                try:
                    sock.close()
                except:  # noqa
                    pass
    
            if isinstance(e, (OSError, IOError)):
                exc = err.OperationalError(
                    CR.CR_CONN_HOST_ERROR,
                    f"Can't connect to MySQL server on {self.host!r} ({e})",
                )
                # Keep original exception and traceback to investigate error.
                exc.original_exception = e
                exc.traceback = traceback.format_exc()
                if DEBUG:
                    print(exc.traceback)
>               raise exc
E               pymysql.err.OperationalError: (2003, "Can't connect to MySQL server on 'localhost' ([Errno 111] Connection refused)")

.../local/lib/python3.13.............../site-packages/pymysql/connections.py:716: OperationalError

The above exception was the direct cause of the following exception:

    @pytest.fixture(scope="session", autouse=True)
    def apply_migrations():
        base_dir = os.path.dirname(os.path.dirname(__file__))
        alembic_cfg = Config(os.path.join(base_dir, "alembic.ini"))
>       command.upgrade(alembic_cfg, "head")

tests/conftest.py:11: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../local/lib/python3.13.../site-packages/alembic/command.py:406: in upgrade
    script.run_env()
.../local/lib/python3.13.../alembic/script/base.py:586: in run_env
    util.load_python_file(self.dir, "env.py")
.../local/lib/python3.13.../alembic/util/pyfiles.py:95: in load_python_file
    module = load_module_py(module_id, path)
.../local/lib/python3.13.../alembic/util/pyfiles.py:113: in load_module_py
    spec.loader.exec_module(module)  # type: ignore
alembic/env.py:62: in <module>
    run_migrations_online()
alembic/env.py:50: in run_migrations_online
    with connectable.connect() as connection:
.../local/lib/python3.13.../sqlalchemy/engine/base.py:3274: in connect
    return self._connection_cls(self)
.../local/lib/python3.13.../sqlalchemy/engine/base.py:148: in __init__
    Connection._handle_dbapi_exception_noconnection(
.../local/lib/python3.13.../sqlalchemy/engine/base.py:2439: in _handle_dbapi_exception_noconnection
    raise sqlalchemy_exception.with_traceback(exc_info[2]) from e
.../local/lib/python3.13.../sqlalchemy/engine/base.py:146: in __init__
    self._dbapi_connection = engine.raw_connection()
.../local/lib/python3.13.../sqlalchemy/engine/base.py:3298: in raw_connection
    return self.pool.connect()
.../local/lib/python3.13.../sqlalchemy/pool/base.py:449: in connect
    return _ConnectionFairy._checkout(self)
.../local/lib/python3.13.../sqlalchemy/pool/base.py:1264: in _checkout
    fairy = _ConnectionRecord.checkout(pool)
.../local/lib/python3.13.../sqlalchemy/pool/base.py:713: in checkout
    rec = pool._do_get()
.../local/lib/python3.13.../sqlalchemy/pool/impl.py:308: in _do_get
    return self._create_connection()
.../local/lib/python3.13.../sqlalchemy/pool/base.py:390: in _create_connection
    return _ConnectionRecord(self)
.../local/lib/python3.13.../sqlalchemy/pool/base.py:675: in __init__
    self.__connect()
.../local/lib/python3.13.../sqlalchemy/pool/base.py:901: in __connect
    with util.safe_reraise():
.../local/lib/python3.13.../sqlalchemy/util/langhelpers.py:146: in __exit__
    raise exc_value.with_traceback(exc_tb)
.../local/lib/python3.13.../sqlalchemy/pool/base.py:897: in __connect
    self.dbapi_connection = connection = pool._invoke_creator(self)
.../local/lib/python3.13.../sqlalchemy/engine/create.py:646: in connect
    return dialect.connect(*cargs, **cparams)
.../local/lib/python3.13.../sqlalchemy/engine/default.py:622: in connect
    return self.loaded_dbapi.connect(*cargs, **cparams)
.../local/lib/python3.13.............../site-packages/pymysql/connections.py:361: in __init__
    self.connect()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <pymysql.connections.Connection object at 0x7efc7ec45d30>, sock = None

    def connect(self, sock=None):
        self._closed = False
        try:
            if sock is None:
                if self.unix_socket:
                    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
                    sock.settimeout(self.connect_timeout)
                    sock.connect(self.unix_socket)
                    self.host_info = "Localhost via UNIX socket"
                    self._secure = True
                    if DEBUG:
                        print("connected using unix_socket")
                else:
                    kwargs = {}
                    if self.bind_address is not None:
                        kwargs["source_address"] = (self.bind_address, 0)
                    while True:
                        try:
                            sock = socket.create_connection(
                                (self.host, self.port), self.connect_timeout, **kwargs
                            )
                            break
                        except OSError as e:
                            if e.errno == errno.EINTR:
                                continue
                            raise
                    self.host_info = "socket %s:%d" % (self.host, self.port)
                    if DEBUG:
                        print("connected using socket")
                    sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
                    sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
                sock.settimeout(None)
    
            self._sock = sock
            self._rfile = sock.makefile("rb")
            self._next_seq_id = 0
    
            self._get_server_information()
            self._request_authentication()
    
            # Send "SET NAMES" query on init for:
            # - Ensure charaset (and collation) is set to the server.
            #   - collation_id in handshake packet may be ignored.
            # - If collation is not specified, we don't know what is server's
            #   default collation for the charset. For example, default collation
            #   of utf8mb4 is:
            #   - MySQL 5.7, MariaDB 10.x: utf8mb4_general_ci
            #   - MySQL 8.0: utf8mb4_0900_ai_ci
            #
            # Reference:
            # - https://github..../PyMySQL/issues/1092
            # - https://github..../wagtail/issues/9477
            # - https://zenn..../methane/articles/2023-mysql-collation (Japanese)
            self.set_character_set(self.charset, self.collation)
    
            if self.sql_mode is not None:
                c = self.cursor()
                c.execute("SET sql_mode=%s", (self.sql_mode,))
                c.close()
    
            if self.init_command is not None:
                c = self.cursor()
                c.execute(self.init_command)
                c.close()
    
            if self.autocommit_mode is not None:
                self.autocommit(self.autocommit_mode)
        except BaseException as e:
            self._rfile = None
            if sock is not None:
                try:
                    sock.close()
                except:  # noqa
                    pass
    
            if isinstance(e, (OSError, IOError)):
                exc = err.OperationalError(
                    CR.CR_CONN_HOST_ERROR,
                    f"Can't connect to MySQL server on {self.host!r} ({e})",
                )
                # Keep original exception and traceback to investigate error.
                exc.original_exception = e
                exc.traceback = traceback.format_exc()
                if DEBUG:
                    print(exc.traceback)
>               raise exc
E               sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (2003, "Can't connect to MySQL server on 'localhost' ([Errno 111] Connection refused)")
E               (Background on this error at: https://sqlalche..../e/20/e3q8)

.../local/lib/python3.13.............../site-packages/pymysql/connections.py:716: OperationalError
tests.unit.test_main::test_upload_invalid_event
Stack Traces | 0.001s run time
self = <pymysql.connections.Connection object at 0x7efc7ec45d30>, sock = None

    def connect(self, sock=None):
        self._closed = False
        try:
            if sock is None:
                if self.unix_socket:
                    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
                    sock.settimeout(self.connect_timeout)
                    sock.connect(self.unix_socket)
                    self.host_info = "Localhost via UNIX socket"
                    self._secure = True
                    if DEBUG:
                        print("connected using unix_socket")
                else:
                    kwargs = {}
                    if self.bind_address is not None:
                        kwargs["source_address"] = (self.bind_address, 0)
                    while True:
                        try:
>                           sock = socket.create_connection(
                                (self.host, self.port), self.connect_timeout, **kwargs
                            )

.../local/lib/python3.13.............../site-packages/pymysql/connections.py:649: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../local/lib/python3.13/socket.py:864: in create_connection
    raise exceptions[0]
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

address = ('localhost', 3306), timeout = 10, source_address = None

    def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT,
                          source_address=None, *, all_errors=False):
        """Connect to *address* and return the socket object.
    
        Convenience function.  Connect to *address* (a 2-tuple ``(host,
        port)``) and return the socket object.  Passing the optional
        *timeout* parameter will set the timeout on the socket instance
        before attempting to connect.  If no *timeout* is supplied, the
        global default timeout setting returned by :func:`getdefaulttimeout`
        is used.  If *source_address* is set it must be a tuple of (host, port)
        for the socket to bind as a source address before making the connection.
        A host of '' or port 0 tells the OS to use the default. When a connection
        cannot be created, raises the last error if *all_errors* is False,
        and an ExceptionGroup of all errors if *all_errors* is True.
        """
    
        host, port = address
        exceptions = []
        for res in getaddrinfo(host, port, 0, SOCK_STREAM):
            af, socktype, proto, canonname, sa = res
            sock = None
            try:
                sock = socket(af, socktype, proto)
                if timeout is not _GLOBAL_DEFAULT_TIMEOUT:
                    sock.settimeout(timeout)
                if source_address:
                    sock.bind(source_address)
>               sock.connect(sa)
E               ConnectionRefusedError: [Errno 111] Connection refused

.../local/lib/python3.13/socket.py:849: ConnectionRefusedError

During handling of the above exception, another exception occurred:

self = <sqlalchemy.engine.base.Connection object at 0x7efc7ec45be0>
engine = Engine(mysql+pymysql://root:***@localhost:3306/microservice)
connection = None, _has_events = None, _allow_revalidate = True
_allow_autobegin = True

    def __init__(
        self,
        engine: Engine,
        connection: Optional[PoolProxiedConnection] = None,
        _has_events: Optional[bool] = None,
        _allow_revalidate: bool = True,
        _allow_autobegin: bool = True,
    ):
        """Construct a new Connection."""
        self.engine = engine
        self.dialect = dialect = engine.dialect
    
        if connection is None:
            try:
>               self._dbapi_connection = engine.raw_connection()

.../local/lib/python3.13.../sqlalchemy/engine/base.py:146: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../local/lib/python3.13.../sqlalchemy/engine/base.py:3298: in raw_connection
    return self.pool.connect()
.../local/lib/python3.13.../sqlalchemy/pool/base.py:449: in connect
    return _ConnectionFairy._checkout(self)
.../local/lib/python3.13.../sqlalchemy/pool/base.py:1264: in _checkout
    fairy = _ConnectionRecord.checkout(pool)
.../local/lib/python3.13.../sqlalchemy/pool/base.py:713: in checkout
    rec = pool._do_get()
.../local/lib/python3.13.../sqlalchemy/pool/impl.py:308: in _do_get
    return self._create_connection()
.../local/lib/python3.13.../sqlalchemy/pool/base.py:390: in _create_connection
    return _ConnectionRecord(self)
.../local/lib/python3.13.../sqlalchemy/pool/base.py:675: in __init__
    self.__connect()
.../local/lib/python3.13.../sqlalchemy/pool/base.py:901: in __connect
    with util.safe_reraise():
.../local/lib/python3.13.../sqlalchemy/util/langhelpers.py:146: in __exit__
    raise exc_value.with_traceback(exc_tb)
.../local/lib/python3.13.../sqlalchemy/pool/base.py:897: in __connect
    self.dbapi_connection = connection = pool._invoke_creator(self)
.../local/lib/python3.13.../sqlalchemy/engine/create.py:646: in connect
    return dialect.connect(*cargs, **cparams)
.../local/lib/python3.13.../sqlalchemy/engine/default.py:622: in connect
    return self.loaded_dbapi.connect(*cargs, **cparams)
.../local/lib/python3.13.............../site-packages/pymysql/connections.py:361: in __init__
    self.connect()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <pymysql.connections.Connection object at 0x7efc7ec45d30>, sock = None

    def connect(self, sock=None):
        self._closed = False
        try:
            if sock is None:
                if self.unix_socket:
                    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
                    sock.settimeout(self.connect_timeout)
                    sock.connect(self.unix_socket)
                    self.host_info = "Localhost via UNIX socket"
                    self._secure = True
                    if DEBUG:
                        print("connected using unix_socket")
                else:
                    kwargs = {}
                    if self.bind_address is not None:
                        kwargs["source_address"] = (self.bind_address, 0)
                    while True:
                        try:
                            sock = socket.create_connection(
                                (self.host, self.port), self.connect_timeout, **kwargs
                            )
                            break
                        except OSError as e:
                            if e.errno == errno.EINTR:
                                continue
                            raise
                    self.host_info = "socket %s:%d" % (self.host, self.port)
                    if DEBUG:
                        print("connected using socket")
                    sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
                    sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
                sock.settimeout(None)
    
            self._sock = sock
            self._rfile = sock.makefile("rb")
            self._next_seq_id = 0
    
            self._get_server_information()
            self._request_authentication()
    
            # Send "SET NAMES" query on init for:
            # - Ensure charaset (and collation) is set to the server.
            #   - collation_id in handshake packet may be ignored.
            # - If collation is not specified, we don't know what is server's
            #   default collation for the charset. For example, default collation
            #   of utf8mb4 is:
            #   - MySQL 5.7, MariaDB 10.x: utf8mb4_general_ci
            #   - MySQL 8.0: utf8mb4_0900_ai_ci
            #
            # Reference:
            # - https://github..../PyMySQL/issues/1092
            # - https://github..../wagtail/issues/9477
            # - https://zenn..../methane/articles/2023-mysql-collation (Japanese)
            self.set_character_set(self.charset, self.collation)
    
            if self.sql_mode is not None:
                c = self.cursor()
                c.execute("SET sql_mode=%s", (self.sql_mode,))
                c.close()
    
            if self.init_command is not None:
                c = self.cursor()
                c.execute(self.init_command)
                c.close()
    
            if self.autocommit_mode is not None:
                self.autocommit(self.autocommit_mode)
        except BaseException as e:
            self._rfile = None
            if sock is not None:
                try:
                    sock.close()
                except:  # noqa
                    pass
    
            if isinstance(e, (OSError, IOError)):
                exc = err.OperationalError(
                    CR.CR_CONN_HOST_ERROR,
                    f"Can't connect to MySQL server on {self.host!r} ({e})",
                )
                # Keep original exception and traceback to investigate error.
                exc.original_exception = e
                exc.traceback = traceback.format_exc()
                if DEBUG:
                    print(exc.traceback)
>               raise exc
E               pymysql.err.OperationalError: (2003, "Can't connect to MySQL server on 'localhost' ([Errno 111] Connection refused)")

.../local/lib/python3.13.............../site-packages/pymysql/connections.py:716: OperationalError

The above exception was the direct cause of the following exception:

    @pytest.fixture(scope="session", autouse=True)
    def apply_migrations():
        base_dir = os.path.dirname(os.path.dirname(__file__))
        alembic_cfg = Config(os.path.join(base_dir, "alembic.ini"))
>       command.upgrade(alembic_cfg, "head")

tests/conftest.py:11: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../local/lib/python3.13.../site-packages/alembic/command.py:406: in upgrade
    script.run_env()
.../local/lib/python3.13.../alembic/script/base.py:586: in run_env
    util.load_python_file(self.dir, "env.py")
.../local/lib/python3.13.../alembic/util/pyfiles.py:95: in load_python_file
    module = load_module_py(module_id, path)
.../local/lib/python3.13.../alembic/util/pyfiles.py:113: in load_module_py
    spec.loader.exec_module(module)  # type: ignore
alembic/env.py:62: in <module>
    run_migrations_online()
alembic/env.py:50: in run_migrations_online
    with connectable.connect() as connection:
.../local/lib/python3.13.../sqlalchemy/engine/base.py:3274: in connect
    return self._connection_cls(self)
.../local/lib/python3.13.../sqlalchemy/engine/base.py:148: in __init__
    Connection._handle_dbapi_exception_noconnection(
.../local/lib/python3.13.../sqlalchemy/engine/base.py:2439: in _handle_dbapi_exception_noconnection
    raise sqlalchemy_exception.with_traceback(exc_info[2]) from e
.../local/lib/python3.13.../sqlalchemy/engine/base.py:146: in __init__
    self._dbapi_connection = engine.raw_connection()
.../local/lib/python3.13.../sqlalchemy/engine/base.py:3298: in raw_connection
    return self.pool.connect()
.../local/lib/python3.13.../sqlalchemy/pool/base.py:449: in connect
    return _ConnectionFairy._checkout(self)
.../local/lib/python3.13.../sqlalchemy/pool/base.py:1264: in _checkout
    fairy = _ConnectionRecord.checkout(pool)
.../local/lib/python3.13.../sqlalchemy/pool/base.py:713: in checkout
    rec = pool._do_get()
.../local/lib/python3.13.../sqlalchemy/pool/impl.py:308: in _do_get
    return self._create_connection()
.../local/lib/python3.13.../sqlalchemy/pool/base.py:390: in _create_connection
    return _ConnectionRecord(self)
.../local/lib/python3.13.../sqlalchemy/pool/base.py:675: in __init__
    self.__connect()
.../local/lib/python3.13.../sqlalchemy/pool/base.py:901: in __connect
    with util.safe_reraise():
.../local/lib/python3.13.../sqlalchemy/util/langhelpers.py:146: in __exit__
    raise exc_value.with_traceback(exc_tb)
.../local/lib/python3.13.../sqlalchemy/pool/base.py:897: in __connect
    self.dbapi_connection = connection = pool._invoke_creator(self)
.../local/lib/python3.13.../sqlalchemy/engine/create.py:646: in connect
    return dialect.connect(*cargs, **cparams)
.../local/lib/python3.13.../sqlalchemy/engine/default.py:622: in connect
    return self.loaded_dbapi.connect(*cargs, **cparams)
.../local/lib/python3.13.............../site-packages/pymysql/connections.py:361: in __init__
    self.connect()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <pymysql.connections.Connection object at 0x7efc7ec45d30>, sock = None

    def connect(self, sock=None):
        self._closed = False
        try:
            if sock is None:
                if self.unix_socket:
                    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
                    sock.settimeout(self.connect_timeout)
                    sock.connect(self.unix_socket)
                    self.host_info = "Localhost via UNIX socket"
                    self._secure = True
                    if DEBUG:
                        print("connected using unix_socket")
                else:
                    kwargs = {}
                    if self.bind_address is not None:
                        kwargs["source_address"] = (self.bind_address, 0)
                    while True:
                        try:
                            sock = socket.create_connection(
                                (self.host, self.port), self.connect_timeout, **kwargs
                            )
                            break
                        except OSError as e:
                            if e.errno == errno.EINTR:
                                continue
                            raise
                    self.host_info = "socket %s:%d" % (self.host, self.port)
                    if DEBUG:
                        print("connected using socket")
                    sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
                    sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
                sock.settimeout(None)
    
            self._sock = sock
            self._rfile = sock.makefile("rb")
            self._next_seq_id = 0
    
            self._get_server_information()
            self._request_authentication()
    
            # Send "SET NAMES" query on init for:
            # - Ensure charaset (and collation) is set to the server.
            #   - collation_id in handshake packet may be ignored.
            # - If collation is not specified, we don't know what is server's
            #   default collation for the charset. For example, default collation
            #   of utf8mb4 is:
            #   - MySQL 5.7, MariaDB 10.x: utf8mb4_general_ci
            #   - MySQL 8.0: utf8mb4_0900_ai_ci
            #
            # Reference:
            # - https://github..../PyMySQL/issues/1092
            # - https://github..../wagtail/issues/9477
            # - https://zenn..../methane/articles/2023-mysql-collation (Japanese)
            self.set_character_set(self.charset, self.collation)
    
            if self.sql_mode is not None:
                c = self.cursor()
                c.execute("SET sql_mode=%s", (self.sql_mode,))
                c.close()
    
            if self.init_command is not None:
                c = self.cursor()
                c.execute(self.init_command)
                c.close()
    
            if self.autocommit_mode is not None:
                self.autocommit(self.autocommit_mode)
        except BaseException as e:
            self._rfile = None
            if sock is not None:
                try:
                    sock.close()
                except:  # noqa
                    pass
    
            if isinstance(e, (OSError, IOError)):
                exc = err.OperationalError(
                    CR.CR_CONN_HOST_ERROR,
                    f"Can't connect to MySQL server on {self.host!r} ({e})",
                )
                # Keep original exception and traceback to investigate error.
                exc.original_exception = e
                exc.traceback = traceback.format_exc()
                if DEBUG:
                    print(exc.traceback)
>               raise exc
E               sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (2003, "Can't connect to MySQL server on 'localhost' ([Errno 111] Connection refused)")
E               (Background on this error at: https://sqlalche..../e/20/e3q8)

.../local/lib/python3.13.............../site-packages/pymysql/connections.py:716: OperationalError

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@24Victor 24Victor requested a review from a team as a code owner March 21, 2025 08:54
@github-actions github-actions bot added the area/tests Categorizes issue or PR as related to tests. label Mar 21, 2025
@github-actions github-actions bot removed the area/tests Categorizes issue or PR as related to tests. label Mar 24, 2025
@24Victor 24Victor merged commit 2a6f230 into main Mar 24, 2025
8 checks passed
@24Victor 24Victor deleted the feat/endpoint-sensors branch March 24, 2025 15:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/feature Categorizes issue or PR as related to a new feature.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant