From 4f50759741f4b096a83eeca3cea890fa6d4e52f3 Mon Sep 17 00:00:00 2001 From: Kenneth Bingham Date: Thu, 13 Nov 2025 13:25:15 -0500 Subject: [PATCH 1/3] adapt to breaking change in requests 2.30 --- netfoundry/ctl.py | 1 + netfoundry/network.py | 2 +- netfoundry/network_group.py | 2 +- netfoundry/organization.py | 2 +- netfoundry/utility.py | 10 +++++++--- setup.cfg | 2 +- 6 files changed, 12 insertions(+), 7 deletions(-) diff --git a/netfoundry/ctl.py b/netfoundry/ctl.py index ddca9c8..0430149 100644 --- a/netfoundry/ctl.py +++ b/netfoundry/ctl.py @@ -934,6 +934,7 @@ def demo(cli): name=network_name, size=cli.config.demo.size, version=cli.config.demo.product_version, + provider=cli.config.demo.provider, ) network, network_group = use_network( cli, diff --git a/netfoundry/network.py b/netfoundry/network.py index a0f10ff..0018e4e 100644 --- a/netfoundry/network.py +++ b/netfoundry/network.py @@ -5,7 +5,7 @@ import time from packaging.version import parse -from requests.exceptions import JSONDecodeError +from json import JSONDecodeError from netfoundry.exceptions import NetworkBoundaryViolation, UnknownResourceType diff --git a/netfoundry/network_group.py b/netfoundry/network_group.py index a373322..45d332f 100644 --- a/netfoundry/network_group.py +++ b/netfoundry/network_group.py @@ -173,7 +173,7 @@ def create_network(self, name: str, network_group_id: str = None, location: str elif param == 'productVersion': if version: self.logger.debug("clobbering param 'version' with kwarg 'productVersion'") - version == value + version = value else: self.logger.warn(f"ignoring unexpected keyword argument '{param}'") diff --git a/netfoundry/organization.py b/netfoundry/organization.py index ec93d88..492342f 100644 --- a/netfoundry/organization.py +++ b/netfoundry/organization.py @@ -386,7 +386,7 @@ def __init__(self, if self.organizations_by_label.get(organization_label): self.describe = self.get_organization(id=self.organizations_by_label[organization_label]) else: - raise RuntimeError(f"failed to find org label {organization_label} in the list of orgs {', '.join(self.organizations_by_label.keys())}") + raise RuntimeError(f"failed to find org label {organization_label} in the list of {len(self.organizations_by_label)} available organizations") else: self.describe = self.get_organization(id=self.caller['organizationId']) diff --git a/netfoundry/utility.py b/netfoundry/utility.py index 78ab4a8..dbcfa87 100644 --- a/netfoundry/utility.py +++ b/netfoundry/utility.py @@ -485,6 +485,12 @@ def find_generic_resources(setup: object, url: str, headers: dict = dict(), embe ) response.raise_for_status() resource_page = response.json() + + # Handle non-paginated endpoints that return direct lists + if isinstance(resource_page, list): + yield resource_page + return + if isinstance(resource_page, dict) and resource_page.get('page'): try: total_pages = resource_page['page']['totalPages'] @@ -515,8 +521,6 @@ def find_generic_resources(setup: object, url: str, headers: dict = dict(), embe # then yield subsequent pages, if applicable if get_all_pages and total_pages > 1: # get_all_pages is False if param 'page' or 'size' to stop recursion and get a single page next_range_lower, next_range_upper = params['page'] + 1, total_pages - if resource_type.name == 'network-groups': - next_range_upper += 1 # network-groups pages are 1-based and so +1 upper limit for next_page in range(next_range_lower, next_range_upper): params['page'] = next_page try: @@ -902,7 +906,7 @@ def decorated(ref): RETRY_STRATEGY = Retry( total=5, status_forcelist=[403, 404, 413, 429, 503], # The API responds 403 and 404 for not-yet-existing executions for some async operations - method_whitelist=["HEAD", "GET", "PUT", "DELETE", "OPTIONS", "TRACE"], + allowed_methods=["HEAD", "GET", "PUT", "DELETE", "OPTIONS", "TRACE"], backoff_factor=1 ) DEFAULT_TIMEOUT = 31 # seconds, Gateway Service waits 30s before responding with an error code e.g. 503 and diff --git a/setup.cfg b/setup.cfg index 151defa..14059a7 100644 --- a/setup.cfg +++ b/setup.cfg @@ -30,7 +30,7 @@ install_requires = pygments >= 2.11 pyjwt >= 2.3 pyyaml >= 5.4 - requests >= 2.27, < 2.30 + requests >= 2.27 tabulate >= 0.8 requests-cache >= 0.9.4 setup_requires = From c167a95370aef53c78f70d3fccf2584ded402fb4 Mon Sep 17 00:00:00 2001 From: Kenneth Bingham Date: Thu, 13 Nov 2025 13:36:31 -0500 Subject: [PATCH 2/3] fix demo region --- netfoundry/ctl.py | 1 + netfoundry/demo.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/netfoundry/ctl.py b/netfoundry/ctl.py index 0430149..38b19be 100644 --- a/netfoundry/ctl.py +++ b/netfoundry/ctl.py @@ -935,6 +935,7 @@ def demo(cli): size=cli.config.demo.size, version=cli.config.demo.product_version, provider=cli.config.demo.provider, + location=cli.config.demo.regions[0], # Use first region for network location ) network, network_group = use_network( cli, diff --git a/netfoundry/demo.py b/netfoundry/demo.py index 35610cb..e8f8903 100755 --- a/netfoundry/demo.py +++ b/netfoundry/demo.py @@ -28,11 +28,13 @@ def importlib_load_entry_point(spec, group, name): globals().setdefault('load_entry_point', importlib_load_entry_point) + def main(): sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) _args = [sys.argv[0], 'demo'] + sys.argv[1:] sys.argv = _args sys.exit(load_entry_point('netfoundry', 'console_scripts', 'nfctl')()) + if __name__ == '__main__': main() From 0d3916ea2dec51d23d22142579a0d20ed5dd8d52 Mon Sep 17 00:00:00 2001 From: Kenneth Bingham Date: Thu, 13 Nov 2025 13:43:57 -0500 Subject: [PATCH 3/3] require requests versions after the breaking change --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 14059a7..b01084a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -30,7 +30,7 @@ install_requires = pygments >= 2.11 pyjwt >= 2.3 pyyaml >= 5.4 - requests >= 2.27 + requests >= 2.30 tabulate >= 0.8 requests-cache >= 0.9.4 setup_requires =