Skip to content

Commit 77e2b35

Browse files
committed
v1.0.0
0 parents  commit 77e2b35

10 files changed

Lines changed: 446 additions & 0 deletions

File tree

.github/workflows/pypi-publish.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: pypi-publish
2+
3+
on:
4+
release:
5+
types:
6+
- created
7+
8+
jobs:
9+
publish:
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- uses: actions/checkout@v2
14+
15+
- uses: actions/setup-python@v2
16+
with:
17+
python-version: 3.9
18+
19+
- name: "Installs and upgrades pip, dependencies and the package"
20+
run: |
21+
python3 -m pip install --upgrade pip
22+
python3 -m pip install setuptools wheel twine
23+
pip install -r requirements.txt
24+
python3 setup.py install
25+
26+
- name: Build and publish package
27+
run: |
28+
python3 setup.py sdist bdist_wheel
29+
python3 -m twine upload dist/*
30+
env:
31+
TWINE_USERNAME: __token__
32+
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
33+
TWINE_REPOSITORY: pypi

.github/workflows/unittest.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: Unit test
2+
3+
on: [push, pull_request]
4+
5+
jobs:
6+
unit_test:
7+
runs-on: ubuntu-latest
8+
strategy:
9+
matrix:
10+
os: [ubuntu-latest, macos-latest, windows-latest]
11+
python-version: [3.6, 3.7, 3.8, 3.9]
12+
13+
env:
14+
EXCHANGE_RATES_API_KEY: ${{ secrets.API_KEY }}
15+
16+
steps:
17+
- uses: actions/checkout@v2
18+
19+
- name: Install dependencies, and python_core module
20+
run: |
21+
pip3 install -r requirements.txt
22+
python setup.py install --user
23+
24+
- name: Run test
25+
run: |
26+
python3 -m unittest tests/test_python_exchange_rates.py

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
build
2+
dist
3+
**/__pycache__
4+
abstract_python_exchange_rates.egg-info
5+
dev_test.py
6+
.vscode
7+
*.history

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2021 Abstract
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.

