Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

libciss

Python client for CISS applications. Currently supports CISS Control, with helpers for authentication and pré-carga / separação (warehouse pre-load picking).

Status: 0.1.0a3 (alpha) — the API surface may change.

Requirements

  • Python 3.10+ (uses X | None type syntax and dataclass(slots=True))
  • requests>=2.31.0

Installation

pip install libciss

Everything is imported from the single top-level libciss package:

from libciss import CISSClient

Upgrading from 0.1.0a1: that release was unusable — it shipped its modules under a top-level services package (which collided with any application that had its own services/), left client and exceptions out of the distribution entirely, and imported from a src package that was never packaged. 0.1.0a2 moves everything under libciss, so from src import ... becomes from libciss import ....

Quick start

from datetime import datetime

from libciss import CISSClient
from libciss.services.cisscontrol.models import PreCargaSeparacaoSubmission

client = CISSClient("https://your-ciss-host.example.com")

# Authenticate — stores the bearer token on the shared session
user = client.cisscontrol.auth.login("username", "password")
print(user.id_empresa, user.razao_social)

# List pre-loads
preloads = client.cisscontrol.precarga_separacao.get_all(
    id_empresa=user.id_empresa,
    num_dias_sync=30,
)

# Fetch the line items of one pre-load
items = client.cisscontrol.precarga_separacao.items(
    id_empresa=user.id_empresa,
    id_precarga=preloads[0].id_pre_carga,
    id_usuario=user.id_user,
)

# Report a separated item back to CISS
item = items[0]
submission = PreCargaSeparacaoSubmission(
    id_usuario=user.id_user,
    id_empresa=item.id_empresa,
    id_documento=item.id_documento,
    id_pre_carga=item.id_pre_carga,
    id_produto=item.id_produto,
    id_subproduto=item.id_subproduto,
    id_local_retirada=item.id_local_retirada,
    ds_local_retirada=item.ds_local_retirada,
    num_sequencia=item.num_sequencia,
    qtd_produto=item.qtd_produto,
    fg_separado="S",
    qtd_contada=item.qtd_produto,
    dt_hr_inicio=datetime.now(),
)

response = client.cisscontrol.precarga_separacao.submit([submission])

client.cisscontrol.auth.logout()

Architecture

One CISSClient owns a single requests.Session. Services never hold their own transport — they call back into client.request(...), so the token set at login is automatically applied to every later call.

CISSClient(base_url)
├── session          # requests.Session (shared headers / cookies)
├── request(...)     # low-level HTTP helper, raises on 4xx/5xx
└── cisscontrol      # CISSControl
      ├── auth                 # AuthenticationService
      │     ├── login / logout
      │     ├── token / authenticated
      │     └── user → LoginResponse | None
      └── precarga_separacao   # PreCargaSeparacaoService
            ├── get_all(...)  → list[PreCargaSeparacao]
            ├── items(...)    → list[PreCargaSeparacaoItem]
            └── submit(...)   → requests.Response

API reference

CISSClient

Entry point for all services.

CISSClient(base_url: str)
Attribute / method Description
base_url API root URL; a trailing / is stripped
session Shared requests.Session — holds the Authorization header after login
cisscontrol CISSControl service namespace
request(method, endpoint, **kwargs) Sends method to base_url + endpoint, calls raise_for_status(), returns the Response

endpoint is concatenated onto base_url verbatim, so it must start with /. Any extra keyword argument is forwarded to requests.Session.request (json=, params=, timeout=, …).

Session-level configuration goes on client.session:

client.session.verify = "/path/to/ca-bundle.pem"
client.session.proxies = {"https": "http://proxy.internal:3128"}

Every request is bounded by a default (connect, read) timeout of (5.0, 30.0) seconds, exposed as libciss.client.DEFAULT_TIMEOUT. The read half is short deliberately: CISS Control tends to stall rather than answer when a company has no pre-load.

Change it per client, or per call:

client = CISSClient("https://ciss.example.com", timeout=(5, 60))
client.timeout = None                     # wait forever
client.request("GET", "/ciss-control/precarga_separacao", timeout=10)  # this call only

A request that exceeds it raises requests.Timeout. Note that setting client.session.timeout does not work — requests.Session has no such attribute; use the constructor argument above.


Authentication — client.cisscontrol.auth

login(username, password) -> LoginResponse

POST /ciss-control/login

Sends {"username": ..., "password": ...} as JSON. On success it writes the returned tokenBearer into session.headers["Authorization"] and caches the parsed payload on auth.user.

The token is stored exactly as the API returns it — the library does not prepend a Bearer prefix. razao_social is right-stripped of trailing whitespace; all other fields are passed through unchanged.

logout() -> None

Removes the Authorization header and clears auth.user. Client-side only — no request is sent, so the token stays valid server-side until it expires.

Properties

Property Type Description
token str | None Current Authorization header value, or None
authenticated bool True when a token is set
user LoginResponse | None Payload of the last successful login

