Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

New Relic NerdGraph Schema to Notebooks

Imports

Python modules

import ast
import itertools
import json
import os
import re
from datetime import datetime
from io import StringIO
from zoneinfo import ZoneInfo

Third-party modules

import nbformat as nbf
from sgqlc.codegen.schema import CodeGen

Download and save schema

Download schema from New Relic API using sgqlc.introspection

%%bash
config_line="$(cat ../../.env | grep NEW_RELIC_USER_KEY)"
new_relic_user_key="${config_line##*=}"
uv run python3 \
    -m sgqlc.introspection \
    --exclude-deprecated \
    -H "api-key: ${new_relic_user_key}" \
    https://api.newrelic.com/graphql \
    nerdgraph-schema.json

Read saved schema

Read the downloaded schema file

file_name = "./nerdgraph-schema.json"
with open(file_name, encoding="utf-8") as file_handler:
    file_contents = file_handler.read()

Load schema file contents into python dictionary and doing basig exploration over first level keys

schema = json.loads(file_contents)
headers = schema["headers"] if "headers" in schema else {}
schema = schema["data"] if "data" in schema else schema

Schema introspection

notebooks
├── GraphQL
.   ├── GraphQL.ipynb
.   ├── Scalars.ipynb
.   ├── Enums.ipynb
    ├── Objects.ipynb
    └── Input Objects.ipynb

Load schema into generator

Prepare text handler

cell_content_handler = StringIO()

Load Schema into code generator

generator = CodeGen("nerdgraph", schema["__schema"], cell_content_handler.write, True)

Prepare directory strcuture

dir_name = "../GraphQL"

if not os.path.exists(dir_name):
    os.makedirs(dir_name)

Writing notebooks

library_kind_map = {
    "ENUM": "newrelic_sb_sdk.graphql.enums",
    "INPUT_OBJECT": "newrelic_sb_sdk.graphql.input_objects",
    "INTERFACE": "newrelic_sb_sdk.graphql.objects",
    "OBJECT": "newrelic_sb_sdk.graphql.objects",
    "SCALAR": "newrelic_sb_sdk.graphql.scalars",
    "UNION": "newrelic_sb_sdk.graphql.objects",
}

Write notebook for __init__.py file.

notebook_name = "GraphQL.ipynb"
notebook_path = os.path.join(dir_name, notebook_name)
notebook_object = nbf.v4.new_notebook(
    metadata={
        "language_info": {
            "mimetype": "text/x-python",
            "name": "python",
        },
    },
)
notebook_object["cells"] = []
cell_content = """# | default_exp graphql.__init__"""
metadata = {
    "tags": [
        "remove-cell",
    ],
}
cell = nbf.v4.new_code_cell(cell_content, metadata=metadata)
notebook_object["cells"].append(cell)
cell_content = """
# | export
# pylint: disable=duplicate-code,unused-import,too-many-lines
""".strip()
metadata = {
    "tags": [
        "remove-cell",
    ],
}
cell = nbf.v4.new_code_cell(cell_content, metadata=metadata)
notebook_object["cells"].append(cell)
cell_content = """# NerdGraph GraphQL Specs"""
metadata = {
    "tags": [
        "remove-cell",
    ],
}
cell = nbf.v4.new_markdown_cell(cell_content, metadata=metadata)
notebook_object["cells"].append(cell)
cell_content = """## Imports"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """Third-party modules"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """# | export
import sgqlc.types
import sgqlc.types.datetime
""".strip()

cell = nbf.v4.new_code_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """# | export
nerdgraph = sgqlc.types.Schema()
""".strip()

cell = nbf.v4.new_code_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """## Definitions"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """### Constants"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """# | export
__docformat__ = "markdown"
""".strip()

cell = nbf.v4.new_code_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = f"""# | export
__schema_extraction_date__ = "{headers["Date"]}"
""".strip()

cell = nbf.v4.new_code_cell(cell_content)
notebook_object["cells"].append(cell)
with open(notebook_path, mode="w", encoding="utf-8") as notebook_handler:
    nbf.write(notebook_object, notebook_handler)
notebook_name = "Scalars.ipynb"
notebook_path = os.path.join(dir_name, notebook_name)
notebook_object = nbf.v4.new_notebook(
    metadata={
        "language_info": {
            "mimetype": "text/x-python",
            "name": "python",
        },
    },
)
notebook_object["cells"] = []
cell_content = """# | default_exp graphql.scalars"""
metadata = {
    "tags": [
        "remove-cell",
    ],
}
cell = nbf.v4.new_code_cell(cell_content, metadata=metadata)
notebook_object["cells"].append(cell)
cell_content = """
# | export
# pylint: disable=duplicate-code,unused-import,too-many-lines
""".strip()
metadata = {
    "tags": [
        "remove-cell",
    ],
}
cell = nbf.v4.new_code_cell(cell_content, metadata=metadata)
notebook_object["cells"].append(cell)
cell_content = """# NerdGraph Scalar Types"""
metadata = {
    "tags": [
        "remove-cell",
    ],
}
cell = nbf.v4.new_markdown_cell(cell_content, metadata=metadata)
notebook_object["cells"].append(cell)
cell_content = """## Imports"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """Third-party modules"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """# | export
import sgqlc.types
import sgqlc.types.datetime
""".strip()

cell = nbf.v4.new_code_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """# | export
from newrelic_sb_sdk.graphql import nerdgraph
""".strip()

cell = nbf.v4.new_code_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """## Definitions"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """# | export
__docformat__ = "markdown"
""".strip()

cell = nbf.v4.new_code_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """### Scalar types"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
KIND = "SCALAR"
types = [type_ for type_ in generator.types if type_["kind"] == KIND]

