9.2. Serialization JSON

9.2.1. JSON syntax

  • JSON format is similar to dict notation in Python

  • Differences:

    • Coma , is not allowed after the last element in list or object

    • Fields are enclosed only by double quote " character

    • true and false is always lower-cased

    • Instead of None there is null

    • camelCase is convention, although snake_case is also valid

Listing 349. Example JSON file
[
    {"sepalLength": 5.1, "sepalWidth": 3.5, "petalLength": 1.4, "petalWidth": 0.2, "species": "setosa"},
    {"sepalLength": 4.9, "sepalWidth": 3.0, "petalLength": 1.4, "petalWidth": 0.2, "species": "setosa"},
    {"sepalLength": false, "sepalWidth": true, "petalLength": null, "petalWidth": 0.2, "species": null}
]
Listing 350. JSON or Python List[dict]?
[
    {"first_name": "Jan", "last_name": "Twardowski", "addresses": [
        {"street": "Kamienica Pod św. Janem Kapistranem", "city": "Kraków", "post_code": "31-008", "region": "Małopolskie", "country": "Poland"}]},

    {"first_name": "José", "last_name": "Jiménez", "addresses": [
        {"street": "2101 E NASA Pkwy", "city": "Houston", "post_code": 77058, "region": "Texas", "country": "USA"},
        {"street": "", "city": "Kennedy Space Center", "post_code": 32899, "region": "Florida", "country": "USA"}]},

    {"first_name": "Mark", "last_name": "Watney", "addresses": [
        {"street": "4800 Oak Grove Dr", "city": "Pasadena", "post_code": 91109, "region": "California", "country": "USA"},
        {"street": "2825 E Ave P", "city": "Palmdale", "post_code": 93550, "region": "California", "country": "USA"}]},

    {"first_name": "Иван", "last_name": "Иванович", "addresses": [
        {"street": "", "city": "Космодро́м Байкону́р", "post_code": "", "region": "Кызылординская область", "country": "Қазақстан"},
        {"street": "", "city": "Звёздный городо́к", "post_code": 141160, "region": "Московская область", "country": "Россия"}]},

    {"first_name": "Melissa", "last_name": "Lewis", "addresses": []},

    {"first_name": "Alex", "last_name": "Vogel", "addresses": [
        {"street": "Linder Hoehe", "city": "Köln", "post_code": 51147, "region": "North Rhine-Westphalia", "country": "Germany"}]}
]

9.2.2. JSON Serialization of simple objects

To file:

  • json.dump(DATA: dict, file: TextIOWrapper) -> None

  • json.load(file: TextIOWrapper) -> None

To string:

  • json.dumps(DATA: dict) -> str

  • json.loads(DATA: str) -> dict

9.2.2.1. Serialize to JSON

Listing 351. Serialize to JSON
import json


INPUT = {
    'first_name': 'Jan',
    'last_name': 'Twardowski'
}

output = json.dumps(INPUT)
print(output)
# '{"first_name": "Jan", "last_name": "Twardowski"}'

9.2.2.2. Deserialize from JSON

Listing 352. Deserialize from JSON
import json


INPUT = '{"first_name": "Jan", "last_name": "Twardowski"}'

output = json.loads(INPUT)
print(output)
# {
#     'first_name': 'Jan',
#     'last_name': 'Twardowski'
# }

9.2.3. Serializing datetime and date

9.2.3.1. Encoding datetime and date

  • Encoder will be used, when standard procedure fails

Listing 353. Exception during encoding datetime
from datetime import datetime, date
import json


INPUT = {
    'name': 'Jan Twardowski',
    'date': date(1961, 4, 12),
    'datetime': datetime(1969, 7, 21, 2, 56, 15),
}

output = json.dumps(INPUT)
# TypeError: Object of type date is not JSON serializable
Listing 354. Encoding datetime and date
from datetime import datetime, date
import json


INPUT = {
    'name': 'Jan Twardowski',
    'date': date(1961, 4, 12),
    'datetime': datetime(1969, 7, 21, 2, 56, 15),
}


class JSONDatetimeEncoder(json.JSONEncoder):
    def default(self, value):

        if isinstance(value, datetime):
            return value.strftime('%Y-%m-%dT%H:%M:%S.%fZ')

        if isinstance(value, date):
            return value.strftime('%Y-%m-%d')


