Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
ecdb478
Feat: Changed version scheme to Cadenza versioning and adjusted GitHu…
buddemat Oct 2, 2025
9d50d2f
Docs: Broke up long line into separate lines.
buddemat Oct 2, 2025
a58aa74
Feat: Running CI docs pipeline on all branches.
buddemat Oct 2, 2025
12d45a1
Fix: Running CI docs pipeline on all branches.
buddemat Oct 2, 2025
8f11efd
Fix: Running CI docs pipeline on all branches.
buddemat Oct 2, 2025
1f5df0b
Fix: Corrected URL path fpr CI docs deployment.
buddemat Oct 2, 2025
5c3ace2
Feat: Corrected version that is inserted into docs in CI job.
buddemat Oct 2, 2025
4bdafcb
Fix: Added missing closing parenthesis in docs CI job yaml.
buddemat Oct 2, 2025
f9d91e6
Feat: Changed docs deployment paths to allow deploying docs for each …
buddemat Oct 6, 2025
c2a2e77
Feat: Updated docs and reverted documentation git workflow due to inc…
buddemat Oct 11, 2025
6e8b99c
Feat: Added target to external link to force opening in browser windo…
buddemat Oct 14, 2025
0501a55
Fix: Added target to external link to force opening in new browser wi…
buddemat Oct 14, 2025
9e12bd3
Fix: Reverted adding target to external link, since not supported in …
buddemat Oct 14, 2025
c27422f
Docs: Broke up paragraphs into separate lines.
buddemat Oct 17, 2025
520f0c6
Chore: Updated github workflow to trigger document generation on gith…
buddemat Oct 17, 2025
52cf09c
Chore: Disabled positional-argument warning in pylintrc because of fa…
buddemat Oct 17, 2025
d374607
Chore: Consolidated disabled pylint options in MASTER section for bet…
buddemat Oct 17, 2025
17efc46
Fix: Fixed wrong workflow name in doc building action.
buddemat Oct 17, 2025
7bbdcc7
Style: Minor changes to fix pylint errors.
buddemat Oct 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions .github/workflows/branchOffCadenzaVersion.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
name: Branch off Cadenza Version

on:
workflow_dispatch:
inputs:
cadenza-version:
type: string
required: true
description: |
Next Cadenza Main Version
(e.g. '10.4' for setting the main branch up for development against Cadenza 10.4. This would make 10.4.0-dev the new main branch version.)


jobs:
release:
runs-on: ubuntu-latest

steps:
- name: Validate version input
if: "${{ github.event.inputs.cadenza-version != '' }}"
run: |
if ! [[ '${{ github.event.inputs.cadenza-version }}' =~ ^[0-9]+\.[0-9]+$ ]]; then
echo "Cadenza Version must be specified in the format x.x (e.g. 10.4). Was '${{ github.event.inputs.cadenza-version }}'." >&2
exit 1
fi

- uses: actions/create-github-app-token@v1
id: app-token
with:
app-id: ${{ vars.DISY_RELEASE_APP_ID }}
private-key: ${{ secrets.DISY_RELEASE_APP_SECRET }}

- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ steps.app-token.outputs.token }}

- name: Set up Python
uses: actions/setup-python@v3
with:
python-version: ${{ vars.PYTHON_VERSION }}

# poetry is needed for building and for poetry-bumpversion for version management
- name: Install poetry
run: |
pipx install poetry
poetry self add poetry-bumpversion


# Needed for creating the tag
- name: Configure Git
run: |
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git config --global user.name "github-actions[bot]"

- name: Determine branch name
run: echo "BRANCH_NAME=v$(poetry version patch --dry-run -s | cut -d. -f1,2).x" >> $GITHUB_ENV

- name: Create branch for current version
run: git branch ${{ env.BRANCH_NAME }} main

- name: Bump package version of main
run: |
poetry version ${{ github.event.inputs.cadenza-version }}.0-dev
echo "NEW_VERSION=$(poetry version -s)" >> $GITHUB_ENV

- name: Commit and tag changes
run: |
git add "pyproject.toml"
git commit -m "chore: branch off main as ${{ env.BRANCH_NAME }} and bump main version to ${{ env.NEW_VERSION }}"

- name: Push changes
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: git push -u origin ${{ env.BRANCH_NAME }} && git push origin && git push --tags
56 changes: 18 additions & 38 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -1,51 +1,31 @@
name: pdoc
name: Trigger GitHub pages documentation build

