hdl-toolkit
Build, validate, package and load Oracle HCM Data Loader (HDL) files from Python or the command line.
Loading data into Oracle Fusion HCM with HDL usually means hand-editing pipe-delimited .dat files, zipping them, uploading through the UI and waiting for an import to tell you that line 4,812 has one column too many. hdl-toolkit moves those checks to your machine or CI pipeline and wraps the whole REST flow in a single command.
CSV / Python dicts ──► hdl build ──► Worker.dat ──► hdl validate ──► hdl package ──► hdl submit ──► Oracle HCM
(catch errors (upload, load,
before upload) poll, report)
Features
- Build
.datfiles from CSV files or Python dictionaries, with pipe escaping,SETinstructions and multiple business objects (Worker, PersonName, PersonEmail, …) in one file. - Validate before uploading: data lines before
METADATA, column-count mismatches, duplicate attributes, duplicate record keys (date-effective aware), non-YYYY/MM/DDdates, missing keys, and a file name that doesn't match the top-level object. - Package
.datfiles withClobFiles/andBlobFiles/attachments into an HDL-ready ZIP. - Submit through the
dataLoadDataSetsREST API: upload, import and load, poll until the load finishes, then show the error messages. - Report honestly: a load that Oracle marks
SUCCESSbut that has object-level errors is reported asFAILED, and one with unprocessed objects asWARNING. - One runtime dependency (
requests). Typed and tested.
Install
pip install hdl-toolkit
Or, from source:
git clone https://github.com/Pire1809/hdl-toolkit && cd hdl-toolkit
pip install -e ".[dev]"
Command line
Build a .dat file from CSV
Each CSV's header row holds HDL attribute names. List parent objects before their children:
hdl build Worker.dat \
Worker=examples/worker.csv \
PersonName=examples/person_name.csv \
PersonEmail=examples/person_email.csv \
--set PURGE_AFTER_LOAD=Y
wrote Worker.dat: 3 block(s), 6 row(s)
SET PURGE_AFTER_LOAD Y
METADATA|Worker|SourceSystemOwner|SourceSystemId|EffectiveStartDate|EffectiveEndDate|PersonNumber|StartDate|ActionCode
MERGE|Worker|HRC_SQLLOADER|EMP_1001|2026/10/01|4712/12/31|1001|2026/10/01|HIRE
...
METADATA|PersonName|SourceSystemOwner|SourceSystemId|PersonId(SourceSystemId)|...|FirstName|LastName
MERGE|PersonName|HRC_SQLLOADER|EMP_1002_NAME|EMP_1002|...|Luis|Pérez \| Soto
Use --owner MY_SYSTEM to add SourceSystemOwner to CSVs that don't have it, and --op DELETE to generate delete files.
Validate
hdl validate examples/broken/Worker.dat
examples/broken/Worker.dat: ERROR line 1: MERGE line for 'PersonName' before its METADATA line
examples/broken/Worker.dat: WARNING line 3 [Worker]: EffectiveStartDate='2026-10-01' is not in YYYY/MM/DD format
examples/broken/Worker.dat: ERROR line 4 [Worker]: MERGE line has 3 values but METADATA declares 4 attributes
examples/broken/Worker.dat: ERROR line 5 [Worker]: duplicate record key (SourceSystemOwner, SourceSystemId, EffectiveStartDate); first seen on line 3
examples/broken/Worker.dat: WARNING line 5 [Worker]: EffectiveStartDate='2026-10-01' is not in YYYY/MM/DD format
examples/broken/Worker.dat: ERROR line 6: unknown instruction 'UPSERT'
examples/broken/Worker.dat: FAILED (4 error(s), 2 warning(s))
The exit code is 1 when a file has errors (or warnings, with --strict), so the check can gate a CI pipeline.
Package and submit
hdl package Worker.zip Worker.dat --attachments ./attachments # optional ClobFiles/ BlobFiles/
export HCM_INSTANCE_URL=https://your-pod.fa.ocs.oraclecloud.com
export HCM_USERNAME=integration.user
export HCM_PASSWORD='…'
hdl submit Worker.zip --name "NEW_HIRES_2026_10"
10:02:31 transfer=SUCCESS import=IN_PROGRESS load=None (0%)
10:03:01 transfer=SUCCESS import=SUCCESS load=IN_PROGRESS (40%)
10:03:31 transfer=SUCCESS import=SUCCESS load=SUCCESS (100%)
status: SUCCESS
request id: 300000123456789
content id: UCMFA00012345
objects: 6 ok / 0 failed / 0 unprocessed (of 6)
hdl submit also accepts .dat files directly and validates and zips them first. Other useful flags: --import-only, --no-wait, --json.
Check a load that was submitted earlier:
hdl status 300000123456789 --messages
For data sets submitted with --import-only, add --import-only here too, so a finished import is reported as final.
Python API
from hdl_toolkit import HdlClient, HdlFile, NULL, build_zip, has_errors, validate_text
hdl = HdlFile().set("PURGE_AFTER_LOAD", "Y")
hdl.add(
"Worker",
[
{
"SourceSystemOwner": "HRC_SQLLOADER",
"SourceSystemId": "EMP_1001",
"EffectiveStartDate": "2026/10/01",
"PersonNumber": "1001",
"ActionCode": "HIRE",
},
],
)
hdl.add(
"PersonEmail",
[
{
"SourceSystemOwner": "HRC_SQLLOADER",
"SourceSystemId": "EMP_1001_EMAIL",
"PersonId(SourceSystemId)": "EMP_1001",
"EmailType": "W1",
"EmailAddress": "ana@example.com",
"DateTo": NULL,
},
],
)
issues = validate_text(hdl.to_text(), "Worker.dat")
assert not has_errors(issues), issues
hdl.write("Worker.dat")
client = HdlClient("https://your-pod.fa.ocs.oraclecloud.com", "user", "password")
result = client.submit(build_zip(["Worker.dat"]), "Worker.zip", data_set_name="NEW_HIRES")
print(result.status, result.request_id)
for message in result.messages:
print(message)
Values are escaped automatically: None becomes an empty field (Oracle leaves the attribute unchanged), and NULL (#NULL) clears it.
How the REST flow works
| Step | Endpoint (/hcmRestApi/resources/11.13.18.05) |
Returns |
|---|---|---|
| Upload ZIP (base64) | POST /dataLoadDataSets/action/uploadFile |
ContentId |
| Import and load | POST /dataLoadDataSets/action/createFileDataSet |
RequestId |
| Poll | GET /dataLoadDataSets/{RequestId} |
status and counts |
| Diagnose | GET /dataLoadDataSets/{RequestId}/child/messages |
error messages |
The integration user needs the HCM Data Loader privileges (for example the Human Capital Management Integration Specialist role) and access to the hcm/dataloader/import UCM account.
What the validator does not check
It checks structure, not Oracle business rules. It doesn't know which attributes a business object supports, and it can't check lookup codes, legislative data or whether a parent record exists in your pod. Treat a clean hdl validate as "Oracle will be able to read this file", not "every row will load".
Roadmap
- Attribute catalogs per business object (Worker, Assignment, Salary, …) for stricter validation
- Excel (
.xlsx) sources - Parse HDL error reports back into row-level CSVs
- OAuth / JWT authentication
- BI Publisher report as a source, as in oracle-hcm-hdl-azure-function
Development
pip install -e ".[dev]"
pytest
ruff check . && ruff format --check .
License
MIT. This project is not affiliated with or endorsed by Oracle. Oracle and Oracle Fusion Cloud HCM are trademarks of Oracle Corporation.
Metadata
Release files for hdl-toolkit 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| hdl_toolkit-0.1.0.tar.gz | 20.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| hdl_toolkit-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 40.7 kB
Release files / hdl_toolkit-0.1.0.tar.gz
| Download URL | hdl_toolkit-0.1.0.tar.gz |
|---|---|
| Size | 20.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e29b8f0dcac62d29b3ae3b80636cb8495f01059d9865d638565e679f1246076b
|
|
BLAKE2b-256 checksum How to use checksums |
dd5344bd65a46796a114fa9bbabca4a45461cc36531df525d0122f0d79148e69
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 30, 2026.
Transparency logRelease files / hdl_toolkit-0.1.0-py3-none-any.whl
| Download URL | hdl_toolkit-0.1.0-py3-none-any.whl |
|---|---|
| Size | 19.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
dbd8153ee3e8f5517c577f0d69c8922f526bc7655cff3713f0530019c06833d0
|
|
BLAKE2b-256 checksum How to use checksums |
0b3bff155782db85fc8f51a1809260c64f609532001f1b9e610b925fc200d5fc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 30, 2026.
Transparency log