From e12ae4302c810045b2be4f04132d1f971370c1ee Mon Sep 17 00:00:00 2001 From: rupa deadwyler Date: Mon, 3 Aug 2020 16:21:23 -0400 Subject: [PATCH] add a listZones method to "high-level" interface returns a bunch of "unloaded" Zone objects --- examples/zones.py | 18 ++++++++++++++++++ ns1/__init__.py | 14 ++++++++++++++ tests/unit/test_init.py | 27 +++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) diff --git a/examples/zones.py b/examples/zones.py index 181992d..12ef985 100644 --- a/examples/zones.py +++ b/examples/zones.py @@ -21,10 +21,28 @@ config = api.config config["follow_pagination"] = True +###################### +# LISTING ZONES # +###################### + +# The zone list endpoint does not have full information about each zone, +# so the high-level `listZone` method returns a list of "unloaded" Zone +# objects, and you need to call the `.load` method on any that you intend +# use further. +# It's often easier to use the rest interface directly for list() calls, +# and/or skip right to loadZone, but this could be a reasonable method to use +# for actions that require operating on most of all of your zones. +zone_list = api.listZones() + ###################### # LOAD / CREATE ZONE # ###################### +# get a zone from the list and load it. this is not a practical way to fetch +# a single zone +listed_zone = [x for x in zone_list if x["zone"] == "test.com"][0] +listed_zone.load() + # to load an existing zone, get a Zone object back test_zone = api.loadZone("test.com") diff --git a/ns1/__init__.py b/ns1/__init__.py index 7945cfd..d5895ae 100644 --- a/ns1/__init__.py +++ b/ns1/__init__.py @@ -234,6 +234,20 @@ def apikey(self): return ns1.rest.apikey.APIKey(self.config) # HIGH LEVEL INTERFACE + def listZones(self, callback=None, errback=None): + """ + Returns a list of Zone objects for all of your zones. Note that + to avoid needless API traffic, these are NOT "loaded", and you + will need to call the `.load` method on any that you intend to use + further. + + :rtype: list of :py:class:`ns1.zones.Zone` + """ + import ns1.zones + + zones = ns1.rest.zones.Zones(self.config) + return [ns1.zones.Zone(self.config, z["zone"]) for z in zones.list()] + def loadZone(self, zone, callback=None, errback=None): """ Load an existing zone into a high level Zone object. diff --git a/tests/unit/test_init.py b/tests/unit/test_init.py index eaa4e39..f4cdc93 100644 --- a/tests/unit/test_init.py +++ b/tests/unit/test_init.py @@ -1,3 +1,4 @@ +import mock import pytest from ns1 import NS1 @@ -18,6 +19,7 @@ from ns1.rest.team import Team from ns1.rest.user import User from ns1.rest.zones import Zones +from ns1.zones import Zone @pytest.fixture @@ -67,3 +69,28 @@ def test_rest_interface(ns1_config, method, want): client = NS1(config=ns1_config) got = getattr(client, method)() assert isinstance(got, want) + + +@mock.patch.object(Zone, "load") +@mock.patch.object(Zones, "list") +def test_listZones(zones_list, zone_load, ns1_config): + zones_list.return_value = [{"zone": "a.com"}, {"zone": "b.com"}] + client = NS1(config=ns1_config) + + result = client.listZones() + zones_list.assert_called_once_with() + zone_load.assert_not_called() + assert sorted([x.zone for x in result]) == ["a.com", "b.com"] + + result[0].load() + zone_load.assert_called_once_with() + + +@mock.patch.object(Zone, "load") +def test_loadZone(zone_load, ns1_config): + zone_load.return_value = "LOADED_ZONE_OBJECT" + client = NS1(config=ns1_config) + + result = client.loadZone("a.com") + zone_load.assert_called_once_with(callback=None, errback=None) + assert result == "LOADED_ZONE_OBJECT"