From 90337a7e8ccc26e25170c2ca353b7e25de8a6eef Mon Sep 17 00:00:00 2001 From: PerchunPak Date: Sun, 14 May 2023 21:22:57 +0200 Subject: [PATCH] Rename `status_response` to `responses` --- docs/api/basic.rst | 18 +- docs/api/internal.rst | 6 +- .../ping_as_java_and_bedrock_in_one_time.py | 2 +- .../ping_as_java_and_bedrock_in_one_time.rst | 4 +- docs/pages/faq.rst | 2 +- mcstatus/bedrock_status.py | 2 +- mcstatus/motd/__init__.py | 2 +- mcstatus/pinger.py | 2 +- mcstatus/responses.py | 355 ++++++++++++++++++ mcstatus/server.py | 10 +- mcstatus/status_response.py | 345 +---------------- tests/motd/test_motd.py | 2 +- tests/motd/test_transformers.py | 2 +- .../__init__.py | 2 +- .../conftest.py | 2 +- .../test_bedrock.py | 4 +- .../test_java.py | 4 +- .../test_shared.py | 2 +- tests/test_bedrock_status.py | 2 +- 19 files changed, 394 insertions(+), 374 deletions(-) create mode 100644 mcstatus/responses.py rename tests/{status_response => responses}/__init__.py (98%) rename tests/{status_response => responses}/conftest.py (95%) rename tests/{status_response => responses}/test_bedrock.py (93%) rename tests/{status_response => responses}/test_java.py (95%) rename tests/{status_response => responses}/test_shared.py (81%) diff --git a/docs/api/basic.rst b/docs/api/basic.rst index 554e4ff7..7fbe47c0 100644 --- a/docs/api/basic.rst +++ b/docs/api/basic.rst @@ -34,27 +34,27 @@ These are the classes that you get back after making a request. For Java Server *************** -.. module:: mcstatus.status_response +.. module:: mcstatus.responses -.. autoclass:: mcstatus.status_response.JavaStatusResponse() +.. autoclass:: mcstatus.responses.JavaStatusResponse() :members: :undoc-members: :inherited-members: :exclude-members: build -.. autoclass:: mcstatus.status_response.JavaStatusPlayers() +.. autoclass:: mcstatus.responses.JavaStatusPlayers() :members: :undoc-members: :inherited-members: :exclude-members: build -.. autoclass:: mcstatus.status_response.JavaStatusPlayer() +.. autoclass:: mcstatus.responses.JavaStatusPlayer() :members: :undoc-members: :inherited-members: :exclude-members: build -.. autoclass:: mcstatus.status_response.JavaStatusVersion() +.. autoclass:: mcstatus.responses.JavaStatusVersion() :members: :undoc-members: :inherited-members: @@ -144,22 +144,22 @@ For Java Server For Bedrock Servers ******************* -.. module:: mcstatus.status_response +.. module:: mcstatus.responses :noindex: -.. autoclass:: mcstatus.status_response.BedrockStatusResponse() +.. autoclass:: mcstatus.responses.BedrockStatusResponse() :members: :undoc-members: :inherited-members: :exclude-members: build -.. autoclass:: mcstatus.status_response.BedrockStatusPlayers() +.. autoclass:: mcstatus.responses.BedrockStatusPlayers() :members: :undoc-members: :inherited-members: :exclude-members: build -.. autoclass:: mcstatus.status_response.BedrockStatusVersion() +.. autoclass:: mcstatus.responses.BedrockStatusVersion() :members: :undoc-members: :inherited-members: diff --git a/docs/api/internal.rst b/docs/api/internal.rst index cbb29d62..33563390 100644 --- a/docs/api/internal.rst +++ b/docs/api/internal.rst @@ -49,17 +49,17 @@ versions. They are only documented here for linkable reference to them. :undoc-members: :show-inheritance: -.. autoclass:: mcstatus.status_response.BaseStatusResponse +.. autoclass:: mcstatus.responses.BaseStatusResponse :members: :undoc-members: :show-inheritance: -.. autoclass:: mcstatus.status_response.BaseStatusPlayers +.. autoclass:: mcstatus.responses.BaseStatusPlayers :members: :undoc-members: :show-inheritance: -.. autoclass:: mcstatus.status_response.BaseStatusVersion +.. autoclass:: mcstatus.responses.BaseStatusVersion :members: :undoc-members: :show-inheritance: diff --git a/docs/examples/code/ping_as_java_and_bedrock_in_one_time.py b/docs/examples/code/ping_as_java_and_bedrock_in_one_time.py index 1e09d654..16481b14 100644 --- a/docs/examples/code/ping_as_java_and_bedrock_in_one_time.py +++ b/docs/examples/code/ping_as_java_and_bedrock_in_one_time.py @@ -1,7 +1,7 @@ import asyncio from mcstatus import BedrockServer, JavaServer -from mcstatus.status_response import BedrockStatusResponse, JavaStatusResponse +from mcstatus.responses import BedrockStatusResponse, JavaStatusResponse async def status(host: str) -> JavaStatusResponse | BedrockStatusResponse: diff --git a/docs/examples/ping_as_java_and_bedrock_in_one_time.rst b/docs/examples/ping_as_java_and_bedrock_in_one_time.rst index 3c512165..c18fd8ca 100644 --- a/docs/examples/ping_as_java_and_bedrock_in_one_time.rst +++ b/docs/examples/ping_as_java_and_bedrock_in_one_time.rst @@ -5,8 +5,8 @@ You can easily ping a server as a Java server and as a Bedrock server in one tim .. literalinclude:: code/ping_as_java_and_bedrock_in_one_time.py -As you can see in the code, ``status`` function returns :class:`~mcstatus.status_response.JavaStatusResponse` -or :class:`~mcstatus.status_response.BedrockStatusResponse` object. You can use +As you can see in the code, ``status`` function returns :class:`~mcstatus.responses.JavaStatusResponse` +or :class:`~mcstatus.responses.BedrockStatusResponse` object. You can use :func:`isinstance` checks to access attributes that are only in one of the objects. diff --git a/docs/pages/faq.rst b/docs/pages/faq.rst index 636cdff4..e9c49426 100644 --- a/docs/pages/faq.rst +++ b/docs/pages/faq.rst @@ -57,7 +57,7 @@ How to get server image? On Bedrock, only official servers have a server image. There is no way to get or set an icon to a custom server. For Java servers, you can use -:attr:`status.icon ` +:attr:`status.icon ` attribute. It will return `Base64 `_ encoded PNG image, so you can decode it in that way: diff --git a/mcstatus/bedrock_status.py b/mcstatus/bedrock_status.py index d6663893..131866fe 100644 --- a/mcstatus/bedrock_status.py +++ b/mcstatus/bedrock_status.py @@ -8,7 +8,7 @@ import asyncio_dgram from mcstatus.address import Address -from mcstatus.status_response import BedrockStatusResponse +from mcstatus.responses import BedrockStatusResponse # TODO Remove this useless __all__ after 2023-08 __all__ = ("BedrockServerStatus", "BedrockStatusResponse") diff --git a/mcstatus/motd/__init__.py b/mcstatus/motd/__init__.py index 01e90d9b..96b2e5e3 100644 --- a/mcstatus/motd/__init__.py +++ b/mcstatus/motd/__init__.py @@ -11,7 +11,7 @@ if t.TYPE_CHECKING: from typing_extensions import Self - from mcstatus.status_response import RawJavaResponseMotd, RawJavaResponseMotdWhenDict # circular import + from mcstatus.responses import RawJavaResponseMotd, RawJavaResponseMotdWhenDict # circular import else: RawJavaResponseMotdWhenDict = dict diff --git a/mcstatus/pinger.py b/mcstatus/pinger.py index 55c003dd..5f11eb2c 100644 --- a/mcstatus/pinger.py +++ b/mcstatus/pinger.py @@ -7,7 +7,7 @@ from mcstatus.address import Address from mcstatus.protocol.connection import Connection, TCPAsyncSocketConnection, TCPSocketConnection -from mcstatus.status_response import JavaStatusResponse +from mcstatus.responses import JavaStatusResponse if TYPE_CHECKING: from typing_extensions import TypeAlias diff --git a/mcstatus/responses.py b/mcstatus/responses.py new file mode 100644 index 00000000..b3920c1c --- /dev/null +++ b/mcstatus/responses.py @@ -0,0 +1,355 @@ +from __future__ import annotations + +from abc import ABC, abstractmethod +from dataclasses import dataclass +from typing import Any, TYPE_CHECKING + +from mcstatus.motd import Motd + +if TYPE_CHECKING: + from typing_extensions import NotRequired, Self, TypeAlias, TypedDict + + class RawJavaResponsePlayer(TypedDict): + name: str + id: str + + class RawJavaResponsePlayers(TypedDict): + online: int + max: int + sample: NotRequired[list[RawJavaResponsePlayer]] + + class RawJavaResponseVersion(TypedDict): + name: str + protocol: int + + class RawJavaResponseMotdWhenDict(TypedDict, total=False): + text: str # only present if translation is set + translation: str # same to the above field + extra: list[RawJavaResponseMotdWhenDict] + + color: str + bold: bool + strikethrough: bool + italic: bool + underlined: bool + obfuscated: bool + + RawJavaResponseMotd: TypeAlias = "RawJavaResponseMotdWhenDict | list[RawJavaResponseMotdWhenDict] | str" + + class RawJavaResponse(TypedDict): + description: RawJavaResponseMotd + players: RawJavaResponsePlayers + version: RawJavaResponseVersion + favicon: NotRequired[str] + +else: + RawJavaResponsePlayer = dict + RawJavaResponsePlayers = dict + RawJavaResponseVersion = dict + RawJavaResponseMotdWhenDict = dict + RawJavaResponse = dict + +from mcstatus.utils import deprecated + +__all__ = [ + "BaseStatusPlayers", + "BaseStatusResponse", + "BaseStatusVersion", + "BedrockStatusPlayers", + "BedrockStatusResponse", + "BedrockStatusVersion", + "JavaStatusPlayer", + "JavaStatusPlayers", + "JavaStatusResponse", + "JavaStatusVersion", +] + + +@dataclass +class BaseStatusResponse(ABC): + """Class for storing shared data from a status response.""" + + players: BaseStatusPlayers + """The players information.""" + version: BaseStatusVersion + """The version information.""" + motd: Motd + """Message Of The Day. Also known as description. + + .. seealso:: :doc:`/api/motd_parsing`. + """ + latency: float + """Latency between a server and the client (you). In milliseconds.""" + + @property + def description(self) -> str: + """Alias to the :meth:`mcstatus.motd.Motd.to_minecraft` method.""" + return self.motd.to_minecraft() + + @classmethod + @abstractmethod + def build(cls, *args, **kwargs) -> Self: + """Build BaseStatusResponse and check is it valid. + + :param args: Arguments in specific realisation. + :param kwargs: Keyword arguments in specific realisation. + :return: :class:`BaseStatusResponse` object. + """ + raise NotImplementedError("You can't use abstract methods.") + + +@dataclass +class JavaStatusResponse(BaseStatusResponse): + """The response object for :meth:`JavaServer.status() `.""" + + raw: RawJavaResponse + """Raw response from the server. + + This is :class:`~typing.TypedDict` actually, please see sources to find what is here. + """ + players: JavaStatusPlayers + version: JavaStatusVersion + icon: str | None + """The icon of the server. In `Base64 `_ encoded PNG image format. + + .. seealso:: :ref:`pages/faq:how to get server image?` + """ + + @classmethod + def build(cls, raw: RawJavaResponse, latency: float = 0) -> Self: + """Build JavaStatusResponse and check is it valid. + + :param raw: Raw response :class:`dict`. + :param latency: Time that server took to response (in milliseconds). + :raise ValueError: If the required keys (``players``, ``version``, ``description``) are not present. + :raise TypeError: + If the required keys (``players`` - :class:`dict`, ``version`` - :class:`dict`, + ``description`` - :class:`str`) are not of the expected type. + :return: :class:`JavaStatusResponse` object. + """ + return cls( + raw=raw, + players=JavaStatusPlayers.build(raw["players"]), + version=JavaStatusVersion.build(raw["version"]), + motd=Motd.parse(raw["description"], bedrock=False), + icon=raw.get("favicon"), + latency=latency, + ) + + @property + @deprecated(replacement="icon", date="2023-12") + def favicon(self) -> str | None: + """ + .. deprecated:: 11.0.0 + Will be removed 2023-12, use :attr:`icon ` instead. + """ + return self.icon + + +@dataclass +class BedrockStatusResponse(BaseStatusResponse): + """The response object for :meth:`BedrockServer.status() `.""" + + players: BedrockStatusPlayers + version: BedrockStatusVersion + map_name: str | None + """The name of the map.""" + gamemode: str | None + """The name of the gamemode on the server.""" + + @classmethod + def build(cls, decoded_data: list[Any], latency: float) -> Self: + """Build BaseStatusResponse and check is it valid. + + :param decoded_data: Raw decoded response object. + :param latency: Latency of the request. + :return: :class:`BedrockStatusResponse` object. + """ + + try: + map_name = decoded_data[7] + except IndexError: + map_name = None + try: + gamemode = decoded_data[8] + except IndexError: + gamemode = None + + return cls( + players=BedrockStatusPlayers( + online=int(decoded_data[4]), + max=int(decoded_data[5]), + ), + version=BedrockStatusVersion( + name=decoded_data[3], + protocol=int(decoded_data[2]), + brand=decoded_data[0], + ), + motd=Motd.parse(decoded_data[1], bedrock=True), + latency=latency, + map_name=map_name, + gamemode=gamemode, + ) + + @property + @deprecated(replacement="players.online", date="2023-12") + def players_online(self) -> int: + """ + .. deprecated:: 11.0.0 + Will be removed 2023-12, use :attr:`players.online ` instead. + """ + return self.players.online + + @property + @deprecated(replacement="players.max", date="2023-12") + def players_max(self) -> int: + """ + .. deprecated:: 11.0.0 + Will be removed 2023-12, use :attr:`players.max ` instead. + """ + return self.players.max + + @property + @deprecated(replacement="map_name", date="2023-12") + def map(self) -> str | None: + """ + .. deprecated:: 11.0.0 + Will be removed 2023-12, use :attr:`.map_name` instead. + """ + return self.map_name + + +@dataclass +class BaseStatusPlayers(ABC): + """Class for storing information about players on the server.""" + + online: int + """Current number of online players.""" + max: int + """The maximum allowed number of players (aka server slots).""" + + +@dataclass +class JavaStatusPlayers(BaseStatusPlayers): + """Class for storing information about players on the server.""" + + sample: list[JavaStatusPlayer] | None + """List of players, who are online. If server didn't provide this, it will be :obj:`None`. + + Actually, this is what appears when you hover over the slot count on the multiplayer screen. + + .. note:: + It's often empty or even contains some advertisement, because the specific server implementations or plugins can + disable providing this information or even change it to something custom. + + There is nothing that ``mcstatus`` can to do here if the player sample was modified/disabled like this. + """ + + @classmethod + def build(cls, raw: RawJavaResponsePlayers) -> Self: + """Build :class:`JavaStatusPlayers` from raw response :class:`dict`. + + :param raw: Raw response :class:`dict`. + :raise ValueError: If the required keys (``online``, ``max``) are not present. + :raise TypeError: + If the required keys (``online`` - :class:`int`, ``max`` - :class:`int`, + ``sample`` - :class:`list`) are not of the expected type. + :return: :class:`JavaStatusPlayers` object. + """ + sample = None + if "sample" in raw: + sample = [JavaStatusPlayer.build(player) for player in raw["sample"]] + return cls( + online=raw["online"], + max=raw["max"], + sample=sample, + ) + + +@dataclass +class BedrockStatusPlayers(BaseStatusPlayers): + """Class for storing information about players on the server.""" + + +@dataclass +class JavaStatusPlayer: + """Class with information about a single player.""" + + name: str + """Name of the player.""" + id: str + """ID of the player (in `UUID `_ format).""" + + @property + def uuid(self) -> str: + """Alias to :attr:`.id` field.""" + return self.id + + @classmethod + def build(cls, raw: RawJavaResponsePlayer) -> Self: + """Build :class:`JavaStatusPlayer` from raw response :class:`dict`. + + :param raw: Raw response :class:`dict`. + :raise ValueError: If the required keys (``name``, ``id``) are not present. + :raise TypeError: If the required keys (``name`` - :class:`str`, ``id`` - :class:`str`) + are not of the expected type. + :return: :class:`JavaStatusPlayer` object. + """ + return cls(name=raw["name"], id=raw["id"]) + + +@dataclass +class BaseStatusVersion(ABC): + """A class for storing version information.""" + + name: str + """The version name, like ``1.19.3``. + + See `Minecraft wiki `__ + for complete list. + """ + protocol: int + """The protocol version, like ``761``. + + See `Minecraft wiki `__. + """ + + +@dataclass +class JavaStatusVersion(BaseStatusVersion): + """A class for storing version information.""" + + @classmethod + def build(cls, raw: RawJavaResponseVersion) -> Self: + """Build :class:`JavaStatusVersion` from raw response dict. + + :param raw: Raw response :class:`dict`. + :raise ValueError: If the required keys (``name``, ``protocol``) are not present. + :raise TypeError: If the required keys (``name`` - :class:`str`, ``protocol`` - :class:`int`) + are not of the expected type. + :return: :class:`JavaStatusVersion` object. + """ + return cls(name=raw["name"], protocol=raw["protocol"]) + + +@dataclass +class BedrockStatusVersion(BaseStatusVersion): + """A class for storing version information.""" + + name: str + """The version name, like ``1.19.60``. + + See `Minecraft wiki `__ + for complete list. + """ + brand: str + """``MCPE`` or ``MCEE`` for Education Edition.""" + + @property + @deprecated(replacement="name", date="2023-12") + def version(self) -> str: + """ + .. deprecated:: 11.0.0 + Will be removed 2023-12, use :attr:`.name` instead. + """ + return self.name diff --git a/mcstatus/server.py b/mcstatus/server.py index daf37056..21ec33fc 100644 --- a/mcstatus/server.py +++ b/mcstatus/server.py @@ -16,7 +16,7 @@ UDPSocketConnection, ) from mcstatus.querier import AsyncServerQuerier, QueryResponse, ServerQuerier -from mcstatus.status_response import BedrockStatusResponse, JavaStatusResponse +from mcstatus.responses import BedrockStatusResponse, JavaStatusResponse from mcstatus.utils import retry if TYPE_CHECKING: @@ -123,7 +123,7 @@ def status(self, **kwargs) -> JavaStatusResponse: """Checks the status of a Minecraft Java Edition server via the status protocol. :param kwargs: Passed to a :class:`~mcstatus.pinger.ServerPinger` instance. - :return: Status information in a :class:`~mcstatus.status_response.JavaStatusResponse` instance. + :return: Status information in a :class:`~mcstatus.responses.JavaStatusResponse` instance. """ with TCPSocketConnection(self.address, self.timeout) as connection: @@ -140,7 +140,7 @@ async def async_status(self, **kwargs) -> JavaStatusResponse: """Asynchronously checks the status of a Minecraft Java Edition server via the status protocol. :param kwargs: Passed to a :class:`~mcstatus.pinger.AsyncServerPinger` instance. - :return: Status information in a :class:`~mcstatus.status_response.JavaStatusResponse` instance. + :return: Status information in a :class:`~mcstatus.responses.JavaStatusResponse` instance. """ async with TCPAsyncSocketConnection(self.address, self.timeout) as connection: @@ -206,7 +206,7 @@ def status(self, **kwargs) -> BedrockStatusResponse: """Checks the status of a Minecraft Bedrock Edition server. :param kwargs: Passed to a :class:`~mcstatus.bedrock_status.BedrockServerStatus` instance. - :return: Status information in a :class:`~mcstatus.status_response.BedrockStatusResponse` instance. + :return: Status information in a :class:`~mcstatus.responses.BedrockStatusResponse` instance. """ return BedrockServerStatus(self.address, self.timeout, **kwargs).read_status() @@ -215,6 +215,6 @@ async def async_status(self, **kwargs) -> BedrockStatusResponse: """Asynchronously checks the status of a Minecraft Bedrock Edition server. :param kwargs: Passed to a :class:`~mcstatus.bedrock_status.BedrockServerStatus` instance. - :return: Status information in a :class:`~mcstatus.status_response.BedrockStatusResponse` instance. + :return: Status information in a :class:`~mcstatus.responses.BedrockStatusResponse` instance. """ return await BedrockServerStatus(self.address, self.timeout, **kwargs).read_status_async() diff --git a/mcstatus/status_response.py b/mcstatus/status_response.py index b3920c1c..54c56d34 100644 --- a/mcstatus/status_response.py +++ b/mcstatus/status_response.py @@ -1,57 +1,7 @@ -from __future__ import annotations +from mcstatus.responses import * # noqa: F403 -from abc import ABC, abstractmethod -from dataclasses import dataclass -from typing import Any, TYPE_CHECKING - -from mcstatus.motd import Motd - -if TYPE_CHECKING: - from typing_extensions import NotRequired, Self, TypeAlias, TypedDict - - class RawJavaResponsePlayer(TypedDict): - name: str - id: str - - class RawJavaResponsePlayers(TypedDict): - online: int - max: int - sample: NotRequired[list[RawJavaResponsePlayer]] - - class RawJavaResponseVersion(TypedDict): - name: str - protocol: int - - class RawJavaResponseMotdWhenDict(TypedDict, total=False): - text: str # only present if translation is set - translation: str # same to the above field - extra: list[RawJavaResponseMotdWhenDict] - - color: str - bold: bool - strikethrough: bool - italic: bool - underlined: bool - obfuscated: bool - - RawJavaResponseMotd: TypeAlias = "RawJavaResponseMotdWhenDict | list[RawJavaResponseMotdWhenDict] | str" - - class RawJavaResponse(TypedDict): - description: RawJavaResponseMotd - players: RawJavaResponsePlayers - version: RawJavaResponseVersion - favicon: NotRequired[str] - -else: - RawJavaResponsePlayer = dict - RawJavaResponsePlayers = dict - RawJavaResponseVersion = dict - RawJavaResponseMotdWhenDict = dict - RawJavaResponse = dict - -from mcstatus.utils import deprecated - -__all__ = [ +# __all__ is frozen on the moment of deprecation +__all__ = [ # noqa: F405 "BaseStatusPlayers", "BaseStatusResponse", "BaseStatusVersion", @@ -65,291 +15,6 @@ class RawJavaResponse(TypedDict): ] -@dataclass -class BaseStatusResponse(ABC): - """Class for storing shared data from a status response.""" - - players: BaseStatusPlayers - """The players information.""" - version: BaseStatusVersion - """The version information.""" - motd: Motd - """Message Of The Day. Also known as description. - - .. seealso:: :doc:`/api/motd_parsing`. - """ - latency: float - """Latency between a server and the client (you). In milliseconds.""" - - @property - def description(self) -> str: - """Alias to the :meth:`mcstatus.motd.Motd.to_minecraft` method.""" - return self.motd.to_minecraft() - - @classmethod - @abstractmethod - def build(cls, *args, **kwargs) -> Self: - """Build BaseStatusResponse and check is it valid. - - :param args: Arguments in specific realisation. - :param kwargs: Keyword arguments in specific realisation. - :return: :class:`BaseStatusResponse` object. - """ - raise NotImplementedError("You can't use abstract methods.") - - -@dataclass -class JavaStatusResponse(BaseStatusResponse): - """The response object for :meth:`JavaServer.status() `.""" - - raw: RawJavaResponse - """Raw response from the server. - - This is :class:`~typing.TypedDict` actually, please see sources to find what is here. - """ - players: JavaStatusPlayers - version: JavaStatusVersion - icon: str | None - """The icon of the server. In `Base64 `_ encoded PNG image format. - - .. seealso:: :ref:`pages/faq:how to get server image?` - """ - - @classmethod - def build(cls, raw: RawJavaResponse, latency: float = 0) -> Self: - """Build JavaStatusResponse and check is it valid. - - :param raw: Raw response :class:`dict`. - :param latency: Time that server took to response (in milliseconds). - :raise ValueError: If the required keys (``players``, ``version``, ``description``) are not present. - :raise TypeError: - If the required keys (``players`` - :class:`dict`, ``version`` - :class:`dict`, - ``description`` - :class:`str`) are not of the expected type. - :return: :class:`JavaStatusResponse` object. - """ - return cls( - raw=raw, - players=JavaStatusPlayers.build(raw["players"]), - version=JavaStatusVersion.build(raw["version"]), - motd=Motd.parse(raw["description"], bedrock=False), - icon=raw.get("favicon"), - latency=latency, - ) - - @property - @deprecated(replacement="icon", date="2023-12") - def favicon(self) -> str | None: - """ - .. deprecated:: 11.0.0 - Will be removed 2023-12, use :attr:`icon ` instead. - """ - return self.icon - - -@dataclass -class BedrockStatusResponse(BaseStatusResponse): - """The response object for :meth:`BedrockServer.status() `.""" - - players: BedrockStatusPlayers - version: BedrockStatusVersion - map_name: str | None - """The name of the map.""" - gamemode: str | None - """The name of the gamemode on the server.""" - - @classmethod - def build(cls, decoded_data: list[Any], latency: float) -> Self: - """Build BaseStatusResponse and check is it valid. - - :param decoded_data: Raw decoded response object. - :param latency: Latency of the request. - :return: :class:`BedrockStatusResponse` object. - """ - - try: - map_name = decoded_data[7] - except IndexError: - map_name = None - try: - gamemode = decoded_data[8] - except IndexError: - gamemode = None - - return cls( - players=BedrockStatusPlayers( - online=int(decoded_data[4]), - max=int(decoded_data[5]), - ), - version=BedrockStatusVersion( - name=decoded_data[3], - protocol=int(decoded_data[2]), - brand=decoded_data[0], - ), - motd=Motd.parse(decoded_data[1], bedrock=True), - latency=latency, - map_name=map_name, - gamemode=gamemode, - ) - - @property - @deprecated(replacement="players.online", date="2023-12") - def players_online(self) -> int: - """ - .. deprecated:: 11.0.0 - Will be removed 2023-12, use :attr:`players.online ` instead. - """ - return self.players.online - - @property - @deprecated(replacement="players.max", date="2023-12") - def players_max(self) -> int: - """ - .. deprecated:: 11.0.0 - Will be removed 2023-12, use :attr:`players.max ` instead. - """ - return self.players.max - - @property - @deprecated(replacement="map_name", date="2023-12") - def map(self) -> str | None: - """ - .. deprecated:: 11.0.0 - Will be removed 2023-12, use :attr:`.map_name` instead. - """ - return self.map_name - - -@dataclass -class BaseStatusPlayers(ABC): - """Class for storing information about players on the server.""" - - online: int - """Current number of online players.""" - max: int - """The maximum allowed number of players (aka server slots).""" - - -@dataclass -class JavaStatusPlayers(BaseStatusPlayers): - """Class for storing information about players on the server.""" - - sample: list[JavaStatusPlayer] | None - """List of players, who are online. If server didn't provide this, it will be :obj:`None`. - - Actually, this is what appears when you hover over the slot count on the multiplayer screen. - - .. note:: - It's often empty or even contains some advertisement, because the specific server implementations or plugins can - disable providing this information or even change it to something custom. - - There is nothing that ``mcstatus`` can to do here if the player sample was modified/disabled like this. - """ - - @classmethod - def build(cls, raw: RawJavaResponsePlayers) -> Self: - """Build :class:`JavaStatusPlayers` from raw response :class:`dict`. - - :param raw: Raw response :class:`dict`. - :raise ValueError: If the required keys (``online``, ``max``) are not present. - :raise TypeError: - If the required keys (``online`` - :class:`int`, ``max`` - :class:`int`, - ``sample`` - :class:`list`) are not of the expected type. - :return: :class:`JavaStatusPlayers` object. - """ - sample = None - if "sample" in raw: - sample = [JavaStatusPlayer.build(player) for player in raw["sample"]] - return cls( - online=raw["online"], - max=raw["max"], - sample=sample, - ) - - -@dataclass -class BedrockStatusPlayers(BaseStatusPlayers): - """Class for storing information about players on the server.""" - - -@dataclass -class JavaStatusPlayer: - """Class with information about a single player.""" - - name: str - """Name of the player.""" - id: str - """ID of the player (in `UUID `_ format).""" - - @property - def uuid(self) -> str: - """Alias to :attr:`.id` field.""" - return self.id - - @classmethod - def build(cls, raw: RawJavaResponsePlayer) -> Self: - """Build :class:`JavaStatusPlayer` from raw response :class:`dict`. - - :param raw: Raw response :class:`dict`. - :raise ValueError: If the required keys (``name``, ``id``) are not present. - :raise TypeError: If the required keys (``name`` - :class:`str`, ``id`` - :class:`str`) - are not of the expected type. - :return: :class:`JavaStatusPlayer` object. - """ - return cls(name=raw["name"], id=raw["id"]) - - -@dataclass -class BaseStatusVersion(ABC): - """A class for storing version information.""" - - name: str - """The version name, like ``1.19.3``. - - See `Minecraft wiki `__ - for complete list. - """ - protocol: int - """The protocol version, like ``761``. - - See `Minecraft wiki `__. - """ - - -@dataclass -class JavaStatusVersion(BaseStatusVersion): - """A class for storing version information.""" - - @classmethod - def build(cls, raw: RawJavaResponseVersion) -> Self: - """Build :class:`JavaStatusVersion` from raw response dict. - - :param raw: Raw response :class:`dict`. - :raise ValueError: If the required keys (``name``, ``protocol``) are not present. - :raise TypeError: If the required keys (``name`` - :class:`str`, ``protocol`` - :class:`int`) - are not of the expected type. - :return: :class:`JavaStatusVersion` object. - """ - return cls(name=raw["name"], protocol=raw["protocol"]) - - -@dataclass -class BedrockStatusVersion(BaseStatusVersion): - """A class for storing version information.""" - - name: str - """The version name, like ``1.19.60``. - - See `Minecraft wiki `__ - for complete list. - """ - brand: str - """``MCPE`` or ``MCEE`` for Education Edition.""" +import warnings - @property - @deprecated(replacement="name", date="2023-12") - def version(self) -> str: - """ - .. deprecated:: 11.0.0 - Will be removed 2023-12, use :attr:`.name` instead. - """ - return self.name +warnings.warn("`mcstatus.status_response` is deprecated, use `mcstatus.responses` instead", DeprecationWarning, stacklevel=2) diff --git a/tests/motd/test_motd.py b/tests/motd/test_motd.py index c247699d..2d4ad394 100644 --- a/tests/motd/test_motd.py +++ b/tests/motd/test_motd.py @@ -4,7 +4,7 @@ from mcstatus.motd import Motd from mcstatus.motd.components import Formatting, MinecraftColor, TranslationTag, WebColor -from mcstatus.status_response import RawJavaResponseMotdWhenDict +from mcstatus.responses import RawJavaResponseMotdWhenDict class TestMotdParse: diff --git a/tests/motd/test_transformers.py b/tests/motd/test_transformers.py index 8e8dba0f..53c65fe2 100644 --- a/tests/motd/test_transformers.py +++ b/tests/motd/test_transformers.py @@ -9,7 +9,7 @@ from mcstatus.motd.transformers import AnsiTransformer, HtmlTransformer, MinecraftTransformer, PlainTransformer if typing.TYPE_CHECKING: - from mcstatus.status_response import RawJavaResponseMotd + from mcstatus.responses import RawJavaResponseMotd class TestMotdPlain: diff --git a/tests/status_response/__init__.py b/tests/responses/__init__.py similarity index 98% rename from tests/status_response/__init__.py rename to tests/responses/__init__.py index 15c4605e..368b022d 100644 --- a/tests/status_response/__init__.py +++ b/tests/responses/__init__.py @@ -3,7 +3,7 @@ import abc from typing import Any, TypeVar, cast -from mcstatus.status_response import BaseStatusResponse +from mcstatus.responses import BaseStatusResponse __all__ = ["BaseStatusResponseTest"] _T = TypeVar("_T", bound="type[BaseStatusResponseTest]") diff --git a/tests/status_response/conftest.py b/tests/responses/conftest.py similarity index 95% rename from tests/status_response/conftest.py rename to tests/responses/conftest.py index 153b2025..fb9a5424 100644 --- a/tests/status_response/conftest.py +++ b/tests/responses/conftest.py @@ -5,7 +5,7 @@ import pytest from _pytest.python import Function, Metafunc -from tests.status_response import BaseStatusResponseTest +from tests.responses import BaseStatusResponseTest def pytest_generate_tests(metafunc: Metafunc) -> None: diff --git a/tests/status_response/test_bedrock.py b/tests/responses/test_bedrock.py similarity index 93% rename from tests/status_response/test_bedrock.py rename to tests/responses/test_bedrock.py index 7b8cd2c4..e40a8736 100644 --- a/tests/status_response/test_bedrock.py +++ b/tests/responses/test_bedrock.py @@ -1,8 +1,8 @@ from pytest import fixture, mark from mcstatus.motd import Motd -from mcstatus.status_response import BedrockStatusPlayers, BedrockStatusResponse, BedrockStatusVersion -from tests.status_response import BaseStatusResponseTest +from mcstatus.responses import BedrockStatusPlayers, BedrockStatusResponse, BedrockStatusVersion +from tests.responses import BaseStatusResponseTest @fixture(scope="module") diff --git a/tests/status_response/test_java.py b/tests/responses/test_java.py similarity index 95% rename from tests/status_response/test_java.py rename to tests/responses/test_java.py index ecf5d364..806c8e6a 100644 --- a/tests/status_response/test_java.py +++ b/tests/responses/test_java.py @@ -1,8 +1,8 @@ from pytest import fixture from mcstatus.motd import Motd -from mcstatus.status_response import JavaStatusPlayer, JavaStatusPlayers, JavaStatusResponse, JavaStatusVersion -from tests.status_response import BaseStatusResponseTest +from mcstatus.responses import JavaStatusPlayer, JavaStatusPlayers, JavaStatusResponse, JavaStatusVersion +from tests.responses import BaseStatusResponseTest @BaseStatusResponseTest.construct diff --git a/tests/status_response/test_shared.py b/tests/responses/test_shared.py similarity index 81% rename from tests/status_response/test_shared.py rename to tests/responses/test_shared.py index 5183695a..acd6f884 100644 --- a/tests/status_response/test_shared.py +++ b/tests/responses/test_shared.py @@ -1,6 +1,6 @@ from pytest import raises -from mcstatus.status_response import BaseStatusResponse +from mcstatus.responses import BaseStatusResponse class TestMCStatusResponse: diff --git a/tests/test_bedrock_status.py b/tests/test_bedrock_status.py index be82c393..863e27a1 100644 --- a/tests/test_bedrock_status.py +++ b/tests/test_bedrock_status.py @@ -6,7 +6,7 @@ from mcstatus.address import Address from mcstatus.bedrock_status import BedrockServerStatus -from mcstatus.status_response import BedrockStatusResponse +from mcstatus.responses import BedrockStatusResponse def test_bedrock_response_is_expected_type():