# build the documentation whenever there are new commits on main
# build the documentation on branch "githubpages"
on:
release:
types: [published]
push:
branches:
- main
# Alternative: only build for tags.
# tags:
# - '*'
- '*'
## Alternative: only build for tags.
#tags:
# - '*'
workflow_dispatch:

# security: restrict permissions for CI jobs.
permissions:
contents: read

jobs:
# Build the documentation and upload the static HTML files as an artifact.
build:
# Trigger the build script for the documentation on the githubpages branch
trigger-pages:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ vars.PYTHON_VERSION }}

# ADJUST THIS: install all dependencies (including pdoc)
- run: |
python -m pip install --upgrade pip
pip install pdoc
pip install .
# build documentation into docs/.
- run: pdoc --favicon https://www.disy.net/favicon.ico --logo https://www.disy.net/typo3conf/ext/contentelements/Resources/Public/dist/img/logo-disy.svg --logo-link https://www.disy.net/en/products/disy-cadenza -o docs/ --no-show-source src/cadenzaanalytics

- uses: actions/upload-pages-artifact@v3
with:
path: docs/

# Deploy the artifact to GitHub pages.
# This is a separate job so that only actions/deploy-pages has the necessary permissions.
deploy:
needs: build
runs-on: ubuntu-latest
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- id: deployment
uses: actions/deploy-pages@v4
- name: Trigger githubpages workflow
uses: benc-uk/workflow-dispatch@v1
with:
workflow: githubpages.yml
ref: githubpages
# The fine-grained PAT will expire after 1 year and then needs to be renewed!
token: ${{ secrets.WORKFLOW_TRIGGER_TOKEN || secrets.GITHUB_TOKEN }}
79 changes: 41 additions & 38 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,24 +1,7 @@
name: Release

on:
workflow_dispatch:
inputs:
release-type:
type: choice
description: 'Release type'
required: true
options:
- patch
- minor
- major
deployment-env:
type: choice
description: 'Deployment environment'
required: true
options:
- test.pypi.org
- pypi.org
default: 'test.pypi.org'
workflow_dispatch

jobs:
release:
Expand Down Expand Up @@ -65,25 +48,47 @@ jobs:
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git config --global user.name "github-actions[bot]"

- name: Bump package version
- name: Prepare package version (e.g. 1.2.3-dev => 1.2.3)
run: |
echo "RELEASE_VERSION=$(poetry version patch --dry-run -s)" >> $GITHUB_ENV

- name: Set release tag to 'latest'
run: |
echo "NEW_VERSION=$(poetry version ${{ github.event.inputs.release-type }} -s | head -n 1)" >> $GITHUB_ENV
echo "RELEASE_TAG=latest" >> $GITHUB_ENV


# Create a dist/wheel for the bumped version now after "poetry version" has run
- name: Build
run: |
poetry build

# either push to test.pypi.org or pypi.org depending on user input
- name: Publish package distributions to Test (!) PyPI
# if: "${{ github.event.inputs.deployment-env == 'test.pypi.org' }}"
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/


#- name: Publish package distributions to PyPI
# if: "${{ github.event.inputs.deployment-env == 'pypi.org' }}"
# uses: pypa/gh-action-pypi-publish@release/v1


# Update changelog unreleased section with new version
- name: Update changelog
uses: superfaceai/release-changelog-action@v2
with:
path-to-changelog: CHANGELOG.md
version: ${{ env.NEW_VERSION }}
version: ${{ env.RELEASE_VERSION }}
operation: release

- name: Commit and tag changes
run: |
git add "pyproject.toml"
git add "CHANGELOG.md"
git commit -m "chore: release ${{ env.NEW_VERSION }}"
git tag ${{ env.NEW_VERSION }}
git commit -m "chore: release ${{ env.RELEASE_VERSION }}"
git tag ${{ env.RELEASE_VERSION }}

- name: Push changes
env:
Expand All @@ -95,31 +100,29 @@ jobs:
uses: superfaceai/release-changelog-action@v2
with:
path-to-changelog: CHANGELOG.md
version: ${{ env.NEW_VERSION }}
version: ${{ env.RELEASE_VERSION }}
operation: read

- name: Update GitHub release documentation
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ env.NEW_VERSION }}
tag_name: ${{ env.RELEASE_VERSION }}
body: ${{ steps.get-changelog.outputs.changelog }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}