README.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# AbstractAPI python-exchange-rates library
2+
3+
Integrate the powerful [Exchange Rates API from Abstract](https://www.abstractapi.com/exchange-rate-api) in your Python project in a few lines of code.
4+
5+
The Exchange Rate API is an REST API that allows you to:
6+
7+
- look up the latest exchange rates for 80+ currencies via the *live* endpoint
8+
- get historical exchange rates using the *historical* endpoint
9+
- convert an arbitrary amount from one currency to another using the *convert* endpoint
10+
11+
It's very simple to use: you only need to submit your API key and a currency symbol (such as "USD"), and the API will respond with current exchange rate, historical data, or convertion rates.
12+
13+
14+
# Documentation
15+
16+
## Supported Python Versions
17+
18+
This library supports the **Python version 3.6** and higher.
19+
20+
## Installation
21+
22+
You can install **python-exchange-rates** via PyPi or by downloading the source.
23+
24+
### Via PyPi:
25+
26+
**python-exchange-rates** is available on PyPi as the
27+
[`abstract-python-exchange-rates`](https://pypi.org/project/abstract-python-exchange-rates/) package:
28+
29+
```bash
30+
pip install abstract-python-exchange-rates
31+
```
32+
33+
## API key
34+
35+
Get your API key for free and without hassle from the [Abstact website](https://app.abstractapi.com/users/signup?target=/api/exchange-rates/pricing/select).
36+
37+
## Quickstart
38+
39+
### Verify email
40+
41+
```python
42+
import pprint
43+
from python_exchange_rates import AbstractExchangeRates
44+
45+
EXCHANGE_RATES_API_KEY = "YYYYYY"; # Get your API Key from https://app.abstractapi.com/api/exchange-rates/documentation
46+
47+
AbstractExchangeRates.configure(EXCHANGE_RATES_API_KEY)
48+
49+
# Get live exchange rates using Abstract's Exchange Rates API and Python
50+
response = AbstractExchangeRates.live("EUR")
51+
pprint(response)
52+
53+
# Get historical exchange rates using Abstract's Exchange Rates API and Python
54+
response = AbstractExchangeRates.historical('EUR', '2021-05-01');
55+
pprint(response)
56+
57+
# Convert currency using Abstract's Exchange Rates API and Python
58+
response = AbstractExchangeRates.convert('EUR', 'USD');
59+
pprint(response)
60+
```
61+
62+
## API response
63+
64+
The API response contains the following fields:
65+
66+
### `live` response parameters
67+
| Parameter| Type| Details |
68+
| - | - | - |
69+
| base | String | The base currency used to get the exchange rates. |
70+
| last_updated | String | The Unix timestamp of when the returned data was last updated. |
71+
| exchange_rates | Object | A JSON Object containing each of the target currency as the key and its exchange rate versus the base currency as that key's value. |
72+
73+
### `historical` response parameters
74+
75+
| Parameter | Type | Details |
76+
| - | - | - |
77+
| base | String | The base currency used to get the exchange rates. |
78+
| date | String | The date the currencies were pulled from, per the successful request. |
79+
| exchange_rates | Object | A JSON Object containing each of the target currency as the key and its exchange rate versus the base currency as that key's value. |
80+
81+
### `convert` response parameters
82+
83+
| Parameter | Type | Details |
84+
| - | - | - |
85+
| base | String | The base currency used to get the exchange rates. |
86+
| target | String | The target currency that the base_amount was converted into. |
87+
| date | String | The date the currencies were pulled from, per the successful request. |
88+
| base_amount | Float | The amount of the base currency from the request. |
89+
| converted_amount | Float | The amount of the target currency that the base_amount has been converted into |
90+
| exchange_rate | Float | The exchange rate used to convert the base_amount from the base currency to the target currency |
91+
92+
## Detailed documentation
93+
94+
You will find additional information and request examples in the [Abstract help page](https://app.abstractapi.com/api/exchange-rates/documentation).
95+
96+
## Getting help
97+
98+
If you need help installing or using the library, please contact [Abstract's Support](https://app.abstractapi.com/api/exchange-rates/support).
99+
100+
For bug report and feature suggestion, please use [this repository issues page](https://github.com/abstractapi/python-exchange-rates/issues).
101+
102+
# Contribution
103+
104+
Contributions are always welcome, as they improve the quality of the libraries we provide to the community.
105+
106+
Please provide your changes covered by the appropriate unit tests, and post them in the [pull requests page](https://github.com/abstractapi/python-exchange-rates/pulls).
107+
108+
## Setup
109+
110+
To install the requirements, run:
111+
112+
```bash
113+
python3 setup.py install --user
114+
```
115+
116+
Once you implementer all your changes and the unit tests, run the following command to run the tests:
117+
118+
```bash
119+
EMAIL_VAL_API_KEY=YYYYYY python3 tests/test_python_exchange_rates.py
120+
```

python_exchange_rates/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .python_exchange_rates import AbstractExchangeRates
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
from python_core import HttpEndpoint
2+
from collections import namedtuple
3+
4+
class AbstractExchangeRates:
5+
api_key = None
6+
endpoint_subdomain = 'exchange-rates'
7+
global_req_params = {
8+
'lang' : 'python'
9+
}
10+
11+
@staticmethod
12+
def configure(api_key):
13+
AbstractExchangeRates.api_key = api_key
14+
15+
@staticmethod
16+
def live(base, target=""):
17+
18+
http_endpoint = HttpEndpoint(
19+
endpoint_subdomain=AbstractExchangeRates.endpoint_subdomain,
20+
global_req_params=AbstractExchangeRates.global_req_params,
21+
path='live/'
22+
)
23+
24+
if AbstractExchangeRates.api_key is None:
25+
exception_type = "APINotConfiguredException"
26+
exception_msg = "Can't use the endpoint unless it's configured, use configure(api_key)"
27+
raise Exception(
28+
"[{}] : {}".format(exception_type, exception_msg)
29+
)
30+
31+
try:
32+
req_params = {
33+
"api_key" : AbstractExchangeRates.api_key,
34+
"base" : base
35+
}
36+
37+
if target != "":
38+
req_params['target'] = target
39+
40+
response = http_endpoint.get(
41+
req_params=req_params
42+
)
43+
# Convert the dict to an object
44+
for key in response:
45+
if (type(response[key]) == dict):
46+
EmbeddedObject = namedtuple('EmbeddedObject', response[key])
47+
embedded_obj = EmbeddedObject(**response[key])
48+
response[key] = embedded_obj
49+
ResponseObject = namedtuple('ResponseObject', response.keys())
50+
response_obj = ResponseObject(**response)
51+
return response_obj
52+
53+
except Exception as e:
54+
# HttpEndpoint has expressive exceptions
55+
raise SystemExit(e)
56+
57+
@staticmethod
58+
def historical(base, date, target=""):
59+
60+
http_endpoint = HttpEndpoint(
61+
endpoint_subdomain=AbstractExchangeRates.endpoint_subdomain,
62+
global_req_params=AbstractExchangeRates.global_req_params,
63+
path='historical/'
64+
)
65+
66+
if AbstractExchangeRates.api_key is None:
67+
exception_type = "APINotConfiguredException"
68+
exception_msg = "Can't use the endpoint unless it's configured, use configure(api_key)"
69+
raise Exception(
70+
"[{}] : {}".format(exception_type, exception_msg)
71+
)
72+
73+
try:
74+
req_params = {
75+
"api_key" : AbstractExchangeRates.api_key,
76+
"base" : base,
77+
"date" : date
78+
}
79+
80+
if target != "":
81+
req_params['target'] = target
82+
83+
response = http_endpoint.get(
84+
req_params=req_params
85+
)
86+
# Convert the dict to an object
87+
for key in response:
88+
if (type(response[key]) == dict):
89+
EmbeddedObject = namedtuple('EmbeddedObject', response[key])
90+
embedded_obj = EmbeddedObject(**response[key])
91+
response[key] = embedded_obj
92+
ResponseObject = namedtuple('ResponseObject', response.keys())
93+
response_obj = ResponseObject(**response)
94+
return response_obj
95+
96+
except Exception as e:
97+
# HttpEndpoint has expressive exceptions
98+
raise SystemExit(e)
99+
100+
@staticmethod
101+
def convert(base, target, date="", base_amount=""):
102+
103+
http_endpoint = HttpEndpoint(
104+
endpoint_subdomain=AbstractExchangeRates.endpoint_subdomain,
105+
global_req_params=AbstractExchangeRates.global_req_params,
106+
path='convert/'
107+
)
108+
109+
if AbstractExchangeRates.api_key is None:
110+
exception_type = "APINotConfiguredException"
111+
exception_msg = "Can't use the endpoint unless it's configured, use configure(api_key)"
112+
raise Exception(
113+
"[{}] : {}".format(exception_type, exception_msg)
114+
)
115+
116+
try:
117+
req_params = {
118+
"api_key" : AbstractExchangeRates.api_key,
119+
"base" : base,
120+
"target" : target
121+
}
122+
123+
if date != "":
124+
req_params['date'] = date
125+
126+
if base_amount != "":
127+
req_params['base_amount'] = base_amount
128+
129+
response = http_endpoint.get(
130+
req_params=req_params
131+
)
132+
# Convert the dict to an object
133+
for key in response:
134+
if (type(response[key]) == dict):
135+
EmbeddedObject = namedtuple('EmbeddedObject', response[key])
136+
embedded_obj = EmbeddedObject(**response[key])
137+
response[key] = embedded_obj
138+
ResponseObject = namedtuple('ResponseObject', response.keys())
139+
response_obj = ResponseObject(**response)
140+
return response_obj
141+
142+
except Exception as e:
143+
# HttpEndpoint has expressive exceptions
144+
raise SystemExit(e)

requirements.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
certifi==2020.12.5
2+
chardet==4.0.0
3+
idna==2.10
4+
plotly==4.14.3
5+
requests==2.25.1
6+
urllib3==1.26.4
7+
wincertstore==0.2
8+
python-dotenv==0.17.0
9+
abstract_python_core==1.1.0

0 commit comments

Comments
 (0)