From 5e497d9c53a1c2e8c65f1a903789b9039dfbdc61 Mon Sep 17 00:00:00 2001 From: Leodanis Pozo Ramos Date: Mon, 30 Oct 2023 15:59:12 +0100 Subject: [PATCH 1/5] Sample code for the article on underscores in Python names --- python-double-underscore/README.md | 3 ++ python-double-underscore/article_v1.py | 39 ++++++++++++++++++++++++++ python-double-underscore/article_v2.py | 21 ++++++++++++++ python-double-underscore/cart.py | 15 ++++++++++ python-double-underscore/count.py | 15 ++++++++++ python-double-underscore/csv_data.py | 19 +++++++++++++ python-double-underscore/passenger.py | 7 +++++ python-double-underscore/point.py | 26 +++++++++++++++++ python-double-underscore/shapes.py | 23 +++++++++++++++ python-double-underscore/tutorial.py | 7 +++++ 10 files changed, 175 insertions(+) create mode 100644 python-double-underscore/README.md create mode 100644 python-double-underscore/article_v1.py create mode 100644 python-double-underscore/article_v2.py create mode 100644 python-double-underscore/cart.py create mode 100644 python-double-underscore/count.py create mode 100644 python-double-underscore/csv_data.py create mode 100644 python-double-underscore/passenger.py create mode 100644 python-double-underscore/point.py create mode 100644 python-double-underscore/shapes.py create mode 100644 python-double-underscore/tutorial.py diff --git a/python-double-underscore/README.md b/python-double-underscore/README.md new file mode 100644 index 0000000000..4fdba926b3 --- /dev/null +++ b/python-double-underscore/README.md @@ -0,0 +1,3 @@ +# Single and Double Underscores in Python Names: Their Meaning + +This folder provides the code examples for the Real Python tutorial [Single and Double Underscores in Python Names: Their Meaning](https://realpython.com/python-double-underscore/). diff --git a/python-double-underscore/article_v1.py b/python-double-underscore/article_v1.py new file mode 100644 index 0000000000..d4c80f2afd --- /dev/null +++ b/python-double-underscore/article_v1.py @@ -0,0 +1,39 @@ +import datetime + + +class Article: + def __init__(self, title, author, pub_date=None): + self.title = title + self.author = author + self.pub_date = self.update_pub_date(pub_date) + + def update_pub_date(self, pub_date=None): + if pub_date is None: + date = datetime.datetime.now() + else: + date = datetime.datetime.fromisoformat(pub_date) + return date + + def compute_age(self): + now = datetime.datetime.now() + return now - self.pub_date + + +class Article: + def __init__(self, title, author, pub_date=None): + self.title = title + self.author = author + self.pub_date = self.__update_pub_date(pub_date) + + def update_pub_date(self, pub_date=None): + if pub_date is None: + date = datetime.datetime.now() + else: + date = datetime.datetime.fromisoformat(pub_date) + return date + + __update_pub_date = update_pub_date + + def compute_age(self): + now = datetime.datetime.now() + return now - self.pub_date diff --git a/python-double-underscore/article_v2.py b/python-double-underscore/article_v2.py new file mode 100644 index 0000000000..0e07d90914 --- /dev/null +++ b/python-double-underscore/article_v2.py @@ -0,0 +1,21 @@ +import datetime + + +class Article: + def __init__(self, title, author, pub_date=None): + self.title = title + self.author = author + self.pub_date = self.__update_pub_date(pub_date) + + def update_pub_date(self, pub_date=None): + if pub_date is None: + date = datetime.datetime.now() + else: + date = datetime.datetime.fromisoformat(pub_date) + return date + + __update_pub_date = update_pub_date + + def compute_age(self): + now = datetime.datetime.now() + return now - self.pub_date diff --git a/python-double-underscore/cart.py b/python-double-underscore/cart.py new file mode 100644 index 0000000000..4ccd2bf5a4 --- /dev/null +++ b/python-double-underscore/cart.py @@ -0,0 +1,15 @@ +class ShoppingCart: + def __init__(self, customer_id): + self.customer_id = customer_id + self.products = [] + + def add_product(self, product): + self.products.append(product) + + def get_products(self): + return self.products + + def __len__(self): + return len(self.products) + + # Implementation... diff --git a/python-double-underscore/count.py b/python-double-underscore/count.py new file mode 100644 index 0000000000..4fe666c85b --- /dev/null +++ b/python-double-underscore/count.py @@ -0,0 +1,15 @@ +_count = 0 + + +def increment(): + global _count + _count += 1 + + +def decrement(): + global _count + _count -= 1 + + +def get_count(): + return _count diff --git a/python-double-underscore/csv_data.py b/python-double-underscore/csv_data.py new file mode 100644 index 0000000000..e018c5692c --- /dev/null +++ b/python-double-underscore/csv_data.py @@ -0,0 +1,19 @@ +# csv_data.py + +import csv + + +class CSVFileManager: + def __init__(self, file_path): + self.file_path = file_path + + def read_csv(self): + return self._read(delimiter=",") + + def read_tsv(self): + return self._read(delimiter="\t") + + def _read(self, delimiter): + with open(self.file_path, mode="r") as file: + data = [row for row in csv.reader(file, delimiter=delimiter)] + return data diff --git a/python-double-underscore/passenger.py b/python-double-underscore/passenger.py new file mode 100644 index 0000000000..aa98178745 --- /dev/null +++ b/python-double-underscore/passenger.py @@ -0,0 +1,7 @@ +class Passenger: + def __init__(self, name, class_, seat): + self.name = name + self.class_ = class_ + self.seat = seat + + # Implementation... diff --git a/python-double-underscore/point.py b/python-double-underscore/point.py new file mode 100644 index 0000000000..c9fb0261eb --- /dev/null +++ b/python-double-underscore/point.py @@ -0,0 +1,26 @@ +class Point: + def __init__(self, x, y): + self._x = x + self._y = y + + @property + def x(self): + return self._x + + @x.setter + def x(self, value): + self._x = _validate(value) + + @property + def y(self): + return self._y + + @y.setter + def y(self, value): + self._y = _validate(value) + + +def _validate(value): + if not isinstance(value, int | float): + raise ValueError("number expected") + return value diff --git a/python-double-underscore/shapes.py b/python-double-underscore/shapes.py new file mode 100644 index 0000000000..b92546885e --- /dev/null +++ b/python-double-underscore/shapes.py @@ -0,0 +1,23 @@ +_PI = 3.14 + + +class Circle: + def __init__(self, radius): + self.radius = _validate(radius) + + def calculate_area(self): + return round(_PI * self.radius**2, 2) + + +class Square: + def __init__(self, side): + self.side = _validate(side) + + def calculate_area(self): + return round(self.side**2, 2) + + +def _validate(value): + if not isinstance(value, int | float) or value <= 0: + raise ValueError("positive number expected") + return value diff --git a/python-double-underscore/tutorial.py b/python-double-underscore/tutorial.py new file mode 100644 index 0000000000..9d24e9d797 --- /dev/null +++ b/python-double-underscore/tutorial.py @@ -0,0 +1,7 @@ +from article_v1 import Article + + +class Tutorial(Article): + def update_pub_date(self, pub_date=None): + date = super().update_pub_date(pub_date) + return date.strftime("%Y-%m-%d") From 852d2b6ee701c797373111b0afbc75e7f246bd9c Mon Sep 17 00:00:00 2001 From: Leodanis Pozo Ramos Date: Mon, 30 Oct 2023 16:01:35 +0100 Subject: [PATCH 2/5] Fix linter issues --- python-double-underscore/article_v1.py | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/python-double-underscore/article_v1.py b/python-double-underscore/article_v1.py index d4c80f2afd..756188c595 100644 --- a/python-double-underscore/article_v1.py +++ b/python-double-underscore/article_v1.py @@ -17,23 +17,3 @@ def update_pub_date(self, pub_date=None): def compute_age(self): now = datetime.datetime.now() return now - self.pub_date - - -class Article: - def __init__(self, title, author, pub_date=None): - self.title = title - self.author = author - self.pub_date = self.__update_pub_date(pub_date) - - def update_pub_date(self, pub_date=None): - if pub_date is None: - date = datetime.datetime.now() - else: - date = datetime.datetime.fromisoformat(pub_date) - return date - - __update_pub_date = update_pub_date - - def compute_age(self): - now = datetime.datetime.now() - return now - self.pub_date From 071ee3afc909f63a6755200864443ba23c974bf2 Mon Sep 17 00:00:00 2001 From: Leodanis Pozo Ramos Date: Wed, 8 Nov 2023 15:49:15 +0100 Subject: [PATCH 3/5] Remove the Article-Tutorial example --- python-double-underscore/article_v1.py | 19 ------------------- python-double-underscore/article_v2.py | 21 --------------------- python-double-underscore/tutorial.py | 7 ------- 3 files changed, 47 deletions(-) delete mode 100644 python-double-underscore/article_v1.py delete mode 100644 python-double-underscore/article_v2.py delete mode 100644 python-double-underscore/tutorial.py diff --git a/python-double-underscore/article_v1.py b/python-double-underscore/article_v1.py deleted file mode 100644 index 756188c595..0000000000 --- a/python-double-underscore/article_v1.py +++ /dev/null @@ -1,19 +0,0 @@ -import datetime - - -class Article: - def __init__(self, title, author, pub_date=None): - self.title = title - self.author = author - self.pub_date = self.update_pub_date(pub_date) - - def update_pub_date(self, pub_date=None): - if pub_date is None: - date = datetime.datetime.now() - else: - date = datetime.datetime.fromisoformat(pub_date) - return date - - def compute_age(self): - now = datetime.datetime.now() - return now - self.pub_date diff --git a/python-double-underscore/article_v2.py b/python-double-underscore/article_v2.py deleted file mode 100644 index 0e07d90914..0000000000 --- a/python-double-underscore/article_v2.py +++ /dev/null @@ -1,21 +0,0 @@ -import datetime - - -class Article: - def __init__(self, title, author, pub_date=None): - self.title = title - self.author = author - self.pub_date = self.__update_pub_date(pub_date) - - def update_pub_date(self, pub_date=None): - if pub_date is None: - date = datetime.datetime.now() - else: - date = datetime.datetime.fromisoformat(pub_date) - return date - - __update_pub_date = update_pub_date - - def compute_age(self): - now = datetime.datetime.now() - return now - self.pub_date diff --git a/python-double-underscore/tutorial.py b/python-double-underscore/tutorial.py deleted file mode 100644 index 9d24e9d797..0000000000 --- a/python-double-underscore/tutorial.py +++ /dev/null @@ -1,7 +0,0 @@ -from article_v1 import Article - - -class Tutorial(Article): - def update_pub_date(self, pub_date=None): - date = super().update_pub_date(pub_date) - return date.strftime("%Y-%m-%d") From 69838d2ab25cf8e1f5f9870cc26b4d0e734317ae Mon Sep 17 00:00:00 2001 From: KateFinegan <95366190+KateFinegan@users.noreply.github.com> Date: Fri, 17 Nov 2023 17:26:00 -0700 Subject: [PATCH 4/5] README LE --- python-double-underscore/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python-double-underscore/README.md b/python-double-underscore/README.md index 4fdba926b3..e5603ec144 100644 --- a/python-double-underscore/README.md +++ b/python-double-underscore/README.md @@ -1,3 +1,3 @@ -# Single and Double Underscores in Python Names: Their Meaning +# Single and Double Underscores in Python Names -This folder provides the code examples for the Real Python tutorial [Single and Double Underscores in Python Names: Their Meaning](https://realpython.com/python-double-underscore/). +This folder provides the code examples for the Real Python tutorial [Single and Double Underscores in Python Names](https://realpython.com/python-double-underscore/). From 63235ed25ac2e66cbade0fa365affdc4b6bef47b Mon Sep 17 00:00:00 2001 From: profcalculus Date: Mon, 20 Nov 2023 16:10:04 +0200 Subject: [PATCH 5/5] Rich showcase (#458) * Create README.md * Add files via upload * Linter fixes * README LE * Update README.md * TR comments implemented * Fixed README to reference the JSON file * Rename directory * Final QA * Update imports * Rename final example --------- Co-authored-by: KateFinegan <95366190+KateFinegan@users.noreply.github.com> Co-authored-by: Philipp Acsany <68116180+acsany@users.noreply.github.com> Co-authored-by: gahjelle --- python-rich-package/README.md | 35 ++ python-rich-package/crypto_data.json | 702 ++++++++++++++++++++++ python-rich-package/dynamic_status.py | 17 + python-rich-package/get_crypto_data.py | 25 + python-rich-package/live_table.py | 63 ++ python-rich-package/log_exception.py | 17 + python-rich-package/noble_gases.py | 81 +++ python-rich-package/progress_indicator.py | 13 + 8 files changed, 953 insertions(+) create mode 100644 python-rich-package/README.md create mode 100644 python-rich-package/crypto_data.json create mode 100644 python-rich-package/dynamic_status.py create mode 100644 python-rich-package/get_crypto_data.py create mode 100644 python-rich-package/live_table.py create mode 100644 python-rich-package/log_exception.py create mode 100644 python-rich-package/noble_gases.py create mode 100644 python-rich-package/progress_indicator.py diff --git a/python-rich-package/README.md b/python-rich-package/README.md new file mode 100644 index 0000000000..e0278ddb16 --- /dev/null +++ b/python-rich-package/README.md @@ -0,0 +1,35 @@ +# The Python Rich Package: Unleash the Power of Console Text + +This repository holds the sample code for the Real Python [showcase](https://realpython.com/python-rich-package). + +## Dependencies + +You should start by creating a virtual environment: + +```console +$ python -m venv venv +$ source venv/bin/activate +``` + +Next, install `rich` with `pip`: + +```console +(venv) $ python -m pip install rich +``` + +The tutorial includes static sample data for the scrolling cryptocurrency table. This is also included in this repository as `crypto_data.json`. +If you want to download your own fresh data, then you'll need the `requests` package: + +```console +(venv) $ python -m pip install requests +``` + +The code to perform the download is in `get_crypto_data.py`. This demo code demonstrates a single request, which it then dumps to the screen. For a real-time application, you'd need to execute this request and process the data in a loop. The [CoinLore website](https://www.coinlore.com/cryptocurrency-data-api) doesn't impose rate limits, but they suggest making at most one request per second. + +## Author + +[Charles de Villiers](https://realpython.com/team/cdevilliers/) + +## License + +Distributed under the MIT license. See `LICENSE` in the root directory of this `materials` repo for more information. diff --git a/python-rich-package/crypto_data.json b/python-rich-package/crypto_data.json new file mode 100644 index 0000000000..ca4c41041a --- /dev/null +++ b/python-rich-package/crypto_data.json @@ -0,0 +1,702 @@ +[ + { + "symbol": "BTC", + "name": "Bitcoin", + "price_usd": "31252.03", + "percent_change_7d": "3.79", + "volume24": 20953193815.93972 + }, + { + "symbol": "ETH", + "name": "Ethereum", + "price_usd": "1996.94", + "percent_change_7d": "7.72", + "volume24": 43776094155.557755 + }, + { + "symbol": "USDT", + "name": "Tether", + "price_usd": "1.00", + "percent_change_7d": "0.07", + "volume24": 55137371360.06878 + }, + { + "symbol": "BNB", + "name": "Binance Coin", + "price_usd": "254.17", + "percent_change_7d": "8.54", + "volume24": 788139087.131846 + }, + { + "symbol": "USDC", + "name": "USD Coin", + "price_usd": "0.999758", + "percent_change_7d": "-0.03", + "volume24": 34890207329.59203 + }, + { + "symbol": "XRP", + "name": "XRP", + "price_usd": "0.776092", + "percent_change_7d": "65.51", + "volume24": 13289725792.18076 + }, + { + "symbol": "BUSD", + "name": "Binance USD", + "price_usd": "1.00", + "percent_change_7d": "-0.01", + "volume24": 2982268496.878559 + }, + { + "symbol": "ADA", + "name": "Cardano", + "price_usd": "0.348179", + "percent_change_7d": "23.40", + "volume24": 1317758234.4725194 + }, + { + "symbol": "SOL", + "name": "Solana", + "price_usd": "27.96", + "percent_change_7d": "37.47", + "volume24": 2608578104.9363656 + }, + { + "symbol": "DOGE", + "name": "Dogecoin", + "price_usd": "0.070784", + "percent_change_7d": "7.82", + "volume24": 776208544.8693453 + }, + { + "symbol": "STETH", + "name": "Staked Ether", + "price_usd": "1984.92", + "percent_change_7d": "8.38", + "volume24": 970870.4192054314 + }, + { + "symbol": "TRX", + "name": "TRON", + "price_usd": "0.082126", + "percent_change_7d": "5.43", + "volume24": 294442942.6567772 + }, + { + "symbol": "LTC", + "name": "Litecoin", + "price_usd": "100.92", + "percent_change_7d": "3.73", + "volume24": 2010476368.057925 + }, + { + "symbol": "DOT", + "name": "Polkadot", + "price_usd": "5.63", + "percent_change_7d": "10.75", + "volume24": 282938041.0123782 + }, + { + "symbol": "WBTC", + "name": "Wrapped Bitcoin", + "price_usd": "31201.84", + "percent_change_7d": "3.62", + "volume24": 36161715.175137974 + }, + { + "symbol": "BCH", + "name": "Bitcoin Cash", + "price_usd": "272.20", + "percent_change_7d": "-4.50", + "volume24": 2129638945.9266052 + }, + { + "symbol": "AVAX", + "name": "Avalanche", + "price_usd": "15.24", + "percent_change_7d": "20.96", + "volume24": 500476432.5450047 + }, + { + "symbol": "UNI", + "name": "Uniswap", + "price_usd": "5.96", + "percent_change_7d": "10.67", + "volume24": 122940409.6610347 + }, + { + "symbol": "SHIB", + "name": "Shiba Inu", + "price_usd": "0.000008", + "percent_change_7d": "10.67", + "volume24": 204280913.4426844 + }, + { + "symbol": "XLM", + "name": "Stellar", + "price_usd": "0.142132", + "percent_change_7d": "46.19", + "volume24": 1263932212.2337687 + }, + { + "symbol": "LEO", + "name": "UNUS SED LEO", + "price_usd": "3.97", + "percent_change_7d": "8.41", + "volume24": 2339911.236200216 + }, + { + "symbol": "LINK", + "name": "ChainLink", + "price_usd": "7.10", + "percent_change_7d": "15.50", + "volume24": 484358760.1126672 + }, + { + "symbol": "XMR", + "name": "Monero", + "price_usd": "164.65", + "percent_change_7d": "-1.88", + "volume24": 2038036008.0313425 + }, + { + "symbol": "ATOM", + "name": "Cosmos", + "price_usd": "10.01", + "percent_change_7d": "7.68", + "volume24": 222431999.6788462 + }, + { + "symbol": "ETC", + "name": "Ethereum Classic", + "price_usd": "19.89", + "percent_change_7d": "4.32", + "volume24": 382469987.24052006 + }, + { + "symbol": "OKB", + "name": "OKB", + "price_usd": "44.00", + "percent_change_7d": "3.71", + "volume24": 5182537.475964661 + }, + { + "symbol": "LDO", + "name": "Lido DAO", + "price_usd": "2.43", + "percent_change_7d": "25.87", + "volume24": 200042470.0922766 + }, + { + "symbol": "TON", + "name": "The Open Network", + "price_usd": "1.36", + "percent_change_7d": "1.87", + "volume24": 4290911.169640025 + }, + { + "symbol": "MATIC", + "name": "Matic Network", + "price_usd": "0.841325", + "percent_change_7d": "25.56", + "volume24": 715840267.2564398 + }, + { + "symbol": "FIL", + "name": "Filecoin", + "price_usd": "4.61", + "percent_change_7d": "5.08", + "volume24": 276195488.1582698 + }, + { + "symbol": "ARB", + "name": "Arbitrum", + "price_usd": "1.25", + "percent_change_7d": "14.98", + "volume24": 207234601.30264035 + }, + { + "symbol": "VET", + "name": "VeChain", + "price_usd": "0.020024", + "percent_change_7d": "7.60", + "volume24": 70424000.50503708 + }, + { + "symbol": "NEAR", + "name": "NEAR Protocol", + "price_usd": "1.55", + "percent_change_7d": "16.68", + "volume24": 186510632.14473444 + }, + { + "symbol": "QNT", + "name": "Quant", + "price_usd": "105.03", + "percent_change_7d": "0.81", + "volume24": 32760026.63178301 + }, + { + "symbol": "AAVE", + "name": "Aave", + "price_usd": "83.40", + "percent_change_7d": "16.36", + "volume24": 435033534.55578315 + }, + { + "symbol": "GRT", + "name": "The Graph", + "price_usd": "0.124238", + "percent_change_7d": "3.75", + "volume24": 50745768.31360009 + }, + { + "symbol": "FRAX", + "name": "Frax", + "price_usd": "0.999128", + "percent_change_7d": "0.54", + "volume24": 10112664.516622534 + }, + { + "symbol": "TUSD", + "name": "TrueUSD", + "price_usd": "0.999479", + "percent_change_7d": "-0.05", + "volume24": 3269190962.729144 + }, + { + "symbol": "STX", + "name": "Stacks", + "price_usd": "0.680968", + "percent_change_7d": "4.52", + "volume24": 72956976.43657969 + }, + { + "symbol": "MKR", + "name": "Maker", + "price_usd": "913.72", + "percent_change_7d": "-9.45", + "volume24": 325122162.91072315 + }, + { + "symbol": "EOS", + "name": "EOS", + "price_usd": "0.804691", + "percent_change_7d": "12.59", + "volume24": 218036299.95140857 + }, + { + "symbol": "USDP", + "name": "Pax Dollar", + "price_usd": "0.999809", + "percent_change_7d": "-0.08", + "volume24": 1627155.176109821 + }, + { + "symbol": "ALGO", + "name": "Algorand", + "price_usd": "0.118303", + "percent_change_7d": "3.50", + "volume24": 175432880.12364262 + }, + { + "symbol": "XTZ", + "name": "Tezos", + "price_usd": "0.902678", + "percent_change_7d": "14.45", + "volume24": 17862226.065150194 + }, + { + "symbol": "FTM", + "name": "Fantom", + "price_usd": "0.299238", + "percent_change_7d": "11.48", + "volume24": 187495267.91607383 + }, + { + "symbol": "THETA", + "name": "Theta Token", + "price_usd": "0.827153", + "percent_change_7d": "14.36", + "volume24": 39602951.52502267 + }, + { + "symbol": "MANA", + "name": "Decentraland", + "price_usd": "0.433536", + "percent_change_7d": "14.95", + "volume24": 125883681.50783731 + }, + { + "symbol": "BCHSV", + "name": "Bitcoin SV", + "price_usd": "39.35", + "percent_change_7d": "-10.48", + "volume24": 65176121.64507406 + }, + { + "symbol": "USDD", + "name": "USDD", + "price_usd": "1.00", + "percent_change_7d": "0.18", + "volume24": 10943706.717842644 + }, + { + "symbol": "SAND", + "name": "The Sandbox", + "price_usd": "0.467742", + "percent_change_7d": "12.10", + "volume24": 200640950.97449806 + }, + { + "symbol": "PEPE", + "name": "Pepe", + "price_usd": "0.000002", + "percent_change_7d": "11.25", + "volume24": 406548396.3096544 + }, + { + "symbol": "APE", + "name": "APEcoin", + "price_usd": "2.21", + "percent_change_7d": "14.72", + "volume24": 296669905.1748844 + }, + { + "symbol": "NEO", + "name": "Neo", + "price_usd": "9.59", + "percent_change_7d": "5.63", + "volume24": 87953825.32299156 + }, + { + "symbol": "FLOW", + "name": "Flow", + "price_usd": "0.652914", + "percent_change_7d": "4.75", + "volume24": 88816184.52336611 + }, + { + "symbol": "AXS", + "name": "Axie Infinity", + "price_usd": "6.63", + "percent_change_7d": "12.65", + "volume24": 173301949.07415962 + }, + { + "symbol": "CRV", + "name": "Curve DAO Token", + "price_usd": "0.863588", + "percent_change_7d": "17.72", + "volume24": 34442558.73801766 + }, + { + "symbol": "INJ", + "name": "Injective Protocol", + "price_usd": "9.64", + "percent_change_7d": "21.61", + "volume24": 214944721.17498806 + }, + { + "symbol": "PHB", + "name": "Red Pulse Phoenix", + "price_usd": "0.739450", + "percent_change_7d": "11.41", + "volume24": 2127239.3825587 + }, + { + "symbol": "XEC", + "name": "eCash", + "price_usd": "0.000031", + "percent_change_7d": "-19.12", + "volume24": 17398291.14119232 + }, + { + "symbol": "CRO", + "name": "Crypto.com Chain", + "price_usd": "0.060308", + "percent_change_7d": "6.23", + "volume24": 10125581.086761687 + }, + { + "symbol": "CHZ", + "name": "Chiliz", + "price_usd": "0.083790", + "percent_change_7d": "10.56", + "volume24": 46253360.29975289 + }, + { + "symbol": "KCS", + "name": "KuCoin Shares", + "price_usd": "6.24", + "percent_change_7d": "-1.52", + "volume24": 3496576.426964752 + }, + { + "symbol": "KLAY", + "name": "Klaytn", + "price_usd": "0.177168", + "percent_change_7d": "5.05", + "volume24": 19656059.820330244 + }, + { + "symbol": "RNDR", + "name": "Render Token", + "price_usd": "2.14", + "percent_change_7d": "10.64", + "volume24": 92808359.23988137 + }, + { + "symbol": "FTT", + "name": "FTX Token", + "price_usd": "1.64", + "percent_change_7d": "10.01", + "volume24": 53872321.04347122 + }, + { + "symbol": "MIOTA", + "name": "IOTA", + "price_usd": "0.192000", + "percent_change_7d": "4.59", + "volume24": 8649448.187102558 + }, + { + "symbol": "ZEC", + "name": "Zcash", + "price_usd": "32.34", + "percent_change_7d": "3.78", + "volume24": 234082644.50086042 + }, + { + "symbol": "PAXG", + "name": "PAX Gold", + "price_usd": "1935.85", + "percent_change_7d": "2.19", + "volume24": 812583422.7762803 + }, + { + "symbol": "LUNC", + "name": "Terra Classic", + "price_usd": "0.000088", + "percent_change_7d": "5.29", + "volume24": 29817037.116504386 + }, + { + "symbol": "HBAR", + "name": "Hedera Hashgraph", + "price_usd": "0.053269", + "percent_change_7d": "14.34", + "volume24": 41598576.611335196 + }, + { + "symbol": "TACO", + "name": "Tacos", + "price_usd": "78.94", + "percent_change_7d": "18.34", + "volume24": 6717589.401493353 + }, + { + "symbol": "EGLD", + "name": "Elrond eGold", + "price_usd": "37.59", + "percent_change_7d": "11.35", + "volume24": 22131636.4517117 + }, + { + "symbol": "GMX", + "name": "GMX", + "price_usd": "60.02", + "percent_change_7d": "9.75", + "volume24": 30717637.271570735 + }, + { + "symbol": "COMP", + "name": "Compound", + "price_usd": "68.31", + "percent_change_7d": "17.87", + "volume24": 123188541.96973641 + }, + { + "symbol": "TKX", + "name": "Tokenize Xchange", + "price_usd": "6.19", + "percent_change_7d": "7.04", + "volume24": 11293471.330545316 + }, + { + "symbol": "XAUT", + "name": "Tether Gold", + "price_usd": "1959.50", + "percent_change_7d": "2.51", + "volume24": 6054015.365067729 + }, + { + "symbol": "KAS", + "name": "Kaspa", + "price_usd": "0.028860", + "percent_change_7d": "33.85", + "volume24": 12770039.919820618 + }, + { + "symbol": "HT", + "name": "Huobi Token", + "price_usd": "2.78", + "percent_change_7d": "3.13", + "volume24": 12653864.943357613 + }, + { + "symbol": "CSPR", + "name": "Casper", + "price_usd": "0.038206", + "percent_change_7d": "1.91", + "volume24": 5576587.639663127 + }, + { + "symbol": "DASH", + "name": "Dash", + "price_usd": "35.85", + "percent_change_7d": "5.28", + "volume24": 71757437.09998573 + }, + { + "symbol": "XDCE", + "name": "XinFin Network", + "price_usd": "0.032674", + "percent_change_7d": "1.71", + "volume24": 1776317.812194609 + }, + { + "symbol": "KAVA", + "name": "Kava", + "price_usd": "0.967047", + "percent_change_7d": "4.15", + "volume24": 73097054.46498355 + }, + { + "symbol": "RPL", + "name": "Rocket Pool", + "price_usd": "37.84", + "percent_change_7d": "-1.74", + "volume24": 1054669.705829167 + }, + { + "symbol": "SUI", + "name": "Sui", + "price_usd": "0.725466", + "percent_change_7d": "11.08", + "volume24": 92574462.3637904 + }, + { + "symbol": "NEXO", + "name": "Nexo", + "price_usd": "0.658019", + "percent_change_7d": "4.53", + "volume24": 5663554.267356189 + }, + { + "symbol": "FLEX", + "name": "FLEX Coin", + "price_usd": "3.66", + "percent_change_7d": "0.04", + "volume24": 320013.9077801702 + }, + { + "symbol": "ZIL", + "name": "Zilliqa", + "price_usd": "0.022452", + "percent_change_7d": "8.17", + "volume24": 40085286.38067658 + }, + { + "symbol": "TWT", + "name": "Trust Wallet Token", + "price_usd": "0.854440", + "percent_change_7d": "-0.84", + "volume24": 16348028.542735066 + }, + { + "symbol": "RUNE", + "name": "THORChain", + "price_usd": "1.07", + "percent_change_7d": "5.55", + "volume24": 12001247.683048533 + }, + { + "symbol": "FEI", + "name": "Fei USD", + "price_usd": "0.815600", + "percent_change_7d": "-11.06", + "volume24": 940166.3214333741 + }, + { + "symbol": "SNX", + "name": "Synthetix Network Token", + "price_usd": "2.95", + "percent_change_7d": "41.08", + "volume24": 311179071.90065503 + }, + { + "symbol": "DYDX", + "name": "dYdX", + "price_usd": "2.14", + "percent_change_7d": "15.76", + "volume24": 74017943.36035483 + }, + { + "symbol": "AGIX", + "name": "SingularityNET", + "price_usd": "0.274559", + "percent_change_7d": "18.35", + "volume24": 195860297.72295615 + }, + { + "symbol": "LRC", + "name": "Loopring", + "price_usd": "0.243839", + "percent_change_7d": "7.30", + "volume24": 37783839.42544796 + }, + { + "symbol": "ENJ", + "name": "Enjin Coin", + "price_usd": "0.319967", + "percent_change_7d": "8.14", + "volume24": 22514225.851048034 + }, + { + "symbol": "BAT", + "name": "Basic Attention Token", + "price_usd": "0.213415", + "percent_change_7d": "11.79", + "volume24": 19548090.541221704 + }, + { + "symbol": "GNO", + "name": "Gnosis", + "price_usd": "121.48", + "percent_change_7d": "7.51", + "volume24": 2013836.000557435 + }, + { + "symbol": "CVX", + "name": "Convex Finance", + "price_usd": "4.22", + "percent_change_7d": "6.44", + "volume24": 2635140.659348456 + }, + { + "symbol": "OP", + "name": "Optimism", + "price_usd": "1.45", + "percent_change_7d": "20.45", + "volume24": 272662107.71766526 + }, + { + "symbol": "QTUM", + "name": "Qtum", + "price_usd": "2.91", + "percent_change_7d": "5.10", + "volume24": 41268418.71165733 + } +] \ No newline at end of file diff --git a/python-rich-package/dynamic_status.py b/python-rich-package/dynamic_status.py new file mode 100644 index 0000000000..8cc8e1b0cc --- /dev/null +++ b/python-rich-package/dynamic_status.py @@ -0,0 +1,17 @@ +import time + +from rich.console import Console + +console = Console() + + +def do_something_important(): + time.sleep(5.0) # Simulates a long process + + +with console.status( + "Please wait - solving global problems...", spinner="earth" +): + do_something_important() + +console.print("All fixed! :sunglasses:") diff --git a/python-rich-package/get_crypto_data.py b/python-rich-package/get_crypto_data.py new file mode 100644 index 0000000000..71dcba23cf --- /dev/null +++ b/python-rich-package/get_crypto_data.py @@ -0,0 +1,25 @@ +import requests + +COINLORE_API = "https://api.coinlore.net/api/tickers/" +KEYS = frozenset( + ("symbol", "name", "price_usd", "volume24", "percent_change_7d") +) + + +def fetch_coin_data(n_coins=100, keys=KEYS): + """Get sample data from the CoinLore API + + @param n_coins: number of coins to get data for + @param keys: subset of keys to keep for each coin + @return: list of dictionaries containing data for each coin + """ + url = f"{COINLORE_API}?limit={n_coins}" + resp = requests.get(url, timeout=5) + + return [ + {k: v for k, v in d.items() if k in keys} for d in resp.json()["data"] + ] + + +if __name__ == "__main__": + print(fetch_coin_data()) diff --git a/python-rich-package/live_table.py b/python-rich-package/live_table.py new file mode 100644 index 0000000000..3ddcbd6776 --- /dev/null +++ b/python-rich-package/live_table.py @@ -0,0 +1,63 @@ +import contextlib +import json +import time +from pathlib import Path + +from rich.console import Console +from rich.live import Live +from rich.table import Table + +console = Console() + + +def make_table(coin_list): + """Generate a rich table from a list of coins""" + table = Table( + title=f"Crypto Data - {time.asctime()}", + style="black on grey66", + header_style="white on dark_blue", + ) + table.add_column("Symbol") + table.add_column("Name", width=30) + table.add_column("Price (USD)", justify="right") + table.add_column("Volume (24h)", justify="right", width=16) + table.add_column("Percent Change (7d)", justify="right", width=8) + for coin in coin_list: + symbol, name, price, volume, pct_change = ( + coin["symbol"], + coin["name"], + coin["price_usd"], + f"{coin['volume24']:.2f}", + float(coin["percent_change_7d"]), + ) + pct_change_str = f"{pct_change:2.1f}%" + if pct_change > 5.0: + pct_change_str = f"[white on dark_green]{pct_change_str:>8}[/]" + elif pct_change < -5.0: + pct_change_str = f"[white on red]{pct_change_str:>8}[/]" + table.add_row(symbol, name, price, volume, pct_change_str) + return table + + +# Load the coins data +raw_data = json.loads(Path("crypto_data.json").read_text(encoding="utf-8")) +num_coins = len(raw_data) +coins = raw_data + raw_data # Double the dataset to simulate streaming + + +def display_table(nlines): + """Display a scrolling table with `nlines` lines""" + with Live(make_table(coins[:nlines]), screen=True) as live: + index = 0 + with contextlib.suppress(KeyboardInterrupt): + while True: + live.update(make_table(coins[index : index + nlines])) + time.sleep(0.5) + index = (index + 1) % num_coins + + +if __name__ == "__main__": + import sys + + NLINES = int(sys.argv[1]) if len(sys.argv) > 1 else 20 + display_table(NLINES) diff --git a/python-rich-package/log_exception.py b/python-rich-package/log_exception.py new file mode 100644 index 0000000000..27ad84cc7a --- /dev/null +++ b/python-rich-package/log_exception.py @@ -0,0 +1,17 @@ +import time + +from rich.console import Console +from rich.theme import Theme +from rich.traceback import install + +install(show_locals=True) +custom_theme = Theme( + {"info": "dim cyan", "warning": "magenta", "danger": "bold red"} +) +console = Console(theme=custom_theme) + +console.log("Nothing happening here", style="info") +console.log("Trouble brewing...", style="warning") +time.sleep(1) +console.log("Bad news!!", style="danger") +raise RuntimeError("Things haven't worked out as we hoped") diff --git a/python-rich-package/noble_gases.py b/python-rich-package/noble_gases.py new file mode 100644 index 0000000000..836cbad280 --- /dev/null +++ b/python-rich-package/noble_gases.py @@ -0,0 +1,81 @@ +from rich.console import Console +from rich.table import Table + +console = Console() + +table = Table(title="Noble Gases") + +columns = [ + {"heading": "Name", "style": "cyan", "justify": "center"}, + {"heading": "Symbol", "style": "magenta", "justify": "center"}, + {"heading": "Atomic Number", "style": "yellow", "justify": "right"}, + {"heading": "Atomic Mass", "style": "green", "justify": "right"}, + {"heading": "Main Properties", "style": "blue", "justify": "center"}, +] +for column in columns: + table.add_column( + column["heading"], style=column["style"], justify=column["justify"] + ) + +noble_gases = [ + { + "name": "Helium", + "symbol": "He", + "atomic_number": 2, + "atomic_mass": 4.0026, + "properties": "Inert gas", + }, + { + "name": "Neon", + "symbol": "Ne", + "atomic_number": 10, + "atomic_mass": 20.1797, + "properties": "Inert gas", + }, + { + "name": "Argon", + "symbol": "Ar", + "atomic_number": 18, + "atomic_mass": 39.948, + "properties": "Inert gas", + }, + { + "name": "Krypton", + "symbol": "Kr", + "atomic_number": 36, + "atomic_mass": 83.798, + "properties": "Inert gas", + }, + { + "name": "Xenon", + "symbol": "Xe", + "atomic_number": 54, + "atomic_mass": 131.293, + "properties": "Inert gas", + }, + { + "name": "Radon", + "symbol": "Rn", + "atomic_number": 86, + "atomic_mass": 222.0, + "properties": "Radioactive gas", + }, + { + "name": "Oganesson", + "symbol": "Og", + "atomic_number": 118, + "atomic_mass": "(294)", + "properties": "Synthetic radioactive gas", + }, +] + +for noble_gas in noble_gases: + table.add_row( + noble_gas["name"], + noble_gas["symbol"], + str(noble_gas["atomic_number"]), + str(noble_gas["atomic_mass"]), + noble_gas["properties"], + ) + +console.print(table) diff --git a/python-rich-package/progress_indicator.py b/python-rich-package/progress_indicator.py new file mode 100644 index 0000000000..b30361e3c9 --- /dev/null +++ b/python-rich-package/progress_indicator.py @@ -0,0 +1,13 @@ +import time + +from rich.progress import Progress + +with Progress() as progress: + task1 = progress.add_task("[red]Fribbulating...[/]", total=1000) + task2 = progress.add_task("[green]Wobbulizing...[/]", total=1000) + task3 = progress.add_task("[cyan]Fandangling...[/]", total=1000) + while not progress.finished: + progress.update(task1, advance=0.5) + progress.update(task2, advance=0.3) + progress.update(task3, advance=0.9) + time.sleep(0.01)