docstring_regex = re.compile(r"( +'''[\s\w!()*:`]+''')\n")
docstring_replace = ""

for i, type_ in enumerate(types, 1):
    title_cell_content = f"""#### {i}. `{type_["name"]}`"""
    title_cell = nbf.v4.new_markdown_cell(title_cell_content)
    notebook_object["cells"].append(title_cell)

    description_cell_content = (type_.get("description", "") or "").strip()

    if description_cell_content:
        description_cell = nbf.v4.new_markdown_cell(description_cell_content)
        notebook_object["cells"].append(description_cell)

    if "description" in type_:
        del type_["description"]

    cell_content_handler.seek(0)
    cell_content_handler.truncate(0)
    generator.write_type_scalar(type_)

    cell_content_handler.seek(0)
    cell_content = cell_content_handler.read().strip()
    cell_content = re.sub(docstring_regex, docstring_replace, cell_content)
    cell_content = cell_content.split("\n")
    declaration, *definition = cell_content

    if "= sgqlc." in declaration or "__schema__" in declaration:
        cell_content = declaration
    else:
        cell_content = "\n".join(cell_content)

    cell_content = "\n".join(["""# | export""", cell_content])
    cell = nbf.v4.new_code_cell(cell_content)

    notebook_object["cells"].append(cell)
with open(notebook_path, mode="w", encoding="utf-8") as notebook_handler:
    nbf.write(notebook_object, notebook_handler)

Write notebook for enums.py file.

notebook_name = "Enums.ipynb"
notebook_path = os.path.join(dir_name, notebook_name)
notebook_object = nbf.v4.new_notebook(
    metadata={
        "language_info": {
            "mimetype": "text/x-python",
            "name": "python",
        },
    },
)
notebook_object["cells"] = []
cell_content = """# | default_exp graphql.enums"""
metadata = {
    "tags": [
        "remove-cell",
    ],
}
cell = nbf.v4.new_code_cell(cell_content, metadata=metadata)
notebook_object["cells"].append(cell)
cell_content = """
# | export
# pylint: disable=duplicate-code,unused-import,too-many-lines
""".strip()
metadata = {
    "tags": [
        "remove-cell",
    ],
}
cell = nbf.v4.new_code_cell(cell_content, metadata=metadata)
notebook_object["cells"].append(cell)
cell_content = """# NerdGraph Enum Types"""
metadata = {
    "tags": [
        "remove-cell",
    ],
}
cell = nbf.v4.new_markdown_cell(cell_content, metadata=metadata)
notebook_object["cells"].append(cell)
cell_content = """## Imports"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """Third-party modules"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """# | export
import sgqlc.types
import sgqlc.types.datetime
""".strip()

cell = nbf.v4.new_code_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """`newrelic_sb_sdk` module"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """# | export
from newrelic_sb_sdk.graphql import nerdgraph
""".strip()

cell = nbf.v4.new_code_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """## Definitions"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """### Constants"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """# | export
__docformat__ = "markdown"
""".strip()

cell = nbf.v4.new_code_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """### Enum types"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
KIND = "ENUM"
types = [type_ for type_ in generator.types if type_["kind"] == KIND]

