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)