Coder Social home page Coder Social logo

JSON example about patma HOT 5 OPEN

gvanrossum avatar gvanrossum commented on June 24, 2024
JSON example

from patma.

Comments (5)

gvanrossum avatar gvanrossum commented on June 24, 2024 1

Okay, but maybe then the example should validate everything and raise in the default case? That would actually simplify things a bit because we can get rid of the Optional (| None).

We should also add case _: raise ... to get_pets() then.

from patma.

Tobias-Kohn avatar Tobias-Kohn commented on June 24, 2024

The example certainly works, but it looks a wee bit artificial too me, to be perfectly honest.

Yes, the str(name) part is a bit of an ugly spot. The reason why it bothers me a bit is that it is used to validate the data without really handling it. To my mind, patterns should be used to let the interpreter select the 'correct' case clause and extract data. Somehow, having a pattern like { "name": str(name) } suggests to me that there will be another pattern { "name": ... } handling anything that is not a string. But I would not use the str() here just as a kind of type annotation.

So, may I propose to slightly change the example like this:

def get_pet(raw_pet: object) -> Cat | Dog | None:
    match raw_pet:
        case {"type": "cat", "name": str(name), "breed": str(breed), "favorite_toy": str(toy)}:
            return Cat(name, breed, toy)
        case {"type": "dog", "name": str(name), "breed": str(breed), "leash_color": str(leash)}:
            return Dog(name, breed, leash)
        case {"type": "cat" | "dog"}:
            raise malformed_data(repr(raw_pet))
        case _:
            return None  # Not a known type of pet

Perhaps it might also be a nice touch to add a very brief description or title saying something like "transforming data from JSON to Python data classes."

from patma.

Tobias-Kohn avatar Tobias-Kohn commented on June 24, 2024

Yes, that sounds good to me. I would still have the additional case then, though, and use perhaps two different exception types. One could be malformed_data and the other not_a_pet, for instance.

from patma.

gvanrossum avatar gvanrossum commented on June 24, 2024

Okay, then my next version is:

# Cats and Dogs

import sys
import json
from dataclasses import dataclass

@dataclass
class Animal:
    pass

@dataclass
class Pet(Animal):
    name: str
    breed: str

@dataclass
class Dog(Pet):
    leash_color: str

@dataclass
class Cat(Pet):
    favorite_toy: str

def get_pets(raw: object) -> list[Cat | Dog]:
    match raw:
        case [*raw_pets]:  # List of pets
            return [get_pet(raw_pet) for raw_pet in raw_pets]
        case {**raw_pet}:  # Maybe a single pet
            return [get_pet(raw_pet)]
        case _:
            raise TypeError(f"Neither a pet nor a list of pets: {raw}")

def get_pet(raw_pet: object) -> Cat | Dog:
    match raw_pet:
        case {"type": "cat", "name": str(name), "breed": str(breed), "favorite_toy": str(toy)}:
            return Cat(name, breed, toy)
        case {"type": "dog", "name": str(name), "breed": str(breed), "leash_color": str(leash)}:
            return Dog(name, breed, leash)
        case {"type": "cat" | "dog"}:
            raise TypeError(f"Malformed pet: {raw_pet}")
        case _:
            raise TypeError(f"Not a pet: {raw_pet}")

def main() -> None:
    raw = json.load(sys.stdin)
    for pet in get_pets(raw):
        print(pet)

if __name__ == "__main__":
    main()

However, I still find this too long for inclusion in PEP 635 (where I have a TODO suggesting a JSON example), and even if we link to it I'm less than thrilled about using str(name) six times -- this is too similar to the expression of that form. If we could instead use

    case {"type": "cat", "name": name, "breed": breed, "favorite_toy": toy}:

it would be more accessible as an example, but of course it fails to validate properly.

from patma.

gvanrossum avatar gvanrossum commented on June 24, 2024

Cleaned up as https://github.com/gvanrossum/patma/blob/master/examples/jsonpets.py

I changed the structure somewhat, moving "breed" into Dog and changing it to "pattern" for Cat (tuxedo cats aren't a breed, the Internet tells me).

Note that there's no way to validate the type annotations, as no type checker for Python currently supports match statements (nor the PEP 604 | notation for Unions :-).

from patma.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.