docstring_regex = re.compile(r"( +'''[\s\w!()*:`]+''')\n")
docstring_replace = ""

for i, type_ in enumerate(types, 1):
    title_cell_content = f"""#### {i}. `{type_["name"]}`"""
    title_cell = nbf.v4.new_markdown_cell(title_cell_content)
    notebook_object["cells"].append(title_cell)

    description_cell_content = (type_.get("description", "") or "").strip()

    enum_value_description_content = ""
    for j, enum_value in enumerate(type_["enumValues"]):
        enum_value_name = enum_value["name"]
        enum_value_description = (enum_value.get("description", "") or "").strip()
        enum_value_description_content = "\n".join(
            [
                enum_value_description_content,
                f"* `{enum_value_name}` {':' if enum_value_description else ''} {enum_value_description}".strip(),
            ]
        )
        if "description" in type_["enumValues"][j]:
            del type_["enumValues"][j]["description"]

    description_cell_content = "\n".join(
        [
            description_cell_content,
            "\n",
            "Available choices:",
            "\n",
            enum_value_description_content,
        ]
    ).strip()

    if description_cell_content:
        description_cell = nbf.v4.new_markdown_cell(description_cell_content)
        notebook_object["cells"].append(description_cell)

    if "description" in type_:
        del type_["description"]

    cell_content_handler.seek(0)
    cell_content_handler.truncate(0)
    generator.write_type_enum(type_)

    cell_content_handler.seek(0)
    cell_content = cell_content_handler.read().strip()
    cell_content = re.sub(docstring_regex, docstring_replace, cell_content)
    cell_content = cell_content.split("\n")
    declaration, *definition = cell_content

    if "= sgqlc." in declaration or "__schema__" in declaration:
        cell_content = declaration
    else:
        cell_content = "\n".join(cell_content)

    cell_content = "\n".join(["""# | export""", cell_content])
    cell = nbf.v4.new_code_cell(cell_content)

    notebook_object["cells"].append(cell)
with open(notebook_path, mode="w", encoding="utf-8") as notebook_handler:
    nbf.write(notebook_object, notebook_handler)

Write notebook for input_objects.py file.

notebook_name = "Input Objects.ipynb"
notebook_path = os.path.join(dir_name, notebook_name)
notebook_object = nbf.v4.new_notebook(
    metadata={
        "language_info": {
            "mimetype": "text/x-python",
            "name": "python",
        },
    },
)
notebook_object["cells"] = []
cell_content = """# | default_exp graphql.input_objects"""
metadata = {
    "tags": [
        "remove-cell",
    ],
}
cell = nbf.v4.new_code_cell(cell_content, metadata=metadata)
notebook_object["cells"].append(cell)
cell_content = """
# | export
# pylint: disable=duplicate-code,unused-import,too-many-lines,disallowed-name
""".strip()
metadata = {
    "tags": [
        "remove-cell",
    ],
}
cell = nbf.v4.new_code_cell(cell_content, metadata=metadata)
notebook_object["cells"].append(cell)
cell_content = """# NerdGraph Input Object Types"""
metadata = {
    "tags": [
        "remove-cell",
    ],
}
cell = nbf.v4.new_markdown_cell(cell_content, metadata=metadata)
notebook_object["cells"].append(cell)
cell_content = """## Imports"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """Third-party modules"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """# | export
import sgqlc.types
import sgqlc.types.datetime
""".strip()

cell = nbf.v4.new_code_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """`newrelic_sb_sdk` module"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """# | export
from newrelic_sb_sdk.graphql import nerdgraph
""".strip()

cell = nbf.v4.new_code_cell(cell_content)
notebook_object["cells"].append(cell)
KIND = "INPUT_OBJECT"
types = [type_ for type_ in generator.types if type_["kind"] == KIND]
imports_map = {}

related_types = list(itertools.chain(*[type_["inputFields"] for type_ in types]))
related_types = {
    (
        (type_["type"]["kind"], type_["type"]["name"])
        if type_["type"]["kind"] in library_kind_map
        else (
            (type_["type"]["ofType"]["kind"], type_["type"]["ofType"]["name"])
            if type_["type"]["ofType"]["kind"] in library_kind_map
            else (
                (
                    type_["type"]["ofType"]["ofType"]["kind"],
                    type_["type"]["ofType"]["ofType"]["name"],
                )
                if type_["type"]["ofType"]["ofType"]["kind"] in library_kind_map
                else (
                    type_["type"]["ofType"]["ofType"]["ofType"]["kind"],
                    type_["type"]["ofType"]["ofType"]["ofType"]["name"],
                )
            )
        )
    )
    for type_ in related_types
}
related_types = {
    (kind, name)
    for kind, name in related_types
    if name
    not in list(
        itertools.chain(
            generator.builtin_enum_names,
            generator.builtin_object_names,
        )
    )
}

for kind, name in related_types:
    if kind in library_kind_map:
        library = library_kind_map[kind]

        if library not in imports_map:
            imports_map[library] = []

        imports_map[library].append(name)

imports_map = {key: sorted(set(value)) for key, value in imports_map.items()}

if "newrelic_sb_sdk.graphql.input_objects" in imports_map:
    del imports_map["newrelic_sb_sdk.graphql.input_objects"]
for sub_module in imports_map:
    cell_content = """# | export"""
    cell_content = "\n".join([cell_content, f"from {sub_module} import ("])
    cell_content = "\n".join(
        [
            cell_content,
            *[f"    {type_}," for type_ in imports_map[sub_module]],
        ]
    )
    cell_content = "\n".join([cell_content, ")"])

    cell = nbf.v4.new_code_cell(cell_content)
    notebook_object["cells"].append(cell)
