Tags

Tags give the ability to mark specific points in history as being important
  • 1.0.0rc6

    9753ce99 · Updated version and date ·
    Release: Release 1.0.0rc6
    # 1.0.0rc6 - Release Candidate 6
    
    Sixth release candidate of the `1.0.0` line. It adds document search-flag querying,
    archive/lock status properties on document instances, and three new system methods
    (`get_icons`, `jobs`, `check_connections`), and fixes the `build` CI job. The public
    API of `1.0.0rc5` is unchanged apart from the additive capabilities below.
    
    ## Added
    
    - **Query documents by `OBJECT_SEARCHFLAGS` state (#14491).** The `ObjectSearchFlags`
      enum existed but could not be used: the only condition entry point emitted `system="0"`,
      so the server ignored the bitmask. Document models now expose boolean search-flag
      properties on their `system` namespace (`Model.system.in_register`, `.signed_current`,
      `.without_pages`, `.archivable`, ...) usable directly in `where()`, e.g.
      `ecm.dms.select(Document).where(Document.system.in_register == True).execute()`.
      Multiple flag conditions collapse into one correct `<FieldCondition
      internal_name="OBJECT_SEARCHFLAGS" system="1">`. Paired flags (`archivable`,
      `in_register`) also accept `== False`.
    
    - **Archive-status and lock properties on loaded document instances (#14491).**
      `OBJECT_FLAGS` (1102) and `OBJECT_LOCKUSER` (1116) are now part of the document default
      system fields, so `ECMDocumentModel` instances expose decoded boolean properties without
      any extra query flag: `obj.system.archived`, `.archivable`, `.not_archivable`,
      `.page_error`, `.without_pages`, `.reference`, `.external_archived` (from the
      `OBJECT_FLAGS` status code) and `.locked` (from `OBJECT_LOCKUSER`), plus the raw
      `.flags`. The query-only search-flag properties (`multi_location`, `has_variants`,
      `signed_current`, `signed_former`) remain usable only inside `where(...)`.
    
    - **`ecm.system.get_icons()` fetches object/type icons by ID.** Wraps the `cnv.GetIcons`
      server job and returns the GIF images for the given icon IDs as a `dict[int, bytes]`
      (icon ID to raw GIF bytes). Icon IDs come from the object definition (`icon_id` per
      object type) or from `document.system.file_properties.iconid`. Multiple IDs are fetched
      in a single round-trip; unknown IDs are silently omitted; passing no IDs returns `{}`
      without contacting the server. Sync and async.
    
    - **`ecm.check_connections()` probes every configured pool server individually (#15467).**
      This root-level method opens a throwaway connection to each server in the pool
      configuration (TCP/TLS, login, `krn.GetServerInfoEx`), reports reachability,
      authentication state and server info per server, then closes it again. Probe connections
      never enter the pool and never affect pool statistics; one unreachable server does not
      abort the others, failures are recorded in the result's `error` field instead of being
      raised. Returns `list[ECMServerConnectionCheck]` (sync and async).
    
    - **`ecm.system.jobs()` lists all server jobs grouped by namespace.** Combines
      `krn.EnumNameSpaces` and one `krn.EnumJobs` call per engine into a single
      `dict[str, list[str]]`, keyed by namespace short label (e.g. `"krn"`) with the
      namespace's jobs as values, each including the namespace prefix. Dict keys and job lists
      are sorted; the async variant runs the per-engine calls concurrently (sync and async).
    
    ## Fixed
    
    - **The `build` CI job failed at `uv build` (#15468).** A newer `uv` refuses to build when
      its cache lives inside the build source tree, and the shared GitLab cache restored
      `.cache/uv` back into the project directory. The `build` job now points `UV_CACHE_DIR`
      outside the source and skips the shared cache, so the package builds again. The test job
      keeps its in-project cache for reuse between pipelines.
    
    **Full changelog:** https://gitlab.ecmind.ch/open/ecmind_blue_client/-/compare/1.0.0rc5...1.0.0rc6
  • 1.0.0rc5

    Release: Release 1.0.0rc5
    # 1.0.0rc5 - Release Candidate 5
    
    Fifth release candidate of the `1.0.0` line. It fixes a model-generator defect that
    silently dropped data-bearing fields displayed with the GROUP control. The public API of
    `1.0.0rc4` is unchanged.
    
    ## Fixed
    
    - **`ecm-generate-models` dropped data-bearing GROUP-control fields.** enaio uses the GROUP
      control (`dt='G'`) both for visual containers and for real index fields that have their own
      data type and database column. The generator skipped every GROUP control, so such fields
      (e.g. `PostDoc`'s `hash`, `group`, `user`) were silently missing from the generated model
      class. GROUP-control fields that carry a data type are now emitted as `ECMField`
      declarations; purely visual GROUP boxes (no data type, or static) stay excluded. Present
      since `1.0.0a1`; regenerate model files to pick up the affected fields.
    
    **Full changelog:** https://gitlab.ecmind.ch/open/ecmind_blue_client/-/compare/1.0.0rc4...1.0.0rc5
  • 1.0.0rc4

    Release: Release 1.0.0rc4
    # 1.0.0rc4 — Release Candidate 4
    
    Fourth release candidate of the `1.0.0` line. It adds class-level queryable system
    fields and group-management write methods, and fixes license handling on enaio 12,
    field clearing on update and a SQL-whitespace edge case. The public API of `1.0.0rc3`
    is unchanged apart from the additive capabilities below.
    
    ## Added
    
    - **Class-level `Model.system.<field>` as queryable fields.** `system` is now
      access-aware: instance access (`obj.system.id`) still returns the loaded value, while
      class access (`Model.system.id`) returns an `ECMField` usable in `where()` /
      `order_by()`. This enables cross-type filtering on a parent via the same dotted path,
      e.g. all documents inside a known folder via
      `select(Doc).where(Folder.system.id == folder.system.id)`. Exposed for every system
      field with a single queryable backing column (`id`, `owner_guid`, `creator`,
      `creation_date`, `last_modifier`, `last_modified`, `creation_time`, `deleted_at`;
      register/document location fields; and the queryable subset of `system.base_params`
      and `system.file_properties`). Aggregate values without a backing column (`rights`,
      `name`, `is_modified`) remain instance-only. Verified against a live server.
    - **Group-management write methods on `ecm.security` (#15...).** `create_group()`,
      `update_group()`, `delete_group()` and `empty_group()` wrap `mng.CreateGroup`,
      `mng.SetGroupAttributes`, `mng.DeleteGroup` and `mng.EmptyGroup`. `create_group()`
      returns an `ECMGroup` with the server-assigned `id` and `guid`; `update_group()` takes
      a (modified) `ECMGroup`; `delete_group()` / `empty_group()` accept either an `ECMGroup`
      or a group name. A group can only be deleted once empty. Sync and async.
    
    ## Fixed
    
    - **License jobs no longer raise a hard error on enaio 12+.** `check_license()` and
      `module_info()` now pass `Flags=1` to the `LIC_CHECKLICENSE` and `LIC_LICGETMODULEINFO`
      server jobs; since enaio version 12 these return a hard error with the previous
      `Flags=0`. As a consequence `module_info()` for an unknown module now returns a result
      with a `?` license-type marker instead of failing; this is detected and reported as the
      documented `ECMNotFoundException` (sync and async).
    - **Fields could not be cleared on update (#15434).** Setting a loaded field to `None`
      was correctly detected as a change, but `_build_update_xml` skipped `None`-valued
      fields, so the reset was never sent and the server kept the old value. A field changed
      to `None` is now emitted with `field_function="NULL"` so the server actually clears it
      (sync and async). `insert()` still omits `None` fields.
    - **`ecm.db.select()` raised an opaque `IndexError` on leading whitespace (#15431).** A
      statement beginning with whitespace (e.g. a leading newline from a multi-line literal)
      made `ado.ExecuteSQL` return no result set while still reporting success, tripping
      `files[0]`. The bound command is now left-trimmed before being sent (sync and async).
    
    **Full changelog:** https://gitlab.ecmind.ch/open/ecmind_blue_client/-/compare/1.0.0rc3...1.0.0rc4
  • 1.0.0rc3

    Release: Release 1.0.0rc3
    # 1.0.0rc3 — Release Candidate 3
    
    Third release candidate of the `1.0.0` line. It adds table-field column conditions to
    the query builder and fixes enum and workflow-model handling. The public API of
    `1.0.0rc2` is unchanged apart from the additive query capability below.
    
    ## Added
    
    - **Table-field column conditions in the query builder (#15428).** Conditions can now
      target columns of a sub-table / multi-field (e.g. `Invoice.Positions.ArticleNo == "A-100"`),
      emitting `<TableCondition>` / `<TableColumn>` instead of a flat field condition. Restrict a
      condition to a row via `Invoice.Positions[3].Quantity == 5` (alias `.row(3)`). Works in
      `select` and `select_lol` (sync and async) with all comparison and collection operators.
    
    ## Fixed
    
    - **Enum (catalog) field values were serialized as their Python repr (#15427).** Passing a
      generated `(str, Enum)` / `IntEnum` member to `insert` / `update` / `upsert` emitted
      `Class.MEMBER` instead of the catalog value, which the server rejected. Enum members are
      now unwrapped to their value before conversion.
    - **Workflow start inputs were under-detected.** Inputs were read from `INOUT` parameters
      across the whole model (including activities) and `IN` was ignored. They are now read from
      the `<WorkflowProcess>` interface only, counting both `IN` and `INOUT`; the standard ad-hoc
      workflow, for example, previously reported 2 of its 5 input variables.
    - **List-of-record workflow variables lost their type and members.** Variables typed as a
      list of records are now correctly typed as `list[...Record]` with their members.
    
    ## Changed
    
    - **Generated workflow-model class names derive from the stable workflow display name**
      (e.g. `Standard_Ad_hoc_WorkflowModel` instead of `Ad_hoc_Version_3_0_5WorkflowModel`), so
      they no longer change when the workflow version increases.
    
    ## Documentation
    
    - New **FastAPI integration** and **workflow-start** guides (with matching skills). German
      docs use "Schrank"; skill documentation links now point to the hosted Antora site.
    
    **Full changelog:** https://gitlab.ecmind.ch/open/ecmind_blue_client/-/compare/1.0.0rc2...1.0.0rc3
  • 1.0.0rc2

    Release: Release 1.0.0rc2
    # 1.0.0rc2 — Release Candidate 2
    
    Second release candidate of the `1.0.0` line. It adds steerable table-field
    replacement and fixes two object/XML handling defects, one of which affected a
    production environment. The public API of `1.0.0rc1` is unchanged apart from the
    additive parameters below.
    
    ## Added
    
    - **Steerable table-field replacement on `upsert` and `update` (#15422).** New
      `replace_table_fields(value=True)` fluent method on the upsert builder, and a
      keyword-only `replace_table_fields: bool | None` parameter on `ecm.dms.update()`
      and `ecm.dms.update_and_get()` (sync and async). `None` (default) keeps the
      automatic detection, `True` forces `REPLACETABLEFIELDS=1`, `False` suppresses it.
    
    ## Fixed
    
    - **Invalid upsert XML when a search section was used (#15424).** The `<Search>`
      element was placed after `<Fields>`, but the schema requires it first; the server
      rejected such requests (`Element 'Search' is unexpected …`). `<Search>` is now
      emitted first, so every `upsert(...).search(...)` call produces valid XML.
    - **Object definition dropped fields from unnamed PageControl tabs.** Tabs with a
      blank internal name collapsed onto one entry and lost their fields. Pages now fall
      back to their unique `page_id`, restoring the missing fields in
      `ecm.system.definition()`, `ecm.dms.model_by_name()` and `ecm-generate-models`.
    
    **Full changelog:** https://gitlab.ecmind.ch/open/ecmind_blue_client/-/compare/1.0.0rc1...1.0.0rc2
  • 1.0.0rc1

    Release: Release 1.0.0rc1
    First release candidate of the `1.0.0` line. There are **no functional changes
    to the library API** since `1.0.0a9`; this candidate stabilises the release
    tooling and test suite.
    
    - **Automatic GitLab Release on tags.** Tag pipelines now create a GitLab
      Release whose description is taken from this tag's message. The built library
      (wheel + sdist) and the rendered documentation are uploaded to the project's
      generic Package Registry and linked as permanent release assets, alongside a
      link to the matching PyPI project page. The rendered Antora site is also
      bundled as `docs-<tag>.zip`.
    
    - **Workflow process-list integration test no longer assumes the creator is the
      inbox owner.** `ecm.workflow.process_list_by_user()` returns the processes in
      a user's inbox, and an inbox item may have been created by any user. The
      `test_process_has_creation_block` test (sync and async) now only asserts that
      the `creation` block is populated. No change to library behaviour.
    
    **Full changelog:** https://gitlab.ecmind.ch/open/ecmind_blue_client/-/compare/1.0.0a9...1.0.0rc1
  • 1.0.0a9

    2c4405ab · Release 1.0.0a9 ·
    Release: 1.0.0a9
  • 1.0.0a8

    fe61107c · Release 1.0.0a8 ·
  • 1.0.0a7

    61c9ba1f · Release 1.0.0a7 ·
  • 1.0.0a6

    ### Added
    
    - **`ecm.workflow.process_list_by_user()`**: New sync and async method wrapping
      the server job `wfm.AdminGetProcessListByUser`. Returns a list of typed
      `ECMProcess` objects, each containing an `ECMProcessCreation` block and a
      tuple of `ECMProcessActivity` instances with parsed timestamps and a
      convenient `is_personalised` flag (equivalent to `Activity.State & 128`).
      The `user` argument expects the workflow-organisation user object — not the
      security user GUID.
    
    - **Full-text search on the typed model query builders**: New `.fulltext(term, **engine_options)`
      chain method on `ecm.dms.select()` (HOL) and `ecm.dms.select_lol()` (LOL), available in both
      sync and async variants. Adds a `<Fulltext>` condition to the queried object type's
      `<ConditionObject>` and accepts optional RetrievalWare engine attributes (`mode`,
      `expansion_level`, `fuzzy_spell_half_words`, `fuzzy_spell_threshold`, `max_fuzzy_spell`,
      `max_reg_expr`, `warn_max_reg_expr`, `word_expansion_limit`). Requires a configured
      RetrievalWare search engine on the enaio® server. The archive-wide `<FulltextQuery>` flavour
      (hits across multiple object types in one request) remains HOL-exclusive at the low-level
      `DmsQueryBuilder.fulltext_query()` API and is intentionally not exposed on the typed
      single-model builders.
  • 1.0.0a5

    3612af07 · Add Changelog ·
    ## 1.0.0a5
    
    ### Added
    - `ECMDocumentModelSystem.system_id` (`OBJECT_SYSTEMID`): ID of the external archive system holding the referenced file; now also loaded on `get()`.
    - Read-only enforcement for model fields via the new `ECMField(read_only=...)` parameter (`"always"` / `"init"` / `"arch"`), checked on `insert()`, `insert_variant()`, `update()` and `upsert()` (sync and async). Disable per call with `check_read_only=False`.
    
    ### Changed
    - `generate_ecm_models` now derives `read_only` from the ECM flags (`readonly` → `"always"`, `readonly_after_initialization` → `"init"`, `readonly_after_archiving` → `"arch"`) and emits it on the generated `ECMField(...)` line.
    - Clarified `foreign_id` documentation, including the *green arrow* special case.
    
    ### Fixed
    - **#15222** Model feature: `update()` failed for fields flagged "read-only after initialization". A `mandatory` + `read_only="always"` field is no longer generated as a required constructor argument.
  • 1.0.0a4

    0658eb72 · Update Readme ·
    ## Release Notes — since 1.0.0a3
    
    ### New features
    
    - **Skills bundle for AI assistants** — collection of compact, LLM-optimised skill descriptions for every public ECM operation. Auto-loaded by Claude Code / Cline / Cursor via description-based invocation. Downloadable as `/skills.zip` from the docs site.
    - **`ecm.security` user lifecycle** — `create_user()`, `update_user()`, `delete_user()`, `add_user_to_group()`, `remove_user_from_group()`, plus full sync + async coverage and DE/EN documentation.
    - **`ecm.security.export_security_system()`** — typed `ECMSecuritySystemExport` wrapping `mng.ExportSecuritySystem`. Group-level security clauses are mapped to their object rights; `ECMObjectRight` (R/W/D/X/U) and `ECMAnnotationRight` (G/P) are decoded as `IntFlag`.
    - **`ecm.system.info()`** — process-local snapshot of pool connection stats and auto-fetched server info. No RPC; cheap to call from dashboards or health checks.
    - **Pool connection statistics** — `pool.connection_stats()` returns a `list[ConnectionStats]` (host, port, server_info, connected_at, last_call_at, call_count, stable `connection_id`).
    - **`RpcServerInfo`** — fetched once per pool connection from `krn.GetServerInfoEx` and exposed on `RpcConnection.server_info`. Tolerant parser: partial server responses never break the connection.
    - **Coverage in CI** — every `unittests` run now emits Cobertura + JUnit reports and feeds the GitLab coverage badge.
    
    ### Improvements
    
    - **Codebase-wide docstring refactor** — Google-style docstrings (Args/Returns/Raises/Example) across the public API and across the test suite.
    - **`pyproject.toml` cleanup** — removed dead `[tool.uv.workspace]` / `[tool.uv.sources]` declarations, dropped redundant `setuptools-scm` and unused `pytest-xdist` from dev extras, added `pyright`. The `TcpClient` extra alias is kept and now documented as a backwards-compatibility shim.
    - **`.gitlab-ci.yml` overhaul** — shared `default.before_script` with `uv sync --frozen` (lockfile drift now fails the pipeline); `build_docs` moved into the `build` stage and now zips `skills/ecmind-blue-client` into `public/skills.zip`; `deploy_pypi_alpha` renamed to `deploy_pypi_prerelease` (regex covers `a`/`b`/`rc`); redundant `when: always` removed from deploy rules.
    - **Documentation** — new "Skills for AI assistants" / "Skills für KI-Assistenten" section on the DE + EN index pages with direct download link.
    
    ### Fixed
    
    - **`uv build` regression** introduced by the dev-extra cleanup — `--no-build-isolation` dropped from the `build` job so build dependencies come from `[build-system].requires` again.
    - Test assertions aligned with current behaviour for XML self-closing tags and SQL-quote escaping.
  • 1.0.0a3

    ## Release Notes — since 1.0.0a2
    
    ### New features
    
    - **Document variants** (dc79def) — `ecm.dms.insert_variant(...)` and `insert_variant_and_get(...)` (sync + async) for creating new variants of an existing document. The internal XML builder gained a `variant_parent_id` parameter; the variant inherits `folder_id`/`register_id` from its parent. New docs: `insert_variant`, `insert_variant_and_get`.
    - **Generic model from type name** (f104f2c) — `ecm.dms.model_by_name("…")` resolves an internal object-type name via `ecm.system.definition()` and returns the matching dynamic subclass (`ECMFolderModel` / `ECMRegisterModel` / `ECMDocumentModel`). Usable directly in `select(...)`. New doc: `model_by_name`.
    - **Default system fields inherited** (24beaaf) — `ECMRegisterModel` and `ECMDocumentModel` now append their specific `SystemFields` to `_ECMModelBase._ecm_system_fields_` instead of overriding them. Breaking for code that relied on the base fields being absent.
    
    ### Improvements
    
    - **`tcp` extra is optional again** (68fad5f) — `Client`, `Job`, `Param`, `QueryConditionField`, `QueryConditionGroup`, `QueryResultField` are lazily re-exported in `ecmind_blue_client/__init__.py` via PEP 562 `__getattr__`. The ECM abstraction (`SyncPoolClient` / `AsyncPoolClient`) can now be used without installing `XmlElement`.
    - **Pyright config** (94736bc) — `build`, `dist`, `__pycache__`, `.venv` excluded from the scan.
    
    ### Cleanup
    
    - **Expanded tests** — new suites for variants (`test_ecm_dms_variant_sync/async/unit.py`) and `model_by_name` (`test_ecm_model_sync/async.py`); minor cleanups in the async DMS tests.
  • 1.0.0a2

    1c880159 · Add std.GetDocumentStream ·
    ## Changelog since tag `1.0.0a1`
    
    ### New Features
    
    **DMS**
    - `std.GetDocumentStream` – partial reading of document file ranges (1c88015)
    - `dms.SetUserData` / `dms.GetUserData` – user-scoped data storage (86c37c1)
    - `dms.CheckOut`, `dms.UndoCheckOut`, `dms.CheckIn` including document history (693133d, b7da1e0)
    - `dms.CheckPermission` (3cc2bad)
    
    **Workflow (wfm)**
    - Full Workflow API added (e2fcdad)
    - Workflow organisations (1bcc01f)
    - `wfm.SetSubstitutes` (cbd138d)
    - `wfm.ConfigUserAbsence` (a7809df)
    - `wfm.SaveOrganisation` (d067fd8)
    
    **License & Kernel**
    - `lic.CheckLicense` and `lic.LicGetModuleInfo` (2c80f84)
    - `krn.RunScript` and `krn.EmptyJob` (78552c3)
    
    ### Improvements
    - Eliminated unnecessary `get_object_type_by_id` calls (f929ec4)
    - Tests optimised, manual unit tests added (84ab824, e3f637b)
    
    ### Documentation & Infrastructure
    - Model API documentation added (04372aa)
    - Docker container for documentation added (c8405c1, 1e03990, 5589eae, 9ce084a, 340c39c)
    - German documentation as default landing page (9f812b8)
  • 1.0.0a1

    6347ccfd · update documentation ·
    Release: 1.0.0a1
    ## Changelog: 0.9.2 → 1.0.0
    
    ### New Features
    - **Model API (ORM-style):** Declarative query builder with typed model classes, conditions, sorting, and table fields
    - **Upsert builder:** Fluent `ecm.dms.upsert()` with configurable search and action strategies
    - **Dynamic models:** Runtime model creation via `make_folder_model()` / `make_register_model()` / `make_document_model()`
    - **`ecm.security` namespace:** User and group management (`users()`, `groups()`, `roles()`, `user()`)
    - **Impersonation:** `ecm.impersonate(username)` context manager
    - **Definition module:** Full parsing of `asobjdef` XML into a typed object graph
    
    ### New Endpoints
    - `dms.XMLCopy` — copy DMS objects
    - `dms.XMLMove` — move DMS objects
    - `dms.XMLDelete` — delete DMS objects by query
    - `dms.GetObjectDetails` — retrieve detailed object metadata
    - `std.CalcDocumentDigest` / `std.FindDocumentDigest` — document integrity via hash
    - `ado.ExecuteSQL` — execute raw SQL via ADO
    - `mng.GetUserList` / `mng.GetUserAttributes` / `mng.GetUserGroups` / `mng.GetUserRoles` — user management
    - `mng.GetGroupList` / `mng.GetGroupAttributes` / `mng.GetGroupMembers` — group management
    
    ### Architecture
    - Sync/async split into `ecm/synchron/` and `ecm/asynchron/`
    - `SyncPoolClient` / `AsyncPoolClient` replace `TcpPoolClient`
    - Python 3.12+, switched to **UV** as package manager
    - Added `ECMNotFoundException` and `ECMWrongStateException`
    
    ### Documentation
    - Antora-based documentation with migration guide and quickstart
  • 0.9.2

    Release: 0.9.2
    Catch ConnectionResetError
  • 0.9.1

    Release: 0.9.1
    Add optional SQL prepared statements feature by Komm.one
  • 0.9.0

    Release: 0.9.0
    # Release notes
    
    - remove protlib dependency
    - remove deprecated SOAP and COM clients and all related dependencies
    - replace tcp_client_classes with new rpc implementation
    - Add code documentation
    - bugfix pooling errors
  • 0.8.1

    Release: 0.8.1
    * Linting warnings
    * Fix buffer of buffer in RequestFile
    * Rename parameter bytes into file_bytes init in RequestFile
    * Fix CamelCase properties in sopa_client
    * Fix JobCaller connection error handling
  • 0.8.0

    01ddad50 · Add pypi prod ·
    Release: 0.8.0
    Init CICD automation for pypi prod