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 9.51. 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 9.52. 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 9.53. Serialize to JSON
import json


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

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

9.2.2.2. Deserialize from JSON

Listing 9.54. Deserialize from JSON
import json


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

result = json.loads(DATA)
print(result)
# {
#     '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 9.55. Exception during encoding datetime
from datetime import datetime, date
import json


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

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


DATA = {
    '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')


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

9.2.3.2. Decoding datetime and date

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


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

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


DATA = '{"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, result: dict) -> dict:
        for field, value in result.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)

            result[field] = value
        return result


result = json.loads(DATA, cls=JSONDatetimeDecoder)
print(result)
# {
#     '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 9.59. 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


result = json.dumps(CREW, cls=JSONObjectEncoder, sort_keys=True, indent=2)
print(result)
# [
#   {
#     "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 9.60. Encoding nested objects with relations to JSON
import json
import sys

DATA = """[{"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)


result = json.loads(DATA, cls=JSONObjectDecoder)
print(result)
# 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 9.61. Minified JSON file
$ DATA='https://raw.githubusercontent.com/AstroMatt/book-python/master/stdlib/serialization/data/iris.json'
$ curl $DATA
[{"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 9.62. Pretty Printing JSON
$ DATA='https://raw.githubusercontent.com/AstroMatt/book-python/master/stdlib/serialization/data/iris.json'
$ curl $DATA |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 9.63. 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. Use data from "Input" section (see below)

  2. Extract from input a header and data

  3. Create List[dict]

    • key: name from the header

    • value: measurement or species

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

  5. Compare result with "Output" section (see below)

Polish
  1. Użyj danych z sekcji "Input" (patrz poniżej)

  2. Z danych wydziel nagłówek i pomiary

  3. Wygeneruj List[dict]

    • klucz: nazwa z nagłówka

    • wartość: wyniki pomiarów lub gatunek

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

  5. Porównaj wyniki z sekcją "Output" (patrz poniżej)

The whys and wherefores
  • Serializing nested data structures

  • Using stdlib json library

  • Type casting

  • Working with files

Input
DATA = [
    ('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 9.64. Output
result: 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. Use data from "Input" section (see below)

  2. Save input data to "iris_deserialize.json" file

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

  4. First line must be a header

  5. Other lines must contain data

Polish
  1. Użyj danych z sekcji "Input" (patrz poniżej)

  2. Zapisz dane wejściowe do pliku "iris_deserialize.json"

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

  4. Pierwsza linijka ma zawierać nagłówek

  5. 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. Use data from "Input" section (see below)

  2. Save data to file in JSON format

  3. Read data from file

  4. Recreate data structure

Polish
  1. Użyj danych z sekcji "Input" (patrz poniżej)

  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


DATA = {
    "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. Use data from "Input" section (see below)

  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. Użyj danych z sekcji "Input" (patrz poniżej)

  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