Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions src/tf2_utils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
# flake8: noqa
__title__ = "tf2-utils"
__author__ = "offish"
__version__ = "2.3.1"
__version__ = "2.3.2"
__license__ = "MIT"

from .currency import CurrencyExchange
from .exceptions import *
from .exceptions import InvalidInventory, TF2UtilsError
from .inventory import Inventory, map_inventory
from .item import Item
from .marketplace_tf import *
from .marketplace_tf import (
MarketplaceTF,
MarketplaceTFException,
NoAPIKey,
SKUDoesNotMatch,
)
from .offer import Offer
from .prices_tf import PricesTF
from .prices_tf import (
EmptyResponse,
InternalServerError,
PricesTF,
PricesTFError,
RateLimited,
UnauthorizedError,
)
from .prices_tf_websocket import PricesTFWebsocket
from .schema import SchemaItemsUtils
from .sku import *
from .utils import *

# flake8: noqa
31 changes: 0 additions & 31 deletions src/tf2_utils/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,6 @@
# generic
class TF2UtilsError(Exception):
pass


class InvalidInventory(TF2UtilsError):
pass


# pricestf
class PricesTFError(TF2UtilsError):
pass


class InternalServerError(PricesTFError):
pass


class RateLimited(PricesTFError):
pass


class EmptyResponse(PricesTFError):
pass


# marketplacetf
class MarketplaceTFException(TF2UtilsError):
pass


class SKUDoesNotMatch(MarketplaceTFException):
pass


class NoAPIKey(MarketplaceTFException):
pass
14 changes: 13 additions & 1 deletion src/tf2_utils/marketplace_tf.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,23 @@

import requests

from .exceptions import NoAPIKey, SKUDoesNotMatch
from .exceptions import TF2UtilsError
from .schema import SchemaItemsUtils
from .sku import sku_is_craftable, sku_to_quality_name


class MarketplaceTFException(TF2UtilsError):
pass


class SKUDoesNotMatch(MarketplaceTFException):
pass


class NoAPIKey(MarketplaceTFException):
pass


def api_key_required(func):
def wrapper(self, *args, **kwargs):
if self._api_key is None:
Expand Down
59 changes: 39 additions & 20 deletions src/tf2_utils/prices_tf.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,46 @@

import requests

from .exceptions import EmptyResponse, InternalServerError, PricesTFError, RateLimited
from .utils import to_refined
from .exceptions import TF2UtilsError
from .utils import refinedify


class PricesTF:
URL = "https://api2.prices.tf"
class PricesTFError(TF2UtilsError):
pass


class UnauthorizedError(PricesTFError):
pass


class InternalServerError(PricesTFError):
pass


class RateLimited(PricesTFError):
pass


class EmptyResponse(PricesTFError):
pass


class PricesTF:
def __init__(self) -> None:
self.url = "https://api2.prices.tf"
self._access_token = ""
self._headers = {}

@staticmethod
def _format_price(data: dict) -> dict:
def format_price(data: dict) -> dict:
buy_keys = data.get("buyKeys", 0)
buy_metal = refinedify(data.get("buyHalfScrap", 0) / 18)
sell_keys = data.get("sellKeys", 0)
sell_metal = refinedify(data.get("sellHalfScrap", 0) / 18)

return {
"buy": {
"keys": data["buyKeys"],
"metal": to_refined(data["buyHalfScrap"] / 2),
},
"sell": {
"keys": data["sellKeys"],
"metal": to_refined(data["sellHalfScrap"] / 2),
},
"buy": {"keys": buy_keys, "metal": buy_metal},
"sell": {"keys": sell_keys, "metal": sell_metal},
}

@staticmethod
Expand All @@ -34,6 +52,9 @@ def _validate_response(response: dict[str, Any]) -> None:

status_code = response.get("statusCode")

if status_code == 401:
raise UnauthorizedError("unauthorized, please request a new access token")

if status_code == 500:
raise InternalServerError("there was an interal server error")

Expand All @@ -44,22 +65,22 @@ def _set_header(self, header: dict) -> None:
self._headers = header

def _get(self, endpoint: str, params: dict = {}) -> dict:
url = self.URL + endpoint
url = self.url + endpoint
response = requests.get(url, headers=self._headers, params=params)
res = response.json()
self._validate_response(res)

