Skip to content

Use object instead of Any for labels() parameters#1186

Open
gregoiredx wants to merge 1 commit into
prometheus:masterfrom
gregoiredx:gdeveaux/labels-object-typing
Open

Use object instead of Any for labels() parameters#1186
gregoiredx wants to merge 1 commit into
prometheus:masterfrom
gregoiredx:gdeveaux/labels-object-typing

Conversation

@gregoiredx

@gregoiredx gregoiredx commented Jun 26, 2026

Copy link
Copy Markdown

I'm working on a project where we try to reduce lines flagged as Any by mypy line precision report.

The type of labels() parameters is Any, reducing the whole line as Any (mypy takes the worst of the line typing for its report).

Using object here looks like the right choice.

From https://mypy.readthedocs.io/en/stable/kinds_of_types.html#the-any-type

This should not be confused with the object type, which represents the set of all values. Unlike object, Any introduces type unsafety — see Any vs. object for more.

I first thought it would even be str since it's the natural type of labels, but labels() transforms parameters to strings automatically (labelvalues = tuple(str(labelkwargs[l]) for l in self._labelnames) and labelvalues = tuple(str(l) for l in labelvalues)).

So we mean "anything that can be stred", object looks like a good candidate for that type.

Note: I had to introduce str_labelvalues to comply with mypy (since now labelvalues has type tuple[object, ...] which is not compatible with tuple[str, ...]).

@gregoiredx gregoiredx force-pushed the gdeveaux/labels-object-typing branch from 9c154a6 to 49c6c19 Compare June 26, 2026 10:27
@gregoiredx gregoiredx marked this pull request as ready for review June 26, 2026 10:27
@gregoiredx

Copy link
Copy Markdown
Author

Hello @csmarchbanks 👋 Following the CONTRIBUTING.md, I should ping you to get your review for a trivial change.

This is just a type change from Any to object. What do you think about it?

Signed-off-by: Grégoire Deveaux <gregoire.deveaux@gitguardian.com>
@gregoiredx gregoiredx force-pushed the gdeveaux/labels-object-typing branch from 49c6c19 to 757abe8 Compare June 26, 2026 10:40

@csmarchbanks csmarchbanks left a comment

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.

Thanks for the PR!

I don't feel like it helps all that much though, I don't love introducing another variable just to appease the typechecker when Any still works (or will raise) today. What's the goal of reducing Any usage?

@gregoiredx

gregoiredx commented Jun 28, 2026

Copy link
Copy Markdown
Author

Thanks for looking into it!

What's the goal of reducing Any usage?

The name Any may be a bit counter intuitive, but it's usage is meant to say "I don't know, I want to opt out from type checking here" and not just "this can be of any type". When you want the type checker to look at the code while making sure it can handle any type, then the proper type to use is object.
mypy doc is pretty clear about that:

You can use Any as an “escape hatch” when you can’t use a more precise type for some reason.
This should not be confused with the object type, which represents the set of all values. Unlike object, Any introduces type unsafety — see Any vs. object for more.

That's actually exactly what happened to labelvalues. It was using the "escape hatch" so mypy did not type check anything related to labelvalues but when I switched to object, mypy started to actually check this variable.

In our case, we have introduced type checking on a big code base (>1M lines). We can't type everything at once but we need a metric to be able to follow our progress. mypy reports help us do this by giving statistics per lines and modules for what it's able to infer. Lines using the Any "escape hatch" intruduce "type unsafety" (by mypy definition). Those are lines where mypy is in effect useless. Since we want to enforce typing, measuring that this number goes down is highly correlated to our code being actually type safe.

I don't love introducing another variable just to appease the typechecker

Me neither. You can say it's just to appease the typechecker but one could say it's to fix types in this method.
It's the cost of going from a purely dynamically typed language to a type checked one. Some things are not doable anymore.
In this case:

  • assigning tuple[str, ...] to a variable already typed tuple[object, ...], see "invariance" about that
  • comply with _metrics: Dict[Sequence[str], T]

We may be able to keep type checking and handle those problems via casts or ignored errors but I'm not sure it's better than introducing a variable.

From my perspective, it looks like we can easily remove "type unsafety" from labels() for a very small cost. It's already built to accept anything that can be stred, a perfect candidate for object rather than Any.
In our code base only, it would introduce type safety to hundreds of lines, so in the global ecosystem of Python project using prometheus-client, it will be a big type safety improvement!

But you're the maintainer and it could make sense to consciously choose type unsafety in some parts of the lib. We can do some kind of wrapper on our side to confine the Prometheus client type unsafety part.

I hope this is clear and not too long 😄

@gregoiredx gregoiredx requested a review from csmarchbanks June 28, 2026 11:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants