# -*- coding: utf-8 -*-
"""
Author: Jacek 'Szumak' Kotlarski --<szumak@virthost.pl>
Created: 2024-10-08
Purpose: EDSM API client classes.
"""
import requests # type: ignore
import json
from typing import Dict, List, Optional, Any, Union
from requests.utils import requote_uri # type: ignore
from inspect import currentframe
from .edsm_keys import EdsmKeys
from ..basetool import BData
from ..attribtool import ReadOnlyClass
from ..raisetool import Raise
from ..edmctool.stars import StarsSystem
class _Keys(object, metaclass=ReadOnlyClass):
"""Internal keys container class."""
OPTIONS: str = "__options__"
SYSTEMS_URL: str = "__systems_url__"
SYSTEM_URL: str = "__system_url__"
[docs]
class Url(BData):
"""Url.
Class for serving HTTP/HTTPS requests.
"""
[docs]
def __init__(self) -> None:
"""Create Url helper object."""
self.__options = {
EdsmKeys.SHOW_ID: 1,
EdsmKeys.SHOW_PERMIT: 1,
EdsmKeys.SHOW_COORDINATES: 1,
EdsmKeys.SHOW_INFORMATION: 0,
EdsmKeys.SHOW_PRIMARY_STAR: 0,
EdsmKeys.INCLUDE_HIDDEN: 0,
}
self._set_data(
key=_Keys.SYSTEMS_URL,
value="https://www.edsm.net/api-v1/",
set_default_type=str,
)
self._set_data(
key=_Keys.SYSTEM_URL,
value="https://www.edsm.net/api-system-v1/",
set_default_type=str,
)
@property
def __options(self) -> Dict:
"""Return the options dictionary for URL parameters.
### Returns:
Dict - URL query options mapping.
"""
return self._get_data(key=_Keys.OPTIONS) # type: ignore
@__options.setter
def __options(self, value: Optional[Dict]) -> None:
"""Assign the options dictionary.
### Arguments:
* value: Optional[Dict] - Options dictionary or None to initialize empty.
"""
if value is None:
self._set_data(key=_Keys.OPTIONS, value={}, set_default_type=Dict)
else:
self._set_data(key=_Keys.OPTIONS, value=value, set_default_type=Dict)
@property
def __system_url(self) -> str:
"""Return the system API endpoint URL.
### Returns:
str - URL for single system queries.
"""
return self._get_data(key=_Keys.SYSTEM_URL) # type: ignore
@property
def __systems_url(self) -> str:
"""Return the systems API endpoint URL.
### Returns:
str - URL for multiple systems queries.
"""
return self._get_data(key=_Keys.SYSTEMS_URL) # type: ignore
@property
def options(self) -> str:
"""Get url options string.
### Returns:
str - Formatted URL parameter string.
"""
out: str = ""
for key, value in self.__options.items():
out += f"&{key}={value}"
return out
[docs]
def bodies_url(self, s_system: StarsSystem) -> str:
"""Returns proper API url for getting bodies information data.
### Arguments:
* s_system: StarsSystem - System object containing name or address.
### Returns:
str - Formatted URL for bodies query.
### Raises:
* TypeError: If s_system is not a StarsSystem instance.
"""
if not isinstance(s_system, StarsSystem):
raise Raise.error(
f"StarsSystem type expected, '{type(s_system)}' received",
TypeError,
self._c_name,
currentframe(),
)
if s_system.name:
return requote_uri(f"{self.__system_url}bodies?systemName={s_system.name}")
if s_system.address:
return requote_uri(f"{self.__system_url}bodies?systemId={s_system.address}")
return ""
[docs]
def system_url(self, s_system: StarsSystem) -> str:
"""Returns proper API url for getting system data.
### Arguments:
* s_system: StarsSystem - System object containing name.
### Returns:
str - Formatted URL for system query.
### Raises:
* TypeError: If s_system is not a StarsSystem instance.
"""
if not isinstance(s_system, StarsSystem):
raise Raise.error(
f"StarsSystem type expected, '{type(s_system)}' received",
TypeError,
self._c_name,
currentframe(),
)
if s_system.name:
return requote_uri(
f"{self.__systems_url}system?systemName={s_system.name}{self.options}"
)
return ""
[docs]
def radius_url(self, s_system: StarsSystem, radius: int) -> str:
"""Returns proper API url for getting systems data in radius.
### Arguments:
* s_system: StarsSystem - System object containing name.
* radius: int - Search radius in light years (clamped to 5-100).
### Returns:
str - Formatted URL for sphere-systems query.
### Raises:
* TypeError: If s_system is not a StarsSystem instance.
"""
if not isinstance(s_system, StarsSystem):
raise Raise.error(
f"StarsSystem type expected, '{type(s_system)}' received",
TypeError,
self._c_name,
currentframe(),
)
if not isinstance(radius, int):
radius = 50
else:
if radius < 5:
radius = 5
elif radius > 100:
radius = 100
if s_system.name:
return requote_uri(
f"{self.__systems_url}sphere-systems?systemName={s_system.name}&radius={radius}{self.options}"
)
return ""
[docs]
def cube_url(self, s_system: StarsSystem, size: int) -> str:
"""Returns proper API url for getting systems data in cube.
### Arguments:
* s_system: StarsSystem - System object containing name.
* size: int - Cube size in light years (clamped to 10-200).
### Returns:
str - Formatted URL for cube-systems query.
### Raises:
* TypeError: If s_system is not a StarsSystem instance.
"""
if not isinstance(s_system, StarsSystem):
raise Raise.error(
f"StarsSystem type expected, '{type(s_system)}' received",
TypeError,
self._c_name,
currentframe(),
)
if not isinstance(size, int):
size = 100
else:
if size < 10:
size = 10
elif size > 200:
size = 200
if s_system.name:
return requote_uri(
f"{self.__systems_url}cube-systems?systemName={s_system.name}&size={size}{self.options}"
)
return ""
[docs]
def system_query(self, s_system: StarsSystem) -> Optional[Dict]:
"""Returns result of query for system data.
### Arguments:
* s_system: StarsSystem - System object containing name.
### Returns:
Optional[Dict] - System data from EDSM API or None on failure.
### Raises:
* TypeError: If s_system is not a StarsSystem instance.
"""
if not isinstance(s_system, StarsSystem):
raise Raise.error(
f"StarsSystem type expected, '{type(s_system)}' received",
TypeError,
self._c_name,
currentframe(),
)
url: str = self.system_url(s_system)
if not url:
return None
try:
response: requests.Response = requests.get(url, timeout=30)
if response.status_code != 200:
print(f"Error calling API for system data: {response.status_code}")
return None
return json.loads(response.text)
except Exception as ex:
print(ex)
return None
[docs]
def url_query(self, url: str) -> Union[List[Dict[str, Any]], Dict[str, Any]]:
"""Returns result of query for url.
### Arguments:
* url: str - Full API URL to query.
### Returns:
Union[List[Dict[str, Any]], Dict[str, Any]] - Response data from EDSM API or empty list on failure.
"""
out = []
if not url:
return out
try:
response: requests.Response = requests.get(url, timeout=60)
if response.status_code != 200:
print(f"Error calling API for EDSM data: {response.status_code}")
else:
out = json.loads(response.text)
except Exception as ex:
print(ex)
return out
# #[EOF]#######################################################################