firstcash.py 1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- firstcash/__init__.py +37 -0
- firstcash/_utils.py +123 -0
- firstcash/api_client.py +841 -0
- firstcash/exceptions.py +97 -0
- firstcash/py.typed +0 -0
- firstcash/types/__init__.py +0 -0
- firstcash/types/category.py +20 -0
- firstcash/types/http_content.py +4 -0
- firstcash/types/http_method.py +4 -0
- firstcash/types/http_request_message.py +14 -0
- firstcash/types/http_response_message.py +15 -0
- firstcash/types/http_status_code.py +48 -0
- firstcash/types/item_request_by_icn.py +30 -0
- firstcash/types/item_request_search.py +39 -0
- firstcash/types/store_address.py +22 -0
- firstcash/types/store_details.py +32 -0
- firstcash/types/store_display_info.py +39 -0
- firstcash/types/store_hours.py +18 -0
- firstcash/types/store_item.py +42 -0
- firstcash/types/store_item_response.py +26 -0
- firstcash/types/store_license.py +4 -0
- firstcash/types/store_request.py +6 -0
- firstcash/types/todays_store_hours.py +21 -0
- firstcash/types/version.py +9 -0
- firstcash_py-1.0.dist-info/METADATA +120 -0
- firstcash_py-1.0.dist-info/RECORD +29 -0
- firstcash_py-1.0.dist-info/WHEEL +5 -0
- firstcash_py-1.0.dist-info/licenses/LICENSE +21 -0
- firstcash_py-1.0.dist-info/top_level.txt +1 -0
firstcash/__init__.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""
|
|
2
|
+
FirstCash.Py
|
|
3
|
+
------------
|
|
4
|
+
A basic API wrapper for the FirstCash
|
|
5
|
+
mobile app API, which exposes the combined
|
|
6
|
+
functionality of the store and inventory
|
|
7
|
+
management APIs, allowing the user to fetch
|
|
8
|
+
store details as well as search for items across
|
|
9
|
+
the massive FirstCash inventory network.
|
|
10
|
+
|
|
11
|
+
:copyright: (c) 2026 AgentLoneStar007
|
|
12
|
+
:license: MIT
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
__title__: str = "firstcash"
|
|
16
|
+
__author__: str = "AgentLoneStar007"
|
|
17
|
+
__license__: str = "MIT"
|
|
18
|
+
__copyright__: str = "Copyright © 2026-present AgentLoneStar007"
|
|
19
|
+
__version__: str = "1.0"
|
|
20
|
+
|
|
21
|
+
# Imports from library files, to make everything accessible under the main import of "firstcash"
|
|
22
|
+
|
|
23
|
+
from .api_client import APIClient
|
|
24
|
+
from .types.category import Category
|
|
25
|
+
from .types.store_address import StoreAddress
|
|
26
|
+
from .types.store_details import StoreDetails
|
|
27
|
+
from .types.store_display_info import StoreDisplayInfo
|
|
28
|
+
from .types.store_hours import StoreHours
|
|
29
|
+
from .types.store_item import StoreItem
|
|
30
|
+
from .types.store_item_response import StoreItemResponse
|
|
31
|
+
from .types.store_license import StoreLicense
|
|
32
|
+
from .types.todays_store_hours import TodaysStoreHours
|
|
33
|
+
from .exceptions import (
|
|
34
|
+
FirstCashException, APIGeneralError, APIServerError, APIUnauthorizedError, APIResponseTimedOut, APIContentNotFound,
|
|
35
|
+
APIRateLimited, SearchCoordinateValueError, SearchRadiusValueError, StoreIDValueError, CategoryCodeValueError,
|
|
36
|
+
PageIndexValueError, PageSizeValueError, PriceValueError
|
|
37
|
+
)
|
firstcash/_utils.py
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
from urllib.parse import urljoin, urlencode
|
|
2
|
+
from .exceptions import (SearchCoordinateValueError, SearchRadiusValueError, StoreIDValueError, CategoryCodeValueError,
|
|
3
|
+
PageIndexValueError, PageSizeValueError, PriceValueError)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# Function to build a URL to make a request to
|
|
7
|
+
def buildURL(base_api_url: str, api_key: str, endpoint: str = None, params: dict = None) -> str:
|
|
8
|
+
"""
|
|
9
|
+
A function to build a URL that can be used to make an API request.
|
|
10
|
+
|
|
11
|
+
:param base_api_url: The base URL of the API.
|
|
12
|
+
:param api_key: The API key for the used API.
|
|
13
|
+
:param endpoint: The endpoint to use. Optional.
|
|
14
|
+
This will be something like "Categories," or "Items."
|
|
15
|
+
:param params: The parameters to append to the URL, in a dictionary
|
|
16
|
+
"key": "value" format.
|
|
17
|
+
|
|
18
|
+
:returns: ``str`` - The URL to query with all provided parameters.
|
|
19
|
+
|
|
20
|
+
:raises None:
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
# Create the base URL
|
|
24
|
+
url: str = urljoin(base_api_url, endpoint) if endpoint else base_api_url
|
|
25
|
+
|
|
26
|
+
if params:
|
|
27
|
+
# Join the parameters to the base URL, if provided
|
|
28
|
+
query_string: str = urlencode(params)
|
|
29
|
+
if "?" not in url:
|
|
30
|
+
url += "?" + query_string
|
|
31
|
+
else:
|
|
32
|
+
url += "&" + query_string
|
|
33
|
+
|
|
34
|
+
# Append the API key to the end, using a & separator if any parameters were
|
|
35
|
+
# provided, or a ? if none were provided
|
|
36
|
+
url += f"{"&" if params else "?"}key={api_key}"
|
|
37
|
+
|
|
38
|
+
return url
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class ValueCheckers:
|
|
42
|
+
@staticmethod
|
|
43
|
+
def checkLatitude(latitude: float) -> None:
|
|
44
|
+
"""Checks a latitude coordinate to see if it's within bounds."""
|
|
45
|
+
|
|
46
|
+
if not (-90 <= latitude <= 90):
|
|
47
|
+
raise SearchCoordinateValueError(
|
|
48
|
+
"A latitude value must be greater than or equal to -90, and less than or equal to 90.")
|
|
49
|
+
|
|
50
|
+
return
|
|
51
|
+
|
|
52
|
+
@staticmethod
|
|
53
|
+
def checkLongitude(longitude: float) -> None:
|
|
54
|
+
"""Checks a longitude coordinate to see if it's within bounds."""
|
|
55
|
+
|
|
56
|
+
if not (-180 <= longitude <= 180):
|
|
57
|
+
raise SearchCoordinateValueError(
|
|
58
|
+
"A longitude value must be greater than or equal to -180 and less than or equal to 180.")
|
|
59
|
+
|
|
60
|
+
return
|
|
61
|
+
|
|
62
|
+
@staticmethod
|
|
63
|
+
def checkSearchRadius(search_radius: int | float) -> None:
|
|
64
|
+
"""Checks a search radius to see if it's within bounds."""
|
|
65
|
+
|
|
66
|
+
if not (0 <= search_radius <= 5000):
|
|
67
|
+
raise SearchRadiusValueError(
|
|
68
|
+
"A search radius cannot be negative and must be less than or equal to 5,000 miles.")
|
|
69
|
+
|
|
70
|
+
return
|
|
71
|
+
|
|
72
|
+
@staticmethod
|
|
73
|
+
def checkPriceFilters(max_price: float | int, min_price: float | int = None) -> None:
|
|
74
|
+
"""Checks price filters to see if they're within bounds."""
|
|
75
|
+
|
|
76
|
+
if max_price < 0:
|
|
77
|
+
raise PriceValueError("Price filters cannot be negative.")
|
|
78
|
+
|
|
79
|
+
if min_price:
|
|
80
|
+
if min_price < 0:
|
|
81
|
+
raise PriceValueError("Price filters cannot be negative.")
|
|
82
|
+
|
|
83
|
+
if max_price < min_price:
|
|
84
|
+
raise PriceValueError("The maximum price filter cannot be less than the minimum price filter.")
|
|
85
|
+
return
|
|
86
|
+
|
|
87
|
+
@staticmethod
|
|
88
|
+
def checkStoreID(store_id: int) -> None:
|
|
89
|
+
"""Checks a store ID to see if it's within bounds."""
|
|
90
|
+
|
|
91
|
+
if not (0 <= store_id <= 32767):
|
|
92
|
+
raise StoreIDValueError("A store ID cannot be negative and must be less than or equal to 32,767.")
|
|
93
|
+
|
|
94
|
+
return
|
|
95
|
+
|
|
96
|
+
@staticmethod
|
|
97
|
+
def checkCategoryCode(category_code: int) -> None:
|
|
98
|
+
"""Checks a category code to see if it's within bounds."""
|
|
99
|
+
|
|
100
|
+
if not (0 <= category_code <= 9999):
|
|
101
|
+
raise CategoryCodeValueError("Category codes must be between zero and 9,999.")
|
|
102
|
+
|
|
103
|
+
return
|
|
104
|
+
|
|
105
|
+
@staticmethod
|
|
106
|
+
def checkPageIndex(index: int, starting_index: int = 0) -> None:
|
|
107
|
+
"""Checks a page index to see if it's within bounds."""
|
|
108
|
+
|
|
109
|
+
if index < 0:
|
|
110
|
+
raise PageIndexValueError("Page index cannot be negative.")
|
|
111
|
+
|
|
112
|
+
## While this is semi-unnecessary, it adds a bit of prettification to the error.
|
|
113
|
+
if index < starting_index:
|
|
114
|
+
raise PageIndexValueError("Page index below starting index.")
|
|
115
|
+
|
|
116
|
+
return
|
|
117
|
+
|
|
118
|
+
@staticmethod
|
|
119
|
+
def checkPageSize(page_size: int) -> None:
|
|
120
|
+
"""Checks a page's size to see if it's within bounds."""
|
|
121
|
+
|
|
122
|
+
if page_size <= 0:
|
|
123
|
+
raise PageSizeValueError("The page size must be greater than or equal to one.")
|