|
|
from typing import Any, List |
|
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field, field_validator |
|
|
from pydantic.alias_generators import to_camel |
|
|
|
|
|
|
|
|
class BaseSchema(BaseModel): |
|
|
model_config = ConfigDict( |
|
|
alias_generator=to_camel, |
|
|
populate_by_name=True, |
|
|
from_attributes=True, |
|
|
) |
|
|
|
|
|
|
|
|
class DateComponent(BaseSchema): |
|
|
""" |
|
|
Represents a date component with year, month, and day. |
|
|
|
|
|
Attributes: |
|
|
year (int | None): The year component of the date. |
|
|
month (int | None): The month component of the date. Defaults to None. |
|
|
day (int | None): The day component of the date. Defaults to None. |
|
|
""" |
|
|
|
|
|
year: int | None = None |
|
|
month: int | None = None |
|
|
day: int | None = None |
|
|
model_config = {"frozen": True} |
|
|
|
|
|
@field_validator("year", "month", "day", mode="before") |
|
|
@classmethod |
|
|
def zero_to_none(cls, v: int | None) -> int | None: |
|
|
return None if v == 0 else v |
|
|
|
|
|
|
|
|
|
|
|
class StartEndMixin(BaseSchema): |
|
|
""" |
|
|
A mixin class for including start and end dates in other Pydantic models. |
|
|
This class is designed to be inherited by other classes that require start and end date attributes. |
|
|
""" |
|
|
|
|
|
start: DateComponent | None = None |
|
|
end: DateComponent | None = None |
|
|
|
|
|
@field_validator("start", "end", mode="before") |
|
|
@classmethod |
|
|
def validate_date(cls, v: dict[str, str] | DateComponent) -> dict[str, str] | DateComponent | None: |
|
|
if isinstance(v, DateComponent): |
|
|
return v |
|
|
if not v or v.get("year") is None: |
|
|
return None |
|
|
return v |
|
|
|
|
|
|
|
|
class Geo(BaseSchema): |
|
|
country: str | None = None |
|
|
city: str | None = None |
|
|
full: str | None = None |
|
|
|
|
|
|
|
|
class Language(BaseSchema): |
|
|
name: str | None = None |
|
|
proficiency: str | None = None |
|
|
|
|
|
|
|
|
class Education(StartEndMixin): |
|
|
field_of_study: str | None = None |
|
|
degree: str | None = None |
|
|
grade: str | None = None |
|
|
school_name: str | None = None |
|
|
description: str | None = None |
|
|
activities: str | None = None |
|
|
model_config = {"frozen": True} |
|
|
|
|
|
|
|
|
class Position(StartEndMixin): |
|
|
company_name: str | None = None |
|
|
company_username: str | None = None |
|
|
company_url: str | None = None |
|
|
company_industry: str | None = None |
|
|
company_description: str | None = None |
|
|
company_staff_count_range: str | None = None |
|
|
title: str | None = None |
|
|
location: str | None = None |
|
|
description: str | None = None |
|
|
employment_type: str | None = None |
|
|
model_config = {"frozen": True} |
|
|
|
|
|
|
|
|
class Skill(BaseSchema): |
|
|
name: str | None = None |
|
|
|
|
|
|
|
|
class Course(BaseSchema): |
|
|
name: str | None = None |
|
|
number: str | None = None |
|
|
|
|
|
|
|
|
class CertificationCompany(BaseSchema): |
|
|
name: str | None = None |
|
|
universal_name: str | None = None |
|
|
logo: str | None = None |
|
|
|
|
|
|
|
|
class Certification(StartEndMixin): |
|
|
name: str | None = None |
|
|
authority: str | None = None |
|
|
company: CertificationCompany | None = None |
|
|
time_period: StartEndMixin | None = None |
|
|
|
|
|
|
|
|
class LinkedinProfile(BaseSchema): |
|
|
""" |
|
|
Represents a comprehensive profile, encompassing various sections such as articles, |
|
|
accomplishments, experiences, education, certifications, courses, test scores, |
|
|
and more personal and professional details. |
|
|
""" |
|
|
|
|
|
first_name: str | None = None |
|
|
last_name: str | None = None |
|
|
is_open_to_work: bool | None = None |
|
|
is_hiring: bool | None = None |
|
|
profile_picture: str | None = None |
|
|
summary: str | None = None |
|
|
headline: str | None = None |
|
|
geo: Geo | None = None |
|
|
languages: List[Language] | None = [] |
|
|
educations: List[Education] = [] |
|
|
positions: List[Position] = Field(default=[], alias="position") |
|
|
full_positions: List[Position] = Field(default=[]) |
|
|
skills: List[Skill] | None = [] |
|
|
courses: List[Course] | None = [] |
|
|
certifications: List[Certification] | None = [] |
|
|
|
|
|
@staticmethod |
|
|
def profile_from_json(json: dict[str, Any]) -> "LinkedinProfile": |
|
|
""" |
|
|
Create a Profile instance from the given JSON data. |
|
|
|
|
|
:param json: The JSON data to create a Profile instance from. |
|
|
:return: A Profile instance created from the given JSON data. |
|
|
""" |
|
|
profile = LinkedinProfile.model_validate(json) |
|
|
profile.positions = profile.full_positions |
|
|
return profile |
|
|
|