authenticated only reports whether a token is present — it does not validate or check expiry. An expired token still reads as True, and the call then fails with requests.HTTPError (401).

requires_login decorator

libciss.services.cisscontrol.auth.requires_login guards service methods. It reads self.client.cisscontrol.auth.authenticated and raises NotAuthenticatedError when no token is set, so it can only decorate methods of a service that holds a client attribute.

from libciss.services.cisscontrol.auth import requires_login

class MyService:
    def __init__(self, client):
        self.client = client

    @requires_login
    def do_something(self):
        return self.client.request("GET", "/ciss-control/something")

Pré-carga separação — client.cisscontrol.precarga_separacao

Every method is decorated with @requires_login and raises NotAuthenticatedError when called before login().

get_all(*, id_empresa, ...) -> list[PreCargaSeparacao]

GET /ciss-control/precarga_separacao

Keyword-only. All filter parameters are always sent, empty strings included.

Parameter Type Default API query key
id_empresa int required idEmpresa
num_dias_sync int 99 numDiasSync
ds_separacao str "" dsSeparacao
ds_precarga str "" dsPreCarga
ds_ponto_retirada str "" dsPontoRetirada
dt_inicio str "" dtInicio
ds_pre_separacao str "" dsPreSeparacao
dt_fim str "" dtFim

Returns [] on HTTP 204 or an empty/non-array body, otherwise one PreCargaSeparacao per element of the JSON array.

Date filters (dt_inicio / dt_fim) are typed str and forwarded verbatim — the library does not format date objects for you.

A large num_dias_sync can make this endpoint stall. It no longer hangs indefinitely — the default read timeout caps it — but a stalled call still costs you that timeout, so prefer a bounded window (e.g. num_dias_sync=30).

items(*, id_empresa, id_precarga, id_usuario, ...) -> list[PreCargaSeparacaoItem]

GET /ciss-control/precarga_separacao/itens

Parameter Type Default API query key
id_empresa int required idEmpresa
id_precarga int required idPreCarga
id_usuario int required idUsuario
ds_separacao str "" dsSeparacao
ds_precarga str "" dsPreCarga
ds_ponto_retirada str "" dsPontoRetirada
dt_inicio str "" dtInicio
ds_pre_separacao str "" dsPreSeparacao
dt_fim str "" dtFim

Returns [] on HTTP 204 or an empty/non-array body, matching get_all.

submit(items) -> requests.Response

POST /ciss-control/precarga_separacao

Takes a positional list[PreCargaSeparacaoSubmission] and posts [item.to_dict() for item in items] as a JSON array. Returns the raw requests.Response — the body is not parsed, so inspect response.status_code / response.json() yourself.


Data models

Models live in libciss.services.cisscontrol.models. They are @dataclass(slots=True), use snake_case in Python, and map to the API's camelCase. Response models expose from_dict; the request model exposes to_dict.

Being slotted dataclasses, they take positional or keyword arguments, compare by value, and reject attributes that are not declared fields.

from_dict requires the keys that identify a record and tolerates the merely descriptive ones, because CISS omits those on some pre-loads and losing a description is not a reason to fail a whole batch. Each model below lists what it tolerates.

LoginResponse

Built by auth.login().

Field Type API field
token_bearer str tokenBearer
id_user int idUser
id_grupo int idGrupo
username str username
enabled bool enabled
id_empresa int idEmpresa
cnpj_empresa str cnpjEmpresa
razao_social str razaoSocial (right-stripped)
permissions list[str] permissionsList

A missing or null razaoSocial becomes "" and a missing permissionsList becomes []. The remaining keys are required.

PreCargaSeparacao

Field Type API field
id_empresa int idEmpresa
id_pre_carga int idPreCarga
descricao str descricao
dt_movimento date dtMovimento, coerced to a date

idEmpresa, idPreCarga and dtMovimento are required — a missing one raises KeyError. A missing or null descricao becomes "", and it is right-stripped since CISS pads it to a fixed width.

dtMovimento accepts "2026-08-05", a full "2026-08-05T00:00:00" timestamp, or an already-decoded date/datetime; CISS returns all of these for the same field. Anything else raises ValueError.

PreCargaSeparacaoItem

Field Type API field
id_pre_carga int idPreCarga
id_empresa int idEmpresa
id_documento int idDocumento
id_produto int idProduto
id_subproduto int idSubproduto
ds_local_retirada str dsLocalRetirada
num_sequencia int numSequencia
id_lote str | None idLote — optional, None when absent
qtd_produto float qtdProduto
fg_separado str fgSeparado
qtd_contada_divergente bool qtdContadaDivergente
id_local_retirada int idLocalRetirada

Required: idPreCarga, idEmpresa, idDocumento, idProduto, idSubproduto, numSequencia and qtdProduto — these identify the line, so a missing one raises KeyError. The rest fall back when missing or null:

