Metadata-Version: 2.5
Name: astromansion
Version: 0.1.0
Summary: Official Python client for the AstroMansion astrology API.
Project-URL: Homepage, https://astromansion.com
Project-URL: Documentation, https://astromansion.com/en/docs
Project-URL: API, https://api.astromansion.com/docs
Author-email: Mustafa Yavuz Ak <founder@mustafayavuzak.com>
License: MIT
License-File: LICENSE
Keywords: api,astrology,chart,client,ephemeris,natal
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Astronomy
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: httpx>=0.24
Provides-Extra: dev
Requires-Dist: build; extra == 'dev'
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Requires-Dist: twine; extra == 'dev'
Description-Content-Type: text/markdown

# astromansion

Official Python client for the [AstroMansion](https://astromansion.com) astrology API.

Nothing is computed locally. Every call reaches `https://api.astromansion.com`,
which owns the ephemeris, your plan, your quota and your rate limit. The
package never opens a feature the server did not grant.

## Install

```bash
pip install astromansion
```

Python 3.10 or newer. The only dependency is `httpx`.

## Get an API key

Create an account at [astromansion.com](https://astromansion.com), open your
account page and generate a key. Requests made with it count against that
account, under the plan it already has.

## First chart

Put the key in the environment rather than in your source:

```bash
export ASTROMANSION_API_KEY="your key"
```

```python
from astromansion import AstroMansion

client = AstroMansion()

chart = client.natal(
    date="1990-07-19",
    time="14:30",
    lat=41.0082,
    lon=28.9784,
    timezone=3,
)

print(chart.summary.Sun.sign)  # Cancer
print(chart.planets[0].house)  # 9
```

Birth data is passed flat. The API nests it under `birth`; the client does
that for you.

Fields: `date` as `YYYY-MM-DD`, `time` as `HH:MM` (omit if unknown), `lat` and
`lon` in decimal degrees, `timezone` as an hour offset or an IANA zone name,
`houses` for a house system.

You can pass a mapping instead of keywords, but not both at once:

```python
chart = client.natal({"date": "1990-07-19", "lat": 41.0082, "lon": 28.9784})
```

## Where the key comes from

In order: the `api_key` argument, then `astromansion.set_api_key(...)`, then
`ASTROMANSION_API_KEY`. With none of them the call raises
`AuthenticationError` before touching the network.

```python
client = AstroMansion(api_key="your key")
```

## Quick use

For a notebook or a one-file script:

```python
import astromansion as am

am.set_api_key("your key")  # or rely on the environment
chart = am.natal(date="1990-07-19", lat=41.0082, lon=28.9784)
```

Applications should build a client instead: it holds a connection pool, and
two of them can carry two different keys.

## Async

```python
from astromansion import AsyncAstroMansion

async with AsyncAstroMansion() as client:
    chart = await client.natal(
        date="1990-07-19",
        time="14:30",
        lat=41.0082,
        lon=28.9784,
        timezone=3,
    )
```

Same method names, same arguments, same exceptions. Python cannot make one
class serve both, so the bare name is synchronous and `Async` marks the other,
as in `httpx`, `openai` and `anthropic`.

## Reading a response

The response is the server's own JSON, readable either way:

```python
chart.summary.Sun.sign
chart["summary"]["Sun"]["sign"]
chart.to_dict()
```

Nothing is remodelled, so a field the API adds reaches you instead of being
dropped, and no field it did not send is invented.

## Every endpoint

Every published operation, 66 of them, has a method on both clients and a
module-level shortcut, all generated from the schema: `natal`, `transits`, `synastry`, `composite`,
`solar_return`, `progression`, `harmonics`, `astrocartography`, `vedic_chart`,
`zodiacal_releasing`, `firdaria`, `horary`, `electional` and the rest.

Anything new is reachable before this client names it:

```python
result = client.request("POST", "/v1/harmonics", json={"birth": {...}})
```

Authentication, timeouts, retries and error handling behave identically there.

## Errors

```python
from astromansion import QuotaExceededError, RateLimitError

try:
    chart = client.natal(date="1990-07-19", lat=41.0, lon=29.0)
except RateLimitError as error:
    print("wait", error.retry_after, "seconds")
except QuotaExceededError:
    print("this period's allowance is spent")
```

| Exception | Meaning |
|---|---|
| `AuthenticationError` | Key missing, malformed or unknown |
| `PermissionDeniedError` | Valid key, feature not in the plan |
| `QuotaExceededError` | Allowance for the period is spent |
| `RateLimitError` | Too many requests just now; `retry_after` says how long |
| `ValidationError` | Request rejected; `details` names the field |
| `NotFoundError`, `ConflictError` | Missing resource, conflicting state |
| `ServerError` | The API failed to answer |
| `AstroMansionConnectionError` | The request never completed |

All descend from `AstroMansionError`. Each carries `status_code`,
`error_code`, `details`, `request_id` and `retry_after` when the API supplies
them.

## Rate limits and quota

A rate limit clears on its own after `retry_after`. A spent quota does not:
it needs a new period or a larger plan. They are separate exceptions for that
reason.

The client retries only failures that carry no result: connection errors, 429
and 5xx, twice by default, honouring `Retry-After`. A refusal you must fix is
never retried.

```python
client = AstroMansion(timeout=60.0, max_retries=0)
```

## Documents

```python
pdf = client.export_pdf(date="1990-07-19", lat=41.0082, lon=28.9784)

with open("chart.pdf", "wb") as file:
    file.write(pdf)
```

Or name a path and let the client write it:

```python
client.export_pdf(date="1990-07-19", lat=41.0082, lon=28.9784, output="chart.pdf")
```

Nothing is written to disk unless you ask. `export_csv`, `render_svg`,
`render_png` and `render_biwheel` also return bytes.

## Security

The key travels in the `X-API-Key` header, never in a URL. It is masked in
`repr(client)` and appears in no exception or log line the package writes.
Keep it in the environment or a secret store, not in source control. Rotate it
from your account page if it leaks.

## Staging

```python
client = AstroMansion(base_url="http://localhost:8000")
```

Also readable from `ASTROMANSION_BASE_URL`.

## Links

- [API reference](https://api.astromansion.com/docs)
- [Documentation](https://astromansion.com/en/docs)
