diff --git a/.whitesource b/.whitesource
index 7230be15..6f3269f3 100644
--- a/.whitesource
+++ b/.whitesource
@@ -11,5 +11,11 @@
"patch"
],
"automerge": true
- }]
-}
\ No newline at end of file
+ }],
+ "scanSettings": {
+ "baseBranches": ["develop"],
+ "configMode": "LOCAL",
+ "configExternalURL": "",
+ "projectToken": ""
+ }
+}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b674e8f2..6b48e975 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
# Open Prediction Service HUB
+## 2.8.0 _2022/11/28_
+
+* [DBACLD-47417] Extend OPS to support downloading of Ruleset Models
+
## 2.7.1 _2022/09/15_
* [DBACLD-58320] Fix ads ml service rule import
diff --git a/open-prediction-service.yaml b/open-prediction-service.yaml
index a6ddbfcc..40273f2b 100644
--- a/open-prediction-service.yaml
+++ b/open-prediction-service.yaml
@@ -1,7 +1,7 @@
openapi: 3.0.3
info:
title: Open Prediction Service
- version: 2.7.4-SNAPSHOT
+ version: 2.8.0-SNAPSHOT
description: The Open Prediction Service API is an effort to provide an Open API that enables unsupported native ML Providers in Decision Designer or Decision Runtime.
tags:
- name: info
@@ -213,6 +213,47 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Error'
+ /models/{model_id}/download:
+ get:
+ tags:
+ - discover
+ summary: Download model binary
+ operationId: get_binary_by_id
+ parameters:
+ - $ref: '#/components/parameters/ModelIDParam'
+ responses:
+ '200':
+ description: Successful Response
+ content:
+ # A binary file:
+ application/octet-stream: {}
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /models/{model_id}/metadata:
+ get:
+ tags:
+ - discover
+ summary: Get parsed model metadata
+ operationId: get_metadata_by_id
+ parameters:
+ - $ref: '#/components/parameters/ModelIDParam'
+ responses:
+ '200':
+ description: Successful Response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AdditionalModelInfo'
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
/endpoints:
get:
tags:
@@ -823,13 +864,15 @@ components:
unknown_file_size:
type: boolean
default: false
- description: Whether the user can upload a file whose length is unknown at the time of the request.
+ description: Whether the user can upload a file whose length(Content-Length in HTTP header) is unknown at the time of the request.
example:
capabilities:
- info
- discover
- manage
- prediction
+ - download
+ - metadata
managed_capabilities:
supported_input_data_structure:
- "auto"
@@ -854,6 +897,10 @@ components:
- discover
- manage
- run
+ # Download model binary
+ - download
+ # Inspect model specific metadata, for example for PMML model return subType (Scorecard, Ruleset)
+ - metadata
Parameter:
title: Parameter
description: Parameter for ml model invocation
@@ -907,6 +954,21 @@ components:
target:
- rel: endpoint
href: 'http://open-prediction-service.org/endpoints/8c2af534-cdce-11ea-87d0-0242ac130003'
+ AdditionalModelInfo:
+ type: object
+ title: Additional Model Information
+ required:
+ - modelPackage
+ - modelType
+ properties:
+ modelPackage:
+ type: string
+ description: The file format of binary model
+ example: pmml
+ modelType:
+ type: string
+ description: Model type of binary model
+ example: RuleSetModel
parameters:
ModelIDParam:
in: path
diff --git a/ops-client-sdk/pom.xml b/ops-client-sdk/pom.xml
index 9927c824..cf4777a9 100644
--- a/ops-client-sdk/pom.xml
+++ b/ops-client-sdk/pom.xml
@@ -6,7 +6,7 @@
com.ibm.decision
ops-client-sdk
- 2.7.4-SNAPSHOT
+ 2.8.0-SNAPSHOT
2020
@@ -224,7 +224,7 @@ limitations under the License.IBM Confidential]]>
${java.version}
${java.version}
1.8.5
- 1.6.8
+ 1.6.9
4.10.0
2.10
3.12.0
diff --git a/ops-implementations/ads-ml-service/Dockerfile b/ops-implementations/ads-ml-service/Dockerfile
index a0404874..5b1a0516 100644
--- a/ops-implementations/ads-ml-service/Dockerfile
+++ b/ops-implementations/ads-ml-service/Dockerfile
@@ -1,4 +1,4 @@
-FROM --platform=${BUILDPLATFORM} python:3.8-slim AS python-base
+FROM --platform=${BUILDPLATFORM} python:3.11-slim AS python-base
ENV \
OPS_HOME="/usr/src/ads-ml-service" \
@@ -15,6 +15,7 @@ FROM python-base AS codegen-image
COPY app/gen/. app/gen/
RUN \
+ apt-get -q update && apt-get -q install --assume-yes build-essential && \
python3 -m pip install -q --no-cache-dir --upgrade pip && \
python3 -m pip install -q datamodel-code-generator~=0.11.19 && \
datamodel-codegen \
@@ -30,8 +31,9 @@ COPY requirements.txt ./
COPY logging.yaml /etc/ads-ml-service/logging/logging.yaml
RUN \
python3 -m venv /usr/src/ads-ml-service/venv && \
+ apt-get -q update && apt-get -q install --assume-yes build-essential libpq-dev python3-numpy && \
python3 -m pip install -q --no-cache-dir --upgrade pip && \
- python3 -m pip install -q --no-cache-dir --requirement requirements.txt && \
+ python3 -m pip install -q --no-cache-dir --prefer-binary --requirement requirements.txt && \
mkdir -p /var/log/ads-ml-service && \
mkdir -p /var/lib/ads-ml-service/models
diff --git a/ops-implementations/ads-ml-service/app/api/api_v2/endpoints/capabilities.py b/ops-implementations/ads-ml-service/app/api/api_v2/endpoints/capabilities.py
index b3f9f0b5..6e9e92fb 100644
--- a/ops-implementations/ads-ml-service/app/api/api_v2/endpoints/capabilities.py
+++ b/ops-implementations/ads-ml-service/app/api/api_v2/endpoints/capabilities.py
@@ -35,7 +35,9 @@ async def server_capabilities() -> typing.Dict[typing.Text, typing.Any]:
ops_model.Capability.info,
ops_model.Capability.discover,
ops_model.Capability.manage,
- ops_model.Capability.run
+ ops_model.Capability.run,
+ ops_model.Capability.download,
+ ops_model.Capability.metadata
],
'managed_capabilities': {
'supported_input_data_structure': ['auto', 'DataFrame', 'ndarray', 'DMatrix', 'list'],
diff --git a/ops-implementations/ads-ml-service/app/api/api_v2/endpoints/models.py b/ops-implementations/ads-ml-service/app/api/api_v2/endpoints/models.py
index 0d8cb612..7eebb10f 100644
--- a/ops-implementations/ads-ml-service/app/api/api_v2/endpoints/models.py
+++ b/ops-implementations/ads-ml-service/app/api/api_v2/endpoints/models.py
@@ -17,6 +17,7 @@
import logging
import typing
+import io
import fastapi
import fastapi.encoders as encoders
@@ -28,10 +29,12 @@
import app.crud as crud
import app.gen.schemas.ops_schemas as ops_schemas
import app.runtime.model_upload as app_model_upload
+import app.runtime.inspection as app_runtime_inspection
import app.schemas as schemas
import app.schemas.binary_config as app_binary_config
import app.schemas.impl as impl
import app.core.configuration as app_conf
+import app.models as models
router = fastapi.APIRouter()
LOGGER = logging.getLogger(__name__)
@@ -182,3 +185,76 @@ async def add_binary(
model_id=model_id
)
return impl.EndpointImpl.from_database(crud.endpoint.get(db, id=m))
+
+
+@router.get(
+ path='/models/{model_id}/metadata',
+ response_model=ops_schemas.AdditionalModelInfo,
+ tags=['discover'])
+def get_model_metadata(
+ model_id: int,
+ db: saorm.Session = fastapi.Depends(deps.get_db)):
+ LOGGER.info('Retrieving model metadata for id: %s', model_id)
+ match crud.binary_ml_model.get(db=db, id=model_id):
+ case None:
+ raise fastapi.HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND, detail=f'Model with id {model_id} is not found')
+ case models.BinaryMlModel(format=app_binary_config.ModelWrapper.PICKLE | app_binary_config.ModelWrapper.JOBLIB as format):
+ return ops_schemas.AdditionalModelInfo(
+ modelPackage=format.value,
+ modelType='other')
+ case models.BinaryMlModel(format=app_binary_config.ModelWrapper.PMML, model_b64=binary):
+ match app_runtime_inspection.inspect_pmml_subtype(binary):
+ case 'Scorecard' | 'RuleSetModel' as typ:
+ return ops_schemas.AdditionalModelInfo(
+ modelPackage='pmml',
+ modelType=typ)
+ case _:
+ return ops_schemas.AdditionalModelInfo(
+ modelPackage='pmml',
+ modelType='other')
+ case _:
+ return ops_schemas.AdditionalModelInfo(
+ modelPackage='other',
+ modelType='other')
+
+
+@router.get(
+ path='/models/{model_id}/download',
+ response_class=responses.StreamingResponse,
+ tags=['discover'])
+def get_model_binary(
+ model_id: int,
+ db: saorm.Session = fastapi.Depends(deps.get_db)):
+ LOGGER.info('Retrieving model binary for id: %s', model_id)
+
+ model = crud.model.get(db=db, id=model_id)
+
+ if model is None:
+ raise fastapi.HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND, detail=f'Model with id {model_id} is not found')
+
+ filename = model.config.configuration['name']
+
+ try:
+ binary = model.endpoint.binary
+ except AttributeError:
+ raise fastapi.HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND, detail=f'Model binary with id {model_id} is not found')
+
+ if binary.format == app_binary_config.ModelWrapper.PMML:
+ file_extension = 'pmml'
+ elif binary.format == app_binary_config.ModelWrapper.PICKLE:
+ file_extension = 'pickle'
+ elif binary.format == app_binary_config.ModelWrapper.JOBLIB:
+ file_extension = 'joblib'
+ else:
+ file_extension = 'bin'
+
+ LOGGER.info('Downloading model binary with name %s and format %s', filename, file_extension)
+
+ return responses.StreamingResponse(
+ content=io.BytesIO(binary.model_b64),
+ media_type='application/octet-stream',
+ headers={'Content-Disposition': 'attachment; filename="{basename}.{extension}"'.format(
+ basename=filename, extension=file_extension)})
diff --git a/ops-implementations/ads-ml-service/app/api/api_v2/endpoints/upload.py b/ops-implementations/ads-ml-service/app/api/api_v2/endpoints/upload.py
index 60cb18a7..7986364e 100644
--- a/ops-implementations/ads-ml-service/app/api/api_v2/endpoints/upload.py
+++ b/ops-implementations/ads-ml-service/app/api/api_v2/endpoints/upload.py
@@ -77,7 +77,7 @@ async def upload(
model_binary,
input_data_structure,
output_data_structure,
- format_,
+ file_format,
name=model_name
)
diff --git a/ops-implementations/ads-ml-service/app/db/session.py b/ops-implementations/ads-ml-service/app/db/session.py
index 750c2654..521ffd29 100644
--- a/ops-implementations/ads-ml-service/app/db/session.py
+++ b/ops-implementations/ads-ml-service/app/db/session.py
@@ -43,7 +43,11 @@ def get_db_opts() -> typing.Dict[str, typing.Any]:
return opt
+def get_engine():
+ return create_engine(get_db_url(), **get_db_opts())
+
+
SessionLocal = sessionmaker(
autocommit=False,
autoflush=False,
- bind=create_engine(get_db_url(), **get_db_opts()))
+ bind=get_engine())
diff --git a/ops-implementations/ads-ml-service/app/gen/tmp.schemas.ops.yaml b/ops-implementations/ads-ml-service/app/gen/tmp.schemas.ops.yaml
index 4e0eae84..40273f2b 100644
--- a/ops-implementations/ads-ml-service/app/gen/tmp.schemas.ops.yaml
+++ b/ops-implementations/ads-ml-service/app/gen/tmp.schemas.ops.yaml
@@ -1,7 +1,7 @@
openapi: 3.0.3
info:
title: Open Prediction Service
- version: 2.7.0-SNAPSHOT
+ version: 2.8.0-SNAPSHOT
description: The Open Prediction Service API is an effort to provide an Open API that enables unsupported native ML Providers in Decision Designer or Decision Runtime.
tags:
- name: info
@@ -213,6 +213,47 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Error'
+ /models/{model_id}/download:
+ get:
+ tags:
+ - discover
+ summary: Download model binary
+ operationId: get_binary_by_id
+ parameters:
+ - $ref: '#/components/parameters/ModelIDParam'
+ responses:
+ '200':
+ description: Successful Response
+ content:
+ # A binary file:
+ application/octet-stream: {}
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /models/{model_id}/metadata:
+ get:
+ tags:
+ - discover
+ summary: Get parsed model metadata
+ operationId: get_metadata_by_id
+ parameters:
+ - $ref: '#/components/parameters/ModelIDParam'
+ responses:
+ '200':
+ description: Successful Response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AdditionalModelInfo'
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
/endpoints:
get:
tags:
@@ -823,13 +864,15 @@ components:
unknown_file_size:
type: boolean
default: false
- description: Whether the user can upload a file whose length is unknown at the time of the request.
+ description: Whether the user can upload a file whose length(Content-Length in HTTP header) is unknown at the time of the request.
example:
capabilities:
- info
- discover
- manage
- prediction
+ - download
+ - metadata
managed_capabilities:
supported_input_data_structure:
- "auto"
@@ -854,6 +897,10 @@ components:
- discover
- manage
- run
+ # Download model binary
+ - download
+ # Inspect model specific metadata, for example for PMML model return subType (Scorecard, Ruleset)
+ - metadata
Parameter:
title: Parameter
description: Parameter for ml model invocation
@@ -907,6 +954,21 @@ components:
target:
- rel: endpoint
href: 'http://open-prediction-service.org/endpoints/8c2af534-cdce-11ea-87d0-0242ac130003'
+ AdditionalModelInfo:
+ type: object
+ title: Additional Model Information
+ required:
+ - modelPackage
+ - modelType
+ properties:
+ modelPackage:
+ type: string
+ description: The file format of binary model
+ example: pmml
+ modelType:
+ type: string
+ description: Model type of binary model
+ example: RuleSetModel
parameters:
ModelIDParam:
in: path
diff --git a/ops-implementations/ads-ml-service/app/runtime/inspection.py b/ops-implementations/ads-ml-service/app/runtime/inspection.py
index e53755ab..6f635241 100644
--- a/ops-implementations/ads-ml-service/app/runtime/inspection.py
+++ b/ops-implementations/ads-ml-service/app/runtime/inspection.py
@@ -17,6 +17,7 @@
import logging
import typing
+import pickletools
import pypmml.base as pypmml_base
@@ -65,3 +66,8 @@ def inspect_pmml_model_name(model_file: bytes) -> typing.Optional[str]:
return wrapper.model.modelName
else:
return None
+
+
+def inspect_pmml_subtype(model_file: bytes) -> typing.Optional[str]:
+ wrapper = load_pmml_model(model_file).loaded_model
+ return wrapper.model.modelElement
diff --git a/ops-implementations/ads-ml-service/app/tests/api/api_v2/test_capabilities.py b/ops-implementations/ads-ml-service/app/tests/api/api_v2/test_capabilities.py
index b9fb2415..aeb6f13f 100644
--- a/ops-implementations/ads-ml-service/app/tests/api/api_v2/test_capabilities.py
+++ b/ops-implementations/ads-ml-service/app/tests/api/api_v2/test_capabilities.py
@@ -34,6 +34,8 @@ def test_get_server_capabilities(
assert 'discover' in content['capabilities']
assert 'manage' in content['capabilities']
assert 'run' in content['capabilities']
+ assert 'download' in content['capabilities']
+ assert 'metadata' in content['capabilities']
def test_get_managed_capabilities(
diff --git a/ops-implementations/ads-ml-service/app/tests/api/api_v2/test_models.py b/ops-implementations/ads-ml-service/app/tests/api/api_v2/test_models.py
index f2bd56cf..2b565ac9 100644
--- a/ops-implementations/ads-ml-service/app/tests/api/api_v2/test_models.py
+++ b/ops-implementations/ads-ml-service/app/tests/api/api_v2/test_models.py
@@ -20,6 +20,7 @@
import time
import typing
import typing as typ
+import re
import pytest
import fastapi.testclient as tstc
@@ -31,6 +32,8 @@
import app.schemas as schemas
import app.tests.predictors.identity.model as app_tests_identity
import app.tests.predictors.scikit_learn.model as app_test_skl
+import app.models as models
+import app.tests.predictors.pmml_sample.model as app_test_pmml
def test_get_model(
@@ -233,3 +236,67 @@ def test_update_binary(
assert response.status_code == 201
assert response.json()['status'] == 'in_service'
assert response_1.status_code == 422
+
+
+def test_not_supported_metadata(
+ client: tstc.TestClient,
+ xgboost_endpoint: models.Endpoint
+) -> typ.NoReturn:
+ # When
+ resp = client.get(url=f'/models/{xgboost_endpoint.id}/metadata')
+
+ # Assert
+ assert resp.ok
+ assert resp.json()['modelType'] == 'other'
+
+
+def test_pickle_metadata(
+ client: tstc.TestClient
+) -> typ.NoReturn:
+ # When
+ model = client.post(
+ url='/upload',
+ data={'format': 'pickle'},
+ files={'file': ('model.pkl', pickle.dumps(app_test_skl.get_classification_predictor()))}).json()
+ model_id = model['id']
+ resp = client.get(url=f'/models/{model_id}/metadata')
+
+ # Assert
+ assert resp.ok
+ assert resp.json()['modelPackage'] == 'pickle'
+ assert resp.json()['modelType'] == 'other'
+
+
+def test_pmml_metadata(
+ client: tstc.TestClient
+) -> typ.NoReturn:
+ # When
+ model = client.post(
+ url='/upload',
+ data={'format': 'pmml'},
+ files={'file': ('scorecard.pmml', app_test_pmml.get_pmml_scorecard_file().read_text())}).json()
+ model_id = model['id']
+ resp = client.get(url=f'/models/{model_id}/metadata')
+
+ # Assert
+ assert resp.ok
+ assert resp.json()['modelPackage'] == 'pmml'
+ assert resp.json()['modelType'] == 'Scorecard'
+
+
+def test_download_binary(
+ client: tstc.TestClient
+) -> typ.NoReturn:
+ # When
+ model_content = app_test_pmml.get_pmml_scorecard_file().read_text()
+ model = client.post(
+ url='/upload',
+ files={'file': ('scorecard.pmml', model_content)}).json()
+ model_id = model['id']
+ resp = client.get(url=f'/models/{model_id}/download')
+
+ # Assert
+ assert resp.ok
+ assert resp.content == str.encode(model_content)
+ # filename
+ assert re.findall("filename=\"(.+)\"", resp.headers['content-disposition'])[0] == 'scorecard.pmml'
diff --git a/ops-implementations/ads-ml-service/app/tests/predictors/pmml_sample/model.py b/ops-implementations/ads-ml-service/app/tests/predictors/pmml_sample/model.py
index 1473e5a0..6187c34b 100644
--- a/ops-implementations/ads-ml-service/app/tests/predictors/pmml_sample/model.py
+++ b/ops-implementations/ads-ml-service/app/tests/predictors/pmml_sample/model.py
@@ -22,5 +22,9 @@ def get_pmml_file() -> pathlib.Path:
return pathlib.Path(__file__).resolve().parent.joinpath('model.pmml')
+def get_pmml_scorecard_file() -> pathlib.Path:
+ return pathlib.Path(__file__).resolve().parent.joinpath('scorecard.pmml')
+
+
def get_pmml_no_output_schema_file() -> pathlib.Path:
return pathlib.Path(__file__).resolve().parent.joinpath('model-no-output-schema.pmml')
diff --git a/ops-implementations/ads-ml-service/app/tests/predictors/pmml_sample/scorecard.pmml b/ops-implementations/ads-ml-service/app/tests/predictors/pmml_sample/scorecard.pmml
new file mode 100644
index 00000000..643949c4
--- /dev/null
+++ b/ops-implementations/ads-ml-service/app/tests/predictors/pmml_sample/scorecard.pmml
@@ -0,0 +1,708 @@
+
+
+
+
+ 2022-11-25 05:46:41.942928
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ "F"
+
+
+
+
+ "M"
+
+
+
+
+
+
+ "D"
+
+
+
+
+ "M"
+
+
+
+
+ "S"
+
+
+
+
+
+
+ "N"
+
+
+
+
+ "Y"
+
+
+
+
+
+
+ "Auto"
+
+
+
+
+ "CC"
+
+
+
+
+ "CH"
+
+
+
+
+
+
diff --git a/ops-implementations/ads-ml-service/app/tests/runtime/test_signature_inspection.py b/ops-implementations/ads-ml-service/app/tests/runtime/test_signature_inspection.py
index 99d6c45f..135dee02 100644
--- a/ops-implementations/ads-ml-service/app/tests/runtime/test_signature_inspection.py
+++ b/ops-implementations/ads-ml-service/app/tests/runtime/test_signature_inspection.py
@@ -16,6 +16,7 @@
import pathlib
+import pickle
import app.runtime.inspection as app_signature_inspection
import app.tests.predictors.pmml_sample.model as app_test_pmml
@@ -52,3 +53,15 @@ def test_pmml_output_schema_inspection(
'probability_1': 'double',
'predicted_paymentDefault': 'integer'
}
+
+
+def test_inspect_pmml_subtype():
+ # When
+ sub_type_regression = app_signature_inspection.inspect_pmml_subtype(
+ str.encode(app_test_pmml.get_pmml_file().read_text()))
+ sub_type_scorecard = app_signature_inspection.inspect_pmml_subtype(
+ str.encode(app_test_pmml.get_pmml_scorecard_file().read_text()))
+
+ # Assert
+ assert sub_type_regression == 'RegressionModel'
+ assert sub_type_scorecard == 'Scorecard'
diff --git a/ops-implementations/ads-ml-service/app/version.py b/ops-implementations/ads-ml-service/app/version.py
index 1d8e1393..bb4701d5 100644
--- a/ops-implementations/ads-ml-service/app/version.py
+++ b/ops-implementations/ads-ml-service/app/version.py
@@ -1 +1 @@
-__version__ = '2.7.4-SNAPSHOT'
+__version__ = '2.8.0-SNAPSHOT'
diff --git a/ops-implementations/ads-ml-service/doc/installation/docker-compose.yaml b/ops-implementations/ads-ml-service/doc/installation/docker-compose.yaml
index 63b1a915..b6dfd4bf 100644
--- a/ops-implementations/ads-ml-service/doc/installation/docker-compose.yaml
+++ b/ops-implementations/ads-ml-service/doc/installation/docker-compose.yaml
@@ -2,7 +2,7 @@ version: '3'
services:
db:
- image: postgres:15.0
+ image: postgres:15.1
restart: always
environment:
POSTGRES_DB: 'serving'
diff --git a/ops-implementations/ads-ml-service/pom.xml b/ops-implementations/ads-ml-service/pom.xml
index 3347a872..e721157f 100644
--- a/ops-implementations/ads-ml-service/pom.xml
+++ b/ops-implementations/ads-ml-service/pom.xml
@@ -5,7 +5,7 @@
com.ibm.decision.ops
ml-service-implementations
- 2.7.4-SNAPSHOT
+ 2.8.0-SNAPSHOT
..
diff --git a/ops-implementations/ads-ml-service/requirements.txt b/ops-implementations/ads-ml-service/requirements.txt
index ed624918..a8e910c8 100644
--- a/ops-implementations/ads-ml-service/requirements.txt
+++ b/ops-implementations/ads-ml-service/requirements.txt
@@ -2,12 +2,12 @@
## Web interface
python-multipart==0.0.5
-sqlalchemy==1.4.43
+sqlalchemy==1.4.44
alembic==1.8.1
psycopg2-binary==2.9.5
fastapi==0.86.0
-orjson==3.8.1
-pandas==1.5.1
+orjson==3.8.2
+pandas==1.5.2
## ASGI server
hypercorn==0.14.3
@@ -33,7 +33,7 @@ pypmml==0.9.17
py4j==0.10.9.7
## Testes
-tox==4.0.0b2
+tox==4.0.0rc1
requests==2.28.1
pytest==7.2.0
nyoka==5.4.0
diff --git a/ops-implementations/ads-ml-service/tox.ini b/ops-implementations/ads-ml-service/tox.ini
index d76f3d9a..c0cc3c98 100755
--- a/ops-implementations/ads-ml-service/tox.ini
+++ b/ops-implementations/ads-ml-service/tox.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = py38
+envlist = py310, py311
skipsdist = True
[testenv]
diff --git a/ops-implementations/explanation-service/requirements.txt b/ops-implementations/explanation-service/requirements.txt
index 0e1c7fbf..674d9595 100644
--- a/ops-implementations/explanation-service/requirements.txt
+++ b/ops-implementations/explanation-service/requirements.txt
@@ -7,7 +7,7 @@ connexion[swagger-ui] ==2.14.1; python_version=="3.5" or python_version=="3.4"
werkzeug ==2.2.2; python_version=="3.5" or python_version=="3.4"
swagger-ui-bundle ==0.0.9
python_dateutil ==2.8.2
-setuptools ==65.5.1
+setuptools ==65.6.3
numpy
pandas
sklearn
diff --git a/ops-implementations/pom.xml b/ops-implementations/pom.xml
index 130c9849..a6e0fc6d 100644
--- a/ops-implementations/pom.xml
+++ b/ops-implementations/pom.xml
@@ -4,7 +4,7 @@
com.ibm.decision.ops
ml-service-implementations
- 2.7.4-SNAPSHOT
+ 2.8.0-SNAPSHOT
pom
diff --git a/ops-implementations/sagemaker-service/Dockerfile b/ops-implementations/sagemaker-service/Dockerfile
index b109d577..20fd9c3a 100755
--- a/ops-implementations/sagemaker-service/Dockerfile
+++ b/ops-implementations/sagemaker-service/Dockerfile
@@ -1,4 +1,4 @@
-FROM --platform=${BUILDPLATFORM} python:3.7-slim
+FROM --platform=${BUILDPLATFORM} python:3.11-slim
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
diff --git a/ops-implementations/sagemaker-service/openapi_server/version.py b/ops-implementations/sagemaker-service/openapi_server/version.py
index 1d8e1393..bb4701d5 100644
--- a/ops-implementations/sagemaker-service/openapi_server/version.py
+++ b/ops-implementations/sagemaker-service/openapi_server/version.py
@@ -1 +1 @@
-__version__ = '2.7.4-SNAPSHOT'
+__version__ = '2.8.0-SNAPSHOT'
diff --git a/ops-implementations/sagemaker-service/pom.xml b/ops-implementations/sagemaker-service/pom.xml
index 1e9b29fc..555e3cf4 100644
--- a/ops-implementations/sagemaker-service/pom.xml
+++ b/ops-implementations/sagemaker-service/pom.xml
@@ -5,7 +5,7 @@
com.ibm.decision.ops
ml-service-implementations
- 2.7.4-SNAPSHOT
+ 2.8.0-SNAPSHOT
..
diff --git a/ops-implementations/sagemaker-service/requirements.txt b/ops-implementations/sagemaker-service/requirements.txt
index 67f4a523..8730624e 100644
--- a/ops-implementations/sagemaker-service/requirements.txt
+++ b/ops-implementations/sagemaker-service/requirements.txt
@@ -8,5 +8,5 @@ openapi-schema-validator==0.3.4
protobuf==3.20.3
# --- Dependences of sagemaker --- end
-boto3==1.26.3
-sagemaker==2.116.0
+boto3==1.26.21
+sagemaker==2.118.0
diff --git a/ops-implementations/wml-service/Dockerfile b/ops-implementations/wml-service/Dockerfile
index 40492e43..0aa1555a 100755
--- a/ops-implementations/wml-service/Dockerfile
+++ b/ops-implementations/wml-service/Dockerfile
@@ -1,4 +1,4 @@
-FROM --platform=${BUILDPLATFORM} python:3.7-slim
+FROM --platform=${BUILDPLATFORM} python:3.11-slim
RUN pip3 install connexion[swagger-ui]
diff --git a/ops-implementations/wml-service/pom.xml b/ops-implementations/wml-service/pom.xml
index 8f3a7e44..b15d539f 100644
--- a/ops-implementations/wml-service/pom.xml
+++ b/ops-implementations/wml-service/pom.xml
@@ -5,7 +5,7 @@
com.ibm.decision.ops
ml-service-implementations
- 2.7.4-SNAPSHOT
+ 2.8.0-SNAPSHOT
..
diff --git a/ops-implementations/wml-service/requirements.txt b/ops-implementations/wml-service/requirements.txt
index 0c946872..f3d2b2e4 100755
--- a/ops-implementations/wml-service/requirements.txt
+++ b/ops-implementations/wml-service/requirements.txt
@@ -1,5 +1,5 @@
connexion[swagger-ui] ==2.14.1
python_dateutil ==2.8.2
-setuptools ==65.5.1
-jsonschema ==4.17.0
+setuptools ==65.6.3
+jsonschema ==4.17.3
requests ==2.28.1
diff --git a/ops-implementations/wml-service/swagger_server/version.py b/ops-implementations/wml-service/swagger_server/version.py
index 1d8e1393..bb4701d5 100644
--- a/ops-implementations/wml-service/swagger_server/version.py
+++ b/ops-implementations/wml-service/swagger_server/version.py
@@ -1 +1 @@
-__version__ = '2.7.4-SNAPSHOT'
+__version__ = '2.8.0-SNAPSHOT'
diff --git a/ops-implementations/wml-service/test-requirements.txt b/ops-implementations/wml-service/test-requirements.txt
index c4785bf9..9291f709 100755
--- a/ops-implementations/wml-service/test-requirements.txt
+++ b/ops-implementations/wml-service/test-requirements.txt
@@ -1,6 +1,3 @@
flask_testing==0.8.1
coverage==6.5.0
nose==1.3.7
-pluggy==1.0.0
-py==1.11.0
-randomize==0.14
diff --git a/whitesource.config b/whitesource.config
new file mode 100644
index 00000000..bf46b364
--- /dev/null
+++ b/whitesource.config
@@ -0,0 +1 @@
+offline=True
\ No newline at end of file