return res

def _post(self, endpoint: str) -> tuple[dict, int]:
url = self.URL + endpoint
url = self.url + endpoint
response = requests.post(url, headers=self._headers)
res = response.json()
self._validate_response(res)

return (res, response.status_code)

def _get_prices_till_page(
def get_prices_till_page(
self, page_limit: int, print_rate_limit: bool = False
) -> dict:
prices = {}
Expand All @@ -83,7 +104,7 @@ def _get_prices_till_page(
raise PricesTFError("could not find any items in response")

for item in response["items"]:
prices[item["sku"]] = self._format_price(item)
prices[item["sku"]] = self.format_price(item)

current_page = response["meta"]["currentPage"] + 1
total_pages = response["meta"]["totalPages"]
Expand All @@ -107,16 +128,14 @@ def get_prices(self, page: int, limit: int = 100, order: str = "DESC") -> dict:
return self._get("/prices", {"page": page, "limit": limit, "order": order})

def get_all_prices(self, print_rate_limit: bool = False) -> dict:
return self._get_prices_till_page(-1, print_rate_limit)
return self.get_prices_till_page(-1, print_rate_limit)

def update_price(self, sku: str) -> tuple[dict, int]:
return self._post(f"/prices/{sku}/refresh")

def request_access_token(self) -> None:
res, _ = self._post("/auth/access")

self._validate_response(res)

self._access_token = res["accessToken"]

self._set_header(
Expand Down
2 changes: 1 addition & 1 deletion src/tf2_utils/providers/express_load.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
class ExpressLoad(Provider):
def __init__(self, api_key: str = ""):
super().__init__(api_key)
self.headers = {"X-API-Key": self.api_key}
self.headers = {"X-API-Key": self.api_key, "User-Agent": "tf2-express"}

def get_url_and_params(
self, steam_id: str, app_id: int, context_id: int
Expand Down
72 changes: 72 additions & 0 deletions tests/test_prices_tf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import pytest

from src.tf2_utils import PricesTF, UnauthorizedError

prices_tf = PricesTF()


def test_inital() -> None:
assert prices_tf._access_token == ""
assert prices_tf._headers == {}

with pytest.raises(UnauthorizedError):
prices_tf.get_price("5021;6")

prices_tf.request_access_token()

assert prices_tf._access_token != ""
assert prices_tf._headers != {}


def test_get_price() -> None:
price = prices_tf.get_price("5021;6")

assert isinstance(price, dict)
assert "sku" in price
assert "buyHalfScrap" in price
assert "buyKeys" in price
assert "buyKeyHalfScrap" in price
assert "sellHalfScrap" in price
assert "sellKeys" in price
assert "sellKeyHalfScrap" in price
assert "createdAt" in price
assert "updatedAt" in price


def test_formatting_price() -> None:
item = {
"sku": "5021;6",
"buyHalfScrap": 1210,
"buyKeys": 0,
"buyKeyHalfScrap": None,
"sellHalfScrap": 1212,
"sellKeys": 0,
"sellKeyHalfScrap": None,
"createdAt": "2021-10-11T23:05:32.696Z",
"updatedAt": "2025-04-03T16:36:22.624Z",
}
formatted_price = prices_tf.format_price(item)

assert formatted_price["buy"]["keys"] == 0
assert formatted_price["buy"]["metal"] == 67.22
assert formatted_price["sell"]["keys"] == 0
assert formatted_price["sell"]["metal"] == 67.33


def test_get_prices_till_page() -> None:
pages = 2
prices = prices_tf.get_prices_till_page(pages)

assert len(prices) == pages * 50

for sku in prices:
price = prices[sku]

assert isinstance(price, dict)
assert "buy" in price
assert "sell" in price
assert "keys" in price["buy"]
assert "metal" in price["buy"]
assert "keys" in price["sell"]
assert "metal" in price["sell"]
break
5 changes: 4 additions & 1 deletion tests/test_providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,7 @@ def test_express_load_inventory(express_load_api_key: str, steam_id: str) -> Non

assert url == f"https://api.express-load.com/inventory/{steam_id}/440/2"
assert params == {}
assert provider.headers == {"X-API-Key": express_load_api_key}
assert provider.headers == {
"X-API-Key": express_load_api_key,
"User-Agent": "tf2-express",
}