Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
741aed5
Update aiohttp requirement from <4.0.0,>=3.14.3 to >=3.14.4,<4.0.0
dependabot[bot] Oct 9, 2026
20b800a
deps: pin oauthlib>=4.0.0 (CVE-2026-49264, CVE-2026-49265)
friedrichwilken Oct 1, 2026
b48ea73
Bump helm/kind-action from 1.15.0 to 1.15.1
dependabot[bot] Oct 9, 2026
b97fce1
Update pydantic requirement from >=2.13.5 to >=2.14.0
dependabot[bot] Oct 12, 2026
73398e0
fix: normalize quantity overflow errors
KeuqS Oct 12, 2026
fa4998c
test: cover quantity exponent overflow
KeuqS Oct 12, 2026
8e6724e
Update aiohttp requirement from <4.0.0,>=3.14.4 to >=3.14.5,<4.0.0
dependabot[bot] Oct 14, 2026
f024960
Fix websocket proxy auth truncating passwords with colons
Akshaay1 Oct 13, 2026
2333b0c
Update pydantic requirement from >=2.14.0 to >=2.14.1
dependabot[bot] Oct 15, 2026
963b191
test(utils): make keepalive tests pass on macOS
ArfiArfath21 Oct 16, 2026
46d0705
Relax the certifi lower bound and stop Dependabot raising lower bounds
sayaksatpathi Oct 15, 2026
b19694b
fix(utils): reject mi, ni and ui as quantity suffixes
ArfiArfath21 Oct 16, 2026
f467c84
Update pluggy requirement from >=1.6.0 to >=1.7.0
dependabot[bot] Oct 19, 2026
9610832
Update setuptools requirement from >=84.0.0 to >=84.2.0
dependabot[bot] Oct 23, 2026
b32cd7e
Update setuptools requirement from >=84.2.0 to >=84.2.1
dependabot[bot] Oct 26, 2026
7d51a8b
Update python-dateutil requirement from >=2.8.2 to >=3.0.0
dependabot[bot] Oct 26, 2026
84ae61e
Bump actions/setup-python from 7.0.0 to 7.1.0
dependabot[bot] Oct 26, 2026
dad2463
Update pydantic requirement from >=2.14.1 to >=2.14.2
dependabot[bot] Nov 2, 2026
49be82d
update version constants for 37.0.2 release
yliaog Nov 5, 2026
2e77435
update changelog
yliaog Nov 5, 2026
e38039f
generated client change
yliaog Nov 5, 2026
3778eda
updated compatibility matrix and maintenance status in the README
yliaog Nov 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ updates:
schedule:
interval: "daily"
time: "02:00"
# requirements.txt is the install_requires of a published library, so
# widen ranges instead of raising lower bounds on every new release.
versioning-strategy: "widen"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/e2e-master.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
with:
submodules: true
- name: Create Kind Cluster
uses: helm/kind-action@06c1ae10762d3b9c1644e7fe69596ae519e015a2
uses: helm/kind-action@1544676c07bb3570fcb70166beaa07c4528fd4aa
with:
cluster_name: kubernetes-python-e2e-master-${{ matrix.python-version }}
# The kind version to be used to spin the cluster up
Expand All @@ -30,7 +30,7 @@ jobs:
# as we sync with Kubernetes upstream
config: .github/workflows/kind-configs/cluster-1.35.yaml
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/e2e-release-35.0.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
with:
submodules: true
- name: Create Kind Cluster
uses: helm/kind-action@06c1ae10762d3b9c1644e7fe69596ae519e015a2
uses: helm/kind-action@1544676c07bb3570fcb70166beaa07c4528fd4aa
with:
cluster_name: kubernetes-python-e2e-release-35.0-${{ matrix.python-version }}
# The kind version to be used to spin the cluster up
Expand All @@ -30,7 +30,7 @@ jobs:
# as we sync with Kubernetes upstream
config: .github/workflows/kind-configs/cluster-1.35.yaml
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
with:
submodules: true
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# v37.0.2

Kubernetes API Version: v1.37.2


Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Anything worth documented in the changelog for cutting a new release?

# v37.0.1

