Metadata-Version: 2.4
Name: pybc365
Version: 0.1.0
Summary: A modern, fully typed Python client for Microsoft Dynamics 365 Business Central.
Keywords: business-central,dynamics-365,microsoft-dynamics,erp,api,odata,python
Author: Akshay Prabhu
Author-email: Akshay Prabhu <akshay.prabhu@konspec.com>
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 2 - Pre-Alpha
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Office/Business :: Financial
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Dist: httpx>=0.28.1
Requires-Python: >=3.12
Project-URL: Homepage, https://github.com/konfpa/pybc365
Project-URL: Repository, https://github.com/konfpa/pybc365
Project-URL: Issues, https://github.com/konfpa/pybc365/issues
Description-Content-Type: text/markdown

# pybc365

A modern, fully typed Python client for Microsoft Dynamics 365 Business Central.

[![CI](https://github.com/konfpa/pybc365/actions/workflows/ci.yml/badge.svg)](https://github.com/konfpa/pybc365/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/pybc365.svg)](https://pypi.org/project/pybc365/)
[![Python versions](https://img.shields.io/pypi/pyversions/pybc365.svg)](https://pypi.org/project/pybc365/)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
[![Checked with mypy](https://www.mypy-lang.org/static/mypy_badge.svg)](https://mypy-lang.org/)

## What is pybc365?

`pybc365` is a Python library for talking to Microsoft Dynamics 365
Business Central. It's meant to be a dependable building block for the
kinds of code that need to move data in and out of BC: applications,
automation scripts, ETL/data pipelines, and backend services.

The library is generic by design: it does not assume anything about a
particular Business Central tenant, company, or set of custom entities.

## Why pybc365?

- **Python-friendly** - designed to feel natural in Python code, not like
  a thin wrapper around BC's OData/REST conventions.
- **Fully typed** - the whole library ships type annotations and a
  `py.typed` marker, so type checkers understand it out of the box.
- **Explicit over magical** - no hidden metaclass tricks or implicit
  global state; what the code does is visible in the code.
- **Minimal assumptions** - no baked-in entities, companies, or
  environment configuration.
- **Composable and minimal dependencies** - suitable for use as
  infrastructure inside larger systems.

`httpx` is the only runtime dependency. See
[Project status](#project-status) for what v0.1 covers.

## Installation

```bash
pip install pybc365
```

or, with uv:

```bash
uv add pybc365
```

`pybc365` itself does not require uv; it's a normal PyPI package.

## Quick start

```python
import httpx

from pybc365 import Client, F, desc

with Client(
    base_url="https://bc.example.com/BC240",
    company="CRONUS International Ltd.",
    auth=httpx.BasicAuth("webservice", "hunter2"),
) as client:
    customers = (
        client.service("Customers")
        .filter(F.Name.startswith("Contoso"), F.Blocked == "")
        .select("No", "Name", "Balance")
        .order_by(desc("Balance"))
    )

    print(customers.count())

    for row in customers:
        print(row["No"], row["Name"], row["Balance"])
```

`base_url` is the server root, stopping **before** the `ODataV4` segment.
Construction sends no request; the first request goes out when the loop asks
for its first row.

Reading amounts? Pass `parse_float=Decimal`. The default `float` loses the
digits of an `Edm.Decimal` before your code ever sees them. See
[Types on the wire](./docs/types-on-the-wire.md).

If `Client` collides with `httpx.Client` in your module, import the package
instead and write `pybc365.Client`.

## Documentation

The [documentation](./docs/index.md) ships in this repository.

| Page | Answers |
|---|---|
| [Getting started](./docs/getting-started.md) | How do I install it and read my first rows? |
| [Authentication](./docs/authentication.md) | Which auth recipe is tested, and against what? |
| [Queries](./docs/queries.md) | How do I select, order, page and count? |
| [Filters](./docs/filters.md) | What literal does my value become, and what does Business Central refuse? |
| [Types on the wire](./docs/types-on-the-wire.md) | What Python type will this value be? |
| [Errors](./docs/errors.md) | Which exception is this, and what caused it? |
| [Not shipped: the REST surface](./docs/rest-surface.md) | Why is there no `/api/v2.0` client? |
| [API reference](./docs/api.md) | The full signature of every public name. |

## Project status

**v0.1: sync, fully typed, read-only.** The library reads published web
services (OData V4) from one company on one server, with filters, selection,
ordering, server-driven paging, retry and one exception hierarchy.

Not in v0.1: create, update and delete; an async client; the REST API
(`/api/v2.0`); `$expand`; and any fetch of `$metadata`. `AsyncClient` is the
reserved name for the async client, and no such class ships today.

"Fully typed" means the library checks the **call shape** and nothing about the
**data**. A misspelled web service, field, projection or ordering key all pass a
strict `mypy` check with `dict[str, Any]` rows. A `row=` converter is the only
thing that closes that gap.

Every Business Central fact in this documentation is an observation of **BC
22.2 on-premises**, never a Business Central guarantee.

`pybc365` is not affiliated with or endorsed by Microsoft.

## Design principles

- Typed by default, everywhere in the public API.
- Explicit over magical.
- Minimal runtime dependencies.
- Endpoint-agnostic: no assumptions about specific BC entities or setups.
- Composable pieces over one large client object.
- Predictable, deliberately designed public APIs.
- Testable architecture, with behavior-focused tests.

## Development

```bash
git clone https://github.com/konfpa/pybc365.git
cd pybc365
uv sync
uv run prek install
```

Common commands:

```bash
uv run ruff format .          # format
uv run ruff check .           # lint
uv run mypy src scripts tests  # type check
uv run pytest                  # test (with coverage)
uv run prek run --all-files    # all pre-commit hooks
```

See [`AGENTS.md`](./AGENTS.md) for the fuller set of engineering
principles and quality expectations this project follows.

## Contributing

Contributions are welcome. Please read [`AGENTS.md`](./AGENTS.md) for the
project's engineering principles before opening a pull request, and see
[`CONTRIBUTING.md`](./CONTRIBUTING.md) for the contribution workflow.

## Security

See [`SECURITY.md`](./SECURITY.md) for how to report a vulnerability.

## License

Licensed under the [MIT License](./LICENSE).

`pybc365` is an independent open-source project and is not affiliated
with or endorsed by Microsoft.
