You've pretty much answered it yourself. Unless there's something more to the question.
from typing import Optional
from pydantic import BaseModel
class ProjectCreateObject(BaseModel):
    project_id: str
    project_name: str
    project_type: str
    depot: str
    system: str
class ProjectPatchObject(ProjectCreateObject):
    project_name: Optional[str]
    project_type: Optional[str]
    depot: Optional[str]
    system: Optional[str]
if __name__ == "__main__":
    p = ProjectCreateObject(
        project_id="id",
        project_name="name",
        project_type="type",
        depot="depot",
        system="system",
    )
    print(p)
    c = ProjectPatchObject(project_id="id", depot="newdepot")
    print(c)
Running this gives:
project_id='id' project_name='name' project_type='type' depot='depot' system='system'
project_id='id' project_name=None project_type=None depot='newdepot' system=None
Another way to look at it is to define the base as optional and then create a validator to check when all required:
from pydantic import BaseModel, root_validator, MissingError
class ProjectPatchObject(BaseModel):
    project_id: str
    project_name: Optional[str]
    project_type: Optional[str]
    depot: Optional[str]
    system: Optional[str]
class ProjectCreateObject(ProjectPatchObject):
    @root_validator
    def check(cls, values):
        for k, v in values.items():
            if v is None:
                raise MissingError()
        return values