output = json.dumps(INPUT, cls=JSONDatetimeEncoder)
print(output)
# '{"name": "Jan Twardowski", "date": "1961-04-12", "datetime": "1969-07-21T02:56:15.000Z"}'

9.2.3.2. Decoding datetime and date

Listing 355. Simple loading returns str not datetime or date
import json


INPUT = '{"name": "Jan Twardowski", "date": "1961-04-12", "datetime": "1969-07-21T02:56:15.000Z"}'

output = json.loads(INPUT)
print(output)
# {
#     'name': 'Jan Twardowski',
#     'date': '1961-04-12',
#     'datetime': '1969-07-21T02:56:15.000Z',
# }
Listing 356. Decoding datetime and date
from datetime import datetime, timezone
import json


INPUT = '{"name": "Jan Twardowski", "date": "1961-04-12", "datetime": "1969-07-21T02:56:15.000Z"}'


class JSONDatetimeDecoder(json.JSONDecoder):
    DATE_FIELDS = ['date', 'date_of_birth']
    DATETIME_FIELDS = ['datetime']

    def __init__(self):
        super().__init__(object_hook=self.default)

    def default(self, output: dict) -> dict:
        for field, value in output.items():

            if field in self.DATE_FIELDS:
                value = datetime.strptime(value, '%Y-%m-%d').date()

            if field in self.DATETIME_FIELDS:
                value = datetime.strptime(value, '%Y-%m-%dT%H:%M:%S.%fZ').replace(tzinfo=timezone.utc)

            output[field] = value
        return output


output = json.loads(INPUT, cls=JSONDatetimeDecoder)
print(output)
# {
#     'name': 'Jan Twardowski',
#     'date': date(1961, 4, 12),
#     'datetime': datetime(1969, 7, 21, 2, 56, 15, tzinfo=datetime.timezone.utc),
# }

9.2.4. Serializing objects

9.2.4.1. Encoding nested objects with relations to JSON

  • Encoder will be used, when standard procedure fails

Listing 357. Encoding nested objects with relations to JSON
import json


class Astronaut:
    def __init__(self, name, missions=()):
        self.name = name
        self.missions = missions


class Mission:
    def __init__(self, year, name):
        self.year = year
        self.name = name


CREW = [
    Astronaut('Jan Twardowski', missions=(
        Mission(1969, 'Apollo 18'),
        Mission(2024, 'Artemis 3'))),

    Astronaut('Mark Watney', missions=(
        Mission(2035, 'Ares 3'))),

    Astronaut('Melissa Lewis'),
]


class JSONObjectEncoder(json.JSONEncoder):
    def default(self, obj):
        result = obj.__dict__
        result['__class_name__'] = obj.__class__.__name__
        return result


output = json.dumps(CREW, cls=JSONObjectEncoder, sort_keys=True, indent=2)
print(output)
# [
#   {
#     "name": "Jan Twardowski",
#     "missions": [
#       {
#         "year": 1969,
#         "name": "Apollo 18",
#         "__class_name__": "Mission"
#       },
#       {
#         "year": 2024,
#         "name": "Artemis 3",
#         "__class_name__": "Mission"
#       }
#     ],
#     "__class_name__": "Astronaut"
#   },
#   {
#     "name": "Mark Watney",
#     "missions": {
#       "year": 2035,
#       "name": "Ares 3",
#       "__class_name__": "Mission"
#     },
#     "__class_name__": "Astronaut"
#   },
#   {
#     "name": "Melissa Lewis",
#     "missions": [],
#     "__class_name__": "Astronaut"
#   }
# ]

9.2.4.2. Decoding nested objects with relations to JSON

Listing 358. Encoding nested objects with relations to JSON
import json
import sys

INPUT = """[{"name": "Jan Twardowski", "missions": [{"year": 1969, "name": "Apollo 18", "__class_name__": "Mission"}, {"year": 2024, "name": "Artemis 3", "__class_name__": "Mission"}], "__class_name__": "Astronaut"}, {"name": "Mark Watney", "missions": {"year": 2035, "name": "Ares 3", "__class_name__": "Mission"}, "__class_name__": "Astronaut"}, {"name": "Melissa Lewis", "missions": [], "__class_name__": "Astronaut"}]"""


