diff --git a/README.md b/README.md index 32da93c..1c34095 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@
- Logo + Logo

MagicalAPI Python Client

@@ -34,8 +34,8 @@ - View Demo - · + + Report Bug · Request Feature @@ -75,7 +75,7 @@ ## What is [MagicalAPI][website-url]? -MagicalAPI is your AI edge in **content** and **careers**, Your ultimate tool for **YouTube SEO**, **Resume Parsing**, **LinkedIn data** and more. +MagicalAPI is your AI edge in **content** and **careers**, Your ultimate tool for **Resume Parsing**, **LinkedIn data** and more.
@@ -149,44 +149,43 @@ client = AsyncClinet()
-Here is an example of how to get keywords of [Youtube Top Keywords](https://magicalapi.com/services/youtube-keywords) service: +Here is an example of how to parse a resume using [Resume Parser](https://magicalapi.com/resume/) service: ```python import asyncio + from magicalapi.client import AsyncClient +from magicalapi.errors import APIServerError, APIServerTimedout from magicalapi.types.base import ErrorResponse -search_sentence = "chatgpt 4 turbo" # your search sentence to get keywords related to -country = "1" # use get_countries method to see countries codes (Default = 1 : WorlWide) -language = "1000" # use get_languages method to see countries codes (Default = 1000 : English) +resume_url = ( + "https://resume-resource.com/wp-content/uploads/00123-sales-professional-resume.pdf" +) +output_file_name = "resume_parser.json" async def main(): - # the api_key will load from the .env file - async with AsyncClient() as client: - # Get YouTube keywords - keywords_response = await client.youtube_top_keywords.get_keywords( - search_sentence=search_sentence, - country=country, - language=language, - ) - if type(keywords_response) == ErrorResponse: - # got error from API - print("Error :", keywords_response.message) - else: - # got response successfully - print("credits :", keywords_response.usage.credits) - print("keywords count :", len(keywords_response.data.keywords)) - - # save response in JSON file - with open("keywords_response.json", "w") as file: - file.write(keywords_response.model_dump_json(indent=3)) - - - # get languages list - # languages = await client.youtube_top_keywords.get_languages() - # get countries list - # countries = await client.youtube_top_keywords.get_countries() + try: + # the api_key will load from the .env file + async with AsyncClient() as client: + response = await client.resume_parser.get_resume_parser(url=resume_url) + + if isinstance(response, ErrorResponse): + # got error from api + print("Error :", response.message) + else: + # got response successfully + print("credists :", response.usage.credits) + # save response in json file + with open(output_file_name, "w") as file: + file.write(response.model_dump_json(indent=3)) + + print(f"response saved to {output_file_name}") + except (APIServerError, APIServerTimedout) as e: + # handling server errors + print(e) + except Exception as e: + print("An error occurred:", str(e)) asyncio.run(main()) diff --git a/docs/logo.jpg b/docs/logo.jpg deleted file mode 100644 index 949ca8a..0000000 Binary files a/docs/logo.jpg and /dev/null differ diff --git a/docs/logo.png b/docs/logo.png index e0f4c1c..66e2236 100644 Binary files a/docs/logo.png and b/docs/logo.png differ diff --git a/examples/youtube_seo.py b/examples/youtube_seo.py deleted file mode 100644 index 69eedee..0000000 --- a/examples/youtube_seo.py +++ /dev/null @@ -1,35 +0,0 @@ -import asyncio - -from magicalapi.client import AsyncClient -from magicalapi.errors import APIServerError, APIServerTimedout -from magicalapi.types.base import ErrorResponse - -video_url = "https://www.youtube.com/watch?v=PZZI1QXlM80" -output_file_name = "youtube_seo.json" - - -async def main(): - try: - # the api_key will load from the .env file - async with AsyncClient() as client: - response = await client.youtube_seo.get_youtube_seo(url=video_url) - - if isinstance(response, ErrorResponse): - # got error from api - print("Error :", response.message) - else: - # got response successfully - print("credists :", response.usage.credits) - # save response in json file - with open(output_file_name, "w") as file: - file.write(response.model_dump_json(indent=3)) - - print(f"response saved to {output_file_name}") - except (APIServerError, APIServerTimedout) as e: - # handling server errors - print(e) - except Exception as e: - print("An error occurred:", str(e)) - - -asyncio.run(main()) diff --git a/examples/youtube_suggestions.py b/examples/youtube_suggestions.py deleted file mode 100644 index 3dc7a94..0000000 --- a/examples/youtube_suggestions.py +++ /dev/null @@ -1,41 +0,0 @@ -import asyncio - -from magicalapi.client import AsyncClient -from magicalapi.errors import APIServerError, APIServerTimedout -from magicalapi.types.base import ErrorResponse - -prompt_sentence = "How to create a profitable Shopify store" -count = 5 -suggestion_goal = "hashtag" -output_file_name = "youtube_suggestions.json" - - -async def main(): - try: - # the api_key will load from the .env file - async with AsyncClient() as client: - response = await client.youtube_suggestions.get_youtube_suggestions( - prompt_sentence=prompt_sentence, - count=count, - suggestion_goal=suggestion_goal, - ) - - if isinstance(response, ErrorResponse): - # got error from api - print("Error :", response.message) - else: - # got response successfully - print("credists :", response.usage.credits) - # save response in json file - with open(output_file_name, "w") as file: - file.write(response.model_dump_json(indent=3)) - - print(f"response saved to {output_file_name}") - except (APIServerError, APIServerTimedout) as e: - # handling server errors - print(e) - except Exception as e: - print("An error occurred:", str(e)) - - -asyncio.run(main()) diff --git a/examples/youtube_top_keywords.py b/examples/youtube_top_keywords.py deleted file mode 100644 index 204a516..0000000 --- a/examples/youtube_top_keywords.py +++ /dev/null @@ -1,51 +0,0 @@ -import asyncio - -from magicalapi.client import AsyncClient -from magicalapi.errors import APIServerError, APIServerTimedout -from magicalapi.types.base import ErrorResponse - -search_sentence = "movie trailers" -country = "1" -language = "1000" -output_file_name = f"youtube_top_keywords_{search_sentence}.json" - - -async def main(): - try: - # the api_key will load from the .env file - async with AsyncClient() as client: - # get languages and countries list - # languages = await client.youtube_top_keywords.get_languages() - # countries = await client.youtube_top_keywords.get_countries() - # print("Languauges :") - # print(languages) - # print("Countries : ") - # print(countries) - - # get youtube keywords - response = await client.youtube_top_keywords.get_keywords( - search_sentence=search_sentence, - country=country, - language=language, - ) - if isinstance(response, ErrorResponse): - # got error from api - print("Error :", response.message) - else: - # got response successfully - print("credists :", response.usage.credits) - print("keywords count :", len(response.data.keywords)) - - # save response in json file - with open(output_file_name, "w") as file: - file.write(response.model_dump_json(indent=3)) - - print(f"response saved to {output_file_name}") - except (APIServerError, APIServerTimedout) as e: - # handling server errors - print(e) - except Exception as e: - print("An error occurred:", str(e)) - - -asyncio.run(main()) diff --git a/magicalapi/client.py b/magicalapi/client.py index 17e483e..51e9bfc 100644 --- a/magicalapi/client.py +++ b/magicalapi/client.py @@ -7,9 +7,6 @@ ProfileDataService, ResumeParserService, ResumeScoreService, - YoutubeSeoService, - YoutubeSuggestionsService, - YoutubeTopKeywordsService, ) from magicalapi.services.resume_review_service import ResumeReviewService from magicalapi.settings import settings @@ -58,18 +55,11 @@ def __init__(self, api_key: str | None = None) -> None: logger.debug("httpx client created") # create service - self.youtube_top_keywords = YoutubeTopKeywordsService( - httpx_client=self._httpx_client - ) self.profile_data = ProfileDataService(httpx_client=self._httpx_client) self.company_data = CompanyDataService(httpx_client=self._httpx_client) - self.youtube_seo = YoutubeSeoService(httpx_client=self._httpx_client) self.resume_parser = ResumeParserService(httpx_client=self._httpx_client) self.resume_score = ResumeScoreService(httpx_client=self._httpx_client) self.resume_review = ResumeReviewService(httpx_client=self._httpx_client) - self.youtube_suggestions = YoutubeSuggestionsService( - httpx_client=self._httpx_client - ) logger.debug(f"async client created : {self}") diff --git a/magicalapi/services/__init__.py b/magicalapi/services/__init__.py index 5fa92f1..1423750 100644 --- a/magicalapi/services/__init__.py +++ b/magicalapi/services/__init__.py @@ -3,17 +3,11 @@ from .resume_parser_service import ResumeParserService from .resume_review_service import ResumeReviewService from .resume_score_service import ResumeScoreService -from .youtube_seo_service import YoutubeSeoService -from .youtube_suggestions_service import YoutubeSuggestionsService -from .youtube_top_keywords_service import YoutubeTopKeywordsService __all__ = [ - "YoutubeTopKeywordsService", "ProfileDataService", "CompanyDataService", - "YoutubeSeoService", "ResumeParserService", "ResumeScoreService", "ResumeReviewService", - "YoutubeSuggestionsService", ] diff --git a/magicalapi/services/youtube_seo_service.py b/magicalapi/services/youtube_seo_service.py deleted file mode 100644 index 43972a1..0000000 --- a/magicalapi/services/youtube_seo_service.py +++ /dev/null @@ -1,36 +0,0 @@ -""" -this file stores the implementation of youtube seo Service. - -""" - -from pydantic import BaseModel - -from magicalapi.types.base import ErrorResponse -from magicalapi.types.schemas import HttpResponse -from magicalapi.types.youtube_seo import YoutubeSeoResponse - -from .base_service import BaseService - - -class YoutubeSeoService(BaseService): - service_path = "youtube-seo" - - async def get_youtube_seo(self, url: str) -> YoutubeSeoResponse | ErrorResponse: - """this method sends request to youtube seo service in magicalAPI. - - url (``str``): - the URL of youtube video that you want to get it's seo data. - - """ - request_body = { - "video_url": url, - } - response = await self._send_post_request(self.service_path, data=request_body) - return self.validate_response( - response=response, validate_model=YoutubeSeoResponse - ) - - def validate_response( - self, response: HttpResponse, validate_model: type[BaseModel] - ) -> YoutubeSeoResponse | ErrorResponse: - return super().validate_response(response, validate_model) diff --git a/magicalapi/services/youtube_suggestions_service.py b/magicalapi/services/youtube_suggestions_service.py deleted file mode 100644 index 16b57bb..0000000 --- a/magicalapi/services/youtube_suggestions_service.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -this file stores the implementation of youtube suggestions Service. -https://magicalapi.com/services/youtube-suggestions - -""" - -from typing import Literal - -from pydantic import BaseModel - -from magicalapi.types.base import ErrorResponse -from magicalapi.types.schemas import HttpResponse -from magicalapi.types.youtube_suggestions import YoutubeSuggestionsResponse - -from .base_service import BaseService - - -class YoutubeSuggestionsService(BaseService): - service_path = "youtube-suggestions" - - async def get_youtube_suggestions( - self, - prompt_sentence: str, - count: int, - suggestion_goal: Literal["caption", "title", "hashtag", "tag"], - ) -> YoutubeSuggestionsResponse | ErrorResponse: - """this method sends request to youtube suggestions service in magicalAPI. - https://magicalapi.com/services/youtube-suggestions - - prompt_sentence (``str``): - your prompt sentence to get suggestions based on it - - count (``int``) - the number of results - - suggestion_goal (``str``): - the goal that you want to get suggestions about it, one of `caption`, `title`, `hashtag`, `tag` - - """ - request_body = { - "prompt_sentence": prompt_sentence, - "count": count, - "suggestion_goal": suggestion_goal, - } - response = await self._send_post_request(self.service_path, data=request_body) - return self.validate_response( - response=response, validate_model=YoutubeSuggestionsResponse - ) - - def validate_response( - self, response: HttpResponse, validate_model: type[BaseModel] - ) -> YoutubeSuggestionsResponse | ErrorResponse: - return super().validate_response(response, validate_model) diff --git a/magicalapi/services/youtube_top_keywords_service.py b/magicalapi/services/youtube_top_keywords_service.py deleted file mode 100644 index 39e610f..0000000 --- a/magicalapi/services/youtube_top_keywords_service.py +++ /dev/null @@ -1,115 +0,0 @@ -""" -this file stores the implementation of Youtube Top Keywords Service. -https://magicalapi.com/services/youtube-keywords - -""" - -from typing import overload - -from pydantic import BaseModel - -from magicalapi.types.base import ErrorResponse -from magicalapi.types.company_data import CountriesResponse, LanguagesResponse -from magicalapi.types.schemas import HttpResponse -from magicalapi.types.youtube_top_keywords import YoutubeTopKeywordsResponse - -from .base_service import BaseService - - -class YoutubeTopKeywordsService(BaseService): - service_path = "youtube-keywords" - - @overload - def validate_response( - self, - response: HttpResponse, - validate_model: type[YoutubeTopKeywordsResponse], - ) -> YoutubeTopKeywordsResponse | ErrorResponse: - pass - - @overload - def validate_response( - self, - response: HttpResponse, - validate_model: type[CountriesResponse], - ) -> CountriesResponse | ErrorResponse: - pass - - @overload - def validate_response( - self, - response: HttpResponse, - validate_model: type[LanguagesResponse], - ) -> LanguagesResponse | ErrorResponse: - pass - - @overload - def validate_response( - self, response: HttpResponse, validate_model: type[BaseModel] - ) -> ( - YoutubeTopKeywordsResponse - | LanguagesResponse - | CountriesResponse - | ErrorResponse - ): - pass - - def validate_response( - self, response: HttpResponse, validate_model: type[BaseModel] - ) -> ( - YoutubeTopKeywordsResponse - | LanguagesResponse - | CountriesResponse - | ErrorResponse - ): - return super().validate_response(response, validate_model) - - async def get_keywords( - self, search_sentence: str, country: str, language: str - ) -> YoutubeTopKeywordsResponse | ErrorResponse: - """this method sends request to Youtube Top Keywords service in magicalAPI. - https://magicalapi.com/services/youtube-keywords - - country (``str``): - the country code of the country that you want to get keywords from. - - language (``str``): - the language code of the language that you want to get keywords from. - - request_id (``str``, *optional*): - the request_id if you have sent a request before and want to get response of it. - """ - request_body = { - "search_sentence": search_sentence, - "country": country, - "language": language, - } - - response = await self._send_post_request("/youtube-keywords", data=request_body) - return self.validate_response( - response=response, validate_model=YoutubeTopKeywordsResponse - ) - - async def get_countries(self) -> CountriesResponse | ErrorResponse: - """this method retrives the supported - countries list for Youtube Top Keywords service in magicalAPI. - https://magicalapi.com/services/youtube-keywords - - """ - # get request - response = await self._send_get_request(self.service_path + "/countries") - return self.validate_response( - response=response, validate_model=CountriesResponse - ) - - async def get_languages(self) -> LanguagesResponse | ErrorResponse: - """this method retrives the supported - languages list for Youtube Top Keywords service in magicalAPI. - https://magicalapi.com/services/youtube-keywords - - """ - # get request - response = await self._send_get_request(self.service_path + "/languages") - return self.validate_response( - response=response, validate_model=LanguagesResponse - ) diff --git a/magicalapi/types/__init__.py b/magicalapi/types/__init__.py index 04c3a8b..5c3a051 100644 --- a/magicalapi/types/__init__.py +++ b/magicalapi/types/__init__.py @@ -1,11 +1,8 @@ from .base import ErrorResponse from .profile_data import Profile, ProfileDataResponse -from .youtube_top_keywords import KeywordIdea, YoutubeTopKeywordsResponse __all__ = [ "ErrorResponse", - "YoutubeTopKeywordsResponse", - "KeywordIdea", "ProfileDataResponse", "Profile", ] diff --git a/magicalapi/types/resume_review.py b/magicalapi/types/resume_review.py index fbbc9bf..338dd61 100644 --- a/magicalapi/types/resume_review.py +++ b/magicalapi/types/resume_review.py @@ -1,5 +1,5 @@ """ -types schem of youtube seo service +types schem of resume review service """ diff --git a/magicalapi/types/youtube_seo.py b/magicalapi/types/youtube_seo.py deleted file mode 100644 index 79b2c12..0000000 --- a/magicalapi/types/youtube_seo.py +++ /dev/null @@ -1,103 +0,0 @@ -""" -types schem of youtube seo service - -""" - -from __future__ import annotations - -from datetime import datetime -from typing import Literal - -from pydantic import BaseModel, HttpUrl - -from magicalapi.types.base import BaseResponse - - -class YoutubeAPI: - # youtube api video response schema - - class Thumbnail(BaseModel): - url: HttpUrl - width: int - height: int - - class Thumbnails(BaseModel): - default: YoutubeAPI.Thumbnail - medium: YoutubeAPI.Thumbnail - high: YoutubeAPI.Thumbnail - standard: YoutubeAPI.Thumbnail | None = None - maxres: YoutubeAPI.Thumbnail | None = None - - class Localized(BaseModel): - title: str - description: str - - class Snippet(BaseModel): - publishedAt: datetime - channelId: str - title: str - description: str - thumbnails: YoutubeAPI.Thumbnails - channelTitle: str - categoryId: str - liveBroadcastContent: str - defaultLanguage: str | None = None - defaultAudioLanguage: str | None = None - tags: list[str] - - class contentDetails(BaseModel): - duration: str - definition: Literal["hd", "sd"] - # TODO ensure empty always - # contentRating: - - class statistics(BaseModel): - viewCount: int - likeCount: int - favoriteCount: int - commentCount: int | None - - class VideoItem(BaseModel): - kind: str - etag: str - id: str - snippet: YoutubeAPI.Snippet - contentDetails: YoutubeAPI.contentDetails - statistics: YoutubeAPI.statistics - - class VideoDetails(BaseModel): - kind: str - etag: str - # TODO keep only the first item video - items: list[YoutubeAPI.VideoItem] - - -class SeoItem(BaseModel): - pros: list[str] - cons: list[str] - - -class SeoItems(BaseModel): - title: SeoItem - description: SeoItem - tags: SeoItem - video_quality: SeoItem - comments: SeoItem - - -class LongVideoSeoItems(SeoItems): - thumbnail: SeoItem - - -class ShortVideoSeoItems(SeoItems): - pass - - -class YoutubeSeo(BaseModel): - score: int - result: LongVideoSeoItems | ShortVideoSeoItems - details: YoutubeAPI.VideoDetails - - -class YoutubeSeoResponse(BaseResponse): - data: YoutubeSeo diff --git a/magicalapi/types/youtube_suggestions.py b/magicalapi/types/youtube_suggestions.py deleted file mode 100644 index 2ff6d7a..0000000 --- a/magicalapi/types/youtube_suggestions.py +++ /dev/null @@ -1,33 +0,0 @@ -""" -types schem of resume score service -https://magicalapi.com/services/resume-score -""" - -from __future__ import annotations - -from .base import BaseModelValidated, BaseResponse - - -class Captions(BaseModelValidated): - captions: list[str] - - -class Titles(BaseModelValidated): - titles: list[str] - - -class Hashtags(BaseModelValidated): - hashtags: list[str] - - -class Keywords(BaseModelValidated): - keywords: list[str] - - -class YoutubeSuggestionsResponse(BaseResponse): - """ - the main resposne schema for resume score service - https://magicalapi.com/services/resume-score - """ - - data: Captions | Titles | Hashtags | Keywords diff --git a/magicalapi/types/youtube_top_keywords.py b/magicalapi/types/youtube_top_keywords.py deleted file mode 100644 index 830338c..0000000 --- a/magicalapi/types/youtube_top_keywords.py +++ /dev/null @@ -1,30 +0,0 @@ -from pydantic import BaseModel - -from .base import BaseResponse - - -class KeywordIdeaMonth(BaseModel): - month: str - year: int - monthly_searches: int - - -class KeywordIdea(BaseModel): - keyword: str - search_volume: int - competition: str - competition_index: int - low_top_of_page_bid_micros: int - high_top_of_page_bid_micros: int - average_cpc: str - monthly_search: list[KeywordIdeaMonth] - - -class Keywords(BaseModel): - keywords: list[KeywordIdea] - - -class YoutubeTopKeywordsResponse(BaseResponse): - """respone model of profile data service""" - - data: Keywords diff --git a/pyproject.toml b/pyproject.toml index a3512d8..23a219a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "magicalapi" -version = "1.1.1" +version = "1.2.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" } @@ -64,6 +64,9 @@ allow-direct-references = true [tool.hatch.build.targets.wheel] packages = ["magicalapi"] +[tool.rye.scripts] +smoke = { cmd = "pytest -vs smoke", env-file = ".env"} +test = { cmd = "pytest -vs tests"} [tool.pytest.ini_options] diff --git a/smoke/test_smoke.py b/smoke/test_smoke.py index c9150c2..91eaf48 100644 --- a/smoke/test_smoke.py +++ b/smoke/test_smoke.py @@ -17,9 +17,6 @@ from magicalapi.types.resume_parser import ResumeParserResponse from magicalapi.types.resume_review import ResumeReviewResponse from magicalapi.types.resume_score import ResumeScoreResponse -from magicalapi.types.youtube_seo import YoutubeSeoResponse -from magicalapi.types.youtube_suggestions import YoutubeSuggestionsResponse -from magicalapi.types.youtube_top_keywords import YoutubeTopKeywordsResponse @pytest_asyncio.fixture(scope="function") @@ -100,35 +97,3 @@ async def test_resume_score(client: AsyncClient): ) assert isinstance(response, ResumeScoreResponse) - - -@pytest.mark.asyncio -async def test_youtube_seo(client: AsyncClient): - # test api returns 200 and correct response schema - response = await client.youtube_seo.get_youtube_seo( - url="https://www.youtube.com/watch?v=PZZI1QXlM80" - ) - - assert isinstance(response, YoutubeSeoResponse) - - -@pytest.mark.asyncio -async def test_youtube_suggestions(client: AsyncClient): - # test api returns 200 and correct response schema - response = await client.youtube_suggestions.get_youtube_suggestions( - prompt_sentence="How to create a profitable Shopify store", - count=5, - suggestion_goal="hashtag", - ) - - assert isinstance(response, YoutubeSuggestionsResponse) - - -@pytest.mark.asyncio -async def test_youtube_keywords(client: AsyncClient): - # test api returns 200 and correct response schema - response = await client.youtube_top_keywords.get_keywords( - search_sentence="movie trailers", country="1", language="1000" - ) - - assert isinstance(response, YoutubeTopKeywordsResponse) diff --git a/tests/conftest.py b/tests/conftest.py index 3581b6a..5514a01 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -8,46 +8,6 @@ Faker.seed() -@pytest.fixture(scope="function") -def youtube_keyword(): - # create a sample profile data dictionary - fake = Faker(locale="en") - MONTH_LIST = [ - "JANUARY", - "FEBRUARY", - "MARCH", - "APRIL", - "MAY", - "JUNE", - "JULY", - "AUGUST", - "SEPTEMBER", - "OCTOBER", - "NOVEMBER", - "DECEMBER", - ] - keyword = { - "keyword": fake.text(max_nb_chars=15), - "search_volume": randint(1000, 1000000), - "competition": choice(("LOW", "MEDIUM", "HIGH")), - "competition_index": randint(0, 100), - "low_top_of_page_bid_micros": randint(0, 10**7), - "high_top_of_page_bid_micros": randint(0, 10**7), - "average_cpc": f"${random.random()}", - "monthly_search": [ - { - "month": month, - "year": randint(2000, 2023), - "monthly_searches": randint(1000, 1000000), - } - for month in MONTH_LIST - ], - } - - yield keyword - del keyword - - @pytest.fixture(scope="function") def resume_data(): # sample data of resume parser service diff --git a/tests/services/test_base_service.py b/tests/services/test_base_service.py index 9c16ba4..1ee8d81 100644 --- a/tests/services/test_base_service.py +++ b/tests/services/test_base_service.py @@ -8,11 +8,8 @@ from magicalapi.errors import APIServerError, APIServerTimedout from magicalapi.services.base_service import BaseService from magicalapi.types.base import ErrorResponse +from magicalapi.types.resume_score import ResumeScore, ResumeScoreResponse from magicalapi.types.schemas import HttpResponse -from magicalapi.types.youtube_top_keywords import ( - KeywordIdea, - YoutubeTopKeywordsResponse, -) @pytest_asyncio.fixture(scope="function") @@ -68,38 +65,32 @@ async def test_base_service_request_timed_out(httpxclient: httpx.AsyncClient): await base_service._send_get_request(path="https://httpbin.org/delay/6") -def test_base_service_validating_response( - httpxclient: httpx.AsyncClient, youtube_keyword: KeywordIdea -): +def test_base_service_validating_response(httpxclient: httpx.AsyncClient): # test validating base service valida_response method base_service = BaseService(httpxclient) # fake response fake_json_response = { - "data": {"keywords": [youtube_keyword]}, + "data": {"score": 10, "reason": "some reason"}, "usage": {"credits": randint(1, 200)}, } - # test validating youtube top keywords validation + # test validating resume score keywords validation # 200 response fake_response = HttpResponse(text=json.dumps(fake_json_response), status_code=200) - assert ( - type( - base_service.validate_response( - response=fake_response, validate_model=YoutubeTopKeywordsResponse - ) - ) - == YoutubeTopKeywordsResponse + assert isinstance( + base_service.validate_response( + response=fake_response, validate_model=ResumeScoreResponse + ), + ResumeScoreResponse, ) # 404 response fake_json_response = {"usage": {"credits": 0}, "message": "request not found !"} fake_response = HttpResponse(text=json.dumps(fake_json_response), status_code=404) - assert ( - type( - base_service.validate_response( - response=fake_response, validate_model=YoutubeTopKeywordsResponse - ) - ) - == ErrorResponse + assert isinstance( + base_service.validate_response( + response=fake_response, validate_model=ResumeScoreResponse + ), + ErrorResponse, ) @@ -110,5 +101,5 @@ def test_base_service_validating_response_raise_error(httpxclient: httpx.AsyncCl fake_response = HttpResponse(text="Internal Server Error!", status_code=500) with pytest.raises(APIServerError): base_service.validate_response( - response=fake_response, validate_model=YoutubeTopKeywordsResponse + response=fake_response, validate_model=ResumeScoreResponse ) diff --git a/tests/types/test_youtube_seo_type.py b/tests/types/test_youtube_seo_type.py deleted file mode 100644 index 2acc48b..0000000 --- a/tests/types/test_youtube_seo_type.py +++ /dev/null @@ -1,139 +0,0 @@ -from random import choice, randint -from uuid import uuid4 - -import pytest -from faker import Faker -from pydantic import ValidationError - -from magicalapi.types.youtube_seo import YoutubeSeoResponse - -Faker.seed() - - -@pytest.fixture(scope="function") -def youtube_seo_data(): # type: ignore - # test data for youtube seo - fake = Faker(locale="en") - _video_id = str(uuid4()) - youtube_seo = { # type: ignore - "score": 41, - "result": { - "title": { - "pros": [], - "cons": [fake.text()], - }, - "description": { - "pros": [], - "cons": [fake.text(), fake.text(), fake.text()], - }, - "tags": { - "pros": [], - "cons": [fake.text()], - }, - "comments": { - "pros": [], - "cons": [fake.text()], - }, - "video_quality": { - "pros": [ - fake.text(), - ], - "cons": [], - }, - "thumbnail": { - "pros": [fake.text()], - "cons": [], - }, - }, - "details": { - "kind": "youtube#videoListResponse", - "etag": "dKkUgpwMfKcMUUXnKYiyXvsCcAA", - "items": [ - { - "kind": "youtube#video", - "etag": str(uuid4()), - "id": _video_id, - "snippet": { - "publishedAt": fake.date_time_this_year().strftime("%FT%TZ"), - "channelId": str(uuid4()), - "title": fake.text(max_nb_chars=100), - "description": fake.text(), - "thumbnails": { - "default": { - "url": f"https://i.ytimg.com/vi/{_video_id}/mqdefault.jpg", - "width": 120, - "height": 90, - }, - "medium": { - "url": f"https://i.ytimg.com/vi/{_video_id}/mqdefault.jpg", - "width": 320, - "height": 180, - }, - "high": { - "url": f"https://i.ytimg.com/vi/{_video_id}/hqdefault.jpg", - "width": 480, - "height": 360, - }, - }, - "channelTitle": fake.name(), - "categoryId": str(randint(1, 40)), - "liveBroadcastContent": "none", - "defaultLanguage": "en", - "localized": { - "title": fake.text(max_nb_chars=100), - "description": fake.text(), - }, - "defaultAudioLanguage": "en", - "tags": [fake.text(max_nb_chars=10) for _ in range(1, 5)], - }, - "contentDetails": { - "duration": f"PT{randint(0,59)}M{randint(0,59)}S", - "dimension": "2d", - "definition": choice(("hd", "sd")), - "caption": choice(("true", "false")), - "licensedContent": choice((True, False)), - "projection": "rectangular", - }, - "status": { - "uploadStatus": "processed", - "privacyStatus": "public", - "license": "youtube", - "embeddable": choice((True, False)), - "publicStatsViewable": choice((True, False)), - "madeForKids": choice((True, False)), - }, - "statistics": { - "viewCount": str(randint(1, 1000000)), - "likeCount": str(randint(1, 1000000)), - "favoriteCount": str(randint(1, 1000000)), - # "commentCount": str(randint(1, 1000000)), - "commentCount": None, # test no comment count - }, - } - ], - "pageInfo": {"totalResults": 1, "resultsPerPage": 1}, - }, - } - - yield youtube_seo - - del youtube_seo - - -def test_youtube_seo_validate_type(youtube_seo_data): - # test validating youtube_seo response type - response = {"data": youtube_seo_data, "usage": {"credits": randint(10, 500)}} - - assert type(YoutubeSeoResponse.model_validate(response)) == YoutubeSeoResponse - - -def test_youtube_seo_validate_type_failing(youtube_seo_data): - # test validating youtube_seo response type must fail - # make data schema invalid - del youtube_seo_data["score"] - youtube_seo_data["details"]["items"] = {} - - response = {"data": youtube_seo_data, "usage": {"credits": randint(10, 500)}} - - with pytest.raises(ValidationError): - YoutubeSeoResponse.model_validate(response) diff --git a/tests/types/test_youtube_suggestions_type.py b/tests/types/test_youtube_suggestions_type.py deleted file mode 100644 index d030e85..0000000 --- a/tests/types/test_youtube_suggestions_type.py +++ /dev/null @@ -1,68 +0,0 @@ -from random import randint - -import pytest -from faker import Faker - -from magicalapi.types.youtube_suggestions import YoutubeSuggestionsResponse - -Faker.seed() - - -@pytest.fixture(scope="function") -def captions(): - fake = Faker(locale="en") - captions = {"captions": [fake.text() for _ in range(5)]} - - yield captions - - del captions - - -@pytest.fixture(scope="function") -def titles(): - fake = Faker(locale="en") - titles = {"titles": [fake.text(max_nb_chars=80) for _ in range(5)]} - - yield titles - - del titles - - -@pytest.fixture(scope="function") -def hashtags(): - fake = Faker(locale="en") - hashtags = {"hashtags": [fake.text(max_nb_chars=10) for _ in range(5)]} - - yield hashtags - - del hashtags - - -@pytest.fixture(scope="function") -def keywords(): - fake = Faker(locale="en") - keywords = {"keywords": [fake.text(max_nb_chars=10) for _ in range(5)]} - - yield keywords - - del keywords - - -def test_youtube_suggestions_validate_type(captions, titles, hashtags, keywords): - # test validating youtube_suggestions response type - - responses = ( - {"data": captions, "usage": {"credits": randint(10, 500)}}, - {"data": titles, "usage": {"credits": randint(10, 500)}}, - {"data": hashtags, "usage": {"credits": randint(10, 500)}}, - {"data": keywords, "usage": {"credits": randint(10, 500)}}, - ) - - # check all suggestion goals - assert all( - [ - type(YoutubeSuggestionsResponse.model_validate(response)) - == YoutubeSuggestionsResponse - for response in responses - ] - ) diff --git a/tests/types/test_youtube_top_keywords_types.py b/tests/types/test_youtube_top_keywords_types.py deleted file mode 100644 index 8ae3862..0000000 --- a/tests/types/test_youtube_top_keywords_types.py +++ /dev/null @@ -1,33 +0,0 @@ -from random import randint - -import pytest -from pydantic import ValidationError - -from magicalapi.types.youtube_top_keywords import ( - KeywordIdea, - YoutubeTopKeywordsResponse, -) - - -@pytest.mark.dependency() -def test_youtube_top_keywords_type(youtube_keyword: KeywordIdea): - try: - # validating keywords - KeywordIdea.model_validate( - obj=youtube_keyword, - ) - - except ValidationError as exc: - assert False, "validating youtube_top_keywords type failed : " + str(exc) - - -@pytest.mark.dependency(depends=["test_youtube_top_keywords_type"]) -def test_youtube_top_keywords_response_type(youtube_keyword: KeywordIdea): - try: - response_schema = { - "data": {"keywords": [youtube_keyword]}, - "usage": {"credits": randint(1, 200)}, - } - YoutubeTopKeywordsResponse.model_validate(response_schema) - except ValidationError as exc: - assert False, "validating youtube_top_keywords response failed : " + str(exc)