Skip to content

Commit 7da2f7f

Browse files
authored
enhancements to testing framework (#142)
**Improvements** - Added `Session.version_info()` to check which version of Viya the session is connected to. - Updated the `properties=` parameter of `model_repository.create_model()` to accept a dictionary containing custom property names and values, and to correctly indicate their type (numeric, string, date, datetime) when passing the values to Viya. **Changes** - Deprecated `core.platform_version()` in favor of `Session.version_info()`. - A `RuntimeError` is now raised if an obsolete service is called on a Viya 4 session (sentiment_analysis, text_categorization, and text_parsing) - Replaced the JSON cassettes used for testing with compressed binary cassettes to save space. - Updated the testing framework to allow regression testing of multiple Viya versions. **Bugfixes** - Fixed an issue with `register_model()` that caused invalid SAS score code to be generated when registering an ASTORE model in Viya 3.5. - Fixed a bug where calling a "get_item()" function and passing `None` would throw an error on most services instead of returning `None`.
1 parent 4b05179 commit 7da2f7f

File tree

515 files changed

+1251
-167590
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

515 files changed

+1251
-167590
lines changed

.deepsource.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,6 @@ name = "python"
1414
enabled = true
1515

1616
[analyzers.meta]
17-
runtime_version = "3.x.x"
17+
runtime_version = "3.x.x"
18+
max_line_length = 90
19+
skip_doc_coverage = ["init", "magic", "nonpublic"]

.github/workflows/build-test-deploy.yml

+1-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ jobs:
2121
LANG: en_US.UTF-8
2222
strategy:
2323
matrix:
24-
python-version: [3.6, 3.7, 3.8] #, 3.9, '3.10'] <-- auto fails due to lack of 3.9 & 3.10 env in tox.ini
25-
# Removing support for Python 3.5
24+
python-version: ['3.6', '3.7', '3.8', '3.9', '3.10']
2625
os-version: [ubuntu-latest, windows-latest, macos-latest]
2726

2827
steps:

CHANGELOG.md

+36-16
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,57 @@
11
Unreleased
22
----------
33

4+
**Improvements**
5+
- Added `Session.version_info()` to check which version of Viya the session is connected to.
6+
- Updated the `properties=` parameter of `model_repository.create_model()` to accept a dictionary containing
7+
custom property names and values, and to correctly indicate their type (numeric, string, date, datetime) when
8+
passing the values to Viya.
9+
10+
**Changes**
11+
- Deprecated `core.platform_version()` in favor of `Session.version_info()`.
12+
- A `RuntimeError` is now raised if an obsolete service is called on a Viya 4 session (sentiment_analysis,
13+
text_categorization, and text_parsing)
14+
- Replaced the JSON cassettes used for testing with compressed binary cassettes to save space.
15+
- Updated the testing framework to allow regression testing of multiple Viya versions.
16+
17+
**Bugfixes**
18+
- Fixed an issue with `register_model()` that caused invalid SAS score code to be generated when registering an
19+
ASTORE model in Viya 3.5.
20+
- Fixed a bug where calling a "get_item()" function and passing `None` would throw an error on most services instead
21+
of returning `None`.
22+
23+
424
v1.7.3 (2022-09-20)
525
-------------------
626
**Improvements**
7-
- Refactor astore model upload to fix 422 response from SAS Viya 4
8-
- ASTORE model import now uses SAS Viya to generate ASTORE model assets
9-
- Expanded usage for cas_management service (credit to @SilvestriStefano)
27+
- Refactor astore model upload to fix 422 response from SAS Viya 4
28+
- ASTORE model import now uses SAS Viya to generate ASTORE model assets
29+
- Expanded usage for cas_management service (credit to @SilvestriStefano)
1030

1131
**Bugfixes**
12-
- ASTORE model import no longer returns a 422 error
13-
- Fix improper filter usage for model_repository service
14-
- Fix error with loss of stream in add_model_content call for duplicate content
15-
- Update integration test cassettes for SAS Viya 4
32+
- ASTORE model import no longer returns a 422 error
33+
- Fix improper filter usage for model_repository service
34+
- Fix error with loss of stream in add_model_content call for duplicate content
35+
- Update integration test cassettes for SAS Viya 4
1636

1737
v1.7.2 (2022-06-16)
1838
-------------------
1939
**Improvements**
20-
- Added a new example notebook for git integration
21-
- Added a model migration tool for migrating Python models from Viya 3.5 to Viya 4
22-
- Improved handling of CAS authentication with tokens
40+
- Added a new example notebook for git integration
41+
- Added a model migration tool for migrating Python models from Viya 3.5 to Viya 4
42+
- Improved handling of CAS authentication with tokens
2343

2444
**Bugfixes**
25-
- Fixed git integration failure caused by detached head
26-
- Fixed minor bugs in score code generation feature
27-
- Fixed 500 error when importing models to Viya 4 with prewritten score code
28-
- Fixed incorrect handling of optional packages in pzmm
45+
- Fixed git integration failure caused by detached head
46+
- Fixed minor bugs in score code generation feature
47+
- Fixed 500 error when importing models to Viya 4 with prewritten score code
48+
- Fixed incorrect handling of optional packages in pzmm
2949

3050
v1.7.1 (2022-04-19)
3151
-------------------
3252
**Bugfixes**
33-
- Removed linux breaking import from new git integration feature
34-
- Various minor bug fixes in the git integration feature
53+
- Removed linux breaking import from new git integration feature
54+
- Various minor bug fixes in the git integration feature
3555

3656
v1.7.0 (2022-04-07)
3757
-------------------

src/sasctl/_services/model_repository.py

+32-11
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
"""The Model Repository service supports registering and managing models."""
88

9+
import datetime
910
from warnings import warn
1011

1112
from .service import Service
@@ -292,8 +293,9 @@ def create_model(
292293
Indicates whether the model can be retrained or not.
293294
is_immutable : bool
294295
Indicates whether the model can be changed or not.
295-
properties : array_like, optional (custom properties)
296-
Custom model properties that can be set: name, value, type
296+
properties : dict, optional
297+
Custom model properties provided as name: value pairs.
298+
Allowed types are int, float, string, datetime.date, and datetime.datetime
297299
input_variables : array_like, optional
298300
Model input variables. By default, these are the same as the model
299301
project.
@@ -334,9 +336,27 @@ def create_model(
334336
elif is_challenger:
335337
model["role"] = "challenger"
336338

337-
model.setdefault(
338-
"properties", [{"name": k, "value": v} for k, v in properties.items()]
339-
)
339+
model.setdefault("properties", [])
340+
for k, v in properties.items():
341+
if type(v) in (int, float):
342+
t = "numeric"
343+
elif type(v) is datetime.date:
344+
# NOTE: do not use isinstance() to compare types as isinstance(v, datetime.date) evaluates to True
345+
# even for datetime.datetime instances.
346+
# Convert to datetime to extract timestamp and then scale to milliseconds
347+
v = datetime.datetime(v.year, v.month, v.day).timestamp()
348+
v = int(v * 1000)
349+
t = "date"
350+
elif type(v) is datetime.datetime:
351+
# Extract timestamp and scale to milliseconds
352+
v = int(v.timestamp() * 1000)
353+
t = "dateTime"
354+
else:
355+
t = "string"
356+
v = str(v)
357+
358+
model["properties"].append({"name": k, "value": v, "type": t})
359+
340360
model["scoreCodeType"] = score_code_type or model.get("scoreCodeType")
341361
model["trainTable"] = training_table or model.get("trainTable")
342362
model[
@@ -422,8 +442,11 @@ def add_model_content(
422442
for item in model_contents:
423443
if item.name == name:
424444
cls.delete("/models/{}/contents/{}".format(id_, item.id))
445+
425446
# Return json stream to beginning of file content
426-
files["files"][1].seek(0)
447+
if hasattr(files["files"][1], "seek"):
448+
files["files"][1].seek(0)
449+
427450
return cls.post(
428451
"/models/{}/contents".format(id_),
429452
files=files,
@@ -777,7 +800,7 @@ def get_model_details(cls, model):
777800

778801
@classmethod
779802
def list_project_versions(cls, project):
780-
"""_summary_
803+
"""Get a list of all versions of a project.
781804
782805
Parameters
783806
----------
@@ -796,8 +819,6 @@ def list_project_versions(cls, project):
796819
modified : datetime
797820
798821
"""
799-
from datetime import datetime
800-
801822
project_info = cls.get_project(project)
802823

803824
if project_info is None:
@@ -813,7 +834,7 @@ def list_project_versions(cls, project):
813834
"name": version.name,
814835
"id": version.id,
815836
"number": version.versionNumber,
816-
"modified": datetime.strptime(
837+
"modified": datetime.datetime.strptime(
817838
version.modifiedTimeStamp, "%Y-%m-%dT%H:%M:%S.%fZ"
818839
),
819840
}
@@ -823,7 +844,7 @@ def list_project_versions(cls, project):
823844
"name": projectVersions.name,
824845
"id": projectVersions.id,
825846
"number": projectVersions.versionNumber,
826-
"modified": datetime.strptime(
847+
"modified": datetime.datetime.strptime(
827848
projectVersions.modifiedTimeStamp, "%Y-%m-%dT%H:%M:%S.%fZ"
828849
),
829850
}

src/sasctl/_services/sentiment_analysis.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77

88
from .service import Service
9-
from ..core import uri_as_str
9+
from ..core import current_session, uri_as_str
1010

1111

1212
class SentimentAnalysis(Service):
@@ -71,6 +71,11 @@ def analyze_sentiment(
7171
:meth:`cas_management.get_table <.CASManagement.get_table>`
7272
7373
"""
74+
if current_session().version_info() >= 4:
75+
raise RuntimeError(
76+
"The Sentiment Analysis service was removed from Viya 4."
77+
)
78+
7479
if documents is None:
7580
raise TypeError("`documents` cannot be None.")
7681

src/sasctl/_services/service.py

+3
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,9 @@ def get_item(cls, item, refresh=False):
235235
calls when data is already available on the client.
236236
237237
"""
238+
if item is None:
239+
return item
240+
238241
# If the input already appears to be the requested object just
239242
# return it, unless a refresh of the data was explicitly requested.
240243
if isinstance(item, dict) and all(k in item for k in ("id", "name")):

src/sasctl/_services/text_categorization.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77

88
from .service import Service
9-
from ..core import uri_as_str
9+
from ..core import current_session, uri_as_str
1010

1111

1212
class TextCategorization(Service):
@@ -64,6 +64,11 @@ def categorize(
6464
:meth:`cas_management.get_table <.CASManagement.get_table>`
6565
6666
"""
67+
if current_session().version_info() >= 4:
68+
raise RuntimeError(
69+
"The Text Categorization service was removed from Viya 4."
70+
)
71+
6772
if documents is None:
6873
raise TypeError("`documents` cannot be None.")
6974

src/sasctl/_services/text_parsing.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77

88
from .service import Service
9-
from sasctl.core import uri_as_str
9+
from sasctl.core import current_session, uri_as_str
1010

1111

1212
class TextParsing(Service):
@@ -100,6 +100,8 @@ def parse_documents(
100100
:meth:`cas_management.get_table <.CASManagement.get_table>`
101101
102102
"""
103+
if current_session().version_info() >= 4:
104+
raise RuntimeError("The Text Parsing service was removed from Viya 4.")
103105

104106
if documents is None:
105107
raise TypeError("`documents` cannot be None.")

0 commit comments

Comments
 (0)