Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
3b16f60ab0 | |||
06e12a8467 | |||
7a3bcc05b3 | |||
8b34f6d475 | |||
35554771d4 | |||
b238952198 | |||
d19dfe741f | |||
4a3124f75f | |||
8010c1f4a9 |
18
README.md
18
README.md
|
@ -14,7 +14,23 @@
|
|||
|
||||
This project requires [Python](https://www.python.org/) 3.8 or newer.
|
||||
|
||||
This project does not have any library requirements 😎
|
||||
All required libraries can be installed easily using:
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
Full list of requirements:
|
||||
- [beautifulsoup4](https://pypi.org/project/beautifulsoup4/)
|
||||
- [cssselect](https://pypi.org/project/cssselect/)
|
||||
- [fin-defs](https://gitfub.space/Jmaa/fin-defs)
|
||||
- [lxml](https://pypi.org/project/lxml/)
|
||||
- [requests](https://pypi.org/project/requests/)
|
||||
- [frozendict](https://pypi.org/project/frozendict/)
|
||||
- [requests-ratelimiter](https://pypi.org/project/requests-ratelimiter/)
|
||||
- [requests-util](https://gitfub.space/Jmaa/requests_util)
|
||||
- [requests_cache](https://pypi.org/project/requests_cache/)
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
"""# Common HTTP/REST clients interface
|
||||
"""
|
||||
"""# Common HTTP/REST clients interface"""
|
||||
|
||||
import urllib.parse
|
||||
|
||||
import abc
|
||||
|
@ -11,6 +11,10 @@ import bs4
|
|||
import lxml.html
|
||||
import requests
|
||||
|
||||
from ._version import __version__
|
||||
|
||||
__all__ = ['__version__']
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
@ -40,8 +44,10 @@ class AbstractClient(abc.ABC):
|
|||
|
||||
def fetch(self, url: str, **kwargs) -> requests.Response:
|
||||
r = self._fetch(url, **kwargs)
|
||||
if r.status_code in {301,302,303}:
|
||||
msg = f'Redirection: {r.request.method} {url} -> GET {r.headers["Location"]}'
|
||||
if r.status_code in {301, 302, 303}:
|
||||
msg = (
|
||||
f'Redirection: {r.request.method} {url} -> GET {r.headers["Location"]}'
|
||||
)
|
||||
raise Exception(msg)
|
||||
r.raise_for_status()
|
||||
return r
|
||||
|
@ -51,7 +57,9 @@ class AbstractClient(abc.ABC):
|
|||
kwargs.setdefault('allow_redirects', True)
|
||||
|
||||
url_parsed = urllib.parse.urlparse(url)
|
||||
origin_url = url_parsed._replace(path='',params='',query='',fragment='').geturl()
|
||||
origin_url = url_parsed._replace(
|
||||
path='', params='', query='', fragment=''
|
||||
).geturl()
|
||||
|
||||
kwargs.setdefault('headers', {}).setdefault('Origin', origin_url)
|
||||
kwargs.setdefault('headers', {}).setdefault('Alt-Used', url_parsed.hostname)
|
||||
|
@ -68,21 +76,21 @@ class AbstractClient(abc.ABC):
|
|||
url: str,
|
||||
**kwargs,
|
||||
) -> None | bs4.BeautifulSoup:
|
||||
kwargs.setdefault('headers', {}).setdefault('Accept', 'text/html')
|
||||
kwargs.setdefault('headers', {}).setdefault('Accept', 'text/html')
|
||||
text = self.fetch_text(url, **kwargs)
|
||||
if text is None:
|
||||
return None
|
||||
return lxml.html.document_fromstring(text)
|
||||
|
||||
def fetch_soup(self, url: str, **kwargs) -> None | bs4.BeautifulSoup:
|
||||
kwargs.setdefault('headers', {}).setdefault('Accept', 'text/html')
|
||||
kwargs.setdefault('headers', {}).setdefault('Accept', 'text/html')
|
||||
text = self.fetch_text(url, **kwargs)
|
||||
if text is None:
|
||||
return None
|
||||
return bs4.BeautifulSoup(text, 'html.parser')
|
||||
|
||||
def fetch_json(self, url: str, **kwargs) -> None | dict[str, Any]:
|
||||
kwargs.setdefault('headers', {}).setdefault('Accept', 'application/json')
|
||||
kwargs.setdefault('headers', {}).setdefault('Accept', 'application/json')
|
||||
|
||||
response = self.fetch(url=url, **kwargs)
|
||||
loaded_json = response.json()
|
||||
|
|
|
@ -1 +1 @@
|
|||
__version__ = '0.1.2'
|
||||
__version__ = '0.1.5'
|
||||
|
|
|
@ -15,6 +15,7 @@ DEFAULT_MAX_RESULTS = 1
|
|||
|
||||
URL = str
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True, order=True, slots=True)
|
||||
class SellerInfo:
|
||||
name: str
|
||||
|
@ -39,6 +40,7 @@ class StoreOfferProperty(enum.Enum):
|
|||
AUCTION = enum.auto()
|
||||
SOLD_OUT = enum.auto()
|
||||
DISCOUNT = enum.auto()
|
||||
PRE_ORDER = enum.auto()
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True, order=True, slots=True)
|
||||
|
|
|
@ -7,6 +7,7 @@ import dataclasses
|
|||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class WishlistItem:
|
||||
"""A single wishlished product."""
|
||||
|
@ -14,12 +15,11 @@ class WishlistItem:
|
|||
product_name: str # Name of the game/product
|
||||
reference_url: str # URL to a reference page for the item.
|
||||
image_url: str | None = None # URL to the product image
|
||||
console_name: str | None = None # Gaming platform/console name
|
||||
reference_price: fin_defs.AssetAmount | None = None # Reference price, if any
|
||||
console_name: str | None = None # Gaming platform/console name
|
||||
reference_price: fin_defs.AssetAmount | None = None # Reference price, if any
|
||||
|
||||
|
||||
class WishlistClient(abc.ABC):
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_wishlist(self) -> Sequence[WishlistItem]:
|
||||
pass
|
||||
|
|
22
setup.py
22
setup.py
|
@ -10,8 +10,7 @@ from setuptools import setup
|
|||
PACKAGE_NAME = 'clients_protocol'
|
||||
|
||||
PACKAGE_DESCRIPTION = """
|
||||
# Common HTTP/REST clients interface
|
||||
""".strip()
|
||||
# Common HTTP/REST clients interface""".strip()
|
||||
|
||||
PACKAGE_DESCRIPTION_SHORT = """
|
||||
""".strip()
|
||||
|
@ -27,11 +26,9 @@ def parse_version_file(text: str) -> str:
|
|||
|
||||
|
||||
def find_python_packages() -> list[str]:
|
||||
"""
|
||||
Find all python packages. (Directories containing __init__.py files.)
|
||||
"""
|
||||
"""Find all python packages (directories containing __init__.py files)."""
|
||||
root_path = Path(PACKAGE_NAME)
|
||||
packages: set[str] = set([PACKAGE_NAME])
|
||||
packages: set[str] = {PACKAGE_NAME}
|
||||
|
||||
# Search recursively
|
||||
for init_file in root_path.rglob('__init__.py'):
|
||||
|
@ -39,11 +36,22 @@ def find_python_packages() -> list[str]:
|
|||
|
||||
return sorted(packages)
|
||||
|
||||
|
||||
with open(PACKAGE_NAME + '/_version.py') as f:
|
||||
version = parse_version_file(f.read())
|
||||
|
||||
|
||||
REQUIREMENTS_MAIN = []
|
||||
REQUIREMENTS_MAIN = [
|
||||
'beautifulsoup4',
|
||||
'cssselect',
|
||||
'fin-defs @ git+https://gitfub.space/Jmaa/fin-defs.git',
|
||||
'lxml',
|
||||
'requests',
|
||||
'frozendict',
|
||||
'requests-ratelimiter',
|
||||
'requests-util @ git+https://gitfub.space/Jmaa/requests_util.git',
|
||||
'requests_cache',
|
||||
]
|
||||
REQUIREMENTS_TEST = []
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
def test_init():
|
||||
import clients_protocol
|
||||
import clients_protocol.autoload
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user