diff --git a/src/netius/base/agent.pyi b/src/netius/base/agent.pyi
new file mode 100644
index 00000000..6b79980b
--- /dev/null
+++ b/src/netius/base/agent.pyi
@@ -0,0 +1,21 @@
+from typing import Any
+
+from .observer import Observable
+from .client import Client
+
+class Agent(Observable):
+ @classmethod
+ def cleanup_s(cls) -> None: ...
+ def cleanup(self, destroy: bool = ...) -> None: ...
+ def destroy(self) -> None: ...
+
+class ClientAgent(Agent):
+ _clients: dict[int, Client]
+
+ @classmethod
+ def cleanup_s(cls) -> None: ...
+ @classmethod
+ def get_client_s(cls, *args, **kwargs) -> Client: ...
+
+class ServerAgent(Agent):
+ pass
diff --git a/src/netius/base/client.pyi b/src/netius/base/client.pyi
new file mode 100644
index 00000000..1de07278
--- /dev/null
+++ b/src/netius/base/client.pyi
@@ -0,0 +1,32 @@
+from typing import Any
+
+from .common import Base, BaseThread
+
+class Client(Base):
+ _client: "Client | None" = None
+
+ def __init__(self, thread: bool = ..., daemon: bool = ..., *args, **kwargs): ...
+ @classmethod
+ def get_client_s(cls, *args, **kwargs) -> "Client": ...
+ @classmethod
+ def cleanup_s(cls) -> None: ...
+ def ensure_loop(self, env: bool = ...) -> None: ...
+ def join(self, timeout: float | None = ...) -> None: ...
+ def connect(
+ self,
+ host: str,
+ port: int,
+ ssl: bool = ...,
+ key_file: str | None = ...,
+ cer_file: str | None = ...,
+ ca_file: str | None = ...,
+ ca_root: bool = ...,
+ ssl_verify: bool = ...,
+ family: int = ...,
+ type: int = ...,
+ ensure_loop: bool = ...,
+ env: bool = ...,
+ ) -> bool: ...
+
+class DatagramClient(Client):
+ def __init__(self, *args, **kwargs): ...
diff --git a/src/netius/base/common.pyi b/src/netius/base/common.pyi
new file mode 100644
index 00000000..25df93cc
--- /dev/null
+++ b/src/netius/base/common.pyi
@@ -0,0 +1,48 @@
+from typing import Any, Callable, Iterable
+import threading
+
+class BaseThread(threading.Thread):
+ def __init__(
+ self, owner: Any | None = ..., daemon: bool = ..., *args, **kwargs
+ ): ...
+ def run(self) -> None: ...
+
+def new_loop_main(
+ factory: type | None = ..., env: bool = ..., _compat: bool | None = ..., **kwargs
+) -> Any: ...
+def new_loop_asyncio(**kwargs) -> Any | None: ...
+def new_loop(
+ factory: type | None = ...,
+ _compat: bool | None = ...,
+ asyncio: bool | None = ...,
+ **kwargs
+) -> Any: ...
+def ensure_main(factory: type | None = ..., env: bool = ..., **kwargs) -> None: ...
+def ensure_asyncio(**kwargs) -> Any | None: ...
+def ensure_loop(
+ factory: type | None = ..., asyncio: bool | None = ..., **kwargs
+) -> None: ...
+def get_main(factory: type | None = ..., ensure: bool = ..., **kwargs) -> Any: ...
+def get_loop(
+ factory: type | None = ...,
+ ensure: bool = ...,
+ _compat: bool | None = ...,
+ asyncio: bool | None = ...,
+ **kwargs
+) -> Any: ...
+def get_event_loop(*args, **kwargs) -> Any: ...
+def stop_loop(compat: bool = ..., asyncio: bool = ...) -> None: ...
+def compat_loop(loop: Any) -> Any: ...
+def get_poll() -> Any: ...
+def build_future(compat: bool = ..., asyncio: bool = ...) -> Any: ...
+def ensure(
+ coroutine: Callable[..., Any],
+ args: Iterable[Any] | None = ...,
+ kwargs: dict | None = ...,
+ thread: bool | None = ...,
+) -> Any: ...
+def ensure_pool(
+ coroutine: Callable[..., Any],
+ args: Iterable[Any] | None = ...,
+ kwargs: dict | None = ...,
+) -> Any: ...
diff --git a/src/netius/base/container.pyi b/src/netius/base/container.pyi
new file mode 100644
index 00000000..25f36675
--- /dev/null
+++ b/src/netius/base/container.pyi
@@ -0,0 +1,35 @@
+from typing import Any
+
+from .common import Base
+from .server import StreamServer
+
+class Container(Base):
+ owner: Base | None
+ bases: list[Base]
+
+ def __init__(self, *args, **kwargs): ...
+ def start(self, owner: Base) -> None: ...
+ def cleanup(self) -> None: ...
+ def loop(self) -> None: ...
+ def ticks(self) -> None: ...
+ def connections_dict(self, full: bool = ...) -> dict[str, Any]: ...
+ def connection_dict(self, id: str, full: bool = ...) -> dict[str, Any] | None: ...
+ def on_start(self) -> None: ...
+ def on_stop(self) -> None: ...
+ def add_base(self, base: Base) -> None: ...
+ def remove_base(self, base: Base) -> None: ...
+ def start_base(self, base: Base) -> None: ...
+ def start_all(self) -> None: ...
+ def apply_all(self) -> None: ...
+ def apply_base(self, base: Base) -> None: ...
+ def call_all(self, name: str, *args, **kwargs) -> None: ...
+ def trigger_all(self, name: str, *args, **kwargs) -> None: ...
+
+class ContainerServer(StreamServer):
+ container: Container
+
+ def __init__(self, *args, **kwargs): ...
+ def start(self) -> None: ...
+ def stop(self) -> None: ...
+ def cleanup(self) -> None: ...
+ def add_base(self, base: Base) -> None: ...
diff --git a/src/netius/base/observer.pyi b/src/netius/base/observer.pyi
new file mode 100644
index 00000000..42ef5955
--- /dev/null
+++ b/src/netius/base/observer.pyi
@@ -0,0 +1,14 @@
+from typing import Any, Callable
+
+class Observable:
+ events: dict[str, list[Callable[..., Any]]]
+
+ def __init__(self, *args, **kwargs): ...
+ def build(self) -> None: ...
+ def destroy(self) -> None: ...
+ def bind(
+ self, name: str, method: Callable[..., Any], oneshot: bool = ...
+ ) -> None: ...
+ def unbind(self, name: str, method: Callable[..., Any] | None = ...) -> None: ...
+ def unbind_all(self) -> None: ...
+ def trigger(self, name: str, *args, **kwargs) -> None: ...
diff --git a/src/netius/base/poll.pyi b/src/netius/base/poll.pyi
new file mode 100644
index 00000000..ceed1053
--- /dev/null
+++ b/src/netius/base/poll.pyi
@@ -0,0 +1,86 @@
+from typing import Any
+
+class Poll:
+ timeout: float
+
+ def __init__(self): ...
+ @classmethod
+ def name(cls) -> str: ...
+ @classmethod
+ def test(cls) -> bool: ...
+ def open(self, timeout: float = ...) -> None: ...
+ def close(self) -> None: ...
+ def poll(self) -> tuple[list[Any], list[Any], list[Any]]: ...
+ def poll_owner(self) -> dict[Any, tuple[list[Any], list[Any], list[Any]]]: ...
+ def is_open(self) -> bool: ...
+ def is_edge(self) -> bool: ...
+ def is_empty(self) -> bool: ...
+ def sub_all(self, socket: Any, owner: Any | None = ...) -> None: ...
+ def unsub_all(self, socket: Any) -> None: ...
+ def is_sub_read(self, socket: Any) -> bool: ...
+ def is_sub_write(self, socket: Any) -> bool: ...
+ def is_sub_error(self, socket: Any) -> bool: ...
+ def sub_read(self, socket: Any, owner: Any | None = ...) -> None: ...
+ def sub_write(self, socket: Any, owner: Any | None = ...) -> None: ...
+ def sub_error(self, socket: Any, owner: Any | None = ...) -> None: ...
+ def unsub_read(self, socket: Any) -> None: ...
+ def unsub_write(self, socket: Any) -> None: ...
+ def unsub_error(self, socket: Any) -> None: ...
+
+class EpollPoll(Poll):
+ def __init__(self, *args, **kwargs): ...
+ @classmethod
+ def test(cls) -> bool: ...
+ def open(self, timeout: float = ...) -> None: ...
+ def close(self) -> None: ...
+ def poll(self) -> tuple[list[Any], list[Any], list[Any]]: ...
+ def is_edge(self) -> bool: ...
+ def sub_read(self, socket: Any, owner: Any | None = ...) -> None: ...
+ def sub_write(self, socket: Any, owner: Any | None = ...) -> None: ...
+ def sub_error(self, socket: Any, owner: Any | None = ...) -> None: ...
+ def unsub_read(self, socket: Any) -> None: ...
+ def unsub_write(self, socket: Any) -> None: ...
+ def unsub_error(self, socket: Any) -> None: ...
+
+class KqueuePoll(Poll):
+ def __init__(self, *args, **kwargs): ...
+ @classmethod
+ def test(cls) -> bool: ...
+ def open(self, timeout: float = ...) -> None: ...
+ def close(self) -> None: ...
+ def poll(self) -> tuple[list[Any], list[Any], list[Any]]: ...
+ def is_edge(self) -> bool: ...
+ def sub_read(self, socket: Any, owner: Any | None = ...) -> None: ...
+ def sub_write(self, socket: Any, owner: Any | None = ...) -> None: ...
+ def sub_error(self, socket: Any, owner: Any | None = ...) -> None: ...
+ def unsub_read(self, socket: Any) -> None: ...
+ def unsub_write(self, socket: Any) -> None: ...
+ def unsub_error(self, socket: Any) -> None: ...
+
+class PollPoll(Poll):
+ def __init__(self, *args, **kwargs): ...
+ @classmethod
+ def test(cls) -> bool: ...
+ def open(self, timeout: float = ...) -> None: ...
+ def close(self) -> None: ...
+ def poll(self) -> tuple[list[Any], list[Any], list[Any]]: ...
+ def is_edge(self) -> bool: ...
+ def sub_read(self, socket: Any, owner: Any | None = ...) -> None: ...
+ def sub_write(self, socket: Any, owner: Any | None = ...) -> None: ...
+ def sub_error(self, socket: Any, owner: Any | None = ...) -> None: ...
+ def unsub_read(self, socket: Any) -> None: ...
+ def unsub_write(self, socket: Any) -> None: ...
+ def unsub_error(self, socket: Any) -> None: ...
+
+class SelectPoll(Poll):
+ def __init__(self, *args, **kwargs): ...
+ def open(self, timeout: float = ...) -> None: ...
+ def close(self) -> None: ...
+ def poll(self) -> tuple[list[Any], list[Any], list[Any]]: ...
+ def is_edge(self) -> bool: ...
+ def sub_read(self, socket: Any, owner: Any | None = ...) -> None: ...
+ def sub_write(self, socket: Any, owner: Any | None = ...) -> None: ...
+ def sub_error(self, socket: Any, owner: Any | None = ...) -> None: ...
+ def unsub_read(self, socket: Any) -> None: ...
+ def unsub_write(self, socket: Any) -> None: ...
+ def unsub_error(self, socket: Any) -> None: ...
diff --git a/src/netius/base/server.pyi b/src/netius/base/server.pyi
new file mode 100644
index 00000000..0bfdf644
--- /dev/null
+++ b/src/netius/base/server.pyi
@@ -0,0 +1,48 @@
+from typing import Any, Mapping
+
+from .common import Base
+
+class Server(Base):
+ socket: Any
+ host: str | None
+ port: int | str | None
+ type: int | None
+ ssl: bool
+ key_file: str | None
+ cer_file: str | None
+ ca_file: str | None
+ env: bool
+
+ def __init__(self, *args, **kwargs): ...
+ def welcome(self) -> None: ...
+ def cleanup(self) -> None: ...
+ def info_dict(self, full: bool = ...) -> Mapping[str, Any]: ...
+ def serve(
+ self,
+ host: str | None = ...,
+ port: int | str | None = ...,
+ type: int = ...,
+ ipv6: bool = ...,
+ ssl: bool = ...,
+ key_file: str | None = ...,
+ cer_file: str | None = ...,
+ ca_file: str | None = ...,
+ ca_root: bool = ...,
+ ssl_verify: bool = ...,
+ ssl_host: str | None = ...,
+ ssl_fingerprint: str | None = ...,
+ ssl_dump: bool = ...,
+ setuid: int | None = ...,
+ backlog: int = ...,
+ load: bool = ...,
+ start: bool = ...,
+ env: bool = ...,
+ ) -> None: ...
+
+class DatagramServer(Server):
+ def __init__(self, *args, **kwargs): ...
+ def reads(self, reads: list[Any], state: bool = ...) -> None: ...
+ def writes(self, writes: list[Any], state: bool = ...) -> None: ...
+ def errors(self, errors: list[Any], state: bool = ...) -> None: ...
+ def serve(self, type: int = ..., *args, **kwargs) -> None: ...
+ def on_read(self, _socket: Any) -> None: ...
diff --git a/src/netius/base/service.pyi b/src/netius/base/service.pyi
new file mode 100644
index 00000000..a02c38b1
--- /dev/null
+++ b/src/netius/base/service.pyi
@@ -0,0 +1,31 @@
+from typing import Any
+
+from .observer import Observable
+from .transport import Transport
+
+class Service(Observable):
+ owner: Any | None
+ transport: Transport | None
+ socket: Any | None
+ host: str | None
+ port: Any | None
+ ssl: bool
+ receive_buffer_s: int | None
+ send_buffer_s: int | None
+ receive_buffer_c: int | None
+ send_buffer_c: int | None
+
+ def __init__(
+ self,
+ owner: Any | None = ...,
+ transport: Transport | None = ...,
+ socket: Any | None = ...,
+ host: str | None = ...,
+ port: Any | None = ...,
+ ssl: bool = ...,
+ receive_buffer_s: int | None = ...,
+ send_buffer_s: int | None = ...,
+ receive_buffer_c: int | None = ...,
+ send_buffer_c: int | None = ...,
+ ): ...
+ def on_socket_c(self, socket_c: Any, address: Any) -> None: ...
diff --git a/src/netius/base/stream.pyi b/src/netius/base/stream.pyi
new file mode 100644
index 00000000..b3e7f753
--- /dev/null
+++ b/src/netius/base/stream.pyi
@@ -0,0 +1,21 @@
+from typing import Any
+
+from .observer import Observable
+
+OPEN: int
+CLOSED: int
+PENDING: int
+
+class Stream(Observable):
+ status: int
+ owner: Any | None
+ connection: Any | None
+
+ def __init__(self, owner: Any | None = ...): ...
+ def reset(self) -> None: ...
+ def open(self) -> None: ...
+ def close(self) -> None: ...
+ def info_dict(self, full: bool = ...) -> dict[str, Any]: ...
+ def is_open(self) -> bool: ...
+ def is_closed(self) -> bool: ...
+ def is_pending(self) -> bool: ...
diff --git a/src/netius/base/util.pyi b/src/netius/base/util.pyi
new file mode 100644
index 00000000..10fa6e9e
--- /dev/null
+++ b/src/netius/base/util.pyi
@@ -0,0 +1,4 @@
+def camel_to_underscore(camel: str, separator: str = ...) -> str: ...
+def verify(
+ condition: bool, message: str | None = ..., exception: type | None = ...
+) -> None: ...
diff --git a/src/netius/test/base/stubs.py b/src/netius/test/base/stubs.py
new file mode 100644
index 00000000..dc9c2025
--- /dev/null
+++ b/src/netius/test/base/stubs.py
@@ -0,0 +1,74 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Hive Netius System
+# Copyright (c) 2008-2024 Hive Solutions Lda.
+#
+# This file is part of Hive Netius System.
+#
+# Hive Netius System is free software: you can redistribute it and/or modify
+# it under the terms of the Apache License as published by the Apache
+# Foundation, either version 2.0 of the License, or (at your option) any
+# later version.
+#
+# Hive Netius System is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# Apache License for more details.
+#
+# You should have received a copy of the Apache License along with
+# Hive Netius System. If not, see .
+
+__author__ = "João Magalhães "
+""" The author(s) of the module """
+
+__copyright__ = "Copyright (c) 2008-2024 Hive Solutions Lda."
+""" The copyright for the module """
+
+__license__ = "Apache License, Version 2.0"
+""" The license for the module """
+
+import subprocess
+import sys
+import importlib.util
+import unittest
+
+
+class StubsTest(unittest.TestCase):
+ MODULES = [
+ "netius.base.agent",
+ "netius.base.client",
+ "netius.base.common",
+ "netius.base.container",
+ "netius.base.observer",
+ "netius.base.poll",
+ "netius.base.server",
+ "netius.base.service",
+ "netius.base.stream",
+ "netius.base.util",
+ ]
+
+ def _run_stubtest(self, module: str) -> None:
+ result = subprocess.run(
+ [
+ sys.executable,
+ "-m",
+ "mypy.stubtest",
+ module,
+ "--mypy-config-file",
+ "/dev/null",
+ "--ignore-missing-stub",
+ "--allowlist",
+ "/dev/null",
+ ],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ text=True,
+ )
+ self.assertEqual(result.returncode, 0, result.stdout)
+
+ def test_stubtest(self):
+ if importlib.util.find_spec("mypy.stubtest") is None:
+ self.skipTest("mypy is not installed")
+ for module in self.MODULES:
+ self._run_stubtest(module)