Key Fallback
dsLocalRetirada ""
idLote None
fgSeparado ""
qtdContadaDivergente False
idLocalRetirada 0

Because of that fallback, id_local_retirada == 0 means "CISS did not say", not pick-up location number zero. qtd_produto is coerced with float() and id_local_retirada with int(), since CISS sometimes sends them as strings.

PreCargaSeparacaoSubmission

Request DTO for submit(). Every field is required — there are no defaults, so all thirteen must be supplied.

Field Type JSON key
id_usuario int idUsuario
id_empresa int idEmpresa
id_documento int idDocumento
id_pre_carga int idPreCarga
id_produto int idProduto
id_subproduto int idSubproduto
id_local_retirada int idLocalRetirada
ds_local_retirada str dsLocalRetirada
num_sequencia int numSequencia
qtd_produto float qtdProduto
fg_separado str fgSeparado
qtd_contada float qtdContada
dt_hr_inicio datetime.datetime dtHrInicio, serialized with .isoformat()

to_dict() calls .isoformat() on dt_hr_inicio, so it must be a datetime — passing a string raises AttributeError. Nothing is validated beyond that: fg_separado is sent as-is ("S" / "N"), and a qtd_contada that differs from qtd_produto is accepted and resolved server-side.


Exceptions

Exception
└── CISSClientError
    └── AuthenticationError
        └── NotAuthenticatedError

Defined in libciss.exceptions.

Exception Raised when
CISSClientError Base class for library errors — catch this to catch them all
AuthenticationError Auth-related failures
NotAuthenticatedError A @requires_login method is called with no token set

Transport and HTTP failures are not wrapped: client.request() calls raise_for_status(), so 4xx/5xx surface as requests.HTTPError, and connection/timeout problems surface as the corresponding requests.RequestException subclasses.

import requests

from libciss.exceptions import NotAuthenticatedError

try:
    preloads = client.cisscontrol.precarga_separacao.get_all(id_empresa=1)
except NotAuthenticatedError:
    client.cisscontrol.auth.login("user", "pass")
except requests.HTTPError as e:
    print(e.response.status_code, e.response.text)

A 401 from an expired token arrives as requests.HTTPError, not NotAuthenticatedError — the local check only sees that a token exists. To recover, call login() again.


Endpoint map

HTTP Path Client method
POST /ciss-control/login auth.login
GET /ciss-control/precarga_separacao precarga_separacao.get_all
GET /ciss-control/precarga_separacao/itens precarga_separacao.items
POST /ciss-control/precarga_separacao precarga_separacao.submit

Known issues

These are current limitations of the code, not of the documentation.

Issue Impact
get_all can stall on wide sync windows Bounded by the read timeout now, but a stalled call still costs you those seconds — keep num_dias_sync small
logout() is client-side only The token remains valid on the server
Transport errors are not wrapped Callers catch requests exceptions (HTTPError, Timeout) alongside CISSClientError
No test suite Changes are unverified

Glossary

Portuguese terms used by the CISS API, kept untranslated in the model field names.

Term Meaning
Empresa Company / store (id_empresa, CNPJ, razão social)
Pré-carga Pre-load batch for warehouse picking
Separação Product picking / separation
Local de retirada Pick-up location
Documento Related document ID
Produto / Subproduto Product and subproduct IDs
Lote Lot / batch code (optional)
Qtd produto Expected quantity on the pre-load
Qtd contada Quantity actually counted during separation
fgSeparado Separation flag, an API string ("S" / "N")
numDiasSync Days of history to sync (default 99)

License

MIT © Redson

Metadata

Release files for libciss 0.1.0a4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for libciss 0.1.0a4
File Size Uploaded Provenance Actions
libciss-0.1.0a4.tar.gz 18.0 kB Without provenance Details for libciss-0.1.0a4.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for libciss 0.1.0a4
File Interpreter ABI Platform Actions
libciss-0.1.0a4-py3-none-any.whl Python 3 none any Details for libciss-0.1.0a4-py3-none-any.whl

Total release size: 34.7 kB

Release files / libciss-0.1.0a4.tar.gz

Download URL libciss-0.1.0a4.tar.gz
Size 18.0 kB
Tags Source
SHA-256 checksum
How to use checksums
685b4c49ec7a22b058c60f5717805875a9eec2cea414fc2728d6e695346207eb
BLAKE2b-256 checksum
How to use checksums
8402095d5827bf6565456705b8103e877e23f85260b102ef69c7907bb60fbe76
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

Release files / libciss-0.1.0a4-py3-none-any.whl

Download URL libciss-0.1.0a4-py3-none-any.whl
Size 16.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6b2d0ae08c35f98ffaecb671ff213fe723b694d7742334453d40ae244a6d1abc
BLAKE2b-256 checksum
How to use checksums
b1b2532718b22a82829b1ac41c1d5486611c67ed247cd54ebd140ef2cabf05df
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

Security for libciss 0.1.0a4

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page