class Astronaut:
    def __init__(self, name, missions=()):
        self.name = name
        self.missions = missions

    def __repr__(self):
        return f'\n\nAstronaut(name="{self.name}", missions={self.missions})'


class Mission:
    def __init__(self, year, name):
        self.year = year
        self.name = name

    def __repr__(self):
        return f'\n\tMission(year={self.year}, name="{self.name}")'


class JSONObjectDecoder(json.JSONDecoder):
    def __init__(self):
        super().__init__(object_hook=self.default)

    def default(self, obj):
        class_name = obj.pop('__class_name__')
        cls = getattr(sys.modules[__name__], class_name)
        return cls(**obj)


output = json.loads(INPUT, cls=JSONObjectDecoder)
print(output)
# Astronaut(name="Jan Twardowski", missions=[
#    Mission(year=1969, name="Apollo 18"),
#    Mission(year=2024, name="Artemis 3")]),
#
# Astronaut(name="Mark Watney", missions=
#    Mission(year=2035, name="Ares 3")),
#
# Astronaut(name="Melissa Lewis", missions=[])]

9.2.5. Pretty Printing JSON

9.2.5.1. JSON can be minified

  • Save space for network transmission

  • It is not very readable

Listing 359. Minified JSON file
$ INPUT='https://raw.githubusercontent.com/AstroMatt/book-python/master/stdlib/serialization/data/iris.json'
$ curl $INPUT
[{"sepalLength":5.1,"sepalWidth":3.5,"petalLength":1.4,"petalWidth":0.2,"species":"setosa"},{"sepalLength":4.9,"sepalWidth":3,"petalLength":1.4,"petalWidth":0.2,"species":"setosa"},{"sepalLength":4.7,"sepalWidth":3.2,"petalLength":1.3,"petalWidth":0.2,"species":"setosa"},{"sepalLength":4.6,"sepalWidth":3.1,"petalLength":1.5,"petalWidth":0.2,"species":"setosa"},{"sepalLength":5,"sepalWidth":3.6,"petalLength":1.4,"petalWidth":0.2,"species":"setosa"},{"sepalLength":5.4,"sepalWidth":3.9,"petalLength":1.7,"petalWidth":0.4,"species":"setosa"},{"sepalLength":4.6,"sepalWidth":3.4,"petalLength":1.4,"petalWidth":0.3,"species":"setosa"},{"sepalLength":5,"sepalWidth":3.4,"petalLength":1.5,"petalWidth":0.2,"species":"setosa"},{"sepalLength":4.4,"sepalWidth":2.9,"petalLength":1.4,"petalWidth":0.2,"species":"setosa"},{"sepalLength":4.9,"sepalWidth":3.1,"petalLength":1.5,"petalWidth":0.1,"species":"setosa"},{"sepalLength":7,"sepalWidth":3.2,"petalLength":4.7,"petalWidth":1.4,"species":"versicolor"},{"sepalLength":6.4,"sepalWidth":3.2,"petalLength":4.5,"petalWidth":1.5,"species":"versicolor"},{"sepalLength":6.9,"sepalWidth":3.1,"petalLength":4.9,"petalWidth":1.5,"species":"versicolor"},{"sepalLength":5.5,"sepalWidth":2.3,"petalLength":4,"petalWidth":1.3,"species":"versicolor"},{"sepalLength":6.5,"sepalWidth":2.8,"petalLength":4.6,"petalWidth":1.5,"species":"versicolor"},{"sepalLength":5.7,"sepalWidth":2.8,"petalLength":4.5,"petalWidth":1.3,"species":"versicolor"},{"sepalLength":6.3,"sepalWidth":3.3,"petalLength":4.7,"petalWidth":1.6,"species":"versicolor"},{"sepalLength":4.9,"sepalWidth":2.4,"petalLength":3.3,"petalWidth":1,"species":"versicolor"},{"sepalLength":6.6,"sepalWidth":2.9,"petalLength":4.6,"petalWidth":1.3,"species":"versicolor"},{"sepalLength":5.2,"sepalWidth":2.7,"petalLength":3.9,"petalWidth":1.4,"species":"versicolor"},{"sepalLength":6.3,"sepalWidth":3.3,"petalLength":6,"petalWidth":2.5,"species":"virginica"},{"sepalLength":5.8,"sepalWidth":2.7,"petalLength":5.1,"petalWidth":1.9,"species":"virginica"},{"sepalLength":7.1,"sepalWidth":3,"petalLength":5.9,"petalWidth":2.1,"species":"virginica"},{"sepalLength":6.3,"sepalWidth":2.9,"petalLength":5.6,"petalWidth":1.8,"species":"virginica"},{"sepalLength":6.5,"sepalWidth":3,"petalLength":5.8,"petalWidth":2.2,"species":"virginica"},{"sepalLength":7.6,"sepalWidth":3,"petalLength":6.6,"petalWidth":2.1,"species":"virginica"},{"sepalLength":4.9,"sepalWidth":2.5,"petalLength":4.5,"petalWidth":1.7,"species":"virginica"},{"sepalLength":7.3,"sepalWidth":2.9,"petalLength":6.3,"petalWidth":1.8,"species":"virginica"},{"sepalLength":6.7,"sepalWidth":2.5,"petalLength":5.8,"petalWidth":1.8,"species":"virginica"},{"sepalLength":7.2,"sepalWidth":3.6,"petalLength":6.1,"petalWidth":2.5,"species":"virginica"}]

