python
python copied to clipboard
Friendlier OOP API?
What is the feature and why do you need it:
I'd love to be able to do something like this:
from kubernetes.client import ExtensionsV1beta1Ingress as Ingress
...
for ingress in Ingress.list(namespace="default"):
ingress.metadata.labels["foo"] = "bar"
ingress.patch()
Describe the solution you'd like to see:
Implementing a bunch of default class methods and properties such as list and list_namespaced (or maybe list(namespace="...")), as well as instance methods such as delete and patch.
I know that this feature proposal is rather succinct, and I'm sorry about this, but I'd love some feedback before moving in any direction. Maybe this is too much of a change and would be simpler implemented in another library based on this client?
This sounds like a huge change to the client interface. Could you list the Pros and Cons of the change? We need to see more evidence of the benefits to this client library.
TL;DR: This indeed a huge change, but not a breaking one: it's most likely possible to implement this as an abstraction layer that uses current mechanisms, and Python developers will very probably like this higher level of abstraction.
If we take my example again
from kubernetes.client import ExtensionsV1beta1Ingress as Ingress
...
for ingress in Ingress.list(namespace="default"):
ingress.metadata.labels["foo"] = "bar"
ingress.patch()
and rewrite it with the current API
from kubernetes.client import ExtensionsV1beta1Api
...
api_instance = ExtensionsV1beta1Api()
ingress_list = api_instance.list_namespaced_ingress(namespace="sandbox")
for ingress in ingress_list.items:
ingress.metadata.labels["foo"] = "bar"
api_instance.patch_namespaced_ingress(
name=ingress.metadata.name, namespace="sandbox", body=ingress
)
we easily see that the current API is more verbose and thus harder to read and understand, and there is just a few lines of code here; it's not getting better with more. We also doubled the number of lines. This goes against Python mindset which is to provide a code as simple as possible. Of course, this is arguably subjective, and the verbosity might be actually useful for some particular use-cases.
More explicitly, there are a few things that could be considered useless (or rather cumbersome) in that rewrite:
- The
api_instance = ExtensionsV1beta1Api()statement: I just want to list the ingresses, whatever version they are defined in. If I want to list ingresses from a specific version, I will enjoy having the option available, but that's not the case here. - The
.items: why would I fetch these objects if I don't iterate on them? - Specifying the name and the namespace of the ingress I want to patch, whereas I could just use the ingress object itself that contains the required information.
I'm not trying to make a point on each of these bullet points, and we might argue on each of those as to why it's better doing it in a way or another, but that's not my... point. I'm just trying to show that overall, it's not as simple as a Python developer would expect it to be.
To go a little further in my thinking, I feel that the current API looks like a lot of cross-language projects where the main influence comes from the Java world, which is not bad as it gives a lot of flexibility and most of the time a good structure, but where the idiomacy of each language's library isn't a priority. This is understandable when you have to work with a lot of languages but boring when you are used to one of these in particular. gRPC, for example, is another cross-language project that has the exact same flaw, in my opinion.
So basically, the pros would be:
- simpler code, smoother learning curve;
- less surface for the developer, so easier use of the library and less risk of doing wrong things;
- thus the library being more "pythonic", which induces a better developer experience for pythonistas and a higher probability that they use this library rather than another one (or try to reinvent the wheel).
I guess that cons might be:
- a small cost in performance as in any abstraction, although this is probably not relevant;
- some missing features in comparison to the current API, but we could leave the current API as is so that the developer is free to use any of both (and base the "new" API on current mechanisms);
- if both API are still available, some documentation and testing complexity.
Sorry for the long comment, I usually don't do this, but I couldn't find another way here.
Issues go stale after 90d of inactivity.
Mark the issue as fresh with /remove-lifecycle stale.
Stale issues rot after an additional 30d of inactivity and eventually close.
If this issue is safe to close now please do so with /close.
Send feedback to sig-testing, kubernetes/test-infra and/or fejta. /lifecycle stale
The current interface comes from the code generator that we use. The openapi-based code generation allows us to generate clients in different languages for the ever-growing Kubernetes API. I would be happy if these changes can be made in the upstream generator, but some of the changes seem to require deep knowledge about Kubernetes. Implementing in another library based on this client can be another option, but it could be hard to maintain when Kubneretes API changes.
If you have idea about small changes that can make this client easier to use, I would suggest creating some util methods under https://github.com/kubernetes-client/python/tree/master/kubernetes/utils
Stale issues rot after 30d of inactivity.
Mark the issue as fresh with /remove-lifecycle rotten.
Rotten issues close after an additional 30d of inactivity.
If this issue is safe to close now please do so with /close.
Send feedback to sig-testing, kubernetes/test-infra and/or fejta. /lifecycle rotten
/remove-lifecycle-rotten
I would love to present you a PoC but I'm on a very different work at the moment. As soon as I put my hands back on code that uses this library, I will try to make it happen. If anyone else wants to work on this meanwhile, you're very welcome.
/remove-lifecycle rotten /lifecycle frozen
Just discovered a few alternative clients, and it seems that they all went for an API similar to what I suggested previously (examples coming from their documentation / README):
from lightkube import Client
from lightkube.resources.core_v1 import Node
client = Client()
for node in client.list(Node):
print(node.metadata.name)
>>> Deployment.list()
>>> [Deployment(
status=DeploymentStatus(replicas=1,
observedGeneration=1, updatedReplicas=1,
... # omitted for brevity
)]
- hjacobs/pykube-ng (what kopf uses)
import pykube
api = pykube.HTTPClient(pykube.KubeConfig.from_file())
pods = pykube.Pod.objects(api).filter(namespace="gondor-system")
- Frankkkkk/pykorm (this one actually sits on top of the official library)
>>> all_peaches = Peach.query.all()
>>> for peach in all_peaches:
>>> print(peach)
<Peach namespace=default, name=cake-peach, variety=Frost>
- mnubo/kubernetes-py (abandoned)
from kubernetes_py import K8sDeployment
deployment = K8sDeployment(config=cfg_cert, name='my-deployment')
deployment.list()
Maybe that can help proving that this kind of API is more idiomatic? Or at least familiar to Python developers.