Let's say I have two classes Base and Child with a factory method in Base. The factory method calls another classmethod which may be overriden by Base's child classes.
class Base(object):
    @classmethod
    def create(cls, *args: Tuple) -> 'Base':
        value = cls._prepare(*args)
        return cls(value)
    @classmethod
    def _prepare(cls, *args: Tuple) -> Any:
        return args[0] if args else None
    def __init__(self, value: Any) -> None:
        self.value = value
class Child(Base):
    @classmethod
    def _prepare(cls, *args: Tuple) -> Any:
        return args[1] if len(args) > 1 else None
    def method_not_present_on_base(self) -> None:
        pass
Is there a way to annotate Base.create so that a static type checker could infer that Base.create() returned an instance of Base and Child.create() returned an instance of Child, so that the following example would pass static analysis?
base = Base.create(1)
child = Child.create(2, 3)
child.method_not_present_on_base()
In the above example a static type checker would rightfully complain that the method_not_present_on_base is, well, not present on the Base class.
I thought about turning Base into a generic class and having the child classes specify themselves as type arguments, i.e. bringing the CRTP to Python.
T = TypeVar('T')
class Base(Generic[T]):
    @classmethod
    def create(cls, *args: Tuple) -> T: ...
class Child(Base['Child']): ...
But this feels rather unpythonic with CRTP coming from C++ and all...
                        
It is indeed possible: the feature is called TypeVar with Generic Self (though this is slightly misleading because we're using this for a class method in this case). I believe it behaves roughly equivalently to the "CRTP" technique you linked to (though I'm not a C++ expert so can't say for certain).
In any case, you would declare your base and child classes like so:
Note that:
clsfor the child definition.