cell_content = """## Definitions"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """### Constants"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """# | export
__docformat__ = "markdown"
""".strip()

cell = nbf.v4.new_code_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """### Input object types"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
docstring_regex = re.compile(r"( +'''[\s\w!()*:`]+''')\n")
docstring_replace = ""

for i, type_ in enumerate(types, 1):
    title_cell_content = f"""#### {i}. `{type_["name"]}`"""
    title_cell = nbf.v4.new_markdown_cell(title_cell_content)
    notebook_object["cells"].append(title_cell)

    description_cell_content = (type_.get("description", "") or "").strip()

    input_field_description_content = ""

    for j, input_field in enumerate(type_["inputFields"]):
        input_field_name = input_field["name"]
        input_field_description = (input_field.get("description", "") or "").strip()
        input_field_description_content = "\n".join(
            [
                input_field_description_content,
                f"* `{input_field_name}` {':' if input_field_description else ''} {input_field_description}".strip(),
            ]
        )
        if "description" in type_["inputFields"][j]:
            del type_["inputFields"][j]["description"]

    description_cell_content = "\n".join(
        [
            description_cell_content,
            "\n",
            "Available input fields:",
            "\n",
            input_field_description_content,
        ]
    ).strip()

    if description_cell_content:
        description_cell = nbf.v4.new_markdown_cell(description_cell_content)
        notebook_object["cells"].append(description_cell)

    if "description" in type_:
        del type_["description"]

    cell_content_handler.seek(0)
    cell_content_handler.truncate(0)
    generator.write_type_input_object(type_)

    cell_content_handler.seek(0)
    cell_content = cell_content_handler.read().strip()
    cell_content = re.sub(docstring_regex, docstring_replace, cell_content)
    cell_content = cell_content.split("\n")
    declaration, *definition = cell_content

    if "= sgqlc." in declaration or "__schema__" in declaration:
        cell_content = declaration
    else:
        cell_content = "\n".join(cell_content)

    cell_content = "\n".join(["""# | export""", cell_content])
    cell = nbf.v4.new_code_cell(cell_content)

    notebook_object["cells"].append(cell)
with open(notebook_path, mode="w", encoding="utf-8") as notebook_handler:
    nbf.write(notebook_object, notebook_handler)

Write notebook for objects.py file.