# Create a dist/wheel for the bumped version now after "poetry version" has run
- name: Build
- name: Bump package version to new dev version (e.g. 1.2.3 => 1.2.4-dev)
run: |
poetry build
poetry version --dry-run "$(poetry version patch --dry-run -s)-dev"
DEV_VERSION=$(poetry version -s) && echo "DEV_VERSION=$DEV_VERSION" >> $GITHUB_ENV # Determine DEV_VERSION

# either push to test.pypi.org or pypi.org depending on user input
- name: Publish package distributions to Test (!) PyPI
if: "${{ github.event.inputs.deployment-env == 'test.pypi.org' }}"
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
- name: Commit version bump
run: |
git add "pyproject.toml"
git commit -m "chore: bump up version to ${{ env.DEV_VERSION }}"

- name: Push changes
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: git push origin

- name: Publish package distributions to PyPI
if: "${{ github.event.inputs.deployment-env == 'pypi.org' }}"
uses: pypa/gh-action-pypi-publish@release/v1
9 changes: 5 additions & 4 deletions .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ disable=
missing-class-docstring,
missing-function-docstring,
missing-module-docstring,
too-many-arguments,
too-many-positional-arguments,
too-few-public-methods,
duplicate-code

[DESIGN]
max-args=9

[FORMAT]
max-line-length=120

[MISCELLANEOUS]
notes=FIXME

[MESSAGES CONTROL]
disable=duplicate-code
26 changes: 15 additions & 11 deletions docs/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@

# disy Cadenza Analytics Extensions

