Skip to content

fix: move names definition to class-level#913

Merged
PierreF merged 2 commits into
eclipse-paho:masterfrom
pswsm:refactor/reason-codes
Jun 16, 2026
Merged

fix: move names definition to class-level#913
PierreF merged 2 commits into
eclipse-paho:masterfrom
pswsm:refactor/reason-codes

Conversation

@pswsm

@pswsm pswsm commented May 26, 2026

Copy link
Copy Markdown
Contributor

ResonCode documentation states:

See ReasonCode.names for a list of possible numeric values
along with their names and the packets to which they apply.

Make the code comply with the docs.

ResonCode documentation states:
> See ReasonCode.names for a list of possible numeric values
> along with their names and the packets to which they apply.

Signed-off-by: Pau Figueras <pau.figueras@asensenova.com>
@pswsm pswsm changed the title move names definition to class-level fix: move names definition to class-level Jun 10, 2026
@pswsm

pswsm commented Jun 11, 2026

Copy link
Copy Markdown
Contributor Author

Looks like I made a duplicate of #845 , but that PR has more changes.

@JamesParrott

JamesParrott commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

I completely understand where you're coming from, but it would be simpler to change the documentation, than to change the code.

My concern is that mutations to the dict, would now affect all instances' dicts. I don't know why a user would ever do that, but that's no reason to break their code.

More importantly, it would cause test pollution if that dict was mutated in testing (it would then affect that dict in other tests).

My first request is simply to rephrase the docstring, and any other references to it.

If there are still good reasons for this change, then my second request is to making the class variable name = MappingProxyType({ ... }) (a read only view from types) to make it obvious that mutations are not supported.

@pswsm

pswsm commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

My reason for this change was to see the list of ReasonCode's to know which packetType and aName combination I was looking for, I was writing unit tests for some of the rejection logic and I needed to test MQTT server disconnects, since I was manually triggering the callbacks.

I agree changing the docs is easier, since I assume creating ReadonCode objects from outside is something that is rarely done.

Should I close this PR? I can take care of updating the docs referencing this part.

@JamesParrott

JamesParrott commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

I think having ReasonCode.name visible is very useful. But if that mean's it's a class variable, it would just be even better if it was a read only one. This is what I'd do:

import functools
import warnings
from typing import Any
from types import MappingProxyType

from .packettypes import PacketTypes


@functools.total_ordering
class ReasonCode:
    """MQTT version 5.0 reason codes class.

    See ReasonCode.names for a list of possible numeric values along with their
    names and the packets to which they apply.

    """

    names = MappingProxyType({
        0: {
            "Success": [PacketTypes.CONNACK, PacketTypes.PUBACK, PacketTypes.PUBREC, PacketTypes.PUBREL, PacketTypes.PUBCOMP, PacketTypes.UNSUBACK, PacketTypes.AUTH],
            "Normal disconnection": [PacketTypes.DISCONNECT],
            "Granted QoS 0": [PacketTypes.SUBACK],
        },
        1: { ... },
        ...
    })
        

I tried to click the file in browser and make a suggestion it that way. But I ended up adding a PR on top of your PR (how are you two creating these suggestions - have I just not got permissions to do it?).

@pswsm

pswsm commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

I can see that. I did not know about this MappingProxyType, cool.

Also to add a suggestion, when you have selected a line or a few lines on the code review, there a button that looks like a file and has a «±» in the middle. Click it and it adds the suggestion.

@JamesParrott

Copy link
Copy Markdown
Contributor

Nice one Pau - thankyou :). I was wondering how to do exactly that.

@PierreF

PierreF commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

My reason for this change was to see the list of ReasonCode's to know which packetType and aName combination I was looking for, I was writing unit tests for some of the rejection logic and I needed to test MQTT server disconnects, since I was manually triggering the callbacks.

But therefore the option of updating documentation won't solve this problem ? Since you need a instance of the class to access those attributes.

Since the value are "constant", I do think they belong to class attributes (not instance attribute as they correctly do). But I agree that mutation could be an issue: if someone previously mutated the instance attributes, thinking it would be safe since it's instance attribute, our change shouldn't impact globally. So we should ensure user don't mutate by mistake the global values.

I never user MQTT v5 & Properties, but I don't known if the format exported by .names, .properties are fine or too complex (e.g. the "type" which is just a number, or the name which contains or not whitespace). But maybe it's not this PR that should rework this.

As minimal step, I suggest:

  • Moving the information to class attribute, either with enforced read-only or clear enough documentation that mutation shouldn't be done (I'm okay if user is conscious about the risk of doing mutation and do the mutation)
  • But to avoid any possible breaking change, copy the class attribute as instance attribute. Therefore mutation of instance is possible and don't affect class attribute.

What do you think about this suggestion ?

@JamesParrott

Copy link
Copy Markdown
Contributor

Making a mutable instance variable from a read only class variable sounds like the best of both worlds to me.

Make the class attribute immutable using a `MappingProxyType`, as suggested, and mask it a mutable instance class.
@pswsm

pswsm commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

Changes applied. As a side note, IMO the ReasonCode class is weirdly implemented and could probably have a cleaner interface, but that's out of the scope of this PR.

@pswsm

pswsm commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

Also, should I merge main to fix the lint checks?

@JamesParrott

Copy link
Copy Markdown
Contributor

The lint check is failing due to this mypy error:

src/paho/mqtt/reasoncodes.py:122: error: Incompatible types in assignment (expression has type "dict[int, dict[str, list[int]]]", variable has type "MappingProxyType[int, dict[str, list[int]]]")  [assignment]

I'll take a look. Hopefully it's a straightforward annotation.

@pswsm

pswsm commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

Alr thanks @JamesParrott , it looks like shadowing self.names is messing with mypy.

@PierreF PierreF merged commit 7a3d161 into eclipse-paho:master Jun 16, 2026
9 of 10 checks passed
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.

3 participants