Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 52 additions & 18 deletions magicalapi/types/company_data.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from datetime import datetime
from datetime import date
from typing import TypeAlias

from pydantic import BaseModel, HttpUrl, field_validator
Expand All @@ -17,6 +18,51 @@ class Product(BaseModelValidated):
customers: list[URL]


class Employee(BaseModelValidated):
title: str | None
subtitle: str | None
link: str | None
image_url: URL | None


class SimilarCompany(BaseModelValidated):
title: str | None
subtitle: str | None
location: str | None
link: str | None


class Post(BaseModelValidated):
text: str | None

post_url: URL | None
post_id: str | None
time: str | None
videos: list[str]
images: list[str]
likes_count: int | None
comments_count: int | None


class Investor(BaseModelValidated):
name: str | None
link: str | None
image_url: URL | None


class FundingRound(BaseModelValidated):
date: date | None
type: str | None
raised_amount: str | None


class Funding(BaseModelValidated):
last_round: FundingRound | None
rounds_count: int | None
investors: list[Investor]
crunchbase_url: URL | None


class Company(BaseModelValidated):
"""
The main type of company data service
Expand All @@ -41,8 +87,13 @@ class Company(BaseModelValidated):
foundedOn: str | None
specialties: str | None
#
locations: list[list[str]]
products: list[Product]
locations: list[list[str]]
#
employees_at_linkedin: list[Employee]
similar_companies: list[SimilarCompany]
funding: Funding
posts: list[Post]

@field_validator("crawled_at", mode="before")
@classmethod
Expand All @@ -52,20 +103,3 @@ def datetime_validator(cls, value: str) -> datetime:

class CompanyDataResponse(BaseResponse):
data: Company


class Language(BaseModel):
name: str
code: str


class Country(Language):
pass


class LanguagesResponse(BaseResponse):
data: list[Language]


class CountriesResponse(BaseResponse):
data: list[Country]
30 changes: 27 additions & 3 deletions magicalapi/types/profile_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

class StartEndDate(BaseModelValidated):
# Example: "Jan 2024" or "2024-01" or "Present"
start_date: str | None
end_date: str | None
start_date: int | str | None
end_date: int | str | None

# validating the dates in format %b %Y ,Example : Jan 2024
# @field_validator("start_date", "end_date", mode="before")
Expand Down Expand Up @@ -52,7 +52,7 @@ class StartEndDateEducation(StartEndDate):
# raise e


class Duration(BaseModel):
class Duration(BaseModelValidated):
years: int = 0
months: int

Expand Down Expand Up @@ -143,6 +143,26 @@ def date_validator(cls, value: str) -> date | None:
return datetime.strptime(value, "%b %Y").date()


class Activity(BaseModelValidated):
title: str | None
subtitle: str | None
image_url: str | None
link: str | None


class SimilarProfile(BaseModelValidated):
url: str | None
name: str | None
title: str | None
image_url: str | None


class Patent(BaseModelValidated):
title: str | None
patent_id: str | None
link: str | None


class Profile(BaseModelValidated):
"""
The main type of linkedin profile data service
Expand All @@ -166,6 +186,10 @@ class Profile(BaseModelValidated):
courses: list[Course]
honors_and_awards: list[HonorAndAward]

activities: list[Activity]
similar_profiles: list[SimilarProfile]
patents: list[Patent]