9.2.5.2. Pretty Printing JSON

Listing 360. Pretty Printing JSON
$ INPUT='https://raw.githubusercontent.com/AstroMatt/book-python/master/stdlib/serialization/data/iris.json'
$ curl $INPUT |python -m json.tool
[
    {
        "petalLength": 1.4,
        "petalWidth": 0.2,
        "sepalLength": 5.1,
        "sepalWidth": 3.5,
        "species": "setosa"
    },
    {
        "petalLength": 1.4,
        "petalWidth": 0.2,
        "sepalLength": 4.9,
        "sepalWidth": 3,
        "species": "setosa"
    },
    {
        "petalLength": 1.3,
        "petalWidth": 0.2,
        "sepalLength": 4.7,
        "sepalWidth": 3.2,
        "species": "setosa"
    },
...

9.2.5.3. Check JSON syntax validity

Listing 361. json.tool checks JSON syntax validity
$ echo '{"sepalLength":5.1,"sepalWidth":3.5,}' | python -m json.tool
Expecting property name enclosed in double quotes: line 1 column 37 (char 36)

9.2.6. Assignments

9.2.6.1. Serialize nested sequences to JSON

  • Complexity level: easy

  • Lines of code to write: 8 lines

  • Estimated time of completion: 20 min

  • Solution: solution/json_dump.py

English
  1. Extract from input a header and data

  2. Create List[dict]

    • key: name from the header

    • value: measurement or species

  3. Write structure to file iris_serialize.json in JSON format

Polish
  1. Z danych wydziel nagłówek i pomiary

  2. Wygeneruj List[dict]

    • klucz: nazwa z nagłówka

    • wartość: wyniki pomiarów lub gatunek

  3. Zapisz strukturę do pliku iris_serialize.json w formacie JSON

The whys and wherefores
  • Serializing nested data structures

  • Using stdlib json library

  • Type casting

  • Working with files

Input
INPUT = [
    ('Sepal length', 'Sepal width', 'Petal length', 'Petal width', 'Species'),
    (5.8, 2.7, 5.1, 1.9, 'virginica'),
    (5.1, 3.5, 1.4, 0.2, 'setosa'),
    (5.7, 2.8, 4.1, 1.3, 'versicolor'),
    (6.3, 2.9, 5.6, 1.8, 'virginica'),
    (6.4, 3.2, 4.5, 1.5, 'versicolor'),
    (4.7, 3.2, 1.3, 0.2, 'setosa'),
    (7.0, 3.2, 4.7, 1.4, 'versicolor'),
    (7.6, 3.0, 6.6, 2.1, 'virginica'),
    (4.9, 3.0, 1.4, 0.2, 'setosa'),
    (4.9, 2.5, 4.5, 1.7, 'virginica'),
    (7.1, 3.0, 5.9, 2.1, 'virginica'),
    (4.6, 3.4, 1.4, 0.3, 'setosa'),
    (5.4, 3.9, 1.7, 0.4, 'setosa'),
    (5.7, 2.8, 4.5, 1.3, 'versicolor'),
    (5.0, 3.6, 1.4, 0.3, 'setosa'),
    (5.5, 2.3, 4.0, 1.3, 'versicolor'),
    (6.5, 3.0, 5.8, 2.2, 'virginica'),
    (6.5, 2.8, 4.6, 1.5, 'versicolor'),
    (6.3, 3.3, 6.0, 2.5, 'virginica'),
    (6.9, 3.1, 4.9, 1.5, 'versicolor'),
    (4.6, 3.1, 1.5, 0.2, 'setosa'),
]
Output
Listing 362. Output
output: List[dict] = [
    {'Sepal length': 5.8, 'Sepal width': 2.7, 'Petal length': 5.1, 'Petal width': 1.9, 'Species': 'virginica'},
    {'Sepal length': 5.1, 'Sepal width': 3.5, 'Petal length': 1.4, 'Petal width': 0.2, 'Species': 'setosa'},
    {'Sepal length': 5.7, 'Sepal width': 2.8, 'Petal length': 4.1, 'Petal width': 1.3, 'Species': 'versicolor'},
    ...
]

9.2.6.2. Deserialize nested sequences from JSON

  • Complexity level: easy

  • Lines of code to write: 8 lines

  • Estimated time of completion: 20 min

  • Solution: solution/json_load.py

English
  1. Write input data to "iris_deserialize.json"

  2. Read file and print data in List[tuple] format

  3. First line must be a header

  4. Other lines must contain data

Polish
  1. Dane z listingu poniżej skopiuj do pliku "iris_deserialize.json"

  2. Odczytaj dane z pliku, i wyświetl je w formacie List[tuple]

  3. Pierwsza linijka ma zawierać nagłówek

  4. Kolejne linie mają mieć dane

The whys and wherefores
  • Serializing nested data structures

  • Using stdlib json library

  • Type casting

  • Working with files

Input
[{"sepalLength":5.1,"sepalWidth":3.5,"petalLength":1.4,"petalWidth":0.2,"species":"setosa"},{"sepalLength":4.9,"sepalWidth":3,"petalLength":1.4,"petalWidth":0.2,"species":"setosa"},{"sepalLength":4.7,"sepalWidth":3.2,"petalLength":1.3,"petalWidth":0.2,"species":"setosa"},{"sepalLength":4.6,"sepalWidth":3.1,"petalLength":1.5,"petalWidth":0.2,"species":"setosa"},{"sepalLength":5,"sepalWidth":3.6,"petalLength":1.4,"petalWidth":0.2,"species":"setosa"},{"sepalLength":5.4,"sepalWidth":3.9,"petalLength":1.7,"petalWidth":0.4,"species":"setosa"},{"sepalLength":4.6,"sepalWidth":3.4,"petalLength":1.4,"petalWidth":0.3,"species":"setosa"},{"sepalLength":5,"sepalWidth":3.4,"petalLength":1.5,"petalWidth":0.2,"species":"setosa"},{"sepalLength":4.4,"sepalWidth":2.9,"petalLength":1.4,"petalWidth":0.2,"species":"setosa"},{"sepalLength":4.9,"sepalWidth":3.1,"petalLength":1.5,"petalWidth":0.1,"species":"setosa"},{"sepalLength":7,"sepalWidth":3.2,"petalLength":4.7,"petalWidth":1.4,"species":"versicolor"},{"sepalLength":6.4,"sepalWidth":3.2,"petalLength":4.5,"petalWidth":1.5,"species":"versicolor"},{"sepalLength":6.9,"sepalWidth":3.1,"petalLength":4.9,"petalWidth":1.5,"species":"versicolor"},{"sepalLength":5.5,"sepalWidth":2.3,"petalLength":4,"petalWidth":1.3,"species":"versicolor"},{"sepalLength":6.5,"sepalWidth":2.8,"petalLength":4.6,"petalWidth":1.5,"species":"versicolor"},{"sepalLength":5.7,"sepalWidth":2.8,"petalLength":4.5,"petalWidth":1.3,"species":"versicolor"},{"sepalLength":6.3,"sepalWidth":3.3,"petalLength":4.7,"petalWidth":1.6,"species":"versicolor"},{"sepalLength":4.9,"sepalWidth":2.4,"petalLength":3.3,"petalWidth":1,"species":"versicolor"},{"sepalLength":6.6,"sepalWidth":2.9,"petalLength":4.6,"petalWidth":1.3,"species":"versicolor"},{"sepalLength":5.2,"sepalWidth":2.7,"petalLength":3.9,"petalWidth":1.4,"species":"versicolor"},{"sepalLength":6.3,"sepalWidth":3.3,"petalLength":6,"petalWidth":2.5,"species":"virginica"},{"sepalLength":5.8,"sepalWidth":2.7,"petalLength":5.1,"petalWidth":1.9,"species":"virginica"},{"sepalLength":7.1,"sepalWidth":3,"petalLength":5.9,"petalWidth":2.1,"species":"virginica"},{"sepalLength":6.3,"sepalWidth":2.9,"petalLength":5.6,"petalWidth":1.8,"species":"virginica"},{"sepalLength":6.5,"sepalWidth":3,"petalLength":5.8,"petalWidth":2.2,"species":"virginica"},{"sepalLength":7.6,"sepalWidth":3,"petalLength":6.6,"petalWidth":2.1,"species":"virginica"},{"sepalLength":4.9,"sepalWidth":2.5,"petalLength":4.5,"petalWidth":1.7,"species":"virginica"},{"sepalLength":7.3,"sepalWidth":2.9,"petalLength":6.3,"petalWidth":1.8,"species":"virginica"},{"sepalLength":6.7,"sepalWidth":2.5,"petalLength":5.8,"petalWidth":1.8,"species":"virginica"},{"sepalLength":7.2,"sepalWidth":3.6,"petalLength":6.1,"petalWidth":2.5,"species":"virginica"}]

9.2.6.3. Serializing datetime to JSON

  • Complexity level: easy

  • Lines of code to write: 10 lines

  • Estimated time of completion: 15 min

  • Solution: solution/json_datetime.py

Enlish
  1. Copy input data to your script

  2. Save data to file in JSON format

  3. Read data from file

  4. Recreate data structure

Polish
  1. Skopiuj dane wejściowe do swojego skryptu

  2. Zapisz dane do pliku w formacie JSON

  3. Odczytaj dane z pliku

  4. Odtwórz strukturę danych

The whys and wherefores
  • Serializing nested data structures

  • Using stdlib json library

  • Serialize and deserialize date and datetime objects

Input
from datetime import datetime, date


INPUT = {
    "astronaut": {
        "date": date(1961, 4, 12),
        "person": "[email protected]"
    },
    "flight": [
        {"datetime": datetime(1969, 7, 21, 2, 56, 15), "action": "landing"}
    ]
}

9.2.6.4. Serializing objects to JSON

  • Complexity level: medium

  • Lines of code to write: 15 lines

  • Estimated time of completion: 20 min

English
  1. Copy input data in JSON format to your script

  2. Convert from JSON format to Python

  3. Create classes Setosa, Virginica, Versicolor representing data

  4. Reading file create instances of those classes based on value in field "species"

Polish
  1. Skopiuj dane wejściowe w formacie JSON do swojego skryptu

  2. Przekonwertuj dane z JSON do Python

  3. Stwórz klasy Setosa, Virginica, Versicolor reprezentujące dane

  4. Czytając plik twórz obiekty powyższych klas w zależności od wartości pola "species"

The whys and wherefores
  • Serializing nested data structures

  • Using stdlib json library

  • Serialize and deserialize objects

Input
[
    {"sepalLength": 5.0, "sepalWidth": 3.6, "petalLength": 1.4, "petalWidth": 0.2, "species": "setosa"},
    {"sepalLength": 4.9, "sepalWidth": 3.1, "petalLength": 1.5, "petalWidth": 0.1, "species": "setosa"},
    {"sepalLength": 4.9, "sepalWidth": 3.0, "petalLength": 1.4, "petalWidth": 0.2, "species": "setosa"},
    {"sepalLength": 7.0, "sepalWidth": 3.2, "petalLength": 4.7, "petalWidth": 1.4, "species": "versicolor"},
    {"sepalLength": 4.6, "sepalWidth": 3.1, "petalLength": 1.5, "petalWidth": 0.2, "species": "setosa"},
    {"sepalLength": 6.5, "sepalWidth": 3.0, "petalLength": 5.8, "petalWidth": 2.2, "species": "virginica"},
    {"sepalLength": 7.1, "sepalWidth": 3.0, "petalLength": 5.9, "petalWidth": 2.1, "species": "virginica"},
    {"sepalLength": 6.7, "sepalWidth": 2.5, "petalLength": 5.8, "petalWidth": 1.8, "species": "virginica"},
    {"sepalLength": 5.2, "sepalWidth": 2.7, "petalLength": 3.9, "petalWidth": 1.4, "species": "versicolor"},
    {"sepalLength": 5.0, "sepalWidth": 3.4, "petalLength": 1.5, "petalWidth": 0.2, "species": "setosa"},
    {"sepalLength": 4.9, "sepalWidth": 2.4, "petalLength": 3.3, "petalWidth": 1.0, "species": "versicolor"},
    {"sepalLength": 6.5, "sepalWidth": 2.8, "petalLength": 4.6, "petalWidth": 1.5, "species": "versicolor"},
    {"sepalLength": 5.4, "sepalWidth": 3.9, "petalLength": 1.7, "petalWidth": 0.4, "species": "setosa"},
    {"sepalLength": 6.3, "sepalWidth": 3.3, "petalLength": 4.7, "petalWidth": 1.6, "species": "versicolor"},
    {"sepalLength": 6.4, "sepalWidth": 3.2, "petalLength": 4.5, "petalWidth": 1.5, "species": "versicolor"},
    {"sepalLength": 6.6, "sepalWidth": 2.9, "petalLength": 4.6, "petalWidth": 1.3, "species": "versicolor"},
    {"sepalLength": 5.8, "sepalWidth": 2.7, "petalLength": 5.1, "petalWidth": 1.9, "species": "virginica"},
    {"sepalLength": 6.3, "sepalWidth": 2.9, "petalLength": 5.6, "petalWidth": 1.8, "species": "virginica"},
    {"sepalLength": 7.6, "sepalWidth": 3.0, "petalLength": 6.6, "petalWidth": 2.1, "species": "virginica"},
    {"sepalLength": 5.1, "sepalWidth": 3.5, "petalLength": 1.4, "petalWidth": 0.2, "species": "setosa"},
    {"sepalLength": 7.3, "sepalWidth": 2.9, "petalLength": 6.3, "petalWidth": 1.8, "species": "virginica"},
    {"sepalLength": 4.7, "sepalWidth": 3.2, "petalLength": 1.3, "petalWidth": 0.2, "species": "setosa"},
    {"sepalLength": 6.9, "sepalWidth": 3.1, "petalLength": 4.9, "petalWidth": 1.5, "species": "versicolor"},
    {"sepalLength": 7.2, "sepalWidth": 3.6, "petalLength": 6.1, "petalWidth": 2.5, "species": "virginica"},
    {"sepalLength": 4.4, "sepalWidth": 2.9, "petalLength": 1.4, "petalWidth": 0.2, "species": "setosa"},
    {"sepalLength": 5.5, "sepalWidth": 2.3, "petalLength": 4.0, "petalWidth": 1.3, "species": "versicolor"},
    {"sepalLength": 4.6, "sepalWidth": 3.4, "petalLength": 1.4, "petalWidth": 0.3, "species": "setosa"},
    {"sepalLength": 6.3, "sepalWidth": 3.3, "petalLength": 6.0, "petalWidth": 2.5, "species": "virginica"},
    {"sepalLength": 4.9, "sepalWidth": 2.5, "petalLength": 4.5, "petalWidth": 1.7, "species": "virginica"},
    {"sepalLength": 5.7, "sepalWidth": 2.8, "petalLength": 4.5, "petalWidth": 1.3, "species": "versicolor"}
]

9.2.6.5. Deserialize data from GitHub

  • Complexity level: medium

  • Lines of code to write: 15 lines

  • Estimated time of completion: 20 min

  • Solution: solution/json_github.py

English
  1. Use requests library (requires installation)

  2. Download data from https://api.github.com/users

  3. Model data as class User

  4. Iterate over records and create instances of this class

  5. Collect all instances to one list

Polish
  1. Użyj biblioteki requests (wymagana instalacja)

  2. Pobierz dane z https://api.github.com/users

  3. Zamodeluj dane za pomocą klasy User

  4. Iterując po rekordach twórz instancje tej klasy

  5. Zbierz wszystkie instancje do jednej listy

The whys and wherefores
  • Serializing nested data structures

  • Using stdlib json library

  • Serialize and deserialize nested objects

  • Model data from API