An Analytics Extension extends the functional spectrum of [disy Cadenza](https://www.disy.net/en/products/disy-cadenza/) with an analysis function or a visualisation type. An Analytics Extension is a web service that exchanges structured data with disy Cadenza via the Cadenza API. A user can integrate an analysis extension into disy Cadenza via the Management Center and manage it there (if they have the appropriate rights).
An Analytics Extension extends the functional spectrum of [disy Cadenza](https://www.disy.net/en/products/disy-cadenza/) with an analysis function or a visualisation type.
An Analytics Extension is a web service that exchanges structured data with disy Cadenza via the Cadenza API.
A user can integrate an analysis extension into disy Cadenza via the Management Center and manage it there (if they have the appropriate rights).

As of disy Cadenza Autumn 2023 (9.3), the following types and capabilities of analysis extensions are officially supported:

Expand All @@ -31,9 +33,11 @@ An Analytics Extension defines one endpoint that, depending on the HTTP method o
--->
<img src="communication.png" alt="(Image: Communication between disy Cadenza and Analytics Extension)" width="800">

When receiving an `HTTP(S) GET` request, the endpoint returns a JSON representation of the extention's configuration. This step is executed once when registering the Analytics Extension from the disy Cadenza Management Center GUI and does not need to be repeated unless the extension's configuration changes.
When receiving an `HTTP(S) GET` request, the endpoint returns a JSON representation of the extention's configuration.
This step is executed once when registering the Analytics Extension from the disy Cadenza Management Center GUI and does not need to be repeated unless the extension's configuration changes.

By sending an `HTTP(S) POST` request to the same endpoint and including the data, metadata and parameters as specified in the extension's configuration as payload, the extension is executed. This step is executed each time that the Analytics Extension is invoked from the disy Cadenza GUI and Cadenza takes care of properly formatting the payload.
By sending an `HTTP(S) POST` request to the same endpoint and including the data, metadata and parameters as specified in the extension's configuration as payload, the extension is executed.
This step is executed each time that the Analytics Extension is invoked from the disy Cadenza GUI and Cadenza takes care of properly formatting the payload.

The `cadenzaanalytics` module provides the functionality to abstract the required communication and easily configure the Analytics Extension's responses to the above requests.

Expand All @@ -53,13 +57,11 @@ The `cadenzaanalytics` package has the following dependencies:
* [Pandas](https://pandas.pydata.org/)
* requests-toolbelt

The first version of disy Cadenza that supports Analytics Extensions is disy Cadenza Autumn 2023 (9.3). For each disy Cadenza version, the correct corresponding library version needs to be used:

|disy Cadenza version | cadenzaanalytics version|
|---------------------|-------------------------|
| 9.3 (Autumn 2023) | < 0.2 (beta)|

For each disy Cadenza version, the correct corresponding library version needs to be used.
The disy Cadenza main version is reflected in the corresponding major and minor version of `cadenzaanalytics` (e.g. 10.4.0 for Cadenza 10.4), while the last version segment is increased for both bugfixes and functional changes.

For Cadenza 10.2 and earlier versions, `cadenzaanalytics` used a semantic versioning scheme.
The first version of disy Cadenza that supported Analytics Extensions is disy Cadenza Autumn 2023 (9.3).

<!--
## Installation via PyPI
Expand All @@ -78,7 +80,8 @@ pip install cadenzaanalytics==0.1.21


## Installation from Source
The source of the package can be obtained from the project's public [GitHub repository](https://github.com/DisyInformationssysteme/cadenza-analytics-python). Alternatively with each release of disy Cadenza, the offline source code of the matching version of `cadenzaanalytics` is packaged in the distributions `developer.zip`.
The source of the package can be obtained from the project's public [GitHub repository](https://github.com/DisyInformationssysteme/cadenza-analytics-python).
Alternatively with each release of disy Cadenza, the offline source code of the matching version of `cadenzaanalytics` is packaged in the distributions `developer.zip`.

Once the repository is locally available, the package can be installed using the package installer [`pip`](https://pypi.org/project/pip/).
To install the package from source, navigate to the root folder of the project and run:
Expand Down Expand Up @@ -231,7 +234,8 @@ The table shows the mapping to Pyton data types:
| Geometry | string | `"POINT(8.41594949941623 49.0048124984033)"` | A geometry is represented as a [WKT](https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry) string.<br><br>*Note:* By default, coordinates use the WGS84 projection. |


Parameters are stored in `metadata` as well. They are always passed as `string` and can be read through the [`RequestMetadata`](cadenzaanalytics/request/request_metadata.html) methods `get_parameter` for a single parameter, respectively `get_parameters` for a dictionary of all parameters.
Parameters are stored in `metadata` as well.
They are always passed as `string` and can be read through the [`RequestMetadata`](cadenzaanalytics/request/request_metadata.html) methods `get_parameter` for a single parameter, respectively `get_parameters` for a dictionary of all parameters.

```python
param_flag = metadata.get_parameter('flag')
Expand Down
7 changes: 4 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ package-mode = true
name = "cadenzaanalytics"
authors = [
"Julian Janßen <julian.janssen@disy.net>",
"Daniel Dittmar <daniel.dittmar@disy.net>"
"Daniel Dittmar <daniel.dittmar@disy.net>",
"Matthias Budde <matthias.budde@disy.net>"
]
version="0.1.26"
version="10.3.0-dev"
description = "Official Python Package for creation of disy Cadenza analytics extensions"
readme = "README.md"
license = "Apache-2.0"
Expand All @@ -36,4 +37,4 @@ name = "cadenzaanalytics"
[project.urls]
Repository = "https://github.com/DisyInformationssysteme/cadenza-analytics-python"

[tool.poetry_bumpversion]
[tool.poetry_bumpversion]
7 changes: 4 additions & 3 deletions src/cadenzaanalytics/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
"""The `cadenzaanalytics` module provides functionality to extend the business
and location intelligence software [disy Cadenza](https://www.disy.net/en/products/disy-cadenza/)
with Analytics Extensions, which may be used to execute custom Python code, e.g.
to create, enrich or visualize data using Python.
and location intelligence software [disy Cadenza](https://www.disy.net/en/products/disy-cadenza/)
with Analytics Extensions, which may be used to execute custom Python code, e.g.
to create, enrich or visualize data using Python.

The purpose of this module is to encapsulate the communication via the Cadenza API.

This is `cadenzaanalytics` version {{version}}.

.. include:: ../../docs/intro.md
"""
Expand Down
4 changes: 3 additions & 1 deletion src/cadenzaanalytics/cadenza_analytics_extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,6 @@ def _get_request_data(self, multipart_request) -> AnalyticsRequest:
return AnalyticsRequest(metadata, df_data)

def _get_from_request(self, multipart_request, part_name):
return multipart_request.form[part_name] if part_name in multipart_request.form else multipart_request.files[part_name].read().decode('UTF-8')
if part_name in multipart_request.form:
return multipart_request.form[part_name]
return multipart_request.files[part_name].read().decode('UTF-8')
Loading
Loading