Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Anomaly Detector 3.0.0b2 release #13351

Merged
merged 4 commits into from
Aug 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 14 additions & 1 deletion sdk/anomalydetector/azure-ai-anomalydetector/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
# Release History

## 3.0.0b2 (Unreleased)
## 3.0.0b2 (2020-08-27)

**Bug Fixes**
- Fixed an issue with ChangePointDetect
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to mark Breaking Changes here?


**Breaking Changes**
- Renamed `entire_detect` to `detect_entire_series`
- Renamed `APIError` to `AnomalyDetectorError`
- Renamed `Request` to `DetectRequest`
- Renamed `LastDetect` to `DetectLastPoint`
- Renamed `ChangePointDetect` to `DetectChangePoint`
- Renamed `Granularity` to `TimeGranularity`
- Renamed `minutely` and `secondly` to `per_minute` and `per_second`
- Renamed `Point` to `TimeSeriesPoint`


## 3.0.0b1 (2020-08-17)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@

class AnomalyDetectorClientOperationsMixin:

async def entire_detect(
async def detect_entire_series(
self,
body: "models.Request",
body: "models.DetectRequest",
**kwargs
) -> "models.EntireDetectResponse":
"""Detect anomalies for the entire series in batch.
Expand All @@ -32,7 +32,7 @@ async def entire_detect(

:param body: Time series points and period if needed. Advanced model parameters can also be set
in the request.
:type body: ~azure.ai.anomalydetector.models.Request
:type body: ~azure.ai.anomalydetector.models.DetectRequest
:keyword callable cls: A custom type or function that will be passed the direct response
:return: EntireDetectResponse, or the result of cls(response)
:rtype: ~azure.ai.anomalydetector.models.EntireDetectResponse
Expand All @@ -44,7 +44,7 @@ async def entire_detect(
content_type = kwargs.pop("content_type", "application/json")

# Construct URL
url = self.entire_detect.metadata['url'] # type: ignore
url = self.detect_entire_series.metadata['url'] # type: ignore
path_format_arguments = {
'Endpoint': self._serialize.url("self._config.endpoint", self._config.endpoint, 'str', skip_quote=True),
}
Expand All @@ -59,7 +59,7 @@ async def entire_detect(
header_parameters['Accept'] = 'application/json'

body_content_kwargs = {} # type: Dict[str, Any]
body_content = self._serialize.body(body, 'Request')
body_content = self._serialize.body(body, 'DetectRequest')
body_content_kwargs['content'] = body_content
request = self._client.post(url, query_parameters, header_parameters, **body_content_kwargs)

Expand All @@ -68,7 +68,7 @@ async def entire_detect(

if response.status_code not in [200]:
map_error(status_code=response.status_code, response=response, error_map=error_map)
error = self._deserialize(models.APIError, response)
error = self._deserialize(models.AnomalyDetectorError, response)
raise HttpResponseError(response=response, model=error)

deserialized = self._deserialize('EntireDetectResponse', pipeline_response)
Expand All @@ -77,11 +77,11 @@ async def entire_detect(
return cls(pipeline_response, deserialized, {})

return deserialized
entire_detect.metadata = {'url': '/timeseries/entire/detect'} # type: ignore
detect_entire_series.metadata = {'url': '/timeseries/entire/detect'} # type: ignore

async def last_detect(
async def detect_last_point(
self,
body: "models.Request",
body: "models.DetectRequest",
**kwargs
) -> "models.LastDetectResponse":
"""Detect anomaly status of the latest point in time series.
Expand All @@ -92,7 +92,7 @@ async def last_detect(

:param body: Time series points and period if needed. Advanced model parameters can also be set
in the request.
:type body: ~azure.ai.anomalydetector.models.Request
:type body: ~azure.ai.anomalydetector.models.DetectRequest
:keyword callable cls: A custom type or function that will be passed the direct response
:return: LastDetectResponse, or the result of cls(response)
:rtype: ~azure.ai.anomalydetector.models.LastDetectResponse
Expand All @@ -104,7 +104,7 @@ async def last_detect(
content_type = kwargs.pop("content_type", "application/json")

# Construct URL
url = self.last_detect.metadata['url'] # type: ignore
url = self.detect_last_point.metadata['url'] # type: ignore
path_format_arguments = {
'Endpoint': self._serialize.url("self._config.endpoint", self._config.endpoint, 'str', skip_quote=True),
}
Expand All @@ -119,7 +119,7 @@ async def last_detect(
header_parameters['Accept'] = 'application/json'

body_content_kwargs = {} # type: Dict[str, Any]
body_content = self._serialize.body(body, 'Request')
body_content = self._serialize.body(body, 'DetectRequest')
body_content_kwargs['content'] = body_content
request = self._client.post(url, query_parameters, header_parameters, **body_content_kwargs)

Expand All @@ -128,7 +128,7 @@ async def last_detect(

if response.status_code not in [200]:
map_error(status_code=response.status_code, response=response, error_map=error_map)
error = self._deserialize(models.APIError, response)
error = self._deserialize(models.AnomalyDetectorError, response)
raise HttpResponseError(response=response, model=error)

deserialized = self._deserialize('LastDetectResponse', pipeline_response)
Expand All @@ -137,9 +137,9 @@ async def last_detect(
return cls(pipeline_response, deserialized, {})

return deserialized
last_detect.metadata = {'url': '/timeseries/last/detect'} # type: ignore
detect_last_point.metadata = {'url': '/timeseries/last/detect'} # type: ignore

async def change_point_detect(
async def detect_change_point(
self,
body: "models.ChangePointDetectRequest",
**kwargs
Expand All @@ -162,7 +162,7 @@ async def change_point_detect(
content_type = kwargs.pop("content_type", "application/json")

# Construct URL
url = self.change_point_detect.metadata['url'] # type: ignore
url = self.detect_change_point.metadata['url'] # type: ignore
path_format_arguments = {
'Endpoint': self._serialize.url("self._config.endpoint", self._config.endpoint, 'str', skip_quote=True),
}
Expand All @@ -186,7 +186,7 @@ async def change_point_detect(

if response.status_code not in [200]:
map_error(status_code=response.status_code, response=response, error_map=error_map)
error = self._deserialize(models.APIError, response)
error = self._deserialize(models.AnomalyDetectorError, response)
raise HttpResponseError(response=response, model=error)

deserialized = self._deserialize('ChangePointDetectResponse', pipeline_response)
Expand All @@ -195,4 +195,4 @@ async def change_point_detect(
return cls(pipeline_response, deserialized, {})

return deserialized
change_point_detect.metadata = {'url': '/timeseries/changePoint/detect'} # type: ignore
detect_change_point.metadata = {'url': '/timeseries/changepoint/detect'} # type: ignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,35 @@
# --------------------------------------------------------------------------

try:
from ._models_py3 import APIError
from ._models_py3 import AnomalyDetectorError
from ._models_py3 import ChangePointDetectRequest
from ._models_py3 import ChangePointDetectResponse
from ._models_py3 import DetectRequest
from ._models_py3 import EntireDetectResponse
from ._models_py3 import LastDetectResponse
from ._models_py3 import Point
from ._models_py3 import Request
from ._models_py3 import TimeSeriesPoint
except (SyntaxError, ImportError):
from ._models import APIError # type: ignore
from ._models import AnomalyDetectorError # type: ignore
from ._models import ChangePointDetectRequest # type: ignore
from ._models import ChangePointDetectResponse # type: ignore
from ._models import DetectRequest # type: ignore
from ._models import EntireDetectResponse # type: ignore
from ._models import LastDetectResponse # type: ignore
from ._models import Point # type: ignore
from ._models import Request # type: ignore
from ._models import TimeSeriesPoint # type: ignore

from ._anomaly_detector_client_enums import (
AnomalyDetectorErrorCodes,
Granularity,
TimeGranularity,
)

__all__ = [
'APIError',
'AnomalyDetectorError',
'ChangePointDetectRequest',
'ChangePointDetectResponse',
'DetectRequest',
'EntireDetectResponse',
'LastDetectResponse',
'Point',
'Request',
'TimeSeriesPoint',
'AnomalyDetectorErrorCodes',
'Granularity',
'TimeGranularity',
]
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class AnomalyDetectorErrorCodes(with_metaclass(_CaseInsensitiveEnumMeta, str, En
REQUIRED_GRANULARITY = "RequiredGranularity"
REQUIRED_SERIES = "RequiredSeries"

class Granularity(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)):
class TimeGranularity(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)):
"""Can only be one of yearly, monthly, weekly, daily, hourly, minutely or secondly. Granularity is
used for verify whether input series is valid.
"""
Expand All @@ -50,5 +50,5 @@ class Granularity(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)):
WEEKLY = "weekly"
DAILY = "daily"
HOURLY = "hourly"
MINUTELY = "minutely"
SECONDLY = "secondly"
PER_MINUTE = "minutely"
PER_SECOND = "secondly"
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import msrest.serialization


class APIError(msrest.serialization.Model):
class AnomalyDetectorError(msrest.serialization.Model):
"""Error information returned by the API.

:param code: The error code. Possible values include: "InvalidCustomInterval", "BadArgument",
Expand All @@ -30,7 +30,7 @@ def __init__(
self,
**kwargs
):
super(APIError, self).__init__(**kwargs)
super(AnomalyDetectorError, self).__init__(**kwargs)
self.code = kwargs.get('code', None)
self.message = kwargs.get('message', None)

Expand All @@ -42,11 +42,11 @@ class ChangePointDetectRequest(msrest.serialization.Model):

:param series: Required. Time series data points. Points should be sorted by timestamp in
ascending order to match the change point detection result.
:type series: list[~azure.ai.anomalydetector.models.Point]
:type series: list[~azure.ai.anomalydetector.models.TimeSeriesPoint]
:param granularity: Required. Can only be one of yearly, monthly, weekly, daily, hourly,
minutely or secondly. Granularity is used for verify whether input series is valid. Possible
values include: "yearly", "monthly", "weekly", "daily", "hourly", "minutely", "secondly".
:type granularity: str or ~azure.ai.anomalydetector.models.Granularity
:type granularity: str or ~azure.ai.anomalydetector.models.TimeGranularity
:param custom_interval: Custom Interval is used to set non-standard time interval, for example,
if the series is 5 minutes, request can be set as {"granularity":"minutely",
"customInterval":5}.
Expand All @@ -68,7 +68,7 @@ class ChangePointDetectRequest(msrest.serialization.Model):
}

_attribute_map = {
'series': {'key': 'series', 'type': '[Point]'},
'series': {'key': 'series', 'type': '[TimeSeriesPoint]'},
'granularity': {'key': 'granularity', 'type': 'str'},
'custom_interval': {'key': 'customInterval', 'type': 'int'},
'period': {'key': 'period', 'type': 'int'},
Expand Down Expand Up @@ -127,6 +127,62 @@ def __init__(
self.confidence_scores = kwargs['confidence_scores']


class DetectRequest(msrest.serialization.Model):
"""DetectRequest.

All required parameters must be populated in order to send to Azure.

:param series: Required. Time series data points. Points should be sorted by timestamp in
ascending order to match the anomaly detection result. If the data is not sorted correctly or
there is duplicated timestamp, the API will not work. In such case, an error message will be
returned.
:type series: list[~azure.ai.anomalydetector.models.TimeSeriesPoint]
:param granularity: Required. Can only be one of yearly, monthly, weekly, daily, hourly,
minutely or secondly. Granularity is used for verify whether input series is valid. Possible
values include: "yearly", "monthly", "weekly", "daily", "hourly", "minutely", "secondly".
:type granularity: str or ~azure.ai.anomalydetector.models.TimeGranularity
:param custom_interval: Custom Interval is used to set non-standard time interval, for example,
if the series is 5 minutes, request can be set as {"granularity":"minutely",
"customInterval":5}.
:type custom_interval: int
:param period: Optional argument, periodic value of a time series. If the value is null or does
not present, the API will determine the period automatically.
:type period: int
:param max_anomaly_ratio: Optional argument, advanced model parameter, max anomaly ratio in a
time series.
:type max_anomaly_ratio: float
:param sensitivity: Optional argument, advanced model parameter, between 0-99, the lower the
value is, the larger the margin value will be which means less anomalies will be accepted.
:type sensitivity: int
"""

_validation = {
'series': {'required': True},
'granularity': {'required': True},
}

_attribute_map = {
'series': {'key': 'series', 'type': '[TimeSeriesPoint]'},
'granularity': {'key': 'granularity', 'type': 'str'},
'custom_interval': {'key': 'customInterval', 'type': 'int'},
'period': {'key': 'period', 'type': 'int'},
'max_anomaly_ratio': {'key': 'maxAnomalyRatio', 'type': 'float'},
'sensitivity': {'key': 'sensitivity', 'type': 'int'},
}

def __init__(
self,
**kwargs
):
super(DetectRequest, self).__init__(**kwargs)
self.series = kwargs['series']
self.granularity = kwargs['granularity']
self.custom_interval = kwargs.get('custom_interval', None)
self.period = kwargs.get('period', None)
self.max_anomaly_ratio = kwargs.get('max_anomaly_ratio', None)
self.sensitivity = kwargs.get('sensitivity', None)


class EntireDetectResponse(msrest.serialization.Model):
"""EntireDetectResponse.

Expand Down Expand Up @@ -268,8 +324,8 @@ def __init__(
self.is_positive_anomaly = kwargs['is_positive_anomaly']


class Point(msrest.serialization.Model):
"""Point.
class TimeSeriesPoint(msrest.serialization.Model):
"""TimeSeriesPoint.

All required parameters must be populated in order to send to Azure.

Expand All @@ -293,62 +349,6 @@ def __init__(
self,
**kwargs
):
super(Point, self).__init__(**kwargs)
super(TimeSeriesPoint, self).__init__(**kwargs)
self.timestamp = kwargs['timestamp']
self.value = kwargs['value']


class Request(msrest.serialization.Model):
"""Request.

All required parameters must be populated in order to send to Azure.

:param series: Required. Time series data points. Points should be sorted by timestamp in
ascending order to match the anomaly detection result. If the data is not sorted correctly or
there is duplicated timestamp, the API will not work. In such case, an error message will be
returned.
:type series: list[~azure.ai.anomalydetector.models.Point]
:param granularity: Required. Can only be one of yearly, monthly, weekly, daily, hourly,
minutely or secondly. Granularity is used for verify whether input series is valid. Possible
values include: "yearly", "monthly", "weekly", "daily", "hourly", "minutely", "secondly".
:type granularity: str or ~azure.ai.anomalydetector.models.Granularity
:param custom_interval: Custom Interval is used to set non-standard time interval, for example,
if the series is 5 minutes, request can be set as {"granularity":"minutely",
"customInterval":5}.
:type custom_interval: int
:param period: Optional argument, periodic value of a time series. If the value is null or does
not present, the API will determine the period automatically.
:type period: int
:param max_anomaly_ratio: Optional argument, advanced model parameter, max anomaly ratio in a
time series.
:type max_anomaly_ratio: float
:param sensitivity: Optional argument, advanced model parameter, between 0-99, the lower the
value is, the larger the margin value will be which means less anomalies will be accepted.
:type sensitivity: int
"""

_validation = {
'series': {'required': True},
'granularity': {'required': True},
}

_attribute_map = {
'series': {'key': 'series', 'type': '[Point]'},
'granularity': {'key': 'granularity', 'type': 'str'},
'custom_interval': {'key': 'customInterval', 'type': 'int'},
'period': {'key': 'period', 'type': 'int'},
'max_anomaly_ratio': {'key': 'maxAnomalyRatio', 'type': 'float'},
'sensitivity': {'key': 'sensitivity', 'type': 'int'},
}

def __init__(
self,
**kwargs
):
super(Request, self).__init__(**kwargs)
self.series = kwargs['series']
self.granularity = kwargs['granularity']
self.custom_interval = kwargs.get('custom_interval', None)
self.period = kwargs.get('period', None)
self.max_anomaly_ratio = kwargs.get('max_anomaly_ratio', None)
self.sensitivity = kwargs.get('sensitivity', None)