lechuga 0.3__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.
lechuga-0.3/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Teofilo Sibileau
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.
lechuga-0.3/PKG-INFO ADDED
@@ -0,0 +1,103 @@
1
+ Metadata-Version: 2.3
2
+ Name: lechuga
3
+ Version: 0.3
4
+ Summary: retrieves AR$ rates from fixer.io API
5
+ License: MIT
6
+ Author: Teofilo Sibileau
7
+ Author-email: teo.sibileau@gmail.com
8
+ Requires-Python: >=3.10,<4.0
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Requires-Dist: click
16
+ Requires-Dist: colorama
17
+ Requires-Dist: pydantic (>=2.12.5,<3.0.0)
18
+ Requires-Dist: python-dotenv (>=1.2.2,<2.0.0)
19
+ Requires-Dist: requests
20
+ Requires-Dist: requests-cache
21
+ Requires-Dist: simplejson
22
+ Requires-Dist: tabulate
23
+ Requires-Dist: tenacity (>=9.1.4,<10.0.0)
24
+ Description-Content-Type: text/markdown
25
+
26
+ # Lechuga
27
+
28
+ :leaves:
29
+
30
+ "Lechuga" (lettuce) is a commonly used slang financial term in Argentina to refer to US Dollars.
31
+
32
+ ## Installation
33
+
34
+ Requirements:
35
+
36
+ + A [fixer.io](https://fixer.io/quickstart) free account
37
+ + python 3.7+
38
+ + [Poetry](https://python-poetry.org/)
39
+
40
+ ```bash
41
+ $ poetry add git+https://github.com/drkloc/lechuga.git
42
+ ```
43
+
44
+ Or install directly with pip:
45
+
46
+ ```bash
47
+ $ pip install git+https://github.com/drkloc/lechuga.git
48
+ ```
49
+
50
+ Setup an environment variable with the Fixer IO API access key:
51
+
52
+ ```
53
+ export FIXERIOKEY=YOUR_API_KEY
54
+ ```
55
+
56
+ ## What it does
57
+
58
+ It retrieves data from the `fixer.io` API && prints it using pretty colors right to the cli output.
59
+
60
+
61
+ ## How it works
62
+
63
+ ### Help
64
+
65
+ ```bash
66
+ $ lechuga --help
67
+
68
+ Usage: lechuga.py [OPTIONS]
69
+
70
+ Options:
71
+ --n INTEGER How far in the past should we go?
72
+ --help Show this message and exit.
73
+ ```
74
+
75
+ ### Get latest n rates
76
+
77
+ ```bash
78
+ ➔ lechuga --n 20
79
+
80
+ Fecha USD EURO
81
+ ---------- ------- --------
82
+ 2018-11-11 35.42 40.1
83
+ 2018-11-12 35.54 39.92
84
+ 2018-11-13 36.01 40.73
85
+ 2018-11-14 35.89 40.6
86
+ 2018-11-15 36.04 40.82
87
+ 2018-11-16 35.92 41.02
88
+ 2018-11-17 35.76 40.84
89
+ 2018-11-18 35.78 40.84
90
+ 2018-11-19 35.91 41.13
91
+ 2018-11-20 36.18 41.14
92
+ 2018-11-21 36.27 41.3
93
+ 2018-11-22 36.43 41.54
94
+ 2018-11-23 37.56 42.61
95
+ 2018-11-24 37.56 42.61
96
+ 2018-11-25 37.58 42.61
97
+ 2018-11-26 39.08 44.29
98
+ 2018-11-27 38.54 43.55
99
+ 2018-11-28 38.45 43.71
100
+ 2018-11-29 37.73 42.98
101
+ 2018-11-30 37.73 42.67
102
+ ```
103
+
lechuga-0.3/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # Lechuga
2
+
3
+ :leaves:
4
+
5
+ "Lechuga" (lettuce) is a commonly used slang financial term in Argentina to refer to US Dollars.
6
+
7
+ ## Installation
8
+
9
+ Requirements:
10
+
11
+ + A [fixer.io](https://fixer.io/quickstart) free account
12
+ + python 3.7+
13
+ + [Poetry](https://python-poetry.org/)
14
+
15
+ ```bash
16
+ $ poetry add git+https://github.com/drkloc/lechuga.git
17
+ ```
18
+
19
+ Or install directly with pip:
20
+
21
+ ```bash
22
+ $ pip install git+https://github.com/drkloc/lechuga.git
23
+ ```
24
+
25
+ Setup an environment variable with the Fixer IO API access key:
26
+
27
+ ```
28
+ export FIXERIOKEY=YOUR_API_KEY
29
+ ```
30
+
31
+ ## What it does
32
+
33
+ It retrieves data from the `fixer.io` API && prints it using pretty colors right to the cli output.
34
+
35
+
36
+ ## How it works
37
+
38
+ ### Help
39
+
40
+ ```bash
41
+ $ lechuga --help
42
+
43
+ Usage: lechuga.py [OPTIONS]
44
+
45
+ Options:
46
+ --n INTEGER How far in the past should we go?
47
+ --help Show this message and exit.
48
+ ```
49
+
50
+ ### Get latest n rates
51
+
52
+ ```bash
53
+ ➔ lechuga --n 20
54
+
55
+ Fecha USD EURO
56
+ ---------- ------- --------
57
+ 2018-11-11 35.42 40.1
58
+ 2018-11-12 35.54 39.92
59
+ 2018-11-13 36.01 40.73
60
+ 2018-11-14 35.89 40.6
61
+ 2018-11-15 36.04 40.82
62
+ 2018-11-16 35.92 41.02
63
+ 2018-11-17 35.76 40.84
64
+ 2018-11-18 35.78 40.84
65
+ 2018-11-19 35.91 41.13
66
+ 2018-11-20 36.18 41.14
67
+ 2018-11-21 36.27 41.3
68
+ 2018-11-22 36.43 41.54
69
+ 2018-11-23 37.56 42.61
70
+ 2018-11-24 37.56 42.61
71
+ 2018-11-25 37.58 42.61
72
+ 2018-11-26 39.08 44.29
73
+ 2018-11-27 38.54 43.55
74
+ 2018-11-28 38.45 43.71
75
+ 2018-11-29 37.73 42.98
76
+ 2018-11-30 37.73 42.67
77
+ ```
File without changes
@@ -0,0 +1,28 @@
1
+ import os
2
+ import sqlite3
3
+ import requests_cache
4
+ from dotenv import load_dotenv
5
+ from colorama import init
6
+
7
+ load_dotenv()
8
+
9
+ SCRIPT_ROOT = os.path.dirname(os.path.realpath(__file__))
10
+ DB_PATH = os.path.join(SCRIPT_ROOT, "lechuga.sqlite")
11
+
12
+ init(autoreset=True)
13
+ requests_cache.install_cache(
14
+ os.path.join(SCRIPT_ROOT, "lechuga"), backend="sqlite", expire_after=60
15
+ )
16
+
17
+
18
+ def get_db_connection(db_path=None):
19
+ conn = sqlite3.connect(db_path or DB_PATH)
20
+ conn.execute("""
21
+ CREATE TABLE IF NOT EXISTS rates (
22
+ date TEXT PRIMARY KEY,
23
+ usd REAL NOT NULL,
24
+ euro REAL NOT NULL
25
+ )
26
+ """)
27
+ conn.commit()
28
+ return conn
@@ -0,0 +1,106 @@
1
+ import click
2
+ from datetime import date, datetime, timedelta
3
+ import os
4
+ import logging
5
+ import requests
6
+ from requests.exceptions import HTTPError
7
+ from colorama import Fore, Back, Style
8
+ from tabulate import tabulate
9
+ from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception
10
+
11
+ from lechuga.config import get_db_connection
12
+ from lechuga.models import Rate, cached_rate
13
+
14
+
15
+ def _is_retryable(exception):
16
+ return (
17
+ isinstance(exception, HTTPError)
18
+ and exception.response is not None
19
+ and exception.response.status_code == 429
20
+ )
21
+
22
+
23
+ def _trend(current, previous):
24
+ pct = (current - previous) / previous * 100
25
+ if pct > 3:
26
+ return " 🚀"
27
+ if pct > 0:
28
+ return " 📈"
29
+ if pct < -3:
30
+ return " 💥"
31
+ if pct < 0:
32
+ return " 📉"
33
+ return " ➡️"
34
+
35
+
36
+ class Lechuga:
37
+ def __init__(self, depth=1):
38
+ self.api_key = os.environ.get("FIXERIOKEY", False)
39
+ if not self.api_key:
40
+ raise Exception("Please set the FIXERIOKEY environ variable")
41
+ self.depth = depth
42
+ self.p = []
43
+ self.db_conn = get_db_connection()
44
+ self.refresh()
45
+
46
+ @cached_rate
47
+ @retry(
48
+ retry=retry_if_exception(_is_retryable),
49
+ wait=wait_exponential(multiplier=1, min=1, max=10),
50
+ stop=stop_after_attempt(3),
51
+ )
52
+ def fetch_rate(self, date_str):
53
+ API = "http://data.fixer.io/api/%s?access_key=%s&format=1&symbols=USD,ARS"
54
+ uri = API % (date_str, self.api_key)
55
+ r = requests.get(uri)
56
+ r.raise_for_status()
57
+ r = r.json()
58
+ return Rate(
59
+ date=r["date"],
60
+ usd=r["rates"]["ARS"] / r["rates"]["USD"],
61
+ euro=r["rates"]["ARS"],
62
+ )
63
+
64
+ def refresh(self):
65
+ last = False
66
+ while self.depth:
67
+ date_str = (
68
+ date.today().strftime("%Y-%m-%d")
69
+ if not last
70
+ else last.strftime("%Y-%m-%d")
71
+ )
72
+ rate = self.fetch_rate(date_str)
73
+ self.p.append(rate.model_dump())
74
+ last = datetime.strptime(rate.date, "%Y-%m-%d") - timedelta(days=1)
75
+ self.depth -= 1
76
+
77
+ def print_it(self):
78
+ print("")
79
+ h = [
80
+ Back.YELLOW + Fore.BLACK + " Fecha " + Style.RESET_ALL,
81
+ Back.GREEN + Fore.WHITE + " USD " + Style.RESET_ALL,
82
+ Back.BLUE + Fore.WHITE + " EURO " + Style.RESET_ALL,
83
+ ]
84
+ rows = list(reversed(self.p))
85
+ o = []
86
+ for idx, i in enumerate(rows):
87
+ usd_str = "%.2f" % i["usd"]
88
+ euro_str = "%.2f" % i["euro"]
89
+ if idx > 0:
90
+ usd_str += _trend(i["usd"], rows[idx - 1]["usd"])
91
+ euro_str += _trend(i["euro"], rows[idx - 1]["euro"])
92
+ o.append([i["date"], usd_str, euro_str])
93
+ print(tabulate(o, headers=h))
94
+ print("")
95
+
96
+
97
+ @click.command()
98
+ @click.option("--n", default=4, help="How far in the past should we go?")
99
+ def run(n):
100
+ client = Lechuga(n)
101
+ client.print_it()
102
+
103
+
104
+ if __name__ == "__main__":
105
+ logging.captureWarnings(True)
106
+ run()
@@ -0,0 +1,30 @@
1
+ import functools
2
+
3
+ from pydantic import BaseModel
4
+
5
+
6
+ class Rate(BaseModel):
7
+ date: str
8
+ usd: float
9
+ euro: float
10
+
11
+
12
+ def cached_rate(fn):
13
+ @functools.wraps(fn)
14
+ def wrapper(self, date_str):
15
+ row = self.db_conn.execute(
16
+ "SELECT date, usd, euro FROM rates WHERE date = ?", (date_str,)
17
+ ).fetchone()
18
+ if row:
19
+ return Rate(date=row[0], usd=row[1], euro=row[2])
20
+
21
+ rate = fn(self, date_str)
22
+
23
+ self.db_conn.execute(
24
+ "INSERT OR IGNORE INTO rates (date, usd, euro) VALUES (?, ?, ?)",
25
+ (rate.date, rate.usd, rate.euro),
26
+ )
27
+ self.db_conn.commit()
28
+ return rate
29
+
30
+ return wrapper
@@ -0,0 +1,32 @@
1
+ [tool.poetry]
2
+ name = "lechuga"
3
+ version = "0.3"
4
+ description = "retrieves AR$ rates from fixer.io API"
5
+ authors = ["Teofilo Sibileau <teo.sibileau@gmail.com>"]
6
+ license = "MIT"
7
+ readme = "README.md"
8
+ packages = [{include = "lechuga"}]
9
+
10
+ [tool.poetry.scripts]
11
+ lechuga = "lechuga.lechuga:run"
12
+
13
+ [tool.poetry.dependencies]
14
+ python = "^3.10"
15
+ click = "*"
16
+ requests = "*"
17
+ requests-cache = "*"
18
+ colorama = "*"
19
+ tabulate = "*"
20
+ simplejson = "*"
21
+ python-dotenv = "^1.2.2"
22
+ pydantic = "^2.12.5"
23
+ tenacity = "^9.1.4"
24
+
25
+ [tool.poetry.group.dev.dependencies]
26
+ ipython = "*"
27
+ ipdb = "^0.13.13"
28
+ pytest = "^9.0.2"
29
+
30
+ [build-system]
31
+ requires = ["poetry-core"]
32
+ build-backend = "poetry.core.masonry.api"