Kubernetes API Version: v1.37.1
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ supported versions of Kubernetes clusters.
- [client 34.y.z](https://pypi.org/project/kubernetes/34.1.0/): Kubernetes 1.33 or below (+-), Kubernetes 1.34 (✓), Kubernetes 1.35 or above (+-)
- [client 35.y.z](https://pypi.org/project/kubernetes/35.0.0/): Kubernetes 1.34 or below (+-), Kubernetes 1.35 (✓), Kubernetes 1.36 or above (+-)
- [client 36.y.z](https://pypi.org/project/kubernetes/36.0.3/): Kubernetes 1.35 or below (+-), Kubernetes 1.36 (✓), Kubernetes 1.37 or above (+-)
- [client 37.y.z](https://pypi.org/project/kubernetes/37.0.1/): Kubernetes 1.36 or below (+-), Kubernetes 1.37 (✓), Kubernetes 1.38 or above (+-)
- [client 37.y.z](https://pypi.org/project/kubernetes/37.0.2/): Kubernetes 1.36 or below (+-), Kubernetes 1.37 (✓), Kubernetes 1.38 or above (+-)


> See [here](#homogenizing-the-kubernetes-python-client-versions) for an explanation of why there is no v13-v16 release.
Expand Down
2 changes: 1 addition & 1 deletion kubernetes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ No description provided (generated by Openapi Generator https://github.com/opena
This Python package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:

- API version: release-1.37
- Package version: 37.0.1
- Package version: 37.0.2
- Generator version: 7.25.0
- Build package: org.openapitools.codegen.languages.PythonClientCodegen

Expand Down
2 changes: 1 addition & 1 deletion kubernetes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

__project__ = 'kubernetes'
# The version is auto-updated. Please do not edit.
__version__ = "37.0.1"
__version__ = "37.0.2"

from . import client
from . import config
Expand Down
2 changes: 1 addition & 1 deletion kubernetes/aio/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ No description provided (generated by Openapi Generator https://github.com/opena
This Python package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:

- API version: release-1.37
- Package version: 37.0.1
- Package version: 37.0.2
- Generator version: 7.25.0
- Build package: org.openapitools.codegen.languages.PythonClientCodegen

Expand Down
2 changes: 1 addition & 1 deletion kubernetes/aio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

__project__ = "kubernetes_aio"
# The version is auto-updated. Please do not edit.
__version__ = "37.0.1"
__version__ = "37.0.2"

import kubernetes.aio.client as client
import kubernetes.aio.config as config
Expand Down
2 changes: 1 addition & 1 deletion kubernetes/aio/client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
""" # noqa: E501


__version__ = "37.0.1"
__version__ = "37.0.2"

# Define package exports
__all__ = [
Expand Down
2 changes: 1 addition & 1 deletion kubernetes/aio/client/api_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ def __init__(
self.default_headers[header_name] = header_value
self.cookie = cookie
# Set default User-Agent.
self.user_agent = 'OpenAPI-Generator/37.0.1/python'
self.user_agent = 'OpenAPI-Generator/37.0.2/python'
self.client_side_validation = configuration.client_side_validation

async def __aenter__(self):
Expand Down
2 changes: 1 addition & 1 deletion kubernetes/aio/client/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,7 @@ def to_debug_report(self) -> str:
"OS: {env}\n"\
"Python Version: {pyversion}\n"\
"Version of the API: release-1.37\n"\
"SDK Package Version: 37.0.1".\
"SDK Package Version: 37.0.2".\
format(env=sys.platform, pyversion=sys.version)

def get_host_settings(self) -> List[HostSetting]:
Expand Down
2 changes: 1 addition & 1 deletion kubernetes/client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
""" # noqa: E501


__version__ = "37.0.1"
__version__ = "37.0.2"

# Define package exports
__all__ = [
Expand Down
2 changes: 1 addition & 1 deletion kubernetes/client/api_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ def __init__(
self.pool_threads = pool_threads
self._pool_lock = Lock()
# Set default User-Agent.
self.user_agent = 'OpenAPI-Generator/37.0.1/python'
self.user_agent = 'OpenAPI-Generator/37.0.2/python'
self.client_side_validation = configuration.client_side_validation

def close(self):
Expand Down
2 changes: 1 addition & 1 deletion kubernetes/client/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,7 @@ def to_debug_report(self) -> str:
"OS: {env}\n"\
"Python Version: {pyversion}\n"\
"Version of the API: release-1.37\n"\
"SDK Package Version: 37.0.1".\
"SDK Package Version: 37.0.2".\
format(env=sys.platform, pyversion=sys.version)

def get_host_settings(self) -> List[HostSetting]:
Expand Down
12 changes: 12 additions & 0 deletions kubernetes/e2e_test/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -688,8 +688,16 @@ def test_parse_quantity(self):
self.assertRaises(
ValueError, lambda: quantity.parse_quantity("1000ki")
)
# "m", "n" and "u" are base 1000 only; there is no mi, ni or ui
for invalid in ("1mi", "1ni", "1ui"):
self.assertRaises(
ValueError, lambda: quantity.parse_quantity(invalid)
)
self.assertRaises(ValueError, lambda: quantity.parse_quantity("1000foo"))
self.assertRaises(ValueError, lambda: quantity.parse_quantity("foo"))
self.assertRaises(
ValueError, lambda: quantity.parse_quantity("2.e388635141Ki")
)

# == no suffix ==
self.assertEqual(quantity.parse_quantity("1000"), Decimal(1000))
Expand Down Expand Up @@ -729,6 +737,10 @@ def test_format_quantity(self):
self.assertRaises(
ValueError, lambda: quantity.format_quantity(Decimal(1_000), "ki")
)
for invalid in ("mi", "ni", "ui"):
self.assertRaises(
ValueError, lambda: quantity.format_quantity(Decimal(1_000), invalid)
)
self.assertRaises(
ValueError, lambda: quantity.format_quantity(Decimal(1_000), "foo")
)
Expand Down
5 changes: 3 additions & 2 deletions kubernetes/stream/ws_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -599,8 +599,9 @@ def websocket_proxycare(connect_opt, configuration, url, headers):
for key,value in configuration.proxy_headers.items():
if key == 'proxy-authorization' and value.startswith('Basic'):
b64value = value.split()[1]
auth = urlsafe_b64decode(b64value).decode().split(':')
connect_opt.update({'http_proxy_auth': (auth[0], auth[1]) })
auth = urlsafe_b64decode(b64value).decode().split(':', 1)
if len(auth) == 2:
connect_opt.update({'http_proxy_auth': (auth[0], auth[1]) })
return(connect_opt)


Expand Down
2 changes: 2 additions & 0 deletions kubernetes/stream/ws_client_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ def test_websocket_proxycare(self):
( 'http://proxy.example.com:8080/', 'user:pass', '*', 'proxy.example.com', 8080, ('user','pass'), ['*']),
( 'http://proxy.example.com:8080/', 'user:pass', '.example.com', 'proxy.example.com', 8080, ('user','pass'), ['.example.com']),
( 'http://proxy.example.com:8080/', 'user:pass', 'localhost,.local,.example.com', 'proxy.example.com', 8080, ('user','pass'), ['localhost','.local','.example.com']),
( 'http://proxy.example.com:8080/', 'user:pa:ss:word', None, 'proxy.example.com', 8080, ('user','pa:ss:word'), None),
( 'http://proxy.example.com:8080/', 'useronly', None, 'proxy.example.com', 8080, None, None),
]:
# input setup
cfg = Configuration(proxy='', no_proxy='')
Expand Down
22 changes: 17 additions & 5 deletions kubernetes/utils/keepalive_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@
from kubernetes.utils.keepalive import tcp_keepalive_socket_options


# Linux spells the idle time TCP_KEEPIDLE, macOS spells it TCP_KEEPALIVE, and
# some platforms have neither (keepalive.py skips the option there).
IDLE_OPTION = getattr(socket, 'TCP_KEEPIDLE',
getattr(socket, 'TCP_KEEPALIVE', None))
needs_idle_option = unittest.skipIf(
IDLE_OPTION is None, 'platform has no TCP keepalive idle option')


def fake_socket_module(**names):
"""A stand-in for the socket module exposing only the given names."""

Expand All @@ -39,12 +47,13 @@ def fake_socket_module(**names):

class TestTcpKeepaliveSocketOptions(unittest.TestCase):

@needs_idle_option
def test_defaults_match_client_go(self):
options = tcp_keepalive_socket_options()

self.assertIn((socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1), options)
self.assertIn(
(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 30), options)
(socket.IPPROTO_TCP, IDLE_OPTION, 30), options)
self.assertIn(
(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 15), options)
self.assertIn((socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 9), options)
Expand All @@ -56,10 +65,11 @@ def test_keeps_the_urllib3_defaults(self):
for default in defaults:
self.assertIn(default, options)

@needs_idle_option
def test_custom_timings(self):
options = tcp_keepalive_socket_options(idle=5, interval=2, count=3)

self.assertIn((socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 5), options)
self.assertIn((socket.IPPROTO_TCP, IDLE_OPTION, 5), options)
self.assertIn((socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 2), options)
self.assertIn((socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 3), options)

Expand All @@ -74,15 +84,17 @@ def test_options_are_setsockopt_triples(self):
for item in option:
self.assertIsInstance(item, int)

@needs_idle_option
def test_options_apply_to_a_socket(self):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
for level, name, value in tcp_keepalive_socket_options():
sock.setsockopt(level, name, value)

# Boolean options read back as any non-zero value (8 on macOS)
self.assertNotEqual(
0, sock.getsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE))
self.assertEqual(
1, sock.getsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE))
self.assertEqual(
30, sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE))
30, sock.getsockopt(socket.IPPROTO_TCP, IDLE_OPTION))

def test_falls_back_to_tcp_keepalive_on_macos(self):
macos = fake_socket_module(
Expand Down
22 changes: 13 additions & 9 deletions kubernetes/utils/quantity.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from decimal import Decimal, InvalidOperation
from decimal import Decimal, DecimalException, InvalidOperation

_EXPONENTS = {
"n": -3,
Expand All @@ -26,6 +26,9 @@
"E": 6,
}

# Only these prefixes exist in base 1024 (Ki, Mi, Gi, Ti, Pi, Ei).
_BINARY_PREFIXES = "KMGTPE"


def parse_quantity(quantity):
"""
Expand Down Expand Up @@ -68,21 +71,23 @@ def parse_quantity(quantity):
return number

if suffix.endswith("i"):
# handle SI inconsistency: "ki", "mi", "ni" and "ui" are not valid binary suffixes
if suffix[0] not in _BINARY_PREFIXES:
raise ValueError("{} has unknown suffix".format(quantity))
base = 1024
elif len(suffix) == 1:
base = 1000
else:
raise ValueError("{} has unknown suffix".format(quantity))

# handle SI inconsistency
if suffix == "ki":
raise ValueError("{} has unknown suffix".format(quantity))

if suffix[0] not in _EXPONENTS:
raise ValueError("{} has unknown suffix".format(quantity))

exponent = Decimal(_EXPONENTS[suffix[0]])
return number * (base ** exponent)
try:
return number * (base ** exponent)
except DecimalException as exc:
raise ValueError("Invalid quantity: {}".format(quantity)) from exc


def format_quantity(quantity_value, suffix, quantize=None) -> str:
Expand Down Expand Up @@ -124,15 +129,14 @@ def format_quantity(quantity_value, suffix, quantize=None) -> str:
return str(quantity_value)

if suffix.endswith("i"):
if suffix[0] not in _BINARY_PREFIXES:
raise ValueError(f"{quantity_value} has unknown suffix")
base = 1024
elif len(suffix) == 1:
base = 1000
else:
raise ValueError(f"{quantity_value} has unknown suffix")

if suffix == "ki":
raise ValueError(f"{quantity_value} has unknown suffix")

if suffix[0] not in _EXPONENTS:
raise ValueError(f"{quantity_value} has unknown suffix")

Expand Down
6 changes: 3 additions & 3 deletions requirements-asyncio.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
python-dateutil>=2.8.2 # BSD
python-dateutil>=3.0.0 # BSD
PyYAML>=6.0.3 # MIT
urllib3>=2.8.0 # MIT
aiohttp>=3.14.3,<4.0.0 # Apache-2.0
aiohttp>=3.14.5,<4.0.0 # Apache-2.0
aiohttp-retry>=2.9.1 # MIT
pydantic>=2.13.5 # MIT
pydantic>=2.14.2 # MIT
typing-extensions>=4.16.0 # PSF
9 changes: 5 additions & 4 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
certifi>=2026.7.22 # MPL
python-dateutil>=2.8.2 # BSD
pydantic>=2.13.5 # MIT
setuptools>=84.0.0 # PSF/ZPL
certifi>=2024.7.4 # MPL -- oldest release without a known advisory (CVE-2024-39689)
python-dateutil>=3.0.0 # BSD
pydantic>=2.14.2 # MIT
setuptools>=84.2.1 # PSF/ZPL
PyYAML>=6.0.3 # MIT
websocket-client>=0.32.0,!=0.40.0,!=0.41.*,!=0.42.* # LGPLv2+
requests # Apache-2.0
requests-oauthlib # ISC
oauthlib>=4.0.0 # ISC -- CVE-2026-49264, CVE-2026-49265; remove once requests-oauthlib bumps its own lower bound
typing-extensions>=4.16.0 # PSF
urllib3>=2.8.0,<3.0.0 # MIT
durationpy>=0.11 # MIT
2 changes: 1 addition & 1 deletion scripts/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
KUBERNETES_BRANCH = "release-1.37"

# client version for packaging and releasing.
CLIENT_VERSION = "37.0.1"
CLIENT_VERSION = "37.0.2"

# Name of the release package
PACKAGE_NAME = "kubernetes"
Expand Down
2 changes: 1 addition & 1 deletion setup-asyncio.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

# Do not edit these constants. They will be updated automatically
# by scripts/update-client-asyncio.sh.
CLIENT_VERSION = "37.0.1"
CLIENT_VERSION = "37.0.2"
PACKAGE_NAME = "kubernetes.aio"
DEVELOPMENT_STATUS = "5 - Production/Stable"

Expand Down
2 changes: 1 addition & 1 deletion setup-release.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

# Do not edit these constants. They will be updated automatically
# by scripts/update-client.sh.
CLIENT_VERSION = "37.0.1"
CLIENT_VERSION = "37.0.2"
PACKAGE_NAME = "kubernetes"
DEVELOPMENT_STATUS = "5 - Production/Stable"

Expand Down
Loading
Loading