Skip to content

Commit

Permalink
Updated examples, split into standalone directories, fixed pylint issues
Browse files Browse the repository at this point in the history
  • Loading branch information
dittmar committed Aug 5, 2024
1 parent 71864cd commit b361084
Show file tree
Hide file tree
Showing 25 changed files with 168 additions and 67 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased
- Breaking API changes in RequestMetadata for column metadata access
- Updates examples, split into separate standalone directories

## 0.1.22 - 2024-08-05

Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ Find the docs at https://disyinformationssysteme.github.io/cadenza-analytics-pyt


## Example:
An example extension can be found in [examples/extension/example_extensions.py](examples/extension/example_extensions.py).
Example extension can be found in [examples](examples).

To test the example extension, clone this repository, install the dependencies, navigate to the folder `examples/extension`. Run the example file in your python environment e.g.:
To test a example extension, clone this repository, install the dependencies, navigate to the folder, e.g. `examples/calculation/extension`. Run the example file in your python environment e.g.:
```
python example_extensions.py
```
Expand Down Expand Up @@ -56,7 +56,7 @@ To run the example (and your production application) in a docker container you w
The provided Dockerfile in the examples uses gunicorn with some example options, for more details consult the [documentation](https://docs.gunicorn.org/en/latest/settings.html). Important is that gunicorn has access to a function creating or providing the flask app object, which for `cadenzanalytics` is the `CadenzaAnalyticsExtensionService`.
The requirements file can use test releases when adding `--extra-index-url https://test.pypi.org/simple` in the first line. It can (re)define versions of its own or transient dependencies, but most importantly needs the `cadenzaanalytics` dependency.
```commandline
cd /examples
cd /examples/calculation
docker build . -t cadenza-analytics-example
docker image list
docker run -p 8080:8080 YOUR_CREATED_IMAGE_ID
Expand Down
File renamed without changes.
12 changes: 9 additions & 3 deletions examples/Dockerfile → examples/calculation/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
FROM registry.disy.net/docker-hub-proxy/library/python:3.11.0-slim
FROM python:3.11-slim

RUN mkdir /service
RUN mkdir /service/logs
COPY ./requirements.txt /service/requirements.txt
COPY ./extension /service/extension
WORKDIR /service

RUN apt-get update && apt-get -y upgrade
RUN pip install -r requirements.txt
RUN apt-get update && apt-get upgrade -y \
&& apt-get install -y --no-install-recommends \
build-essential \
gcc \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

RUN pip install --no-cache-dir -r requirements.txt

CMD ["gunicorn", "-w", "4", "-b", ":8080", "--chdir", "extension", "example_extensions:analytics_service()", "--access-logfile", "../logs/access.log"]
33 changes: 33 additions & 0 deletions examples/calculation/extension/example_extensions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""Example module for running a disy Cadenza analytics extension that
will show a (static) image in disy Cadenza"""
import pandas as pd

import cadenzaanalytics as ca


def calculation_echo_analytics_function(metadata: ca.RequestMetadata, data: pd.DataFrame):
return ca.CsvResponse(data, metadata.get_columns_by_attribute_group()['any_data'])


any_attribute_group = ca.AttributeGroup(
name="any_data",
print_name="Any attribute",
# any except geometry, these cannot be mixed to make it clear when a geometry or a related
# non-geometry attribute is wanted from the user
data_types=[ca.DataType.STRING, ca.DataType.INT64, ca.DataType.FLOAT64, ca.DataType.ZONEDDATETIME],
min_attributes=1
)

calculation_echo_extension = ca.CadenzaAnalyticsExtension(
relative_path="calculation-echo-extension",
analytics_function=calculation_echo_analytics_function,
print_name="Example Echo Calculation Extension",
extension_type=ca.ExtensionType.CALCULATION,
attribute_groups=[any_attribute_group]
)

analytics_service = ca.CadenzaAnalyticsExtensionService()
analytics_service.add_analytics_extension(calculation_echo_extension)

if __name__ == '__main__':
analytics_service.run_development_server(5005)
7 changes: 7 additions & 0 deletions examples/calculation/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# --extra-index-url https://test.pypi.org/simple
Flask>=2.2.5
Flask-Cors>=3.0.10
gunicorn>=20.1.0
requests-toolbelt>=1.0.0
pandas>=2.0.2
cadenzaanalytics
2 changes: 2 additions & 0 deletions examples/enrichment/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
**/__pycache__
*.py[cod]
18 changes: 18 additions & 0 deletions examples/enrichment/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
FROM python:3.11-slim

RUN mkdir /service
RUN mkdir /service/logs
COPY ./requirements.txt /service/requirements.txt
COPY ./extension /service/extension
WORKDIR /service

RUN apt-get update && apt-get upgrade -y \
&& apt-get install -y --no-install-recommends \
build-essential \
gcc \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

RUN pip install --no-cache-dir -r requirements.txt

CMD ["gunicorn", "-w", "4", "-b", ":8080", "--chdir", "extension", "example_extensions:analytics_service()", "--access-logfile", "../logs/access.log"]
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,15 @@
import cadenzaanalytics as ca


def image_analytics_function(metadata: ca.RequestMetadata, data: pd.DataFrame):
# pylint: disable=unused-argument
with open("example_image.png", "rb") as image_file:
image = image_file.read()

return ca.ImageResponse(image)


def calculation_echo_analytics_function(metadata: ca.RequestMetadata, data: pd.DataFrame):
return ca.CsvResponse(data, metadata.get_all_columns_by_attribute_group()['any_data'])


def enrichment_echo_analytics_function(metadata: ca.RequestMetadata, data: pd.DataFrame):
# pylint: disable=unused-argument
response_columns = metadata.get_all_columns_by_attribute_group()['any_data']
response_columns = metadata.get_columns_by_attribute_group()['any_data']
response_column_names = [c.name for c in response_columns]
return ca.RowWiseMappingCsvResponse(
response_columns,
lambda row: row[response_column_names])


image_attribute_group = ca.AttributeGroup(
name="data",
print_name="Data",
data_types=[ca.DataType.STRING]
)

any_attribute_group = ca.AttributeGroup(
name="any_data",
print_name="Any attribute",
Expand All @@ -41,22 +23,6 @@ def enrichment_echo_analytics_function(metadata: ca.RequestMetadata, data: pd.Da
min_attributes=1
)

image_extension = ca.CadenzaAnalyticsExtension(
relative_path="image-extension",
analytics_function=image_analytics_function,
print_name="Example Image Extension",
extension_type=ca.ExtensionType.VISUALIZATION,
attribute_groups=[image_attribute_group]
)

calculation_echo_extension = ca.CadenzaAnalyticsExtension(
relative_path="calculation-echo-extension",
analytics_function=calculation_echo_analytics_function,
print_name="Example Echo Calculation Extension",
extension_type=ca.ExtensionType.CALCULATION,
attribute_groups=[any_attribute_group]
)

enrichment_echo_extension = ca.CadenzaAnalyticsExtension(
relative_path="echo-extension",
analytics_function=enrichment_echo_analytics_function,
Expand All @@ -66,8 +32,6 @@ def enrichment_echo_analytics_function(metadata: ca.RequestMetadata, data: pd.Da
)

analytics_service = ca.CadenzaAnalyticsExtensionService()
analytics_service.add_analytics_extension(image_extension)
analytics_service.add_analytics_extension(calculation_echo_extension)
analytics_service.add_analytics_extension(enrichment_echo_extension)

if __name__ == '__main__':
Expand Down
7 changes: 7 additions & 0 deletions examples/enrichment/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# --extra-index-url https://test.pypi.org/simple
Flask>=2.2.5
Flask-Cors>=3.0.10
gunicorn>=20.1.0
requests-toolbelt>=1.0.0
pandas>=2.0.2
cadenzaanalytics
7 changes: 0 additions & 7 deletions examples/requirements.txt

This file was deleted.

2 changes: 2 additions & 0 deletions examples/visualization/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
**/__pycache__
*.py[cod]
18 changes: 18 additions & 0 deletions examples/visualization/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
FROM python:3.11-slim

RUN mkdir /service
RUN mkdir /service/logs
COPY ./requirements.txt /service/requirements.txt
COPY ./extension /service/extension
WORKDIR /service

RUN apt-get update && apt-get upgrade -y \
&& apt-get install -y --no-install-recommends \
build-essential \
gcc \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

RUN pip install --no-cache-dir -r requirements.txt

CMD ["gunicorn", "-w", "4", "-b", ":8080", "--chdir", "extension", "example_extensions:analytics_service()", "--access-logfile", "../logs/access.log"]
34 changes: 34 additions & 0 deletions examples/visualization/extension/example_extensions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""Example module for running a disy Cadenza analytics extension that
will show a (static) image in disy Cadenza"""
import pandas as pd

import cadenzaanalytics as ca


def image_analytics_function(metadata: ca.RequestMetadata, data: pd.DataFrame):
# pylint: disable=unused-argument
with open("resources/example_image.png", "rb") as image_file:
image = image_file.read()

return ca.ImageResponse(image)


image_attribute_group = ca.AttributeGroup(
name="data",
print_name="Data",
data_types=[ca.DataType.STRING]
)

image_extension = ca.CadenzaAnalyticsExtension(
relative_path="image-extension",
analytics_function=image_analytics_function,
print_name="Example Image Extension",
extension_type=ca.ExtensionType.VISUALIZATION,
attribute_groups=[image_attribute_group]
)

analytics_service = ca.CadenzaAnalyticsExtensionService()
analytics_service.add_analytics_extension(image_extension)

if __name__ == '__main__':
analytics_service.run_development_server(5005)
File renamed without changes
7 changes: 7 additions & 0 deletions examples/visualization/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# --extra-index-url https://test.pypi.org/simple
Flask>=2.2.5
Flask-Cors>=3.0.10
gunicorn>=20.1.0
requests-toolbelt>=1.0.0
pandas>=2.0.2
cadenzaanalytics
7 changes: 4 additions & 3 deletions src/cadenzaanalytics/cadenza_analytics_extension_service.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Provides a service which encapsulates the configuration and execution of individual analytics extensions. Runs a http server which
executes the individual extensions analytics function and serves an extension discovery endpoint."""
"""Provides a service which encapsulates the configuration and execution of individual analytics extensions.
Runs a http server which executes the individual extensions analytics function and serves an extension
discovery endpoint."""
import json

from flask import Flask, Response
Expand Down Expand Up @@ -39,7 +40,7 @@ def add_analytics_extension(self, analytics_extension: CadenzaAnalyticsExtension
methods=['POST'])

def run_development_server(self, port: int = 5000):
"""Start a development server wich runs the service.
"""Start a development server which runs the service.
Parameters:
----------
Expand Down
3 changes: 2 additions & 1 deletion src/cadenzaanalytics/data/analytics_extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@


class AnalyticsExtension(DataObject):
"""A class representing an analytics extension containing print_name, extension_type, attribute_groups and parameters.
"""A class representing an analytics extension containing print_name, extension_type, attribute_groups
and parameters.
Parameters
----------
Expand Down
3 changes: 2 additions & 1 deletion src/cadenzaanalytics/data/attribute_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@


class AttributeGroup(DataObject):
"""A class representing a group of attributes such as name, print_name, data_types, geometry_types, min_attributes and max_attributes.
"""A class representing a group of attributes such as name, print_name, data_types, geometry_types,
min_attributes and max_attributes.
Parameters
----------
Expand Down
3 changes: 2 additions & 1 deletion src/cadenzaanalytics/data/column_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

# pylint: disable=too-many-instance-attributes
class ColumnMetadata(DataObject):
"""A class representing metadata for columns such as the name, print_name, attribute_group_name, data_type, role, measure_aggregation, format and gemetry_type.
"""A class representing metadata for columns such as the name, print_name, attribute_group_name, data_type, role,
measure_aggregation, format and geometry_type.
Parameters
----------
Expand Down
3 changes: 2 additions & 1 deletion src/cadenzaanalytics/data/geometry_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@


class GeometryType(Enum):
"""A class representing different types of geometries such as point, linestring, polygon, multipoint, multilinestring, multipolygon.
"""A class representing different types of geometries such as point, linestring, polygon, multipoint,
multilinestring, multipolygon.
"""
POINT = "point"
LINESTRING = "linestring"
Expand Down
3 changes: 2 additions & 1 deletion src/cadenzaanalytics/data/measure_aggregation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@


class MeasureAggregation(Enum):
"""A class representing various aggregation functions for measures such as count, countDistinct, sum, average, min and max.
"""A class representing various aggregation functions for measures such as count, countDistinct,
sum, average, min and max.
"""
COUNT = "count"
COUNT_DISTINCT = "countDistinct"
Expand Down
3 changes: 2 additions & 1 deletion src/cadenzaanalytics/data/parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@


class Parameter(DataObject):
"""A class representing parameters such as name, print_name, parameter_type, options, required and default_value used in data objects.
"""A class representing parameters such as name, print_name, parameter_type, options, required
and default_value used in data objects.
Parameters
----------
Expand Down
Loading

0 comments on commit b361084

Please sign in to comment.