@field_validator("crawled_at", mode="before")
@classmethod
def datetime_validator(cls, value: str) -> datetime:
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "magicalapi"
version = "1.3.0"
version = "1.4.0"
description = "This is a Python client that provides easy access to the MagicalAPI.com services, fully type annotated, and asynchronous."
authors = [
{ name = "MagicalAPI", email = "info@magicalapi.com" }
Expand Down
53 changes: 53 additions & 0 deletions tests/types/test_company_data_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,59 @@ def company_data():
"customers": [fake.uri()],
}
],
#
"employees_at_linkedin": [
{
"title": fake.job(),
"subtitle": fake.text(max_nb_chars=30),
"link": f"https://linkedin.com/in/{fake.user_name()}/",
"image_url": fake.image_url(),
}
for _ in range(randint(1, 5))
],
"similar_companies": [
{
"title": fake.company(),
"subtitle": fake.text(max_nb_chars=50),
"location": fake.city(),
"link": f"https://linkedin.com/company/{fake.slug()}/",
}
for _ in range(randint(1, 3))
],
"funding": {
"last_round": {
"date": fake.date_between(
start_date="-5y", end_date="today"
).isoformat(),
"type": fake.random_element(
elements=("Seed", "Series A", "Series B", "Series C", "IPO")
),
"raised_amount": f"${randint(1, 100)}M",
},
"rounds_count": randint(1, 5),
"investors": [
{
"name": fake.company(),
"link": f"https://linkedin.com/company/{fake.slug()}/",
"image_url": fake.image_url(),
}
for _ in range(randint(1, 4))
],
"crunchbase_url": f"https://crunchbase.com/organization/{fake.slug()}",
},
"posts": [
{
"text": fake.text(max_nb_chars=200),
"post_url": f"https://linkedin.com/posts/{fake.user_name()}_{fake.uuid4()}",
"post_id": fake.uuid4(),
"time": fake.date_time_this_month().strftime("%Y-%m-%d %H:%M:%S"),
"videos": [fake.url() for _ in range(randint(0, 2))],
"images": [fake.image_url() for _ in range(randint(0, 3))],
"likes_count": randint(0, 1000),
"comments_count": randint(0, 100),
}
for _ in range(randint(1, 3))
],
}

yield company
Expand Down
51 changes: 39 additions & 12 deletions tests/types/test_profile_data_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@


@pytest.fixture()
def profile_dataprofile_data():
def profile_data():
# create a sample profile data dictionary
fake = Faker(locale="en_US")
_username = fake.user_name()
Expand Down Expand Up @@ -188,31 +188,58 @@ def profile_dataprofile_data():
"description": "",
},
],
#
"activities": [
{
"title": fake.text(max_nb_chars=50),
"subtitle": fake.text(max_nb_chars=30),
"image_url": fake.image_url(),
"link": fake.uri(),
}
for _ in range(randint(1, 3))
],
"similar_profiles": [
{
"url": f"https://linkedin.com/in/{fake.user_name()}/",
"name": fake.name(),
"title": fake.job(),
"image_url": fake.image_url(),
}
for _ in range(randint(1, 5))
],
"patents": [
{
"title": fake.text(max_nb_chars=100),
"patent_id": f"US{randint(1000000, 9999999)}",
"link": f"https://patents.google.com/patent/US{randint(1000000, 9999999)}",
}
for _ in range(randint(0, 2))
],
}

yield profile
del profile


@pytest.mark.dependency()
def test_profile_data_type(profile_dataprofile_data: dict[str, Any]):
def test_profile_data_type(profile_data: dict[str, Any]):
# check profile data validated successfull
try:
Profile.model_validate(profile_dataprofile_data)
Profile.model_validate(profile_data)
except ValidationError as exc:
assert False, "validating profile data failed : " + str(exc)


@pytest.mark.dependency()
def test_profile_data_type_failing(profile_dataprofile_data: dict[str, Any]):
def test_profile_data_type_failing(profile_data: dict[str, Any]):
# validating profile data must fail
profile_dataprofile_data["experience"][0]["date"]["start_date"] = "none"
del profile_dataprofile_data["education"][0]["date"]
del profile_dataprofile_data["projects"][0]["date"]["end_date"]
profile_dataprofile_data["publications"][0]["publication_date"] = 12
profile_dataprofile_data["honors_and_awards"][0]["issued_date"] = None
profile_data["experience"][0]["date"]["start_date"] = "none"
del profile_data["education"][0]["date"]
del profile_data["projects"][0]["date"]["end_date"]
profile_data["publications"][0]["publication_date"] = 12
profile_data["honors_and_awards"][0]["issued_date"] = None
try:
Profile.model_validate(profile_dataprofile_data)
Profile.model_validate(profile_data)
except:
pass
else:
Expand All @@ -223,10 +250,10 @@ def test_profile_data_type_failing(profile_dataprofile_data: dict[str, Any]):
@pytest.mark.dependency(
depends=["test_profile_data_type", "test_profile_data_type_failing"]
)
def test_profile_data_response_type(profile_dataprofile_data: dict[str, Any]):
def test_profile_data_response_type(profile_data: dict[str, Any]):
try:
response_schema = {
"data": profile_dataprofile_data,
"data": profile_data,
"usage": {"credits": randint(1, 200)},
}
ProfileDataResponse.model_validate(response_schema)
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.