Metadata-Version: 2.4
Name: raptor21-sap-rfc
Version: 0.1.0rc1
Summary: Typed access to SAP tables over the RFC_READ_TABLE family.
Project-URL: Repository, https://github.com/RaptorTwentyOne/Raptor21.SAP.RFC.Python
Author: RaptorTwentyOne
License-Expression: MIT
License-File: LICENSE
Keywords: abap,rfc,rfc-read-table,sap
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Database
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# Raptor21 SAP RFC for Python

Typed access to SAP tables from Python, over the `RFC_READ_TABLE` family.

[![CI](https://github.com/RaptorTwentyOne/Raptor21.SAP.RFC.Python/actions/workflows/ci.yml/badge.svg)](https://github.com/RaptorTwentyOne/Raptor21.SAP.RFC.Python/actions/workflows/ci.yml)

The Python port of [`Raptor21.SAP.RFC`](https://github.com/RaptorTwentyOne/Raptor21.SAP.RFC), beside
its [JVM](https://github.com/RaptorTwentyOne/Raptor21.SAP.RFC.Java) and
[Node](https://github.com/RaptorTwentyOne/Raptor21.SAP.RFC.TypeScript) siblings. The wire behaviour is
the .NET library's, deliberately: everything measured there against live systems is recorded as
conformance fixtures, and this runtime's suite asserts the same envelopes, the same response parses
and the same `OPTIONS` splits, byte for byte. SAP archived its own `pyrfc` connector in 2024; this
library needs no SAP SDK at all — the transport is the system's generic SOAP RFC endpoint, spoken
through `urllib`.

```python
import datetime
from raptor21_sap_rfc import SapClient, SapDestination
from sap.kna1 import Kna1

sap = SapClient.connect(SapDestination(
    name="S4",
    base_url="https://s4.example.com:44300",
    user="READER",
    password=password,
    client="100",
))

customers = (
    sap.query(Kna1.ENTITY)
    .where(Kna1.Columns.LAND1.eq("TR") & Kna1.Columns.ERDAT.ge(datetime.date(2024, 1, 1)))
    .select(Kna1.Columns.KUNNR, Kna1.Columns.NAME1, Kna1.Columns.ORT01)
    .take(5)
    .list()
)
```

`where` is sent as SAP's `OPTIONS` clause and `select` as its field list, so filtering and projection
happen in SAP rather than after the rows arrive. A condition SAP cannot answer correctly is refused
while the query is built, never silently: a filter on a column whose conversion exit depends on the
system's own customising raises instead of returning confident, wrong rows. For large reads,
`for row in query.stream():` pages with the measured `ROWCOUNT` rules.

## How values are represented

- **`DEC`, `CURR`, `QUAN` — `decimal.Decimal`.** Exact at any width, which is the whole point; a
  float would misread the wide ones. Currency scaling — a stored yen `10.00` really being ¥1000 —
  shifts the exponent, exactly.
- **`INT1` through `INT8` — `int`.** Arbitrary precision; nineteen digits are just an int.
- **`DATS`, `TIMS` — `datetime.date` / `datetime.time`**, `None` for never-set. SAP's end-of-day
  `240000` reads as `END_OF_DAY` (`time.max`) and renders back as `240000`, so it round-trips.
- **Timestamps — timezone-aware `datetime.datetime` in UTC.** One honest cost, stated rather than
  hidden: `datetime` holds microseconds and the long form holds seven fractional digits, so the last
  digit is truncated on read; `row.get_raw` still hands over the stored text unconverted.
- **`RAW` — `bytes`.**

## Getting the classes

`Kna1` above is generated. The scaffolder ships with the .NET package and gained a Python target:

```
dotnet <package>/tools/net10.0/Raptor21.SAP.RFC.Tool.dll scaffold \
    --tables KNA1,TVKO --target python --out sap
```

One scaffolder for every language on purpose. The Data Dictionary pipeline — one round trip per table,
conversion exits, reference fields, the domain test that tells a timestamp from a quantity — lives
once, and each language is only a renderer at the end of it. The generated file is ordinary source:
read it, review it, commit it.

No .NET on the machine? The same tool ships as a native, self-contained binary (~7 MB) on each release
of the .NET repository — `raptor21-sap-rfc-tool-<platform>` under
[releases](https://github.com/RaptorTwentyOne/Raptor21.SAP.RFC/releases); download the one for your
platform and run it directly with the same arguments, no runtime required.

## Requirements

- Python 3.10 or newer. No dependencies: the transport is `urllib`, the values are `decimal` and
  `datetime`.
- A SAP system whose SOAP RFC endpoint (`/sap/bc/soap/rfc`) is reachable, and a user with `S_RFC`
  authorisation for the table-reading function modules.

## Building

```
set PYTHONPATH=src        # or: export PYTHONPATH=src
python -m unittest discover -s tests
```

`python scripts/sync_conformance.py` refreshes the conformance snapshot from a sibling
`Raptor21.SAP.RFC` checkout; the suite fails when the sibling is present and the snapshot is stale.

## Licence

MIT — see [LICENSE](LICENSE).

---

*Raptor21 SAP RFC is an independent, community-developed library. It is not affiliated with, sponsored
by, or endorsed by SAP SE. SAP, SAP S/4HANA and ABAP are trademarks or registered trademarks of SAP SE
(or an SAP affiliate company) in Germany and other countries. This library is designed for use with SAP
software and is not an SAP product.*
