'How to create linked lists using pydantic so auto-completion doesn't break

I am trying to create a linked list using pydantic.

The following code works, but I can't get auto-completion to work. As you can see from the attached screenshot, the property 'next' doesn't show auto-completion.

How do I preserve the auto-comp

Update: I am working on Pycharm Professional 2020.3 + Python 3.10.2 + pydantic 1.9.0


Code

from pydantic import BaseModel
from pydantic.typing import ForwardRef

Node = ForwardRef('Node')


class Node(BaseModel):
    data: int
    next: Node = None


# Node.update_forward_refs()

def get_l1() -> Node:
    l1: Node = Node(data=1)
    l1.next = Node(data=2)
    l1.next.next = Node(data=3)

    return l1


l2: Node = get_l1()

print(l2)
print(l2.next)
print(l2.next.next)

Output

data=1 next=Node(data=2, next=Node(data=3, next=None))
data=2 next=Node(data=3, next=None)
data=3 next=None

Screenshot

l2.next does not show auto-completion



Solution 1:[1]

Do not use ForwardRef, use typing.Optional because you are assigning None to the node field and surround Node with quotes:

# Node = ForwardRef('Node')  <- Do not use this


class Node(BaseModel):
    data: int
    next: Optional["Node"] = None # <- Use typing.Optional and quotes here

About typing.Optional from the pydantic documentation:

typing.Optional

Optional[x] is simply short hand for Union[x, None];

About the usage of quotes in a type hint of a forward reference according to PEP 484:

When a type hint contains names that have not been defined yet, that definition may be expressed as a string literal, to be resolved later.

A situation where this occurs commonly is the definition of a container class, where the class being defined occurs in the signature of some of the methods. For example, the following code (the start of a simple binary tree implementation) does not work:

class Tree:
    def __init__(self, left: Tree, right: Tree):
        self.left = left
        self.right = right

To address this, we write:

class Tree:
    def __init__(self, left: 'Tree', right: 'Tree'):
        self.left = left
        self.right = right

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1