firstcash.py 1.0__tar.gz
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_py-1.0/LICENSE +21 -0
- firstcash_py-1.0/PKG-INFO +120 -0
- firstcash_py-1.0/README.md +91 -0
- firstcash_py-1.0/firstcash/__init__.py +37 -0
- firstcash_py-1.0/firstcash/_utils.py +123 -0
- firstcash_py-1.0/firstcash/api_client.py +841 -0
- firstcash_py-1.0/firstcash/exceptions.py +97 -0
- firstcash_py-1.0/firstcash/py.typed +0 -0
- firstcash_py-1.0/firstcash/types/__init__.py +0 -0
- firstcash_py-1.0/firstcash/types/category.py +20 -0
- firstcash_py-1.0/firstcash/types/http_content.py +4 -0
- firstcash_py-1.0/firstcash/types/http_method.py +4 -0
- firstcash_py-1.0/firstcash/types/http_request_message.py +14 -0
- firstcash_py-1.0/firstcash/types/http_response_message.py +15 -0
- firstcash_py-1.0/firstcash/types/http_status_code.py +48 -0
- firstcash_py-1.0/firstcash/types/item_request_by_icn.py +30 -0
- firstcash_py-1.0/firstcash/types/item_request_search.py +39 -0
- firstcash_py-1.0/firstcash/types/store_address.py +22 -0
- firstcash_py-1.0/firstcash/types/store_details.py +32 -0
- firstcash_py-1.0/firstcash/types/store_display_info.py +39 -0
- firstcash_py-1.0/firstcash/types/store_hours.py +18 -0
- firstcash_py-1.0/firstcash/types/store_item.py +42 -0
- firstcash_py-1.0/firstcash/types/store_item_response.py +26 -0
- firstcash_py-1.0/firstcash/types/store_license.py +4 -0
- firstcash_py-1.0/firstcash/types/store_request.py +6 -0
- firstcash_py-1.0/firstcash/types/todays_store_hours.py +21 -0
- firstcash_py-1.0/firstcash/types/version.py +9 -0
- firstcash_py-1.0/firstcash.py.egg-info/PKG-INFO +120 -0
- firstcash_py-1.0/firstcash.py.egg-info/SOURCES.txt +33 -0
- firstcash_py-1.0/firstcash.py.egg-info/dependency_links.txt +1 -0
- firstcash_py-1.0/firstcash.py.egg-info/requires.txt +1 -0
- firstcash_py-1.0/firstcash.py.egg-info/top_level.txt +1 -0
- firstcash_py-1.0/pyproject.toml +41 -0
- firstcash_py-1.0/setup.cfg +4 -0
- firstcash_py-1.0/setup.py +21 -0
firstcash_py-1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AgentLoneStar007
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: firstcash.py
|
|
3
|
+
Version: 1.0
|
|
4
|
+
Summary: A basic Python library to communicate with FirstCash' mobile app API.
|
|
5
|
+
Author-email: AgentLoneStar007 <contactagent.3gxdf@simplelogin.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/AgentLoneStar007/FirstCash.Py
|
|
8
|
+
Project-URL: Documentation, https://github.com/AgentLoneStar007/FirstCash.Py/tree/main/docs
|
|
9
|
+
Project-URL: Issues, https://github.com/AgentLoneStar007/FirstCash.Py/issues
|
|
10
|
+
Keywords: api,web,web api,http,https,http api,https api,rest,restful,restful api
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Natural Language :: English
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Classifier: Topic :: Database
|
|
21
|
+
Classifier: Topic :: Internet
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.12
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: httpx
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# FirstCash.py
|
|
31
|
+
|
|
32
|
+
#### *A basic Python library to communicate with the FirstCash mobile app API.*
|
|
33
|
+
|
|
34
|
+
This is a super basic library designed for querying the FirstCash mobile app API, which
|
|
35
|
+
allows the developer to search for stores, items, and more. One major advantage of this
|
|
36
|
+
library is it exposes API methods that aren't in use on the FirstCash [inventory website](https://search.cashamerica.com/),
|
|
37
|
+
such as limiting your search to specific stores or multiple categories.
|
|
38
|
+
|
|
39
|
+
Note: This library does require an API key. While one is very is easy to obtain if you just look
|
|
40
|
+
a little for it, I doubt they're legal to distribute, so you have to attain one on your own.
|
|
41
|
+
|
|
42
|
+
#### Features:
|
|
43
|
+
- Methods/attributes extensively explained within
|
|
44
|
+
- Use of modern Python built-in typing capabilities
|
|
45
|
+
- Asynchronous functionality
|
|
46
|
+
|
|
47
|
+
## Installation:
|
|
48
|
+
**This library requires at least Python 3.12 or higher.** <br>
|
|
49
|
+
|
|
50
|
+
### Pip:
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
Windows:
|
|
54
|
+
```commandline
|
|
55
|
+
py -3 -m pip install -U firstcash.py
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Linux/macOS/Unix:
|
|
59
|
+
```bash
|
|
60
|
+
python3 -m pip install -U firstcash.py
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### UV:
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
Windows/macOS/Linux/Unix:
|
|
67
|
+
```bash
|
|
68
|
+
uv add firstcash.py
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Usage:
|
|
72
|
+
```python
|
|
73
|
+
from firstcash import APIClient, StoreItemResponse
|
|
74
|
+
from asyncio import run
|
|
75
|
+
|
|
76
|
+
firstcash_client: APIClient = APIClient(api_key="<api key>")
|
|
77
|
+
|
|
78
|
+
async def main():
|
|
79
|
+
try:
|
|
80
|
+
response: StoreItemResponse = await firstcash_client.searchItemsByGeoLocation(
|
|
81
|
+
category_code=0, # Zero for all categories
|
|
82
|
+
search_latitude=39.105,
|
|
83
|
+
search_longitude=-94.593,
|
|
84
|
+
search_radius=20 # In miles
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
for item in response.results:
|
|
88
|
+
print(item)
|
|
89
|
+
finally:
|
|
90
|
+
await firstcash_client.closeAsyncRequestClient()
|
|
91
|
+
|
|
92
|
+
run(main())
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
(More examples provided in the [documentation](https://github.com/AgentLoneStar007/FirstCash.Py/tree/main/docs).)
|
|
96
|
+
|
|
97
|
+
## Contributing:
|
|
98
|
+
To build this library, a normal virtual environment is required (A.K.A. not UV).
|
|
99
|
+
First, install the build requirements:
|
|
100
|
+
```bash
|
|
101
|
+
python -m pip install -r requirements.txt
|
|
102
|
+
```
|
|
103
|
+
Then run the build script for either Linux or Windows:
|
|
104
|
+
```bash
|
|
105
|
+
# Linux
|
|
106
|
+
./scripts/build_and_install.sh
|
|
107
|
+
|
|
108
|
+
# Windows
|
|
109
|
+
scripts/build_and_install.bat
|
|
110
|
+
```
|
|
111
|
+
This will uninstall any existing versions of the library, build the newest version, and install it
|
|
112
|
+
into the environment.
|
|
113
|
+
|
|
114
|
+
I'll add more to this in the future!
|
|
115
|
+
|
|
116
|
+
## TODO:
|
|
117
|
+
- [ ] Add a test suite
|
|
118
|
+
- [ ] Add some documentation and examples
|
|
119
|
+
- [ ] Add more extensive error handling
|
|
120
|
+
- [ ] Add a cache to store recently queried items and store details (possibly)
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# FirstCash.py
|
|
2
|
+
|
|
3
|
+
#### *A basic Python library to communicate with the FirstCash mobile app API.*
|
|
4
|
+
|
|
5
|
+
This is a super basic library designed for querying the FirstCash mobile app API, which
|
|
6
|
+
allows the developer to search for stores, items, and more. One major advantage of this
|
|
7
|
+
library is it exposes API methods that aren't in use on the FirstCash [inventory website](https://search.cashamerica.com/),
|
|
8
|
+
such as limiting your search to specific stores or multiple categories.
|
|
9
|
+
|
|
10
|
+
Note: This library does require an API key. While one is very is easy to obtain if you just look
|
|
11
|
+
a little for it, I doubt they're legal to distribute, so you have to attain one on your own.
|
|
12
|
+
|
|
13
|
+
#### Features:
|
|
14
|
+
- Methods/attributes extensively explained within
|
|
15
|
+
- Use of modern Python built-in typing capabilities
|
|
16
|
+
- Asynchronous functionality
|
|
17
|
+
|
|
18
|
+
## Installation:
|
|
19
|
+
**This library requires at least Python 3.12 or higher.** <br>
|
|
20
|
+
|
|
21
|
+
### Pip:
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
Windows:
|
|
25
|
+
```commandline
|
|
26
|
+
py -3 -m pip install -U firstcash.py
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Linux/macOS/Unix:
|
|
30
|
+
```bash
|
|
31
|
+
python3 -m pip install -U firstcash.py
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### UV:
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
Windows/macOS/Linux/Unix:
|
|
38
|
+
```bash
|
|
39
|
+
uv add firstcash.py
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Usage:
|
|
43
|
+
```python
|
|
44
|
+
from firstcash import APIClient, StoreItemResponse
|
|
45
|
+
from asyncio import run
|
|
46
|
+
|
|
47
|
+
firstcash_client: APIClient = APIClient(api_key="<api key>")
|
|
48
|
+
|
|
49
|
+
async def main():
|
|
50
|
+
try:
|
|
51
|
+
response: StoreItemResponse = await firstcash_client.searchItemsByGeoLocation(
|
|
52
|
+
category_code=0, # Zero for all categories
|
|
53
|
+
search_latitude=39.105,
|
|
54
|
+
search_longitude=-94.593,
|
|
55
|
+
search_radius=20 # In miles
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
for item in response.results:
|
|
59
|
+
print(item)
|
|
60
|
+
finally:
|
|
61
|
+
await firstcash_client.closeAsyncRequestClient()
|
|
62
|
+
|
|
63
|
+
run(main())
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
(More examples provided in the [documentation](https://github.com/AgentLoneStar007/FirstCash.Py/tree/main/docs).)
|
|
67
|
+
|
|
68
|
+
## Contributing:
|
|
69
|
+
To build this library, a normal virtual environment is required (A.K.A. not UV).
|
|
70
|
+
First, install the build requirements:
|
|
71
|
+
```bash
|
|
72
|
+
python -m pip install -r requirements.txt
|
|
73
|
+
```
|
|
74
|
+
Then run the build script for either Linux or Windows:
|
|
75
|
+
```bash
|
|
76
|
+
# Linux
|
|
77
|
+
./scripts/build_and_install.sh
|
|
78
|
+
|
|
79
|
+
# Windows
|
|
80
|
+
scripts/build_and_install.bat
|
|
81
|
+
```
|
|
82
|
+
This will uninstall any existing versions of the library, build the newest version, and install it
|
|
83
|
+
into the environment.
|
|
84
|
+
|
|
85
|
+
I'll add more to this in the future!
|
|
86
|
+
|
|
87
|
+
## TODO:
|
|
88
|
+
- [ ] Add a test suite
|
|
89
|
+
- [ ] Add some documentation and examples
|
|
90
|
+
- [ ] Add more extensive error handling
|
|
91
|
+
- [ ] Add a cache to store recently queried items and store details (possibly)
|
|
@@ -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
|
+
)
|
|
@@ -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.")
|