notebook_name = "Objects.ipynb"
notebook_path = os.path.join(dir_name, notebook_name)
notebook_object = nbf.v4.new_notebook(
    metadata={
        "language_info": {
            "mimetype": "text/x-python",
            "name": "python",
        },
    },
)
notebook_object["cells"] = []
cell_content = """# | default_exp graphql.objects"""
metadata = {
    "tags": [
        "remove-cell",
    ],
}
cell = nbf.v4.new_code_cell(cell_content, metadata=metadata)
notebook_object["cells"].append(cell)
cell_content = """
# | export
# pylint: disable=duplicate-code,unused-import,too-many-lines,disallowed-name
""".strip()
metadata = {
    "tags": [
        "remove-cell",
    ],
}
cell = nbf.v4.new_code_cell(cell_content, metadata=metadata)
notebook_object["cells"].append(cell)
cell_content = """# NerdGraph Object Types""".strip()
metadata = {
    "tags": [
        "remove-cell",
    ],
}
cell = nbf.v4.new_markdown_cell(cell_content, metadata=metadata)
notebook_object["cells"].append(cell)
cell_content = """## Imports"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """Third-party modules"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """# | export
import sgqlc.types
import sgqlc.types.datetime
""".strip()

cell = nbf.v4.new_code_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """`newrelic_sb_sdk` module"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """# | export
from newrelic_sb_sdk.graphql import nerdgraph
""".strip()

cell = nbf.v4.new_code_cell(cell_content)
notebook_object["cells"].append(cell)
KINDS = ["OBJECT", "INTERFACE"]
types = [type_ for type_ in generator.types if type_["kind"] in KINDS]

types.sort(key=generator.get_depend_sort_key())
imports_map = {}

related_types = list(itertools.chain(*[type_["fields"] for type_ in types]))
related_types = list(
    itertools.chain(*[type_["args"] for type_ in related_types], related_types)
)

related_types = {
    (
        (type_["type"]["kind"], type_["type"]["name"])
        if type_["type"]["kind"] in library_kind_map
        else (
            (type_["type"]["ofType"]["kind"], type_["type"]["ofType"]["name"])
            if type_["type"]["ofType"]["kind"] in library_kind_map
            else (
                (
                    type_["type"]["ofType"]["ofType"]["kind"],
                    type_["type"]["ofType"]["ofType"]["name"],
                )
                if type_["type"]["ofType"]["ofType"]["kind"] in library_kind_map
                else (
                    type_["type"]["ofType"]["ofType"]["ofType"]["kind"],
                    type_["type"]["ofType"]["ofType"]["ofType"]["name"],
                )
            )
        )
    )
    for type_ in related_types
}
related_types = {
    (kind, name)
    for kind, name in related_types
    if name
    not in list(
        itertools.chain(
            generator.builtin_enum_names,
            generator.builtin_object_names,
        )
    )
}

for kind, name in related_types:
    if kind in library_kind_map:
        library = library_kind_map[kind]

        if library not in imports_map:
            imports_map[library] = []

        imports_map[library].append(name)

imports_map = {key: sorted(set(value)) for key, value in imports_map.items()}

if "newrelic_sb_sdk.graphql.objects" in imports_map:
    del imports_map["newrelic_sb_sdk.graphql.objects"]
for sub_module in imports_map:
    cell_content = """# | export"""
    cell_content = "\n".join([cell_content, f"from {sub_module} import ("])
    cell_content = "\n".join(
        [
            cell_content,
            *[f"    {type_}," for type_ in imports_map[sub_module]],
        ]
    )
    cell_content = "\n".join([cell_content, ")"])

    cell = nbf.v4.new_code_cell(cell_content)
    notebook_object["cells"].append(cell)
cell_content = """## Definitions"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """### Constants"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """# | export
__docformat__ = "markdown"
""".strip()

cell = nbf.v4.new_code_cell(cell_content)
notebook_object["cells"].append(cell)
cell_content = """### Interface types"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
KIND = "INTERFACE"
interface_types = [type_ for type_ in types if type_["kind"] == KIND]

docstring_regex = re.compile(r"( +'''[\s\w!()*:`]+''')\n")
docstring_replace = ""

markdown_title_regex = re.compile(r"#+")
markdown_title_replace = "####"

for i, type_ in enumerate(interface_types, 1):
    title_cell_content = f"""#### {i}. `{type_["name"]}`"""
    title_cell = nbf.v4.new_markdown_cell(title_cell_content)
    notebook_object["cells"].append(title_cell)

    description_cell_content = (type_.get("description", "") or "").strip()

    field_description_content = ""

    for j, field in enumerate(type_["fields"]):
        field_name = field["name"]
        field_description = (field.get("description", "") or "").strip()
        field_description_content = "\n".join(
            [
                field_description_content,
                f"* `{field_name}` {':' if field_description else ''} {field_description}".strip(),
            ]
        )

        if "description" in type_["fields"][j]:
            del type_["fields"][j]["description"]

    description_cell_content = "\n".join(
        [
            description_cell_content,
            "\n",
            "Available fields:",
            "\n",
            field_description_content,
        ]
    ).strip()

    if description_cell_content:
        description_cell_content = re.sub(
            markdown_title_regex, markdown_title_replace, description_cell_content
        )
        description_cell = nbf.v4.new_markdown_cell(description_cell_content)
        notebook_object["cells"].append(description_cell)

    if "description" in type_:
        del type_["description"]

    cell_content_handler.seek(0)
    cell_content_handler.truncate(0)
    generator.write_type_interface(type_)

    cell_content_handler.seek(0)
    cell_content = cell_content_handler.read().strip()
    cell_content = re.sub(docstring_regex, docstring_replace, cell_content)
    cell_content = cell_content.split("\n")
    declaration, *definition = cell_content

    if "= sgqlc." in declaration or "__schema__" in declaration:
        cell_content = declaration
    else:
        cell_content = "\n".join(cell_content)

    cell_content = "\n".join(["""# | export""", cell_content])
    cell = nbf.v4.new_code_cell(cell_content)

    notebook_object["cells"].append(cell)
