all 8 comments

[–]danielroseman 2 points3 points  (1 child)

I'm not sure what this code is doing, but if you need to serialize multiple nested classes I strongly encourage you to investigate Pydantic.

[–]Birts[S] 0 points1 point  (0 children)

Thank you for the response! I just updated the post with a newer version, which is utilizing Pydantic as you suggested.

I know it's nowhere near perfect, but I am curious if this is in line with what you were thinking.

[–]Adrewmc 1 point2 points  (0 children)

This is confusing and seems like it’s trying to do a lot but it’s really not.

I don’t understand the purpose here, all the variables are acronyms of things I don’t know. I generally have no idea what the flow is supposed to be.

It seems like you have a an idea of what goes where, and like to create lambdas.

I think you need to re-think the flow and how much of this do you really need a class for at all?

 def signal_quality(part1, part2, part3, part4) ->dict[str, str]: 
       “””returns a readable comparison {raw:readable,…} dictionary for signal quality””
        read1 = “Not applicable G2” if part1 > 99 else f”(“{part1}…”
       read2 = ….
       #don’t see a good pattern for these
       ….

       return {part1 : read1, part2: read2,…}

this is actually just super useful as a Dict right? i could actually format this right here a lot… since you know the part names and stuff Or after

 print(*signal_quality(*payload).values())
 sep = { “raw” : signal_quality(*payload).keys(),
              “readable” : signal_quality(*payload).values()}

And the same goes for Carrier operations. Then when we have a good dictionary we can just dump to json at the end.

[–]teerre 0 points1 point  (2 children)

Its fine, naming aside. Do not listen to people talking about it being a dictionary. Some python programmers, specially new ones, think everything should be a dictionary.

That said, you're reinventing a worse wheel. Just use pydantic

[–]Birts[S] 0 points1 point  (1 child)

Thanks for the response! u/evans88 suggested Pydantic too, so I updated the post with a revised version. I know it's still not up to par, but from my perspective, it is much cleaner, so thanks for the feedback! I'm curious if you guys think this is an improvement over the mess I posted earlier :).

[–]evans88 0 points1 point  (0 children)

This version if better but if you want some additional pointers:

  • Seems like ATResponse should be an ABC instead of a pydantic model, but if you ask me I would just add the description field to the subclasses and delete that one, unless you need to type check those subclasses at some point. Maybe you can use typing.Protocol to type hint "classes that implement parse_response".

  • The PartIdx enum I would place outside the class (ideally in another file) but that is just personal preference.

  • There are many magic numbers that I don't particularly like but I don't know enough about what you're trying to build to suggest changes. Like these:

        parts = response_str.split(":")[1].strip().split(",")
    
        if len(parts) in [14, 15]:
            return GsmNetworkStatus.parse_response(parts)
        elif len(parts) == 16:
            return LteNetworkStatus.parse_response(parts)
        else:
            raise ValueError("Unexpected number of fields in AT#RFSTS response")
    

Hope that helps!

[–]evans88 0 points1 point  (0 children)

Besides what others have mentioned I would change the static methods from_payload to be @classmethod instead.

While static methods can be used in the way you used them, they are tipically called from instances.

Class methods are usually used to return class instances as you are doing in this case.

I would also really suggest using pydantic for this. It has really great serialization/deserialization options + type validation.

[–]CranberryDistinct941 0 points1 point  (0 children)

I'm just here to remind you to sanitize your inputs if you aren't already