From 0593d5b7b69c4df6d6dbc80387cc6ff5dc5f4e8f Mon Sep 17 00:00:00 2001 From: Andrey Almabekov <32712926+almabekov@users.noreply.github.com> Date: Fri, 29 Mar 2019 16:15:46 -0300 Subject: [PATCH] ARE-6139: sensitivity analysis enpoint wrapper (#49) * python wrapper for sensitivity analsys and tests drafts * some updates to the tests * candidates filtering and supporting test * made parameterized test, added list of attributes --- analyzere/resources.py | 11 +++++++++ tests/test_base_resources.py | 46 ++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/analyzere/resources.py b/analyzere/resources.py index 5d928ea..64ebcf1 100644 --- a/analyzere/resources.py +++ b/analyzere/resources.py @@ -212,6 +212,17 @@ def candidate_metrics(self): resp = request('get', path) return convert_to_analyzere_object(resp) + def sensitivity_analysis(self, candidates=[]): + # candidates can be only non negative integers + candidates = list(filter(lambda x: isinstance(x, int) and x >= 0, candidates)) + if len(candidates) == 0: + path = '{}/sensitivity_analysis'.format(self._get_path(self.id)) + else: + path = '{}/sensitivity_analysis?candidates={}'.format(self._get_path(self.id), + ','.join(str(c) for c in candidates)) + resp = request('get', path) + return convert_to_analyzere_object(resp) + class OptimizationDomain(EmbeddedResource): pass diff --git a/tests/test_base_resources.py b/tests/test_base_resources.py index a156d0f..5ffb9ad 100644 --- a/tests/test_base_resources.py +++ b/tests/test_base_resources.py @@ -911,3 +911,49 @@ def test_initial_portfolio_metrics(self, reqmock): text='{"num": 1.0}') f = OptimizationView(id='abc123').initial_metrics() assert f.num == 1.0 + + sensitivity_text = """ + {"sensitivities": [ + {"normalized_interquartile_range": 0.25, "min": 0.0, "normalized_standard_deviation": 0.29, + "initial_share": 0.18, "hist": { "0.05": 5, "0.1": 0, "0.15": 0, "0.2": 0, "0.25": 0, "0.3": 9, "0.35": 0, + "0.4": 0, "0.45": 0, "0.5": 3, "0.55": 0, "0.6": 5, "0.65": 0, "0.7": 3, "0.75": 0, "0.8": 3, "0.85": 2, + "0.9": 4, "0.95": 2, "1.0": 64}, "mean": 0.81, "max": 1.0, "ref_id": "layer2" + }, + { "normalized_interquartile_range": 0.71, "min": 0.0, "normalized_standard_deviation": 0.35, + "initial_share": 0.08, "hist": {"0.05": 36, "0.1": 0, "0.15": 8, "0.2": 1, "0.25": 1, "0.3": 3, + "0.35": 2, "0.4": 3, "0.45": 0, "0.5": 0, "0.55": 8, "0.6": 0, "0.65": 12, "0.7": 0, "0.75": 1, + "0.8": 10, "0.85": 0, "0.9": 7, "0.95": 0, "1.0": 8}, "mean": 0.37, "max": 1.0, "ref_id": "layer1" } + ] } """ + + required_attributes = ['hist', 'min', 'max', 'mean', 'normalized_standard_deviation', + 'normalized_interquartile_range', 'ref_id'] + + @pytest.mark.parametrize("get_string, candidates, expected_len", [ + ('https://api/optimization_views/abc_id/sensitivity_analysis', [], 2), + ('https://api/optimization_views/abc_id/sensitivity_analysis?candidates=0,2,5', [0, 2, 5], 2), + ('https://api/optimization_views/abc_id/sensitivity_analysis?candidates=0,2,5', [0, 2, 5, 'a', 1.1, -2], 2) + ]) + def test_sensitivity_analysis_with_candidates(self, reqmock, candidates, expected_len, get_string): + # list of candidates should be translated to the correct api request + reqmock.get('https://api/optimization_views/abc_id', + status_code=200, text='{"id":"abc_id"}') + ov = OptimizationView.retrieve('abc_id') + reqmock.get(get_string, + status_code=200, text=TestOptimizationResource.sensitivity_text) + r = ov.sensitivity_analysis(candidates=candidates) + assert hasattr(r, 'sensitivities') + assert len(r.sensitivities) == expected_len + for i in range(len(r.sensitivities)): + for attribute in TestOptimizationResource.required_attributes: + assert hasattr(r.sensitivities[i], attribute) + + def test_sensitivity_analysis_empty(self, reqmock): + # result can be an empty list + reqmock.get('https://api/optimization_views/abc_id', + status_code=200, text='{"id":"abc_id"}') + ov = OptimizationView.retrieve('abc_id') + reqmock.get('https://api/optimization_views/abc_id/sensitivity_analysis', + status_code=200, text='{"sensitivities": []}') + r = ov.sensitivity_analysis() + assert hasattr(r, 'sensitivities') + assert len(r.sensitivities) == 0