From 9b54ef1bbf1cc56c47794dab76e182da919c5c1b Mon Sep 17 00:00:00 2001 From: tamilarasan-ns1 Date: Fri, 21 Nov 2025 07:13:26 -0800 Subject: [PATCH 1/8] added decision endpoints into SDK --- examples/pulsar_decisions.py | 295 ++++++++++++++++++++++++++++ ns1/__init__.py | 10 + ns1/rest/pulsar_decisions.py | 195 ++++++++++++++++++ tests/unit/test_pulsar_decisions.py | 202 +++++++++++++++++++ 4 files changed, 702 insertions(+) create mode 100644 examples/pulsar_decisions.py create mode 100644 ns1/rest/pulsar_decisions.py create mode 100644 tests/unit/test_pulsar_decisions.py diff --git a/examples/pulsar_decisions.py b/examples/pulsar_decisions.py new file mode 100644 index 0000000..1ea2735 --- /dev/null +++ b/examples/pulsar_decisions.py @@ -0,0 +1,295 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014, 2025 NSONE, Inc. +# +# License under The MIT License (MIT). See LICENSE in project root. +# +""" +Example usage of Pulsar Decisions API endpoints. + +This example demonstrates how to query Pulsar decision analytics data +using the ns1-python library. +""" + +from ns1 import NS1 +import time + +# NS1 will use config in ~/.nsone by default +api = NS1() + +# to specify an apikey here instead, use: + +# from ns1 import Config +# config = Config() +# config.createFromAPIKey('<>') +# api = NS1(config=config) + +# Get current timestamp and 1 hour ago for time-based queries +end_time = int(time.time()) +start_time = end_time - 3600 # 1 hour ago + + +def main(): + """ + Demonstrate various Pulsar Decisions API endpoints. + """ + + print("=" * 60) + print("Pulsar Decisions API Examples") + print("=" * 60) + + ############################ + # GET DECISIONS DATA # + ############################ + print("\n1. Getting decisions data...") + try: + decisions = api.pulsardecisions().get_decisions( + start=start_time, + end=end_time, + period="1h" + ) + print(f" Total decisions: {decisions.get('total', 0)}") + print(f" Number of graphs: {len(decisions.get('graphs', []))}") + except Exception as e: + print(f" Error: {e}") + + ############################ + # GET REGIONAL GRAPH DATA # + ############################ + print("\n2. Getting regional graph data...") + try: + region_data = api.pulsardecisions().get_decisions_graph_region( + start=start_time, + end=end_time + ) + print(f" Regions found: {len(region_data.get('data', []))}") + for region in region_data.get('data', [])[:3]: # Show first 3 + print(f" - {region.get('region')}: {len(region.get('counts', []))} job counts") + except Exception as e: + print(f" Error: {e}") + + ############################## + # GET TIME-SERIES GRAPH DATA # + ############################## + print("\n3. Getting time-series graph data...") + try: + time_data = api.pulsardecisions().get_decisions_graph_time( + start=start_time, + end=end_time, + period="5m" + ) + print(f" Time points: {len(time_data.get('data', []))}") + if time_data.get('data'): + first_point = time_data['data'][0] + print(f" First timestamp: {first_point.get('timestamp')}") + print(f" Job counts at first point: {len(first_point.get('counts', []))}") + except Exception as e: + print(f" Error: {e}") + + ############################## + # GET AREA-BASED DECISIONS # + ############################## + print("\n4. Getting area-based decisions...") + try: + area_data = api.pulsardecisions().get_decisions_area( + start=start_time, + end=end_time, + area="US" + ) + print(f" Areas found: {len(area_data.get('areas', []))}") + for area in area_data.get('areas', [])[:3]: # Show first 3 + print(f" - {area.get('area_name')}: {area.get('count')} decisions") + except Exception as e: + print(f" Error: {e}") + + ############################## + # GET ASN-BASED DECISIONS # + ############################## + print("\n5. Getting ASN-based decisions...") + try: + asn_data = api.pulsardecisions().get_decisions_asn( + start=start_time, + end=end_time + ) + print(f" ASNs found: {len(asn_data.get('data', []))}") + for asn in asn_data.get('data', [])[:3]: # Show first 3 + print(f" - ASN {asn.get('asn')}: {asn.get('count')} decisions " + f"({asn.get('traffic_distribution', 0)*100:.1f}% of traffic)") + except Exception as e: + print(f" Error: {e}") + + ############################## + # GET RESULTS OVER TIME # + ############################## + print("\n6. Getting results over time...") + try: + results_time = api.pulsardecisions().get_decisions_results_time( + start=start_time, + end=end_time, + job="your-job-id" # Replace with actual job ID + ) + print(f" Time points: {len(results_time.get('data', []))}") + if results_time.get('data'): + first_point = results_time['data'][0] + print(f" Results at first point: {len(first_point.get('results', []))}") + except Exception as e: + print(f" Error: {e}") + + ############################## + # GET RESULTS BY AREA # + ############################## + print("\n7. Getting results by area...") + try: + results_area = api.pulsardecisions().get_decisions_results_area( + start=start_time, + end=end_time + ) + print(f" Areas found: {len(results_area.get('area', []))}") + for area in results_area.get('area', [])[:3]: # Show first 3 + print(f" - {area.get('area')}: {area.get('decision_count')} decisions, " + f"{len(area.get('results', []))} unique results") + except Exception as e: + print(f" Error: {e}") + + ############################## + # GET FILTER DATA OVER TIME # + ############################## + print("\n8. Getting filter data over time...") + try: + filters_time = api.pulsardecisions().get_filters_time( + start=start_time, + end=end_time + ) + print(f" Time points: {len(filters_time.get('filters', []))}") + if filters_time.get('filters'): + first_point = filters_time['filters'][0] + print(f" Filters at first point: {len(first_point.get('filters', {}))}") + except Exception as e: + print(f" Error: {e}") + + ################################### + # GET CUSTOMER-SPECIFIC DECISIONS # + ################################### + print("\n9. Getting customer-specific decisions...") + try: + customer_id = "your-customer-id" # Replace with actual customer ID + customer_data = api.pulsardecisions().get_decision_customer( + customer_id, + start=start_time, + end=end_time + ) + print(f" Data points: {len(customer_data.get('data', []))}") + if customer_data.get('data'): + total = sum(point.get('total', 0) for point in customer_data['data']) + print(f" Total decisions: {total}") + except Exception as e: + print(f" Error: {e}") + + ################################### + # GET RECORD-SPECIFIC DECISIONS # + ################################### + print("\n10. Getting record-specific decisions...") + try: + customer_id = "your-customer-id" # Replace with actual customer ID + domain = "example.com" + rec_type = "A" + record_data = api.pulsardecisions().get_decision_record( + customer_id, + domain, + rec_type, + start=start_time, + end=end_time + ) + print(f" Data points: {len(record_data.get('data', []))}") + if record_data.get('data'): + total = sum(point.get('total', 0) for point in record_data['data']) + print(f" Total decisions for {domain}/{rec_type}: {total}") + except Exception as e: + print(f" Error: {e}") + + #################################### + # GET TOTAL DECISIONS FOR CUSTOMER # + #################################### + print("\n11. Getting total decisions for customer...") + try: + customer_id = "your-customer-id" # Replace with actual customer ID + total_data = api.pulsardecisions().get_decision_total( + customer_id, + start=start_time, + end=end_time + ) + print(f" Total decisions: {total_data.get('total', 0)}") + except Exception as e: + print(f" Error: {e}") + + ################################ + # GET DECISIONS BY RECORD # + ################################ + print("\n12. Getting decisions by record...") + try: + records_data = api.pulsardecisions().get_decisions_records( + start=start_time, + end=end_time + ) + print(f" Total decisions: {records_data.get('total', 0)}") + print(f" Number of records: {len(records_data.get('records', {}))}") + for record_key, record_info in list(records_data.get('records', {}).items())[:3]: + print(f" - {record_key}: {record_info.get('count')} decisions " + f"({record_info.get('percentage_of_total', 0):.1f}%)") + except Exception as e: + print(f" Error: {e}") + + ############################## + # GET RESULTS BY RECORD # + ############################## + print("\n13. Getting results by record...") + try: + results_record = api.pulsardecisions().get_decisions_results_record( + start=start_time, + end=end_time + ) + print(f" Number of records: {len(results_record.get('record', {}))}") + for record_key, record_info in list(results_record.get('record', {}).items())[:3]: + print(f" - {record_key}: {record_info.get('decision_count')} decisions, " + f"{len(record_info.get('results', {}))} unique results") + except Exception as e: + print(f" Error: {e}") + + ################################## + # QUERYING WITH MULTIPLE FILTERS # + ################################## + print("\n14. Querying with multiple filters...") + try: + filtered_data = api.pulsardecisions().get_decisions( + start=start_time, + end=end_time, + period="1h", + area="US", + job="your-job-id", # Replace with actual job ID + agg="sum" + ) + print(f" Total decisions (filtered): {filtered_data.get('total', 0)}") + except Exception as e: + print(f" Error: {e}") + + ################################## + # QUERYING WITH MULTIPLE JOBS # + ################################## + print("\n15. Querying with multiple jobs...") + try: + multi_job_data = api.pulsardecisions().get_decisions( + start=start_time, + end=end_time, + jobs=["job1", "job2", "job3"] # Replace with actual job IDs + ) + print(f" Total decisions (multi-job): {multi_job_data.get('total', 0)}") + except Exception as e: + print(f" Error: {e}") + + print("\n" + "=" * 60) + print("Examples completed!") + print("=" * 60) + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/ns1/__init__.py b/ns1/__init__.py index 46a1726..537aace 100644 --- a/ns1/__init__.py +++ b/ns1/__init__.py @@ -251,6 +251,16 @@ def billing_usage(self): return ns1.rest.billing_usage.BillingUsage(self.config) + def pulsardecisions(self): + """ + Return a new raw REST interface to Pulsar Decisions resources + + :rtype: :py:class:`ns1.rest.pulsar_decisions.Decisions` + """ + import ns1.rest.pulsar_decisions + + return ns1.rest.pulsar_decisions.Decisions(self.config) + # HIGH LEVEL INTERFACE def loadZone(self, zone, callback=None, errback=None): """ diff --git a/ns1/rest/pulsar_decisions.py b/ns1/rest/pulsar_decisions.py new file mode 100644 index 0000000..7f0f57b --- /dev/null +++ b/ns1/rest/pulsar_decisions.py @@ -0,0 +1,195 @@ +# +# Copyright (c) 2014, 2025 NSONE, Inc. +# +# License under The MIT License (MIT). See LICENSE in project root. +# +from . import resource + +try: + from urllib.parse import urlencode +except ImportError: + from urllib import urlencode + + +class Decisions(resource.BaseResource): + ROOT = "pulsar/query" + PASSTHRU_FIELDS = [] + + def _build_query_params(self, **kwargs): + params = {} + + if 'start' in kwargs and kwargs['start']: + params['start'] = int(kwargs['start']) + if 'end' in kwargs and kwargs['end']: + params['end'] = int(kwargs['end']) + if 'period' in kwargs and kwargs['period']: + params['period'] = kwargs['period'] + if 'area' in kwargs and kwargs['area']: + params['area'] = kwargs['area'] + if 'asn' in kwargs and kwargs['asn']: + params['asn'] = kwargs['asn'] + if 'job' in kwargs and kwargs['job']: + params['job'] = kwargs['job'] + if 'jobs' in kwargs and kwargs['jobs']: + params['jobs'] = ','.join(kwargs['jobs']) + if 'record' in kwargs and kwargs['record']: + params['record'] = kwargs['record'] + if 'result' in kwargs and kwargs['result']: + params['result'] = kwargs['result'] + if 'agg' in kwargs and kwargs['agg']: + params['agg'] = kwargs['agg'] + if 'geo' in kwargs and kwargs['geo']: + params['geo'] = kwargs['geo'] + if 'zone_id' in kwargs and kwargs['zone_id']: + params['zone_id'] = kwargs['zone_id'] + if 'customer_id' in kwargs and kwargs['customer_id']: + params['customer_id'] = int(kwargs['customer_id']) + + return params + + def _make_query_url(self, path, **kwargs): + params = self._build_query_params(**kwargs) + if params: + return "%s?%s" % (path, urlencode(params)) + return path + + def get_decisions(self, callback=None, errback=None, **kwargs): + path = self._make_query_url("decisions", **kwargs) + return self._make_request( + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback + ) + + def get_decisions_graph_region(self, callback=None, errback=None, **kwargs): + path = self._make_query_url("decisions/graph/region", **kwargs) + return self._make_request( + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback + ) + + def get_decisions_graph_time(self, callback=None, errback=None, **kwargs): + path = self._make_query_url("decisions/graph/time", **kwargs) + return self._make_request( + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback + ) + + def get_decisions_area(self, callback=None, errback=None, **kwargs): + path = self._make_query_url("decisions/area", **kwargs) + return self._make_request( + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback + ) + + def get_decisions_asn(self, callback=None, errback=None, **kwargs): + path = self._make_query_url("decisions/asn", **kwargs) + return self._make_request( + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback + ) + + def get_decisions_results_time(self, callback=None, errback=None, **kwargs): + path = self._make_query_url("decisions/results/time", **kwargs) + return self._make_request( + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback + ) + + def get_decisions_results_area(self, callback=None, errback=None, **kwargs): + path = self._make_query_url("decisions/results/area", **kwargs) + return self._make_request( + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback + ) + + def get_filters_time(self, callback=None, errback=None, **kwargs): + path = self._make_query_url("decisions/filters/time", **kwargs) + return self._make_request( + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback + ) + + def get_decision_customer(self, customer_id, callback=None, errback=None, **kwargs): + path = self._make_query_url("decision/customer/%s" % customer_id, **kwargs) + return self._make_request( + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback + ) + + def get_decision_customer_undetermined(self, customer_id, callback=None, errback=None, **kwargs): + path = self._make_query_url("decision/customer/%s/undetermined" % customer_id, **kwargs) + return self._make_request( + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback + ) + + def get_decision_record(self, customer_id, domain, rec_type, callback=None, errback=None, **kwargs): + path = self._make_query_url( + "decision/customer/%s/record/%s/%s" % (customer_id, domain, rec_type), + **kwargs + ) + return self._make_request( + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback + ) + + def get_decision_record_undetermined(self, customer_id, domain, rec_type, callback=None, errback=None, **kwargs): + path = self._make_query_url( + "decision/customer/%s/record/%s/%s/undetermined" % (customer_id, domain, rec_type), + **kwargs + ) + return self._make_request( + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback + ) + + def get_decision_total(self, customer_id, callback=None, errback=None, **kwargs): + path = self._make_query_url("decision/customer/%s/total" % customer_id, **kwargs) + return self._make_request( + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback + ) + + def get_decisions_records(self, callback=None, errback=None, **kwargs): + path = self._make_query_url("decisions/records", **kwargs) + return self._make_request( + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback + ) + + def get_decisions_results_record(self, callback=None, errback=None, **kwargs): + path = self._make_query_url("decisions/results/record", **kwargs) + return self._make_request( + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback + ) diff --git a/tests/unit/test_pulsar_decisions.py b/tests/unit/test_pulsar_decisions.py new file mode 100644 index 0000000..3e2c2c3 --- /dev/null +++ b/tests/unit/test_pulsar_decisions.py @@ -0,0 +1,202 @@ +# +# Copyright (c) 2014, 2025 NSONE, Inc. +# +# License under The MIT License (MIT). See LICENSE in project root. +# + +import ns1.rest.pulsar_decisions +import pytest + +try: # Python 3.3 + + import unittest.mock as mock +except ImportError: + import mock + + +@pytest.fixture +def pulsar_decisions_config(config): + config.loadFromDict( + { + "endpoint": "api.nsone.net", + "default_key": "test1", + "keys": { + "test1": { + "key": "key-1", + "desc": "test key number 1", + } + }, + } + ) + + return config + + +@pytest.mark.parametrize( + "op, args, method, url, kwargs", + [ + ( + "get_decisions", + None, + "GET", + "pulsar/query/decisions", + {"callback": None, "errback": None}, + ), + ( + "get_decisions", + [{"start": 1234567890, "end": 1234567900}], + "GET", + "pulsar/query/decisions?start=1234567890&end=1234567900", + {"callback": None, "errback": None}, + ), + ( + "get_decisions_graph_region", + None, + "GET", + "pulsar/query/decisions/graph/region", + {"callback": None, "errback": None}, + ), + ( + "get_decisions_graph_time", + None, + "GET", + "pulsar/query/decisions/graph/time", + {"callback": None, "errback": None}, + ), + ( + "get_decisions_area", + None, + "GET", + "pulsar/query/decisions/area", + {"callback": None, "errback": None}, + ), + ( + "get_decisions_asn", + None, + "GET", + "pulsar/query/decisions/asn", + {"callback": None, "errback": None}, + ), + ( + "get_decisions_results_time", + None, + "GET", + "pulsar/query/decisions/results/time", + {"callback": None, "errback": None}, + ), + ( + "get_decisions_results_area", + None, + "GET", + "pulsar/query/decisions/results/area", + {"callback": None, "errback": None}, + ), + ( + "get_filters_time", + None, + "GET", + "pulsar/query/decisions/filters/time", + {"callback": None, "errback": None}, + ), + ( + "get_decision_customer", + ["12345"], + "GET", + "pulsar/query/decision/customer/12345", + {"callback": None, "errback": None}, + ), + ( + "get_decision_customer_undetermined", + ["12345"], + "GET", + "pulsar/query/decision/customer/12345/undetermined", + {"callback": None, "errback": None}, + ), + ( + "get_decision_record", + ["12345", "example.com", "A"], + "GET", + "pulsar/query/decision/customer/12345/record/example.com/A", + {"callback": None, "errback": None}, + ), + ( + "get_decision_record_undetermined", + ["12345", "example.com", "A"], + "GET", + "pulsar/query/decision/customer/12345/record/example.com/A/undetermined", + {"callback": None, "errback": None}, + ), + ( + "get_decision_total", + ["12345"], + "GET", + "pulsar/query/decision/customer/12345/total", + {"callback": None, "errback": None}, + ), + ( + "get_decisions_records", + None, + "GET", + "pulsar/query/decisions/records", + {"callback": None, "errback": None}, + ), + ( + "get_decisions_results_record", + None, + "GET", + "pulsar/query/decisions/results/record", + {"callback": None, "errback": None}, + ), + ], +) +def test_rest_pulsar_decisions( + pulsar_decisions_config, op, args, method, url, kwargs +): + """Test Pulsar Decisions REST API endpoints.""" + m = ns1.rest.pulsar_decisions.Decisions(pulsar_decisions_config) + m._make_request = mock.MagicMock() + operation = getattr(m, op) + if args is not None: + if isinstance(args, list) and len(args) == 1 and isinstance(args[0], dict): + # Handle kwargs case + operation(**args[0]) + else: + # Handle positional args case + operation(*args) + else: + operation() + m._make_request.assert_called_once_with(method, url, **kwargs) + + +def test_rest_pulsar_decisions_build_query_params(pulsar_decisions_config): + """Test _build_query_params helper method.""" + m = ns1.rest.pulsar_decisions.Decisions(pulsar_decisions_config) + + params = m._build_query_params( + start=1234567890, + end=1234567900, + period="1h", + area="US", + asn="15169", + job="test_job", + jobs=["job1", "job2"], + record="example.com", + result="192.0.2.1", + agg="sum", + geo="country", + zone_id="zone123", + customer_id=12345 + ) + + assert params["start"] == 1234567890 + assert params["end"] == 1234567900 + assert params["period"] == "1h" + assert params["area"] == "US" + assert params["asn"] == "15169" + assert params["job"] == "test_job" + assert params["jobs"] == "job1,job2" + assert params["record"] == "example.com" + assert params["result"] == "192.0.2.1" + assert params["agg"] == "sum" + assert params["geo"] == "country" + assert params["zone_id"] == "zone123" + assert params["customer_id"] == 12345 From 28d20e4131e1dcb6ae36fe5061b7ac8a9dd3fb53 Mon Sep 17 00:00:00 2001 From: tamilarasan-ns1 Date: Wed, 26 Nov 2025 07:11:43 -0800 Subject: [PATCH 2/8] fixed blankspace issue --- examples/pulsar_decisions.py | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/examples/pulsar_decisions.py b/examples/pulsar_decisions.py index 1ea2735..6119f05 100644 --- a/examples/pulsar_decisions.py +++ b/examples/pulsar_decisions.py @@ -6,11 +6,9 @@ # """ Example usage of Pulsar Decisions API endpoints. - This example demonstrates how to query Pulsar decision analytics data using the ns1-python library. """ - from ns1 import NS1 import time @@ -28,12 +26,10 @@ end_time = int(time.time()) start_time = end_time - 3600 # 1 hour ago - def main(): """ Demonstrate various Pulsar Decisions API endpoints. """ - print("=" * 60) print("Pulsar Decisions API Examples") print("=" * 60) @@ -52,7 +48,7 @@ def main(): print(f" Number of graphs: {len(decisions.get('graphs', []))}") except Exception as e: print(f" Error: {e}") - + ############################ # GET REGIONAL GRAPH DATA # ############################ @@ -67,7 +63,7 @@ def main(): print(f" - {region.get('region')}: {len(region.get('counts', []))} job counts") except Exception as e: print(f" Error: {e}") - + ############################## # GET TIME-SERIES GRAPH DATA # ############################## @@ -85,7 +81,7 @@ def main(): print(f" Job counts at first point: {len(first_point.get('counts', []))}") except Exception as e: print(f" Error: {e}") - + ############################## # GET AREA-BASED DECISIONS # ############################## @@ -101,7 +97,7 @@ def main(): print(f" - {area.get('area_name')}: {area.get('count')} decisions") except Exception as e: print(f" Error: {e}") - + ############################## # GET ASN-BASED DECISIONS # ############################## @@ -117,7 +113,7 @@ def main(): f"({asn.get('traffic_distribution', 0)*100:.1f}% of traffic)") except Exception as e: print(f" Error: {e}") - + ############################## # GET RESULTS OVER TIME # ############################## @@ -134,7 +130,7 @@ def main(): print(f" Results at first point: {len(first_point.get('results', []))}") except Exception as e: print(f" Error: {e}") - + ############################## # GET RESULTS BY AREA # ############################## @@ -150,7 +146,7 @@ def main(): f"{len(area.get('results', []))} unique results") except Exception as e: print(f" Error: {e}") - + ############################## # GET FILTER DATA OVER TIME # ############################## @@ -166,7 +162,7 @@ def main(): print(f" Filters at first point: {len(first_point.get('filters', {}))}") except Exception as e: print(f" Error: {e}") - + ################################### # GET CUSTOMER-SPECIFIC DECISIONS # ################################### @@ -184,7 +180,7 @@ def main(): print(f" Total decisions: {total}") except Exception as e: print(f" Error: {e}") - + ################################### # GET RECORD-SPECIFIC DECISIONS # ################################### @@ -206,7 +202,7 @@ def main(): print(f" Total decisions for {domain}/{rec_type}: {total}") except Exception as e: print(f" Error: {e}") - + #################################### # GET TOTAL DECISIONS FOR CUSTOMER # #################################### @@ -221,7 +217,7 @@ def main(): print(f" Total decisions: {total_data.get('total', 0)}") except Exception as e: print(f" Error: {e}") - + ################################ # GET DECISIONS BY RECORD # ################################ @@ -238,7 +234,7 @@ def main(): f"({record_info.get('percentage_of_total', 0):.1f}%)") except Exception as e: print(f" Error: {e}") - + ############################## # GET RESULTS BY RECORD # ############################## @@ -254,7 +250,7 @@ def main(): f"{len(record_info.get('results', {}))} unique results") except Exception as e: print(f" Error: {e}") - + ################################## # QUERYING WITH MULTIPLE FILTERS # ################################## @@ -271,7 +267,7 @@ def main(): print(f" Total decisions (filtered): {filtered_data.get('total', 0)}") except Exception as e: print(f" Error: {e}") - + ################################## # QUERYING WITH MULTIPLE JOBS # ################################## @@ -290,6 +286,5 @@ def main(): print("Examples completed!") print("=" * 60) - if __name__ == '__main__': main() \ No newline at end of file From 221e8730d0532ebe6e85f8f8f4454f64cdb59500 Mon Sep 17 00:00:00 2001 From: tamilarasan-ns1 Date: Wed, 26 Nov 2025 07:20:13 -0800 Subject: [PATCH 3/8] fixed git issue --- examples/pulsar_decisions.py | 14 +++++++------- ns1/__init__.py | 2 +- ns1/rest/pulsar_decisions.py | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/pulsar_decisions.py b/examples/pulsar_decisions.py index 6119f05..192ad9e 100644 --- a/examples/pulsar_decisions.py +++ b/examples/pulsar_decisions.py @@ -33,7 +33,7 @@ def main(): print("=" * 60) print("Pulsar Decisions API Examples") print("=" * 60) - + ############################ # GET DECISIONS DATA # ############################ @@ -114,7 +114,7 @@ def main(): except Exception as e: print(f" Error: {e}") - ############################## + ############################## # GET RESULTS OVER TIME # ############################## print("\n6. Getting results over time...") @@ -131,7 +131,7 @@ def main(): except Exception as e: print(f" Error: {e}") - ############################## + ############################## # GET RESULTS BY AREA # ############################## print("\n7. Getting results by area...") @@ -147,7 +147,7 @@ def main(): except Exception as e: print(f" Error: {e}") - ############################## + ############################## # GET FILTER DATA OVER TIME # ############################## print("\n8. Getting filter data over time...") @@ -163,7 +163,7 @@ def main(): except Exception as e: print(f" Error: {e}") - ################################### + ################################### # GET CUSTOMER-SPECIFIC DECISIONS # ################################### print("\n9. Getting customer-specific decisions...") @@ -181,7 +181,7 @@ def main(): except Exception as e: print(f" Error: {e}") - ################################### + ################################### # GET RECORD-SPECIFIC DECISIONS # ################################### print("\n10. Getting record-specific decisions...") @@ -203,7 +203,7 @@ def main(): except Exception as e: print(f" Error: {e}") - #################################### + #################################### # GET TOTAL DECISIONS FOR CUSTOMER # #################################### print("\n11. Getting total decisions for customer...") diff --git a/ns1/__init__.py b/ns1/__init__.py index 537aace..cadbc02 100644 --- a/ns1/__init__.py +++ b/ns1/__init__.py @@ -260,7 +260,7 @@ def pulsardecisions(self): import ns1.rest.pulsar_decisions return ns1.rest.pulsar_decisions.Decisions(self.config) - + # HIGH LEVEL INTERFACE def loadZone(self, zone, callback=None, errback=None): """ diff --git a/ns1/rest/pulsar_decisions.py b/ns1/rest/pulsar_decisions.py index 7f0f57b..1644290 100644 --- a/ns1/rest/pulsar_decisions.py +++ b/ns1/rest/pulsar_decisions.py @@ -17,7 +17,7 @@ class Decisions(resource.BaseResource): def _build_query_params(self, **kwargs): params = {} - + if 'start' in kwargs and kwargs['start']: params['start'] = int(kwargs['start']) if 'end' in kwargs and kwargs['end']: @@ -44,7 +44,7 @@ def _build_query_params(self, **kwargs): params['zone_id'] = kwargs['zone_id'] if 'customer_id' in kwargs and kwargs['customer_id']: params['customer_id'] = int(kwargs['customer_id']) - + return params def _make_query_url(self, path, **kwargs): From c33c4b214e533c1c3f43c788f698d22644450d1d Mon Sep 17 00:00:00 2001 From: tamilarasan-ns1 Date: Wed, 26 Nov 2025 07:24:59 -0800 Subject: [PATCH 4/8] fixed blankspace issue in code --- examples/pulsar_decisions.py | 6 ++++-- tests/unit/test_pulsar_decisions.py | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/examples/pulsar_decisions.py b/examples/pulsar_decisions.py index 192ad9e..f3d4800 100644 --- a/examples/pulsar_decisions.py +++ b/examples/pulsar_decisions.py @@ -26,6 +26,7 @@ end_time = int(time.time()) start_time = end_time - 3600 # 1 hour ago + def main(): """ Demonstrate various Pulsar Decisions API endpoints. @@ -281,10 +282,11 @@ def main(): print(f" Total decisions (multi-job): {multi_job_data.get('total', 0)}") except Exception as e: print(f" Error: {e}") - + print("\n" + "=" * 60) print("Examples completed!") print("=" * 60) + if __name__ == '__main__': - main() \ No newline at end of file + main() diff --git a/tests/unit/test_pulsar_decisions.py b/tests/unit/test_pulsar_decisions.py index 3e2c2c3..e412c91 100644 --- a/tests/unit/test_pulsar_decisions.py +++ b/tests/unit/test_pulsar_decisions.py @@ -170,7 +170,7 @@ def test_rest_pulsar_decisions( def test_rest_pulsar_decisions_build_query_params(pulsar_decisions_config): """Test _build_query_params helper method.""" m = ns1.rest.pulsar_decisions.Decisions(pulsar_decisions_config) - + params = m._build_query_params( start=1234567890, end=1234567900, @@ -186,7 +186,8 @@ def test_rest_pulsar_decisions_build_query_params(pulsar_decisions_config): zone_id="zone123", customer_id=12345 ) - + + assert params["start"] == 1234567890 assert params["end"] == 1234567900 assert params["period"] == "1h" From cd2a4218c4d99d569ab6e3e478228ecb4677db37 Mon Sep 17 00:00:00 2001 From: tamilarasan-ns1 Date: Wed, 26 Nov 2025 07:26:30 -0800 Subject: [PATCH 5/8] fixed whitespace --- tests/unit/test_pulsar_decisions.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/unit/test_pulsar_decisions.py b/tests/unit/test_pulsar_decisions.py index e412c91..ae237aa 100644 --- a/tests/unit/test_pulsar_decisions.py +++ b/tests/unit/test_pulsar_decisions.py @@ -187,7 +187,6 @@ def test_rest_pulsar_decisions_build_query_params(pulsar_decisions_config): customer_id=12345 ) - assert params["start"] == 1234567890 assert params["end"] == 1234567900 assert params["period"] == "1h" From 56c8959750fef891af394734ff31c4766dbd426b Mon Sep 17 00:00:00 2001 From: tamilarasan-ns1 Date: Wed, 26 Nov 2025 07:36:35 -0800 Subject: [PATCH 6/8] fixed lint issue --- examples/pulsar_decisions.py | 116 ++++++++++----------- ns1/rest/pulsar_decisions.py | 150 +++++++++++----------------- tests/unit/test_pulsar_decisions.py | 6 +- 3 files changed, 115 insertions(+), 157 deletions(-) diff --git a/examples/pulsar_decisions.py b/examples/pulsar_decisions.py index f3d4800..d6c3575 100644 --- a/examples/pulsar_decisions.py +++ b/examples/pulsar_decisions.py @@ -41,9 +41,7 @@ def main(): print("\n1. Getting decisions data...") try: decisions = api.pulsardecisions().get_decisions( - start=start_time, - end=end_time, - period="1h" + start=start_time, end=end_time, period="1h" ) print(f" Total decisions: {decisions.get('total', 0)}") print(f" Number of graphs: {len(decisions.get('graphs', []))}") @@ -56,12 +54,13 @@ def main(): print("\n2. Getting regional graph data...") try: region_data = api.pulsardecisions().get_decisions_graph_region( - start=start_time, - end=end_time + start=start_time, end=end_time ) print(f" Regions found: {len(region_data.get('data', []))}") - for region in region_data.get('data', [])[:3]: # Show first 3 - print(f" - {region.get('region')}: {len(region.get('counts', []))} job counts") + for region in region_data.get("data", [])[:3]: # Show first 3 + print( + f" - {region.get('region')}: {len(region.get('counts', []))} job counts" + ) except Exception as e: print(f" Error: {e}") @@ -71,13 +70,11 @@ def main(): print("\n3. Getting time-series graph data...") try: time_data = api.pulsardecisions().get_decisions_graph_time( - start=start_time, - end=end_time, - period="5m" + start=start_time, end=end_time, period="5m" ) print(f" Time points: {len(time_data.get('data', []))}") - if time_data.get('data'): - first_point = time_data['data'][0] + if time_data.get("data"): + first_point = time_data["data"][0] print(f" First timestamp: {first_point.get('timestamp')}") print(f" Job counts at first point: {len(first_point.get('counts', []))}") except Exception as e: @@ -89,12 +86,10 @@ def main(): print("\n4. Getting area-based decisions...") try: area_data = api.pulsardecisions().get_decisions_area( - start=start_time, - end=end_time, - area="US" + start=start_time, end=end_time, area="US" ) print(f" Areas found: {len(area_data.get('areas', []))}") - for area in area_data.get('areas', [])[:3]: # Show first 3 + for area in area_data.get("areas", [])[:3]: # Show first 3 print(f" - {area.get('area_name')}: {area.get('count')} decisions") except Exception as e: print(f" Error: {e}") @@ -105,13 +100,14 @@ def main(): print("\n5. Getting ASN-based decisions...") try: asn_data = api.pulsardecisions().get_decisions_asn( - start=start_time, - end=end_time + start=start_time, end=end_time ) print(f" ASNs found: {len(asn_data.get('data', []))}") - for asn in asn_data.get('data', [])[:3]: # Show first 3 - print(f" - ASN {asn.get('asn')}: {asn.get('count')} decisions " - f"({asn.get('traffic_distribution', 0)*100:.1f}% of traffic)") + for asn in asn_data.get("data", [])[:3]: # Show first 3 + print( + f" - ASN {asn.get('asn')}: {asn.get('count')} decisions " + f"({asn.get('traffic_distribution', 0)*100:.1f}% of traffic)" + ) except Exception as e: print(f" Error: {e}") @@ -123,11 +119,11 @@ def main(): results_time = api.pulsardecisions().get_decisions_results_time( start=start_time, end=end_time, - job="your-job-id" # Replace with actual job ID + job="your-job-id", # Replace with actual job ID ) print(f" Time points: {len(results_time.get('data', []))}") - if results_time.get('data'): - first_point = results_time['data'][0] + if results_time.get("data"): + first_point = results_time["data"][0] print(f" Results at first point: {len(first_point.get('results', []))}") except Exception as e: print(f" Error: {e}") @@ -138,13 +134,14 @@ def main(): print("\n7. Getting results by area...") try: results_area = api.pulsardecisions().get_decisions_results_area( - start=start_time, - end=end_time + start=start_time, end=end_time ) print(f" Areas found: {len(results_area.get('area', []))}") - for area in results_area.get('area', [])[:3]: # Show first 3 - print(f" - {area.get('area')}: {area.get('decision_count')} decisions, " - f"{len(area.get('results', []))} unique results") + for area in results_area.get("area", [])[:3]: # Show first 3 + print( + f" - {area.get('area')}: {area.get('decision_count')} decisions, " + f"{len(area.get('results', []))} unique results" + ) except Exception as e: print(f" Error: {e}") @@ -154,12 +151,11 @@ def main(): print("\n8. Getting filter data over time...") try: filters_time = api.pulsardecisions().get_filters_time( - start=start_time, - end=end_time + start=start_time, end=end_time ) print(f" Time points: {len(filters_time.get('filters', []))}") - if filters_time.get('filters'): - first_point = filters_time['filters'][0] + if filters_time.get("filters"): + first_point = filters_time["filters"][0] print(f" Filters at first point: {len(first_point.get('filters', {}))}") except Exception as e: print(f" Error: {e}") @@ -171,13 +167,11 @@ def main(): try: customer_id = "your-customer-id" # Replace with actual customer ID customer_data = api.pulsardecisions().get_decision_customer( - customer_id, - start=start_time, - end=end_time + customer_id, start=start_time, end=end_time ) print(f" Data points: {len(customer_data.get('data', []))}") - if customer_data.get('data'): - total = sum(point.get('total', 0) for point in customer_data['data']) + if customer_data.get("data"): + total = sum(point.get("total", 0) for point in customer_data["data"]) print(f" Total decisions: {total}") except Exception as e: print(f" Error: {e}") @@ -191,15 +185,11 @@ def main(): domain = "example.com" rec_type = "A" record_data = api.pulsardecisions().get_decision_record( - customer_id, - domain, - rec_type, - start=start_time, - end=end_time + customer_id, domain, rec_type, start=start_time, end=end_time ) print(f" Data points: {len(record_data.get('data', []))}") - if record_data.get('data'): - total = sum(point.get('total', 0) for point in record_data['data']) + if record_data.get("data"): + total = sum(point.get("total", 0) for point in record_data["data"]) print(f" Total decisions for {domain}/{rec_type}: {total}") except Exception as e: print(f" Error: {e}") @@ -211,9 +201,7 @@ def main(): try: customer_id = "your-customer-id" # Replace with actual customer ID total_data = api.pulsardecisions().get_decision_total( - customer_id, - start=start_time, - end=end_time + customer_id, start=start_time, end=end_time ) print(f" Total decisions: {total_data.get('total', 0)}") except Exception as e: @@ -225,14 +213,17 @@ def main(): print("\n12. Getting decisions by record...") try: records_data = api.pulsardecisions().get_decisions_records( - start=start_time, - end=end_time + start=start_time, end=end_time ) print(f" Total decisions: {records_data.get('total', 0)}") print(f" Number of records: {len(records_data.get('records', {}))}") - for record_key, record_info in list(records_data.get('records', {}).items())[:3]: - print(f" - {record_key}: {record_info.get('count')} decisions " - f"({record_info.get('percentage_of_total', 0):.1f}%)") + for record_key, record_info in list(records_data.get("records", {}).items())[ + :3 + ]: + print( + f" - {record_key}: {record_info.get('count')} decisions " + f"({record_info.get('percentage_of_total', 0):.1f}%)" + ) except Exception as e: print(f" Error: {e}") @@ -242,13 +233,16 @@ def main(): print("\n13. Getting results by record...") try: results_record = api.pulsardecisions().get_decisions_results_record( - start=start_time, - end=end_time + start=start_time, end=end_time ) print(f" Number of records: {len(results_record.get('record', {}))}") - for record_key, record_info in list(results_record.get('record', {}).items())[:3]: - print(f" - {record_key}: {record_info.get('decision_count')} decisions, " - f"{len(record_info.get('results', {}))} unique results") + for record_key, record_info in list(results_record.get("record", {}).items())[ + :3 + ]: + print( + f" - {record_key}: {record_info.get('decision_count')} decisions, " + f"{len(record_info.get('results', {}))} unique results" + ) except Exception as e: print(f" Error: {e}") @@ -263,7 +257,7 @@ def main(): period="1h", area="US", job="your-job-id", # Replace with actual job ID - agg="sum" + agg="sum", ) print(f" Total decisions (filtered): {filtered_data.get('total', 0)}") except Exception as e: @@ -277,7 +271,7 @@ def main(): multi_job_data = api.pulsardecisions().get_decisions( start=start_time, end=end_time, - jobs=["job1", "job2", "job3"] # Replace with actual job IDs + jobs=["job1", "job2", "job3"], # Replace with actual job IDs ) print(f" Total decisions (multi-job): {multi_job_data.get('total', 0)}") except Exception as e: @@ -288,5 +282,5 @@ def main(): print("=" * 60) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/ns1/rest/pulsar_decisions.py b/ns1/rest/pulsar_decisions.py index 1644290..6ab60c1 100644 --- a/ns1/rest/pulsar_decisions.py +++ b/ns1/rest/pulsar_decisions.py @@ -18,32 +18,32 @@ class Decisions(resource.BaseResource): def _build_query_params(self, **kwargs): params = {} - if 'start' in kwargs and kwargs['start']: - params['start'] = int(kwargs['start']) - if 'end' in kwargs and kwargs['end']: - params['end'] = int(kwargs['end']) - if 'period' in kwargs and kwargs['period']: - params['period'] = kwargs['period'] - if 'area' in kwargs and kwargs['area']: - params['area'] = kwargs['area'] - if 'asn' in kwargs and kwargs['asn']: - params['asn'] = kwargs['asn'] - if 'job' in kwargs and kwargs['job']: - params['job'] = kwargs['job'] - if 'jobs' in kwargs and kwargs['jobs']: - params['jobs'] = ','.join(kwargs['jobs']) - if 'record' in kwargs and kwargs['record']: - params['record'] = kwargs['record'] - if 'result' in kwargs and kwargs['result']: - params['result'] = kwargs['result'] - if 'agg' in kwargs and kwargs['agg']: - params['agg'] = kwargs['agg'] - if 'geo' in kwargs and kwargs['geo']: - params['geo'] = kwargs['geo'] - if 'zone_id' in kwargs and kwargs['zone_id']: - params['zone_id'] = kwargs['zone_id'] - if 'customer_id' in kwargs and kwargs['customer_id']: - params['customer_id'] = int(kwargs['customer_id']) + if "start" in kwargs and kwargs["start"]: + params["start"] = int(kwargs["start"]) + if "end" in kwargs and kwargs["end"]: + params["end"] = int(kwargs["end"]) + if "period" in kwargs and kwargs["period"]: + params["period"] = kwargs["period"] + if "area" in kwargs and kwargs["area"]: + params["area"] = kwargs["area"] + if "asn" in kwargs and kwargs["asn"]: + params["asn"] = kwargs["asn"] + if "job" in kwargs and kwargs["job"]: + params["job"] = kwargs["job"] + if "jobs" in kwargs and kwargs["jobs"]: + params["jobs"] = ",".join(kwargs["jobs"]) + if "record" in kwargs and kwargs["record"]: + params["record"] = kwargs["record"] + if "result" in kwargs and kwargs["result"]: + params["result"] = kwargs["result"] + if "agg" in kwargs and kwargs["agg"]: + params["agg"] = kwargs["agg"] + if "geo" in kwargs and kwargs["geo"]: + params["geo"] = kwargs["geo"] + if "zone_id" in kwargs and kwargs["zone_id"]: + params["zone_id"] = kwargs["zone_id"] + if "customer_id" in kwargs and kwargs["customer_id"]: + params["customer_id"] = int(kwargs["customer_id"]) return params @@ -56,140 +56,106 @@ def _make_query_url(self, path, **kwargs): def get_decisions(self, callback=None, errback=None, **kwargs): path = self._make_query_url("decisions", **kwargs) return self._make_request( - "GET", - "%s/%s" % (self.ROOT, path), - callback=callback, - errback=errback + "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback ) def get_decisions_graph_region(self, callback=None, errback=None, **kwargs): path = self._make_query_url("decisions/graph/region", **kwargs) return self._make_request( - "GET", - "%s/%s" % (self.ROOT, path), - callback=callback, - errback=errback + "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback ) def get_decisions_graph_time(self, callback=None, errback=None, **kwargs): path = self._make_query_url("decisions/graph/time", **kwargs) return self._make_request( - "GET", - "%s/%s" % (self.ROOT, path), - callback=callback, - errback=errback + "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback ) def get_decisions_area(self, callback=None, errback=None, **kwargs): path = self._make_query_url("decisions/area", **kwargs) return self._make_request( - "GET", - "%s/%s" % (self.ROOT, path), - callback=callback, - errback=errback + "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback ) def get_decisions_asn(self, callback=None, errback=None, **kwargs): path = self._make_query_url("decisions/asn", **kwargs) return self._make_request( - "GET", - "%s/%s" % (self.ROOT, path), - callback=callback, - errback=errback + "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback ) def get_decisions_results_time(self, callback=None, errback=None, **kwargs): path = self._make_query_url("decisions/results/time", **kwargs) return self._make_request( - "GET", - "%s/%s" % (self.ROOT, path), - callback=callback, - errback=errback + "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback ) def get_decisions_results_area(self, callback=None, errback=None, **kwargs): path = self._make_query_url("decisions/results/area", **kwargs) return self._make_request( - "GET", - "%s/%s" % (self.ROOT, path), - callback=callback, - errback=errback + "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback ) def get_filters_time(self, callback=None, errback=None, **kwargs): path = self._make_query_url("decisions/filters/time", **kwargs) return self._make_request( - "GET", - "%s/%s" % (self.ROOT, path), - callback=callback, - errback=errback + "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback ) def get_decision_customer(self, customer_id, callback=None, errback=None, **kwargs): path = self._make_query_url("decision/customer/%s" % customer_id, **kwargs) return self._make_request( - "GET", - "%s/%s" % (self.ROOT, path), - callback=callback, - errback=errback + "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback ) - def get_decision_customer_undetermined(self, customer_id, callback=None, errback=None, **kwargs): - path = self._make_query_url("decision/customer/%s/undetermined" % customer_id, **kwargs) + def get_decision_customer_undetermined( + self, customer_id, callback=None, errback=None, **kwargs + ): + path = self._make_query_url( + "decision/customer/%s/undetermined" % customer_id, **kwargs + ) return self._make_request( - "GET", - "%s/%s" % (self.ROOT, path), - callback=callback, - errback=errback + "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback ) - def get_decision_record(self, customer_id, domain, rec_type, callback=None, errback=None, **kwargs): + def get_decision_record( + self, customer_id, domain, rec_type, callback=None, errback=None, **kwargs + ): path = self._make_query_url( "decision/customer/%s/record/%s/%s" % (customer_id, domain, rec_type), **kwargs ) return self._make_request( - "GET", - "%s/%s" % (self.ROOT, path), - callback=callback, - errback=errback + "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback ) - def get_decision_record_undetermined(self, customer_id, domain, rec_type, callback=None, errback=None, **kwargs): + def get_decision_record_undetermined( + self, customer_id, domain, rec_type, callback=None, errback=None, **kwargs + ): path = self._make_query_url( - "decision/customer/%s/record/%s/%s/undetermined" % (customer_id, domain, rec_type), + "decision/customer/%s/record/%s/%s/undetermined" + % (customer_id, domain, rec_type), **kwargs ) return self._make_request( - "GET", - "%s/%s" % (self.ROOT, path), - callback=callback, - errback=errback + "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback ) def get_decision_total(self, customer_id, callback=None, errback=None, **kwargs): - path = self._make_query_url("decision/customer/%s/total" % customer_id, **kwargs) + path = self._make_query_url( + "decision/customer/%s/total" % customer_id, **kwargs + ) return self._make_request( - "GET", - "%s/%s" % (self.ROOT, path), - callback=callback, - errback=errback + "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback ) def get_decisions_records(self, callback=None, errback=None, **kwargs): path = self._make_query_url("decisions/records", **kwargs) return self._make_request( - "GET", - "%s/%s" % (self.ROOT, path), - callback=callback, - errback=errback + "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback ) def get_decisions_results_record(self, callback=None, errback=None, **kwargs): path = self._make_query_url("decisions/results/record", **kwargs) return self._make_request( - "GET", - "%s/%s" % (self.ROOT, path), - callback=callback, - errback=errback + "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback ) diff --git a/tests/unit/test_pulsar_decisions.py b/tests/unit/test_pulsar_decisions.py index ae237aa..363d012 100644 --- a/tests/unit/test_pulsar_decisions.py +++ b/tests/unit/test_pulsar_decisions.py @@ -148,9 +148,7 @@ def pulsar_decisions_config(config): ), ], ) -def test_rest_pulsar_decisions( - pulsar_decisions_config, op, args, method, url, kwargs -): +def test_rest_pulsar_decisions(pulsar_decisions_config, op, args, method, url, kwargs): """Test Pulsar Decisions REST API endpoints.""" m = ns1.rest.pulsar_decisions.Decisions(pulsar_decisions_config) m._make_request = mock.MagicMock() @@ -184,7 +182,7 @@ def test_rest_pulsar_decisions_build_query_params(pulsar_decisions_config): agg="sum", geo="country", zone_id="zone123", - customer_id=12345 + customer_id=12345, ) assert params["start"] == 1234567890 From 9b1fe3a0e6516cc764b3c6b31ee272e4ff6d2079 Mon Sep 17 00:00:00 2001 From: tamilarasan-ns1 Date: Wed, 26 Nov 2025 07:39:52 -0800 Subject: [PATCH 7/8] clean up code --- examples/pulsar_decisions.py | 40 ++++++--- ns1/rest/pulsar_decisions.py | 122 ++++++++++++++++++++++------ tests/unit/test_pulsar_decisions.py | 10 ++- 3 files changed, 132 insertions(+), 40 deletions(-) diff --git a/examples/pulsar_decisions.py b/examples/pulsar_decisions.py index d6c3575..4d2ca3a 100644 --- a/examples/pulsar_decisions.py +++ b/examples/pulsar_decisions.py @@ -76,7 +76,9 @@ def main(): if time_data.get("data"): first_point = time_data["data"][0] print(f" First timestamp: {first_point.get('timestamp')}") - print(f" Job counts at first point: {len(first_point.get('counts', []))}") + print( + f" Job counts at first point: {len(first_point.get('counts', []))}" + ) except Exception as e: print(f" Error: {e}") @@ -90,7 +92,9 @@ def main(): ) print(f" Areas found: {len(area_data.get('areas', []))}") for area in area_data.get("areas", [])[:3]: # Show first 3 - print(f" - {area.get('area_name')}: {area.get('count')} decisions") + print( + f" - {area.get('area_name')}: {area.get('count')} decisions" + ) except Exception as e: print(f" Error: {e}") @@ -124,7 +128,9 @@ def main(): print(f" Time points: {len(results_time.get('data', []))}") if results_time.get("data"): first_point = results_time["data"][0] - print(f" Results at first point: {len(first_point.get('results', []))}") + print( + f" Results at first point: {len(first_point.get('results', []))}" + ) except Exception as e: print(f" Error: {e}") @@ -156,7 +162,9 @@ def main(): print(f" Time points: {len(filters_time.get('filters', []))}") if filters_time.get("filters"): first_point = filters_time["filters"][0] - print(f" Filters at first point: {len(first_point.get('filters', {}))}") + print( + f" Filters at first point: {len(first_point.get('filters', {}))}" + ) except Exception as e: print(f" Error: {e}") @@ -171,7 +179,9 @@ def main(): ) print(f" Data points: {len(customer_data.get('data', []))}") if customer_data.get("data"): - total = sum(point.get("total", 0) for point in customer_data["data"]) + total = sum( + point.get("total", 0) for point in customer_data["data"] + ) print(f" Total decisions: {total}") except Exception as e: print(f" Error: {e}") @@ -217,9 +227,9 @@ def main(): ) print(f" Total decisions: {records_data.get('total', 0)}") print(f" Number of records: {len(records_data.get('records', {}))}") - for record_key, record_info in list(records_data.get("records", {}).items())[ - :3 - ]: + for record_key, record_info in list( + records_data.get("records", {}).items() + )[:3]: print( f" - {record_key}: {record_info.get('count')} decisions " f"({record_info.get('percentage_of_total', 0):.1f}%)" @@ -236,9 +246,9 @@ def main(): start=start_time, end=end_time ) print(f" Number of records: {len(results_record.get('record', {}))}") - for record_key, record_info in list(results_record.get("record", {}).items())[ - :3 - ]: + for record_key, record_info in list( + results_record.get("record", {}).items() + )[:3]: print( f" - {record_key}: {record_info.get('decision_count')} decisions, " f"{len(record_info.get('results', {}))} unique results" @@ -259,7 +269,9 @@ def main(): job="your-job-id", # Replace with actual job ID agg="sum", ) - print(f" Total decisions (filtered): {filtered_data.get('total', 0)}") + print( + f" Total decisions (filtered): {filtered_data.get('total', 0)}" + ) except Exception as e: print(f" Error: {e}") @@ -273,7 +285,9 @@ def main(): end=end_time, jobs=["job1", "job2", "job3"], # Replace with actual job IDs ) - print(f" Total decisions (multi-job): {multi_job_data.get('total', 0)}") + print( + f" Total decisions (multi-job): {multi_job_data.get('total', 0)}" + ) except Exception as e: print(f" Error: {e}") diff --git a/ns1/rest/pulsar_decisions.py b/ns1/rest/pulsar_decisions.py index 6ab60c1..def62b9 100644 --- a/ns1/rest/pulsar_decisions.py +++ b/ns1/rest/pulsar_decisions.py @@ -56,55 +56,92 @@ def _make_query_url(self, path, **kwargs): def get_decisions(self, callback=None, errback=None, **kwargs): path = self._make_query_url("decisions", **kwargs) return self._make_request( - "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback, ) - def get_decisions_graph_region(self, callback=None, errback=None, **kwargs): + def get_decisions_graph_region( + self, callback=None, errback=None, **kwargs + ): path = self._make_query_url("decisions/graph/region", **kwargs) return self._make_request( - "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback, ) def get_decisions_graph_time(self, callback=None, errback=None, **kwargs): path = self._make_query_url("decisions/graph/time", **kwargs) return self._make_request( - "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback, ) def get_decisions_area(self, callback=None, errback=None, **kwargs): path = self._make_query_url("decisions/area", **kwargs) return self._make_request( - "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback, ) def get_decisions_asn(self, callback=None, errback=None, **kwargs): path = self._make_query_url("decisions/asn", **kwargs) return self._make_request( - "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback, ) - def get_decisions_results_time(self, callback=None, errback=None, **kwargs): + def get_decisions_results_time( + self, callback=None, errback=None, **kwargs + ): path = self._make_query_url("decisions/results/time", **kwargs) return self._make_request( - "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback, ) - def get_decisions_results_area(self, callback=None, errback=None, **kwargs): + def get_decisions_results_area( + self, callback=None, errback=None, **kwargs + ): path = self._make_query_url("decisions/results/area", **kwargs) return self._make_request( - "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback, ) def get_filters_time(self, callback=None, errback=None, **kwargs): path = self._make_query_url("decisions/filters/time", **kwargs) return self._make_request( - "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback, ) - def get_decision_customer(self, customer_id, callback=None, errback=None, **kwargs): - path = self._make_query_url("decision/customer/%s" % customer_id, **kwargs) + def get_decision_customer( + self, customer_id, callback=None, errback=None, **kwargs + ): + path = self._make_query_url( + "decision/customer/%s" % customer_id, **kwargs + ) return self._make_request( - "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback, ) def get_decision_customer_undetermined( @@ -114,22 +151,41 @@ def get_decision_customer_undetermined( "decision/customer/%s/undetermined" % customer_id, **kwargs ) return self._make_request( - "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback, ) def get_decision_record( - self, customer_id, domain, rec_type, callback=None, errback=None, **kwargs + self, + customer_id, + domain, + rec_type, + callback=None, + errback=None, + **kwargs ): path = self._make_query_url( - "decision/customer/%s/record/%s/%s" % (customer_id, domain, rec_type), + "decision/customer/%s/record/%s/%s" + % (customer_id, domain, rec_type), **kwargs ) return self._make_request( - "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback, ) def get_decision_record_undetermined( - self, customer_id, domain, rec_type, callback=None, errback=None, **kwargs + self, + customer_id, + domain, + rec_type, + callback=None, + errback=None, + **kwargs ): path = self._make_query_url( "decision/customer/%s/record/%s/%s/undetermined" @@ -137,25 +193,41 @@ def get_decision_record_undetermined( **kwargs ) return self._make_request( - "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback, ) - def get_decision_total(self, customer_id, callback=None, errback=None, **kwargs): + def get_decision_total( + self, customer_id, callback=None, errback=None, **kwargs + ): path = self._make_query_url( "decision/customer/%s/total" % customer_id, **kwargs ) return self._make_request( - "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback, ) def get_decisions_records(self, callback=None, errback=None, **kwargs): path = self._make_query_url("decisions/records", **kwargs) return self._make_request( - "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback, ) - def get_decisions_results_record(self, callback=None, errback=None, **kwargs): + def get_decisions_results_record( + self, callback=None, errback=None, **kwargs + ): path = self._make_query_url("decisions/results/record", **kwargs) return self._make_request( - "GET", "%s/%s" % (self.ROOT, path), callback=callback, errback=errback + "GET", + "%s/%s" % (self.ROOT, path), + callback=callback, + errback=errback, ) diff --git a/tests/unit/test_pulsar_decisions.py b/tests/unit/test_pulsar_decisions.py index 363d012..7381c99 100644 --- a/tests/unit/test_pulsar_decisions.py +++ b/tests/unit/test_pulsar_decisions.py @@ -148,13 +148,19 @@ def pulsar_decisions_config(config): ), ], ) -def test_rest_pulsar_decisions(pulsar_decisions_config, op, args, method, url, kwargs): +def test_rest_pulsar_decisions( + pulsar_decisions_config, op, args, method, url, kwargs +): """Test Pulsar Decisions REST API endpoints.""" m = ns1.rest.pulsar_decisions.Decisions(pulsar_decisions_config) m._make_request = mock.MagicMock() operation = getattr(m, op) if args is not None: - if isinstance(args, list) and len(args) == 1 and isinstance(args[0], dict): + if ( + isinstance(args, list) + and len(args) == 1 + and isinstance(args[0], dict) + ): # Handle kwargs case operation(**args[0]) else: From 01181e2f18882a375277a3ee6ce375f77f92db25 Mon Sep 17 00:00:00 2001 From: tamilarasan-ns1 Date: Tue, 2 Dec 2025 05:33:41 -0800 Subject: [PATCH 8/8] updated changelog --- CHANGELOG.md | 5 +++++ ns1/__init__.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0008df..2cc2e46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.26.0 (August 28th, 2025) + +ENHANCEMENTS: +* Adds support for pulsar decision endpoints + ## 0.25.0 (August 28th, 2025) ENHANCEMENTS: diff --git a/ns1/__init__.py b/ns1/__init__.py index cadbc02..da2f817 100644 --- a/ns1/__init__.py +++ b/ns1/__init__.py @@ -5,7 +5,7 @@ # from .config import Config -version = "0.25.0" +version = "0.26.0" class NS1: