bestrandom 0.1.0
Random addresses from bestrandoms.com with country name and flag
Requires Python: >=3.10
Keywords: bestrandom, random, address, bestrandoms, fake, data, testing

# bestrandom

Python library to get **random addresses** from [bestrandoms.com](https://www.bestrandoms.com), with **country name and flag** for the requested country code. Useful for testing, sample data, or forms.

## Installation

From [PyPI](https://pypi.org/project/bestrandom/):

```bash
pip install bestrandom
```

**Requirements:** Python 3.10+, `curl_cffi` (installed automatically with bestrandom).

## Quick start

```python
from bestrandom import random_address, get_country_info, list_countries

# One random address for a country
addr = random_address("US")
print(addr["street"], addr["city"], addr["state"])
print(addr["country_flag"], addr["country_name"])  # 🇺🇸 United States

# Country info only (name and flag)
info = get_country_info("MX")  # {"country_name": "México", "country_flag": "🇲🇽", ...}

# List all supported countries
for c in list_countries():
    print(c["country_flag"], c["country_name"], c["country_code"])
```

## Public API

### `random_address(country_code: str) -> dict`

Generates a random address for the given country by calling bestrandoms.com and adds country name and flag from the internal catalog.

| Parameter      | Type | Description                                                |
|----------------|------|------------------------------------------------------------|
| `country_code` | str  | Country code (e.g. `"US"`, `"MX"`, `"ES"`). Case-insensitive. |

**Returns** a dict with:

| Key             | Type        | Description              |
|-----------------|-------------|--------------------------|
| `street`        | str \| None | Street                   |
| `city`          | str \| None | City                     |
| `state`         | str \| None | State / Province / Area  |
| `phone_number`  | str \| None | Phone number             |
| `zip`           | str \| None | Zip / postal code        |
| `phone_code`    | str \| None | Country calling code     |
| `country_code`  | str         | Country code (normalized)|
| `country_name`  | str \| None | Country name             |
| `country_flag`  | str \| None | Flag emoji (e.g. 🇺🇸)    |

**Example**

```python
addr = random_address("es")
# {
#   "street": "Calle Example 123",
#   "city": "Madrid",
#   "state": "Madrid",
#   "phone_number": "...",
#   "zip": "28001",
#   "phone_code": "+34",
#   "country_code": "ES",
#   "country_name": "Spain",
#   "country_flag": "🇪🇸"
# }
```

If the country is not in the internal catalog, `country_name` and `country_flag` will be `None`; the address is still fetched from bestrandoms.com.

### `get_country_info(country_code: str) -> dict | None`

Returns only country info (name, flag, code) from the internal catalog. No HTTP request is made.

| Parameter      | Type | Description                     |
|----------------|------|---------------------------------|
| `country_code` | str  | Country code (case-insensitive). |

**Returns**

- A dict with `country_code`, `country_name`, and `country_flag`, or  
- `None` if the code is not in the catalog.

**Example**

```python
get_country_info("MX")   # {"country_code": "MX", "country_name": "México", "country_flag": "🇲🇽"}
get_country_info("XX")   # None
```

### `list_countries() -> list[dict]`

Returns the list of all supported countries in the catalog (same source used by `get_country_info` and `random_address` for name and flag).

**Returns** a list of dicts, each with `country_code`, `country_name`, and `country_flag`.

**Example**

```python
countries = list_countries()
# [{"country_code": "AL", "country_name": "Albania", "country_flag": "🇦🇱"}, ...]
```

### `GenerateRandomAddress(country_code: str) -> dict`

Alias for `random_address(country_code)`. Kept for backward compatibility.

## Supported countries

The catalog includes 120+ countries. Common codes: `US`, `UK`, `CA`, `MX`, `ES`, `AR`, `BR`, `DE`, `FR`, `IT`, `JP`, `CN`, `IN`, `AU`, etc. Use `list_countries()` for the full list.

Country codes in the bestrandoms.com URL can be 2 or 3 letters (e.g. `US`, `BOL`). They must match what the site accepts; the internal catalog may have name/flag for that code.

## Architecture (Clean Architecture)

The project is organized in layers: domain, application (use cases + ports), and infrastructure.

```
bestrandom/
├── __init__.py              # Public API and default wiring
├── domain/                  # Domain layer
│   ├── entities.py          # Address, Country entities
│   └── ...
├── application/             # Application layer
│   ├── ports.py             # Interfaces: IAddressProvider, ICountryRepository
│   └── use_cases.py         # GetRandomAddressUseCase, GetCountryInfoUseCase, ListCountriesUseCase
├── infrastructure/         # Infrastructure layer
│   ├── bestrandoms_client.py   # HTTP client → IAddressProvider
│   ├── country_repository.py   # In-memory catalog → ICountryRepository
│   └── html_parser.py          # HTML extraction utility
└── data/                    # Static data
    └── countries.py         # Country list (code, name, flag)
```

- **Domain:** `Address` and `Country` entities with no external dependencies.  
- **Application:** Use cases that depend only on **ports** (interfaces).  
- **Infrastructure:** Concrete implementations of those ports (HTTP client, in-memory repository, parser).  
- **Public API:** `__init__.py` instantiates adapters and use cases and exposes `random_address`, `get_country_info`, `list_countries`, and `GenerateRandomAddress`.

You can replace the HTTP client or country repository (e.g. for tests or another data source) without changing the domain or use cases.

## Advanced: dependency injection

To use your own address provider or country repository (e.g. for tests or another API), instantiate the use cases yourself:

```python
from bestrandom.application.use_cases import GetRandomAddressUseCase, GetCountryInfoUseCase, ListCountriesUseCase
from bestrandom.infrastructure import BestRandomsAddressProvider, MemoryCountryRepository

# Default implementations
address_provider = BestRandomsAddressProvider()
country_repository = MemoryCountryRepository()

# Injected use cases
get_address = GetRandomAddressUseCase(address_provider, country_repository)
get_country = GetCountryInfoUseCase(country_repository)
list_all = ListCountriesUseCase(country_repository)

# Usage
address = get_address.execute("US")
print(address.to_dict())

country = get_country.execute("MX")
countries = list_all.execute()
```

You can replace `BestRandomsAddressProvider` or `MemoryCountryRepository` with your own implementations that satisfy the protocols in `application/ports.py`.

## License

MIT License. See [LICENSE](LICENSE) for details.