cell_content = """### Object types"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
KIND = "OBJECT"
object_types = [type_ for type_ in types if type_["kind"] == KIND]

docstring_regex = re.compile(r"('''[\s\w!()*:`]+''')\n")
docstring_replace = ""

for i, type_ in enumerate(object_types, 1):
    title_cell_content = f"""#### {i}. `{type_["name"]}`"""
    title_cell = nbf.v4.new_markdown_cell(title_cell_content)
    notebook_object["cells"].append(title_cell)

    description_cell_content = (type_.get("description", "") or "").strip()

    field_description_content = ""

    for j, field in enumerate(type_["fields"]):
        field_name = field["name"]
        field_description = (field.get("description", "") or "").strip()
        field_description_content = "\n".join(
            [
                field_description_content,
                f"* `{field_name}` {':' if field_description else ''} {field_description}".strip(),
            ]
        )
        if "description" in type_["fields"][j]:
            del type_["fields"][j]["description"]

    description_cell_content = "\n".join(
        [
            description_cell_content,
            "\n",
            "Available fields:",
            "\n",
            field_description_content,
        ]
    ).strip()

    if description_cell_content:
        description_cell = nbf.v4.new_markdown_cell(description_cell_content)
        notebook_object["cells"].append(description_cell)

    if "description" in type_:
        del type_["description"]

    cell_content_handler.seek(0)
    cell_content_handler.truncate(0)
    generator.write_type_object(type_)

    cell_content_handler.seek(0)
    cell_content = cell_content_handler.read().strip()
    cell_content = re.sub(docstring_regex, docstring_replace, cell_content)
    cell_content = cell_content.split("\n")
    declaration, *definition = cell_content

    if "= sgqlc." in declaration or "__schema__" in declaration:
        cell_content = declaration
    else:
        cell_content = "\n".join(cell_content)

    cell_content = "\n".join(["""# | export""", cell_content])
    cell = nbf.v4.new_code_cell(cell_content)

    notebook_object["cells"].append(cell)
cell_content = """### Union types"""
cell = nbf.v4.new_markdown_cell(cell_content)
notebook_object["cells"].append(cell)
KIND = "UNION"
union_types = [type_ for type_ in generator.types if type_["kind"] == KIND]

docstring_regex = re.compile(r"('''[\s\w!()*:`]+''')\n")
docstring_replace = ""

for i, type_ in enumerate(union_types, 1):
    title_cell_content = f"""#### {i}. `{type_["name"]}`"""
    title_cell = nbf.v4.new_markdown_cell(title_cell_content)
    notebook_object["cells"].append(title_cell)

    description_cell_content = (type_.get("description", "") or "").strip()

    if description_cell_content:
        description_cell = nbf.v4.new_markdown_cell(description_cell_content)
        notebook_object["cells"].append(description_cell)

    if "description" in type_:
        del type_["description"]

    if "possibleTypes" not in type_:
        type_["possibleTypes"] = []

    if type_["possibleTypes"] is None:
        type_["possibleTypes"] = []

    cell_content_handler.seek(0)
    cell_content_handler.truncate(0)
    generator.write_type_union(type_)

    cell_content_handler.seek(0)
    cell_content = cell_content_handler.read().strip()
    cell_content = re.sub(docstring_regex, docstring_replace, cell_content)
    cell_content = cell_content.split("\n")
    declaration, *definition = cell_content

    if "= sgqlc." in declaration or "__schema__" in declaration:
        cell_content = declaration
    else:
        cell_content = "\n".join(cell_content)

    cell_content = "\n".join(["""# | export""", cell_content])
    cell = nbf.v4.new_code_cell(cell_content)

    notebook_object["cells"].append(cell)
with open(notebook_path, mode="w", encoding="utf-8") as notebook_handler:
    nbf.write(notebook_object, notebook_handler)