Files
Python/web_programming/get_top_billionaires.py
priya-sundaram-devandpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> bfa655ecea deps: migrate from httpx to httpx2 (pydantic's maintained fork) (#15192)
* deps: migrate from httpx to httpx2 (pydantic's maintained fork)

Mechanical rename of httpx -> httpx2 (API-compatible fork of httpx 0.28.1):
pyproject.toml deps, PEP 723 inline-script headers, and all import/call sites.
Excludes uv.lock (the keeper's allow-list rejects .lock files); the lock
refresh needs a separate maintainer-merged PR.

Refs #15081

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* deps: drop tweepy + migrate remaining requests refs to httpx2

- maths/allocation_number.py: docstring example uses httpx2, not requests
- web_programming/get_imdbtop.py.DISABLED: import httpx2 instead of requests
- remove web_programming/get_user_tweets.py.DISABLED (a Twitter API how-to,
  not an algorithm) and drop the tweepy dependency that was its only user and
  the last high-level dep pulling in requests
- uv.lock intentionally untouched (keeper allow-list)

Refs #15081

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2026-09-05 09:26:45 +02:00

110 lines
3.0 KiB
Python

"""
CAUTION: You may get a json.decoding error.
This works for some of us but fails for others.
"""
# /// script
# requires-python = ">=3.13"
# dependencies = [
# "httpx2",
# "rich",
# ]
# ///
from datetime import UTC, date, datetime
import httpx2
from rich import box
from rich import console as rich_console
from rich import table as rich_table
LIMIT = 10
TODAY = datetime.now(tz=UTC)
API_URL = (
"https://www.forbes.com/forbesapi/person/rtb/0/position/true.json"
"?fields=personName,gender,source,countryOfCitizenship,birthDate,finalWorth"
f"&limit={LIMIT}"
)
def years_old(birth_timestamp: int, today: date | None = None) -> int:
"""
Calculate the age in years based on the given birth date. Only the year, month,
and day are used in the calculation. The time of day is ignored.
Args:
birth_timestamp: The date of birth.
today: (useful for writing tests) or if None then datetime.date.today().
Returns:
int: The age in years.
Examples:
>>> today = date(2024, 1, 12)
>>> years_old(birth_timestamp=datetime(1959, 11, 20).timestamp(), today=today)
64
>>> years_old(birth_timestamp=datetime(1970, 2, 13).timestamp(), today=today)
53
>>> all(
... years_old(datetime(today.year - i, 1, 12).timestamp(), today=today) == i
... for i in range(1, 111)
... )
True
"""
today = today or TODAY.date()
birth_date = datetime.fromtimestamp(birth_timestamp, tz=UTC).date()
return (today.year - birth_date.year) - (
(today.month, today.day) < (birth_date.month, birth_date.day)
)
def get_forbes_real_time_billionaires() -> list[dict[str, int | str]]:
"""
Get the top 10 real-time billionaires using Forbes API.
Returns:
List of top 10 realtime billionaires data.
"""
response_json = httpx2.get(API_URL, timeout=10).json()
return [
{
"Name": person["personName"],
"Source": person["source"],
"Country": person["countryOfCitizenship"],
"Gender": person["gender"],
"Worth ($)": f"{person['finalWorth'] / 1000:.1f} Billion",
"Age": str(years_old(person["birthDate"] / 1000)),
}
for person in response_json["personList"]["personsLists"]
]
def display_billionaires(forbes_billionaires: list[dict[str, int | str]]) -> None:
"""
Display Forbes real-time billionaires in a rich table.
Args:
forbes_billionaires (list): Forbes top 10 real-time billionaires
"""
table = rich_table.Table(
title=f"Forbes Top {LIMIT} Real-Time Billionaires at {TODAY:%Y-%m-%d %H:%M}",
style="green",
highlight=True,
box=box.SQUARE,
)
for key in forbes_billionaires[0]:
table.add_column(key)
for billionaire in forbes_billionaires:
table.add_row(*billionaire.values())
rich_console.Console().print(table)
if __name__ == "__main__":
from doctest import testmod
testmod()
display_billionaires(get_forbes_real_time_billionaires())